From 799e3be9bdbb5b895b004a0c553954b3f104ace6 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 12:07:38 +0100
Subject: [PATCH 001/173] New Crowdin Translations (automated) (#29726)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ar.json    |  1 +
 app/javascript/mastodon/locales/be.json    |  4 ++
 app/javascript/mastodon/locales/da.json    |  4 +-
 app/javascript/mastodon/locales/de.json    |  2 +
 app/javascript/mastodon/locales/es-AR.json |  4 +-
 app/javascript/mastodon/locales/es-MX.json |  9 ++++
 app/javascript/mastodon/locales/es.json    |  9 ++++
 app/javascript/mastodon/locales/eu.json    |  2 +
 app/javascript/mastodon/locales/fa.json    |  2 +
 app/javascript/mastodon/locales/fi.json    |  2 +
 app/javascript/mastodon/locales/fo.json    |  2 +
 app/javascript/mastodon/locales/gd.json    |  6 +--
 app/javascript/mastodon/locales/he.json    |  2 +
 app/javascript/mastodon/locales/is.json    |  4 ++
 app/javascript/mastodon/locales/it.json    |  2 +
 app/javascript/mastodon/locales/ja.json    | 25 +++++++++++
 app/javascript/mastodon/locales/ko.json    |  1 +
 app/javascript/mastodon/locales/lt.json    |  3 ++
 app/javascript/mastodon/locales/nl.json    | 20 +++++----
 app/javascript/mastodon/locales/pl.json    |  9 ++++
 app/javascript/mastodon/locales/pt-PT.json |  9 ++++
 app/javascript/mastodon/locales/sk.json    |  3 ++
 app/javascript/mastodon/locales/sq.json    |  2 +
 app/javascript/mastodon/locales/sv.json    |  1 +
 app/javascript/mastodon/locales/th.json    |  9 ++++
 app/javascript/mastodon/locales/tr.json    |  2 +
 app/javascript/mastodon/locales/uk.json    |  2 +
 app/javascript/mastodon/locales/zh-CN.json |  2 +
 app/javascript/mastodon/locales/zh-HK.json |  9 ++++
 app/javascript/mastodon/locales/zh-TW.json |  2 +
 config/locales/be.yml                      |  8 ++++
 config/locales/devise.hu.yml               |  2 +-
 config/locales/doorkeeper.hu.yml           |  4 +-
 config/locales/es-AR.yml                   |  2 +-
 config/locales/es-MX.yml                   | 12 ++++++
 config/locales/es.yml                      | 12 ++++++
 config/locales/hu.yml                      | 48 +++++++++++-----------
 config/locales/is.yml                      |  3 ++
 config/locales/ja.yml                      |  3 ++
 config/locales/ko.yml                      |  2 +-
 config/locales/lt.yml                      | 19 ++++++---
 config/locales/pt-PT.yml                   | 12 ++++++
 config/locales/simple_form.hu.yml          | 12 +++---
 config/locales/simple_form.nl.yml          |  4 +-
 config/locales/th.yml                      | 11 +++++
 config/locales/zh-HK.yml                   | 13 ++++++
 46 files changed, 265 insertions(+), 56 deletions(-)

diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 747c47960..62ac7739d 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -89,6 +89,7 @@
   "announcement.announcement": "إعلان",
   "attachments_list.unprocessed": "(غير معالَج)",
   "audio.hide": "إخفاء المقطع الصوتي",
+  "block_modal.remote_users_caveat": "Do t’i kërkojmë shërbyesit {domain} të respektojë vendimin tuaj. Por, pajtimi s’është i garantuar, ngaqë disa shërbyes mund t’i trajtojnë ndryshe bllokimet. Psotimet publike mundet të jenë ende të dukshme për përdorues pa bërë hyrje në llogari.",
   "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة",
   "bundle_column_error.copy_stacktrace": "انسخ تقرير الخطأ",
   "bundle_column_error.error.body": "لا يمكن تقديم الصفحة المطلوبة. قد يكون بسبب خطأ في التعليمات البرمجية، أو مشكلة توافق المتصفح.",
diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json
index 1ff94eca6..754b7156b 100644
--- a/app/javascript/mastodon/locales/be.json
+++ b/app/javascript/mastodon/locales/be.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "Ваша апытанне скончылася",
   "notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
   "notification.reblog": "{name} пашырыў ваш допіс",
+  "notification.severed_relationships": "Зносіны з {name} былі разарваныя",
   "notification.status": "Новы допіс ад {name}",
   "notification.update": "Допіс {name} адрэдагаваны",
   "notification_requests.accept": "Прыняць",
@@ -483,6 +484,7 @@
   "notifications.column_settings.admin.sign_up": "Новыя ўваходы:",
   "notifications.column_settings.alert": "Апавяшчэнні на працоўным стале",
   "notifications.column_settings.favourite": "Упадабанае:",
+  "notifications.column_settings.filter_bar.advanced": "Паказаць усе катэгорыі",
   "notifications.column_settings.follow": "Новыя падпісчыкі:",
   "notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
   "notifications.column_settings.mention": "Згадванні:",
@@ -587,6 +589,8 @@
   "refresh": "Абнавiць",
   "regeneration_indicator.label": "Загрузка…",
   "regeneration_indicator.sublabel": "Пачакайце, рыхтуем вашу стужку!",
+  "relationship_severance_notification.types.user_domain_block": "Вы заблакіравалі гэты дамен",
+  "relationship_severance_notification.view": "Праглядзець",
   "relative_time.days": "{number} д",
   "relative_time.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}} таму",
   "relative_time.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}} таму",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index ca32ba298..97468c627 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -220,7 +220,7 @@
   "domain_pill.activitypub_lets_connect": "Det muliggør at komme i forbindelse og interagere med folk ikke kun på Mastodon, men også på tværs af forskellige sociale apps.",
   "domain_pill.activitypub_like_language": "ActivityPub er \"sproget\", Mastodon taler med andre sociale netværk.",
   "domain_pill.server": "Server",
-  "domain_pill.their_handle": "Deres handle:",
+  "domain_pill.their_handle": "Vedkommendes handle:",
   "domain_pill.username": "Brugernavn",
   "domain_pill.whats_in_a_handle": "Hvad er der i et handle (@brugernavn)?",
   "domain_pill.who_they_are": "Da et handle fortæller, hvem nogen er, og hvor de er, kan man interagere med folk på tværs af det sociale net af <button>ActivityPub-drevne platforme</button>.",
@@ -481,6 +481,8 @@
   "notifications.column_settings.admin.sign_up": "Nye tilmeldinger:",
   "notifications.column_settings.alert": "Computernotifikationer",
   "notifications.column_settings.favourite": "Favoritter:",
+  "notifications.column_settings.filter_bar.advanced": "Vis alle kategorier",
+  "notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
   "notifications.column_settings.follow": "Nye følgere:",
   "notifications.column_settings.follow_request": "Nye følgeanmodninger:",
   "notifications.column_settings.mention": "Omtaler:",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index bed336f76..8cc77c072 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Neue Registrierungen:",
   "notifications.column_settings.alert": "Desktop-Benachrichtigungen",
   "notifications.column_settings.favourite": "Favoriten:",
+  "notifications.column_settings.filter_bar.advanced": "Alle Filterkategorien anzeigen",
+  "notifications.column_settings.filter_bar.category": "Filterleiste",
   "notifications.column_settings.follow": "Neue Follower:",
   "notifications.column_settings.follow_request": "Neue Follower-Anfragen:",
   "notifications.column_settings.mention": "Erwähnungen:",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index fec707be6..a9db8831e 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -427,7 +427,7 @@
   "loading_indicator.label": "Cargando…",
   "media_gallery.toggle_visible": "Ocultar {number, plural, one {imagen} other {imágenes}}",
   "moved_to_account_banner.text": "Tu cuenta {disabledAccount} está actualmente deshabilitada porque te mudaste a {movedToAccount}.",
-  "mute_modal.hide_from_notifications": "Ocultar de las notificaciones",
+  "mute_modal.hide_from_notifications": "Ocultar en las notificaciones",
   "mute_modal.hide_options": "Ocultar opciones",
   "mute_modal.indefinite": "Hasta que deje de silenciarlos",
   "mute_modal.show_options": "Mostrar opciones",
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nuevos registros:",
   "notifications.column_settings.alert": "Notificaciones de escritorio",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías",
+  "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
   "notifications.column_settings.follow": "Nuevos seguidores:",
   "notifications.column_settings.follow_request": "Nuevas solicitudes de seguimiento:",
   "notifications.column_settings.mention": "Menciones:",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index 00dcb8146..dea71a935 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "Tu encuesta ha terminado",
   "notification.poll": "Una encuesta en la que has votado ha terminado",
   "notification.reblog": "{name} ha retooteado tu estado",
+  "notification.severed_relationships": "Se han cortado las relaciones con {name}",
   "notification.status": "{name} acaba de publicar",
   "notification.update": "{name} editó una publicación",
   "notification_requests.accept": "Aceptar",
@@ -483,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Registros nuevos:",
   "notifications.column_settings.alert": "Notificaciones de escritorio",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías",
+  "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
   "notifications.column_settings.follow": "Nuevos seguidores:",
   "notifications.column_settings.follow_request": "Nuevas solicitudes de seguimiento:",
   "notifications.column_settings.mention": "Menciones:",
@@ -587,6 +590,12 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "Cargando…",
   "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
+  "relationship_severance_notification.purged_data": "purgado por administradores",
+  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relaciones}}",
+  "relationship_severance_notification.types.account_suspension": "La cuenta ha sido suspendida",
+  "relationship_severance_notification.types.domain_block": "El dominio ha sido suspendido",
+  "relationship_severance_notification.types.user_domain_block": "Bloqueaste este dominio",
+  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "{number, plural, one {# día} other {# días hace}}",
   "relative_time.full.hours": "{number, plural, one {# hora} other {# horas}} hace",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 728f4d05f..64bcf7d9c 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "Tu encuesta ha terminado",
   "notification.poll": "Una encuesta en la que has votado ha terminado",
   "notification.reblog": "{name} ha impulsado tu publicación",
+  "notification.severed_relationships": "Se han cortado las relaciones con {name}",
   "notification.status": "{name} acaba de publicar",
   "notification.update": "{name} editó una publicación",
   "notification_requests.accept": "Aceptar",
@@ -483,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nuevos registros:",
   "notifications.column_settings.alert": "Notificaciones de escritorio",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías",
+  "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
   "notifications.column_settings.follow": "Nuevos seguidores:",
   "notifications.column_settings.follow_request": "Nuevas solicitudes de seguimiento:",
   "notifications.column_settings.mention": "Menciones:",
@@ -587,6 +590,12 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "Cargando…",
   "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
+  "relationship_severance_notification.purged_data": "purgado por administradores",
+  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relaciones}}",
+  "relationship_severance_notification.types.account_suspension": "La cuenta ha sido suspendida",
+  "relationship_severance_notification.types.domain_block": "El dominio ha sido suspendido",
+  "relationship_severance_notification.types.user_domain_block": "Bloqueaste este dominio",
+  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "hace {number, plural, one {# día} other {# días}}",
   "relative_time.full.hours": "hace {number, plural, one {# hora} other {# horas}}",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index bd0081d71..8c3c5f984 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Izen-emate berriak:",
   "notifications.column_settings.alert": "Mahaigaineko jakinarazpenak",
   "notifications.column_settings.favourite": "Gogokoak:",
+  "notifications.column_settings.filter_bar.advanced": "Bistaratu kategoria guztiak",
+  "notifications.column_settings.filter_bar.category": "Iragazki-barra bizkorra",
   "notifications.column_settings.follow": "Jarraitzaile berriak:",
   "notifications.column_settings.follow_request": "Jarraitzeko eskaera berriak:",
   "notifications.column_settings.mention": "Aipamenak:",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index b784a1d5c..6d6b7d612 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -462,6 +462,8 @@
   "notifications.permission_denied": "آگاهی‌های میزکار به دلیل رد کردن درخواست اجازهٔ پیشین مرورگر، در دسترس نیستند",
   "notifications.permission_denied_alert": "از آن‌جا که پیش از این اجازهٔ مرورگر رد شده است، آگاهی‌های میزکار نمی‌توانند به کار بیفتند",
   "notifications.permission_required": "آگاهی‌های میزکار در دسترس نیستند زیرا اجازه‌های لازم، اعطا نشده.",
+  "notifications.policy.filter_not_followers_title": "کسانی که شما را دنبال میکنند",
+  "notifications.policy.filter_not_following_hint": "",
   "notifications_permission_banner.enable": "به کار انداختن آگاهی‌های میزکار",
   "notifications_permission_banner.how_to_control": "برای دریافت آگاهی‌ها هنگام باز نبودن ماستودون، آگاهی‌های میزکار را به کار بیندازید. پس از به کار افتادنشان می‌توانید گونه‌های دقیق برهم‌کنش‌هایی که آگاهی‌های میزکار تولید می‌کنند را از {icon} بالا واپایید.",
   "notifications_permission_banner.title": "هرگز چیزی را از دست ندهید",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 2cf85926f..16670d9ff 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Uudet rekisteröitymiset:",
   "notifications.column_settings.alert": "Työpöytäilmoitukset",
   "notifications.column_settings.favourite": "Suosikit:",
+  "notifications.column_settings.filter_bar.advanced": "Näytä kaikki luokat",
+  "notifications.column_settings.filter_bar.category": "Pikasuodatuspalkki",
   "notifications.column_settings.follow": "Uudet seuraajat:",
   "notifications.column_settings.follow_request": "Uudet seuraamispyynnöt:",
   "notifications.column_settings.mention": "Maininnat:",
diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json
index 3ea13cc7f..c86829ee3 100644
--- a/app/javascript/mastodon/locales/fo.json
+++ b/app/javascript/mastodon/locales/fo.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nýggjar tilmeldingar:",
   "notifications.column_settings.alert": "Skriviborðsfráboðanir",
   "notifications.column_settings.favourite": "Dámdir postar:",
+  "notifications.column_settings.filter_bar.advanced": "Vís allar bólkar",
+  "notifications.column_settings.filter_bar.category": "Skjótfilturbjálki",
   "notifications.column_settings.follow": "Nýggir fylgjarar:",
   "notifications.column_settings.follow_request": "Nýggjar umbønir um at fylgja:",
   "notifications.column_settings.mention": "Umrøður:",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index 9c566909a..612e36377 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -701,10 +701,10 @@
   "status.direct_indicator": "Iomradh prìobhaideach",
   "status.edit": "Deasaich",
   "status.edited": "An deasachadh mu dheireadh {date}",
-  "status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{counter} turas} two {{counter} thuras} few {{counter} tursan} other {{counter} turas}}",
+  "status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{count} turas} two {{count} thuras} few {{count} tursan} other {{count} turas}}",
   "status.embed": "Leabaich",
   "status.favourite": "Cuir ris na h-annsachdan",
-  "status.favourites": "{count, plural, one {annsachd} two {annsachd} few {annsachdan} other {annsachd}",
+  "status.favourites": "{count, plural, one {annsachd} two {annsachd} few {annsachdan} other {annsachd}}",
   "status.filter": "Criathraich am post seo",
   "status.filtered": "Criathraichte",
   "status.hide": "Falaich am post",
@@ -725,7 +725,7 @@
   "status.reblog": "Brosnaich",
   "status.reblog_private": "Brosnaich leis an t-so-fhaicsinneachd tùsail",
   "status.reblogged_by": "’Ga bhrosnachadh le {name}",
-  "status.reblogs": "{count, plural, one {bhrosnachadh} two {bhrosnachadh} few {brosnachaidhean} other {brosnachadh}",
+  "status.reblogs": "{count, plural, one {bhrosnachadh} two {bhrosnachadh} few {brosnachaidhean} other {brosnachadh}}",
   "status.reblogs.empty": "Chan deach am post seo a bhrosnachadh le duine sam bith fhathast. Nuair a bhrosnaicheas cuideigin e, nochdaidh iad an-seo.",
   "status.redraft": "Sguab às ⁊ dèan dreachd ùr",
   "status.remove_bookmark": "Thoir an comharra-lìn air falbh",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 1f65c3549..82dec2d86 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "הרשמות חדשות:",
   "notifications.column_settings.alert": "התראות לשולחן העבודה",
   "notifications.column_settings.favourite": "חיבובים:",
+  "notifications.column_settings.filter_bar.advanced": "להציג את כל הקטגוריות",
+  "notifications.column_settings.filter_bar.category": "שורת סינון מהיר",
   "notifications.column_settings.follow": "עוקבים חדשים:",
   "notifications.column_settings.follow_request": "בקשות מעקב חדשות:",
   "notifications.column_settings.mention": "פניות:",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index d050aa031..b65df2fc5 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -483,6 +483,8 @@
   "notifications.column_settings.admin.sign_up": "Nýjar skráningar:",
   "notifications.column_settings.alert": "Tilkynningar á skjáborði",
   "notifications.column_settings.favourite": "Eftirlæti:",
+  "notifications.column_settings.filter_bar.advanced": "Birta alla flokka",
+  "notifications.column_settings.filter_bar.category": "Skyndisíustika",
   "notifications.column_settings.follow": "Nýir fylgjendur:",
   "notifications.column_settings.follow_request": "Nýjar beiðnir um að fylgjast með:",
   "notifications.column_settings.mention": "Tilvísanir:",
@@ -587,6 +589,8 @@
   "refresh": "Endurlesa",
   "regeneration_indicator.label": "Hleð inn…",
   "regeneration_indicator.sublabel": "Verið er að útbúa heimastreymið þitt!",
+  "relationship_severance_notification.relationships": "{count, plural, one {# tengsl} other {# tengsl}}",
+  "relationship_severance_notification.view": "Skoða",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "Fyrir {number, plural, one {# degi} other {# dögum}} síðan",
   "relative_time.full.hours": "Fyrir {number, plural, one {# klukkustund} other {# klukkustundum}} síðan",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 7d5df9198..090278b83 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nuove iscrizioni:",
   "notifications.column_settings.alert": "Notifiche desktop",
   "notifications.column_settings.favourite": "Preferiti:",
+  "notifications.column_settings.filter_bar.advanced": "Mostra tutte le categorie",
+  "notifications.column_settings.filter_bar.category": "Barra del filtro veloce",
   "notifications.column_settings.follow": "Nuovi seguaci:",
   "notifications.column_settings.follow_request": "Nuove richieste di seguirti:",
   "notifications.column_settings.mention": "Menzioni:",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 66811eafd..1f1065f5f 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -89,6 +89,14 @@
   "announcement.announcement": "お知らせ",
   "attachments_list.unprocessed": "(未処理)",
   "audio.hide": "音声を閉じる",
+  "block_modal.remote_users_caveat": "このサーバーはあなたのブロックの意思を尊重するように {domain} へ通知します。しかしながら、ブロックの扱い方はサーバーによってさまざまで、相手のサーバーは必ずしもこのブロックを適切に取り扱うものではないことに留意が必要です。また、あなたの公開投稿はサーバーからログアウトすれば誰からも見ることができます。",
+  "block_modal.show_less": "注意事項を閉じる",
+  "block_modal.show_more": "注意事項",
+  "block_modal.they_cant_mention": "相手はあなたへの返信やフォローができなくなります。",
+  "block_modal.they_cant_see_posts": "相手はあなたの投稿を閲覧できなくなり、あなたも相手の投稿を閲覧できなくなります。",
+  "block_modal.they_will_know": "ブロックは相手からわかります。",
+  "block_modal.title": "ユーザーをブロックしますか?",
+  "block_modal.you_wont_see_mentions": "宛先に相手が入っている投稿も閲覧できなくなります。",
   "boost_modal.combo": "次からは{combo}を押せばスキップできます",
   "bundle_column_error.copy_stacktrace": "エラーレポートをコピー",
   "bundle_column_error.error.body": "要求されたページをレンダリングできませんでした。コードのバグ、またはブラウザの互換性の問題が原因である可能性があります。",
@@ -200,6 +208,14 @@
   "dismissable_banner.explore_statuses": "ネットワーク上で注目を集めている投稿です。ブーストやお気に入り登録の多い新しい投稿が上位に表示されます。",
   "dismissable_banner.explore_tags": "ネットワーク上でトレンドになっているハッシュタグです。たくさんのユーザーに使われたタグほど上位に表示されます。",
   "dismissable_banner.public_timeline": "{domain}のユーザーがリモートフォローしているアカウントからの公開投稿のタイムラインです。",
+  "domain_block_modal.block": "サーバーをブロック",
+  "domain_block_modal.block_account_instead": "@{name} さんのみをブロック",
+  "domain_block_modal.they_can_interact_with_old_posts": "あなたの今までの投稿は、引き続きこのサーバーのユーザーが閲覧できます。",
+  "domain_block_modal.they_cant_follow": "このサーバーのユーザーはあなたをフォローできなくなります。",
+  "domain_block_modal.they_wont_know": "ドメインブロックは相手からはわかりません。",
+  "domain_block_modal.title": "ドメインをブロックしますか?",
+  "domain_block_modal.you_will_lose_followers": "このサーバーのフォロワーはすべてフォロー解除されます。",
+  "domain_block_modal.you_wont_see_posts": "このサーバーのユーザーからの投稿や通知が閲覧できなくなります。",
   "embed.instructions": "下記のコードをコピーしてウェブサイトに埋め込みます。",
   "embed.preview": "表示例:",
   "emoji_button.activity": "活動",
@@ -397,6 +413,15 @@
   "loading_indicator.label": "読み込み中…",
   "media_gallery.toggle_visible": "{number, plural, one {画像を閉じる} other {画像を閉じる}}",
   "moved_to_account_banner.text": "あなたのアカウント『{disabledAccount}』は『{movedToAccount}』に移動したため現在無効になっています。",
+  "mute_modal.hide_from_notifications": "通知をオフにする",
+  "mute_modal.hide_options": "オプションを閉じる",
+  "mute_modal.indefinite": "無期限",
+  "mute_modal.show_options": "オプションを表示",
+  "mute_modal.they_can_mention_and_follow": "相手はあなたへの返信やフォローができますが、あなたには見えません。",
+  "mute_modal.they_wont_know": "ミュートは相手からはわかりません。",
+  "mute_modal.title": "ユーザーをミュートしますか?",
+  "mute_modal.you_wont_see_mentions": "宛先に相手が入っている投稿も閲覧できなくなります。",
+  "mute_modal.you_wont_see_posts": "相手はあなたの投稿を今までどおり閲覧できますが、あなたは相手の投稿を閲覧できなくなります。",
   "navigation_bar.about": "概要",
   "navigation_bar.advanced_interface": "上級者向けUIに戻る",
   "navigation_bar.blocks": "ブロックしたユーザー",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index da354f391..5553636f2 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -484,6 +484,7 @@
   "notifications.column_settings.admin.sign_up": "새로운 가입:",
   "notifications.column_settings.alert": "데스크탑 알림",
   "notifications.column_settings.favourite": "좋아요:",
+  "notifications.column_settings.filter_bar.advanced": "모든 범주 표시",
   "notifications.column_settings.follow": "새 팔로워:",
   "notifications.column_settings.follow_request": "새 팔로우 요청:",
   "notifications.column_settings.mention": "멘션:",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index f9ef7e242..728485b2b 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -555,6 +555,9 @@
   "refresh": "Atnaujinti",
   "regeneration_indicator.label": "Kraunama…",
   "regeneration_indicator.sublabel": "Ruošiamas tavo pagrindinis srautas!",
+  "relationship_severance_notification.relationships": "{count, plural, one {# santykis} few {# santykiai} many {# santykio} other {# santykių}}",
+  "relationship_severance_notification.types.user_domain_block": "Užblokavai šį domeną",
+  "relationship_severance_notification.view": "Peržiūrėti",
   "relative_time.days": "{number} d.",
   "relative_time.full.days": "prieš {number, plural, one {# dieną} few {# dienas} many {# dienos} other {# dienų}}",
   "relative_time.full.hours": "prieš {number, plural, one {# valandą} few {# valandas} many {# valandos} other {# valandų}}",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 4be0808f2..1e710bda4 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -205,10 +205,10 @@
   "disabled_account_banner.text": "Jouw account {disabledAccount} is momenteel uitgeschakeld.",
   "dismissable_banner.community_timeline": "Dit zijn de meest recente openbare berichten van accounts op {domain}. Je kunt onder 'instellingen > voorkeuren > overig' kiezen welke talen je wilt zien.",
   "dismissable_banner.dismiss": "Sluiten",
-  "dismissable_banner.explore_links": "Dit zijn nieuwsberichten die vandaag het meest op het sociale web worden gedeeld. Nieuwere nieuwsberichten die door meer verschillende mensen zijn geplaatst staan hoger op de lijst.",
-  "dismissable_banner.explore_statuses": "Dit zijn berichten op het sociale web die vandaag aan populariteit winnen. Nieuwere berichten met meer boosts en favorieten staan hoger.",
-  "dismissable_banner.explore_tags": "Deze hashtags winnen aan populariteit op het sociale web. Hashtags die door meer verschillende mensen worden gebruikt staan hoger.",
-  "dismissable_banner.public_timeline": "Dit zijn de meest recente openbare berichten van accounts op het sociale web die door mensen op {domain} worden gevolgd.",
+  "dismissable_banner.explore_links": "Dit zijn nieuwsberichten die vandaag het meest op het sociale web (fediverse) worden gedeeld. Nieuwere nieuwsberichten die door meer verschillende mensen zijn geplaatst staan hoger op de lijst.",
+  "dismissable_banner.explore_statuses": "Dit zijn berichten op het sociale web (fediverse) die vandaag aan populariteit winnen. Nieuwere berichten met meer boosts en favorieten staan hoger.",
+  "dismissable_banner.explore_tags": "Deze hashtags winnen aan populariteit op het sociale web (fediverse). Hashtags die door meer verschillende mensen worden gebruikt staan hoger.",
+  "dismissable_banner.public_timeline": "Dit zijn de meest recente openbare berichten van accounts op het sociale web (fediverse) die door mensen op {domain} worden gevolgd.",
   "domain_block_modal.block": "Server blokkeren",
   "domain_block_modal.block_account_instead": "In plaats hiervan {name} blokkeren",
   "domain_block_modal.they_can_interact_with_old_posts": "Mensen op deze server kunnen interactie hebben met jouw oude berichten.",
@@ -220,14 +220,14 @@
   "domain_pill.activitypub_lets_connect": "Het zorgt ervoor dat je niet alleen maar kunt verbinden en communiceren met mensen op Mastodon, maar ook met andere sociale apps.",
   "domain_pill.activitypub_like_language": "ActivityPub is de taal die Mastodon met andere sociale netwerken spreekt.",
   "domain_pill.server": "Server",
-  "domain_pill.their_handle": "Hun Mastodon-adres:",
+  "domain_pill.their_handle": "Hun fediverse-adres:",
   "domain_pill.their_server": "Hun digitale thuis, waar al hun berichten zich bevinden.",
   "domain_pill.their_username": "Hun unieke identificatie-adres op hun server. Het is mogelijk dat er gebruikers met dezelfde gebruikersnaam op verschillende servers te vinden zijn.",
   "domain_pill.username": "Gebruikersnaam",
-  "domain_pill.whats_in_a_handle": "Wat is een Mastodon-adres?",
-  "domain_pill.who_they_are": "Omdat je aan een Mastodon-adres kunt zien wie iemand is en waar die zich bevindt, kun je met mensen op het door <button>ActivityPub aangedreven</button> sociale web communiceren.",
-  "domain_pill.who_you_are": "Omdat je aan jouw Mastodon-adres kunt zien wie jij bent is en waar je je bevindt, kunnen mensen op het door <button>ActivityPub aangedreven</button> sociale web met jou communiceren.",
-  "domain_pill.your_handle": "Jouw Mastodon-adres:",
+  "domain_pill.whats_in_a_handle": "Wat is een fediverse-adres?",
+  "domain_pill.who_they_are": "Omdat je aan een fediverse-adres kunt zien wie iemand is en waar die zich bevindt, kun je met mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) communiceren.",
+  "domain_pill.who_you_are": "Omdat je aan jouw fediverse-adres kunt zien wie jij bent is en waar je je bevindt, kunnen mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) met jou communiceren.",
+  "domain_pill.your_handle": "Jouw fediverse-adres:",
   "domain_pill.your_server": "Jouw digitale thuis, waar al jouw berichten zich bevinden. Is deze server toch niet naar jouw wens? Dan kun je op elk moment naar een andere server verhuizen en ook jouw volgers overbrengen.",
   "domain_pill.your_username": "Jouw unieke identificatie-adres op deze server. Het is mogelijk dat er gebruikers met dezelfde gebruikersnaam op verschillende servers te vinden zijn.",
   "embed.instructions": "Embed dit bericht op jouw website door de onderstaande code te kopiëren.",
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nieuwe registraties:",
   "notifications.column_settings.alert": "Desktopmeldingen",
   "notifications.column_settings.favourite": "Favorieten:",
+  "notifications.column_settings.filter_bar.advanced": "Alle categorieën tonen",
+  "notifications.column_settings.filter_bar.category": "Snelle filterbalk",
   "notifications.column_settings.follow": "Nieuwe volgers:",
   "notifications.column_settings.follow_request": "Nieuw volgverzoek:",
   "notifications.column_settings.mention": "Vermeldingen:",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 782ea9d76..3ee134d6c 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "Twoje głosowanie zakończyło się",
   "notification.poll": "Głosowanie w którym brałeś(-aś) udział zakończyło się",
   "notification.reblog": "Twój post został podbity przez {name}",
+  "notification.severed_relationships": "Zerwano związki z {name}",
   "notification.status": "{name} opublikował(a) nowy wpis",
   "notification.update": "{name} edytował(a) post",
   "notification_requests.accept": "Akceptuj",
@@ -483,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Nowe rejestracje:",
   "notifications.column_settings.alert": "Powiadomienia na pulpicie",
   "notifications.column_settings.favourite": "Ulubione:",
+  "notifications.column_settings.filter_bar.advanced": "Wyświetl wszystkie kategorie",
+  "notifications.column_settings.filter_bar.category": "Szybkie filtrowanie",
   "notifications.column_settings.follow": "Nowi obserwujący:",
   "notifications.column_settings.follow_request": "Nowe prośby o możliwość obserwacji:",
   "notifications.column_settings.mention": "Wspomnienia:",
@@ -587,6 +590,12 @@
   "refresh": "Odśwież",
   "regeneration_indicator.label": "Ładuję…",
   "regeneration_indicator.sublabel": "Twoja oś czasu jest przygotowywana!",
+  "relationship_severance_notification.purged_data": "wyczyszczone przez administratorów",
+  "relationship_severance_notification.relationships": "{count, plural, one {# związek} few {# związki} other {# związków}}",
+  "relationship_severance_notification.types.account_suspension": "Konto zostało zawieszone",
+  "relationship_severance_notification.types.domain_block": "Domena została zawieszona",
+  "relationship_severance_notification.types.user_domain_block": "Domena przez ciebie blokowana",
+  "relationship_severance_notification.view": "Pokaż",
   "relative_time.days": "{number} dni",
   "relative_time.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}} temu",
   "relative_time.full.hours": "{number, plural, one {# godzinę} few {# godziny} many {# godzin} other {# godzin}} temu",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index d4b37ffe6..6732973d5 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "A sua votação terminou",
   "notification.poll": "Uma votação em que participaste chegou ao fim",
   "notification.reblog": "{name} reforçou a tua publicação",
+  "notification.severed_relationships": "Relações com {name} cessadas",
   "notification.status": "{name} acabou de publicar",
   "notification.update": "{name} editou uma publicação",
   "notification_requests.accept": "Aceitar",
@@ -483,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Novas inscrições:",
   "notifications.column_settings.alert": "Notificações no ambiente de trabalho",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas as categorias",
+  "notifications.column_settings.filter_bar.category": "Barra de filtros rápidos",
   "notifications.column_settings.follow": "Novos seguidores:",
   "notifications.column_settings.follow_request": "Novos pedidos de seguidor:",
   "notifications.column_settings.mention": "Menções:",
@@ -587,6 +590,12 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "A carregar…",
   "regeneration_indicator.sublabel": "A tua página inicial está a ser preparada!",
+  "relationship_severance_notification.purged_data": "purgado pelos administradores",
+  "relationship_severance_notification.relationships": "{count, plural,one {# relação} other {# relações}}",
+  "relationship_severance_notification.types.account_suspension": "A conta foi suspensa",
+  "relationship_severance_notification.types.domain_block": "O domínio foi suspenso",
+  "relationship_severance_notification.types.user_domain_block": "Bloqueou este domínio",
+  "relationship_severance_notification.view": "Visualizar",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural,one {# dia} other {# dias}} atrás",
   "relative_time.full.hours": "{number, plural,one {# hora}other {# horas}} atrás",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index dd21d3030..0ab147569 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -406,6 +406,7 @@
   "loading_indicator.label": "Načítavanie…",
   "media_gallery.toggle_visible": "{number, plural, one {Skryť obrázok} other {Skryť obrázky}}",
   "moved_to_account_banner.text": "Váš účet {disabledAccount} je momentálne deaktivovaný, pretože ste sa presunuli na {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Ukryť z upozornení",
   "mute_modal.hide_options": "Skryť možnosti",
   "mute_modal.show_options": "Zobraziť možnosti",
   "mute_modal.title": "Stíšiť užívateľa?",
@@ -456,6 +457,7 @@
   "notifications.column_settings.admin.sign_up": "Nové registrácie:",
   "notifications.column_settings.alert": "Upozornenia na ploche",
   "notifications.column_settings.favourite": "Ohviezdičkované:",
+  "notifications.column_settings.filter_bar.advanced": "Zobraziť všetky kategórie",
   "notifications.column_settings.follow": "Nové sledovania od:",
   "notifications.column_settings.follow_request": "Nové žiadosti o sledovanie od:",
   "notifications.column_settings.mention": "Označenia:",
@@ -555,6 +557,7 @@
   "refresh": "Obnoviť",
   "regeneration_indicator.label": "Načítavanie…",
   "regeneration_indicator.sublabel": "Váš domovský kanál sa pripravuje.",
+  "relationship_severance_notification.types.user_domain_block": "Túto doménu si zablokoval/a",
   "relationship_severance_notification.view": "Zobraziť",
   "relative_time.days": "{number} dní",
   "relative_time.full.days": "Pred {number, plural, one {# dňom} other {# dňami}}",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index a5122d098..d69231d82 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -483,6 +483,8 @@
   "notifications.column_settings.admin.sign_up": "Regjistrime të reja:",
   "notifications.column_settings.alert": "Njoftime desktopi",
   "notifications.column_settings.favourite": "Të parapëlqyer:",
+  "notifications.column_settings.filter_bar.advanced": "Shfaq krejt kategoritë",
+  "notifications.column_settings.filter_bar.category": "Shtyllë filtrimesh të shpejta",
   "notifications.column_settings.follow": "Ndjekës të rinj:",
   "notifications.column_settings.follow_request": "Kërkesa të reja për ndjekje:",
   "notifications.column_settings.mention": "Përmendje:",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 016007f49..b28b4826d 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -471,6 +471,7 @@
   "notifications.column_settings.admin.sign_up": "Nya registreringar:",
   "notifications.column_settings.alert": "Skrivbordsaviseringar",
   "notifications.column_settings.favourite": "Favoriter:",
+  "notifications.column_settings.filter_bar.advanced": "Visa alla kategorier",
   "notifications.column_settings.follow": "Nya följare:",
   "notifications.column_settings.follow_request": "Ny följ-förfrågan:",
   "notifications.column_settings.mention": "Omnämningar:",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index ce3b4eaa2..4490f038c 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "การสำรวจความคิดเห็นของคุณได้สิ้นสุดแล้ว",
   "notification.poll": "การสำรวจความคิดเห็นที่คุณได้ลงคะแนนได้สิ้นสุดแล้ว",
   "notification.reblog": "{name} ได้ดันโพสต์ของคุณ",
+  "notification.severed_relationships": "ตัดขาดความสัมพันธ์กับ {name} แล้ว",
   "notification.status": "{name} เพิ่งโพสต์",
   "notification.update": "{name} ได้แก้ไขโพสต์",
   "notification_requests.accept": "ยอมรับ",
@@ -483,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "การลงทะเบียนใหม่:",
   "notifications.column_settings.alert": "การแจ้งเตือนบนเดสก์ท็อป",
   "notifications.column_settings.favourite": "รายการโปรด:",
+  "notifications.column_settings.filter_bar.advanced": "แสดงหมวดหมู่ทั้งหมด",
+  "notifications.column_settings.filter_bar.category": "แถบตัวกรองด่วน",
   "notifications.column_settings.follow": "ผู้ติดตามใหม่:",
   "notifications.column_settings.follow_request": "คำขอติดตามใหม่:",
   "notifications.column_settings.mention": "การกล่าวถึง:",
@@ -587,6 +590,12 @@
   "refresh": "รีเฟรช",
   "regeneration_indicator.label": "กำลังโหลด…",
   "regeneration_indicator.sublabel": "กำลังเตรียมฟีดหน้าแรกของคุณ!",
+  "relationship_severance_notification.purged_data": "ล้างข้อมูลโดยผู้ดูแล",
+  "relationship_severance_notification.relationships": "{count, plural, other {# ความสัมพันธ์}}",
+  "relationship_severance_notification.types.account_suspension": "ระงับบัญชีแล้ว",
+  "relationship_severance_notification.types.domain_block": "ระงับโดเมนแล้ว",
+  "relationship_severance_notification.types.user_domain_block": "คุณได้ปิดกั้นโดเมนนี้",
+  "relationship_severance_notification.view": "ดู",
   "relative_time.days": "{number} วัน",
   "relative_time.full.days": "{number, plural, other {# วัน}}ที่แล้ว",
   "relative_time.full.hours": "{number, plural, other {# ชั่วโมง}}ที่แล้ว",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 799400ea3..12d82c70e 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "Yeni kayıtlar:",
   "notifications.column_settings.alert": "Masaüstü bildirimleri",
   "notifications.column_settings.favourite": "Favorilerin:",
+  "notifications.column_settings.filter_bar.advanced": "Tüm kategorileri görüntüle",
+  "notifications.column_settings.filter_bar.category": "Hızlı filtre çubuğu",
   "notifications.column_settings.follow": "Yeni takipçiler:",
   "notifications.column_settings.follow_request": "Yeni takip istekleri:",
   "notifications.column_settings.mention": "Değinmeler:",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 3456327a6..f2e58f093 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -473,6 +473,8 @@
   "notifications.column_settings.admin.sign_up": "Нові реєстрації:",
   "notifications.column_settings.alert": "Сповіщення стільниці",
   "notifications.column_settings.favourite": "Уподобане:",
+  "notifications.column_settings.filter_bar.advanced": "Показати всі категорії",
+  "notifications.column_settings.filter_bar.category": "Панель швидкого фільтру",
   "notifications.column_settings.follow": "Нові підписники:",
   "notifications.column_settings.follow_request": "Нові запити на підписку:",
   "notifications.column_settings.mention": "Згадки:",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index cc68ab762..52a98d000 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "新注册:",
   "notifications.column_settings.alert": "桌面通知",
   "notifications.column_settings.favourite": "喜欢:",
+  "notifications.column_settings.filter_bar.advanced": "显示所有类别",
+  "notifications.column_settings.filter_bar.category": "快速筛选栏",
   "notifications.column_settings.follow": "新粉丝:",
   "notifications.column_settings.follow_request": "新关注请求:",
   "notifications.column_settings.mention": "提及:",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 44a1435b2..68be293df 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "你的投票已結束",
   "notification.poll": "你參與過的一個投票已經結束",
   "notification.reblog": "{name} 轉推你的文章",
+  "notification.severed_relationships": "已斷絕與 {name} 的關係",
   "notification.status": "{name} 剛發表了文章",
   "notification.update": "{name} 編輯了帖文",
   "notification_requests.accept": "接受",
@@ -587,6 +588,12 @@
   "refresh": "重新整理",
   "regeneration_indicator.label": "載入中……",
   "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!",
+  "relationship_severance_notification.purged_data": "已被管理員清除",
+  "relationship_severance_notification.relationships": "{count, plural, one {# 個關係} other {# 個關係}}",
+  "relationship_severance_notification.types.account_suspension": "帳號已被停權",
+  "relationship_severance_notification.types.domain_block": "網域已被停權",
+  "relationship_severance_notification.types.user_domain_block": "你封鎖了此網域",
+  "relationship_severance_notification.view": "查看",
   "relative_time.days": "{number}日前",
   "relative_time.full.days": "{number, plural, one {# 天} other {# 天}}前",
   "relative_time.full.hours": "{number, plural, one {# 小時} other {# 小時}}前",
@@ -697,6 +704,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} 次} other {{count} 次}}",
   "status.embed": "嵌入",
   "status.favourite": "最愛",
+  "status.favourites": "{count, plural, one {則最愛} other {則最愛}}",
   "status.filter": "篩選此帖文",
   "status.filtered": "已過濾",
   "status.hide": "隱藏帖文",
@@ -717,6 +725,7 @@
   "status.reblog": "轉推",
   "status.reblog_private": "轉推到原讀者",
   "status.reblogged_by": "{name} 轉推",
+  "status.reblogs": "{count, plural, one {則轉推} other {則轉推}}",
   "status.reblogs.empty": "還未有人轉推。有的話會顯示在這裡。",
   "status.redraft": "刪除並編輯",
   "status.remove_bookmark": "移除書籤",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 228430dd8..d8e1e1e32 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -484,6 +484,8 @@
   "notifications.column_settings.admin.sign_up": "新註冊帳號:",
   "notifications.column_settings.alert": "桌面通知",
   "notifications.column_settings.favourite": "最愛:",
+  "notifications.column_settings.filter_bar.advanced": "顯示所有分類",
+  "notifications.column_settings.filter_bar.category": "快速過濾器",
   "notifications.column_settings.follow": "新的跟隨者:",
   "notifications.column_settings.follow_request": "新的跟隨請求:",
   "notifications.column_settings.mention": "提及:",
diff --git a/config/locales/be.yml b/config/locales/be.yml
index 63f605e9f..cdfc9cb39 100644
--- a/config/locales/be.yml
+++ b/config/locales/be.yml
@@ -1712,6 +1712,14 @@ be:
     strikes: Папярэджанні мадэратараў
     two_factor_authentication: Двухфактарная аўтэнтыфікацыя
     webauthn_authentication: Ключы бяспекі
+  severed_relationships:
+    download: Спампаваць (%{count})
+    event_type:
+      user_domain_block: Вы заблакіравалі %{target_name}
+    lost_followers: Страчаныя падпісчыкі
+    lost_follows: Страчаныя падпіскі
+    preamble: Вы можаце страціць падпіскі і падпісчыкаў, калі заблакіруеце дамен або калі вашы мадэратары вырашаць прыпыніць зносіны з серверам. Калі гэта адбудзецца, вы зможаце загрузіць спіс страчаных зносін, каб праверыць іх і, магчыма, імпартаваць на іншы сервер.
+    type: Падзея
   statuses:
     attached:
       audio:
diff --git a/config/locales/devise.hu.yml b/config/locales/devise.hu.yml
index 8c9fdf6a5..459bd01d9 100644
--- a/config/locales/devise.hu.yml
+++ b/config/locales/devise.hu.yml
@@ -54,7 +54,7 @@ hu:
         title: Kétlépcsős hitelesítés kikapcsolva
       two_factor_enabled:
         explanation: Egy párosított TOTP appal generált tokenre lesz szükség a bejelentkezéshez.
-        subject: 'Mastodon: Kétlépcsős azonosítás engedélyezve'
+        subject: 'Mastodon: kétlépcsős hitelesítés engedélyezve'
         subtitle: A kétlépcsős hitelesítés a fiókodhoz aktiválva lett.
         title: Kétlépcsős hitelesítés engedélyezve
       two_factor_recovery_codes_changed:
diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml
index 4559dcbd3..f03f6b58b 100644
--- a/config/locales/doorkeeper.hu.yml
+++ b/config/locales/doorkeeper.hu.yml
@@ -38,7 +38,7 @@ hu:
         application: Alkalmazás
         callback_url: Visszahívási URL
         delete: Eltávolítás
-        empty: Nincsenek saját alkalmazások.
+        empty: Nincsenek saját alkalmazásaid.
         name: Név
         new: Új alkalmazás
         scopes: Hatókörök
@@ -129,7 +129,7 @@ hu:
         crypto: Végpontok közti titkosítás
         favourites: Kedvencek
         filters: Szűrők
-        follow: Követések, Némítások és Letiltások
+        follow: Követések, némítások és letiltások
         follows: Követések
         lists: Listák
         media: Médiamellékletek
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index fd53f9d4f..e10183be1 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -1046,7 +1046,7 @@ es-AR:
     apply_for_account: Solicitar una cuenta
     captcha_confirmation:
       help_html: Si tenés problemas resolviendo la CAPTCHA, podés ponerte en contacto con nosotros a través de %{email} y te vamos a ayudar.
-      hint_html: ¡Sólo una cosa más! Necesitamos confirmar que sos humano (¡esto es para que podamos mantener el spam fuera!). Resuelvé la CAPTCHA abajo y hacé clic en "Continuar".
+      hint_html: ¡Solo una cosa más! Necesitamos confirmar que sos humano (¡esto es para que podamos mantener el spam fuera!). Resolvé la CAPTCHA abajo y hacé clic en "Continuar".
       title: Comprobación de seguridad
     confirmations:
       awaiting_review: "¡Tu dirección de correo electrónico fue confirmada! El equipo de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico si aprueban tu cuenta!"
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index 24b4af7ec..f497de568 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -1659,10 +1659,22 @@ es-MX:
     preferences: Preferencias
     profile: Perfil
     relationships: Siguiendo y seguidores
+    severed_relationships: Relaciones cortadas
     statuses_cleanup: Eliminación automática de publicaciones
     strikes: Amonestaciones de moderación
     two_factor_authentication: Autenticación de dos factores
     webauthn_authentication: Claves de seguridad
+  severed_relationships:
+    download: Descargar (%{count})
+    event_type:
+      account_suspension: Suspensión de cuenta (%{target_name})
+      domain_block: Suspensión del servidor (%{target_name})
+      user_domain_block: Bloqueaste %{target_name}
+    lost_followers: Seguidores perdidos
+    lost_follows: Cuentas seguidas perdidas
+    preamble: Puedes perder cuentas seguidas y seguidores cuando bloqueas un dominio o cuando tus moderadores deciden suspender un servidor remoto. Cuando esto suceda, podrás descargar listas de relaciones cortadas, para ser inspeccionadas y posiblemente importadas en otro servidor.
+    purged: La información sobre este servidor ha sido purgada por los administradores de tu servidor.
+    type: Suceso
   statuses:
     attached:
       audio:
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 22ee45d3b..b5b98bb88 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -1659,10 +1659,22 @@ es:
     preferences: Preferencias
     profile: Perfil
     relationships: Siguiendo y seguidores
+    severed_relationships: Relaciones cortadas
     statuses_cleanup: Eliminación automática de publicaciones
     strikes: Amonestaciones de moderación
     two_factor_authentication: Autenticación de dos factores
     webauthn_authentication: Claves de seguridad
+  severed_relationships:
+    download: Descargar (%{count})
+    event_type:
+      account_suspension: Suspensión de cuenta (%{target_name})
+      domain_block: Suspensión del servidor (%{target_name})
+      user_domain_block: Bloqueaste %{target_name}
+    lost_followers: Seguidores perdidos
+    lost_follows: Cuentas seguidas perdidas
+    preamble: Puedes perder cuentas seguidas y seguidores cuando bloqueas un dominio o cuando tus moderadores deciden suspender un servidor remoto. Cuando esto suceda, podrás descargar listas de relaciones cortadas, para ser inspeccionadas y posiblemente importadas en otro servidor.
+    purged: La información sobre este servidor ha sido purgada por los administradores de tu servidor.
+    type: Suceso
   statuses:
     attached:
       audio:
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 4ea0a9652..e29ce3752 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -139,7 +139,7 @@ hu:
         only_password: Csak jelszó
         password_and_2fa: Jelszó és kétlépcsős hitelesítés
       sensitive: Kényes
-      sensitized: kényesnek jelölve
+      sensitized: Kényesnek jelölve
       shared_inbox_url: Megosztott bejövő üzenetek URL
       show:
         created_reports: Létrehozott jelentések
@@ -257,7 +257,7 @@ hu:
         destroy_status_html: "%{name} eltávolította %{target} felhasználó bejegyzését"
         destroy_unavailable_domain_html: "%{name} újraindította a kézbesítést a %{target} domainbe"
         destroy_user_role_html: "%{name} törölte a(z) %{target} szerepkört"
-        disable_2fa_user_html: "%{name} kikapcsolta a kétlépcsős azonosítást %{target} felhasználó fiókján"
+        disable_2fa_user_html: "%{name} kikapcsolta a kétlépcsős hitelesítést %{target} felhasználó fiókján"
         disable_custom_emoji_html: "%{name} letiltotta az emodzsit: %{target}"
         disable_sign_in_token_auth_user_html: "%{name} letiltotta a tokenes e-mail hitelesítést %{target} felhasználóra"
         disable_user_html: "%{name} letiltotta %{target} felhasználó bejelentkezését"
@@ -716,7 +716,7 @@ hu:
         manage_taxonomies: Taxonómiák kezelése
         manage_taxonomies_description: Lehetővé teszi, hogy a felhasználó átnézze a felkapott tartalmakat és frissítse a hashtagek beállításait
         manage_user_access: Felhasználói hozzáférések kezelése
-        manage_user_access_description: Lehetővé teszi, hogy a felhasználó letiltsa mások kétlépcsős azonosítását, megváltoztassa az email címüket, és alaphelyzetbe állítsa a jelszavukat
+        manage_user_access_description: Lehetővé teszi, hogy a felhasználó letiltsa mások kétlépcsős hitelesítését, megváltoztassa az e-mail-címüket, és alaphelyzetbe állítsa a jelszavukat
         manage_users: Felhasználók kezelése
         manage_users_description: Lehetővé teszi, hogy a felhasználó megtekintse mások részletes adatait és moderálja őket
         manage_webhooks: Webhookok kezelése
@@ -1057,7 +1057,7 @@ hu:
       redirect_to_app_html: Át kellett volna irányítsunk a <strong>%{app_name}</strong> alkalmazáshoz. Ha ez nem történt meg, próbálkozz a %{clicking_this_link} lehetőséggel vagy térj vissza manuálisan az alkalmazáshoz.
       registration_complete: A regisztrációd %{domain} domainen befejeződött!
       welcome_title: Üdvözlet, %{name}!
-      wrong_email_hint: Ha az emailcím nem helyes, a fiókbeállításokban megváltoztathatod.
+      wrong_email_hint: Ha az e-mail-cím nem helyes, a fiókbeállításokban megváltoztathatod.
     delete_account: Felhasználói fiók törlése
     delete_account_html: Felhasználói fiókod törléséhez <a href="%{path}">kattints ide</a>. A rendszer újbóli megerősítést fog kérni.
     description:
@@ -1074,7 +1074,7 @@ hu:
     login: Bejelentkezés
     logout: Kijelentkezés
     migrate_account: Felhasználói fiók költöztetése
-    migrate_account_html: Ha szeretnéd átirányítani ezt a fiókodat egy másikra, a beállításokat <a href="%{path}">itt találod meg</a>.
+    migrate_account_html: Ha át szeretnéd irányítani ezt a fiókodat egy másikra, akkor <a href="%{path}">itt állíthatod be</a>.
     or_log_in_with: Vagy jelentkezz be ezzel
     privacy_policy_agreement_html: Elolvastam és egyetértek az <a href="%{privacy_policy_path}" target="_blank">adatvédemi nyilatkozattal</a>
     progress:
@@ -1133,7 +1133,7 @@ hu:
       invalid_signature: érvénytelen Ed25519 aláírás
   date:
     formats:
-      default: "%Y.%b.%d."
+      default: "%Y. %b %d."
       with_month_name: "%Y. %B %d"
   datetime:
     distance_in_words:
@@ -1223,17 +1223,17 @@ hu:
   exports:
     archive_takeout:
       date: Dátum
-      download: Archív letöltése
+      download: Archívum letöltése
       hint_html: Itt kérhető egy archív az összes <strong>feltöltött bejegyzésedről és médiádról</strong>. Az exportált adatok ActivityPub formátumban lesznek, melyet bármilyen szabványos program tud olvasni. 7 naponként kérhetsz ilyen archívot.
-      in_progress: Archív összeállítása...
-      request: Archív kérése
+      in_progress: Archívum összeállítása…
+      request: Archívum kérése
       size: Méret
-    blocks: Tiltólistádon
-    bookmarks: Könyvjelzők
+    blocks: Tiltás
+    bookmarks: Könyvjelző
     csv: CSV
-    domain_blocks: Tiltott domainjeid
-    lists: Listáid
-    mutes: Némításaid
+    domain_blocks: Tiltott domain
+    lists: Lista
+    mutes: Némítás
     storage: Médiatároló
   featured_tags:
     add_new: Új hozzáadása
@@ -1413,7 +1413,7 @@ hu:
           follow_request: követési kérelemről email értesítő
           mention: megemlítésről email értesítő
           reblog: megtolásról email értesítő
-      resubscribe_html: Ha tévedésből iratkoztál le, újra feliratkozhatsz az <a href="%{settings_path}">email értesítések beállításainál</a>.
+      resubscribe_html: Ha tévedésből iratkoztál le, újra feliratkozhatsz az <a href="%{settings_path}">e-mail-értesítések beállításainál</a>.
       success_html: 'Mostantól nem kapsz %{type} típusú üzeneket a(z) %{domain} Mastodon-kiszolgálón erre a címedre: %{email}.'
       title: Leiratkozás
   media_attachments:
@@ -1496,7 +1496,7 @@ hu:
       subject: "%{name} szerkesztett egy bejegyzést"
   notifications:
     administration_emails: Adminisztrátori e-mail-értesítések
-    email_events: Események email értesítésekhez
+    email_events: Az e-mail-értesítések eseményei
     email_events_hint: 'Válaszd ki azokat az eseményeket, melyekről értesítést szeretnél:'
   number:
     human:
@@ -1510,7 +1510,7 @@ hu:
           trillion: T
   otp_authentication:
     code_hint: Jóváhagyáshoz írd be a hitelesítő alkalmazás által generált kódot
-    description_html: Ha engedélyezed a <strong>kétlépcsős azonosítást</strong>, a bejelentkezéshez szükséged lesz a telefonodra és egy alkalmazásra, amely hozzáférési kódot generál számodra.
+    description_html: Ha engedélyezed a <strong>kétlépcsős hitelesítést</strong>, akkor a bejelentkezéshez szükséged lesz a telefonodra és egy alkalmazásra, amely hozzáférési kódokat állít elő a belépéshez.
     enable: Engedélyezés
     instructions_html: "<strong>Olvasd be ezt a QR-kódot a telefonodon futó Google Authenticator vagy egyéb TOTP alkalmazással</strong>. A jövőben ez az alkalmazás fog számodra hozzáférési kódot generálni a belépéshez."
     manual_instructions: 'Ha nem sikerült a QR-kód beolvasása, itt a szöveges kulcs, amelyet manuálisan kell begépelned:'
@@ -1639,10 +1639,10 @@ hu:
     revoke: Visszavonás
     revoke_success: Munkamenet sikeresen visszavonva
     title: Munkamenetek
-    view_authentication_history: Fiókod hitelesítési történetének megtekintése
+    view_authentication_history: Fiók hitelesítési előzményeinek megtekintése
   settings:
     account: Fiók
-    account_settings: Fiók beállítások
+    account_settings: Fiókbeállítások
     aliases: Fiók aliasok
     appearance: Megjelenés
     authorized_apps: Jóváhagyott alkalmazások
@@ -1740,7 +1740,7 @@ hu:
     keep_polls: Szavazások megtartása
     keep_polls_hint: Egyetlen szavazásodat sem törli
     keep_self_bookmark: Általad könyvjelzőzött bejegyzések megtartása
-    keep_self_bookmark_hint: Egyetlen olyan bejegyzésedet sem törli, melyet könyvjelzővel láttál el
+    keep_self_bookmark_hint: Egyetlen olyan bejegyzésedet sem törli, melyet könyvjelzőztél
     keep_self_fav: Kedvenc bejegyzések megtartása
     keep_self_fav_hint: Nem törli azon bejegyzéseidet, melyeket kedvencnek jelöltél
     min_age:
@@ -1781,10 +1781,10 @@ hu:
   two_factor_authentication:
     add: Hozzáadás
     disable: Kikapcsolás
-    disabled_success: A kétlépcsős azonosítást sikeresen letiltottuk
+    disabled_success: A kétlépcsős hitelesítés sikeresen letiltva
     edit: Szerkesztés
-    enabled: Kétlépcsős azonosítás engedélyezve
-    enabled_success: A kétlépcsős azonosítást sikeresen engedélyezted
+    enabled: Kétlépcsős hitelesítés engedélyezve
+    enabled_success: A kétlépcsős hitelesítés sikeresen engedélyezve
     generate_recovery_codes: Visszaállítási kódok generálása
     lost_recovery_codes: A visszaállítási kódok segítségével tudsz belépni, ha elveszítenéd a telefonod. Ha a visszaállítási kódjaidat hagytad el, itt generálhatsz újakat. A régi kódokat ebben az esetben érvénytelenítjük.
     methods: Kétlépcsős eljárások
@@ -1925,5 +1925,5 @@ hu:
     nickname_hint: Írd be az új biztonsági kulcsod becenevét
     not_enabled: Még nem engedélyezted a WebAuthn-t
     not_supported: Ez a böngésző nem támogatja a biztonsági kulcsokat
-    otp_required: A biztonsági kulcsok használatához először engedélyezd a kétlépcsős azonosítást.
+    otp_required: A biztonsági kulcsok használatához először engedélyezd a kétlépcsős hitelesítést.
     registered_on: 'Regisztráció ekkor: %{date}'
diff --git a/config/locales/is.yml b/config/locales/is.yml
index 710b35fce..fdf54030a 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -1666,6 +1666,9 @@ is:
     strikes: Umsýsla refsinga
     two_factor_authentication: Tveggja-þátta auðkenning
     webauthn_authentication: Öryggislyklar
+  severed_relationships:
+    download: Sækja (%{count})
+    type: Atburður
   statuses:
     attached:
       audio:
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 19b2e94db..b7c6813a7 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -585,6 +585,9 @@ ja:
       actions_description_html: このレポートを解決するために取るアクションを決定します。 報告されたアカウントに対して懲罰的な措置を取った場合、メール通知が送信されますが<strong>スパム</strong>カテゴリが選択されている場合を除きます。
       actions_description_remote_html: この通報を解決するためのアクションを選択してください。これは<strong>あなたの</strong>サーバーがこのリモートアカウントと通信し、そのコンテンツを処理する時のみ影響します。
       add_to_report: 通報にさらに追加
+      already_suspended_badges:
+        local: このサーバーで停止済み
+        remote: リモートのサーバーで停止済み
       are_you_sure: 本当に実行しますか?
       assign_to_self: 担当になる
       assigned: 担当者
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index c556c9e81..9548c4e44 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -14,7 +14,7 @@ ko:
     instance_actor_flash: 이 계정은 서버 자신을 나타내기 위한 가상의 계정이며 개인 사용자가 아닙니다. 이 계정은 연합을 위해 사용되며 정지되지 않아야 합니다.
     last_active: 최근 활동
     link_verified_on: "%{date}에 이 링크의 소유가 확인되었습니다"
-    nothing_here: 텅 비어있네요!
+    nothing_here: 아무 것도 없습니다!
     pin_errors:
       following: 추천하려는 사람을 팔로우 하고 있어야 합니다
     posts:
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 44b5443fc..832d9e9db 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -509,7 +509,7 @@ lt:
     software_updates:
       description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku naujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra atnaujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis.
     statuses:
-      back_to_account: Atgal į paskyros puslapį
+      back_to_account: Grįžti į paskyros puslapį
       media:
         title: Medija
       no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta
@@ -741,16 +741,24 @@ lt:
     browser: Naršyklė
     browsers:
       generic: Nežinoma naršyklė
-    current_session: Dabartinė sesija
+    current_session: Dabartinis seansas
     date: Data
     description: "%{browser} ant %{platform}"
     explanation: Čia rodomos web naršyklės prijungtos prie Jūsų Mastodon paskyros.
+    platforms:
+      android: Android
+      ios: iOS
+      kai_os: KaiOS
+      mac: macOS
+      windows: Windows
+      windows_mobile: Windows Mobile
+      windows_phone: Windows Phone
     revoke: Atšaukti
-    revoke_success: Sesija sėkmingai atšaukta
-    title: Sesijos
+    revoke_success: Seansas sėkmingai panaikintas.
+    title: Seansai
   settings:
     authorized_apps: Autorizuotos aplikacijos
-    back: Atgal į Mastodon
+    back: Grįžti į Mastodon
     delete: Paskyros trynimas
     development: Plėtojimas
     edit_profile: Keisti profilį
@@ -758,6 +766,7 @@ lt:
     featured_tags: Rodomi saitažodžiai(#)
     import: Importuoti
     migrate: Paskyros migracija
+    notifications: El. laiško pranešimai
     preferences: Preferencijos
     two_factor_authentication: Dviejų veiksnių autentikacija
   statuses:
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index 9dde61ff0..666eb0bdd 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -1659,10 +1659,22 @@ pt-PT:
     preferences: Preferências
     profile: Perfil
     relationships: Seguindo e seguidores
+    severed_relationships: Relações cessadas
     statuses_cleanup: Remoção automática da publicação
     strikes: Punições de moderação
     two_factor_authentication: Autenticação em duas etapas
     webauthn_authentication: Chaves de segurança
+  severed_relationships:
+    download: Transferir (%{count})
+    event_type:
+      account_suspension: Suspensão de conta (%{target_name})
+      domain_block: Suspensão de servidor (%{target_name})
+      user_domain_block: Bloqueou %{target_name}
+    lost_followers: Seguidores perdidos
+    lost_follows: Pessoas que segue perdidas
+    preamble: Pode perder seguidores e pessoas que segue quando bloqueia um domínio ou quando os seus moderadores decidem suspender um servidor remoto. Quando isso acontecer, poderá descarregar listas de relações cessadas, para serem inspeccionadas e possivelmente importadas para outro servidor.
+    purged: Informações sobre este servidor foram purgadas pelos administradores do seu servidor.
+    type: Evento
   statuses:
     attached:
       audio:
diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml
index 1d5e14933..242c86327 100644
--- a/config/locales/simple_form.hu.yml
+++ b/config/locales/simple_form.hu.yml
@@ -54,11 +54,11 @@ hu:
         phrase: Illeszkedni fog kis/nagybetű függetlenül, és tartalmi figyelmeztetések mögött is
         scopes: Mely API-kat érheti el az alkalmazás. Ha felső szintű hatáskört választasz, nem kell egyesével kiválasztanod az alatta lévőeket.
         setting_aggregate_reblogs: Ne mutassunk megtolásokat olyan bejegyzésekhez, melyeket nemrég toltak meg (csak új megtolásokra lép életbe)
-        setting_always_send_emails: Alapesetben nem küldünk e-mail értesítéseket, ha aktívan használod a Mastodont
+        setting_always_send_emails: Alapesetben nem küldünk e-mail-értesítéseket, ha aktívan használod a Mastodont
         setting_default_sensitive: A kényes médiatartalmat alapesetben elrejtjük, de egyetlen kattintással előhozható
         setting_display_media_default: Kényes tartalomnak jelölt média elrejtése
-        setting_display_media_hide_all: Mindig minden média elrejtése
-        setting_display_media_show_all: Mindig mutasd a szenzitív tartalomként jelölt médiát
+        setting_display_media_hide_all: Média elrejtése mindig
+        setting_display_media_show_all: Média megjelenítése mindig
         setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt
         setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett
         username: Betűk, számok és alávonások használhatók
@@ -146,7 +146,7 @@ hu:
           name: Címke
           value: Tartalom
         indexable: Nyilvános bejegyzések szerepeltetése a keresési eredményekben
-        show_collections: Követők és követettek megjelnítése a profilban
+        show_collections: Követők és követettek megjelenítése a profilban
         unlocked: Új követők automatikus elfogadása
       account_alias:
         acct: A régi fiók fiókneve
@@ -187,7 +187,7 @@ hu:
         data: Adatok
         display_name: Megjelenített név
         email: E-mail cím
-        expires_in: Elévül
+        expires_in: Elévülés dátuma
         fields: Profil metaadatai
         header: Fejléc
         honeypot: "%{label} (ne töltsd ki)"
@@ -202,7 +202,7 @@ hu:
         phrase: Kulcsszó vagy kifejezés
         setting_advanced_layout: Speciális webes felület engedélyezése
         setting_aggregate_reblogs: Megtolások csoportosítása az idővonalakon
-        setting_always_send_emails: E-mail értesítések küldése mindig
+        setting_always_send_emails: E-mail-értesítések küldése mindig
         setting_auto_play_gif: GIF-ek automatikus lejátszása
         setting_boost_modal: Megerősítés kérése megtolás előtt
         setting_default_language: Bejegyzések nyelve
diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml
index df108a2fe..2f2107b13 100644
--- a/config/locales/simple_form.nl.yml
+++ b/config/locales/simple_form.nl.yml
@@ -149,9 +149,9 @@ nl:
         show_collections: Accounts die jij volgt en die jou volgen op je profiel tonen
         unlocked: Automatisch nieuwe volgers accepteren
       account_alias:
-        acct: Mastodon-adres van het oude account
+        acct: Fediverse-adres van het oude account
       account_migration:
-        acct: Mastodon-adres van het nieuwe account
+        acct: Fediverse-adres van het nieuwe account
       account_warning_preset:
         text: Tekst van preset
         title: Titel
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 558552362..69bae8767 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -1633,10 +1633,21 @@ th:
     preferences: การกำหนดลักษณะ
     profile: โปรไฟล์สาธารณะ
     relationships: การติดตามและผู้ติดตาม
+    severed_relationships: ความสัมพันธ์ที่ตัดขาด
     statuses_cleanup: การลบโพสต์แบบอัตโนมัติ
     strikes: การดำเนินการการกลั่นกรอง
     two_factor_authentication: การรับรองความถูกต้องด้วยสองปัจจัย
     webauthn_authentication: กุญแจความปลอดภัย
+  severed_relationships:
+    download: ดาวน์โหลด (%{count})
+    event_type:
+      account_suspension: การระงับบัญชี (%{target_name})
+      domain_block: การระงับเซิร์ฟเวอร์ (%{target_name})
+      user_domain_block: คุณได้ปิดกั้น %{target_name}
+    lost_followers: ผู้ติดตามที่หายไป
+    lost_follows: การติดตามที่หายไป
+    purged: มีการล้างข้อมูลเกี่ยวกับเซิร์ฟเวอร์นี้โดยผู้ดูแลของเซิร์ฟเวอร์ของคุณ
+    type: เหตุการณ์
   statuses:
     attached:
       audio:
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 2a0f802a1..af2b3b869 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -1626,13 +1626,26 @@ zh-HK:
     import: 匯入
     import_and_export: 匯入及匯出
     migrate: 帳戶遷移
+    notifications: 電郵通知
     preferences: 偏好設定
     profile: 個人資料
     relationships: 關注及追隨者
+    severed_relationships: 已切斷關係
     statuses_cleanup: 自動嘟文刪除
     strikes: 審核警告
     two_factor_authentication: 雙重認證
     webauthn_authentication: 安全鑰匙
+  severed_relationships:
+    download: 下載 (%{count})
+    event_type:
+      account_suspension: 停權帳號 (%{target_name})
+      domain_block: 停權伺服器 (%{target_name})
+      user_domain_block: 你封鎖了 %{target_name}
+    lost_followers: 已流失追蹤者
+    lost_follows: 已流失追蹤
+    preamble: 當你封鎖網域或你的管理員決定暫停遠端伺服器,可能會令你失去追蹤中的對象和追蹤者。屆時你可以下載紀錄了被切斷關係的對象的清單進行檢查,或將其匯入到另一台伺服器上。
+    purged: 有關此伺服器的資訊已被你伺服器的管理員清除。
+    type: 事件
   statuses:
     attached:
       audio:

From bbf36836b651f2d69ee2b1988989e46f73862ff9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 12:07:47 +0100
Subject: [PATCH 002/173] Update formatjs monorepo (#29733)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 13ea8583d..67a7876e1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2287,9 +2287,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@formatjs/intl@npm:2.10.0":
-  version: 2.10.0
-  resolution: "@formatjs/intl@npm:2.10.0"
+"@formatjs/intl@npm:2.10.1":
+  version: 2.10.1
+  resolution: "@formatjs/intl@npm:2.10.1"
   dependencies:
     "@formatjs/ecma402-abstract": "npm:1.18.2"
     "@formatjs/fast-memoize": "npm:2.2.0"
@@ -2303,7 +2303,7 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/7566038b011116cee7069165a25836b3fb687948e61b041809a9d978ac6c0882ae8d81a624a415cfb8e43852d097cd1cbc3c6707e717928e39b75c252491a712
+  checksum: 10c0/24eee77382d1efd226aee7590228d3ae80f66a8547a65295f8028986b15b6abbfea3e380f4a338ece0e841e1db6f36554ca48124d84c0830382e3a9d395b5d75
   languageName: node
   linkType: hard
 
@@ -5125,8 +5125,8 @@ __metadata:
   linkType: hard
 
 "babel-plugin-formatjs@npm:^10.5.1":
-  version: 10.5.13
-  resolution: "babel-plugin-formatjs@npm:10.5.13"
+  version: 10.5.14
+  resolution: "babel-plugin-formatjs@npm:10.5.14"
   dependencies:
     "@babel/core": "npm:^7.10.4"
     "@babel/helper-plugin-utils": "npm:^7.10.4"
@@ -5139,7 +5139,7 @@ __metadata:
     "@types/babel__helper-plugin-utils": "npm:^7.10.0"
     "@types/babel__traverse": "npm:^7.1.7"
     tslib: "npm:^2.4.0"
-  checksum: 10c0/1ce0b69478dd3c92126a7e3440f1fad46feebebc9318e8bbb102dea91a60448da4a8511b3c8ffbf2c3675995fca6c8ce7f097c08907455b33a5f9185e39fb94e
+  checksum: 10c0/78d33f0304c7b6e36334b2f32bacd144cbbe08cb22318ff994e7adc7705b7f8208354c9af9f87b4390d11aee1ea81cfee9f224a57fe5265173b92ee7de921359
   languageName: node
   linkType: hard
 
@@ -14317,12 +14317,12 @@ __metadata:
   linkType: hard
 
 "react-intl@npm:^6.4.2":
-  version: 6.6.2
-  resolution: "react-intl@npm:6.6.2"
+  version: 6.6.3
+  resolution: "react-intl@npm:6.6.3"
   dependencies:
     "@formatjs/ecma402-abstract": "npm:1.18.2"
     "@formatjs/icu-messageformat-parser": "npm:2.7.6"
-    "@formatjs/intl": "npm:2.10.0"
+    "@formatjs/intl": "npm:2.10.1"
     "@formatjs/intl-displaynames": "npm:6.6.6"
     "@formatjs/intl-listformat": "npm:7.5.5"
     "@types/hoist-non-react-statics": "npm:^3.3.1"
@@ -14336,7 +14336,7 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/78288a0fded816735812dca6dcfee3eaa8bb3af7e963ba47639b51cc700a102a526859ff647ca79a5ebcdc69d6d78da90daeeed15cc0b819c7a20a74b2e1469c
+  checksum: 10c0/8a924931668f1bf6364bb41c09fdb54972b8e3372f0768a31478dc3f8a846920caa4dc04ab3950195baa6dbf58a148f43a6a221d5795be2cbb6f4f374a5921d6
   languageName: node
   linkType: hard
 

From 45f8364cd110882a55bbef465064b8bd4d6b7f89 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 11:09:00 +0000
Subject: [PATCH 003/173] Update dependency typescript to v5.4.3 (#29744)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 67a7876e1..7ef202e09 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -17079,22 +17079,22 @@ __metadata:
   linkType: hard
 
 "typescript@npm:5, typescript@npm:^5.0.4":
-  version: 5.4.2
-  resolution: "typescript@npm:5.4.2"
+  version: 5.4.3
+  resolution: "typescript@npm:5.4.3"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/583ff68cafb0c076695f72d61df6feee71689568179fb0d3a4834dac343df6b6ed7cf7b6f6c801fa52d43cd1d324e2f2d8ae4497b09f9e6cfe3d80a6d6c9ca52
+  checksum: 10c0/22443a8760c3668e256c0b34b6b45c359ef6cecc10c42558806177a7d500ab1a7d7aac1f976d712e26989ddf6731d2fbdd3212b7c73290a45127c1c43ba2005a
   languageName: node
   linkType: hard
 
 "typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>":
-  version: 5.4.2
-  resolution: "typescript@patch:typescript@npm%3A5.4.2#optional!builtin<compat/typescript>::version=5.4.2&hash=5adc0c"
+  version: 5.4.3
+  resolution: "typescript@patch:typescript@npm%3A5.4.3#optional!builtin<compat/typescript>::version=5.4.3&hash=5adc0c"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/fcf6658073d07283910d9a0e04b1d5d0ebc822c04dbb7abdd74c3151c7aa92fcddbac7d799404e358197222006ccdc4c0db219d223d2ee4ccd9e2b01333b49be
+  checksum: 10c0/6e51f8b7e6ec55b897b9e56b67e864fe8f44e30f4a14357aad5dc0f7432db2f01efc0522df0b6c36d361c51f2dc3dcac5c832efd96a404cfabf884e915d38828
   languageName: node
   linkType: hard
 

From 55e2c827bdc7f96fc746ce43ea303f9e25805099 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 11:09:05 +0000
Subject: [PATCH 004/173] Update DefinitelyTyped types (non-major) (#29743)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 7ef202e09..a2bc439ee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3679,13 +3679,13 @@ __metadata:
   linkType: hard
 
 "@types/pg@npm:^8.6.6":
-  version: 8.11.2
-  resolution: "@types/pg@npm:8.11.2"
+  version: 8.11.4
+  resolution: "@types/pg@npm:8.11.4"
   dependencies:
     "@types/node": "npm:*"
     pg-protocol: "npm:*"
     pg-types: "npm:^4.0.1"
-  checksum: 10c0/6d873af7f71785d5d4db49311c5c73628918b2b1ece83f17073c4470b2fce6bd24a37de23a42ea0221df4e1c7dc43ea035bb9d0b6274f86ec692b21503a9a55c
+  checksum: 10c0/81158ffa9d2f9b2b299a1650756b90fc418e0040e654d7d9ee46734a3c874d07b638af86d765e22e9c8246054c30a0274ee4dea58a0a7ed5c0c4aa01964a09ef
   languageName: node
   linkType: hard
 
@@ -3697,9 +3697,9 @@ __metadata:
   linkType: hard
 
 "@types/prop-types@npm:*, @types/prop-types@npm:^15.7.5":
-  version: 15.7.11
-  resolution: "@types/prop-types@npm:15.7.11"
-  checksum: 10c0/e53423cf9d510515ef8b47ff42f4f1b65a7b7b37c8704e2dbfcb9a60defe0c0e1f3cb1acfdeb466bad44ca938d7c79bffdd51b48ffb659df2432169d0b27a132
+  version: 15.7.12
+  resolution: "@types/prop-types@npm:15.7.12"
+  checksum: 10c0/1babcc7db6a1177779f8fde0ccc78d64d459906e6ef69a4ed4dd6339c920c2e05b074ee5a92120fe4e9d9f1a01c952f843ebd550bee2332fc2ef81d1706878f8
   languageName: node
   linkType: hard
 
@@ -3842,13 +3842,13 @@ __metadata:
   linkType: hard
 
 "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
-  version: 18.2.66
-  resolution: "@types/react@npm:18.2.66"
+  version: 18.2.70
+  resolution: "@types/react@npm:18.2.70"
   dependencies:
     "@types/prop-types": "npm:*"
     "@types/scheduler": "npm:*"
     csstype: "npm:^3.0.2"
-  checksum: 10c0/56e4b841f2daf03a0b3268d4f2bcf5841167fe56742b9f1c076fad66587fb59191bdaba4d5727dbfbcff750d5e8797fdd4e57d8d9704b0bfc6ad31ee1e268a70
+  checksum: 10c0/2107b1fa8963cabe33d981cf1c0e3b7534c9d12b98c1046cd9f7975851690a0780db011f6a1d637ae4e612ef00c94ebdbe76a9e2f9e0f3baa6aad3213932af41
   languageName: node
   linkType: hard
 

From 766c1fea2036e2360a9b0620b9d83cc4722620e8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 13:14:46 +0100
Subject: [PATCH 005/173] Update devDependencies (non-major) (#29746)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 79 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 47 insertions(+), 32 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index a2bc439ee..5bf1095d8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1578,7 +1578,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/css-parser-algorithms@npm:^2.5.0, @csstools/css-parser-algorithms@npm:^2.6.1":
+"@csstools/css-parser-algorithms@npm:^2.6.1":
   version: 2.6.1
   resolution: "@csstools/css-parser-algorithms@npm:2.6.1"
   peerDependencies:
@@ -1587,14 +1587,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/css-tokenizer@npm:^2.2.3, @csstools/css-tokenizer@npm:^2.2.4":
+"@csstools/css-tokenizer@npm:^2.2.4":
   version: 2.2.4
   resolution: "@csstools/css-tokenizer@npm:2.2.4"
   checksum: 10c0/23997db5874514f4b951ebd215e1e6cc8baf03adf9a35fc6fd028b84cb52aa2dc053860722108c09859a9b37b455f62b84181fe15539cd37797ea699b9ff85f0
   languageName: node
   linkType: hard
 
-"@csstools/media-query-list-parser@npm:^2.1.7, @csstools/media-query-list-parser@npm:^2.1.9":
+"@csstools/media-query-list-parser@npm:^2.1.9":
   version: 2.1.9
   resolution: "@csstools/media-query-list-parser@npm:2.1.9"
   peerDependencies:
@@ -1970,7 +1970,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/selector-specificity@npm:^3.0.1, @csstools/selector-specificity@npm:^3.0.2":
+"@csstools/selector-specificity@npm:^3.0.2":
   version: 3.0.2
   resolution: "@csstools/selector-specificity@npm:3.0.2"
   peerDependencies:
@@ -1995,6 +1995,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@dual-bundle/import-meta-resolve@npm:^4.0.0":
+  version: 4.0.0
+  resolution: "@dual-bundle/import-meta-resolve@npm:4.0.0"
+  checksum: 10c0/868b8314fc753b7767887108535afe3288de941d92bc8453164dbcb1abe886b171e338f6f7d02ff556256dee69c90e4ac6360e0c6a856a5ad7190274ab52de2e
+  languageName: node
+  linkType: hard
+
 "@emotion/babel-plugin@npm:^11.11.0":
   version: 11.11.0
   resolution: "@emotion/babel-plugin@npm:11.11.0"
@@ -2192,8 +2199,8 @@ __metadata:
   linkType: hard
 
 "@formatjs/cli@npm:^6.1.1":
-  version: 6.2.7
-  resolution: "@formatjs/cli@npm:6.2.7"
+  version: 6.2.8
+  resolution: "@formatjs/cli@npm:6.2.8"
   peerDependencies:
     vue: ^3.3.4
   peerDependenciesMeta:
@@ -2201,7 +2208,7 @@ __metadata:
       optional: true
   bin:
     formatjs: bin/formatjs
-  checksum: 10c0/ee7b0873a734e02721ce1ee107ee60845bb30855f4ca686bfb6c5e9862353249d5d20748b18db93200aabc7a59875ff062f485c64d41cb8e61f1d43e2bb5eceb
+  checksum: 10c0/5d8f95434f4522eee7dd3acf54e5265289ec7e72812448cd7c7547bdedaba8927719800dfa2fc92fb82c609f34255367a80d18bf6c064540d5e11ec6b9d4603e
   languageName: node
   linkType: hard
 
@@ -3311,8 +3318,8 @@ __metadata:
   linkType: hard
 
 "@testing-library/react@npm:^14.0.0":
-  version: 14.2.1
-  resolution: "@testing-library/react@npm:14.2.1"
+  version: 14.2.2
+  resolution: "@testing-library/react@npm:14.2.2"
   dependencies:
     "@babel/runtime": "npm:^7.12.5"
     "@testing-library/dom": "npm:^9.0.0"
@@ -3320,7 +3327,7 @@ __metadata:
   peerDependencies:
     react: ^18.0.0
     react-dom: ^18.0.0
-  checksum: 10c0/83b35cf8bf5640f1b63b32223ebc75799dc1a8e034d819120b26838fba0b0ab10bdbe6ad07dd8ae8287365f2b0c52dc9892a6fa11bb24d3e63ad97dfb7f2f296
+  checksum: 10c0/ab36707f6701a4a56dd217e16e00d6326e0f760bb2e716245422c7500a0b94efcd351d0aa89c4fab2916e6ebc68c983cec6b3ae0804de813cafc913a612668f6
   languageName: node
   linkType: hard
 
@@ -9444,10 +9451,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.0":
-  version: 5.3.0
-  resolution: "ignore@npm:5.3.0"
-  checksum: 10c0/dc06bea5c23aae65d0725a957a0638b57e235ae4568dda51ca142053ed2c352de7e3bc93a69b2b32ac31966a1952e9a93c5ef2e2ab7c6b06aef9808f6b55b571
+"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1":
+  version: 5.3.1
+  resolution: "ignore@npm:5.3.1"
+  checksum: 10c0/703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd
   languageName: node
   linkType: hard
 
@@ -11150,6 +11157,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"known-css-properties@npm:^0.30.0":
+  version: 0.30.0
+  resolution: "known-css-properties@npm:0.30.0"
+  checksum: 10c0/8b487a6b33487affcec41eb392ceb77acf4d093558dde5c88b5ea06b9a3c81781876d7cb09872e0518b9602f27c8f4112c9ac333e02c90a91c8fbd12e202ed48
+  languageName: node
+  linkType: hard
+
 "language-subtag-registry@npm:^0.3.20":
   version: 0.3.22
   resolution: "language-subtag-registry@npm:0.3.22"
@@ -11641,10 +11655,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"meow@npm:^13.1.0":
-  version: 13.1.0
-  resolution: "meow@npm:13.1.0"
-  checksum: 10c0/2dac9dbf99a17ce29618fe5919072a9b28e2aedb9547f9b1f15d046d5501dd6c14fe1f35f7a5665d0ee7111c98c4d359fcf3f985463ec5896dd50177363f442d
+"meow@npm:^13.2.0":
+  version: 13.2.0
+  resolution: "meow@npm:13.2.0"
+  checksum: 10c0/d5b339ae314715bcd0b619dd2f8a266891928e21526b4800d49b4fba1cc3fff7e2c1ff5edd3344149fac841bc2306157f858e8c4d5eaee4d52ce52ad925664ce
   languageName: node
   linkType: hard
 
@@ -13817,7 +13831,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.15, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4":
+"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4":
   version: 6.0.16
   resolution: "postcss-selector-parser@npm:6.0.16"
   dependencies:
@@ -13857,7 +13871,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.33":
+"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.38":
   version: 8.4.38
   resolution: "postcss@npm:8.4.38"
   dependencies:
@@ -16428,13 +16442,14 @@ __metadata:
   linkType: hard
 
 "stylelint@npm:^16.0.2":
-  version: 16.2.1
-  resolution: "stylelint@npm:16.2.1"
+  version: 16.3.0
+  resolution: "stylelint@npm:16.3.0"
   dependencies:
-    "@csstools/css-parser-algorithms": "npm:^2.5.0"
-    "@csstools/css-tokenizer": "npm:^2.2.3"
-    "@csstools/media-query-list-parser": "npm:^2.1.7"
-    "@csstools/selector-specificity": "npm:^3.0.1"
+    "@csstools/css-parser-algorithms": "npm:^2.6.1"
+    "@csstools/css-tokenizer": "npm:^2.2.4"
+    "@csstools/media-query-list-parser": "npm:^2.1.9"
+    "@csstools/selector-specificity": "npm:^3.0.2"
+    "@dual-bundle/import-meta-resolve": "npm:^4.0.0"
     balanced-match: "npm:^2.0.0"
     colord: "npm:^2.9.3"
     cosmiconfig: "npm:^9.0.0"
@@ -16448,19 +16463,19 @@ __metadata:
     globby: "npm:^11.1.0"
     globjoin: "npm:^0.1.4"
     html-tags: "npm:^3.3.1"
-    ignore: "npm:^5.3.0"
+    ignore: "npm:^5.3.1"
     imurmurhash: "npm:^0.1.4"
     is-plain-object: "npm:^5.0.0"
-    known-css-properties: "npm:^0.29.0"
+    known-css-properties: "npm:^0.30.0"
     mathml-tag-names: "npm:^2.1.3"
-    meow: "npm:^13.1.0"
+    meow: "npm:^13.2.0"
     micromatch: "npm:^4.0.5"
     normalize-path: "npm:^3.0.0"
     picocolors: "npm:^1.0.0"
-    postcss: "npm:^8.4.33"
+    postcss: "npm:^8.4.38"
     postcss-resolve-nested-selector: "npm:^0.1.1"
     postcss-safe-parser: "npm:^7.0.0"
-    postcss-selector-parser: "npm:^6.0.15"
+    postcss-selector-parser: "npm:^6.0.16"
     postcss-value-parser: "npm:^4.2.0"
     resolve-from: "npm:^5.0.0"
     string-width: "npm:^4.2.3"
@@ -16471,7 +16486,7 @@ __metadata:
     write-file-atomic: "npm:^5.0.1"
   bin:
     stylelint: bin/stylelint.mjs
-  checksum: 10c0/eeaba06885e542c832e5cffc07b2d0dabdc5a72e6ad4d6cb3d01dcc260c29a712b0b935cbd40e059abd68a100e0563fbc617fc4c9bef3b14ecaf6eea651d9d9d
+  checksum: 10c0/98bf770078d727eb7c3ec0932b09c9486481f2d086ea1f4232e00bd1bf58b6b5d3a8d6fc9802df05380cdb06b3d97c5a7c4f27adb221b2a5707ea9829c0ee350
   languageName: node
   linkType: hard
 

From dd061291b1e89b6c67e6dff06ad087abdf7821dc Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
Date: Mon, 25 Mar 2024 13:45:00 +0100
Subject: [PATCH 006/173] Change out-of-band hashtags design in web UI (#29732)

---
 app/javascript/styles/mastodon/components.scss | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 4bb3216e4..55792f22d 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -9734,18 +9734,24 @@ noscript {
   margin-top: 16px;
   display: flex;
   flex-wrap: wrap;
-  font-size: 14px;
-  line-height: 18px;
-  gap: 4px;
+  font-size: 12px;
+  line-height: 16px;
+  gap: 6px;
   color: $darker-text-color;
 
   a {
     display: inline-flex;
     color: inherit;
     text-decoration: none;
+    padding: 4px 12px;
+    background: $ui-base-color;
+    border-radius: 4px;
+    font-weight: 500;
 
-    &:hover span {
-      text-decoration: underline;
+    &:hover,
+    &:focus,
+    &:active {
+      background: lighten($ui-base-color, 4%);
     }
   }
 

From 29f9dc742eaca1898455e37e01fff087e4bf42a6 Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
Date: Mon, 25 Mar 2024 14:27:38 +0100
Subject: [PATCH 007/173] Change design of notification about lost connections
 in web UI (#29731)

---
 .../notifications/components/notification.jsx | 27 ++++----
 .../relationships_severance_event.jsx         | 62 +++++++------------
 app/javascript/mastodon/locales/en.json       | 12 ++--
 .../styles/mastodon/components.scss           | 38 ++++++++++++
 4 files changed, 79 insertions(+), 60 deletions(-)

diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx
index 5527f3d48..c09155462 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.jsx
+++ b/app/javascript/mastodon/features/notifications/components/notification.jsx
@@ -12,7 +12,6 @@ import { HotKeys } from 'react-hotkeys';
 
 import EditIcon from '@/material-icons/400-24px/edit.svg?react';
 import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react';
-import HeartBrokenIcon from '@/material-icons/400-24px/heart_broken-fill.svg?react';
 import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
 import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
 import PersonIcon from '@/material-icons/400-24px/person-fill.svg?react';
@@ -27,7 +26,7 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 
 import FollowRequestContainer from '../containers/follow_request_container';
 
-import RelationshipsSeveranceEvent from './relationships_severance_event';
+import { RelationshipsSeveranceEvent } from './relationships_severance_event';
 import Report from './report';
 
 const messages = defineMessages({
@@ -40,6 +39,7 @@ const messages = defineMessages({
   update: { id: 'notification.update', defaultMessage: '{name} edited a post' },
   adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' },
   adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' },
+  relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' },
 });
 
 const notificationForScreenReader = (intl, message, timestamp) => {
@@ -361,24 +361,23 @@ class Notification extends ImmutablePureComponent {
   }
 
   renderRelationshipsSevered (notification) {
-    const { intl, unread } = this.props;
+    const { intl, unread, hidden } = this.props;
+    const event = notification.get('event');
 
-    if (!notification.get('event')) {
+    if (!event) {
       return null;
     }
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-severed-relationships focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: notification.getIn(['event', 'target_name']) }), notification.get('created_at'))}>
-          <div className='notification__message'>
-            <Icon id='heart_broken' icon={HeartBrokenIcon} />
-
-            <span title={notification.get('created_at')}>
-              <FormattedMessage id='notification.severed_relationships' defaultMessage='Relationships with {name} severed' values={{ name: notification.getIn(['event', 'target_name']) }} />
-            </span>
-          </div>
-
-          <RelationshipsSeveranceEvent event={notification.get('event')} />
+        <div className={classNames('notification notification-severed-relationships focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.relationshipsSevered, { name: notification.getIn(['event', 'target_name']) }), notification.get('created_at'))}>
+          <RelationshipsSeveranceEvent
+            type={event.get('type')}
+            target={event.get('target_name')}
+            followersCount={event.get('followers_count')}
+            followingCount={event.get('following_count')}
+            hidden={hidden}
+          />
         </div>
       </HotKeys>
     );
diff --git a/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx b/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx
index 23d0d2eec..738159fc5 100644
--- a/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx
+++ b/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx
@@ -2,60 +2,44 @@ import PropTypes from 'prop-types';
 
 import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
 
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import HeartBrokenIcon from '@/material-icons/400-24px/heart_broken-fill.svg?react';
+import { Icon }  from 'mastodon/components/icon';
+import { domain } from 'mastodon/initial_state';
 
-import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
-
-// This needs to be kept in sync with app/models/relationship_severance_event.rb
+// This needs to be kept in sync with app/models/relationships_severance_event.rb
 const messages = defineMessages({
-  account_suspension: { id: 'relationship_severance_notification.types.account_suspension', defaultMessage: 'Account has been suspended' },
-  domain_block: { id: 'relationship_severance_notification.types.domain_block', defaultMessage: 'Domain has been suspended' },
-  user_domain_block: { id: 'relationship_severance_notification.types.user_domain_block', defaultMessage: 'You blocked this domain' },
+  account_suspension: { id: 'notification.relationships_severance_event.account_suspension', defaultMessage: 'An admin from {from} has suspended {target}, which means you can no longer receive updates from them or interact with them.' },
+  domain_block: { id: 'notification.relationships_severance_event.domain_block', defaultMessage: 'An admin from {from} has blocked {target}, including {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.' },
+  user_domain_block: { id: 'notification.relationships_severance_event.user_domain_block', defaultMessage: 'You have blocked {target}, removing {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.' },
 });
 
-const RelationshipsSeveranceEvent = ({ event, hidden }) => {
+export const RelationshipsSeveranceEvent = ({ type, target, followingCount, followersCount, hidden }) => {
   const intl = useIntl();
 
-  if (hidden || !event) {
+  if (hidden) {
     return null;
   }
 
   return (
-    <div className='notification__report'>
-      <div className='notification__report__details'>
-        <div>
-          <RelativeTimestamp timestamp={event.get('created_at')} short={false} />
-          {' · '}
-          { event.get('purged') ? (
-            <FormattedMessage
-              id='relationship_severance_notification.purged_data'
-              defaultMessage='purged by administrators'
-            />
-          ) : (
-            <FormattedMessage
-              id='relationship_severance_notification.relationships'
-              defaultMessage='{count, plural, one {# relationship} other {# relationships}}'
-              values={{ count: event.get('followers_count', 0) + event.get('following_count', 0) }}
-            />
-          )}
-          <br />
-          <strong>{intl.formatMessage(messages[event.get('type')])}</strong>
-        </div>
+    <a href='/severed_relationships' target='_blank' rel='noopener noreferrer' className='notification__relationships-severance-event'>
+      <Icon id='heart_broken' icon={HeartBrokenIcon} />
 
-        <div className='notification__report__actions'>
-          <a href='/severed_relationships' className='button' target='_blank' rel='noopener noreferrer'>
-            <FormattedMessage id='relationship_severance_notification.view' defaultMessage='View' />
-          </a>
-        </div>
+      <div className='notification__relationships-severance-event__content'>
+        <p>{intl.formatMessage(messages[type], { from: <strong>{domain}</strong>, target: <strong>{target}</strong>, followingCount, followersCount })}</p>
+        <span className='link-button'><FormattedMessage id='notification.relationships_severance_event.learn_more' defaultMessage='Learn more' /></span>
       </div>
-    </div>
+    </a>
   );
-
 };
 
 RelationshipsSeveranceEvent.propTypes = {
-  event: ImmutablePropTypes.map.isRequired,
+  type: PropTypes.oneOf([
+    'account_suspension',
+    'domain_block',
+    'user_domain_block',
+  ]).isRequired,
+  target: PropTypes.string.isRequired,
+  followersCount: PropTypes.number.isRequired,
+  followingCount: PropTypes.number.isRequired,
   hidden: PropTypes.bool,
 };
-
-export default RelationshipsSeveranceEvent;
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 1134b393a..5aa3b5c90 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -471,7 +471,11 @@
   "notification.own_poll": "Your poll has ended",
   "notification.poll": "A poll you have voted in has ended",
   "notification.reblog": "{name} boosted your post",
-  "notification.severed_relationships": "Relationships with {name} severed",
+  "notification.relationships_severance_event": "Lost connections with {name}",
+  "notification.relationships_severance_event.account_suspension": "An admin from {from} has suspended {target}, which means you can no longer receive updates from them or interact with them.",
+  "notification.relationships_severance_event.domain_block": "An admin from {from} has blocked {target}, including {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.",
+  "notification.relationships_severance_event.learn_more": "Learn more",
+  "notification.relationships_severance_event.user_domain_block": "You have blocked {target}, removing {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.",
   "notification.status": "{name} just posted",
   "notification.update": "{name} edited a post",
   "notification_requests.accept": "Accept",
@@ -590,12 +594,6 @@
   "refresh": "Refresh",
   "regeneration_indicator.label": "Loading…",
   "regeneration_indicator.sublabel": "Your home feed is being prepared!",
-  "relationship_severance_notification.purged_data": "purged by administrators",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relationship} other {# relationships}}",
-  "relationship_severance_notification.types.account_suspension": "Account has been suspended",
-  "relationship_severance_notification.types.domain_block": "Domain has been suspended",
-  "relationship_severance_notification.types.user_domain_block": "You blocked this domain",
-  "relationship_severance_notification.view": "View",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago",
   "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago",
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 55792f22d..e5cfe235d 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2165,6 +2165,44 @@ a.account__display-name {
   }
 }
 
+.notification__relationships-severance-event {
+  display: flex;
+  gap: 16px;
+  color: $secondary-text-color;
+  text-decoration: none;
+  align-items: flex-start;
+  padding: 16px 32px;
+  border-bottom: 1px solid var(--background-border-color);
+
+  &:hover {
+    color: $primary-text-color;
+  }
+
+  .icon {
+    padding: 2px;
+    color: $highlight-text-color;
+  }
+
+  &__content {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 8px;
+    flex-grow: 1;
+    font-size: 16px;
+    line-height: 24px;
+
+    strong {
+      font-weight: 700;
+    }
+
+    .link-button {
+      font-size: inherit;
+      line-height: inherit;
+    }
+  }
+}
+
 .notification__message {
   padding: 16px;
   padding-bottom: 0;

From 0cea7a623be470c51d7a162265f44f5a3e149275 Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
Date: Mon, 25 Mar 2024 14:39:06 +0100
Subject: [PATCH 008/173] Fix background and icon on notification requests in
 web UI (#29706)

---
 .../filtered_notifications_banner.jsx         |  3 +-
 .../components/notification_request.jsx       |  4 +--
 app/javascript/mastodon/locales/en.json       |  1 +
 .../styles/mastodon/components.scss           | 36 +++++++++++--------
 4 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
index adf58afbf..ecf4b74e8 100644
--- a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
+++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
@@ -41,7 +41,8 @@ export const FilteredNotificationsBanner = () => {
       </div>
 
       <div className='filtered-notifications-banner__badge'>
-        {toCappedNumber(policy.getIn(['summary', 'pending_notifications_count']))}
+        <div className='filtered-notifications-banner__badge__badge'>{toCappedNumber(policy.getIn(['summary', 'pending_notifications_count']))}</div>
+        <FormattedMessage id='filtered_notifications_banner.private_mentions' defaultMessage='{count, plural, one {private mention} other {private mentions}}' values={{ count: policy.getIn(['summary', 'pending_notifications_count']) }} />
       </div>
     </Link>
   );
diff --git a/app/javascript/mastodon/features/notifications/components/notification_request.jsx b/app/javascript/mastodon/features/notifications/components/notification_request.jsx
index e24124ca6..3a77ef4e2 100644
--- a/app/javascript/mastodon/features/notifications/components/notification_request.jsx
+++ b/app/javascript/mastodon/features/notifications/components/notification_request.jsx
@@ -7,8 +7,8 @@ import { Link } from 'react-router-dom';
 
 import { useSelector, useDispatch } from 'react-redux';
 
+import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
 import DoneIcon from '@/material-icons/400-24px/done.svg?react';
-import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react';
 import { acceptNotificationRequest, dismissNotificationRequest } from 'mastodon/actions/notifications';
 import { Avatar } from 'mastodon/components/avatar';
 import { IconButton } from 'mastodon/components/icon_button';
@@ -51,7 +51,7 @@ export const NotificationRequest = ({ id, accountId, notificationsCount }) => {
       </Link>
 
       <div className='notification-request__actions'>
-        <IconButton iconComponent={VolumeOffIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
+        <IconButton iconComponent={DeleteIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
         <IconButton iconComponent={DoneIcon} onClick={handleAccept} title={intl.formatMessage(messages.accept)} />
       </div>
     </div>
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 5aa3b5c90..881ed19e0 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filter this post",
   "filter_modal.title.status": "Filter a post",
   "filtered_notifications_banner.pending_requests": "Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {private mention} other {private mentions}}",
   "filtered_notifications_banner.title": "Filtered notifications",
   "firehose.all": "All",
   "firehose.local": "This server",
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index e5cfe235d..3704751ef 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -10005,10 +10005,10 @@ noscript {
 .filtered-notifications-banner {
   display: flex;
   align-items: center;
-  background: $ui-base-color;
-  border-bottom: 1px solid lighten($ui-base-color, 8%);
-  padding: 15px;
-  gap: 15px;
+  border: 1px solid var(--background-border-color);
+  border-top: 0;
+  padding: 24px 32px;
+  gap: 16px;
   color: $darker-text-color;
   text-decoration: none;
 
@@ -10016,15 +10016,12 @@ noscript {
   &:active,
   &:focus {
     color: $secondary-text-color;
-
-    .filtered-notifications-banner__badge {
-      background: $secondary-text-color;
-    }
   }
 
   .icon {
     width: 24px;
     height: 24px;
+    padding: 2px;
   }
 
   &__text {
@@ -10040,13 +10037,24 @@ noscript {
   }
 
   &__badge {
-    background: $darker-text-color;
-    color: $ui-base-color;
-    border-radius: 100px;
-    padding: 2px 8px;
+    display: flex;
+    align-items: center;
+    border-radius: 999px;
+    background: var(--background-border-color);
+    color: $darker-text-color;
+    padding: 4px;
+    padding-inline-end: 8px;
+    gap: 6px;
     font-weight: 500;
     font-size: 11px;
     line-height: 16px;
+
+    &__badge {
+      background: $ui-button-background-color;
+      color: $white;
+      border-radius: 100px;
+      padding: 2px 8px;
+    }
   }
 }
 
@@ -10055,7 +10063,7 @@ noscript {
   align-items: center;
   gap: 16px;
   padding: 15px;
-  border-bottom: 1px solid lighten($ui-base-color, 8%);
+  border-bottom: 1px solid var(--background-border-color);
 
   &__link {
     display: flex;
@@ -10103,7 +10111,7 @@ noscript {
 
     .icon-button {
       border-radius: 4px;
-      border: 1px solid lighten($ui-base-color, 8%);
+      border: 1px solid var(--background-border-color);
       padding: 5px;
     }
   }

From 02ea16150647ac3baf0bb8a89203ccc7200b4a2f Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 26 Mar 2024 10:25:49 +0100
Subject: [PATCH 009/173] Support "system" theme setting (light/dark theme
 depending on user system preference) (#29748)

Co-authored-by: Nishiki Liu <hello@nshki.com>
---
 app/helpers/application_helper.rb             |  9 +++++
 .../features/emoji/__tests__/emoji-test.js    | 38 +++++++++---------
 .../mastodon/features/emoji/emoji.js          | 39 +++++++++++++++----
 app/lib/themes.rb                             |  2 +-
 app/views/layouts/application.html.haml       |  2 +-
 app/views/layouts/embedded.html.haml          |  2 +-
 app/views/layouts/error.html.haml             |  2 +-
 config/locales/en.yml                         |  1 +
 config/settings.yml                           |  2 +-
 9 files changed, 65 insertions(+), 32 deletions(-)

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 668afe7fd..d46d0674a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -160,6 +160,15 @@ module ApplicationHelper
     output.compact_blank.join(' ')
   end
 
+  def theme_style_tags(theme)
+    if theme == 'system'
+      concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
+      concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
+    else
+      stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
+    end
+  end
+
   def cdn_host
     Rails.configuration.action_controller.asset_host
   end
diff --git a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js
index 7b917ac43..9d6ff5226 100644
--- a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js
+++ b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js
@@ -22,23 +22,23 @@ describe('emoji', () => {
 
     it('does unicode', () => {
       expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual(
-        '<img draggable="false" class="emojione" alt="👩‍👩‍👦‍👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg">');
+        '<picture><img draggable="false" class="emojione" alt="👩‍👩‍👦‍👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg"></picture>');
       expect(emojify('👨‍👩‍👧‍👧')).toEqual(
-        '<img draggable="false" class="emojione" alt="👨‍👩‍👧‍👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg">');
-      expect(emojify('👩‍👩‍👦')).toEqual('<img draggable="false" class="emojione" alt="👩‍👩‍👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg">');
+        '<picture><img draggable="false" class="emojione" alt="👨‍👩‍👧‍👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg"></picture>');
+      expect(emojify('👩‍👩‍👦')).toEqual('<picture><img draggable="false" class="emojione" alt="👩‍👩‍👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg"></picture>');
       expect(emojify('\u2757')).toEqual(
-        '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg">');
+        '<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture>');
     });
 
     it('does multiple unicode', () => {
       expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual(
-        '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg">');
+        '<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture>');
       expect(emojify('\u2757#\uFE0F\u20E3')).toEqual(
-        '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg">');
+        '<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture><picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture>');
       expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual(
-        '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg">');
+        '<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture> <picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture>');
       expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual(
-        'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"> bar');
+        'foo <picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture> bar');
     });
 
     it('ignores unicode inside of tags', () => {
@@ -46,16 +46,16 @@ describe('emoji', () => {
     });
 
     it('does multiple emoji properly (issue 5188)', () => {
-      expect(emojify('👌🌈💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg">');
-      expect(emojify('👌 🌈 💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg">');
+      expect(emojify('👌🌈💕')).toEqual('<picture><img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"></picture><picture><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"></picture><picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture>');
+      expect(emojify('👌 🌈 💕')).toEqual('<picture><img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"></picture> <picture><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"></picture> <picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture>');
     });
 
     it('does an emoji that has no shortcode', () => {
-      expect(emojify('👁‍🗨')).toEqual('<img draggable="false" class="emojione" alt="👁‍🗨" title="" src="/emoji/1f441-200d-1f5e8.svg">');
+      expect(emojify('👁‍🗨')).toEqual('<picture><img draggable="false" class="emojione" alt="👁‍🗨" title="" src="/emoji/1f441-200d-1f5e8.svg"></picture>');
     });
 
     it('does an emoji whose filename is irregular', () => {
-      expect(emojify('↙️')).toEqual('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg">');
+      expect(emojify('↙️')).toEqual('<picture><img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg"></picture>');
     });
 
     it('avoid emojifying on invisible text', () => {
@@ -67,11 +67,11 @@ describe('emoji', () => {
 
     it('avoid emojifying on invisible text with nested tags', () => {
       expect(emojify('<span class="invisible">😄<span class="foo">bar</span>😴</span>😇'))
-        .toEqual('<span class="invisible">😄<span class="foo">bar</span>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
+        .toEqual('<span class="invisible">😄<span class="foo">bar</span>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
       expect(emojify('<span class="invisible">😄<span class="invisible">😕</span>😴</span>😇'))
-        .toEqual('<span class="invisible">😄<span class="invisible">😕</span>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
+        .toEqual('<span class="invisible">😄<span class="invisible">😕</span>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
       expect(emojify('<span class="invisible">😄<br>😴</span>😇'))
-        .toEqual('<span class="invisible">😄<br>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
+        .toEqual('<span class="invisible">😄<br>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
     });
 
     it('does not emojify emojis with textual presentation VS15 character', () => {
@@ -79,19 +79,19 @@ describe('emoji', () => {
         .toEqual('✴︎');
     });
 
-    it('does an simple emoji properly', () => {
+    it('does a simple emoji properly', () => {
       expect(emojify('♀♂'))
-        .toEqual('<img draggable="false" class="emojione" alt="♀" title=":female_sign:" src="/emoji/2640.svg"><img draggable="false" class="emojione" alt="♂" title=":male_sign:" src="/emoji/2642.svg">');
+        .toEqual('<picture><img draggable="false" class="emojione" alt="♀" title=":female_sign:" src="/emoji/2640.svg"></picture><picture><img draggable="false" class="emojione" alt="♂" title=":male_sign:" src="/emoji/2642.svg"></picture>');
     });
 
     it('does an emoji containing ZWJ properly', () => {
       expect(emojify('💂‍♀️💂‍♂️'))
-        .toEqual('<img draggable="false" class="emojione" alt="💂\u200D♀️" title=":female-guard:" src="/emoji/1f482-200d-2640-fe0f_border.svg"><img draggable="false" class="emojione" alt="💂\u200D♂️" title=":male-guard:" src="/emoji/1f482-200d-2642-fe0f_border.svg">');
+        .toEqual('<picture><img draggable="false" class="emojione" alt="💂\u200D♀️" title=":female-guard:" src="/emoji/1f482-200d-2640-fe0f_border.svg"></picture><picture><img draggable="false" class="emojione" alt="💂\u200D♂️" title=":male-guard:" src="/emoji/1f482-200d-2642-fe0f_border.svg"></picture>');
     });
 
     it('keeps ordering as expected (issue fixed by PR 20677)', () => {
       expect(emojify('<p>💕 <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>'))
-        .toEqual('<p><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"> <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>');
+        .toEqual('<p><picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture> <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>');
     });
   });
 });
diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js
index 5918a65ed..e4aad302f 100644
--- a/app/javascript/mastodon/features/emoji/emoji.js
+++ b/app/javascript/mastodon/features/emoji/emoji.js
@@ -17,8 +17,13 @@ const emojiFilenames = (emojis) => {
 const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂‍♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂‍♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞', '🕺', '📱', '📲', '🚲', '🪮', '🐦‍⬛']);
 const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️', '🪽', '🪿']);
 
-const emojiFilename = (filename) => {
-  const borderedEmoji = (document.body && document.body.classList.contains('theme-mastodon-light')) ? lightEmoji : darkEmoji;
+/**
+ * @param {string} filename
+ * @param {"light" | "dark" } colorScheme
+ * @returns {string}
+ */
+const emojiFilename = (filename, colorScheme) => {
+  const borderedEmoji = colorScheme === "light" ? lightEmoji : darkEmoji;
   return borderedEmoji.includes(filename) ? (filename + '_border') : filename;
 };
 
@@ -92,12 +97,30 @@ const emojifyTextNode = (node, customEmojis) => {
       const { filename, shortCode } = unicodeMapping[unicode_emoji];
       const title = shortCode ? `:${shortCode}:` : '';
 
-      replacement = document.createElement('img');
-      replacement.setAttribute('draggable', 'false');
-      replacement.setAttribute('class', 'emojione');
-      replacement.setAttribute('alt', unicode_emoji);
-      replacement.setAttribute('title', title);
-      replacement.setAttribute('src', `${assetHost}/emoji/${emojiFilename(filename)}.svg`);
+      replacement = document.createElement('picture');
+
+      const isSystemTheme = !!document.body?.classList.contains('theme-system');
+
+      if(isSystemTheme) {
+        let source = document.createElement('source');
+        source.setAttribute('media', '(prefers-color-scheme: dark)');
+        source.setAttribute('srcset', `${assetHost}/emoji/${emojiFilename(filename, "dark")}.svg`);
+        replacement.appendChild(source);
+      }
+
+      let img = document.createElement('img');
+      img.setAttribute('draggable', 'false');
+      img.setAttribute('class', 'emojione');
+      img.setAttribute('alt', unicode_emoji);
+      img.setAttribute('title', title);
+
+      let theme = "light";
+
+      if(!isSystemTheme && !document.body?.classList.contains('theme-mastodon-light'))
+        theme = "dark";
+
+      img.setAttribute('src', `${assetHost}/emoji/${emojiFilename(filename, theme)}.svg`);
+      replacement.appendChild(img);
     }
 
     // Add the processed-up-to-now string and the emoji replacement
diff --git a/app/lib/themes.rb b/app/lib/themes.rb
index 243ffb9ab..4010d8443 100644
--- a/app/lib/themes.rb
+++ b/app/lib/themes.rb
@@ -11,6 +11,6 @@ class Themes
   end
 
   def names
-    @conf.keys
+    ['system'] + @conf.keys
   end
 end
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 449657f8c..0cd7fc9f4 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -27,7 +27,7 @@
     %title= html_title
 
     = stylesheet_pack_tag 'common', media: 'all', crossorigin: 'anonymous'
-    = stylesheet_pack_tag current_theme, media: 'all', crossorigin: 'anonymous'
+    = theme_style_tags current_theme
     -# Needed for the wicg-inert polyfill. It needs to be on it's own <style> tag, with this `id`
     = stylesheet_pack_tag 'inert', media: 'all', id: 'inert-style'
 
diff --git a/app/views/layouts/embedded.html.haml b/app/views/layouts/embedded.html.haml
index 54d4ba715..c633fa9e0 100644
--- a/app/views/layouts/embedded.html.haml
+++ b/app/views/layouts/embedded.html.haml
@@ -12,7 +12,7 @@
       %link{ rel: 'dns-prefetch', href: storage_host }/
 
     = stylesheet_pack_tag 'common', media: 'all', crossorigin: 'anonymous'
-    = stylesheet_pack_tag Setting.default_settings['theme'], media: 'all', crossorigin: 'anonymous'
+    = theme_style_tags Setting.theme # Use the admin-configured theme here, even if logged in
     = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'
     = preload_pack_asset "locale/#{I18n.locale}-json.js"
     = render_initial_state
diff --git a/app/views/layouts/error.html.haml b/app/views/layouts/error.html.haml
index b7aafe987..485a69c90 100644
--- a/app/views/layouts/error.html.haml
+++ b/app/views/layouts/error.html.haml
@@ -6,7 +6,7 @@
     %title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')
     %meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/
     = stylesheet_pack_tag 'common', media: 'all', crossorigin: 'anonymous'
-    = stylesheet_pack_tag Setting.default_settings['theme'], media: 'all', crossorigin: 'anonymous'
+    = theme_style_tags Setting.default_settings['theme']
     = javascript_pack_tag 'common', crossorigin: 'anonymous'
     = javascript_pack_tag 'error', crossorigin: 'anonymous'
   %body.error
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 823e720ea..6cd996594 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1769,6 +1769,7 @@ en:
     contrast: Mastodon (High contrast)
     default: Mastodon (Dark)
     mastodon-light: Mastodon (Light)
+    system: Automatic (use system theme)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
diff --git a/config/settings.yml b/config/settings.yml
index 208c8e376..297bf0281 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -16,7 +16,7 @@ defaults: &defaults
   show_staff_badge: true
   preview_sensitive_media: false
   noindex: false
-  theme: 'default'
+  theme: 'system'
   trends: true
   trends_as_landing_page: true
   trendable_by_default: false

From 36bc57de959c92806f31a709a18fc15c527cfc1a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 09:27:05 +0000
Subject: [PATCH 010/173] Update dependency cssnano to v6.1.2 (#29754)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 5bf1095d8..696e7960f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6503,12 +6503,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"css-declaration-sorter@npm:^7.1.1":
-  version: 7.1.1
-  resolution: "css-declaration-sorter@npm:7.1.1"
+"css-declaration-sorter@npm:^7.2.0":
+  version: 7.2.0
+  resolution: "css-declaration-sorter@npm:7.2.0"
   peerDependencies:
     postcss: ^8.0.9
-  checksum: 10c0/bea446e441bafde21c3c7b3f7639559311da12eea140db7ee3c61e4f41df455b7b098df107f99bc0cca32a5020841cc94bf8a2d5efb1b383e51f9de478c4816e
+  checksum: 10c0/d8516be94f8f2daa233ef021688b965c08161624cbf830a4d7ee1099429437c0ee124d35c91b1c659cfd891a68e8888aa941726dab12279bc114aaed60a94606
   languageName: node
   linkType: hard
 
@@ -6670,12 +6670,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"cssnano-preset-default@npm:^6.1.1":
-  version: 6.1.1
-  resolution: "cssnano-preset-default@npm:6.1.1"
+"cssnano-preset-default@npm:^6.1.2":
+  version: 6.1.2
+  resolution: "cssnano-preset-default@npm:6.1.2"
   dependencies:
     browserslist: "npm:^4.23.0"
-    css-declaration-sorter: "npm:^7.1.1"
+    css-declaration-sorter: "npm:^7.2.0"
     cssnano-utils: "npm:^4.0.2"
     postcss-calc: "npm:^9.0.1"
     postcss-colormin: "npm:^6.1.0"
@@ -6706,7 +6706,7 @@ __metadata:
     postcss-unique-selectors: "npm:^6.0.4"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/dc5927c8538778f859b781dc1fb10f0082cd7b3afdba30e835e472dbf51724d4f18e5170587761150142284a371d6c9d2c3b51d29826c08d2b9dd86a929597ee
+  checksum: 10c0/af99021f936763850f5f35dc9e6a9dfb0da30856dea36e0420b011da2a447099471db2a5f3d1f5f52c0489da186caf9a439d8f048a80f82617077efb018333fa
   languageName: node
   linkType: hard
 
@@ -6720,14 +6720,14 @@ __metadata:
   linkType: hard
 
 "cssnano@npm:^6.0.1":
-  version: 6.1.1
-  resolution: "cssnano@npm:6.1.1"
+  version: 6.1.2
+  resolution: "cssnano@npm:6.1.2"
   dependencies:
-    cssnano-preset-default: "npm:^6.1.1"
+    cssnano-preset-default: "npm:^6.1.2"
     lilconfig: "npm:^3.1.1"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/2db52c2f5e314f05efec8977de392886ef0e7e08568ac45446f2303218180e317cee64c6c0c6d2c1d70a7f339fcead75384e09e187b88ccacd7f9fd51919fdf1
+  checksum: 10c0/4df0dc0389b34b38acb09b7cfb07267b0eda95349c6d5e9b7666acc7200bb33359650869a60168e9d878298b05f4ad2c7f070815c90551720a3f4e1037f79691
   languageName: node
   linkType: hard
 

From 3002a1e89b0271c242ba16851148aacdab5f3473 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:27:23 +0100
Subject: [PATCH 011/173] Update dependency express to v4.19.2 (#29750)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 696e7960f..a2258375b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8194,8 +8194,8 @@ __metadata:
   linkType: hard
 
 "express@npm:^4.17.1, express@npm:^4.18.2":
-  version: 4.19.1
-  resolution: "express@npm:4.19.1"
+  version: 4.19.2
+  resolution: "express@npm:4.19.2"
   dependencies:
     accepts: "npm:~1.3.8"
     array-flatten: "npm:1.1.1"
@@ -8228,7 +8228,7 @@ __metadata:
     type-is: "npm:~1.6.18"
     utils-merge: "npm:1.0.1"
     vary: "npm:~1.1.2"
-  checksum: 10c0/1cf6d3c095131f0d730105fac23a713083604d4f3ad9364df53cade50662abcfee2f6f8a955fdf164a5ee63f09f457da0b70cbed435ad302fa6f14162a9757f9
+  checksum: 10c0/e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb
   languageName: node
   linkType: hard
 

From 572a8ef7f9f03561a099b6d59ebb26921cbfa776 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:27:41 +0100
Subject: [PATCH 012/173] Update dependency rubocop-rails to v2.24.1 (#29745)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index b341ca84b..0b3c8d5a7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -668,7 +668,7 @@ GEM
     rubocop-performance (1.20.2)
       rubocop (>= 1.48.1, < 2.0)
       rubocop-ast (>= 1.30.0, < 2.0)
-    rubocop-rails (2.24.0)
+    rubocop-rails (2.24.1)
       activesupport (>= 4.2.0)
       rack (>= 1.1)
       rubocop (>= 1.33.0, < 2.0)

From 06fc2b3fde8b8bd80912c66bc25d0fbf19cd55f0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:29:38 +0100
Subject: [PATCH 013/173] Update dependency faker to v3.3.0 (#29755)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 0b3c8d5a7..7354e8a60 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -246,7 +246,7 @@ GEM
       tzinfo
     excon (0.109.0)
     fabrication (2.31.0)
-    faker (3.2.3)
+    faker (3.3.0)
       i18n (>= 1.8.11, < 2)
     faraday (1.10.3)
       faraday-em_http (~> 1.0)

From a3e8b7825056f41617cd469d0fe469d69056953f Mon Sep 17 00:00:00 2001
From: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:30:07 +0100
Subject: [PATCH 014/173] Ensure case-insensitive fields are converted to
 lowercase in Admin Imports (#29739)

---
 app/models/admin/import.rb | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/app/models/admin/import.rb b/app/models/admin/import.rb
index 0fd4bdb82..c12c9a86b 100644
--- a/app/models/admin/import.rb
+++ b/app/models/admin/import.rb
@@ -30,12 +30,14 @@ class Admin::Import
 
     csv_converter = lambda do |field, field_info|
       case field_info.header
-      when '#domain', '#public_comment'
+      when '#domain'
+        field&.downcase&.strip
+      when '#public_comment'
         field&.strip
       when '#severity'
-        field&.strip&.to_sym
+        field&.downcase&.strip&.to_sym
       when '#reject_media', '#reject_reports', '#obfuscate'
-        ActiveModel::Type::Boolean.new.cast(field)
+        ActiveModel::Type::Boolean.new.cast(field&.downcase)
       else
         field
       end

From eb926b7e6075b1fe5aace4d65cb7749717304b4d Mon Sep 17 00:00:00 2001
From: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:30:10 +0100
Subject: [PATCH 015/173] Ensure case-insensitive fields are converted to
 lowercase in user imports (#29740)

---
 app/models/form/import.rb | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/models/form/import.rb b/app/models/form/import.rb
index fc83d9c58..3cc4af064 100644
--- a/app/models/form/import.rb
+++ b/app/models/form/import.rb
@@ -111,12 +111,14 @@ class Form::Import
     csv_converter = lambda do |field, field_info|
       case field_info.header
       when 'Show boosts', 'Notify on new posts', 'Hide notifications'
-        ActiveModel::Type::Boolean.new.cast(field)
+        ActiveModel::Type::Boolean.new.cast(field&.downcase)
       when 'Languages'
         field&.split(',')&.map(&:strip)&.presence
       when 'Account address'
         field.strip.gsub(/\A@/, '')
-      when '#domain', '#uri', 'List name'
+      when '#domain'
+        field&.strip&.downcase
+      when '#uri', 'List name'
         field.strip
       else
         field

From 5e6a600b642cb1b8ea6ba6abe734d16ebe47b63f Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 26 Mar 2024 05:31:24 -0400
Subject: [PATCH 016/173] Bundler version update and misc gem version bumps
 (#29717)

---
 Gemfile.lock | 59 ++++++++++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 7354e8a60..133dae5b3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -99,20 +99,20 @@ GEM
     ast (2.4.2)
     attr_encrypted (4.0.0)
       encryptor (~> 3.0.0)
-    attr_required (1.0.1)
+    attr_required (1.0.2)
     awrence (1.2.1)
     aws-eventstream (1.3.0)
-    aws-partitions (1.873.0)
-    aws-sdk-core (3.190.1)
+    aws-partitions (1.899.0)
+    aws-sdk-core (3.191.4)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.8)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.75.0)
-      aws-sdk-core (~> 3, >= 3.188.0)
+    aws-sdk-kms (1.78.0)
+      aws-sdk-core (~> 3, >= 3.191.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.142.0)
-      aws-sdk-core (~> 3, >= 3.189.0)
+    aws-sdk-s3 (1.146.0)
+      aws-sdk-core (~> 3, >= 3.191.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.8)
     aws-sigv4 (1.8.0)
@@ -132,7 +132,7 @@ GEM
       erubi (>= 1.0.0)
       rack (>= 0.9.0)
       rouge (>= 1.0.0)
-    better_html (2.0.2)
+    better_html (2.1.1)
       actionview (>= 6.0)
       activesupport (>= 6.0)
       ast (~> 2.0)
@@ -140,9 +140,9 @@ GEM
       parser (>= 2.4)
       smart_properties
     bigdecimal (3.1.7)
-    bindata (2.4.15)
-    binding_of_caller (1.0.0)
-      debug_inspector (>= 0.0.1)
+    bindata (2.5.0)
+    binding_of_caller (1.0.1)
+      debug_inspector (>= 1.2.0)
     blurhash (0.1.7)
     bootsnap (1.18.3)
       msgpack (~> 1.2)
@@ -167,7 +167,7 @@ GEM
       xpath (~> 3.2)
     case_transform (0.2)
       activesupport
-    cbor (0.5.9.6)
+    cbor (0.5.9.8)
     charlock_holmes (0.7.7)
     chewy (7.5.1)
       activesupport (>= 5.2)
@@ -182,11 +182,11 @@ GEM
     cose (1.3.0)
       cbor (~> 0.5.9)
       openssl-signature_algorithm (~> 1.0)
-    crack (0.4.6)
+    crack (1.0.0)
       bigdecimal
       rexml
     crass (1.0.6)
-    css_parser (1.14.0)
+    css_parser (1.16.0)
       addressable
     csv (3.2.8)
     database_cleaner-active_record (2.1.0)
@@ -197,7 +197,7 @@ GEM
     debug (1.9.1)
       irb (~> 1.10)
       reline (>= 0.3.8)
-    debug_inspector (1.1.0)
+    debug_inspector (1.2.0)
     devise (4.9.3)
       bcrypt (~> 3.0)
       orm_adapter (~> 0.1)
@@ -217,8 +217,7 @@ GEM
     discard (1.3.0)
       activerecord (>= 4.2, < 8)
     docile (1.4.0)
-    domain_name (0.5.20190701)
-      unf (>= 0.0.5, < 1.0.0)
+    domain_name (0.6.20240107)
     doorkeeper (5.6.9)
       railties (>= 5)
     dotenv (2.8.1)
@@ -242,9 +241,9 @@ GEM
       mail (~> 2.7)
     encryptor (3.0.0)
     erubi (1.12.0)
-    et-orbi (1.2.7)
+    et-orbi (1.2.10)
       tzinfo
-    excon (0.109.0)
+    excon (0.110.0)
     fabrication (2.31.0)
     faker (3.3.0)
       i18n (>= 1.8.11, < 2)
@@ -275,7 +274,7 @@ GEM
       faraday (~> 1.0)
     fast_blank (1.0.1)
     fastimage (2.3.0)
-    ffi (1.15.5)
+    ffi (1.16.3)
     ffi-compiler (1.0.1)
       ffi (>= 1.0.0)
       rake
@@ -291,7 +290,7 @@ GEM
       fog-core (~> 2.1)
       fog-json (>= 1.0)
     formatador (1.1.0)
-    fugit (1.8.1)
+    fugit (1.10.1)
       et-orbi (~> 1, >= 1.2.7)
       raabro (~> 1.4)
     fuubar (2.5.1)
@@ -423,7 +422,7 @@ GEM
       net-imap
       net-pop
       net-smtp
-    marcel (1.0.2)
+    marcel (1.0.4)
     mario-redis-lock (1.2.1)
       redis (>= 3.0.5)
     matrix (0.4.2)
@@ -434,7 +433,7 @@ GEM
     memory_profiler (1.0.1)
     mime-types (3.5.2)
       mime-types-data (~> 3.2015)
-    mime-types-data (3.2023.1205)
+    mime-types-data (3.2024.0305)
     mini_mime (1.1.5)
     mini_portile2 (2.8.5)
     minitest (5.22.3)
@@ -456,7 +455,7 @@ GEM
       timeout
     net-smtp (0.4.0.1)
       net-protocol
-    nio4r (2.5.9)
+    nio4r (2.7.1)
     nokogiri (1.16.3)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
@@ -511,7 +510,7 @@ GEM
     pghero (3.4.1)
       activerecord (>= 6)
     posix-spawn (0.3.15)
-    premailer (1.21.0)
+    premailer (1.23.0)
       addressable
       css_parser (>= 1.12.0)
       htmlentities (>= 4.0.0)
@@ -618,7 +617,7 @@ GEM
       railties (>= 5.2)
     rexml (3.2.6)
     rotp (6.3.0)
-    rouge (4.1.2)
+    rouge (4.2.1)
     rpam2 (4.0.2)
     rqrcode (2.2.0)
       chunky_png (~> 1.0)
@@ -763,7 +762,7 @@ GEM
       tty-cursor (~> 0.7)
       tty-screen (~> 0.8)
       wisper (~> 2.0)
-    tty-screen (0.8.1)
+    tty-screen (0.8.2)
     twitter-text (3.1.0)
       idn-ruby
       unf (~> 0.1.0)
@@ -773,7 +772,7 @@ GEM
       tzinfo (>= 1.0.0)
     unf (0.1.4)
       unf_ext
-    unf_ext (0.0.8.2)
+    unf_ext (0.0.9.1)
     unicode-display_width (2.5.0)
     uri (0.12.2)
     validate_email (0.1.6)
@@ -796,7 +795,7 @@ GEM
     webfinger (1.2.0)
       activesupport
       httpclient (>= 2.4)
-    webmock (3.22.0)
+    webmock (3.23.0)
       addressable (>= 2.8.0)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -956,4 +955,4 @@ RUBY VERSION
    ruby 3.2.2p53
 
 BUNDLED WITH
-   2.5.4
+   2.5.7

From c3e3c600696114065302a81d0be05b7d1a7f0a41 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 26 Mar 2024 05:33:07 -0400
Subject: [PATCH 017/173] Remove extraneous `Lint/UselessAccessModifier` config
 (#29749)

---
 .rubocop.yml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/.rubocop.yml b/.rubocop.yml
index d968346f6..541da330c 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -41,12 +41,6 @@ Layout/FirstHashElementIndentation:
 Layout/LineLength:
   Max: 320 # Default of 120 causes a duplicate entry in generated todo file
 
-# Reason:
-# https://docs.rubocop.org/rubocop/cops_lint.html#lintuselessaccessmodifier
-Lint/UselessAccessModifier:
-  ContextCreatingMethods:
-    - class_methods
-
 ## Disable most Metrics/*Length cops
 # Reason: those are often triggered and force significant refactors when this happend
 #         but the team feel they are not really improving the code quality.

From b3d970bdb85973023a588389f8a5a17df1ee67ca Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:49:19 +0100
Subject: [PATCH 018/173] New Crowdin Translations (automated) (#29756)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/be.json    |  3 ---
 app/javascript/mastodon/locales/bg.json    |  9 ++-----
 app/javascript/mastodon/locales/ca.json    | 15 ++++++------
 app/javascript/mastodon/locales/da.json    | 12 +++++-----
 app/javascript/mastodon/locales/de.json    | 13 +++++-----
 app/javascript/mastodon/locales/es-AR.json | 13 +++++-----
 app/javascript/mastodon/locales/es-MX.json | 12 ++++------
 app/javascript/mastodon/locales/es.json    | 12 ++++------
 app/javascript/mastodon/locales/eu.json    | 10 +++-----
 app/javascript/mastodon/locales/fi.json    |  9 ++-----
 app/javascript/mastodon/locales/fo.json    | 13 +++++-----
 app/javascript/mastodon/locales/fr-CA.json |  7 ------
 app/javascript/mastodon/locales/fr.json    |  7 ------
 app/javascript/mastodon/locales/gd.json    |  7 ------
 app/javascript/mastodon/locales/gl.json    |  9 ++-----
 app/javascript/mastodon/locales/he.json    | 13 +++++-----
 app/javascript/mastodon/locales/hu.json    | 15 ++++++------
 app/javascript/mastodon/locales/is.json    |  5 ++--
 app/javascript/mastodon/locales/it.json    | 10 +++-----
 app/javascript/mastodon/locales/ko.json    |  7 ------
 app/javascript/mastodon/locales/lad.json   |  2 --
 app/javascript/mastodon/locales/lt.json    |  3 ---
 app/javascript/mastodon/locales/lv.json    |  4 ++--
 app/javascript/mastodon/locales/nl.json    | 13 +++++-----
 app/javascript/mastodon/locales/nn.json    | 15 ++++++------
 app/javascript/mastodon/locales/pl.json    | 12 ++++------
 app/javascript/mastodon/locales/pt-PT.json |  7 ------
 app/javascript/mastodon/locales/sk.json    |  3 +--
 app/javascript/mastodon/locales/sl.json    |  9 ++-----
 app/javascript/mastodon/locales/sq.json    | 13 +++++-----
 app/javascript/mastodon/locales/sv.json    |  6 +----
 app/javascript/mastodon/locales/th.json    | 13 +++++-----
 app/javascript/mastodon/locales/tr.json    | 13 +++++-----
 app/javascript/mastodon/locales/uk.json    | 10 +++-----
 app/javascript/mastodon/locales/vi.json    | 15 ++++++------
 app/javascript/mastodon/locales/zh-CN.json | 13 +++++-----
 app/javascript/mastodon/locales/zh-HK.json |  7 ------
 app/javascript/mastodon/locales/zh-TW.json | 13 +++++-----
 config/locales/devise.hu.yml               |  6 ++---
 config/locales/doorkeeper.hu.yml           |  4 ++--
 config/locales/hu.yml                      | 28 +++++++++++-----------
 config/locales/is.yml                      | 10 ++++++++
 config/locales/sl.yml                      |  5 ++++
 43 files changed, 171 insertions(+), 254 deletions(-)

diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json
index 754b7156b..fe186222a 100644
--- a/app/javascript/mastodon/locales/be.json
+++ b/app/javascript/mastodon/locales/be.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Ваша апытанне скончылася",
   "notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
   "notification.reblog": "{name} пашырыў ваш допіс",
-  "notification.severed_relationships": "Зносіны з {name} былі разарваныя",
   "notification.status": "Новы допіс ад {name}",
   "notification.update": "Допіс {name} адрэдагаваны",
   "notification_requests.accept": "Прыняць",
@@ -589,8 +588,6 @@
   "refresh": "Абнавiць",
   "regeneration_indicator.label": "Загрузка…",
   "regeneration_indicator.sublabel": "Пачакайце, рыхтуем вашу стужку!",
-  "relationship_severance_notification.types.user_domain_block": "Вы заблакіравалі гэты дамен",
-  "relationship_severance_notification.view": "Праглядзець",
   "relative_time.days": "{number} д",
   "relative_time.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}} таму",
   "relative_time.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}} таму",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 4670a6e2d..b7a236d60 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Анкетата ви приключи",
   "notification.poll": "Анкета, в която гласувахте, приключи",
   "notification.reblog": "{name} подсили ваша публикация",
-  "notification.severed_relationships": "Връзката с {name} е прекъсната",
   "notification.status": "{name} току-що публикува",
   "notification.update": "{name} промени публикация",
   "notification_requests.accept": "Приемам",
@@ -484,6 +483,8 @@
   "notifications.column_settings.admin.sign_up": "Нови регистрации:",
   "notifications.column_settings.alert": "Известия на работния плот",
   "notifications.column_settings.favourite": "Любими:",
+  "notifications.column_settings.filter_bar.advanced": "Показване на всички категории",
+  "notifications.column_settings.filter_bar.category": "Лента за бърз филтър",
   "notifications.column_settings.follow": "Нови последователи:",
   "notifications.column_settings.follow_request": "Нови заявки за последване:",
   "notifications.column_settings.mention": "Споменавания:",
@@ -588,12 +589,6 @@
   "refresh": "Опресняване",
   "regeneration_indicator.label": "Зареждане…",
   "regeneration_indicator.sublabel": "Подготовка на началния ви инфоканал!",
-  "relationship_severance_notification.purged_data": "прочистено от администраторите",
-  "relationship_severance_notification.relationships": "{count, plural, one {# връзка} other {# връзки}}",
-  "relationship_severance_notification.types.account_suspension": "Акаунтът е спрян",
-  "relationship_severance_notification.types.domain_block": "Домейнът е спрян",
-  "relationship_severance_notification.types.user_domain_block": "Блокирахте този домейн",
-  "relationship_severance_notification.view": "Преглед",
   "relative_time.days": "{number} д.",
   "relative_time.full.days": "преди {number, plural, one {# ден} other {# дни}}",
   "relative_time.full.hours": "преди {number, plural, one {# час} other {# часа}}",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index c95e8a950..eee6d281d 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtra aquest tut",
   "filter_modal.title.status": "Filtra un tut",
   "filtered_notifications_banner.pending_requests": "Notificacions {count, plural, =0 {de ningú} one {d'una persona} other {de # persones}} que potser coneixes",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {menció privada} other {mencions privades}}",
   "filtered_notifications_banner.title": "Notificacions filtrades",
   "firehose.all": "Tots",
   "firehose.local": "Aquest servidor",
@@ -471,7 +472,11 @@
   "notification.own_poll": "La teva enquesta ha finalitzat",
   "notification.poll": "Ha finalitzat una enquesta en què has votat",
   "notification.reblog": "{name} t'ha impulsat",
-  "notification.severed_relationships": "S'han eliminat les relacions amb {name}",
+  "notification.relationships_severance_event": "Connexions perdudes amb {name}",
+  "notification.relationships_severance_event.account_suspension": "Un administrador de {from} ha suspès {target}; això vol dir que ja no en podreu rebre actualitzacions o interactuar-hi.",
+  "notification.relationships_severance_event.domain_block": "Un administrador de {from} ha blocat {target}, incloent-hi {followersCount} dels vostres seguidors i {followingCount, plural, one {# compte} other {# comptes}} que seguiu.",
+  "notification.relationships_severance_event.learn_more": "Per a saber-ne més",
+  "notification.relationships_severance_event.user_domain_block": "Heu blocat {target}, eliminant {followersCount} dels vostres seguidors i {followingCount, plural, one {# compte} other {# comptes}} que seguiu.",
   "notification.status": "{name} acaba de publicar",
   "notification.update": "{name} ha editat un tut",
   "notification_requests.accept": "Accepta",
@@ -484,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Registres nous:",
   "notifications.column_settings.alert": "Notificacions d'escriptori",
   "notifications.column_settings.favourite": "Favorits:",
+  "notifications.column_settings.filter_bar.advanced": "Mostra totes les categories",
+  "notifications.column_settings.filter_bar.category": "Barra ràpida de filtres",
   "notifications.column_settings.follow": "Nous seguidors:",
   "notifications.column_settings.follow_request": "Noves sol·licituds de seguiment:",
   "notifications.column_settings.mention": "Mencions:",
@@ -588,12 +595,6 @@
   "refresh": "Actualitza",
   "regeneration_indicator.label": "Es carrega…",
   "regeneration_indicator.sublabel": "Es prepara la teva línia de temps d'Inici!",
-  "relationship_severance_notification.purged_data": "purgat pels administradors",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relació} other {# relacions}}",
-  "relationship_severance_notification.types.account_suspension": "S'ha suspès el compte",
-  "relationship_severance_notification.types.domain_block": "S'ha suspès el domini",
-  "relationship_severance_notification.types.user_domain_block": "Heu blocat aquest domini",
-  "relationship_severance_notification.view": "Visualitza",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "fa {number, plural, one {# dia} other {# dies}}",
   "relative_time.full.hours": "fa {number, plural, one {# hora} other {# hores}}",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 97468c627..2e5fb21fe 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -296,6 +296,7 @@
   "filter_modal.select_filter.title": "Filtrér dette indlæg",
   "filter_modal.title.status": "Filtrér et indlæg",
   "filtered_notifications_banner.pending_requests": "Notifikationer fra {count, plural, =0 {ingen} one {én person} other {# personer}} du måske kender",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omtale} other {private omtaler}}",
   "filtered_notifications_banner.title": "Filtrerede notifikationer",
   "firehose.all": "Alle",
   "firehose.local": "Denne server",
@@ -469,6 +470,11 @@
   "notification.own_poll": "Din afstemning er afsluttet",
   "notification.poll": "En afstemning, hvori du stemte, er slut",
   "notification.reblog": "{name} boostede dit indlæg",
+  "notification.relationships_severance_event": "Mistede forbindelser med {name}",
+  "notification.relationships_severance_event.account_suspension": "En admin fra {from} har suspenderet {target}, hvofor opdateringer herfra eller interaktion hermed ikke længer er mulig.",
+  "notification.relationships_severance_event.domain_block": "En admin fra {from} har blokeret {target}, herunder {followersCount} tilhængere og {followingCount, plural, one {# konto, der} other {# konti, som}} følges.",
+  "notification.relationships_severance_event.learn_more": "Læs mere",
+  "notification.relationships_severance_event.user_domain_block": "{target} er blevet blokeret, og {followersCount} tilhængere samt {followingCount, plural, one {# konto, der} other {# konti, som}} følges, er hermed fjernet.",
   "notification.status": "{name} har netop postet",
   "notification.update": "{name} redigerede et indlæg",
   "notification_requests.accept": "Acceptér",
@@ -587,12 +593,6 @@
   "refresh": "Genindlæs",
   "regeneration_indicator.label": "Indlæser…",
   "regeneration_indicator.sublabel": "Din hjemmetidslinje klargøres!",
-  "relationship_severance_notification.purged_data": "renset af administratorer",
-  "relationship_severance_notification.relationships": "{count, plural, one {# forhold} other {# forhold}}",
-  "relationship_severance_notification.types.account_suspension": "Konto er blevet suspenderet",
-  "relationship_severance_notification.types.domain_block": "Domæne er blevet suspenderet",
-  "relationship_severance_notification.types.user_domain_block": "Dette domæne blev blokeret",
-  "relationship_severance_notification.view": "Vis",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# dag} other {# dage}} siden",
   "relative_time.full.hours": "{number, plural, one {# time} other {# timer}} siden",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 8cc77c072..b1d0b3ec1 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Diesen Beitrag filtern",
   "filter_modal.title.status": "Beitrag per Filter ausblenden",
   "filtered_notifications_banner.pending_requests": "Benachrichtigungen von {count, plural, =0 {keinem Profil, das du möglicherweise kennst} one {einem Profil, das du möglicherweise kennst} other {# Profilen, die du möglicherweise kennst}}",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {private Erwähnung} other {private Erwähnungen}}",
   "filtered_notifications_banner.title": "Gefilterte Benachrichtigungen",
   "firehose.all": "Alles",
   "firehose.local": "Dieser Server",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Deine Umfrage ist beendet",
   "notification.poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
   "notification.reblog": "{name} teilte deinen Beitrag",
-  "notification.severed_relationships": "Beziehungen zu {name} getrennt",
+  "notification.relationships_severance_event": "Verbindungen mit {name} verloren",
+  "notification.relationships_severance_event.account_suspension": "Ein Admin von {from} hat {target} gesperrt. Du wirst von diesem Profil keine Updates mehr erhalten und auch nicht mit ihm interagieren können.",
+  "notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.",
+  "notification.relationships_severance_event.learn_more": "Mehr erfahren",
+  "notification.relationships_severance_event.user_domain_block": "Du hast {target} blockiert – {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst, wurden entfernt.",
   "notification.status": "{name} hat gerade etwas gepostet",
   "notification.update": "{name} bearbeitete einen Beitrag",
   "notification_requests.accept": "Akzeptieren",
@@ -590,12 +595,6 @@
   "refresh": "Aktualisieren",
   "regeneration_indicator.label": "Wird geladen …",
   "regeneration_indicator.sublabel": "Deine Startseite wird gerade vorbereitet!",
-  "relationship_severance_notification.purged_data": "von Administrator*innen entfernt",
-  "relationship_severance_notification.relationships": "{count, plural, one {# Beziehung} other {# Beziehungen}}",
-  "relationship_severance_notification.types.account_suspension": "Konto wurde gesperrt",
-  "relationship_severance_notification.types.domain_block": "Domain wurde gesperrt",
-  "relationship_severance_notification.types.user_domain_block": "Du hast diese Domain blockiert",
-  "relationship_severance_notification.view": "Anzeigen",
   "relative_time.days": "{number} T.",
   "relative_time.full.days": "vor {number, plural, one {# Tag} other {# Tagen}}",
   "relative_time.full.hours": "vor {number, plural, one {# Stunde} other {# Stunden}}",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index a9db8831e..c14edac6b 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrar este mensaje",
   "filter_modal.title.status": "Filtrar un mensaje",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todos",
   "firehose.local": "Este servidor",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Tu encuesta finalizó",
   "notification.poll": "Finalizó una encuesta en la que votaste",
   "notification.reblog": "{name} adhirió a tu mensaje",
-  "notification.severed_relationships": "Relaciones con {name} cortadas",
+  "notification.relationships_severance_event": "Conexiones perdidas con {name}",
+  "notification.relationships_severance_event.account_suspension": "Un administrador de {from} suspendió a {target}, lo que significa que ya no podés recibir actualizaciones de esa cuenta o interactuar con la misma.",
+  "notification.relationships_severance_event.domain_block": "Un administrador de {from} bloqueó a {target}, incluyendo {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que seguís.",
+  "notification.relationships_severance_event.learn_more": "Aprendé más",
+  "notification.relationships_severance_event.user_domain_block": "Bloqueaste a {target}, eliminando {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que seguís.",
   "notification.status": "{name} acaba de enviar un mensaje",
   "notification.update": "{name} editó un mensaje",
   "notification_requests.accept": "Aceptar",
@@ -590,12 +595,6 @@
   "refresh": "Refrescar",
   "regeneration_indicator.label": "Cargando…",
   "regeneration_indicator.sublabel": "¡Se está preparando tu línea temporal principal!",
-  "relationship_severance_notification.purged_data": "purgada por administradores",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relaciones}}",
-  "relationship_severance_notification.types.account_suspension": "La cuenta fue suspendida",
-  "relationship_severance_notification.types.domain_block": "El dominio fue suspendido",
-  "relationship_severance_notification.types.user_domain_block": "Bloqueaste este dominio",
-  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural,one {hace # día} other {hace # días}}",
   "relative_time.full.hours": "{number, plural,one {hace # hora} other {hace # horas}}",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index dea71a935..fd32d9d90 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -471,7 +471,11 @@
   "notification.own_poll": "Tu encuesta ha terminado",
   "notification.poll": "Una encuesta en la que has votado ha terminado",
   "notification.reblog": "{name} ha retooteado tu estado",
-  "notification.severed_relationships": "Se han cortado las relaciones con {name}",
+  "notification.relationships_severance_event": "Conexiones perdidas con {name}",
+  "notification.relationships_severance_event.account_suspension": "Un administrador de {from} ha suspendido {target}, lo que significa que ya no puedes recibir actualizaciones de sus cuentas o interactuar con ellas.",
+  "notification.relationships_severance_event.domain_block": "Un administrador de {from} ha bloqueado {target}, incluyendo {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que sigues.",
+  "notification.relationships_severance_event.learn_more": "Más información",
+  "notification.relationships_severance_event.user_domain_block": "Has bloqueado {target}, eliminando {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que sigues.",
   "notification.status": "{name} acaba de publicar",
   "notification.update": "{name} editó una publicación",
   "notification_requests.accept": "Aceptar",
@@ -590,12 +594,6 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "Cargando…",
   "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
-  "relationship_severance_notification.purged_data": "purgado por administradores",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relaciones}}",
-  "relationship_severance_notification.types.account_suspension": "La cuenta ha sido suspendida",
-  "relationship_severance_notification.types.domain_block": "El dominio ha sido suspendido",
-  "relationship_severance_notification.types.user_domain_block": "Bloqueaste este dominio",
-  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "{number, plural, one {# día} other {# días hace}}",
   "relative_time.full.hours": "{number, plural, one {# hora} other {# horas}} hace",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 64bcf7d9c..9c15a3cae 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -471,7 +471,11 @@
   "notification.own_poll": "Tu encuesta ha terminado",
   "notification.poll": "Una encuesta en la que has votado ha terminado",
   "notification.reblog": "{name} ha impulsado tu publicación",
-  "notification.severed_relationships": "Se han cortado las relaciones con {name}",
+  "notification.relationships_severance_event": "Conexiones perdidas con {name}",
+  "notification.relationships_severance_event.account_suspension": "Un administrador de {from} ha suspendido {target}, lo que significa que ya no puedes recibir actualizaciones de sus cuentas o interactuar con ellas.",
+  "notification.relationships_severance_event.domain_block": "Un administrador de {from} ha bloqueado {target}, incluyendo {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que sigues.",
+  "notification.relationships_severance_event.learn_more": "Más información",
+  "notification.relationships_severance_event.user_domain_block": "Has bloqueado {target}, eliminando {followersCount} de tus seguidores y {followingCount, plural, one {# cuenta} other {# cuentas}} que sigues.",
   "notification.status": "{name} acaba de publicar",
   "notification.update": "{name} editó una publicación",
   "notification_requests.accept": "Aceptar",
@@ -590,12 +594,6 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "Cargando…",
   "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
-  "relationship_severance_notification.purged_data": "purgado por administradores",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relaciones}}",
-  "relationship_severance_notification.types.account_suspension": "La cuenta ha sido suspendida",
-  "relationship_severance_notification.types.domain_block": "El dominio ha sido suspendido",
-  "relationship_severance_notification.types.user_domain_block": "Bloqueaste este dominio",
-  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "hace {number, plural, one {# día} other {# días}}",
   "relative_time.full.hours": "hace {number, plural, one {# hora} other {# horas}}",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 8c3c5f984..40fec4f49 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -471,7 +471,9 @@
   "notification.own_poll": "Zure inkesta amaitu da",
   "notification.poll": "Zuk erantzun duzun inkesta bat bukatu da",
   "notification.reblog": "{name}(e)k bultzada eman dio zure bidalketari",
-  "notification.severed_relationships": "{name} erabiltzailearekin zenuen erlazioa galdu da",
+  "notification.relationships_severance_event": "{name} erabiltzailearekin galdutako konexioak",
+  "notification.relationships_severance_event.account_suspension": "{from} zerbitzariko administratzaile batek {target} bertan behera utzi du, hau da, ezin izango dituzu jaso hango eguneratzerik edo hangoekin elkarreragin.",
+  "notification.relationships_severance_event.learn_more": "Informazio gehiago",
   "notification.status": "{name} erabiltzaileak bidalketa egin berri du",
   "notification.update": "{name} erabiltzaileak bidalketa bat editatu du",
   "notification_requests.accept": "Onartu",
@@ -590,12 +592,6 @@
   "refresh": "Berritu",
   "regeneration_indicator.label": "Kargatzen…",
   "regeneration_indicator.sublabel": "Zure hasiera-jarioa prestatzen ari da!",
-  "relationship_severance_notification.purged_data": "administratzaileek kendua",
-  "relationship_severance_notification.relationships": "{count, plural, one {Erlazio #} other {# erlazio}}",
-  "relationship_severance_notification.types.account_suspension": "Kontua bertan behera utzi da",
-  "relationship_severance_notification.types.domain_block": "Domeinua bertan behera utzi da",
-  "relationship_severance_notification.types.user_domain_block": "Domeinu hau blokeatu duzu",
-  "relationship_severance_notification.view": "Ikusi",
   "relative_time.days": "{number}e",
   "relative_time.full.days": "Duela {number, plural, one {egun #} other {# egun}}",
   "relative_time.full.hours": "Duela {number, plural, one {ordu #} other {# ordu}}",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 16670d9ff..9dfa61ef4 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Suodata tämä julkaisu",
   "filter_modal.title.status": "Suodata julkaisu",
   "filtered_notifications_banner.pending_requests": "Ilmoitukset {count, plural, =0 {ei keltään} one {yhdeltä henkilöltä} other {# henkilöltä}}, jonka saatat tuntea",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {yksityismaininta} other {yksityismainintaa}}",
   "filtered_notifications_banner.title": "Suodatetut ilmoitukset",
   "firehose.all": "Kaikki",
   "firehose.local": "Tämä palvelin",
@@ -471,7 +472,7 @@
   "notification.own_poll": "Äänestyksesi on päättynyt",
   "notification.poll": "Kysely, johon osallistuit, on päättynyt",
   "notification.reblog": "{name} tehosti julkaisuasi",
-  "notification.severed_relationships": "Suhteet palvelimeen {name} katkenneet",
+  "notification.relationships_severance_event.learn_more": "Lue lisää",
   "notification.status": "{name} julkaisi juuri",
   "notification.update": "{name} muokkasi julkaisua",
   "notification_requests.accept": "Hyväksy",
@@ -590,12 +591,6 @@
   "refresh": "Päivitä",
   "regeneration_indicator.label": "Ladataan…",
   "regeneration_indicator.sublabel": "Kotisyötettäsi valmistellaan!",
-  "relationship_severance_notification.purged_data": "ylläpitäjien tyhjentämä",
-  "relationship_severance_notification.relationships": "{count, plural, one {# suhde} other {# suhdetta}}",
-  "relationship_severance_notification.types.account_suspension": "Tili on jäädytetty",
-  "relationship_severance_notification.types.domain_block": "Verkkotunnus on jäädytetty",
-  "relationship_severance_notification.types.user_domain_block": "Estit tämän verkkotunnuksen",
-  "relationship_severance_notification.view": "Näytä",
   "relative_time.days": "{number} pv",
   "relative_time.full.days": "{number, plural, one {# päivä} other {# päivää}} sitten",
   "relative_time.full.hours": "{number, plural, one {# tunti} other {# tuntia}} sitten",
diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json
index c86829ee3..b8722ee31 100644
--- a/app/javascript/mastodon/locales/fo.json
+++ b/app/javascript/mastodon/locales/fo.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrera hendan postin",
   "filter_modal.title.status": "Filtrera ein post",
   "filtered_notifications_banner.pending_requests": "Fráboðanir frá {count, plural, =0 {ongum} one {einum persóni} other {# persónum}}, sum tú kanska kennir",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat umrøða} other {privatar umrøður}}",
   "filtered_notifications_banner.title": "Sáldaðar fráboðanir",
   "firehose.all": "Allar",
   "firehose.local": "Hesin ambætarin",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Tín atkvøðugreiðsla er endað",
   "notification.poll": "Ein atkvøðugreiðsla, har tú hevur atkvøtt, er endað",
   "notification.reblog": "{name} lyfti tín post",
-  "notification.severed_relationships": "Tilknýti við {name} avbrotið",
+  "notification.relationships_severance_event": "Mist sambond við {name}",
+  "notification.relationships_severance_event.account_suspension": "Ein umsitari frá {from} hevur gjørt {target} óvirkna, sum merkir, at tú ikki kanst móttaka dagføringar ella virka saman við teimum longur.",
+  "notification.relationships_severance_event.domain_block": "Ein umsitari frá {from} hevur blokerað {target}, íroknað {followersCount} av tínum fylgjarum og {followingCount, plural, one {# kontu} other {# kontur}}, sum tú fylgir.",
+  "notification.relationships_severance_event.learn_more": "Lær meira",
+  "notification.relationships_severance_event.user_domain_block": "Tú hevur blokerað {target}, strikað {followersCount} av tínum fylgjarum og {followingCount, plural, one {# kontu} other {# kontur}}, sum tú fylgir.",
   "notification.status": "{name} hevur júst postað",
   "notification.update": "{name} rættaði ein post",
   "notification_requests.accept": "Góðtak",
@@ -590,12 +595,6 @@
   "refresh": "Endurles",
   "regeneration_indicator.label": "Innlesur…",
   "regeneration_indicator.sublabel": "Tín heimarás verður gjørd klár!",
-  "relationship_severance_notification.purged_data": "reinsað av umsitarum",
-  "relationship_severance_notification.relationships": "{count, plural, one {# tilknýti} other {# tilknýti}}",
-  "relationship_severance_notification.types.account_suspension": "Kontan er ógildað",
-  "relationship_severance_notification.types.domain_block": "Økisnavn er ógildað",
-  "relationship_severance_notification.types.user_domain_block": "Tú hevur forðað hesum økisnavni",
-  "relationship_severance_notification.view": "Vís",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# dagur} other {# dagar}} síðani",
   "relative_time.full.hours": "{number, plural, one {# tími} other {# tímar}} síðani",
diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json
index 1e1c78f29..ab4a3f309 100644
--- a/app/javascript/mastodon/locales/fr-CA.json
+++ b/app/javascript/mastodon/locales/fr-CA.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Votre sondage est terminé",
   "notification.poll": "Un sondage auquel vous avez participé est terminé",
   "notification.reblog": "{name} a boosté votre message",
-  "notification.severed_relationships": "Relation avec {name} rompues",
   "notification.status": "{name} vient de publier",
   "notification.update": "{name} a modifié une publication",
   "notification_requests.accept": "Accepter",
@@ -588,12 +587,6 @@
   "refresh": "Actualiser",
   "regeneration_indicator.label": "Chargement…",
   "regeneration_indicator.sublabel": "Votre fil d'accueil est en cours de préparation!",
-  "relationship_severance_notification.purged_data": "supprimées par les administrateurs",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relation} other {# relations}}",
-  "relationship_severance_notification.types.account_suspension": "Le compte a été suspendu",
-  "relationship_severance_notification.types.domain_block": "Le domaine a été suspendu",
-  "relationship_severance_notification.types.user_domain_block": "Vous avez bloqué ce domaine",
-  "relationship_severance_notification.view": "Afficher",
   "relative_time.days": "{number} j",
   "relative_time.full.days": "il y a {number, plural, one {# jour} other {# jours}}",
   "relative_time.full.hours": "il y a {number, plural, one {# heure} other {# heures}}",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index af5ed66bd..5ae6fac9f 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Votre sondage est terminé",
   "notification.poll": "Un sondage auquel vous avez participé vient de se terminer",
   "notification.reblog": "{name} a partagé votre message",
-  "notification.severed_relationships": "Relation avec {name} rompues",
   "notification.status": "{name} vient de publier",
   "notification.update": "{name} a modifié un message",
   "notification_requests.accept": "Accepter",
@@ -588,12 +587,6 @@
   "refresh": "Actualiser",
   "regeneration_indicator.label": "Chargement…",
   "regeneration_indicator.sublabel": "Votre fil principal est en cours de préparation !",
-  "relationship_severance_notification.purged_data": "supprimées par les administrateurs",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relation} other {# relations}}",
-  "relationship_severance_notification.types.account_suspension": "Le compte a été suspendu",
-  "relationship_severance_notification.types.domain_block": "Le domaine a été suspendu",
-  "relationship_severance_notification.types.user_domain_block": "Vous avez bloqué ce domaine",
-  "relationship_severance_notification.view": "Afficher",
   "relative_time.days": "{number} j",
   "relative_time.full.days": "il y a {number, plural, one {# jour} other {# jours}}",
   "relative_time.full.hours": "il y a {number, plural, one {# heure} other {# heures}}",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index 612e36377..d835a4686 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Thàinig an cunntas-bheachd agad gu crìoch",
   "notification.poll": "Thàinig cunntas-bheachd sa bhòt thu gu crìoch",
   "notification.reblog": "Bhrosnaich {name} am post agad",
-  "notification.severed_relationships": "Chaidh na dàimhean le {name} a dhealachadh",
   "notification.status": "Phostaich {name} rud",
   "notification.update": "Dheasaich {name} post",
   "notification_requests.accept": "Gabh ris",
@@ -588,12 +587,6 @@
   "refresh": "Ath-nuadhaich",
   "regeneration_indicator.label": "’Ga luchdadh…",
   "regeneration_indicator.sublabel": "Tha do dhachaigh ’ga ullachadh!",
-  "relationship_severance_notification.purged_data": "chaidh a phurgaideachadh leis na rianairean",
-  "relationship_severance_notification.relationships": "{count, plural, one {# dàimh} two {# dhàimh} few {# dàimhean} other {# dàimh}}",
-  "relationship_severance_notification.types.account_suspension": "Chaidh cunntas a chur à rèim",
-  "relationship_severance_notification.types.domain_block": "Chaidh àrainn a chur à rèim",
-  "relationship_severance_notification.types.user_domain_block": "Bhac thu an àrainn seo",
-  "relationship_severance_notification.view": "Seall",
   "relative_time.days": "{number}l",
   "relative_time.full.days": "{number, plural, one {# latha} two {# latha} few {# làithean} other {# latha}} air ais",
   "relative_time.full.hours": "{number, plural, one {# uair a thìde} two {# uair a thìde} few {# uairean a thìde} other {# uair a thìde}} air ais",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 57d13205f..20de52d30 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "A túa enquisa rematou",
   "notification.poll": "Rematou a enquisa na que votaches",
   "notification.reblog": "{name} compartiu a túa publicación",
-  "notification.severed_relationships": "Cortouse a relación con {name}",
   "notification.status": "{name} publicou",
   "notification.update": "{name} editou unha publicación",
   "notification_requests.accept": "Aceptar",
@@ -484,6 +483,8 @@
   "notifications.column_settings.admin.sign_up": "Novas usuarias:",
   "notifications.column_settings.alert": "Notificacións de escritorio",
   "notifications.column_settings.favourite": "Favoritas:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas as categorías",
+  "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
   "notifications.column_settings.follow": "Novas seguidoras:",
   "notifications.column_settings.follow_request": "Novas peticións de seguimento:",
   "notifications.column_settings.mention": "Mencións:",
@@ -588,12 +589,6 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "Estase a cargar…",
   "regeneration_indicator.sublabel": "Estase a preparar a túa cronoloxía de inicio!",
-  "relationship_severance_notification.purged_data": "purgada pola administración",
-  "relationship_severance_notification.relationships": "{count, plural, one {# relación} other {# relacións}}",
-  "relationship_severance_notification.types.account_suspension": "A conta foi suspendida",
-  "relationship_severance_notification.types.domain_block": "O dominio foi suspendido",
-  "relationship_severance_notification.types.user_domain_block": "Bloqueaches este dominio",
-  "relationship_severance_notification.view": "Ver",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "hai {number, plural, one {# día} other {# días}}",
   "relative_time.full.hours": "hai {number, plural, one {# hora} other {# horas}}",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 82dec2d86..155708cfa 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "סינון ההודעה הזו",
   "filter_modal.title.status": "סנן הודעה",
   "filtered_notifications_banner.pending_requests": "{count, plural,=0 {אין התראות ממשתמשים ה}one {התראה אחת ממישהו/מישהי ה}two {יש התראותיים ממשתמשים }other {יש # התראות ממשתמשים }}מוכרים לך",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {איזכור פרטי} other {איזכורים פרטיים}}",
   "filtered_notifications_banner.title": "התראות מסוננות",
   "firehose.all": "הכל",
   "firehose.local": "שרת זה",
@@ -471,7 +472,11 @@
   "notification.own_poll": "הסקר שלך הסתיים",
   "notification.poll": "סקר שהצבעת בו הסתיים",
   "notification.reblog": "הודעתך הודהדה על ידי {name}",
-  "notification.severed_relationships": "חתכתם כל קשר עם {name}",
+  "notification.relationships_severance_event": "אבד הקשר עם {name}",
+  "notification.relationships_severance_event.account_suspension": "מנהל.ת משרת {from} השע(ת)ה את {target}, ולפיכך לא תעודכנו יותר על ידם ולא תוכלו להיות איתם בקשר.",
+  "notification.relationships_severance_event.domain_block": "מנהל.ת מאתר {from} חסמו את {target} ובכלל זה {followersCount} מעוקביך וגם {followingCount, plural, one {חשבון אחד} two {שני חשבונות} many {# חשבונות} other {# חשבונות}} מבין נעקביך.",
+  "notification.relationships_severance_event.learn_more": "למידע נוסף",
+  "notification.relationships_severance_event.user_domain_block": "חסמת את {target} ובכלל זה {followersCount} מעוקביך וגם {followingCount, plural, one {חשבון אחד} two {שני חשבונות} many {# חשבונות} other {# חשבונות}} מבין נעקביך.",
   "notification.status": "{name} הרגע פרסמו",
   "notification.update": "{name} ערכו הודעה",
   "notification_requests.accept": "לקבל",
@@ -590,12 +595,6 @@
   "refresh": "רענון",
   "regeneration_indicator.label": "טוען…",
   "regeneration_indicator.sublabel": "פיד הבית שלך בהכנה!",
-  "relationship_severance_notification.purged_data": "המידע נמחק על ידי ההנהלה",
-  "relationship_severance_notification.relationships": "{count, plural, one {קשר אחד}  other {# קשרים}}",
-  "relationship_severance_notification.types.account_suspension": "החשבון הושעה",
-  "relationship_severance_notification.types.domain_block": "השרת הושעה",
-  "relationship_severance_notification.types.user_domain_block": "חסמת שרת זה",
-  "relationship_severance_notification.view": "הצג",
   "relative_time.days": "{number} ימים",
   "relative_time.full.days": "לפני {number, plural, one {# יום} other {# ימים}}",
   "relative_time.full.hours": "לפני {number, plural, one {# שעה} other {# שעות}}",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index d9dfd01a2..c8e57c526 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "E bejegyzés szűrése",
   "filter_modal.title.status": "Egy bejegyzés szűrése",
   "filtered_notifications_banner.pending_requests": "Értesítések {count, plural, =0 {nincsenek} one {egy valósztínűleg ismerős személytől} other {# valószínűleg ismerős személytől}}",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privát említés} other {privát említés}}",
   "filtered_notifications_banner.title": "Szűrt értesítések",
   "firehose.all": "Összes",
   "firehose.local": "Ez a kiszolgáló",
@@ -471,7 +472,11 @@
   "notification.own_poll": "A szavazásod véget ért",
   "notification.poll": "Egy szavazás, melyben részt vettél, véget ért",
   "notification.reblog": "{name} megtolta a bejegyzésedet",
-  "notification.severed_relationships": "A kapcsolatok megszakítva ezzel: {name}",
+  "notification.relationships_severance_event": "Elvesztek a kapcsolatok vele: {name}",
+  "notification.relationships_severance_event.account_suspension": "Egy admin a {from} kiszolgálóról felfüggesztette {target} fiókot, ami azt jelenti, hogy mostantól nem tudsz vele interaktálni vagy tőle értesítéseket kapni.",
+  "notification.relationships_severance_event.domain_block": "Egy admin a {from} kiszolgálón letiltotta {target} domaint, beleértve {followersCount} követődet és {followingCount, plural, one {#} other {#}} általad követett személyt.",
+  "notification.relationships_severance_event.learn_more": "További információk",
+  "notification.relationships_severance_event.user_domain_block": "Letiltottad a(z) {target} domaint, ezzel eltávolítva {followersCount} követőt és {followingCount, plural, one {#} other {#}} követett fiókot.",
   "notification.status": "{name} bejegyzést tett közzé",
   "notification.update": "{name} szerkesztett egy bejegyzést",
   "notification_requests.accept": "Elfogadás",
@@ -484,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Új regisztrálók:",
   "notifications.column_settings.alert": "Asztali értesítések",
   "notifications.column_settings.favourite": "Kedvencek:",
+  "notifications.column_settings.filter_bar.advanced": "Minden kategória megjelenítése",
+  "notifications.column_settings.filter_bar.category": "Gyorsszűrő sáv",
   "notifications.column_settings.follow": "Új követők:",
   "notifications.column_settings.follow_request": "Új követési kérelmek:",
   "notifications.column_settings.mention": "Megemlítések:",
@@ -588,12 +595,6 @@
   "refresh": "Frissítés",
   "regeneration_indicator.label": "Betöltés…",
   "regeneration_indicator.sublabel": "A saját idővonalad épp készül!",
-  "relationship_severance_notification.purged_data": "rendszergazdák által véglegesen törölve",
-  "relationship_severance_notification.relationships": "{count, plural, one {# kapcsolat} other {# kapcsolat}}",
-  "relationship_severance_notification.types.account_suspension": "A fiók fel van függesztve",
-  "relationship_severance_notification.types.domain_block": "A domain fel van függesztve",
-  "relationship_severance_notification.types.user_domain_block": "Blokkoltad ezt a domaint",
-  "relationship_severance_notification.view": "Megtekintés",
   "relative_time.days": "{number}n",
   "relative_time.full.days": "{number, plural, one {# napja} other {# napja}}",
   "relative_time.full.hours": "{number, plural, one {# órája} other {# órája}}",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index b65df2fc5..6bcc79f70 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Sía þessa færslu",
   "filter_modal.title.status": "Sía færslu",
   "filtered_notifications_banner.pending_requests": "Tilkynningar frá {count, plural, =0 {engum} one {einum aðila} other {# aðilum}} sem þú gætir þekkt",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {einkaspjall} other {einkaspjöll}}",
   "filtered_notifications_banner.title": "Síaðar tilkynningar",
   "firehose.all": "Allt",
   "firehose.local": "þessum netþjóni",
@@ -471,6 +472,8 @@
   "notification.own_poll": "Könnuninni þinni er lokið",
   "notification.poll": "Könnun sem þú tókst þátt í er lokið",
   "notification.reblog": "{name} endurbirti færsluna þína",
+  "notification.relationships_severance_event": "Missti tengingar við {name}",
+  "notification.relationships_severance_event.learn_more": "Kanna nánar",
   "notification.status": "{name} sendi inn rétt í þessu",
   "notification.update": "{name} breytti færslu",
   "notification_requests.accept": "Samþykkja",
@@ -589,8 +592,6 @@
   "refresh": "Endurlesa",
   "regeneration_indicator.label": "Hleð inn…",
   "regeneration_indicator.sublabel": "Verið er að útbúa heimastreymið þitt!",
-  "relationship_severance_notification.relationships": "{count, plural, one {# tengsl} other {# tengsl}}",
-  "relationship_severance_notification.view": "Skoða",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "Fyrir {number, plural, one {# degi} other {# dögum}} síðan",
   "relative_time.full.hours": "Fyrir {number, plural, one {# klukkustund} other {# klukkustundum}} síðan",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 090278b83..eddab5f37 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -471,7 +471,9 @@
   "notification.own_poll": "Il tuo sondaggio è terminato",
   "notification.poll": "Un sondaggio in cui hai votato è terminato",
   "notification.reblog": "{name} ha rebloggato il tuo post",
-  "notification.severed_relationships": "Relazioni interrotte con {name}",
+  "notification.relationships_severance_event": "Connessioni perse con {name}",
+  "notification.relationships_severance_event.account_suspension": "Un amministratore da {from} ha sospeso {target}, il che significa che non puoi più ricevere aggiornamenti da loro o interagire con loro.",
+  "notification.relationships_severance_event.learn_more": "Scopri di più",
   "notification.status": "{name} ha appena pubblicato un post",
   "notification.update": "{name} ha modificato un post",
   "notification_requests.accept": "Accetta",
@@ -590,12 +592,6 @@
   "refresh": "Ricarica",
   "regeneration_indicator.label": "Caricamento…",
   "regeneration_indicator.sublabel": "Il feed della tua home è in preparazione!",
-  "relationship_severance_notification.purged_data": "rimossi dagli amministratori",
-  "relationship_severance_notification.relationships": "{count, plural,one {# relazione} other {# relazioni}}",
-  "relationship_severance_notification.types.account_suspension": "L'account è stato sospeso",
-  "relationship_severance_notification.types.domain_block": "Il dominio è stato sospeso",
-  "relationship_severance_notification.types.user_domain_block": "Hai bloccato questo dominio",
-  "relationship_severance_notification.view": "Visualizza",
   "relative_time.days": "{number}g",
   "relative_time.full.days": "{number, plural, one {# giorno} other {# giorni}} fa",
   "relative_time.full.hours": "{number, plural, one {# ora} other {# ore}} fa",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 5553636f2..e15089d0c 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "설문을 마침",
   "notification.poll": "참여한 설문이 종료됨",
   "notification.reblog": "{name} 님이 부스트했습니다",
-  "notification.severed_relationships": "{name} 님과의 관계가 단절되었습니다",
   "notification.status": "{name} 님이 방금 게시물을 올렸습니다",
   "notification.update": "{name} 님이 게시물을 수정했습니다",
   "notification_requests.accept": "수락",
@@ -589,12 +588,6 @@
   "refresh": "새로고침",
   "regeneration_indicator.label": "불러오는 중…",
   "regeneration_indicator.sublabel": "홈 피드를 준비하고 있습니다!",
-  "relationship_severance_notification.purged_data": "관리자에 의해 제거되었습니다",
-  "relationship_severance_notification.relationships": "{count, plural, other {# 건의 관계}}",
-  "relationship_severance_notification.types.account_suspension": "계정이 정지되었습니다",
-  "relationship_severance_notification.types.domain_block": "도메인이 정지되었습니다",
-  "relationship_severance_notification.types.user_domain_block": "내가 이 도메인을 차단했습니다",
-  "relationship_severance_notification.view": "보기",
   "relative_time.days": "{number}일 전",
   "relative_time.full.days": "{number} 일 전",
   "relative_time.full.hours": "{number} 시간 전",
diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json
index 1eb8aa4ab..dd76baaf6 100644
--- a/app/javascript/mastodon/locales/lad.json
+++ b/app/javascript/mastodon/locales/lad.json
@@ -571,8 +571,6 @@
   "refresh": "Arefreska",
   "regeneration_indicator.label": "Eskargando…",
   "regeneration_indicator.sublabel": "Tu linya de tiempo prinsipala esta preparando!",
-  "relationship_severance_notification.types.user_domain_block": "Blokates este domeno",
-  "relationship_severance_notification.view": "Mira",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "antes {number, plural, one {# diya} other {# diyas}}",
   "relative_time.full.hours": "antes {number, plural, one {# ora} other {# oras}}",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index 728485b2b..f9ef7e242 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -555,9 +555,6 @@
   "refresh": "Atnaujinti",
   "regeneration_indicator.label": "Kraunama…",
   "regeneration_indicator.sublabel": "Ruošiamas tavo pagrindinis srautas!",
-  "relationship_severance_notification.relationships": "{count, plural, one {# santykis} few {# santykiai} many {# santykio} other {# santykių}}",
-  "relationship_severance_notification.types.user_domain_block": "Užblokavai šį domeną",
-  "relationship_severance_notification.view": "Peržiūrėti",
   "relative_time.days": "{number} d.",
   "relative_time.full.days": "prieš {number, plural, one {# dieną} few {# dienas} many {# dienos} other {# dienų}}",
   "relative_time.full.hours": "prieš {number, plural, one {# valandą} few {# valandas} many {# valandos} other {# valandų}}",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 21fa46faa..55ceb564b 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -626,7 +626,7 @@
   "status.direct_indicator": "Pieminēts privāti",
   "status.edit": "Labot",
   "status.edited_x_times": "Labots {count, plural, one {{count} reizi} other {{count} reizes}}",
-  "status.embed": "Iestrādāt",
+  "status.embed": "Iegult",
   "status.favourite": "Izlasē",
   "status.filter": "Filtrē šo ziņu",
   "status.filtered": "Filtrēts",
@@ -634,7 +634,7 @@
   "status.history.created": "{name} izveidoja {date}",
   "status.history.edited": "{name} laboja {date}",
   "status.load_more": "Ielādēt vairāk",
-  "status.media.open": "Noklikšķini, lai atvērtu",
+  "status.media.open": "Jānoklikšķina, lai atvērtu",
   "status.media.show": "Noklikšķini, lai parādītu",
   "status.media_hidden": "Multivides ir paslēpts",
   "status.mention": "Pieminēt @{name}",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 1e710bda4..c47831b38 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Dit bericht filteren",
   "filter_modal.title.status": "Een bericht filteren",
   "filtered_notifications_banner.pending_requests": "Meldingen van {count, plural, =0 {niemand} one {één persoon} other {# mensen}} die je misschien kent",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privébericht} other {privéberichten}}",
   "filtered_notifications_banner.title": "Gefilterde meldingen",
   "firehose.all": "Alles",
   "firehose.local": "Deze server",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Jouw peiling is beëindigd",
   "notification.poll": "Een peiling waaraan jij hebt meegedaan is beëindigd",
   "notification.reblog": "{name} boostte jouw bericht",
-  "notification.severed_relationships": "Volgrelaties met {name} verbroken",
+  "notification.relationships_severance_event": "Verloren verbindingen met {name}",
+  "notification.relationships_severance_event.account_suspension": "Een beheerder van {from} heeft {target} geschorst, wat betekent dat je geen updates meer van hen kunt ontvangen of met hen kunt communiceren.",
+  "notification.relationships_severance_event.domain_block": "Een beheerder van {from} heeft {target} geblokkeerd, inclusief {followersCount} van jouw volgers en {followingCount, plural, one {# account} other {# accounts}} die jij volgt.",
+  "notification.relationships_severance_event.learn_more": "Meer informatie",
+  "notification.relationships_severance_event.user_domain_block": "Je hebt {target} geblokkeerd, waarmee je {followersCount} van je volgers en {followingCount, plural, one {# account} other {# accounts}} die jij volgt, bent verloren.",
   "notification.status": "{name} heeft zojuist een bericht geplaatst",
   "notification.update": "{name} heeft een bericht bewerkt",
   "notification_requests.accept": "Accepteren",
@@ -590,12 +595,6 @@
   "refresh": "Vernieuwen",
   "regeneration_indicator.label": "Aan het laden…",
   "regeneration_indicator.sublabel": "Jouw starttijdlijn wordt aangemaakt!",
-  "relationship_severance_notification.purged_data": "verwijderd door beheerders",
-  "relationship_severance_notification.relationships": "{count, plural, one {# volgrelatie} other {# volgrelaties}}",
-  "relationship_severance_notification.types.account_suspension": "Account is opgeschort",
-  "relationship_severance_notification.types.domain_block": "Domein is opgeschort",
-  "relationship_severance_notification.types.user_domain_block": "Je hebt dit domein geblokkeerd",
-  "relationship_severance_notification.view": "Weergeven",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# dag} other {# dagen}} geleden",
   "relative_time.full.hours": "{number, plural, one {# uur} other {# uur}} geleden",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index 7742d83e1..ab44c691d 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrer dette innlegget",
   "filter_modal.title.status": "Filtrer eit innlegg",
   "filtered_notifications_banner.pending_requests": "Varsel frå {count, plural, =0 {ingen} one {ein person} other {# folk}} du kanskje kjenner",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omtale} other {private omtaler}}",
   "filtered_notifications_banner.title": "Filtrerte varslingar",
   "firehose.all": "Alle",
   "firehose.local": "Denne tenaren",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Rundspørjinga di er ferdig",
   "notification.poll": "Ei rundspørjing du har røysta i er ferdig",
   "notification.reblog": "{name} framheva innlegget ditt",
-  "notification.severed_relationships": "Forholda med {name} er brotne",
+  "notification.relationships_severance_event": "Tapte samband med {name}",
+  "notification.relationships_severance_event.account_suspension": "Ein administrator på {from} har utvist {target}, som tyder at du ikkje lenger får oppdateringar frå dei eller kan samhandla med dei.",
+  "notification.relationships_severance_event.domain_block": "Ein administrator på {from} har blokkert {target}, inkludert {followersCount} av fylgjarane dine og {followingCount, plural, one {# konto} other {# kontoar}} du fylgjer.",
+  "notification.relationships_severance_event.learn_more": "Lær meir",
+  "notification.relationships_severance_event.user_domain_block": "Du har blokkert {target}, fjerna {followersCount} av fylgjarane dine og {followingCount, plural, one {# konto} other {# kontoar}} du fylgjer.",
   "notification.status": "{name} la nettopp ut",
   "notification.update": "{name} redigerte eit innlegg",
   "notification_requests.accept": "Godkjenn",
@@ -484,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Nyleg registrerte:",
   "notifications.column_settings.alert": "Skrivebordsvarsel",
   "notifications.column_settings.favourite": "Favorittar:",
+  "notifications.column_settings.filter_bar.advanced": "Vis alle kategoriar",
+  "notifications.column_settings.filter_bar.category": "Snøggfilterline",
   "notifications.column_settings.follow": "Nye fylgjarar:",
   "notifications.column_settings.follow_request": "Ny fylgjarførespurnader:",
   "notifications.column_settings.mention": "Omtalar:",
@@ -588,12 +595,6 @@
   "refresh": "Oppdater",
   "regeneration_indicator.label": "Lastar…",
   "regeneration_indicator.sublabel": "Heimetidslina di vert førebudd!",
-  "relationship_severance_notification.purged_data": "sletta av administratorar",
-  "relationship_severance_notification.relationships": "{count, plural, one {# forhold} other {# forhold}}",
-  "relationship_severance_notification.types.account_suspension": "Kontoen er utvist",
-  "relationship_severance_notification.types.domain_block": "Domenet er utestengt",
-  "relationship_severance_notification.types.user_domain_block": "Du blokkerte dette domenet",
-  "relationship_severance_notification.view": "Sjå",
   "relative_time.days": "{number}dg",
   "relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sidan",
   "relative_time.full.hours": "{number, plural, one {# time} other {# timar}} sidan",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 3ee134d6c..718aa32d2 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtruj ten wpis",
   "filter_modal.title.status": "Filtruj wpis",
   "filtered_notifications_banner.pending_requests": "Powiadomienia od {count, plural, =0 {żadnej osoby którą możesz znać} one {# osoby którą możesz znać} other {# osób które możesz znać}}",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {prywatna wzmianka} few {prywatne wzmianki} other {prywatnych wzmianek}}",
   "filtered_notifications_banner.title": "Powiadomienia filtrowane",
   "firehose.all": "Wszystko",
   "firehose.local": "Ten serwer",
@@ -471,7 +472,10 @@
   "notification.own_poll": "Twoje głosowanie zakończyło się",
   "notification.poll": "Głosowanie w którym brałeś(-aś) udział zakończyło się",
   "notification.reblog": "Twój post został podbity przez {name}",
-  "notification.severed_relationships": "Zerwano związki z {name}",
+  "notification.relationships_severance_event": "Utracone związki z {name}",
+  "notification.relationships_severance_event.account_suspension": "Administrator z {from} zawiesił {target}, więc nie dostaniesz wieści ani nie wejdziesz w interakcje z użytkownikami z tego serwera.",
+  "notification.relationships_severance_event.domain_block": "Administrator z {from} zablokował {target}, w tym {followersCount} z Twoich obserwujących i {followingCount, plural, one {# konto} other {# konta}} które obserwujesz.",
+  "notification.relationships_severance_event.learn_more": "Dowiedz się więcej",
   "notification.status": "{name} opublikował(a) nowy wpis",
   "notification.update": "{name} edytował(a) post",
   "notification_requests.accept": "Akceptuj",
@@ -590,12 +594,6 @@
   "refresh": "Odśwież",
   "regeneration_indicator.label": "Ładuję…",
   "regeneration_indicator.sublabel": "Twoja oś czasu jest przygotowywana!",
-  "relationship_severance_notification.purged_data": "wyczyszczone przez administratorów",
-  "relationship_severance_notification.relationships": "{count, plural, one {# związek} few {# związki} other {# związków}}",
-  "relationship_severance_notification.types.account_suspension": "Konto zostało zawieszone",
-  "relationship_severance_notification.types.domain_block": "Domena została zawieszona",
-  "relationship_severance_notification.types.user_domain_block": "Domena przez ciebie blokowana",
-  "relationship_severance_notification.view": "Pokaż",
   "relative_time.days": "{number} dni",
   "relative_time.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}} temu",
   "relative_time.full.hours": "{number, plural, one {# godzinę} few {# godziny} many {# godzin} other {# godzin}} temu",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 6732973d5..3f7f198ef 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "A sua votação terminou",
   "notification.poll": "Uma votação em que participaste chegou ao fim",
   "notification.reblog": "{name} reforçou a tua publicação",
-  "notification.severed_relationships": "Relações com {name} cessadas",
   "notification.status": "{name} acabou de publicar",
   "notification.update": "{name} editou uma publicação",
   "notification_requests.accept": "Aceitar",
@@ -590,12 +589,6 @@
   "refresh": "Actualizar",
   "regeneration_indicator.label": "A carregar…",
   "regeneration_indicator.sublabel": "A tua página inicial está a ser preparada!",
-  "relationship_severance_notification.purged_data": "purgado pelos administradores",
-  "relationship_severance_notification.relationships": "{count, plural,one {# relação} other {# relações}}",
-  "relationship_severance_notification.types.account_suspension": "A conta foi suspensa",
-  "relationship_severance_notification.types.domain_block": "O domínio foi suspenso",
-  "relationship_severance_notification.types.user_domain_block": "Bloqueou este domínio",
-  "relationship_severance_notification.view": "Visualizar",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural,one {# dia} other {# dias}} atrás",
   "relative_time.full.hours": "{number, plural,one {# hora}other {# horas}} atrás",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 0ab147569..d143fda52 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -445,6 +445,7 @@
   "notification.own_poll": "Vaša anketa sa skončila",
   "notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila",
   "notification.reblog": "{name} zdieľa váš príspevok",
+  "notification.relationships_severance_event.learn_more": "Zisti viac",
   "notification.status": "{name} uverejňuje niečo nové",
   "notification.update": "{name} upravuje príspevok",
   "notification_requests.accept": "Prijať",
@@ -557,8 +558,6 @@
   "refresh": "Obnoviť",
   "regeneration_indicator.label": "Načítavanie…",
   "regeneration_indicator.sublabel": "Váš domovský kanál sa pripravuje.",
-  "relationship_severance_notification.types.user_domain_block": "Túto doménu si zablokoval/a",
-  "relationship_severance_notification.view": "Zobraziť",
   "relative_time.days": "{number} dní",
   "relative_time.full.days": "Pred {number, plural, one {# dňom} other {# dňami}}",
   "relative_time.full.hours": "Pred {number, plural, one {# hodinou} other {# hodinami}}",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index d31b41080..80b52ac10 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "Vaša anketa je zaključena",
   "notification.poll": "Anketa, v kateri ste sodelovali, je zaključena",
   "notification.reblog": "{name} je izpostavila/a vašo objavo",
-  "notification.severed_relationships": "Veze z {name} prekinjene",
   "notification.status": "{name} je pravkar objavil/a",
   "notification.update": "{name} je uredil(a) objavo",
   "notification_requests.accept": "Sprejmi",
@@ -484,6 +483,8 @@
   "notifications.column_settings.admin.sign_up": "Novi vpisi:",
   "notifications.column_settings.alert": "Namizna obvestila",
   "notifications.column_settings.favourite": "Priljubljeni:",
+  "notifications.column_settings.filter_bar.advanced": "Prikaži vse kategorije",
+  "notifications.column_settings.filter_bar.category": "Vrstica za hitro filtriranje",
   "notifications.column_settings.follow": "Novi sledilci:",
   "notifications.column_settings.follow_request": "Nove prošnje za sledenje:",
   "notifications.column_settings.mention": "Omembe:",
@@ -588,12 +589,6 @@
   "refresh": "Osveži",
   "regeneration_indicator.label": "Nalaganje …",
   "regeneration_indicator.sublabel": "Vaš domači vir se pripravlja!",
-  "relationship_severance_notification.purged_data": "očistili skrbniki",
-  "relationship_severance_notification.relationships": "{count, plural, one {# veza} two {# vezi} few {# veze} other {# vez}}",
-  "relationship_severance_notification.types.account_suspension": "Račun je bil suspendiran",
-  "relationship_severance_notification.types.domain_block": "Domena je bila suspendirana",
-  "relationship_severance_notification.types.user_domain_block": "Domeno ste blokirali",
-  "relationship_severance_notification.view": "Pogled",
   "relative_time.days": "{number} d",
   "relative_time.full.days": "{number, plural, one {pred # dnem} two {pred # dnevoma} few {pred # dnevi} other {pred # dnevi}}",
   "relative_time.full.hours": "{number, plural, one {pred # uro} two {pred # urama} few {pred # urami} other {pred # urami}}",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index d69231d82..026e19820 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Përdorni një kategori ekzistuese, ose krijoni një të re",
   "filter_modal.select_filter.title": "Filtroje këtë postim",
   "filter_modal.title.status": "Filtroni një postim",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {përmendje private} other {përmendje private}}",
   "filtered_notifications_banner.title": "Njoftime të filtruar",
   "firehose.all": "Krejt",
   "firehose.local": "Këtë shërbyes",
@@ -470,7 +471,11 @@
   "notification.own_poll": "Pyetësori juaj ka përfunduar",
   "notification.poll": "Ka përfunduar një pyetësor ku keni votuar",
   "notification.reblog": "{name} përforcoi mesazhin tuaj",
-  "notification.severed_relationships": "Marrëdhëniet me {name} u ndërprenë",
+  "notification.relationships_severance_event": "Lidhje të humbura me {name}",
+  "notification.relationships_severance_event.account_suspension": "Një përgjegjës nga {from} ka pezulluar {target}, që do të thotë se s’mund të merrni më përditësime prej tij, apo të ndërveproni me të.",
+  "notification.relationships_severance_event.domain_block": "Një përgjegjës nga {from} ka bllokuar {target}, përfshi {followersCount} të ndjekësve tuaj dhe {followingCount, plural, one {# llogari} other {# llogari}} që ndiqni.",
+  "notification.relationships_severance_event.learn_more": "Mësoni më tepër",
+  "notification.relationships_severance_event.user_domain_block": "Keni bllokuar {target}, duke hequr {followersCount} nga ndjekësit tuaj dhe {followingCount, plural, one {# llogari} other {# llogari}} që ndiqni.",
   "notification.status": "{name} sapo postoi",
   "notification.update": "{name} përpunoi një postim",
   "notification_requests.accept": "Pranoje",
@@ -587,12 +592,6 @@
   "refresh": "Rifreskoje",
   "regeneration_indicator.label": "Po ngarkohet…",
   "regeneration_indicator.sublabel": "Prurja juaj vetjake po përgatitet!",
-  "relationship_severance_notification.purged_data": "spastruar nga përgjegjës",
-  "relationship_severance_notification.relationships": "{count, plural, one {# marrëdhënie} other {# marrëdhënie}}",
-  "relationship_severance_notification.types.account_suspension": "Llogaria është pezulluar",
-  "relationship_severance_notification.types.domain_block": "Përkatësia është pezulluar",
-  "relationship_severance_notification.types.user_domain_block": "E bllokuat këtë përkatësi",
-  "relationship_severance_notification.view": "Shiheni",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# ditë} other {# ditë}} më parë",
   "relative_time.full.hours": "{number, plural, one {# orë} other {# orë}} më parë",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index b28b4826d..770daf378 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -459,6 +459,7 @@
   "notification.own_poll": "Din röstning har avslutats",
   "notification.poll": "En omröstning du röstat i har avslutats",
   "notification.reblog": "{name} boostade ditt inlägg",
+  "notification.relationships_severance_event.learn_more": "Läs mer",
   "notification.status": "{name} publicerade just ett inlägg",
   "notification.update": "{name} redigerade ett inlägg",
   "notification_requests.accept": "Godkänn",
@@ -573,11 +574,6 @@
   "refresh": "Läs om",
   "regeneration_indicator.label": "Laddar…",
   "regeneration_indicator.sublabel": "Ditt hemmaflöde förbereds!",
-  "relationship_severance_notification.purged_data": "rensad av administratörer",
-  "relationship_severance_notification.types.account_suspension": "Ditt konto har blivit avstängt",
-  "relationship_severance_notification.types.domain_block": "Domänen har stängts av",
-  "relationship_severance_notification.types.user_domain_block": "Du blockerade denna domän",
-  "relationship_severance_notification.view": "Visa",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sedan",
   "relative_time.full.hours": "{number, plural, one {# timme} other {# timmar}} sedan",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 4490f038c..952ed5adf 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "กรองโพสต์นี้",
   "filter_modal.title.status": "กรองโพสต์",
   "filtered_notifications_banner.pending_requests": "การแจ้งเตือนจาก {count, plural, =0 {ไม่มีใคร} other {# คน}} ที่คุณอาจรู้จัก",
+  "filtered_notifications_banner.private_mentions": "{count, plural, other {การกล่าวถึงแบบส่วนตัว}}",
   "filtered_notifications_banner.title": "การแจ้งเตือนที่กรองอยู่",
   "firehose.all": "ทั้งหมด",
   "firehose.local": "เซิร์ฟเวอร์นี้",
@@ -471,7 +472,11 @@
   "notification.own_poll": "การสำรวจความคิดเห็นของคุณได้สิ้นสุดแล้ว",
   "notification.poll": "การสำรวจความคิดเห็นที่คุณได้ลงคะแนนได้สิ้นสุดแล้ว",
   "notification.reblog": "{name} ได้ดันโพสต์ของคุณ",
-  "notification.severed_relationships": "ตัดขาดความสัมพันธ์กับ {name} แล้ว",
+  "notification.relationships_severance_event": "สูญเสียการเชื่อมต่อกับ {name}",
+  "notification.relationships_severance_event.account_suspension": "ผู้ดูแลจาก {from} ได้ระงับ {target} ซึ่งหมายความว่าคุณจะไม่สามารถรับการอัปเดตจากเขาหรือโต้ตอบกับเขาได้อีกต่อไป",
+  "notification.relationships_severance_event.domain_block": "ผู้ดูแลจาก {from} ได้ปิดกั้น {target} รวมถึง {followersCount} ผู้ติดตามของคุณและ {followingCount, plural, other {# บัญชี}}ที่คุณติดตาม",
+  "notification.relationships_severance_event.learn_more": "เรียนรู้เพิ่มเติม",
+  "notification.relationships_severance_event.user_domain_block": "คุณได้ปิดกั้น {target} เอา {followersCount} ผู้ติดตามของคุณและ {followingCount, plural, other {# บัญชี}}ที่คุณติดตามออก",
   "notification.status": "{name} เพิ่งโพสต์",
   "notification.update": "{name} ได้แก้ไขโพสต์",
   "notification_requests.accept": "ยอมรับ",
@@ -590,12 +595,6 @@
   "refresh": "รีเฟรช",
   "regeneration_indicator.label": "กำลังโหลด…",
   "regeneration_indicator.sublabel": "กำลังเตรียมฟีดหน้าแรกของคุณ!",
-  "relationship_severance_notification.purged_data": "ล้างข้อมูลโดยผู้ดูแล",
-  "relationship_severance_notification.relationships": "{count, plural, other {# ความสัมพันธ์}}",
-  "relationship_severance_notification.types.account_suspension": "ระงับบัญชีแล้ว",
-  "relationship_severance_notification.types.domain_block": "ระงับโดเมนแล้ว",
-  "relationship_severance_notification.types.user_domain_block": "คุณได้ปิดกั้นโดเมนนี้",
-  "relationship_severance_notification.view": "ดู",
   "relative_time.days": "{number} วัน",
   "relative_time.full.days": "{number, plural, other {# วัน}}ที่แล้ว",
   "relative_time.full.hours": "{number, plural, other {# ชั่วโมง}}ที่แล้ว",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 12d82c70e..8dcd2d202 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Bu gönderiyi süzgeçle",
   "filter_modal.title.status": "Bir gönderi süzgeçle",
   "filtered_notifications_banner.pending_requests": "Bildiğiniz {count, plural, =0 {hiç kimseden} one {bir kişiden} other {# kişiden}} bildirim",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {özel değinme} other {özel değinme}}",
   "filtered_notifications_banner.title": "Filtrelenmiş bildirimler",
   "firehose.all": "Tümü",
   "firehose.local": "Bu sunucu",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Anketiniz sona erdi",
   "notification.poll": "Oy verdiğiniz bir anket sona erdi",
   "notification.reblog": "{name} gönderini yeniden paylaştı",
-  "notification.severed_relationships": "{name} ile ilişkiler koptu",
+  "notification.relationships_severance_event": "{name} ile bağlantılar koptu",
+  "notification.relationships_severance_event.account_suspension": "{from} yöneticisi, {target} askıya aldı, bunun anlamı onlardan artık güncelleme alamayacak veya etkileşemeyeceksiniz demektir.",
+  "notification.relationships_severance_event.domain_block": "{from} yöneticisi {target} engelledi, {followersCount} takipçiniz ve takip ettiğiniz {followingCount, plural, one {# hesap} other {# hesap}} buna dahil.",
+  "notification.relationships_severance_event.learn_more": "Daha fazlası",
+  "notification.relationships_severance_event.user_domain_block": "{target} engellediniz, takipçilerinizden {followersCount} ve takip eden {followingCount, plural, one {# hesap} other {# hesap}} kaldırılıyor.",
   "notification.status": "{name} az önce gönderdi",
   "notification.update": "{name} bir gönderiyi düzenledi",
   "notification_requests.accept": "Onayla",
@@ -590,12 +595,6 @@
   "refresh": "Yenile",
   "regeneration_indicator.label": "Yükleniyor…",
   "regeneration_indicator.sublabel": "Ana akışın hazırlanıyor!",
-  "relationship_severance_notification.purged_data": "yöneticiler tarafından temizlendi",
-  "relationship_severance_notification.relationships": "{count, plural, one {# ilişki} other {# ilişki}}",
-  "relationship_severance_notification.types.account_suspension": "Hesap askıya alındı",
-  "relationship_severance_notification.types.domain_block": "Alan adı askıya alındı",
-  "relationship_severance_notification.types.user_domain_block": "Bu alan adını engellediniz",
-  "relationship_severance_notification.view": "Görüntüle",
   "relative_time.days": "{number}d",
   "relative_time.full.days": "{number, plural, one {# gün} other {# gün}} önce",
   "relative_time.full.hours": "{number, plural, one {# saat} other {# saat}} önce",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index f2e58f093..0648fde5b 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -460,7 +460,9 @@
   "notification.own_poll": "Ваше опитування завершилося",
   "notification.poll": "Опитування, у якому ви голосували, скінчилося",
   "notification.reblog": "{name} поширює ваш допис",
-  "notification.severed_relationships": "Зв'язки з {name} розірвані",
+  "notification.relationships_severance_event": "Втрачено з'єднання з {name}",
+  "notification.relationships_severance_event.account_suspension": "Адміністратор з {from} призупинив {target}, що означає, що ви більше не можете отримувати оновлення від них або взаємодіяти з ними.",
+  "notification.relationships_severance_event.learn_more": "Дізнатися більше",
   "notification.status": "{name} щойно дописує",
   "notification.update": "{name} змінює допис",
   "notification_requests.accept": "Прийняти",
@@ -575,12 +577,6 @@
   "refresh": "Оновити",
   "regeneration_indicator.label": "Завантаження…",
   "regeneration_indicator.sublabel": "Хвилинку, ми готуємо вашу стрічку!",
-  "relationship_severance_notification.purged_data": "очищено адміністраторами",
-  "relationship_severance_notification.relationships": "{count, plural, one {# зв'язок} few {# зв'язки} many {# зв'язків} other {# зв'язок}}",
-  "relationship_severance_notification.types.account_suspension": "Обліковий запис призупинено",
-  "relationship_severance_notification.types.domain_block": "Домен призупинено",
-  "relationship_severance_notification.types.user_domain_block": "Ви заблокували цей домен",
-  "relationship_severance_notification.view": "Вигляд",
   "relative_time.days": "{number}д",
   "relative_time.full.days": "{number, plural, one {# день} few {# дні} other {# днів}} тому",
   "relative_time.full.hours": "{number, plural, one {# година} few {# години} other {# годин}} тому",
diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json
index 9b09d2145..58c025494 100644
--- a/app/javascript/mastodon/locales/vi.json
+++ b/app/javascript/mastodon/locales/vi.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Lọc tút này",
   "filter_modal.title.status": "Lọc một tút",
   "filtered_notifications_banner.pending_requests": "Thông báo từ {count, plural, =0 {không ai} other {# người}} bạn có thể biết",
+  "filtered_notifications_banner.private_mentions": "{count, plural, other {lượt nhắc}}",
   "filtered_notifications_banner.title": "Thông báo đã lọc",
   "firehose.all": "Toàn bộ",
   "firehose.local": "Máy chủ này",
@@ -471,7 +472,11 @@
   "notification.own_poll": "Cuộc bình chọn của bạn đã kết thúc",
   "notification.poll": "Cuộc bình chọn đã kết thúc",
   "notification.reblog": "{name} đăng lại tút của bạn",
-  "notification.severed_relationships": "Mối quan hệ với {name} bị cắt đứt",
+  "notification.relationships_severance_event": "Mất kết nối với {name}",
+  "notification.relationships_severance_event.account_suspension": "Quản trị viên {from} đã vô hiệu hóa {target}, điều này có nghĩa là bạn không còn có thể nhận được cập nhật từ họ hoặc tương tác với họ nữa.",
+  "notification.relationships_severance_event.domain_block": "Quản trị viên {from} đã chặn {target}, bao gồm {followersCount} người theo dõi bạn và {followingCount, plural, other {# người}} mà bạn theo dõi.",
+  "notification.relationships_severance_event.learn_more": "Tìm hiểu thêm",
+  "notification.relationships_severance_event.user_domain_block": "Bạn đã chặn {target}, xóa {followersCount} người theo dõi bạn và {followingCount, plural, other {# người}} theo dõi bạn.",
   "notification.status": "{name} đăng tút mới",
   "notification.update": "{name} đã sửa tút",
   "notification_requests.accept": "Chấp nhận",
@@ -484,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Người mới tham gia:",
   "notifications.column_settings.alert": "Báo trên máy tính",
   "notifications.column_settings.favourite": "Lượt thích:",
+  "notifications.column_settings.filter_bar.advanced": "Toàn bộ",
+  "notifications.column_settings.filter_bar.category": "Thanh lọc nhanh",
   "notifications.column_settings.follow": "Người theo dõi:",
   "notifications.column_settings.follow_request": "Yêu cầu theo dõi:",
   "notifications.column_settings.mention": "Lượt nhắc đến:",
@@ -588,12 +595,6 @@
   "refresh": "Làm mới",
   "regeneration_indicator.label": "Đang tải…",
   "regeneration_indicator.sublabel": "Trang chủ của bạn đang được cập nhật!",
-  "relationship_severance_notification.purged_data": "bị quản trị viên xóa",
-  "relationship_severance_notification.relationships": "{count, plural, other {# mối quan hệ}}",
-  "relationship_severance_notification.types.account_suspension": "Người này đã bị vô hiệu hóa",
-  "relationship_severance_notification.types.domain_block": "Máy chủ này đã bị vô hiệu hóa",
-  "relationship_severance_notification.types.user_domain_block": "Bạn đã chặn máy chủ này",
-  "relationship_severance_notification.view": "Chi tiết",
   "relative_time.days": "{number} ngày",
   "relative_time.full.days": "{number, plural, other {# ngày}}",
   "relative_time.full.hours": "{number, plural, other {# giờ}}",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 52a98d000..ca82c8d7c 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "过滤此嘟文",
   "filter_modal.title.status": "过滤一条嘟文",
   "filtered_notifications_banner.pending_requests": "来自你可能认识的 {count, plural, =0 {0 个人} other {# 个人}}的通知",
+  "filtered_notifications_banner.private_mentions": "{count, plural, other {私下提及}}",
   "filtered_notifications_banner.title": "通知(已过滤)",
   "firehose.all": "全部",
   "firehose.local": "此服务器",
@@ -471,7 +472,11 @@
   "notification.own_poll": "你的投票已经结束",
   "notification.poll": "你参与的一个投票已经结束",
   "notification.reblog": "{name} 转发了你的嘟文",
-  "notification.severed_relationships": "与 {name} 的关系已被切断",
+  "notification.relationships_severance_event": "与 {name} 的联系已断开",
+  "notification.relationships_severance_event.account_suspension": "一名来自 {from} 的管理员已经封禁了{target},这意味着你将无法再收到他们的更新或与他们互动。",
+  "notification.relationships_severance_event.domain_block": "一名来自 {from} 的管理员已经屏蔽了 {target},其中包括你的 {followersCount} 个关注者和 {followingCount, plural, other {# 个关注}}。",
+  "notification.relationships_severance_event.learn_more": "了解更多",
+  "notification.relationships_severance_event.user_domain_block": "你已经屏蔽了 {target},移除了你的 {followersCount} 个关注者和 {followingCount, plural, other {# 个关注}}。",
   "notification.status": "{name} 刚刚发布嘟文",
   "notification.update": "{name} 编辑了嘟文",
   "notification_requests.accept": "接受",
@@ -590,12 +595,6 @@
   "refresh": "刷新",
   "regeneration_indicator.label": "加载中…",
   "regeneration_indicator.sublabel": "你的主页动态正在准备中!",
-  "relationship_severance_notification.purged_data": "被管理员清除",
-  "relationship_severance_notification.relationships": "{count, plural, other {# 条关系}}",
-  "relationship_severance_notification.types.account_suspension": "账户已被封禁",
-  "relationship_severance_notification.types.domain_block": "域名已被封禁",
-  "relationship_severance_notification.types.user_domain_block": "你屏蔽了这个域名",
-  "relationship_severance_notification.view": "查看",
   "relative_time.days": "{number} 天前",
   "relative_time.full.days": "{number, plural, one {# 天} other {# 天}}前",
   "relative_time.full.hours": "{number, plural, one {# 小时} other {# 小时}}前",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 68be293df..d618b68e2 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -471,7 +471,6 @@
   "notification.own_poll": "你的投票已結束",
   "notification.poll": "你參與過的一個投票已經結束",
   "notification.reblog": "{name} 轉推你的文章",
-  "notification.severed_relationships": "已斷絕與 {name} 的關係",
   "notification.status": "{name} 剛發表了文章",
   "notification.update": "{name} 編輯了帖文",
   "notification_requests.accept": "接受",
@@ -588,12 +587,6 @@
   "refresh": "重新整理",
   "regeneration_indicator.label": "載入中……",
   "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!",
-  "relationship_severance_notification.purged_data": "已被管理員清除",
-  "relationship_severance_notification.relationships": "{count, plural, one {# 個關係} other {# 個關係}}",
-  "relationship_severance_notification.types.account_suspension": "帳號已被停權",
-  "relationship_severance_notification.types.domain_block": "網域已被停權",
-  "relationship_severance_notification.types.user_domain_block": "你封鎖了此網域",
-  "relationship_severance_notification.view": "查看",
   "relative_time.days": "{number}日前",
   "relative_time.full.days": "{number, plural, one {# 天} other {# 天}}前",
   "relative_time.full.hours": "{number, plural, one {# 小時} other {# 小時}}前",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index d8e1e1e32..22f5420f8 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "過濾此嘟文",
   "filter_modal.title.status": "過濾一則嘟文",
   "filtered_notifications_banner.pending_requests": "來自您可能認識的 {count, plural, =0 {0 人} other {# 人}} 之通知",
+  "filtered_notifications_banner.private_mentions": "{count, plural, other {# 則私訊}}",
   "filtered_notifications_banner.title": "已過濾之通知",
   "firehose.all": "全部",
   "firehose.local": "本站",
@@ -471,7 +472,11 @@
   "notification.own_poll": "您的投票已結束",
   "notification.poll": "您曾投過的投票已經結束",
   "notification.reblog": "{name} 已轉嘟您的嘟文",
-  "notification.severed_relationships": "已斷絕與 {name} 之服務關係",
+  "notification.relationships_severance_event": "與 {name} 失去連結",
+  "notification.relationships_severance_event.account_suspension": "{from} 之管理員已將 {target} 停權,意味著您將不再收到來自他們的更新或與之互動。",
+  "notification.relationships_severance_event.domain_block": "{from} 之管理員已將 {target} 封鎖,包含 {followersCount} 名您的跟隨者及 {followingCount, plural, other {#}} 名您跟隨的帳號。",
+  "notification.relationships_severance_event.learn_more": "了解更多",
+  "notification.relationships_severance_event.user_domain_block": "您已將 {target} 封鎖,將移除 {followersCount} 名您的跟隨者及 {followingCount, plural, other {#}} 名您跟隨的帳號。",
   "notification.status": "{name} 剛剛嘟文",
   "notification.update": "{name} 已編輯嘟文",
   "notification_requests.accept": "接受",
@@ -590,12 +595,6 @@
   "refresh": "重新整理",
   "regeneration_indicator.label": "載入中…",
   "regeneration_indicator.sublabel": "您的首頁時間軸正在準備中!",
-  "relationship_severance_notification.purged_data": "已被管理員清除",
-  "relationship_severance_notification.relationships": "{count, plural, other {# 個服務關係}}",
-  "relationship_severance_notification.types.account_suspension": "該帳號已被停權",
-  "relationship_severance_notification.types.domain_block": "該網域已被停權",
-  "relationship_severance_notification.types.user_domain_block": "您已封鎖此網域",
-  "relationship_severance_notification.view": "檢視",
   "relative_time.days": "{number} 天",
   "relative_time.full.days": "{number, plural, other {# 天}}前",
   "relative_time.full.hours": "{number, plural, one {# 小時} other {# 小時}}前",
diff --git a/config/locales/devise.hu.yml b/config/locales/devise.hu.yml
index 459bd01d9..d8958d5fb 100644
--- a/config/locales/devise.hu.yml
+++ b/config/locales/devise.hu.yml
@@ -43,13 +43,13 @@ hu:
         title: Emailcím megerősítése
       reset_password_instructions:
         action: Jelszó módosítása
-        explanation: A fiókodhoz tartozó jelszó módosítását kezdeményezted.
-        extra: Amennyiben nem te kezdeményezted a módosítást, kérjük tekintsd ezt az emailt tárgytalannak. A jelszavad változatlan marad mindaddig, amíg újat nem hozol létre a fenti linkre kattintva.
+        explanation: Új jelszót kértél a fiókodhoz.
+        extra: Ha nem te kérted, tekintsd ezt az e-mailt tárgytalannak. A jelszavad változatlan marad mindaddig, amíg újat nem hozol létre a fenti hivatkozásra kattintva.
         subject: 'Mastodon: Jelszóvisszaállítási utasítások'
         title: Jelszó visszaállítása
       two_factor_disabled:
         explanation: A bejelentkezés most már csupán email címmel és jelszóval lehetséges.
-        subject: Kétlépcsős azonosítás kikapcsolva
+        subject: 'Mastodon: kétlépcsős hitelesítés letiltva'
         subtitle: A kétlépcsős hitelesítés a fiókodhoz ki lett kapcsolva.
         title: Kétlépcsős hitelesítés kikapcsolva
       two_factor_enabled:
diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml
index f03f6b58b..3822e9c20 100644
--- a/config/locales/doorkeeper.hu.yml
+++ b/config/locales/doorkeeper.hu.yml
@@ -43,7 +43,7 @@ hu:
         new: Új alkalmazás
         scopes: Hatókörök
         show: Megjelenítés
-        title: Alkalmazásaid
+        title: Saját alkalmazások
       new:
         title: Új alkalmazás
       show:
@@ -77,7 +77,7 @@ hu:
         never_used: Soha sem volt használva
         scopes: Jogosultságok
         superapp: Belső
-        title: Hitelesített alkalmazásaid
+        title: Hitelesített saját alkalmazások
     errors:
       messages:
         access_denied: Az erőforrás tulajdonosa vagy az engedélyező kiszolgáló elutasította a kérést.
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index e29ce3752..8f8070d71 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -25,27 +25,27 @@ hu:
   admin:
     account_actions:
       action: Művelet végrehajtása
-      title: "%{acct} moderálása"
+      title: 'Moderálási művelet végrehajtása ezen: %{acct}'
     account_moderation_notes:
-      create: Új moderációs bejegyzés
-      created_msg: Moderációs bejegyzés létrehozva!
-      destroyed_msg: Moderációs bejegyzés törölve!
+      create: Megjegyzés hagyása
+      created_msg: A moderációs megjegyzés sikeresen létrehozva!
+      destroyed_msg: A moderációs megjegyzés sikeresen törölve!
     accounts:
-      add_email_domain_block: Email domain tiltólistára vétele
+      add_email_domain_block: E-mail-domain tiltólistára vétele
       approve: Jóváhagyás
-      approved_msg: A %{username} fiók regisztrációs kérelmét sikeresen elfogadtuk
+      approved_msg: "%{username} regisztrációja sikeresen elfogadva"
       are_you_sure: Biztos vagy benne?
       avatar: Profilkép
       by_domain: Domain
       change_email:
-        changed_msg: Az emailt sikeresen megváltoztattuk!
-        current_email: Jelenlegi e-mail
-        label: E-mail megváltoztatása
-        new_email: Új e-mail
-        submit: E-mail megváltoztatása
-        title: "%{username} felhasználó e-mail változás"
+        changed_msg: Az e-mail-cím sikeresen megváltozott!
+        current_email: Jelenlegi e-mail-cím
+        label: E-mail-cím megváltoztatása
+        new_email: Új e-mail-cím
+        submit: E-mail-cím megváltoztatása
+        title: "%{username} e-mail-címének megváltoztatása"
       change_role:
-        changed_msg: A szerepet sikeresen megváltoztattuk!
+        changed_msg: A szerep sikeresen megváltoztatva!
         label: Szerep megváltoztatása
         no_role: Nincs szerep
         title: "%{username} szerepének megváltoztatása"
@@ -1224,7 +1224,7 @@ hu:
     archive_takeout:
       date: Dátum
       download: Archívum letöltése
-      hint_html: Itt kérhető egy archív az összes <strong>feltöltött bejegyzésedről és médiádról</strong>. Az exportált adatok ActivityPub formátumban lesznek, melyet bármilyen szabványos program tud olvasni. 7 naponként kérhetsz ilyen archívot.
+      hint_html: Itt kérhetsz egy archívumot az összes <strong>bejegyzésedről és médiáfájlodról</strong>. Az exportált adatok ActivityPub formátumban lesznek, mely bármilyen szabványos programmal olvasható. 7 naponta kérhetsz ilyen archívumot.
       in_progress: Archívum összeállítása…
       request: Archívum kérése
       size: Méret
diff --git a/config/locales/is.yml b/config/locales/is.yml
index fdf54030a..6f9d0e7c7 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -1659,15 +1659,25 @@ is:
     import: Flytja inn
     import_and_export: Inn- og útflutningur
     migrate: Yfirfærsla notandaaðgangs
+    notifications: Tilkynningar í tölvupósti
     preferences: Kjörstillingar
     profile: Notandasnið
     relationships: Fylgist með og fylgjendur
+    severed_relationships: Rofin tengsl
     statuses_cleanup: Sjálfvirk eyðing færslna
     strikes: Umsýsla refsinga
     two_factor_authentication: Tveggja-þátta auðkenning
     webauthn_authentication: Öryggislyklar
   severed_relationships:
     download: Sækja (%{count})
+    event_type:
+      account_suspension: Frysting notandaaðgangsins (%{target_name})
+      domain_block: Frysting netþjónsins (%{target_name})
+      user_domain_block: Þú útilokaðir %{target_name}
+    lost_followers: Tapaðir fylgjendur
+    lost_follows: Tapað sem þú fylgist með
+    preamble: Þú gætir misst einhverja sem þú fylgist með og eins fylgjendur þegar þú útilokar lén eða þegar umsjónarmenn netþjónsins þíns ákveða að frysta fjartengdan netþjón. Þegar slíkt gerist, geturðu sótt lista yfir slík skemmd tengsl, til að yfirfara og mögulega flytja inn á öðrum netþjóni.
+    purged: Upplýsingum um þennan netþjón hefur verið eytt af stjórnendum netþjónsins þíns.
     type: Atburður
   statuses:
     attached:
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index adb3a041c..b42856730 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -1944,6 +1944,11 @@ sl:
       follows_subtitle: Sledite dobro znanim računom
       follows_title: Komu slediti
       follows_view_more: Pokaži več oseb za sledenje
+      hashtags_recent_count:
+        few: "%{people} osebe v zadnjih dveh dneh"
+        one: "%{people} oseba v zadnjih dveh dneh"
+        other: "%{people} oseb v zadnjih dveh dneh"
+        two: "%{people} osebi v zadnjih dveh dneh"
       hashtags_subtitle: Raziščite, kaj je v trendu zadnja dva dni
       hashtags_title: Ključniki v trendu
       hashtags_view_more: Pokaži več ključnikov v trendu

From b34c08959126676a9acd87aa57ee4e982d0af1ab Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 26 Mar 2024 14:09:35 +0100
Subject: [PATCH 019/173] Update dependency csv to v3.3.0 (#29715)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 133dae5b3..ad70d8274 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -188,7 +188,7 @@ GEM
     crass (1.0.6)
     css_parser (1.16.0)
       addressable
-    csv (3.2.8)
+    csv (3.3.0)
     database_cleaner-active_record (2.1.0)
       activerecord (>= 5.a)
       database_cleaner-core (~> 2.0.0)

From cf76380c9158a7ab2793a66eb3e74d6a3687cac0 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 26 Mar 2024 09:12:09 -0400
Subject: [PATCH 020/173] Add `AccountStat.by_recent_status`, use in `Account`
 (#29704)

---
 app/models/account.rb             | 3 ++-
 app/models/account_stat.rb        | 3 +++
 app/models/relationship_filter.rb | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/app/models/account.rb b/app/models/account.rb
index 322a29248..3739709a1 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -132,12 +132,13 @@ class Account < ApplicationRecord
   scope :auditable, -> { where(id: Admin::ActionLog.select(:account_id).distinct) }
   scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
   scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
-  scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
+  scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.by_recent_status).references(:account_stat) }
   scope :by_recent_activity, -> { left_joins(:user, :account_stat).order(coalesced_activity_timestamps.desc).order(id: :desc) }
   scope :popular, -> { order('account_stats.followers_count desc') }
   scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) }
   scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
   scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) }
+  scope :dormant, -> { joins(:account_stat).merge(AccountStat.without_recent_activity) }
 
   after_update_commit :trigger_update_webhooks
 
diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb
index 0fea7732e..14aa7ef80 100644
--- a/app/models/account_stat.rb
+++ b/app/models/account_stat.rb
@@ -20,6 +20,9 @@ class AccountStat < ApplicationRecord
 
   belongs_to :account, inverse_of: :account_stat
 
+  scope :by_recent_status, -> { order(arel_table[:last_status_at].desc.nulls_last) }
+  scope :without_recent_activity, -> { where(last_status_at: [nil, ...1.month.ago]) }
+
   update_index('accounts', :account)
 
   def following_count
diff --git a/app/models/relationship_filter.rb b/app/models/relationship_filter.rb
index d686f9ed8..828610e46 100644
--- a/app/models/relationship_filter.rb
+++ b/app/models/relationship_filter.rb
@@ -114,7 +114,7 @@ class RelationshipFilter
   def activity_scope(value)
     case value
     when 'dormant'
-      Account.joins(:account_stat).where(account_stat: { last_status_at: [nil, ...1.month.ago] })
+      Account.dormant
     else
       raise Mastodon::InvalidParameterError, "Unknown activity: #{value}"
     end

From 32938dadd71b57cb60a70039e1fb018f97571ca9 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 26 Mar 2024 09:21:20 -0400
Subject: [PATCH 021/173] Add `not_allowed` scope for `PreviewCardTrend`
 (#29599)

---
 app/models/preview_card_trend.rb | 2 ++
 app/models/trends/links.rb       | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/models/preview_card_trend.rb b/app/models/preview_card_trend.rb
index da2ea2f8c..58155971a 100644
--- a/app/models/preview_card_trend.rb
+++ b/app/models/preview_card_trend.rb
@@ -15,5 +15,7 @@ class PreviewCardTrend < ApplicationRecord
   include RankedTrend
 
   belongs_to :preview_card
+
   scope :allowed, -> { where(allowed: true) }
+  scope :not_allowed, -> { where(allowed: false) }
 end
diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb
index 76e50aa7a..0650c4109 100644
--- a/app/models/trends/links.rb
+++ b/app/models/trends/links.rb
@@ -86,8 +86,8 @@ class Trends::Links < Trends::Base
 
   def request_review
     PreviewCardTrend.pluck('distinct language').flat_map do |language|
-      score_at_threshold  = PreviewCardTrend.where(language: language, allowed: true).by_rank.ranked_below(options[:review_threshold]).first&.score || 0
-      preview_card_trends = PreviewCardTrend.where(language: language, allowed: false).joins(:preview_card)
+      score_at_threshold  = PreviewCardTrend.where(language: language).allowed.by_rank.ranked_below(options[:review_threshold]).first&.score || 0
+      preview_card_trends = PreviewCardTrend.where(language: language).not_allowed.joins(:preview_card)
 
       preview_card_trends.filter_map do |trend|
         preview_card = trend.preview_card

From cfea9cc172fcce5deeafeb4f6f5eba85f7827e96 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 26 Mar 2024 15:45:19 +0100
Subject: [PATCH 022/173] Add list of pending releases directly in mail
 notifications for version updates (#29436)

---
 app/mailers/admin_mailer.rb                                   | 4 ++++
 app/views/admin_mailer/new_critical_software_updates.text.erb | 4 ++++
 app/views/admin_mailer/new_software_updates.text.erb          | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb
index 8990b2a84..8dd7b6e59 100644
--- a/app/mailers/admin_mailer.rb
+++ b/app/mailers/admin_mailer.rb
@@ -46,12 +46,16 @@ class AdminMailer < ApplicationMailer
   end
 
   def new_software_updates
+    @software_updates = SoftwareUpdate.all.to_a.sort_by(&:gem_version)
+
     locale_for_account(@me) do
       mail subject: default_i18n_subject(instance: @instance)
     end
   end
 
   def new_critical_software_updates
+    @software_updates = SoftwareUpdate.where(urgent: true).to_a.sort_by(&:gem_version)
+
     headers['Priority'] = 'urgent'
     headers['X-Priority'] = '1'
     headers['Importance'] = 'high'
diff --git a/app/views/admin_mailer/new_critical_software_updates.text.erb b/app/views/admin_mailer/new_critical_software_updates.text.erb
index 63c170dc0..e4886c262 100644
--- a/app/views/admin_mailer/new_critical_software_updates.text.erb
+++ b/app/views/admin_mailer/new_critical_software_updates.text.erb
@@ -1,3 +1,7 @@
 <%= raw t('admin_mailer.new_critical_software_updates.body') %>
 
+<% @software_updates.each do |update| %>
+- Mastodon #{update.version}: #{update.release_notes}
+<% end %>
+
 <%= raw t('application_mailer.view')%> <%= admin_software_updates_url %>
diff --git a/app/views/admin_mailer/new_software_updates.text.erb b/app/views/admin_mailer/new_software_updates.text.erb
index 96808f3cb..7612b7c59 100644
--- a/app/views/admin_mailer/new_software_updates.text.erb
+++ b/app/views/admin_mailer/new_software_updates.text.erb
@@ -1,3 +1,7 @@
 <%= raw t('admin_mailer.new_software_updates.body') %>
 
+<% @software_updates.each do |update| %>
+- Mastodon #{update.version}: #{update.release_notes}
+<% end %>
+
 <%= raw t('application_mailer.view')%> <%= admin_software_updates_url %>

From 7508472d843e2adab436024daa6898996c9030c6 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 26 Mar 2024 15:46:05 +0100
Subject: [PATCH 023/173] Fix admin interface repeating rule title instead of
 showing hint text (#29758)

---
 app/views/admin/rules/_rule.html.haml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/admin/rules/_rule.html.haml b/app/views/admin/rules/_rule.html.haml
index a0896fe80..5f37f6935 100644
--- a/app/views/admin/rules/_rule.html.haml
+++ b/app/views/admin/rules/_rule.html.haml
@@ -5,7 +5,7 @@
 
   .announcements-list__item__action-bar
     .announcements-list__item__meta
-      = rule.text
+      = rule.hint
 
     %div
       = table_link_to 'trash', t('admin.rules.delete'), admin_rule_path(rule), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, rule)

From 9c24f2d6b17104cac229a126e35fdfda7a557d79 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 26 Mar 2024 15:46:38 +0100
Subject: [PATCH 024/173] Undo notification permissions on individual and
 domain blocks (#29570)

---
 .../after_block_domain_from_account_service.rb    |  5 +++++
 app/services/block_service.rb                     |  2 ++
 ...fter_block_domain_from_account_service_spec.rb | 15 ++++++---------
 spec/services/block_service_spec.rb               |  8 +++++---
 4 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/app/services/after_block_domain_from_account_service.rb b/app/services/after_block_domain_from_account_service.rb
index adb17845c..fc5dc6568 100644
--- a/app/services/after_block_domain_from_account_service.rb
+++ b/app/services/after_block_domain_from_account_service.rb
@@ -12,6 +12,7 @@ class AfterBlockDomainFromAccountService < BaseService
     @domain_block_event = nil
 
     clear_notifications!
+    clear_notification_permissions!
     remove_follows!
     reject_existing_followers!
     reject_pending_follow_requests!
@@ -31,6 +32,10 @@ class AfterBlockDomainFromAccountService < BaseService
     Notification.where(account: @account).where(from_account: Account.where(domain: @domain)).in_batches.delete_all
   end
 
+  def clear_notification_permissions!
+    NotificationPermission.where(account: @account, from_account: Account.where(domain: @domain)).in_batches.delete_all
+  end
+
   def reject_existing_followers!
     @account.passive_relationships.where(account: Account.where(domain: @domain)).includes(:account).reorder(nil).in_batches do |follows|
       domain_block_event.import_from_passive_follows!(follows)
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index 266a0f4b9..98229d98c 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -10,6 +10,8 @@ class BlockService < BaseService
     UnfollowService.new.call(target_account, account) if target_account.following?(account)
     RejectFollowService.new.call(target_account, account) if target_account.requested?(account)
 
+    NotificationPermission.where(account: account, from_account: target_account).destroy_all
+
     block = account.block!(target_account)
 
     BlockWorker.perform_async(account.id, target_account.id)
diff --git a/spec/services/after_block_domain_from_account_service_spec.rb b/spec/services/after_block_domain_from_account_service_spec.rb
index 12e780357..248648a80 100644
--- a/spec/services/after_block_domain_from_account_service_spec.rb
+++ b/spec/services/after_block_domain_from_account_service_spec.rb
@@ -10,20 +10,17 @@ RSpec.describe AfterBlockDomainFromAccountService do
   let(:alice) { Fabricate(:account, username: 'alice') }
 
   before do
+    NotificationPermission.create!(account: alice, from_account: wolf)
+
     wolf.follow!(alice)
     alice.follow!(dog)
   end
 
-  around do |example|
-    Sidekiq::Testing.fake! do
-      example.run
-    end
-  end
+  it 'purge followers from blocked domain, remove notification permissions, sends `Reject->Follow`, and records severed relationships', :aggregate_failures do
+    expect { subject.call(alice, 'evil.org') }
+      .to change { wolf.following?(alice) }.from(true).to(false)
+      .and change { NotificationPermission.exists?(account: alice, from_account: wolf) }.from(true).to(false)
 
-  it 'purges followers from blocked domain, sends them Reject->Follow, and records severed relationships', :aggregate_failures do
-    subject.call(alice, 'evil.org')
-
-    expect(wolf.following?(alice)).to be false
     expect(ActivityPub::DeliveryWorker.jobs.pluck('args')).to contain_exactly(
       [a_string_including('"type":"Reject"'), alice.id, wolf.inbox_url],
       [a_string_including('"type":"Undo"'), alice.id, dog.inbox_url]
diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb
index e72e52825..d096aa1ea 100644
--- a/spec/services/block_service_spec.rb
+++ b/spec/services/block_service_spec.rb
@@ -11,11 +11,13 @@ RSpec.describe BlockService do
     let(:bob) { Fabricate(:account, username: 'bob') }
 
     before do
-      subject.call(sender, bob)
+      NotificationPermission.create!(account: sender, from_account: bob)
     end
 
-    it 'creates a blocking relation' do
-      expect(sender.blocking?(bob)).to be true
+    it 'creates a blocking relation and removes notification permissions' do
+      expect { subject.call(sender, bob) }
+        .to change { sender.blocking?(bob) }.from(false).to(true)
+        .and change { NotificationPermission.exists?(account: sender, from_account: bob) }.from(true).to(false)
     end
   end
 

From de740dfb9cb55af5d77ebdcea84133521200de73 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 26 Mar 2024 16:57:08 +0100
Subject: [PATCH 025/173] Use `upsert_all` and `insert_all` to reduce
 back-and-forth in costly migrations (#29752)

---
 ..._migrate_interaction_settings_to_policy.rb | 70 +++++++++--------
 ...te_interaction_settings_to_policy_again.rb | 76 +++++++++----------
 2 files changed, 75 insertions(+), 71 deletions(-)

diff --git a/db/migrate/20240304090449_migrate_interaction_settings_to_policy.rb b/db/migrate/20240304090449_migrate_interaction_settings_to_policy.rb
index a0ce0a663..ea4cfccdf 100644
--- a/db/migrate/20240304090449_migrate_interaction_settings_to_policy.rb
+++ b/db/migrate/20240304090449_migrate_interaction_settings_to_policy.rb
@@ -4,46 +4,50 @@ class MigrateInteractionSettingsToPolicy < ActiveRecord::Migration[7.1]
   disable_ddl_transaction!
 
   # Dummy classes, to make migration possible across version changes
-  class Account < ApplicationRecord
-    has_one :user, inverse_of: :account
-    has_one :notification_policy, inverse_of: :account
-  end
-
   class User < ApplicationRecord
-    belongs_to :account
+    belongs_to :notification_policy, foreign_key: 'account_id', primary_key: 'account_id', optional: true, inverse_of: false
   end
 
-  class NotificationPolicy < ApplicationRecord
-    belongs_to :account
-  end
+  class NotificationPolicy < ApplicationRecord; end
 
   def up
-    User.includes(account: :notification_policy).find_each do |user|
-      deserialized_settings = Oj.load(user.attributes_before_type_cast['settings'])
-
-      next if deserialized_settings.nil?
-
-      policy = user.account.notification_policy || user.account.build_notification_policy
-      requires_new_policy = false
-
-      if deserialized_settings['interactions.must_be_follower']
-        policy.filter_not_followers = true
-        requires_new_policy = true
-      end
-
-      if deserialized_settings['interactions.must_be_following']
-        policy.filter_not_following = true
-        requires_new_policy = true
-      end
-
-      unless deserialized_settings['interactions.must_be_following_dm']
-        policy.filter_private_mentions = false
-        requires_new_policy = true
-      end
-
-      policy.save if requires_new_policy && policy.changed?
+    User.includes(:notification_policy).in_batches do |users|
+      NotificationPolicy.upsert_all(users.filter_map { |user| policy_for_user(user) })
     end
   end
 
   def down; end
+
+  private
+
+  def policy_for_user(user)
+    deserialized_settings = Oj.load(user.attributes_before_type_cast['settings'])
+    return if deserialized_settings.nil?
+
+    requires_new_policy = false
+
+    policy = {
+      account_id: user.account_id,
+      filter_not_followers: false,
+      filter_not_following: false,
+      filter_private_mentions: true,
+    }
+
+    if deserialized_settings['interactions.must_be_follower']
+      policy[:filter_not_followers] = true
+      requires_new_policy = true
+    end
+
+    if deserialized_settings['interactions.must_be_following']
+      policy[:filter_not_following] = true
+      requires_new_policy = true
+    end
+
+    unless deserialized_settings['interactions.must_be_following_dm']
+      policy[:filter_private_mentions] = false
+      requires_new_policy = true
+    end
+
+    policy if requires_new_policy
+  end
 end
diff --git a/db/post_migrate/20240321160706_migrate_interaction_settings_to_policy_again.rb b/db/post_migrate/20240321160706_migrate_interaction_settings_to_policy_again.rb
index 9baefa677..c789b6395 100644
--- a/db/post_migrate/20240321160706_migrate_interaction_settings_to_policy_again.rb
+++ b/db/post_migrate/20240321160706_migrate_interaction_settings_to_policy_again.rb
@@ -4,51 +4,51 @@ class MigrateInteractionSettingsToPolicyAgain < ActiveRecord::Migration[7.1]
   disable_ddl_transaction!
 
   # Dummy classes, to make migration possible across version changes
-  class Account < ApplicationRecord
-    has_one :user, inverse_of: :account
-    has_one :notification_policy, inverse_of: :account
-  end
-
   class User < ApplicationRecord
-    belongs_to :account
+    belongs_to :notification_policy, foreign_key: 'account_id', primary_key: 'account_id', optional: true, inverse_of: false
   end
 
-  class NotificationPolicy < ApplicationRecord
-    belongs_to :account
-  end
+  class NotificationPolicy < ApplicationRecord; end
 
   def up
-    User.includes(account: :notification_policy).find_each do |user|
-      deserialized_settings = Oj.load(user.attributes_before_type_cast['settings'])
-
-      next if deserialized_settings.nil?
-
-      # If the user has configured a notification policy, don't override it
-      next if user.account.notification_policy.present?
-
-      policy = user.account.build_notification_policy
-      requires_new_policy = false
-
-      if deserialized_settings['interactions.must_be_follower']
-        policy.filter_not_followers = true
-        requires_new_policy = true
-      end
-
-      if deserialized_settings['interactions.must_be_following']
-        policy.filter_not_following = true
-        requires_new_policy = true
-      end
-
-      unless deserialized_settings['interactions.must_be_following_dm']
-        policy.filter_private_mentions = false
-        requires_new_policy = true
-      end
-
-      policy.save if requires_new_policy && policy.changed?
-    rescue ActiveRecord::RecordNotUnique
-      next
+    User.includes(:notification_policy).in_batches do |users|
+      NotificationPolicy.insert_all(users.filter_map { |user| policy_for_user(user) })
     end
   end
 
   def down; end
+
+  private
+
+  def policy_for_user(user)
+    deserialized_settings = Oj.load(user.attributes_before_type_cast['settings'])
+    return if deserialized_settings.nil?
+    return if user.notification_policy.present?
+
+    requires_new_policy = false
+
+    policy = {
+      account_id: user.account_id,
+      filter_not_followers: false,
+      filter_not_following: false,
+      filter_private_mentions: true,
+    }
+
+    if deserialized_settings['interactions.must_be_follower']
+      policy[:filter_not_followers] = true
+      requires_new_policy = true
+    end
+
+    if deserialized_settings['interactions.must_be_following']
+      policy[:filter_not_following] = true
+      requires_new_policy = true
+    end
+
+    unless deserialized_settings['interactions.must_be_following_dm']
+      policy[:filter_private_mentions] = false
+      requires_new_policy = true
+    end
+
+    policy if requires_new_policy
+  end
 end

From c4feba43476635904a4a0f0dbd9c7b48d4c2985a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 26 Mar 2024 11:58:48 -0400
Subject: [PATCH 026/173] Use existing `MascotHelper#instance_presenter`
 instead of local var in `welcome` email template (#29759)

---
 app/mailers/user_mailer.rb              | 5 +++--
 app/views/user_mailer/welcome.html.haml | 2 --
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index 96fcd51ef..f8c1c9a8d 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -5,10 +5,11 @@ class UserMailer < Devise::Mailer
 
   helper :accounts
   helper :application
-  helper :instance
-  helper :statuses
+  helper :mascot
   helper :formatting
+  helper :instance
   helper :routing
+  helper :statuses
 
   before_action :set_instance
 
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index e7f9c47e3..fd8980c23 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -1,5 +1,3 @@
-- instance_presenter = InstancePresenter.new
-
 = content_for :heading do
   .email-desktop-flex
     .email-header-left

From b2d841ce9ae415550d44abecb182ac068ee121e3 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 27 Mar 2024 00:14:11 +0100
Subject: [PATCH 027/173] Fix column borders disappearing in advanced interface
 on low width viewports (#29763)

---
 .../styles/mastodon/components.scss           | 47 +++++++++----------
 1 file changed, 23 insertions(+), 24 deletions(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 3704751ef..2d7aa32d8 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2890,24 +2890,31 @@ $ui-header-height: 55px;
     }
   }
 
-  .layout-single-column .ui__header {
-    display: flex;
-    background: var(--background-color-tint);
-    border-bottom: 1px solid var(--background-border-color);
-  }
+  .layout-single-column {
+    .ui__header {
+      display: flex;
+      background: var(--background-color-tint);
+      border-bottom: 1px solid var(--background-border-color);
+    }
 
-  .column > .scrollable,
-  .tabs-bar__wrapper .column-header,
-  .tabs-bar__wrapper .column-back-button {
-    border-left: 0;
-    border-right: 0;
-  }
+    .column > .scrollable,
+    .tabs-bar__wrapper .column-header,
+    .tabs-bar__wrapper .column-back-button {
+      border-left: 0;
+      border-right: 0;
+    }
 
-  .column-header,
-  .column-back-button,
-  .scrollable,
-  .error-column {
-    border-radius: 0 !important;
+    .column-header,
+    .column-back-button,
+    .scrollable,
+    .error-column {
+      border-radius: 0 !important;
+    }
+
+    .column-header,
+    .column-back-button {
+      border-top: 0;
+    }
   }
 }
 
@@ -3466,10 +3473,6 @@ $ui-header-height: 55px;
   &:hover {
     text-decoration: underline;
   }
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    border-top: 0;
-  }
 }
 
 .column-header__back-button {
@@ -4233,10 +4236,6 @@ a.status-card {
       padding-top: 16px;
     }
   }
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    border-top: 0;
-  }
 }
 
 .column-header__buttons {

From c5692d2f2f4beede8b8c158954d3ab86df3f3e98 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 27 Mar 2024 10:59:42 +0100
Subject: [PATCH 028/173] Update dependency prom-client to v15.1.1 (#29764)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index a2258375b..268aa2448 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14023,12 +14023,12 @@ __metadata:
   linkType: hard
 
 "prom-client@npm:^15.0.0":
-  version: 15.1.0
-  resolution: "prom-client@npm:15.1.0"
+  version: 15.1.1
+  resolution: "prom-client@npm:15.1.1"
   dependencies:
     "@opentelemetry/api": "npm:^1.4.0"
     tdigest: "npm:^0.1.1"
-  checksum: 10c0/c10781adbf49225298e44da5396a51a0bd4d0cddc3c7e237ba50e888e12ead26a8f98261f362a442f1bbcdaddd6e7302d5675b37beac67ea9b6f82e4d39fb3cc
+  checksum: 10c0/b3e6a58fc0ef87cf5b0badf06d7d79c24ac93ba47cccfaad95faeba79824c6a7724d74a257e7268d691245c847173818c16c8153054cccf16b8f033c37c74129
   languageName: node
   linkType: hard
 

From 1d0a43f6a353717ff6e02ab17276228c9cf452a4 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 27 Mar 2024 05:59:45 -0400
Subject: [PATCH 029/173] Use composable query in
 `Status.not_domain_blocked_by_account` scope (#29766)

---
 app/models/status.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/models/status.rb b/app/models/status.rb
index c8effd3da..ae53513ee 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -110,7 +110,7 @@ class Status < ApplicationRecord
   scope :without_reblogs, -> { where(statuses: { reblog_of_id: nil }) }
   scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) }
   scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
-  scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
+  scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).merge(Account.not_domain_blocked_by_account(account)) }
   scope :tagged_with_all, lambda { |tag_ids|
     Array(tag_ids).map(&:to_i).reduce(self) do |result, id|
       result.where(<<~SQL.squish, tag_id: id)

From 86f999c1f2db7186c6d43670f78d05ebd9ccc042 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 27 Mar 2024 10:59:50 +0100
Subject: [PATCH 030/173] Update dependency json-schema to v4.3.0 (#29769)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index ad70d8274..4d36cf4e9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -373,7 +373,7 @@ GEM
     json-ld-preloaded (3.3.0)
       json-ld (~> 3.3)
       rdf (~> 3.3)
-    json-schema (4.2.0)
+    json-schema (4.3.0)
       addressable (>= 2.8)
     jsonapi-renderer (0.2.2)
     jwt (2.7.1)

From d49343ed11b3c08c4e81ecd70e17e01bd30154a6 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 27 Mar 2024 10:59:54 +0100
Subject: [PATCH 031/173] Update dependency react-intl to v6.6.4 (#29771)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 268aa2448..bcdd1bd6f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14331,8 +14331,8 @@ __metadata:
   linkType: hard
 
 "react-intl@npm:^6.4.2":
-  version: 6.6.3
-  resolution: "react-intl@npm:6.6.3"
+  version: 6.6.4
+  resolution: "react-intl@npm:6.6.4"
   dependencies:
     "@formatjs/ecma402-abstract": "npm:1.18.2"
     "@formatjs/icu-messageformat-parser": "npm:2.7.6"
@@ -14350,7 +14350,7 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/8a924931668f1bf6364bb41c09fdb54972b8e3372f0768a31478dc3f8a846920caa4dc04ab3950195baa6dbf58a148f43a6a221d5795be2cbb6f4f374a5921d6
+  checksum: 10c0/bd874ad3a56b0198903c02c878cfa23b5ae9a44d2c74fd4f01ddb602c97a8115de8cebed00b44f7dc5fb3031e5ef0f9cfb4bdabd105b99a785352462deb106d3
   languageName: node
   linkType: hard
 

From 27d014a7fa4a92117e133adfd1c3e4e1c34ddc9c Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Wed, 27 Mar 2024 13:47:09 +0100
Subject: [PATCH 032/173] Rewrite markers reducer in Typescript (#27644)

---
 app/javascript/mastodon/actions/markers.js    | 152 ----------------
 app/javascript/mastodon/actions/markers.ts    | 163 ++++++++++++++++++
 app/javascript/mastodon/api.ts                |   9 +-
 app/javascript/mastodon/api_types/markers.ts  |   7 +
 app/javascript/mastodon/reducers/index.ts     |   4 +-
 app/javascript/mastodon/reducers/markers.js   |  26 ---
 app/javascript/mastodon/reducers/markers.ts   |  18 ++
 .../mastodon/reducers/notifications.js        |   6 +-
 app/serializers/rest/marker_serializer.rb     |   2 +
 9 files changed, 202 insertions(+), 185 deletions(-)
 delete mode 100644 app/javascript/mastodon/actions/markers.js
 create mode 100644 app/javascript/mastodon/actions/markers.ts
 create mode 100644 app/javascript/mastodon/api_types/markers.ts
 delete mode 100644 app/javascript/mastodon/reducers/markers.js
 create mode 100644 app/javascript/mastodon/reducers/markers.ts

diff --git a/app/javascript/mastodon/actions/markers.js b/app/javascript/mastodon/actions/markers.js
deleted file mode 100644
index cfc329a8b..000000000
--- a/app/javascript/mastodon/actions/markers.js
+++ /dev/null
@@ -1,152 +0,0 @@
-import { List as ImmutableList } from 'immutable';
-
-import { debounce } from 'lodash';
-
-import api from '../api';
-import { compareId } from '../compare_id';
-
-export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';
-export const MARKERS_FETCH_SUCCESS = 'MARKERS_FETCH_SUCCESS';
-export const MARKERS_FETCH_FAIL    = 'MARKERS_FETCH_FAIL';
-export const MARKERS_SUBMIT_SUCCESS = 'MARKERS_SUBMIT_SUCCESS';
-
-export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
-  const accessToken = getState().getIn(['meta', 'access_token'], '');
-  const params      = _buildParams(getState());
-
-  if (Object.keys(params).length === 0 || accessToken === '') {
-    return;
-  }
-
-  // The Fetch API allows us to perform requests that will be carried out
-  // after the page closes. But that only works if the `keepalive` attribute
-  // is supported.
-  if (window.fetch && 'keepalive' in new Request('')) {
-    fetch('/api/v1/markers', {
-      keepalive: true,
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-        'Authorization': `Bearer ${accessToken}`,
-      },
-      body: JSON.stringify(params),
-    });
-
-    return;
-  } else if (navigator && navigator.sendBeacon) {
-    // Failing that, we can use sendBeacon, but we have to encode the data as
-    // FormData for DoorKeeper to recognize the token.
-    const formData = new FormData();
-
-    formData.append('bearer_token', accessToken);
-
-    for (const [id, value] of Object.entries(params)) {
-      formData.append(`${id}[last_read_id]`, value.last_read_id);
-    }
-
-    if (navigator.sendBeacon('/api/v1/markers', formData)) {
-      return;
-    }
-  }
-
-  // If neither Fetch nor sendBeacon worked, try to perform a synchronous
-  // request.
-  try {
-    const client = new XMLHttpRequest();
-
-    client.open('POST', '/api/v1/markers', false);
-    client.setRequestHeader('Content-Type', 'application/json');
-    client.setRequestHeader('Authorization', `Bearer ${accessToken}`);
-    client.send(JSON.stringify(params));
-  } catch (e) {
-    // Do not make the BeforeUnload handler error out
-  }
-};
-
-const _buildParams = (state) => {
-  const params = {};
-
-  const lastHomeId         = state.getIn(['timelines', 'home', 'items'], ImmutableList()).find(item => item !== null);
-  const lastNotificationId = state.getIn(['notifications', 'lastReadId']);
-
-  if (lastHomeId && compareId(lastHomeId, state.getIn(['markers', 'home'])) > 0) {
-    params.home = {
-      last_read_id: lastHomeId,
-    };
-  }
-
-  if (lastNotificationId && compareId(lastNotificationId, state.getIn(['markers', 'notifications'])) > 0) {
-    params.notifications = {
-      last_read_id: lastNotificationId,
-    };
-  }
-
-  return params;
-};
-
-const debouncedSubmitMarkers = debounce((dispatch, getState) => {
-  const accessToken = getState().getIn(['meta', 'access_token'], '');
-  const params      = _buildParams(getState());
-
-  if (Object.keys(params).length === 0 || accessToken === '') {
-    return;
-  }
-
-  api(getState).post('/api/v1/markers', params).then(() => {
-    dispatch(submitMarkersSuccess(params));
-  }).catch(() => {});
-}, 300000, { leading: true, trailing: true });
-
-export function submitMarkersSuccess({ home, notifications }) {
-  return {
-    type: MARKERS_SUBMIT_SUCCESS,
-    home: (home || {}).last_read_id,
-    notifications: (notifications || {}).last_read_id,
-  };
-}
-
-export function submitMarkers(params = {}) {
-  const result = (dispatch, getState) => debouncedSubmitMarkers(dispatch, getState);
-
-  if (params.immediate === true) {
-    debouncedSubmitMarkers.flush();
-  }
-
-  return result;
-}
-
-export const fetchMarkers = () => (dispatch, getState) => {
-  const params = { timeline: ['notifications'] };
-
-  dispatch(fetchMarkersRequest());
-
-  api(getState).get('/api/v1/markers', { params }).then(response => {
-    dispatch(fetchMarkersSuccess(response.data));
-  }).catch(error => {
-    dispatch(fetchMarkersFail(error));
-  });
-};
-
-export function fetchMarkersRequest() {
-  return {
-    type: MARKERS_FETCH_REQUEST,
-    skipLoading: true,
-  };
-}
-
-export function fetchMarkersSuccess(markers) {
-  return {
-    type: MARKERS_FETCH_SUCCESS,
-    markers,
-    skipLoading: true,
-  };
-}
-
-export function fetchMarkersFail(error) {
-  return {
-    type: MARKERS_FETCH_FAIL,
-    error,
-    skipLoading: true,
-    skipAlert: true,
-  };
-}
diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts
new file mode 100644
index 000000000..4e90a9c6b
--- /dev/null
+++ b/app/javascript/mastodon/actions/markers.ts
@@ -0,0 +1,163 @@
+import { List as ImmutableList } from 'immutable';
+
+import { debounce } from 'lodash';
+
+import type { MarkerJSON } from 'mastodon/api_types/markers';
+import type { RootState } from 'mastodon/store';
+import { createAppAsyncThunk } from 'mastodon/store/typed_functions';
+
+import api, { authorizationTokenFromState } from '../api';
+import { compareId } from '../compare_id';
+
+export const synchronouslySubmitMarkers = createAppAsyncThunk(
+  'markers/submit',
+  async (_args, { getState }) => {
+    const accessToken = authorizationTokenFromState(getState);
+    const params = buildPostMarkersParams(getState());
+
+    if (Object.keys(params).length === 0 || !accessToken) {
+      return;
+    }
+
+    // The Fetch API allows us to perform requests that will be carried out
+    // after the page closes. But that only works if the `keepalive` attribute
+    // is supported.
+    if ('fetch' in window && 'keepalive' in new Request('')) {
+      await fetch('/api/v1/markers', {
+        keepalive: true,
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+          Authorization: `Bearer ${accessToken}`,
+        },
+        body: JSON.stringify(params),
+      });
+
+      return;
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+    } else if ('navigator' && 'sendBeacon' in navigator) {
+      // Failing that, we can use sendBeacon, but we have to encode the data as
+      // FormData for DoorKeeper to recognize the token.
+      const formData = new FormData();
+
+      formData.append('bearer_token', accessToken);
+
+      for (const [id, value] of Object.entries(params)) {
+        if (value.last_read_id)
+          formData.append(`${id}[last_read_id]`, value.last_read_id);
+      }
+
+      if (navigator.sendBeacon('/api/v1/markers', formData)) {
+        return;
+      }
+    }
+
+    // If neither Fetch nor sendBeacon worked, try to perform a synchronous
+    // request.
+    try {
+      const client = new XMLHttpRequest();
+
+      client.open('POST', '/api/v1/markers', false);
+      client.setRequestHeader('Content-Type', 'application/json');
+      client.setRequestHeader('Authorization', `Bearer ${accessToken}`);
+      client.send(JSON.stringify(params));
+    } catch (e) {
+      // Do not make the BeforeUnload handler error out
+    }
+  },
+);
+
+interface MarkerParam {
+  last_read_id?: string;
+}
+
+function getLastHomeId(state: RootState): string | undefined {
+  /* eslint-disable @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
+  return (
+    state
+      // @ts-expect-error state.timelines is not yet typed
+      .getIn(['timelines', 'home', 'items'], ImmutableList())
+      // @ts-expect-error state.timelines is not yet typed
+      .find((item) => item !== null)
+  );
+}
+
+function getLastNotificationId(state: RootState): string | undefined {
+  // @ts-expect-error state.notifications is not yet typed
+  return state.getIn(['notifications', 'lastReadId']);
+}
+
+const buildPostMarkersParams = (state: RootState) => {
+  const params = {} as { home?: MarkerParam; notifications?: MarkerParam };
+
+  const lastHomeId = getLastHomeId(state);
+  const lastNotificationId = getLastNotificationId(state);
+
+  if (lastHomeId && compareId(lastHomeId, state.markers.home) > 0) {
+    params.home = {
+      last_read_id: lastHomeId,
+    };
+  }
+
+  if (
+    lastNotificationId &&
+    compareId(lastNotificationId, state.markers.notifications) > 0
+  ) {
+    params.notifications = {
+      last_read_id: lastNotificationId,
+    };
+  }
+
+  return params;
+};
+
+export const submitMarkersAction = createAppAsyncThunk<{
+  home: string | undefined;
+  notifications: string | undefined;
+}>('markers/submitAction', async (_args, { getState }) => {
+  const accessToken = authorizationTokenFromState(getState);
+  const params = buildPostMarkersParams(getState());
+
+  if (Object.keys(params).length === 0 || accessToken === '') {
+    return { home: undefined, notifications: undefined };
+  }
+
+  await api(getState).post<MarkerJSON>('/api/v1/markers', params);
+
+  return {
+    home: params.home?.last_read_id,
+    notifications: params.notifications?.last_read_id,
+  };
+});
+
+const debouncedSubmitMarkers = debounce(
+  (dispatch) => {
+    dispatch(submitMarkersAction());
+  },
+  300000,
+  {
+    leading: true,
+    trailing: true,
+  },
+);
+
+export const submitMarkers = createAppAsyncThunk(
+  'markers/submit',
+  (params: { immediate?: boolean }, { dispatch }) => {
+    debouncedSubmitMarkers(dispatch);
+
+    if (params.immediate) {
+      debouncedSubmitMarkers.flush();
+    }
+  },
+);
+
+export const fetchMarkers = createAppAsyncThunk(
+  'markers/fetch',
+  async (_args, { getState }) => {
+    const response =
+      await api(getState).get<Record<string, MarkerJSON>>(`/api/v1/markers`);
+
+    return { markers: response.data };
+  },
+);
diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts
index f262fd857..de597a3e3 100644
--- a/app/javascript/mastodon/api.ts
+++ b/app/javascript/mastodon/api.ts
@@ -29,9 +29,14 @@ const setCSRFHeader = () => {
 
 void ready(setCSRFHeader);
 
+export const authorizationTokenFromState = (getState?: GetState) => {
+  return (
+    getState && (getState().meta.get('access_token', '') as string | false)
+  );
+};
+
 const authorizationHeaderFromState = (getState?: GetState) => {
-  const accessToken =
-    getState && (getState().meta.get('access_token', '') as string);
+  const accessToken = authorizationTokenFromState(getState);
 
   if (!accessToken) {
     return {};
diff --git a/app/javascript/mastodon/api_types/markers.ts b/app/javascript/mastodon/api_types/markers.ts
new file mode 100644
index 000000000..f7664fd7c
--- /dev/null
+++ b/app/javascript/mastodon/api_types/markers.ts
@@ -0,0 +1,7 @@
+// See app/serializers/rest/account_serializer.rb
+
+export interface MarkerJSON {
+  last_read_id: string;
+  version: string;
+  updated_at: string;
+}
diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts
index 3d42cc83f..b88175e77 100644
--- a/app/javascript/mastodon/reducers/index.ts
+++ b/app/javascript/mastodon/reducers/index.ts
@@ -21,7 +21,7 @@ import history from './history';
 import listAdder from './list_adder';
 import listEditor from './list_editor';
 import lists from './lists';
-import markers from './markers';
+import { markersReducer } from './markers';
 import media_attachments from './media_attachments';
 import meta from './meta';
 import { modalReducer } from './modal';
@@ -77,7 +77,7 @@ const reducers = {
   suggestions,
   polls,
   trends,
-  markers,
+  markers: markersReducer,
   picture_in_picture,
   history,
   tags,
diff --git a/app/javascript/mastodon/reducers/markers.js b/app/javascript/mastodon/reducers/markers.js
deleted file mode 100644
index c7c5d99f6..000000000
--- a/app/javascript/mastodon/reducers/markers.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Map as ImmutableMap } from 'immutable';
-
-import {
-  MARKERS_SUBMIT_SUCCESS,
-} from '../actions/markers';
-
-
-const initialState = ImmutableMap({
-  home: '0',
-  notifications: '0',
-});
-
-export default function markers(state = initialState, action) {
-  switch(action.type) {
-  case MARKERS_SUBMIT_SUCCESS:
-    if (action.home) {
-      state = state.set('home', action.home);
-    }
-    if (action.notifications) {
-      state = state.set('notifications', action.notifications);
-    }
-    return state;
-  default:
-    return state;
-  }
-}
diff --git a/app/javascript/mastodon/reducers/markers.ts b/app/javascript/mastodon/reducers/markers.ts
new file mode 100644
index 000000000..ec85d0f17
--- /dev/null
+++ b/app/javascript/mastodon/reducers/markers.ts
@@ -0,0 +1,18 @@
+import { createReducer } from '@reduxjs/toolkit';
+
+import { submitMarkersAction } from 'mastodon/actions/markers';
+
+const initialState = {
+  home: '0',
+  notifications: '0',
+};
+
+export const markersReducer = createReducer(initialState, (builder) => {
+  builder.addCase(
+    submitMarkersAction.fulfilled,
+    (state, { payload: { home, notifications } }) => {
+      if (home) state.home = home;
+      if (notifications) state.notifications = notifications;
+    },
+  );
+});
diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js
index bc8593643..7230fabca 100644
--- a/app/javascript/mastodon/reducers/notifications.js
+++ b/app/javascript/mastodon/reducers/notifications.js
@@ -13,7 +13,7 @@ import {
   unfocusApp,
 } from '../actions/app';
 import {
-  MARKERS_FETCH_SUCCESS,
+  fetchMarkers,
 } from '../actions/markers';
 import {
   notificationsUpdate,
@@ -255,8 +255,8 @@ const recountUnread = (state, last_read_id) => {
 
 export default function notifications(state = initialState, action) {
   switch(action.type) {
-  case MARKERS_FETCH_SUCCESS:
-    return action.markers.notifications ? recountUnread(state, action.markers.notifications.last_read_id) : state;
+  case fetchMarkers.fulfilled.type:
+    return action.payload.markers.notifications ? recountUnread(state, action.payload.markers.notifications.last_read_id) : state;
   case NOTIFICATIONS_MOUNT:
     return updateMounted(state);
   case NOTIFICATIONS_UNMOUNT:
diff --git a/app/serializers/rest/marker_serializer.rb b/app/serializers/rest/marker_serializer.rb
index 2eaf3d507..b0c1c553f 100644
--- a/app/serializers/rest/marker_serializer.rb
+++ b/app/serializers/rest/marker_serializer.rb
@@ -1,6 +1,8 @@
 # frozen_string_literal: true
 
 class REST::MarkerSerializer < ActiveModel::Serializer
+  # Please update `app/javascript/mastodon/api_types/markers.ts` when making changes to the attributes
+
   attributes :last_read_id, :version, :updated_at
 
   def last_read_id

From b016f03637eb19ac22f9eb6dfc26ee07965d2456 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 27 Mar 2024 10:08:04 -0400
Subject: [PATCH 033/173] Pull out constant from `AccountWarning.recent` scope
 (#29767)

---
 app/models/account_warning.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb
index a54387a56..7aa474887 100644
--- a/app/models/account_warning.rb
+++ b/app/models/account_warning.rb
@@ -27,6 +27,8 @@ class AccountWarning < ApplicationRecord
     suspend: 4_000,
   }, suffix: :action
 
+  RECENT_PERIOD = 3.months.freeze
+
   normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
 
   belongs_to :account, inverse_of: :account_warnings
@@ -37,7 +39,7 @@ class AccountWarning < ApplicationRecord
 
   scope :latest, -> { order(id: :desc) }
   scope :custom, -> { where.not(text: '') }
-  scope :recent, -> { where('account_warnings.created_at >= ?', 3.months.ago) }
+  scope :recent, -> { where(created_at: RECENT_PERIOD.ago..) }
 
   def statuses
     Status.with_discarded.where(id: status_ids || [])

From 9fbe8d3a0cf33e1ec7f631b7651e9fb2bca8440e Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Wed, 27 Mar 2024 16:19:33 +0100
Subject: [PATCH 034/173] Rewrite PIP state in Typescript (#27645)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 .../mastodon/actions/picture_in_picture.js    | 46 ----------
 .../mastodon/actions/picture_in_picture.ts    | 31 +++++++
 .../mastodon/containers/status_container.jsx  |  2 +-
 .../picture_in_picture/components/footer.jsx  |  2 +-
 .../picture_in_picture/components/header.jsx  | 51 -----------
 .../picture_in_picture/components/header.tsx  | 46 ++++++++++
 .../features/picture_in_picture/index.jsx     | 89 -------------------
 .../features/picture_in_picture/index.tsx     | 79 ++++++++++++++++
 app/javascript/mastodon/features/ui/index.jsx |  2 +-
 app/javascript/mastodon/reducers/index.ts     |  4 +-
 .../mastodon/reducers/picture_in_picture.js   | 26 ------
 .../mastodon/reducers/picture_in_picture.ts   | 56 ++++++++++++
 app/javascript/mastodon/selectors/index.js    |  2 +-
 13 files changed, 218 insertions(+), 218 deletions(-)
 delete mode 100644 app/javascript/mastodon/actions/picture_in_picture.js
 create mode 100644 app/javascript/mastodon/actions/picture_in_picture.ts
 delete mode 100644 app/javascript/mastodon/features/picture_in_picture/components/header.jsx
 create mode 100644 app/javascript/mastodon/features/picture_in_picture/components/header.tsx
 delete mode 100644 app/javascript/mastodon/features/picture_in_picture/index.jsx
 create mode 100644 app/javascript/mastodon/features/picture_in_picture/index.tsx
 delete mode 100644 app/javascript/mastodon/reducers/picture_in_picture.js
 create mode 100644 app/javascript/mastodon/reducers/picture_in_picture.ts

diff --git a/app/javascript/mastodon/actions/picture_in_picture.js b/app/javascript/mastodon/actions/picture_in_picture.js
deleted file mode 100644
index 898375abe..000000000
--- a/app/javascript/mastodon/actions/picture_in_picture.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// @ts-check
-
-export const PICTURE_IN_PICTURE_DEPLOY = 'PICTURE_IN_PICTURE_DEPLOY';
-export const PICTURE_IN_PICTURE_REMOVE = 'PICTURE_IN_PICTURE_REMOVE';
-
-/**
- * @typedef MediaProps
- * @property {string} src
- * @property {boolean} muted
- * @property {number} volume
- * @property {number} currentTime
- * @property {string} poster
- * @property {string} backgroundColor
- * @property {string} foregroundColor
- * @property {string} accentColor
- */
-
-/**
- * @param {string} statusId
- * @param {string} accountId
- * @param {string} playerType
- * @param {MediaProps} props
- * @returns {object}
- */
-export const deployPictureInPicture = (statusId, accountId, playerType, props) => {
-  // @ts-expect-error
-  return (dispatch, getState) => {
-    // Do not open a player for a toot that does not exist
-    if (getState().hasIn(['statuses', statusId])) {
-      dispatch({
-        type: PICTURE_IN_PICTURE_DEPLOY,
-        statusId,
-        accountId,
-        playerType,
-        props,
-      });
-    }
-  };
-};
-
-/*
- * @return {object}
- */
-export const removePictureInPicture = () => ({
-  type: PICTURE_IN_PICTURE_REMOVE,
-});
diff --git a/app/javascript/mastodon/actions/picture_in_picture.ts b/app/javascript/mastodon/actions/picture_in_picture.ts
new file mode 100644
index 000000000..d34b508a3
--- /dev/null
+++ b/app/javascript/mastodon/actions/picture_in_picture.ts
@@ -0,0 +1,31 @@
+import { createAction } from '@reduxjs/toolkit';
+
+import type { PIPMediaProps } from 'mastodon/reducers/picture_in_picture';
+import { createAppAsyncThunk } from 'mastodon/store/typed_functions';
+
+interface DeployParams {
+  statusId: string;
+  accountId: string;
+  playerType: 'audio' | 'video';
+  props: PIPMediaProps;
+}
+
+export const removePictureInPicture = createAction('pip/remove');
+
+export const deployPictureInPictureAction =
+  createAction<DeployParams>('pip/deploy');
+
+export const deployPictureInPicture = createAppAsyncThunk(
+  'pip/deploy',
+  (args: DeployParams, { dispatch, getState }) => {
+    const { statusId } = args;
+
+    // Do not open a player for a toot that does not exist
+
+    // @ts-expect-error state.statuses is not yet typed
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+    if (getState().hasIn(['statuses', statusId])) {
+      dispatch(deployPictureInPictureAction(args));
+    }
+  },
+);
diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx
index 7bd91c8c9..da93a16b0 100644
--- a/app/javascript/mastodon/containers/status_container.jsx
+++ b/app/javascript/mastodon/containers/status_container.jsx
@@ -262,7 +262,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
   },
 
   deployPictureInPicture (status, type, mediaProps) {
-    dispatch(deployPictureInPicture(status.get('id'), status.getIn(['account', 'id']), type, mediaProps));
+    dispatch(deployPictureInPicture({statusId: status.get('id'), accountId: status.getIn(['account', 'id']), playerType: type, props: mediaProps}));
   },
 
   onInteractionModal (type, status) {
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
index 8dfbf54cb..a7d8356be 100644
--- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
+++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
@@ -210,4 +210,4 @@ class Footer extends ImmutablePureComponent {
 
 }
 
-export default  withRouter(connect(makeMapStateToProps)(injectIntl(Footer)));
+export default  connect(makeMapStateToProps)(withRouter(injectIntl(Footer)));
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx
deleted file mode 100644
index 31073d738..000000000
--- a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import PropTypes from 'prop-types';
-
-import { defineMessages, injectIntl } from 'react-intl';
-
-import { Link } from 'react-router-dom';
-
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import { connect } from 'react-redux';
-
-import CloseIcon from '@/material-icons/400-24px/close.svg?react';
-import { Avatar } from 'mastodon/components/avatar';
-import { DisplayName } from 'mastodon/components/display_name';
-import { IconButton } from 'mastodon/components/icon_button';
-
-const messages = defineMessages({
-  close: { id: 'lightbox.close', defaultMessage: 'Close' },
-});
-
-const mapStateToProps = (state, { accountId }) => ({
-  account: state.getIn(['accounts', accountId]),
-});
-
-class Header extends ImmutablePureComponent {
-
-  static propTypes = {
-    accountId: PropTypes.string.isRequired,
-    statusId: PropTypes.string.isRequired,
-    account: ImmutablePropTypes.record.isRequired,
-    onClose: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-  };
-
-  render () {
-    const { account, statusId, onClose, intl } = this.props;
-
-    return (
-      <div className='picture-in-picture__header'>
-        <Link to={`/@${account.get('acct')}/${statusId}`} className='picture-in-picture__header__account'>
-          <Avatar account={account} size={36} />
-          <DisplayName account={account} />
-        </Link>
-
-        <IconButton icon='times' iconComponent={CloseIcon} onClick={onClose} title={intl.formatMessage(messages.close)} />
-      </div>
-    );
-  }
-
-}
-
-export default connect(mapStateToProps)(injectIntl(Header));
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.tsx b/app/javascript/mastodon/features/picture_in_picture/components/header.tsx
new file mode 100644
index 000000000..0f897dc44
--- /dev/null
+++ b/app/javascript/mastodon/features/picture_in_picture/components/header.tsx
@@ -0,0 +1,46 @@
+import { defineMessages, useIntl } from 'react-intl';
+
+import { Link } from 'react-router-dom';
+
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import { Avatar } from 'mastodon/components/avatar';
+import { DisplayName } from 'mastodon/components/display_name';
+import { IconButton } from 'mastodon/components/icon_button';
+import { useAppSelector } from 'mastodon/store';
+
+const messages = defineMessages({
+  close: { id: 'lightbox.close', defaultMessage: 'Close' },
+});
+
+interface Props {
+  accountId: string;
+  statusId: string;
+  onClose: () => void;
+}
+
+export const Header: React.FC<Props> = ({ accountId, statusId, onClose }) => {
+  const account = useAppSelector((state) => state.accounts.get(accountId));
+
+  const intl = useIntl();
+
+  if (!account) return null;
+
+  return (
+    <div className='picture-in-picture__header'>
+      <Link
+        to={`/@${account.get('acct')}/${statusId}`}
+        className='picture-in-picture__header__account'
+      >
+        <Avatar account={account} size={36} />
+        <DisplayName account={account} />
+      </Link>
+
+      <IconButton
+        icon='times'
+        iconComponent={CloseIcon}
+        onClick={onClose}
+        title={intl.formatMessage(messages.close)}
+      />
+    </div>
+  );
+};
diff --git a/app/javascript/mastodon/features/picture_in_picture/index.jsx b/app/javascript/mastodon/features/picture_in_picture/index.jsx
deleted file mode 100644
index f087cd1b1..000000000
--- a/app/javascript/mastodon/features/picture_in_picture/index.jsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import PropTypes from 'prop-types';
-import { Component } from 'react';
-
-import { connect } from 'react-redux';
-
-import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
-import Audio from 'mastodon/features/audio';
-import Video from 'mastodon/features/video';
-
-import Footer from './components/footer';
-import Header from './components/header';
-
-const mapStateToProps = state => ({
-  ...state.get('picture_in_picture'),
-});
-
-class PictureInPicture extends Component {
-
-  static propTypes = {
-    statusId: PropTypes.string,
-    accountId: PropTypes.string,
-    type: PropTypes.string,
-    src: PropTypes.string,
-    muted: PropTypes.bool,
-    volume: PropTypes.number,
-    currentTime: PropTypes.number,
-    poster: PropTypes.string,
-    backgroundColor: PropTypes.string,
-    foregroundColor: PropTypes.string,
-    accentColor: PropTypes.string,
-    dispatch: PropTypes.func.isRequired,
-  };
-
-  handleClose = () => {
-    const { dispatch } = this.props;
-    dispatch(removePictureInPicture());
-  };
-
-  render () {
-    const { type, src, currentTime, accountId, statusId } = this.props;
-
-    if (!currentTime) {
-      return null;
-    }
-
-    let player;
-
-    if (type === 'video') {
-      player = (
-        <Video
-          src={src}
-          currentTime={this.props.currentTime}
-          volume={this.props.volume}
-          muted={this.props.muted}
-          autoPlay
-          inline
-          alwaysVisible
-        />
-      );
-    } else if (type === 'audio') {
-      player = (
-        <Audio
-          src={src}
-          currentTime={this.props.currentTime}
-          volume={this.props.volume}
-          muted={this.props.muted}
-          poster={this.props.poster}
-          backgroundColor={this.props.backgroundColor}
-          foregroundColor={this.props.foregroundColor}
-          accentColor={this.props.accentColor}
-          autoPlay
-        />
-      );
-    }
-
-    return (
-      <div className='picture-in-picture'>
-        <Header accountId={accountId} statusId={statusId} onClose={this.handleClose} />
-
-        {player}
-
-        <Footer statusId={statusId} />
-      </div>
-    );
-  }
-
-}
-
-export default connect(mapStateToProps)(PictureInPicture);
diff --git a/app/javascript/mastodon/features/picture_in_picture/index.tsx b/app/javascript/mastodon/features/picture_in_picture/index.tsx
new file mode 100644
index 000000000..51b72f972
--- /dev/null
+++ b/app/javascript/mastodon/features/picture_in_picture/index.tsx
@@ -0,0 +1,79 @@
+import { useCallback } from 'react';
+
+import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
+import Audio from 'mastodon/features/audio';
+import Video from 'mastodon/features/video';
+import { useAppDispatch, useAppSelector } from 'mastodon/store/typed_functions';
+
+import Footer from './components/footer';
+import { Header } from './components/header';
+
+export const PictureInPicture: React.FC = () => {
+  const dispatch = useAppDispatch();
+
+  const handleClose = useCallback(() => {
+    dispatch(removePictureInPicture());
+  }, [dispatch]);
+
+  const pipState = useAppSelector((s) => s.picture_in_picture);
+
+  if (pipState.type === null) {
+    return null;
+  }
+
+  const {
+    type,
+    src,
+    currentTime,
+    accountId,
+    statusId,
+    volume,
+    muted,
+    poster,
+    backgroundColor,
+    foregroundColor,
+    accentColor,
+  } = pipState;
+
+  let player;
+
+  switch (type) {
+    case 'video':
+      player = (
+        <Video
+          src={src}
+          currentTime={currentTime}
+          volume={volume}
+          muted={muted}
+          autoPlay
+          inline
+          alwaysVisible
+        />
+      );
+      break;
+    case 'audio':
+      player = (
+        <Audio
+          src={src}
+          currentTime={currentTime}
+          volume={volume}
+          muted={muted}
+          poster={poster}
+          backgroundColor={backgroundColor}
+          foregroundColor={foregroundColor}
+          accentColor={accentColor}
+          autoPlay
+        />
+      );
+  }
+
+  return (
+    <div className='picture-in-picture'>
+      <Header accountId={accountId} statusId={statusId} onClose={handleClose} />
+
+      {player}
+
+      <Footer statusId={statusId} />
+    </div>
+  );
+};
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx
index 34c5dd302..77f26fed9 100644
--- a/app/javascript/mastodon/features/ui/index.jsx
+++ b/app/javascript/mastodon/features/ui/index.jsx
@@ -14,7 +14,7 @@ import { HotKeys } from 'react-hotkeys';
 import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app';
 import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
 import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
-import PictureInPicture from 'mastodon/features/picture_in_picture';
+import { PictureInPicture } from 'mastodon/features/picture_in_picture';
 import { layoutFromWindow } from 'mastodon/is_mobile';
 import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 
diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts
index b88175e77..db5e68a70 100644
--- a/app/javascript/mastodon/reducers/index.ts
+++ b/app/javascript/mastodon/reducers/index.ts
@@ -28,7 +28,7 @@ import { modalReducer } from './modal';
 import { notificationPolicyReducer } from './notification_policy';
 import { notificationRequestsReducer } from './notification_requests';
 import notifications from './notifications';
-import picture_in_picture from './picture_in_picture';
+import { pictureInPictureReducer } from './picture_in_picture';
 import polls from './polls';
 import push_notifications from './push_notifications';
 import { relationshipsReducer } from './relationships';
@@ -78,7 +78,7 @@ const reducers = {
   polls,
   trends,
   markers: markersReducer,
-  picture_in_picture,
+  picture_in_picture: pictureInPictureReducer,
   history,
   tags,
   followed_tags,
diff --git a/app/javascript/mastodon/reducers/picture_in_picture.js b/app/javascript/mastodon/reducers/picture_in_picture.js
deleted file mode 100644
index 6824ad930..000000000
--- a/app/javascript/mastodon/reducers/picture_in_picture.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { PICTURE_IN_PICTURE_DEPLOY, PICTURE_IN_PICTURE_REMOVE } from 'mastodon/actions/picture_in_picture';
-
-import { TIMELINE_DELETE } from '../actions/timelines';
-
-const initialState = {
-  statusId: null,
-  accountId: null,
-  type: null,
-  src: null,
-  muted: false,
-  volume: 0,
-  currentTime: 0,
-};
-
-export default function pictureInPicture(state = initialState, action) {
-  switch(action.type) {
-  case PICTURE_IN_PICTURE_DEPLOY:
-    return { statusId: action.statusId, accountId: action.accountId, type: action.playerType, ...action.props };
-  case PICTURE_IN_PICTURE_REMOVE:
-    return { ...initialState };
-  case TIMELINE_DELETE:
-    return (state.statusId === action.id) ? { ...initialState } : state;
-  default:
-    return state;
-  }
-}
diff --git a/app/javascript/mastodon/reducers/picture_in_picture.ts b/app/javascript/mastodon/reducers/picture_in_picture.ts
new file mode 100644
index 000000000..0feddcb70
--- /dev/null
+++ b/app/javascript/mastodon/reducers/picture_in_picture.ts
@@ -0,0 +1,56 @@
+import type { Reducer } from '@reduxjs/toolkit';
+
+import {
+  deployPictureInPictureAction,
+  removePictureInPicture,
+} from 'mastodon/actions/picture_in_picture';
+
+import { TIMELINE_DELETE } from '../actions/timelines';
+
+export interface PIPMediaProps {
+  src: string;
+  muted: boolean;
+  volume: number;
+  currentTime: number;
+  poster: string;
+  backgroundColor: string;
+  foregroundColor: string;
+  accentColor: string;
+}
+
+interface PIPStateWithValue extends Partial<PIPMediaProps> {
+  statusId: string;
+  accountId: string;
+  type: 'audio' | 'video';
+}
+
+interface PIPStateEmpty extends Partial<PIPMediaProps> {
+  type: null;
+}
+
+type PIPState = PIPStateWithValue | PIPStateEmpty;
+
+const initialState = {
+  type: null,
+  muted: false,
+  volume: 0,
+  currentTime: 0,
+};
+
+export const pictureInPictureReducer: Reducer<PIPState> = (
+  state = initialState,
+  action,
+) => {
+  if (deployPictureInPictureAction.match(action))
+    return {
+      statusId: action.payload.statusId,
+      accountId: action.payload.accountId,
+      type: action.payload.playerType,
+      ...action.payload.props,
+    };
+  else if (removePictureInPicture.match(action)) return initialState;
+  else if (action.type === TIMELINE_DELETE)
+    if (state.type && state.statusId === action.id) return initialState;
+
+  return state;
+};
diff --git a/app/javascript/mastodon/selectors/index.js b/app/javascript/mastodon/selectors/index.js
index b1c60403e..bd9b53919 100644
--- a/app/javascript/mastodon/selectors/index.js
+++ b/app/javascript/mastodon/selectors/index.js
@@ -60,7 +60,7 @@ export const makeGetStatus = () => {
 
 export const makeGetPictureInPicture = () => {
   return createSelector([
-    (state, { id }) => state.get('picture_in_picture').statusId === id,
+    (state, { id }) => state.picture_in_picture.statusId === id,
     (state) => state.getIn(['meta', 'layout']) !== 'mobile',
   ], (inUse, available) => ImmutableMap({
     inUse: inUse && available,

From b9982ce578c24fa2dcdbe4fb79610345257681df Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Wed, 27 Mar 2024 16:49:02 +0100
Subject: [PATCH 035/173] Fix notifications marker fetch (#29777)

---
 app/javascript/mastodon/actions/markers.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts
index 4e90a9c6b..84e5b33bc 100644
--- a/app/javascript/mastodon/actions/markers.ts
+++ b/app/javascript/mastodon/actions/markers.ts
@@ -155,8 +155,10 @@ export const submitMarkers = createAppAsyncThunk(
 export const fetchMarkers = createAppAsyncThunk(
   'markers/fetch',
   async (_args, { getState }) => {
-    const response =
-      await api(getState).get<Record<string, MarkerJSON>>(`/api/v1/markers`);
+    const response = await api(getState).get<Record<string, MarkerJSON>>(
+      `/api/v1/markers`,
+      { params: { timeline: ['notifications'] } },
+    );
 
     return { markers: response.data };
   },

From c913e2f3e50eb4f0f7c1459717ede3070b3e6846 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 27 Mar 2024 17:32:00 +0100
Subject: [PATCH 036/173] Fix language picker and privacy picker not having a
 backdrop filter (#29779)

---
 app/javascript/styles/mastodon/components.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 2d7aa32d8..48998097a 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -5084,6 +5084,7 @@ a.status-card {
 .language-dropdown__dropdown {
   box-shadow: var(--dropdown-shadow);
   background: var(--dropdown-background-color);
+  backdrop-filter: var(--background-filter);
   border: 1px solid var(--dropdown-border-color);
   padding: 4px;
   border-radius: 4px;

From 1025fff6b98d87b4050e373d638f890b44568c28 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 27 Mar 2024 22:19:03 +0100
Subject: [PATCH 037/173] New Crowdin Translations (automated) (#29772)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/bg.json    |  2 ++
 app/javascript/mastodon/locales/ca.json    |  2 +-
 app/javascript/mastodon/locales/fi.json    |  4 +++
 app/javascript/mastodon/locales/gl.json    |  6 ++++
 app/javascript/mastodon/locales/hu.json    | 30 ++++++++--------
 app/javascript/mastodon/locales/is.json    |  3 ++
 app/javascript/mastodon/locales/it.json    |  3 ++
 app/javascript/mastodon/locales/ja.json    |  1 +
 app/javascript/mastodon/locales/ko.json    |  7 ++++
 app/javascript/mastodon/locales/pt-BR.json | 40 ++++++++++++++++++++++
 app/javascript/mastodon/locales/pt-PT.json |  6 ++++
 app/javascript/mastodon/locales/sl.json    |  6 ++++
 app/javascript/mastodon/locales/sr.json    |  2 ++
 config/locales/bg.yml                      |  1 +
 config/locales/ca.yml                      |  1 +
 config/locales/da.yml                      |  1 +
 config/locales/de.yml                      |  1 +
 config/locales/es-AR.yml                   |  1 +
 config/locales/es-MX.yml                   |  1 +
 config/locales/es.yml                      |  1 +
 config/locales/eu.yml                      |  1 +
 config/locales/fi.yml                      |  1 +
 config/locales/fo.yml                      |  1 +
 config/locales/gl.yml                      |  1 +
 config/locales/he.yml                      |  1 +
 config/locales/hu.yml                      | 23 +++++++------
 config/locales/is.yml                      |  1 +
 config/locales/it.yml                      |  1 +
 config/locales/ko.yml                      |  1 +
 config/locales/nl.yml                      |  1 +
 config/locales/nn.yml                      |  1 +
 config/locales/pl.yml                      |  1 +
 config/locales/pt-BR.yml                   | 10 ++++++
 config/locales/pt-PT.yml                   |  1 +
 config/locales/sl.yml                      |  1 +
 config/locales/sq.yml                      |  1 +
 config/locales/sv.yml                      |  1 +
 config/locales/th.yml                      |  1 +
 config/locales/tr.yml                      |  1 +
 config/locales/uk.yml                      |  1 +
 config/locales/vi.yml                      |  1 +
 config/locales/zh-CN.yml                   |  1 +
 config/locales/zh-TW.yml                   |  1 +
 43 files changed, 146 insertions(+), 27 deletions(-)

diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index b7a236d60..113070511 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -471,6 +471,8 @@
   "notification.own_poll": "Анкетата ви приключи",
   "notification.poll": "Анкета, в която гласувахте, приключи",
   "notification.reblog": "{name} подсили ваша публикация",
+  "notification.relationships_severance_event": "Изгуби се връзката с {name}",
+  "notification.relationships_severance_event.learn_more": "Научете повече",
   "notification.status": "{name} току-що публикува",
   "notification.update": "{name} промени публикация",
   "notification_requests.accept": "Приемам",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index eee6d281d..37990cdb2 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -472,7 +472,7 @@
   "notification.own_poll": "La teva enquesta ha finalitzat",
   "notification.poll": "Ha finalitzat una enquesta en què has votat",
   "notification.reblog": "{name} t'ha impulsat",
-  "notification.relationships_severance_event": "Connexions perdudes amb {name}",
+  "notification.relationships_severance_event": "S'han perdut les connexions amb {name}",
   "notification.relationships_severance_event.account_suspension": "Un administrador de {from} ha suspès {target}; això vol dir que ja no en podreu rebre actualitzacions o interactuar-hi.",
   "notification.relationships_severance_event.domain_block": "Un administrador de {from} ha blocat {target}, incloent-hi {followersCount} dels vostres seguidors i {followingCount, plural, one {# compte} other {# comptes}} que seguiu.",
   "notification.relationships_severance_event.learn_more": "Per a saber-ne més",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 9dfa61ef4..b23f1254e 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -472,7 +472,11 @@
   "notification.own_poll": "Äänestyksesi on päättynyt",
   "notification.poll": "Kysely, johon osallistuit, on päättynyt",
   "notification.reblog": "{name} tehosti julkaisuasi",
+  "notification.relationships_severance_event": "Menetettiin yhteydet palvelimeen {name}",
+  "notification.relationships_severance_event.account_suspension": "Palvelimen {from} ylläpitäjä on jäädyttänyt verkkotunnuksen {target}, minkä takia et voi enää vastaanottaa heidän päivityksiään tai olla vuorovaikutuksessa heidän kanssaan.",
+  "notification.relationships_severance_event.domain_block": "Palvelimen {from} ylläpitäjä on estänyt verkkotunnuksen {target}, mukaan lukien {followersCount} seuraajistasi ja {followingCount, plural, one {# seuratuistasi} other {# seuratuistasi}}.",
   "notification.relationships_severance_event.learn_more": "Lue lisää",
+  "notification.relationships_severance_event.user_domain_block": "Olet estänyt verkkotunnuksen {target}, mikä poisti {followersCount} seuraajistasi ja {followingCount, plural, one {# seuratuistasi} other {# seuratuistasi}}.",
   "notification.status": "{name} julkaisi juuri",
   "notification.update": "{name} muokkasi julkaisua",
   "notification_requests.accept": "Hyväksy",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 20de52d30..c7fed4ed0 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar unha publicación",
   "filtered_notifications_banner.pending_requests": "Notificacións de {count, plural, =0 {ninguén} one {unha persoa} other {# persoas}} que poderías coñecer",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {mencións privadas}}",
   "filtered_notifications_banner.title": "Notificacións filtradas",
   "firehose.all": "Todo",
   "firehose.local": "Este servidor",
@@ -471,6 +472,11 @@
   "notification.own_poll": "A túa enquisa rematou",
   "notification.poll": "Rematou a enquisa na que votaches",
   "notification.reblog": "{name} compartiu a túa publicación",
+  "notification.relationships_severance_event": "Perdeuse a conexión con {name}",
+  "notification.relationships_severance_event.account_suspension": "A administración de {from} suspendeu a {target}, o que significa que xa non vas recibir actualizacións de esa conta ou interactuar con ela.",
+  "notification.relationships_severance_event.domain_block": "A administración de {from} bloqueou a {target}, que inclúe a {followersCount} das túas seguidoras e a {followingCount, plural, one {# conta} other {# contas}} que sigues.",
+  "notification.relationships_severance_event.learn_more": "Saber máis",
+  "notification.relationships_severance_event.user_domain_block": "Bloqueaches a {target}, eliminando a {followersCount} das túas seguidoras e a {followingCount, plural, one {# conta} other {# contas}} que sigues.",
   "notification.status": "{name} publicou",
   "notification.update": "{name} editou unha publicación",
   "notification_requests.accept": "Aceptar",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index c8e57c526..1de040a65 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -124,7 +124,7 @@
   "column.domain_blocks": "Letiltott domainek",
   "column.favourites": "Kedvencek",
   "column.firehose": "Hírfolyamok",
-  "column.follow_requests": "Követési kérelmek",
+  "column.follow_requests": "Követési kérések",
   "column.home": "Kezdőlap",
   "column.lists": "Listák",
   "column.mutes": "Némított felhasználók",
@@ -133,8 +133,8 @@
   "column.public": "Föderációs idővonal",
   "column_back_button.label": "Vissza",
   "column_header.hide_settings": "Beállítások elrejtése",
-  "column_header.moveLeft_settings": "Oszlop elmozdítása balra",
-  "column_header.moveRight_settings": "Oszlop elmozdítása jobbra",
+  "column_header.moveLeft_settings": "Oszlop áthelyezése balra",
+  "column_header.moveRight_settings": "Oszlop áthelyezése jobbra",
   "column_header.pin": "Kitűzés",
   "column_header.show_settings": "Beállítások megjelenítése",
   "column_header.unpin": "Kitűzés eltávolítása",
@@ -143,7 +143,7 @@
   "community.column_settings.media_only": "Csak média",
   "community.column_settings.remote_only": "Csak távoli",
   "compose.language.change": "Nyelv megváltoztatása",
-  "compose.language.search": "Nyelv keresése...",
+  "compose.language.search": "Nyelvek keresése…",
   "compose.published.body": "A bejegyzés publikálásra került.",
   "compose.published.open": "Megnyitás",
   "compose.saved.body": "A bejegyzés mentve.",
@@ -473,8 +473,8 @@
   "notification.poll": "Egy szavazás, melyben részt vettél, véget ért",
   "notification.reblog": "{name} megtolta a bejegyzésedet",
   "notification.relationships_severance_event": "Elvesztek a kapcsolatok vele: {name}",
-  "notification.relationships_severance_event.account_suspension": "Egy admin a {from} kiszolgálóról felfüggesztette {target} fiókot, ami azt jelenti, hogy mostantól nem tudsz vele interaktálni vagy tőle értesítéseket kapni.",
-  "notification.relationships_severance_event.domain_block": "Egy admin a {from} kiszolgálón letiltotta {target} domaint, beleértve {followersCount} követődet és {followingCount, plural, one {#} other {#}} általad követett személyt.",
+  "notification.relationships_severance_event.account_suspension": "Egy admin a(z) {from} kiszolgálóról felfüggesztette {target} fiókját, ami azt jelenti, hogy mostantól nem fogsz róla értesítést kapni, és nem fogsz tudni vele kapcsolatba lépni.",
+  "notification.relationships_severance_event.domain_block": "Egy admin a(z) {from} kiszolgálón letiltotta {target} domaint, beleértve {followersCount} követőt és {followingCount, plural, one {#} other {#}} követett fiókot.",
   "notification.relationships_severance_event.learn_more": "További információk",
   "notification.relationships_severance_event.user_domain_block": "Letiltottad a(z) {target} domaint, ezzel eltávolítva {followersCount} követőt és {followingCount, plural, one {#} other {#}} követett fiókot.",
   "notification.status": "{name} bejegyzést tett közzé",
@@ -492,7 +492,7 @@
   "notifications.column_settings.filter_bar.advanced": "Minden kategória megjelenítése",
   "notifications.column_settings.filter_bar.category": "Gyorsszűrő sáv",
   "notifications.column_settings.follow": "Új követők:",
-  "notifications.column_settings.follow_request": "Új követési kérelmek:",
+  "notifications.column_settings.follow_request": "Új követési kérések:",
   "notifications.column_settings.mention": "Megemlítések:",
   "notifications.column_settings.poll": "Szavazási eredmények:",
   "notifications.column_settings.push": "Leküldéses értesítések",
@@ -552,14 +552,14 @@
   "onboarding.share.next_steps": "Lehetséges következő lépések:",
   "onboarding.share.title": "Profil megosztása",
   "onboarding.start.lead": "Az új Mastodon-fiók használatra kész. Így hozhatod ki belőle a legtöbbet:",
-  "onboarding.start.skip": "Szeretnél előreugrani?",
+  "onboarding.start.skip": "Nincs szükséged segítségre a kezdéshez?",
   "onboarding.start.title": "Ez sikerült!",
   "onboarding.steps.follow_people.body": "A Mastodon az érdekes emberek követéséről szól.",
-  "onboarding.steps.follow_people.title": "{count, plural, one {egy ember} other {# ember}} követése",
-  "onboarding.steps.publish_status.body": "Üdvözöljük a világot.",
+  "onboarding.steps.follow_people.title": "Szabd személyre a kezdőlapodat",
+  "onboarding.steps.publish_status.body": "Köszöntsd a világot szöveggel, fotókkal, videókkal vagy szavazásokkal {emoji}",
   "onboarding.steps.publish_status.title": "Az első bejegyzés létrehozása",
-  "onboarding.steps.setup_profile.body": "Mások nagyobb valószínűséggel lépnek kapcsolatba veled egy kitöltött profil esetén.",
-  "onboarding.steps.setup_profile.title": "Profilod testreszabása",
+  "onboarding.steps.setup_profile.body": "Növeld az interakciók számát a profilod részletesebb kitöltésével.",
+  "onboarding.steps.setup_profile.title": "Szabd személyre a profilodat",
   "onboarding.steps.share_profile.body": "Tudasd az ismerőseiddel, hogyan találhatnak meg a Mastodonon",
   "onboarding.steps.share_profile.title": "Oszd meg a Mastodon profilodat",
   "onboarding.tips.2fa": "<strong>Tudtad?</strong> A fiókod biztonságossá teheted, ha a fiók beállításaiban beállítod a kétlépcsős hitelesítést. Bármilyen választott TOTP alkalmazással működik, nincs szükség telefonszámra!",
@@ -787,9 +787,9 @@
   "upload_modal.hint": "Kattints vagy húzd a kört az előnézetben arra a fókuszpontra, mely minden bélyegképen látható kell, hogy legyen.",
   "upload_modal.preparing_ocr": "OCR előkészítése…",
   "upload_modal.preview_label": "Előnézet ({ratio})",
-  "upload_progress.label": "Feltöltés...",
+  "upload_progress.label": "Feltöltés…",
   "upload_progress.processing": "Feldolgozás…",
-  "username.taken": "Ez a felhasználónév foglalt. Válassz másikat",
+  "username.taken": "Ez a felhasználónév foglalt. Válassz másikat.",
   "video.close": "Videó bezárása",
   "video.download": "Fájl letöltése",
   "video.exit_fullscreen": "Kilépés teljes képernyőből",
@@ -799,5 +799,5 @@
   "video.mute": "Hang némítása",
   "video.pause": "Szünet",
   "video.play": "Lejátszás",
-  "video.unmute": "Hang némításának vége"
+  "video.unmute": "Hang némításának feloldása"
 }
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index 6bcc79f70..c9a354f4b 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -473,7 +473,10 @@
   "notification.poll": "Könnun sem þú tókst þátt í er lokið",
   "notification.reblog": "{name} endurbirti færsluna þína",
   "notification.relationships_severance_event": "Missti tengingar við {name}",
+  "notification.relationships_severance_event.account_suspension": "Stjórnandi á {from} hefur fryst {target}, sem þýðir að þú færð ekki lengur skilaboð frá viðkomandi né átt í samskiptum við viðkomandi.",
+  "notification.relationships_severance_event.domain_block": "Stjórnandi á {from} hefur lokað á {target} og þar með {followersCount} fylgjendur þína auk {followingCount, plural, one {# aðgangs} other {# aðganga}} sem þú fylgist með.",
   "notification.relationships_severance_event.learn_more": "Kanna nánar",
+  "notification.relationships_severance_event.user_domain_block": "Þú hefur lokað á {target} og þar með fjarlægt {followersCount} fylgjendur þína auk {followingCount, plural, one {# aðgangs} other {# aðganga}} sem þú fylgist með.",
   "notification.status": "{name} sendi inn rétt í þessu",
   "notification.update": "{name} breytti færslu",
   "notification_requests.accept": "Samþykkja",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index eddab5f37..a6f26bfce 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtra questo post",
   "filter_modal.title.status": "Filtra un post",
   "filtered_notifications_banner.pending_requests": "Notifiche da {count, plural, =0 {nessuno} one {una persona} other {# persone}} che potresti conoscere",
+  "filtered_notifications_banner.private_mentions": "{count, plural,one {menzione privata} other {menzioni private}}",
   "filtered_notifications_banner.title": "Notifiche filtrate",
   "firehose.all": "Tutto",
   "firehose.local": "Questo server",
@@ -473,7 +474,9 @@
   "notification.reblog": "{name} ha rebloggato il tuo post",
   "notification.relationships_severance_event": "Connessioni perse con {name}",
   "notification.relationships_severance_event.account_suspension": "Un amministratore da {from} ha sospeso {target}, il che significa che non puoi più ricevere aggiornamenti da loro o interagire con loro.",
+  "notification.relationships_severance_event.domain_block": "Un amministratore da {from} ha bloccato {target}, inclusi {followersCount} dei tuoi seguaci e {followingCount, plural, one {# account} other {# account}} che segui.",
   "notification.relationships_severance_event.learn_more": "Scopri di più",
+  "notification.relationships_severance_event.user_domain_block": "Tu hai bloccato {target}, rimuovendo {followersCount} dei tuoi seguaci e {followingCount, plural, one {# account} other {# account}} che segui.",
   "notification.status": "{name} ha appena pubblicato un post",
   "notification.update": "{name} ha modificato un post",
   "notification_requests.accept": "Accetta",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 1f1065f5f..9dff30527 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -177,6 +177,7 @@
   "confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
   "confirmations.discard_edit_media.confirm": "破棄",
   "confirmations.discard_edit_media.message": "メディアの説明またはプレビューに保存されていない変更があります。それでも破棄しますか?",
+  "confirmations.domain_block.confirm": "サーバーをブロック",
   "confirmations.domain_block.message": "本当に{domain}全体を非表示にしますか? 多くの場合は個別にブロックやミュートするだけで充分であり、また好ましいです。公開タイムラインにそのドメインのコンテンツが表示されなくなり、通知も届かなくなります。そのドメインのフォロワーはアンフォローされます。",
   "confirmations.edit.confirm": "編集",
   "confirmations.edit.message": "今編集すると現在作成中のメッセージが上書きされます。本当に実行しますか?",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index e15089d0c..249ba6632 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "이 게시물을 필터",
   "filter_modal.title.status": "게시물 필터",
   "filtered_notifications_banner.pending_requests": "알 수도 있는 {count, plural, =0 {0 명} one {한 명} other {# 명}}의 사람들로부터의 알림",
+  "filtered_notifications_banner.private_mentions": "{count, plural, other {개인적인 멘션}}",
   "filtered_notifications_banner.title": "걸러진 알림",
   "firehose.all": "모두",
   "firehose.local": "이 서버",
@@ -471,6 +472,11 @@
   "notification.own_poll": "설문을 마침",
   "notification.poll": "참여한 설문이 종료됨",
   "notification.reblog": "{name} 님이 부스트했습니다",
+  "notification.relationships_severance_event": "{name} 님과의 연결이 끊어졌습니다",
+  "notification.relationships_severance_event.account_suspension": "{from}의 관리자가 {target}를 정지시켰기 때문에 그들과 더이상 상호작용 할 수 없고 정보를 받아볼 수 없습니다.",
+  "notification.relationships_severance_event.domain_block": "{from}의 관리자가 {target}를 차단하였고 여기에는 나의 {followersCount} 명의 팔로워와 {followingCount, plural, other {#}} 명의 팔로우가 포함되었습니다.",
+  "notification.relationships_severance_event.learn_more": "더 알아보기",
+  "notification.relationships_severance_event.user_domain_block": "내가 {target}를 차단하여 {followersCount} 명의 팔로워와 {followingCount, plural, other {#}} 명의 팔로우가 제거되었습니다.",
   "notification.status": "{name} 님이 방금 게시물을 올렸습니다",
   "notification.update": "{name} 님이 게시물을 수정했습니다",
   "notification_requests.accept": "수락",
@@ -484,6 +490,7 @@
   "notifications.column_settings.alert": "데스크탑 알림",
   "notifications.column_settings.favourite": "좋아요:",
   "notifications.column_settings.filter_bar.advanced": "모든 범주 표시",
+  "notifications.column_settings.filter_bar.category": "빠른 필터 막대",
   "notifications.column_settings.follow": "새 팔로워:",
   "notifications.column_settings.follow_request": "새 팔로우 요청:",
   "notifications.column_settings.mention": "멘션:",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 28a18667a..08ed5c021 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -89,8 +89,12 @@
   "announcement.announcement": "Comunicados",
   "attachments_list.unprocessed": "(não processado)",
   "audio.hide": "Ocultar áudio",
+  "block_modal.remote_users_caveat": "Pediremos ao servidor {domínio} que respeite sua decisão. No entanto, a conformidade não é garantida pois alguns servidores podem lidar com os blocos de maneira diferente. As postagens públicas ainda podem estar visíveis para usuários não logados.",
   "block_modal.show_less": "Mostrar menos",
   "block_modal.show_more": "Mostrar mais",
+  "block_modal.they_cant_mention": "Eles não podem mencionar ou seguir você.",
+  "block_modal.they_cant_see_posts": "Eles não podem ver suas postagens e você não verá as deles.",
+  "block_modal.they_will_know": "Eles podem ver que estão bloqueados.",
   "block_modal.title": "Bloquear usuário?",
   "block_modal.you_wont_see_mentions": "Você não verá publicações que os mencionem.",
   "boost_modal.combo": "Pressione {combo} para pular isso na próxima vez",
@@ -173,6 +177,7 @@
   "confirmations.delete_list.message": "Você tem certeza de que deseja excluir esta lista?",
   "confirmations.discard_edit_media.confirm": "Descartar",
   "confirmations.discard_edit_media.message": "Há mudanças não salvas na descrição ou pré-visualização da mídia. Descartar assim mesmo?",
+  "confirmations.domain_block.confirm": "Servidor de blocos",
   "confirmations.domain_block.message": "Você tem certeza de que deseja bloquear tudo de {domain}? Você não verá mais o conteúdo desta instância em nenhuma linha do tempo pública ou nas suas notificações. Seus seguidores desta instância serão removidos.",
   "confirmations.edit.confirm": "Editar",
   "confirmations.edit.message": "Editar agora irá substituir a mensagem que está sendo criando. Tem certeza de que deseja continuar?",
@@ -204,8 +209,27 @@
   "dismissable_banner.explore_statuses": "Estas são postagens de toda a rede social que estão ganhando tração hoje. Postagens mais recentes com mais impulsos e favoritos têm classificações mais altas.",
   "dismissable_banner.explore_tags": "Estas hashtags estão ganhando popularidade no momento entre as pessoas deste e de outros servidores da rede descentralizada.",
   "dismissable_banner.public_timeline": "Estas são as publicações públicas mais recentes de pessoas na rede social que pessoas em {domain} seguem.",
+  "domain_block_modal.block": "Servidor de blocos.",
+  "domain_block_modal.block_account_instead": "Bloco @(nome)",
   "domain_block_modal.they_can_interact_with_old_posts": "Pessoas deste servidor podem interagir com suas publicações antigas.",
   "domain_block_modal.they_cant_follow": "Ninguém deste servidor pode lhe seguir.",
+  "domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.",
+  "domain_block_modal.title": "Dominio do bloco",
+  "domain_block_modal.you_will_lose_followers": "Todos os seus seguidores deste servidor serão removidos.",
+  "domain_block_modal.you_wont_see_posts": "Você não verá postagens ou notificações de usuários neste servidor.",
+  "domain_pill.activitypub_lets_connect": "Ele permite que você se conecte e interaja com pessoas não apenas no Mastodon, mas também em diferentes aplicativos sociais.",
+  "domain_pill.activitypub_like_language": "ActivityPub é como a linguagem que o Mastodon fala com outras redes sociais.",
+  "domain_pill.server": "Servidor",
+  "domain_pill.their_handle": "Seu identificador:",
+  "domain_pill.their_server": "Sua casa digital, onde ficam todas as suas postagens.",
+  "domain_pill.their_username": "Seu identificador exclusivo em seu servidor. É possível encontrar usuários com o mesmo nome de usuário em servidores diferentes.",
+  "domain_pill.username": "Nome de usuário",
+  "domain_pill.whats_in_a_handle": "O que há em uma alça?",
+  "domain_pill.who_they_are": "Como os identificadores indicam quem alguém é e onde está, você pode interagir com pessoas na web social de <button>plataformas alimentadas pelo ActivityPub</button>.",
+  "domain_pill.who_you_are": "Como seu identificador indica quem você é e onde está, as pessoas podem interagir com você nas redes sociais das <button>plataformas alimentadas pelo ActivityPub</button>.",
+  "domain_pill.your_handle": "Seu identificador:",
+  "domain_pill.your_server": "Sua casa digital, onde ficam todas as suas postagens. Não gosta deste? Transfira servidores a qualquer momento e traga seus seguidores também.",
+  "domain_pill.your_username": "Seu identificador exclusivo neste servidor. É possível encontrar usuários com o mesmo nome de usuário em servidores diferentes.",
   "embed.instructions": "Incorpore este toot no seu site ao copiar o código abaixo.",
   "embed.preview": "Aqui está como vai ficar:",
   "emoji_button.activity": "Atividade",
@@ -273,6 +297,8 @@
   "filter_modal.select_filter.subtitle": "Use uma categoria existente ou crie uma nova",
   "filter_modal.select_filter.title": "Filtrar esta publicação",
   "filter_modal.title.status": "Filtrar uma publicação",
+  "filtered_notifications_banner.pending_requests": "Notificações de {count, plural, =0 {no one} one {one person} other {# people}} que você talvez conheça",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {private mention} other {private mentions}}",
   "filtered_notifications_banner.title": "Notificações filtradas",
   "firehose.all": "Tudo",
   "firehose.local": "Este servidor",
@@ -402,7 +428,9 @@
   "loading_indicator.label": "Carregando…",
   "media_gallery.toggle_visible": "{number, plural, one {Ocultar mídia} other {Ocultar mídias}}",
   "moved_to_account_banner.text": "Sua conta {disabledAccount} está desativada porque você a moveu para {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Ocultar das notificações",
   "mute_modal.hide_options": "Ocultar opções",
+  "mute_modal.indefinite": "Até que eu os ative",
   "mute_modal.show_options": "Mostrar opções",
   "mute_modal.they_can_mention_and_follow": "Eles podem mencionar e seguir você, mas você não os verá.",
   "mute_modal.they_wont_know": "Eles não saberão que foram silenciados.",
@@ -444,6 +472,11 @@
   "notification.own_poll": "Sua enquete terminou",
   "notification.poll": "Uma enquete que você votou terminou",
   "notification.reblog": "{name} deu boost no teu toot",
+  "notification.relationships_severance_event": "Conexões perdidas com {name}",
+  "notification.relationships_severance_event.account_suspension": "Um administrador de {from} suspendeu {target}, o que significa que você não pode mais receber atualizações deles ou interagir com eles.",
+  "notification.relationships_severance_event.domain_block": "An admin from {from} has blocked {target}, including {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.",
+  "notification.relationships_severance_event.learn_more": "Saber mais",
+  "notification.relationships_severance_event.user_domain_block": "You have blocked {target}, removing {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.",
   "notification.status": "{name} acabou de tootar",
   "notification.update": "{name} editou uma publicação",
   "notification_requests.accept": "Aceitar",
@@ -456,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Novas inscrições:",
   "notifications.column_settings.alert": "Notificações no computador",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Exibir todas as categorias",
+  "notifications.column_settings.filter_bar.category": "Barra de filtro rápido",
   "notifications.column_settings.follow": "Seguidores:",
   "notifications.column_settings.follow_request": "Seguidores pendentes:",
   "notifications.column_settings.mention": "Menções:",
@@ -481,7 +516,9 @@
   "notifications.permission_denied": "Navegador não tem permissão para ativar notificações no computador.",
   "notifications.permission_denied_alert": "Verifique a permissão do navegador para ativar notificações no computador.",
   "notifications.permission_required": "Ativar notificações no computador exige permissão do navegador.",
+  "notifications.policy.filter_new_accounts.hint": "Created within the past {days, plural, one {one day} other {# days}}",
   "notifications.policy.filter_new_accounts_title": "Novas contas",
+  "notifications.policy.filter_not_followers_hint": "Including people who have been following you fewer than {days, plural, one {one day} other {# days}}",
   "notifications.policy.filter_not_followers_title": "Pessoas que não estão te seguindo",
   "notifications.policy.filter_not_following_hint": "Até que você os aprove manualmente",
   "notifications.policy.filter_not_following_title": "Pessoas que você não segue",
@@ -569,6 +606,7 @@
   "relative_time.minutes": "{number}m",
   "relative_time.seconds": "{number}s",
   "relative_time.today": "hoje",
+  "reply_indicator.attachments": "{count, plural, one {# attachment} other {# attachments}}",
   "reply_indicator.cancel": "Cancelar",
   "reply_indicator.poll": "Enquete",
   "report.block": "Bloquear",
@@ -667,6 +705,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} hora} other {{count} vezes}}",
   "status.embed": "Incorporar",
   "status.favourite": "Favorita",
+  "status.favourites": "{count, plural, one {favorite} other {favorites}}",
   "status.filter": "Filtrar esta publicação",
   "status.filtered": "Filtrado",
   "status.hide": "Ocultar publicação",
@@ -687,6 +726,7 @@
   "status.reblog": "Dar boost",
   "status.reblog_private": "Dar boost para o mesmo público",
   "status.reblogged_by": "{name} deu boost",
+  "status.reblogs": "{count, plural, one {boost} other {boosts}}",
   "status.reblogs.empty": "Nada aqui. Quando alguém der boost, o usuário aparecerá aqui.",
   "status.redraft": "Excluir e rascunhar",
   "status.remove_bookmark": "Remover do Salvos",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 3f7f198ef..39dfba819 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrar esta publicação",
   "filter_modal.title.status": "Filtrar uma publicação",
   "filtered_notifications_banner.pending_requests": "Notificações de {count, plural, =0 {ninguém} one {uma pessoa} other {# pessoas}} que talvez conheça",
+  "filtered_notifications_banner.private_mentions": "{count, plural,one {menção privada} other {menções privadas}}",
   "filtered_notifications_banner.title": "Notificações filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
@@ -471,6 +472,11 @@
   "notification.own_poll": "A sua votação terminou",
   "notification.poll": "Uma votação em que participaste chegou ao fim",
   "notification.reblog": "{name} reforçou a tua publicação",
+  "notification.relationships_severance_event": "Perdeu as ligações com {name}",
+  "notification.relationships_severance_event.account_suspension": "Um administrador de {from} suspendeu {target}, o que significa que já não pode receber atualizações dele ou interagir com ele.",
+  "notification.relationships_severance_event.domain_block": "Um administrador de {from} bloqueou {target}, incluindo {followersCount} dos seus seguidores e {followingCount, plural, one {# conta} other {# contas}} que segue.",
+  "notification.relationships_severance_event.learn_more": "Saber mais",
+  "notification.relationships_severance_event.user_domain_block": "Bloqueou {target}, removendo {followersCount} dos seus seguidores e {followingCount, plural, one {# conta} other {# contas}} que segue.",
   "notification.status": "{name} acabou de publicar",
   "notification.update": "{name} editou uma publicação",
   "notification_requests.accept": "Aceitar",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 80b52ac10..55091dbee 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtriraj to objavo",
   "filter_modal.title.status": "Filtrirajte objavo",
   "filtered_notifications_banner.pending_requests": "Obvestila od {count, plural, =0 {nikogar, ki bi ga} one {# človeka, ki bi ga} two {# ljudi, ki bi ju} few {# ljudi, ki bi jih} other {# ljudi, ki bi jih}} lahko poznali",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {zasebna omemba} two {zasebni omembi} few {zasebne omembe} other {zasebnih omemb}}",
   "filtered_notifications_banner.title": "Filtrirana obvestila",
   "firehose.all": "Vse",
   "firehose.local": "Ta strežnik",
@@ -471,6 +472,11 @@
   "notification.own_poll": "Vaša anketa je zaključena",
   "notification.poll": "Anketa, v kateri ste sodelovali, je zaključena",
   "notification.reblog": "{name} je izpostavila/a vašo objavo",
+  "notification.relationships_severance_event": "Povezave z {name} prekinjene",
+  "notification.relationships_severance_event.account_suspension": "Skrbnik na {from} je suspendiral račun {target}, kar pomeni, da od računa ne morete več prejemati posodobitev ali imeti z njim interakcij.",
+  "notification.relationships_severance_event.domain_block": "Skrbnik na {from} je blokiral domeno {target}, vključno z vašimi sledilci ({followersCount}) in {followingCount, plural, one {# računom, ki mu sledite} two {# računoma, ki jima sledite} few {# računi, ki jim sledite} other {# računi, ki jim sledite}}.",
+  "notification.relationships_severance_event.learn_more": "Več o tem",
+  "notification.relationships_severance_event.user_domain_block": "Blokirali ste domeno {target}, vključno z vašimi sledilci ({followersCount}) in {followingCount, plural, one {# računom, ki mu sledite} two {# računoma, ki jima sledite} few {# računi, ki jim sledite} other {# računi, ki jim sledite}}.",
   "notification.status": "{name} je pravkar objavil/a",
   "notification.update": "{name} je uredil(a) objavo",
   "notification_requests.accept": "Sprejmi",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 347a3f65a..17ee71099 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -462,6 +462,7 @@
   "notification.own_poll": "Ваша анкета је завршена",
   "notification.poll": "Завршена је анкета у којој сте гласали",
   "notification.reblog": "{name} је подржао вашу објаву",
+  "notification.relationships_severance_event.learn_more": "Сазнајте више",
   "notification.status": "{name} је управо објавио",
   "notification.update": "{name} је уредио објаву",
   "notification_requests.accept": "Прихвати",
@@ -474,6 +475,7 @@
   "notifications.column_settings.admin.sign_up": "Нове рагистрације:",
   "notifications.column_settings.alert": "Обавештења на радној површини",
   "notifications.column_settings.favourite": "Омиљено:",
+  "notifications.column_settings.filter_bar.advanced": "Прикажи све категорије",
   "notifications.column_settings.follow": "Нови пратиоци:",
   "notifications.column_settings.follow_request": "Нови захтеви за праћење:",
   "notifications.column_settings.mention": "Помињања:",
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index e888c2ea9..0c4ce3be4 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -1768,6 +1768,7 @@ bg:
     contrast: Mastodon (висок контраст)
     default: Mastodon (тъмно)
     mastodon-light: Mastodon (светло)
+    system: Самодейно (употреба на системната тема)
   time:
     formats:
       default: "%d %b, %Y, %H:%M"
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index f94abe265..032dc1e35 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -1768,6 +1768,7 @@ ca:
     contrast: Mastodon (alt contrast)
     default: Mastodon (fosc)
     mastodon-light: Mastodon (clar)
+    system: Automàtic (utilitza el tema del sistema)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
diff --git a/config/locales/da.yml b/config/locales/da.yml
index 63762f740..acab53d15 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -1767,6 +1767,7 @@ da:
     contrast: Mastodon (høj kontrast)
     default: Mastodont (mørkt)
     mastodon-light: Mastodon (lyst)
+    system: Automatisk (benyt systemtema)
   time:
     formats:
       default: "%d. %b %Y, %H:%M"
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 620b571f9..22710265f 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -1768,6 +1768,7 @@ de:
     contrast: Mastodon (Hoher Kontrast)
     default: Mastodon (Dunkel)
     mastodon-light: Mastodon (Hell)
+    system: Automatisch (mit System synchronisieren)
   time:
     formats:
       default: "%d. %b %Y, %H:%M Uhr"
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index e10183be1..7bfe3b90b 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -1768,6 +1768,7 @@ es-AR:
     contrast: Alto contraste
     default: Oscuro
     mastodon-light: Claro
+    system: Automático (usar tema del sistema)
   time:
     formats:
       default: "%Y.%b.%d, %H:%M"
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index f497de568..f4f953a0c 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -1768,6 +1768,7 @@ es-MX:
     contrast: Alto contraste
     default: Mastodon
     mastodon-light: Mastodon (claro)
+    system: Automático (usar tema del sistema)
   time:
     formats:
       default: "%d de %b del %Y, %H:%M"
diff --git a/config/locales/es.yml b/config/locales/es.yml
index b5b98bb88..086e8e2ef 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -1768,6 +1768,7 @@ es:
     contrast: Alto contraste
     default: Mastodon
     mastodon-light: Mastodon (claro)
+    system: Automático (usar tema del sistema)
   time:
     formats:
       default: "%d de %b del %Y, %H:%M"
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 3e770b85c..523b60197 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -1772,6 +1772,7 @@ eu:
     contrast: Mastodon (Kontraste altua)
     default: Mastodon (Iluna)
     mastodon-light: Mastodon (Argia)
+    system: Automatikoa (erabili sistemaren gaia)
   time:
     formats:
       default: "%Y(e)ko %b %d, %H:%M"
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index fe5956fd5..155e4473b 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -1768,6 +1768,7 @@ fi:
     contrast: Mastodon (Korkea kontrasti)
     default: Mastodon (Tumma)
     mastodon-light: Mastodon (Vaalea)
+    system: Automaattinen (käytä järjestelmän teemaa)
   time:
     formats:
       default: "%d.%m.%Y klo %H.%M"
diff --git a/config/locales/fo.yml b/config/locales/fo.yml
index 1850c2a3b..b6c8b306f 100644
--- a/config/locales/fo.yml
+++ b/config/locales/fo.yml
@@ -1768,6 +1768,7 @@ fo:
     contrast: Mastodon (høgur kontrastur)
     default: Mastodon (myrkt)
     mastodon-light: Mastodon (ljóst)
+    system: Sjálvvirkandi (brúka vanligt uppsetingareyðkenni)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 4b1c9f096..f36d6783c 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -1768,6 +1768,7 @@ gl:
     contrast: Mastodon (Alto contraste)
     default: Mastodon (Escuro)
     mastodon-light: Mastodon (Claro)
+    system: Automático (seguir ao sistema)
   time:
     formats:
       default: "%d %b, %Y, %H:%M"
diff --git a/config/locales/he.yml b/config/locales/he.yml
index da9392554..ddb3417ff 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -1832,6 +1832,7 @@ he:
     contrast: מסטודון (ניגודיות גבוהה)
     default: מסטודון (כהה)
     mastodon-light: מסטודון (בהיר)
+    system: אוטומטי (לפי המערכת)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 8f8070d71..43f769253 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -57,27 +57,27 @@ hu:
       deleted: Törölve
       demote: Lefokozás
       destroyed_msg: A %{username} fiók adatai bekerültek a végleges törlése váró sorba
-      disable: Kikapcsolás
-      disable_sign_in_token_auth: Tokenes e-mail hitelesítés letiltása
+      disable: Befagyasztás
+      disable_sign_in_token_auth: Tokenes e-mail-hitelesítés letiltása
       disable_two_factor_authentication: Kétlépcsős hitelesítés kikapcsolása
-      disabled: Kikapcsolva
-      display_name: Megjelenített név
+      disabled: Befagyasztva
+      display_name: Megjelenítendő név
       domain: Domain
       edit: Szerkesztés
-      email: E-mail
+      email: E-mail-cím
       email_status: E-mail állapot
-      enable: Bekapcsolás
-      enable_sign_in_token_auth: Tokenes e-mail hitelesítés engedélyezése
+      enable: Kiolvasztás
+      enable_sign_in_token_auth: Tokenes e-mail-hitelesítés engedélyezése
       enabled: Bekapcsolva
-      enabled_msg: A %{username} fiók fagyasztását sikeresen visszavontuk
+      enabled_msg: "%{username} fiókja befagyasztása sikeresen visszavonva"
       followers: Követő
       follows: Követett
       header: Fejléc
-      inbox_url: Beérkezett üzenetek URL-je
+      inbox_url: Beérkezett üzenetek webcíme
       invite_request_text: Csatlakozás oka
       invited_by: Meghívta
-      ip: IP
-      joined: Csatlakozott
+      ip: IP-cím
+      joined: Csatlakozva
       location:
         all: Összes
         local: Helyi
@@ -1768,6 +1768,7 @@ hu:
     contrast: Mastodon (nagy kontrasztú)
     default: Mastodon (sötét)
     mastodon-light: Mastodon (világos)
+    system: Automatikus (rendszertéma használata)
   time:
     formats:
       default: "%Y. %b %d., %H:%M"
diff --git a/config/locales/is.yml b/config/locales/is.yml
index 6f9d0e7c7..ba1785d9e 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -1772,6 +1772,7 @@ is:
     contrast: Mastodon (mikil birtuskil)
     default: Mastodon (dökkt)
     mastodon-light: Mastodon (ljóst)
+    system: Sjálfvirkt (nota þema kerfis)
   time:
     formats:
       default: "%d. %b, %Y, %H:%M"
diff --git a/config/locales/it.yml b/config/locales/it.yml
index c63d8ef28..59ccb5f27 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -1770,6 +1770,7 @@ it:
     contrast: Mastodon (contrasto elevato)
     default: Mastodon (scuro)
     mastodon-light: Mastodon (chiaro)
+    system: Automatico (usa il tema di sistema)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 9548c4e44..5ca0324dc 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -1738,6 +1738,7 @@ ko:
     contrast: 마스토돈 (고대비)
     default: 마스토돈 (어두움)
     mastodon-light: 마스토돈 (밝음)
+    system: 자동 선택 (시스템 테마 이용)
   time:
     formats:
       default: "%Y-%m-%d %H:%M"
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 91aabb1fa..553c780be 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -1768,6 +1768,7 @@ nl:
     contrast: Mastodon (hoog contrast)
     default: Mastodon (donker)
     mastodon-light: Mastodon (licht)
+    system: Automatisch (systeemthema gebruiken)
   time:
     formats:
       default: "%d %B %Y om %H:%M"
diff --git a/config/locales/nn.yml b/config/locales/nn.yml
index 7145f3037..8a7cb18a4 100644
--- a/config/locales/nn.yml
+++ b/config/locales/nn.yml
@@ -1768,6 +1768,7 @@ nn:
     contrast: Mastodon (Høg kontrast)
     default: Mastodon (Mørkt)
     mastodon-light: Mastodon (Lyst)
+    system: Automatisk (bruk systemdrakta)
   time:
     formats:
       default: "%d.%b %Y, %H:%M"
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 89eec685d..d3d16fe37 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -1832,6 +1832,7 @@ pl:
     contrast: Mastodon (Wysoki kontrast)
     default: Mastodon (Ciemny)
     mastodon-light: Mastodon (Jasny)
+    system: Automatyczny (odpowiadający motywowi systemu)
   time:
     formats:
       default: "%d. %b %Y, %H:%M"
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 78a20aed0..0b28c8c1b 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -597,6 +597,9 @@ pt-BR:
       actions_description_html: Decida que medidas tomar para resolver esta denúncia. Se você decidir punir a conta denunciada, ela receberá uma notificação por e-mail, exceto quando for selecionada a categoria <strong>spam</strong> for selecionada.
       actions_description_remote_html: Decida quais medidas tomará para resolver esta denúncia. Isso só afetará como <strong>seu servidor</strong> se comunica com esta conta remota e manipula seu conteúdo.
       add_to_report: Adicionar mais à denúncia
+      already_suspended_badges:
+        local: Já suspenso neste servidor
+        remote: Já suspenso em seu servidor
       are_you_sure: Você tem certeza?
       assign_to_self: Atribuir para si
       assigned: Moderador responsável
@@ -1652,13 +1655,20 @@ pt-BR:
     import: Importar
     import_and_export: Importar e exportar
     migrate: Migração de conta
+    notifications: Notificações por e-mail
     preferences: Preferências
     profile: Perfil
     relationships: Seguindo e seguidores
+    severed_relationships: Relacionamentos rompidos
     statuses_cleanup: Exclusão automatizada de publicações
     strikes: Avisos de moderação
     two_factor_authentication: Autenticação de dois fatores
     webauthn_authentication: Chaves de segurança
+  severed_relationships:
+    download: Download  %{count}
+    event_type:
+      account_suspension: Suspensão da conta (%{target_name})
+      domain_block: Suspensão do servidor (%{target_name})
   statuses:
     attached:
       audio:
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index 666eb0bdd..8e30a27b8 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -1768,6 +1768,7 @@ pt-PT:
     contrast: Mastodon (Elevado contraste)
     default: Mastodon (Escuro)
     mastodon-light: Mastodon (Claro)
+    system: Automático (usar tema do sistema)
   time:
     formats:
       default: "%H:%M em %d de %b de %Y"
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index b42856730..ff23e6484 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -1832,6 +1832,7 @@ sl:
     contrast: Mastodon (Visok kontrast)
     default: Mastodon (Temna)
     mastodon-light: Mastodon (Svetla)
+    system: Samodejno (uporabi sistemsko temo)
   time:
     formats:
       default: "%b %d %Y, %H:%M"
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 3742b6142..12627434a 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -1762,6 +1762,7 @@ sq:
     contrast: Mastodon (Me shumë kontrast)
     default: Mastodon (I errët)
     mastodon-light: Mastodon (I çelët)
+    system: E automatizuar (përdor temë sistemi)
   time:
     formats:
       default: "%d %b, %Y, %H:%M"
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 8ffb3c1e2..02c4b8c55 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -1756,6 +1756,7 @@ sv:
     contrast: Hög kontrast
     default: Mastodon
     mastodon-light: Mastodon (ljust)
+    system: Automatisk (använd systemtema)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 69bae8767..3bedfb82f 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -1735,6 +1735,7 @@ th:
     contrast: Mastodon (ความคมชัดสูง)
     default: Mastodon (มืด)
     mastodon-light: Mastodon (สว่าง)
+    system: อัตโนมัติ (ใช้ชุดรูปแบบของระบบ)
   time:
     formats:
       default: "%d %b %Y %H:%M น."
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 692b3d281..4bd0e3455 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -1768,6 +1768,7 @@ tr:
     contrast: Mastodon (Yüksek karşıtlık)
     default: Mastodon (Karanlık)
     mastodon-light: Mastodon (Açık)
+    system: Otomatik (sistem temasını kullan)
   time:
     formats:
       default: "%d %b %Y %H:%M"
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index b02e9c556..7c7652d69 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -1832,6 +1832,7 @@ uk:
     contrast: Mastodon (Висока контрастність)
     default: Mastodon (Темна)
     mastodon-light: Mastodon (світла)
+    system: Автоматично (використовувати системну тему)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index f71ff741d..ec851a828 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -1736,6 +1736,7 @@ vi:
     contrast: Mastodon (Tương phản)
     default: Mastodon (Tối)
     mastodon-light: Mastodon (Sáng)
+    system: Tự động (chủ đề hệ thống)
   time:
     formats:
       default: "%-d.%m.%Y %H:%M"
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index dcc99d7a9..79764539d 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -1736,6 +1736,7 @@ zh-CN:
     contrast: Mastodon(高对比度)
     default: Mastodon(暗色主题)
     mastodon-light: Mastodon(亮色主题)
+    system: 自动切换(使用系统主题)
   time:
     formats:
       default: "%Y年%m月%d日 %H:%M"
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index e83001e7d..407931c20 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -1738,6 +1738,7 @@ zh-TW:
     contrast: Mastodon(高對比)
     default: Mastodon(深色)
     mastodon-light: Mastodon(亮色)
+    system: 自動(使用系統佈景主題)
   time:
     formats:
       default: "%Y 年 %b 月 %d 日 %H:%M"

From f2fd1da23fa6bc1847bf7d96a76826f36b29ae8c Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Thu, 28 Mar 2024 11:05:16 +0100
Subject: [PATCH 038/173] Fix PropTypes for some record objects (#29786)

---
 app/javascript/mastodon/components/status_action_bar.jsx        | 2 +-
 app/javascript/mastodon/features/getting_started/index.jsx      | 2 +-
 .../mastodon/features/status/components/action_bar.jsx          | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx
index 3c6d26e34..6def49fdb 100644
--- a/app/javascript/mastodon/components/status_action_bar.jsx
+++ b/app/javascript/mastodon/components/status_action_bar.jsx
@@ -81,7 +81,7 @@ class StatusActionBar extends ImmutablePureComponent {
 
   static propTypes = {
     status: ImmutablePropTypes.map.isRequired,
-    relationship: ImmutablePropTypes.map,
+    relationship: ImmutablePropTypes.record,
     onReply: PropTypes.func,
     onFavourite: PropTypes.func,
     onReblog: PropTypes.func,
diff --git a/app/javascript/mastodon/features/getting_started/index.jsx b/app/javascript/mastodon/features/getting_started/index.jsx
index a686a0a84..db6e0f6ec 100644
--- a/app/javascript/mastodon/features/getting_started/index.jsx
+++ b/app/javascript/mastodon/features/getting_started/index.jsx
@@ -82,7 +82,7 @@ class GettingStarted extends ImmutablePureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
-    myAccount: ImmutablePropTypes.map,
+    myAccount: ImmutablePropTypes.record,
     multiColumn: PropTypes.bool,
     fetchFollowRequests: PropTypes.func.isRequired,
     unreadFollowRequests: PropTypes.number,
diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx
index a4951260a..69209e8bd 100644
--- a/app/javascript/mastodon/features/status/components/action_bar.jsx
+++ b/app/javascript/mastodon/features/status/components/action_bar.jsx
@@ -74,7 +74,7 @@ class ActionBar extends PureComponent {
 
   static propTypes = {
     status: ImmutablePropTypes.map.isRequired,
-    relationship: ImmutablePropTypes.map,
+    relationship: ImmutablePropTypes.record,
     onReply: PropTypes.func.isRequired,
     onReblog: PropTypes.func.isRequired,
     onFavourite: PropTypes.func.isRequired,

From d08896476100e440d340f19540ae964887bc0a57 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Thu, 28 Mar 2024 11:06:25 +0100
Subject: [PATCH 039/173] Fix props for `<Button>` (#29780)

---
 app/javascript/mastodon/components/button.tsx | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/app/javascript/mastodon/components/button.tsx b/app/javascript/mastodon/components/button.tsx
index 0b6a0f267..c76aaea42 100644
--- a/app/javascript/mastodon/components/button.tsx
+++ b/app/javascript/mastodon/components/button.tsx
@@ -1,26 +1,26 @@
+import type { PropsWithChildren } from 'react';
 import { useCallback } from 'react';
 
 import classNames from 'classnames';
 
-interface BaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+interface BaseProps
+  extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
   block?: boolean;
   secondary?: boolean;
-  text?: JSX.Element;
 }
 
-interface PropsWithChildren extends BaseProps {
-  text?: never;
+interface PropsChildren extends PropsWithChildren<BaseProps> {
+  text?: undefined;
 }
 
 interface PropsWithText extends BaseProps {
-  text: JSX.Element;
-  children: never;
+  text: JSX.Element | string;
+  children?: undefined;
 }
 
-type Props = PropsWithText | PropsWithChildren;
+type Props = PropsWithText | PropsChildren;
 
 export const Button: React.FC<Props> = ({
-  text,
   type = 'button',
   onClick,
   disabled,
@@ -28,6 +28,7 @@ export const Button: React.FC<Props> = ({
   secondary,
   className,
   title,
+  text,
   children,
   ...props
 }) => {

From 961bb84e4c87555bbce930a87291938a988a483a Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Thu, 28 Mar 2024 11:07:01 +0100
Subject: [PATCH 040/173] Fix `<RelativeTimestamp>` types (#29781)

---
 .../mastodon/components/relative_timestamp.tsx    | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/app/javascript/mastodon/components/relative_timestamp.tsx b/app/javascript/mastodon/components/relative_timestamp.tsx
index b9e1e4f8f..ac385e88c 100644
--- a/app/javascript/mastodon/components/relative_timestamp.tsx
+++ b/app/javascript/mastodon/components/relative_timestamp.tsx
@@ -191,7 +191,7 @@ const timeRemainingString = (
 interface Props {
   intl: IntlShape;
   timestamp: string;
-  year: number;
+  year?: number;
   futureDate?: boolean;
   short?: boolean;
 }
@@ -203,11 +203,6 @@ class RelativeTimestamp extends Component<Props, States> {
     now: Date.now(),
   };
 
-  static defaultProps = {
-    year: new Date().getFullYear(),
-    short: true,
-  };
-
   _timer: number | undefined;
 
   shouldComponentUpdate(nextProps: Props, nextState: States) {
@@ -257,7 +252,13 @@ class RelativeTimestamp extends Component<Props, States> {
   }
 
   render() {
-    const { timestamp, intl, year, futureDate, short } = this.props;
+    const {
+      timestamp,
+      intl,
+      futureDate,
+      year = new Date().getFullYear(),
+      short = true,
+    } = this.props;
 
     const timeGiven = timestamp.includes('T');
     const date = new Date(timestamp);

From d44e7a8578a6b9d0ac897d865654dd323e2be28b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 28 Mar 2024 11:54:16 +0100
Subject: [PATCH 041/173] Update dependency node to 20.12 (#29765)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 .nvmrc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.nvmrc b/.nvmrc
index a3597ecbd..7795cadb5 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-20.11
+20.12

From e85f24174e5d467974eb160318d20e13f8d43bda Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 28 Mar 2024 06:56:33 -0400
Subject: [PATCH 042/173] Simplify checklist step loop in welcome mailer
 (#29761)

---
 app/views/application/mailer/_checklist.html.haml |  8 +++-----
 app/views/user_mailer/welcome.html.haml           | 10 +++++-----
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/app/views/application/mailer/_checklist.html.haml b/app/views/application/mailer/_checklist.html.haml
index 324fd7e6f..91c7c98f2 100644
--- a/app/views/application/mailer/_checklist.html.haml
+++ b/app/views/application/mailer/_checklist.html.haml
@@ -16,16 +16,14 @@
                           = image_tag frontend_asset_url('images/mailer-new/welcome/checkbox-off.png'), alt: '', width: 20, height: 20
                       %td.email-checklist-icons-step-td
                         - if defined?(key)
-                          = image_tag frontend_asset_url("images/mailer-new/welcome-icons/#{key}-#{checked ? 'on' : 'off'}.png"), alt: '', width: 40, height: 40
+                          = image_tag frontend_asset_url("images/mailer-new/welcome-icons/#{key}_step-#{checked ? 'on' : 'off'}.png"), alt: '', width: 40, height: 40
                 %td.email-checklist-text-td
                   .email-desktop-flex
                     /[if mso]
                       <table border="0" cellpadding="0" cellspacing="0" align="center" style="width:100%;" role="presentation"><tr><td vertical-align:top;">
                     %div
-                      - if defined?(title)
-                        %h3= title
-                      - if defined?(text)
-                        %p= text
+                      %h3= t("user_mailer.welcome.#{key}_title")
+                      %p= t("user_mailer.welcome.#{key}_step")
                     /[if mso]
                       </td><td style="vertical-align:top;">
                     %div
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index fd8980c23..0e55707d3 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -23,11 +23,11 @@
     %td.email-body-huge-padding-td
       %h2.email-h2= t('user_mailer.welcome.checklist_title')
       %p.email-h-sub= t('user_mailer.welcome.checklist_subtitle')
-      = render 'application/mailer/checklist', key: 'edit_profile_step', title: t('user_mailer.welcome.edit_profile_title'), text: t('user_mailer.welcome.edit_profile_step'), checked: @has_account_fields, button_text: t('user_mailer.welcome.edit_profile_action'), button_url: web_url('start/profile')
-      = render 'application/mailer/checklist', key: 'follow_step', title: t('user_mailer.welcome.follow_title'), text: t('user_mailer.welcome.follow_step'), checked: @has_active_relationships, button_text: t('user_mailer.welcome.follow_action'), button_url: web_url('start/follows')
-      = render 'application/mailer/checklist', key: 'post_step', title: t('user_mailer.welcome.post_title'), text: t('user_mailer.welcome.post_step'), checked: @has_statuses, button_text: t('user_mailer.welcome.post_action'), button_url: web_url
-      = render 'application/mailer/checklist', key: 'share_step', title: t('user_mailer.welcome.share_title'), text: t('user_mailer.welcome.share_step'), checked: false, button_text: t('user_mailer.welcome.share_action'), button_url: web_url('start/share')
-      = render 'application/mailer/checklist', key: 'apps_step', title: t('user_mailer.welcome.apps_title'), text: t('user_mailer.welcome.apps_step'), checked: false, show_apps_buttons: true
+      = render 'application/mailer/checklist', key: 'edit_profile', checked: @has_account_fields, button_text: t('user_mailer.welcome.edit_profile_action'), button_url: web_url('start/profile')
+      = render 'application/mailer/checklist', key: 'follow', checked: @has_active_relationships, button_text: t('user_mailer.welcome.follow_action'), button_url: web_url('start/follows')
+      = render 'application/mailer/checklist', key: 'post', checked: @has_statuses, button_text: t('user_mailer.welcome.post_action'), button_url: web_url
+      = render 'application/mailer/checklist', key: 'share', checked: false, button_text: t('user_mailer.welcome.share_action'), button_url: web_url('start/share')
+      = render 'application/mailer/checklist', key: 'apps', checked: false, show_apps_buttons: true
 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
   %tr
     %td.email-body-columns-td

From 4f068d4fcc4d134fcbd56faa8f39c608dd343417 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Thu, 28 Mar 2024 15:00:57 +0100
Subject: [PATCH 043/173] Fix logo pushing header buttons out of view on
 certain conditions in mobile layout (#29787)

---
 app/javascript/styles/mastodon/components.scss | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 48998097a..3961db50d 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2612,6 +2612,7 @@ a.account__display-name {
 }
 
 $ui-header-height: 55px;
+$ui-header-logo-wordmark-width: 99px;
 
 .ui__header {
   display: none;
@@ -2627,6 +2628,10 @@ $ui-header-height: 55px;
   &__logo {
     display: inline-flex;
     padding: 15px;
+    flex-grow: 1;
+    flex-shrink: 1;
+    overflow: hidden;
+    container: header-logo / inline-size;
 
     .logo {
       height: $ui-header-height - 30px;
@@ -2637,7 +2642,7 @@ $ui-header-height: 55px;
       display: none;
     }
 
-    @media screen and (width >= 320px) {
+    @container header-logo (min-width: #{$ui-header-logo-wordmark-width}) {
       .logo--wordmark {
         display: block;
       }
@@ -2654,6 +2659,7 @@ $ui-header-height: 55px;
     gap: 10px;
     padding: 0 10px;
     overflow: hidden;
+    flex-shrink: 0;
 
     .button {
       flex: 0 0 auto;

From 8a498f4e65ecf27cc2c992d02b47f890dafef20b Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 28 Mar 2024 15:48:09 +0100
Subject: [PATCH 044/173] New Crowdin Translations (automated) (#29785)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/es-MX.json | 1 +
 app/javascript/mastodon/locales/es.json    | 1 +
 app/javascript/mastodon/locales/kab.json   | 5 +++++
 config/locales/kab.yml                     | 9 +++++++++
 config/locales/ru.yml                      | 1 +
 config/locales/simple_form.kab.yml         | 6 ++++--
 config/locales/th.yml                      | 1 +
 7 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index fd32d9d90..78746d8b4 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 9c15a3cae..e3ed560b5 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json
index fbe60c3bd..9fdf60299 100644
--- a/app/javascript/mastodon/locales/kab.json
+++ b/app/javascript/mastodon/locales/kab.json
@@ -221,6 +221,7 @@
   "filter_modal.select_filter.prompt_new": "Taggayt tamaynutt : {name}",
   "filter_modal.select_filter.search": "Nadi neɣ snulfu-d",
   "filter_modal.select_filter.title": "Sizdeg tassufeɣt-a",
+  "filter_modal.title.status": "Sizdeg tassufeɣt",
   "firehose.all": "Akk",
   "firehose.local": "Deg uqeddac-ayi",
   "firehose.remote": "Iqeddacen nniḍen",
@@ -335,6 +336,7 @@
   "mute_modal.show_options": "Sken-d tinefrunin",
   "mute_modal.title": "Sgugem aseqdac?",
   "navigation_bar.about": "Ɣef",
+  "navigation_bar.advanced_interface": "Ldi deg ugrudem n web leqqayen",
   "navigation_bar.blocks": "Iseqdacen yettusḥebsen",
   "navigation_bar.bookmarks": "Ticraḍ",
   "navigation_bar.community_timeline": "Tasuddemt tadigant",
@@ -364,6 +366,7 @@
   "notification.own_poll": "Tafrant-ik·im tfuk",
   "notification.poll": "Tfukk tefrant ideg tettekkaḍ",
   "notification.reblog": "{name} yebḍa tajewwiqt-ik i tikelt-nniḍen",
+  "notification.relationships_severance_event.learn_more": "Issin ugar",
   "notification.status": "{name} akken i d-yessufeɣ",
   "notification_requests.accept": "Qbel",
   "notification_requests.dismiss": "Agi",
@@ -372,6 +375,8 @@
   "notifications.clear_confirmation": "Tebɣiḍ s tidet ad tekkseḍ akk tilɣa-inek·em i lebda?",
   "notifications.column_settings.alert": "Tilɣa n tnarit",
   "notifications.column_settings.favourite": "Imenyafen:",
+  "notifications.column_settings.filter_bar.advanced": "Sken-d akk taggayin",
+  "notifications.column_settings.filter_bar.category": "Iri n usizdeg uzrib",
   "notifications.column_settings.follow": "Imeḍfaṛen imaynuten:",
   "notifications.column_settings.follow_request": "Isuturen imaynuten n teḍfeṛt:",
   "notifications.column_settings.mention": "Abdar:",
diff --git a/config/locales/kab.yml b/config/locales/kab.yml
index 4ba608c9f..b2fc9d847 100644
--- a/config/locales/kab.yml
+++ b/config/locales/kab.yml
@@ -391,6 +391,7 @@ kab:
         invites: Iɛeṛṛuḍen
         moderation: Aseɣyed
       delete: Kkes
+      everyone: Tisirag timezwura
       privileges:
         administrator: Anedbal
     rules:
@@ -441,6 +442,10 @@ kab:
     system_checks:
       rules_check:
         action: Sefrek ilugan n uqeddac
+      software_version_critical_check:
+        action: Wali ileqqman yellan
+      software_version_patch_check:
+        action: Wali ileqqman yellan
     title: Tadbelt
     trends:
       allow: Sireg
@@ -602,6 +607,8 @@ kab:
       notifications: Ilɣa
       thread: Idiwenniyen
     edit:
+      add_keyword: Rnu awal tasarut
+      keywords: Awalen n tsarut
       title: Ẓreg amzizdig
     index:
       delete: Kkes
@@ -640,6 +647,7 @@ kab:
       blocking: Tabdart n yimiḍanen iweḥlen
       bookmarks: Ticraḍ
       following: Tabdert n wid teṭṭafareḍ
+      lists: Tibdarin
       muting: Tabdert n wid tesgugmeḍ
     upload: Sali
   invites:
@@ -750,6 +758,7 @@ kab:
       phantom_js: PhantomJS
       qq: Iminig QQ
       safari: Safari
+      unknown_browser: Iminig arussin
       weibo: Weibo
     current_session: Tiɣimit tamirant
     date: Azemz
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 05ea31ff8..85d8a7a54 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -1899,6 +1899,7 @@ ru:
         suspend: Учётная запись заблокирована
     welcome:
       explanation: Вот несколько советов для новичков
+      feature_action: Подробнее
       subject: Добро пожаловать в Mastodon
       title: Добро пожаловать на борт, %{name}!
   users:
diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml
index 8723e83ef..9461f16cd 100644
--- a/config/locales/simple_form.kab.yml
+++ b/config/locales/simple_form.kab.yml
@@ -74,8 +74,8 @@ kab:
         setting_default_language: Tutlayt n tira
         setting_default_privacy: Tabaḍnit n tira
         setting_display_media_default: Akk-a kan
-        setting_display_media_hide_all: Ffer kullec
-        setting_display_media_show_all: Ssken kullec
+        setting_display_media_hide_all: Ffer-iten akk
+        setting_display_media_show_all: Sken-iten-id akk
         setting_hide_network: Ffer azetta-k·m
         setting_theme: Asental n wesmel
         setting_use_pending_items: Askar aleɣwayan
@@ -115,6 +115,8 @@ kab:
         text: Alugen
       tag:
         name: Ahacṭag
+      user:
+        time_zone: Tamnaḍt tasragant
       user_role:
         name: Isem
         permissions_as_keys: Tisirag
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 3bedfb82f..2a05c892e 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -1646,6 +1646,7 @@ th:
       user_domain_block: คุณได้ปิดกั้น %{target_name}
     lost_followers: ผู้ติดตามที่หายไป
     lost_follows: การติดตามที่หายไป
+    preamble: คุณอาจสูญเสียการติดตามและผู้ติดตามเมื่อคุณปิดกั้นโดเมนหรือเมื่อผู้กลั่นกรองของคุณตัดสินใจที่จะระงับเซิร์ฟเวอร์ระยะไกล เมื่อสิ่งนั้นเกิดขึ้น คุณจะสามารถดาวน์โหลดรายการความสัมพันธ์ที่ตัดขาด เพื่อตรวจสอบและอาจนำเข้าในเซิร์ฟเวอร์อื่น
     purged: มีการล้างข้อมูลเกี่ยวกับเซิร์ฟเวอร์นี้โดยผู้ดูแลของเซิร์ฟเวอร์ของคุณ
     type: เหตุการณ์
   statuses:

From 67442f90393c644064bf34d531bdebe15f88d729 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Thu, 28 Mar 2024 16:33:15 +0100
Subject: [PATCH 045/173] Remove global `boosts` state and convert boosts modal
 to Typescript (#29774)

---
 app/javascript/mastodon/actions/boosts.js     |  32 ----
 .../mastodon/components/visibility_icon.tsx   |   5 +-
 .../mastodon/containers/status_container.jsx  |   3 +-
 .../containers/notification_container.js      |   4 +-
 .../picture_in_picture/components/footer.jsx  |   3 +-
 .../containers/detailed_status_container.js   |   3 +-
 .../mastodon/features/status/index.jsx        |   3 +-
 .../features/ui/components/boost_modal.jsx    | 125 --------------
 .../features/ui/components/boost_modal.tsx    | 162 ++++++++++++++++++
 .../features/ui/components/modal_root.jsx     |   2 +-
 app/javascript/mastodon/models/status.ts      |   4 +
 app/javascript/mastodon/reducers/boosts.js    |  25 ---
 app/javascript/mastodon/reducers/index.ts     |   2 -
 13 files changed, 175 insertions(+), 198 deletions(-)
 delete mode 100644 app/javascript/mastodon/actions/boosts.js
 delete mode 100644 app/javascript/mastodon/features/ui/components/boost_modal.jsx
 create mode 100644 app/javascript/mastodon/features/ui/components/boost_modal.tsx
 create mode 100644 app/javascript/mastodon/models/status.ts
 delete mode 100644 app/javascript/mastodon/reducers/boosts.js

diff --git a/app/javascript/mastodon/actions/boosts.js b/app/javascript/mastodon/actions/boosts.js
deleted file mode 100644
index 1fc2e391e..000000000
--- a/app/javascript/mastodon/actions/boosts.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { openModal } from './modal';
-
-export const BOOSTS_INIT_MODAL = 'BOOSTS_INIT_MODAL';
-export const BOOSTS_CHANGE_PRIVACY = 'BOOSTS_CHANGE_PRIVACY';
-
-export function initBoostModal(props) {
-  return (dispatch, getState) => {
-    const default_privacy = getState().getIn(['compose', 'default_privacy']);
-
-    const privacy = props.status.get('visibility') === 'private' ? 'private' : default_privacy;
-
-    dispatch({
-      type: BOOSTS_INIT_MODAL,
-      privacy,
-    });
-
-    dispatch(openModal({
-      modalType: 'BOOST',
-      modalProps: props,
-    }));
-  };
-}
-
-
-export function changeBoostPrivacy(privacy) {
-  return dispatch => {
-    dispatch({
-      type: BOOSTS_CHANGE_PRIVACY,
-      privacy,
-    });
-  };
-}
diff --git a/app/javascript/mastodon/components/visibility_icon.tsx b/app/javascript/mastodon/components/visibility_icon.tsx
index 753dc0273..3a310cbae 100644
--- a/app/javascript/mastodon/components/visibility_icon.tsx
+++ b/app/javascript/mastodon/components/visibility_icon.tsx
@@ -4,11 +4,10 @@ import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?re
 import LockIcon from '@/material-icons/400-24px/lock.svg?react';
 import PublicIcon from '@/material-icons/400-24px/public.svg?react';
 import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
+import type { StatusVisibility } from 'mastodon/models/status';
 
 import { Icon } from './icon';
 
-type Visibility = 'public' | 'unlisted' | 'private' | 'direct';
-
 const messages = defineMessages({
   public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
   unlisted_short: {
@@ -25,7 +24,7 @@ const messages = defineMessages({
   },
 });
 
-export const VisibilityIcon: React.FC<{ visibility: Visibility }> = ({
+export const VisibilityIcon: React.FC<{ visibility: StatusVisibility }> = ({
   visibility,
 }) => {
   const intl = useIntl();
diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx
index da93a16b0..c6842e8df 100644
--- a/app/javascript/mastodon/containers/status_container.jsx
+++ b/app/javascript/mastodon/containers/status_container.jsx
@@ -8,7 +8,6 @@ import {
 } from '../actions/accounts';
 import { showAlertForError } from '../actions/alerts';
 import { initBlockModal } from '../actions/blocks';
-import { initBoostModal } from '../actions/boosts';
 import {
   replyCompose,
   mentionCompose,
@@ -107,7 +106,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
     if ((e && e.shiftKey) || !boostModal) {
       this.onModalReblog(status);
     } else {
-      dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
+      dispatch(openModal({ modalType: 'BOOST', modalProps: { status, onReblog: this.onModalReblog } }));
     }
   },
 
diff --git a/app/javascript/mastodon/features/notifications/containers/notification_container.js b/app/javascript/mastodon/features/notifications/containers/notification_container.js
index 4458fd7bc..de450cd1a 100644
--- a/app/javascript/mastodon/features/notifications/containers/notification_container.js
+++ b/app/javascript/mastodon/features/notifications/containers/notification_container.js
@@ -1,6 +1,5 @@
 import { connect } from 'react-redux';
 
-import { initBoostModal } from '../../../actions/boosts';
 import { mentionCompose } from '../../../actions/compose';
 import {
   reblog,
@@ -8,6 +7,7 @@ import {
   unreblog,
   unfavourite,
 } from '../../../actions/interactions';
+import { openModal } from '../../../actions/modal';
 import {
   hideStatus,
   revealStatus,
@@ -49,7 +49,7 @@ const mapDispatchToProps = dispatch => ({
       if (e.shiftKey || !boostModal) {
         this.onModalReblog(status);
       } else {
-        dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
+        dispatch(openModal({ modalType: 'BOOST', modalProps: { status, onReblog: this.onModalReblog } }));
       }
     }
   },
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
index a7d8356be..7a163a882 100644
--- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
+++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
@@ -14,7 +14,6 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
 import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
 import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
 import StarIcon from '@/material-icons/400-24px/star.svg?react';
-import { initBoostModal } from 'mastodon/actions/boosts';
 import { replyCompose } from 'mastodon/actions/compose';
 import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
 import { openModal } from 'mastodon/actions/modal';
@@ -140,7 +139,7 @@ class Footer extends ImmutablePureComponent {
       } else if ((e && e.shiftKey) || !boostModal) {
         this._performReblog(status);
       } else {
-        dispatch(initBoostModal({ status, onReblog: this._performReblog }));
+        dispatch(openModal({ modalType: 'BOOST', modalProps: { status, onReblog: this._performReblog } }));
       }
     } else {
       dispatch(openModal({
diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js
index 3e1f8d4d2..1c650f544 100644
--- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js
+++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js
@@ -4,7 +4,6 @@ import { connect } from 'react-redux';
 
 import { showAlertForError } from '../../../actions/alerts';
 import { initBlockModal } from '../../../actions/blocks';
-import { initBoostModal } from '../../../actions/boosts';
 import {
   replyCompose,
   mentionCompose,
@@ -85,7 +84,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
       if (e.shiftKey || !boostModal) {
         this.onModalReblog(status);
       } else {
-        dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
+        dispatch(openModal({ modalType: 'BOOST', modalProps: { status, onReblog: this.onModalReblog } }));
       }
     }
   },
diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx
index 44db9d9c3..391475972 100644
--- a/app/javascript/mastodon/features/status/index.jsx
+++ b/app/javascript/mastodon/features/status/index.jsx
@@ -27,7 +27,6 @@ import {
   unmuteAccount,
 } from '../../actions/accounts';
 import { initBlockModal } from '../../actions/blocks';
-import { initBoostModal } from '../../actions/boosts';
 import {
   replyCompose,
   mentionCompose,
@@ -317,7 +316,7 @@ class Status extends ImmutablePureComponent {
         if ((e && e.shiftKey) || !boostModal) {
           this.handleModalReblog(status);
         } else {
-          dispatch(initBoostModal({ status, onReblog: this.handleModalReblog }));
+          dispatch(openModal({ modalType: 'BOOST', modalProps: { status, onReblog: this.handleModalReblog } }));
         }
       }
     } else {
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx
deleted file mode 100644
index 3b3e1e3f9..000000000
--- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import PropTypes from 'prop-types';
-
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-
-import classNames from 'classnames';
-import { withRouter } from 'react-router-dom';
-
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import { connect } from 'react-redux';
-
-import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
-import { changeBoostPrivacy } from 'mastodon/actions/boosts';
-import AttachmentList from 'mastodon/components/attachment_list';
-import { Icon }  from 'mastodon/components/icon';
-import { VisibilityIcon } from 'mastodon/components/visibility_icon';
-import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
-import { WithRouterPropTypes } from 'mastodon/utils/react_router';
-
-import { Avatar } from '../../../components/avatar';
-import { Button } from '../../../components/button';
-import { DisplayName } from '../../../components/display_name';
-import { RelativeTimestamp } from '../../../components/relative_timestamp';
-import StatusContent from '../../../components/status_content';
-
-const messages = defineMessages({
-  cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
-  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
-});
-
-const mapStateToProps = state => {
-  return {
-    privacy: state.getIn(['boosts', 'new', 'privacy']),
-  };
-};
-
-const mapDispatchToProps = dispatch => {
-  return {
-    onChangeBoostPrivacy(value) {
-      dispatch(changeBoostPrivacy(value));
-    },
-  };
-};
-
-class BoostModal extends ImmutablePureComponent {
-  static propTypes = {
-    status: ImmutablePropTypes.map.isRequired,
-    onReblog: PropTypes.func.isRequired,
-    onClose: PropTypes.func.isRequired,
-    onChangeBoostPrivacy: PropTypes.func.isRequired,
-    privacy: PropTypes.string.isRequired,
-    intl: PropTypes.object.isRequired,
-    ...WithRouterPropTypes,
-  };
-
-  handleReblog = () => {
-    this.props.onReblog(this.props.status, this.props.privacy);
-    this.props.onClose();
-  };
-
-  handleAccountClick = (e) => {
-    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
-      e.preventDefault();
-      this.props.onClose();
-      this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
-    }
-  };
-
-  _findContainer = () => {
-    return document.getElementsByClassName('modal-root__container')[0];
-  };
-
-  render () {
-    const { status, privacy, intl } = this.props;
-    const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
-
-    return (
-      <div className='modal-root__modal boost-modal'>
-        <div className='boost-modal__container'>
-          <div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
-            <div className='status__info'>
-              <a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
-                <span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span>
-                <RelativeTimestamp timestamp={status.get('created_at')} />
-              </a>
-
-              <a onClick={this.handleAccountClick} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name'>
-                <div className='status__avatar'>
-                  <Avatar account={status.get('account')} size={48} />
-                </div>
-
-                <DisplayName account={status.get('account')} />
-              </a>
-            </div>
-
-            <StatusContent status={status} />
-
-            {status.get('media_attachments').size > 0 && (
-              <AttachmentList
-                compact
-                media={status.get('media_attachments')}
-              />
-            )}
-          </div>
-        </div>
-
-        <div className='boost-modal__action-bar'>
-          <div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' icon={RepeatIcon} /></span> }} /></div>
-          {status.get('visibility') !== 'private' && !status.get('reblogged') && (
-            <PrivacyDropdown
-              noDirect
-              value={privacy}
-              container={this._findContainer}
-              onChange={this.props.onChangeBoostPrivacy}
-            />
-          )}
-          <Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} autoFocus />
-        </div>
-      </div>
-    );
-  }
-
-}
-
-export default withRouter(connect(mapStateToProps, mapDispatchToProps)(injectIntl(BoostModal)));
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.tsx b/app/javascript/mastodon/features/ui/components/boost_modal.tsx
new file mode 100644
index 000000000..40b0c8183
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/boost_modal.tsx
@@ -0,0 +1,162 @@
+import type { MouseEventHandler } from 'react';
+import { useCallback, useState } from 'react';
+
+import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
+
+import classNames from 'classnames';
+import { useHistory } from 'react-router';
+
+import type Immutable from 'immutable';
+
+import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
+import AttachmentList from 'mastodon/components/attachment_list';
+import { Icon } from 'mastodon/components/icon';
+import { VisibilityIcon } from 'mastodon/components/visibility_icon';
+import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
+import type { Account } from 'mastodon/models/account';
+import type { Status, StatusVisibility } from 'mastodon/models/status';
+import { useAppSelector } from 'mastodon/store';
+
+import { Avatar } from '../../../components/avatar';
+import { Button } from '../../../components/button';
+import { DisplayName } from '../../../components/display_name';
+import { RelativeTimestamp } from '../../../components/relative_timestamp';
+import StatusContent from '../../../components/status_content';
+
+const messages = defineMessages({
+  cancel_reblog: {
+    id: 'status.cancel_reblog_private',
+    defaultMessage: 'Unboost',
+  },
+  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
+});
+
+export const BoostModal: React.FC<{
+  status: Status;
+  onClose: () => void;
+  onReblog: (status: Status, privacy: StatusVisibility) => void;
+}> = ({ status, onReblog, onClose }) => {
+  const intl = useIntl();
+  const history = useHistory();
+
+  const default_privacy = useAppSelector(
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
+    (state) => state.compose.get('default_privacy') as StatusVisibility,
+  );
+
+  const account = status.get('account') as Account;
+  const statusVisibility = status.get('visibility') as StatusVisibility;
+
+  const [privacy, setPrivacy] = useState<StatusVisibility>(
+    statusVisibility === 'private' ? 'private' : default_privacy,
+  );
+
+  const onPrivacyChange = useCallback((value: StatusVisibility) => {
+    setPrivacy(value);
+  }, []);
+
+  const handleReblog = useCallback(() => {
+    onReblog(status, privacy);
+    onClose();
+  }, [onClose, onReblog, status, privacy]);
+
+  const handleAccountClick = useCallback<MouseEventHandler>(
+    (e) => {
+      if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
+        e.preventDefault();
+        onClose();
+        history.push(`/@${account.acct}`);
+      }
+    },
+    [history, onClose, account],
+  );
+
+  const buttonText = status.get('reblogged')
+    ? messages.cancel_reblog
+    : messages.reblog;
+
+  const findContainer = useCallback(
+    () => document.getElementsByClassName('modal-root__container')[0],
+    [],
+  );
+
+  return (
+    <div className='modal-root__modal boost-modal'>
+      <div className='boost-modal__container'>
+        <div
+          className={classNames(
+            'status',
+            `status-${statusVisibility}`,
+            'light',
+          )}
+        >
+          <div className='status__info'>
+            <a
+              href={`/@${account.acct}/${status.get('id') as string}`}
+              className='status__relative-time'
+              target='_blank'
+              rel='noopener noreferrer'
+            >
+              <span className='status__visibility-icon'>
+                <VisibilityIcon visibility={statusVisibility} />
+              </span>
+              <RelativeTimestamp
+                timestamp={status.get('created_at') as string}
+              />
+            </a>
+
+            <a
+              onClick={handleAccountClick}
+              href={`/@${account.acct}`}
+              className='status__display-name'
+            >
+              <div className='status__avatar'>
+                <Avatar account={account} size={48} />
+              </div>
+
+              <DisplayName account={account} />
+            </a>
+          </div>
+
+          {/* @ts-expect-error Expected until StatusContent is typed */}
+          <StatusContent status={status} />
+
+          {(status.get('media_attachments') as Immutable.List<unknown>).size >
+            0 && (
+            <AttachmentList compact media={status.get('media_attachments')} />
+          )}
+        </div>
+      </div>
+
+      <div className='boost-modal__action-bar'>
+        <div>
+          <FormattedMessage
+            id='boost_modal.combo'
+            defaultMessage='You can press {combo} to skip this next time'
+            values={{
+              combo: (
+                <span>
+                  Shift + <Icon id='retweet' icon={RepeatIcon} />
+                </span>
+              ),
+            }}
+          />
+        </div>
+        {statusVisibility !== 'private' && !status.get('reblogged') && (
+          <PrivacyDropdown
+            noDirect
+            value={privacy}
+            container={findContainer}
+            onChange={onPrivacyChange}
+          />
+        )}
+        <Button
+          text={intl.formatMessage(buttonText)}
+          onClick={handleReblog}
+          // eslint-disable-next-line jsx-a11y/no-autofocus
+          autoFocus
+        />
+      </div>
+    </div>
+  );
+};
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.jsx b/app/javascript/mastodon/features/ui/components/modal_root.jsx
index 97d7706da..404b53c74 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.jsx
+++ b/app/javascript/mastodon/features/ui/components/modal_root.jsx
@@ -24,7 +24,7 @@ import BundleContainer from '../containers/bundle_container';
 
 import ActionsModal from './actions_modal';
 import AudioModal from './audio_modal';
-import BoostModal from './boost_modal';
+import { BoostModal } from './boost_modal';
 import BundleModalError from './bundle_modal_error';
 import ConfirmationModal from './confirmation_modal';
 import FocalPointModal from './focal_point_modal';
diff --git a/app/javascript/mastodon/models/status.ts b/app/javascript/mastodon/models/status.ts
new file mode 100644
index 000000000..83e9f6b88
--- /dev/null
+++ b/app/javascript/mastodon/models/status.ts
@@ -0,0 +1,4 @@
+export type StatusVisibility = 'public' | 'unlisted' | 'private' | 'direct';
+
+// Temporary until we type it correctly
+export type Status = Immutable.Map<string, unknown>;
diff --git a/app/javascript/mastodon/reducers/boosts.js b/app/javascript/mastodon/reducers/boosts.js
deleted file mode 100644
index d0d825057..000000000
--- a/app/javascript/mastodon/reducers/boosts.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import Immutable from 'immutable';
-
-import {
-  BOOSTS_INIT_MODAL,
-  BOOSTS_CHANGE_PRIVACY,
-} from 'mastodon/actions/boosts';
-
-const initialState = Immutable.Map({
-  new: Immutable.Map({
-    privacy: 'public',
-  }),
-});
-
-export default function mutes(state = initialState, action) {
-  switch (action.type) {
-  case BOOSTS_INIT_MODAL:
-    return state.withMutations((state) => {
-      state.setIn(['new', 'privacy'], action.privacy);
-    });
-  case BOOSTS_CHANGE_PRIVACY:
-    return state.setIn(['new', 'privacy'], action.privacy);
-  default:
-    return state;
-  }
-}
diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts
index db5e68a70..6296ef202 100644
--- a/app/javascript/mastodon/reducers/index.ts
+++ b/app/javascript/mastodon/reducers/index.ts
@@ -7,7 +7,6 @@ import { accountsReducer } from './accounts';
 import accounts_map from './accounts_map';
 import alerts from './alerts';
 import announcements from './announcements';
-import boosts from './boosts';
 import compose from './compose';
 import contexts from './contexts';
 import conversations from './conversations';
@@ -60,7 +59,6 @@ const reducers = {
   relationships: relationshipsReducer,
   settings,
   push_notifications,
-  boosts,
   server,
   contexts,
   compose,

From cd9d11dda6a1244ed8dc9e39d54e40c26407267a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 29 Mar 2024 14:30:52 +0100
Subject: [PATCH 046/173] Update dependency debug to v1.9.2 (#29799)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 4d36cf4e9..5464dbef7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -194,7 +194,7 @@ GEM
       database_cleaner-core (~> 2.0.0)
     database_cleaner-core (2.0.1)
     date (3.3.4)
-    debug (1.9.1)
+    debug (1.9.2)
       irb (~> 1.10)
       reline (>= 0.3.8)
     debug_inspector (1.2.0)

From 671167f6dad1e62fac8ee0b22c79a6ab4b61b972 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 29 Mar 2024 14:31:13 +0100
Subject: [PATCH 047/173] Update dependency glob to v10.3.12 (#29790)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index bcdd1bd6f..b4e20cf96 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8863,17 +8863,17 @@ __metadata:
   linkType: hard
 
 "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7":
-  version: 10.3.10
-  resolution: "glob@npm:10.3.10"
+  version: 10.3.12
+  resolution: "glob@npm:10.3.12"
   dependencies:
     foreground-child: "npm:^3.1.0"
-    jackspeak: "npm:^2.3.5"
+    jackspeak: "npm:^2.3.6"
     minimatch: "npm:^9.0.1"
-    minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0"
-    path-scurry: "npm:^1.10.1"
+    minipass: "npm:^7.0.4"
+    path-scurry: "npm:^1.10.2"
   bin:
     glob: dist/esm/bin.mjs
-  checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d
+  checksum: 10c0/f60cefdc1cf3f958b2bb5823e1b233727f04916d489dc4641d76914f016e6704421e06a83cbb68b0cb1cb9382298b7a88075b844ad2127fc9727ea22b18b0711
   languageName: node
   linkType: hard
 
@@ -10334,7 +10334,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"jackspeak@npm:^2.3.5":
+"jackspeak@npm:^2.3.6":
   version: 2.3.6
   resolution: "jackspeak@npm:2.3.6"
   dependencies:
@@ -11447,10 +11447,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0":
-  version: 10.0.1
-  resolution: "lru-cache@npm:10.0.1"
-  checksum: 10c0/982dabfb227b9a2daf56d712ae0e72e01115a28c0a2068cd71277bca04568f3417bbf741c6c7941abc5c620fd8059e34f15607f90ebccbfa0a17533322d27a8e
+"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
+  version: 10.2.0
+  resolution: "lru-cache@npm:10.2.0"
+  checksum: 10c0/c9847612aa2daaef102d30542a8d6d9b2c2bb36581c1bf0dc3ebf5e5f3352c772a749e604afae2e46873b930a9e9523743faac4e5b937c576ab29196774712ee
   languageName: node
   linkType: hard
 
@@ -11916,7 +11916,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3":
+"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4":
   version: 7.0.4
   resolution: "minipass@npm:7.0.4"
   checksum: 10c0/6c7370a6dfd257bf18222da581ba89a5eaedca10e158781232a8b5542a90547540b4b9b7e7f490e4cda43acfbd12e086f0453728ecf8c19e0ef6921bc5958ac5
@@ -12749,13 +12749,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"path-scurry@npm:^1.10.1":
-  version: 1.10.1
-  resolution: "path-scurry@npm:1.10.1"
+"path-scurry@npm:^1.10.2":
+  version: 1.10.2
+  resolution: "path-scurry@npm:1.10.2"
   dependencies:
-    lru-cache: "npm:^9.1.1 || ^10.0.0"
+    lru-cache: "npm:^10.2.0"
     minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0"
-  checksum: 10c0/e5dc78a7348d25eec61ab166317e9e9c7b46818aa2c2b9006c507a6ff48c672d011292d9662527213e558f5652ce0afcc788663a061d8b59ab495681840c0c1e
+  checksum: 10c0/d723777fbf9627f201e64656680f66ebd940957eebacf780e6cce1c2919c29c116678b2d7dbf8821b3a2caa758d125f4444005ccec886a25c8f324504e48e601
   languageName: node
   linkType: hard
 

From 672c9f5f05bde788877ae0dcdb6668366c4c8941 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Fri, 29 Mar 2024 14:32:07 +0100
Subject: [PATCH 048/173] Change the `theme-color` value automatically when
 using a built-in theme (#29795)

---
 app/helpers/application_helper.rb       | 5 ++++-
 app/lib/themes.rb                       | 3 +++
 app/views/layouts/application.html.haml | 1 -
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index d46d0674a..c3ee0d930 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -164,8 +164,11 @@ module ApplicationHelper
     if theme == 'system'
       concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
       concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
+      concat tag.meta name: 'theme-color', content: Themes::MASTODON_DARK_THEME_COLOR, media: '(prefers-color-scheme: dark)'
+      concat tag.meta name: 'theme-color', content: Themes::MASTODON_LIGHT_THEME_COLOR, media: '(prefers-color-scheme: light)'
     else
-      stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
+      concat stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
+      concat tag.meta name: 'theme-color', content: theme == 'mastodon-light' ? Themes::MASTODON_LIGHT_THEME_COLOR : Themes::MASTODON_DARK_THEME_COLOR
     end
   end
 
diff --git a/app/lib/themes.rb b/app/lib/themes.rb
index 4010d8443..3ad230497 100644
--- a/app/lib/themes.rb
+++ b/app/lib/themes.rb
@@ -6,6 +6,9 @@ require 'yaml'
 class Themes
   include Singleton
 
+  MASTODON_DARK_THEME_COLOR = '#191b22'
+  MASTODON_LIGHT_THEME_COLOR = '#f3f5f7'
+
   def initialize
     @conf = YAML.load_file(Rails.root.join('config', 'themes.yml'))
   end
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 0cd7fc9f4..c353b1d87 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -21,7 +21,6 @@
 
     %link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/
     %link{ rel: 'manifest', href: manifest_path(format: :json) }/
-    %meta{ name: 'theme-color', content: '#191b22' }/
     %meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
 
     %title= html_title

From f96648d41c3faf2d8e20ac9c65132156eab9e6be Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 29 Mar 2024 14:35:50 +0100
Subject: [PATCH 049/173] New Crowdin Translations (automated) (#29796)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ar.json    | 27 ++++++++++++++++++++++
 app/javascript/mastodon/locales/be.json    |  2 ++
 app/javascript/mastodon/locales/bg.json    |  3 +++
 app/javascript/mastodon/locales/fr-CA.json | 12 ++++++++--
 app/javascript/mastodon/locales/fr.json    | 12 ++++++++--
 app/javascript/mastodon/locales/uk.json    |  3 ++-
 app/javascript/mastodon/locales/zh-HK.json |  8 +++++++
 config/locales/ar.yml                      | 21 +++++++++++++++++
 config/locales/devise.ar.yml               |  1 +
 config/locales/fr-CA.yml                   |  1 +
 config/locales/fr.yml                      |  1 +
 config/locales/simple_form.ar.yml          |  4 ++++
 config/locales/sk.yml                      |  4 ++++
 config/locales/zh-HK.yml                   |  4 ++++
 14 files changed, 98 insertions(+), 5 deletions(-)

diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 62ac7739d..a231e5e21 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -90,6 +90,8 @@
   "attachments_list.unprocessed": "(غير معالَج)",
   "audio.hide": "إخفاء المقطع الصوتي",
   "block_modal.remote_users_caveat": "Do t’i kërkojmë shërbyesit {domain} të respektojë vendimin tuaj. Por, pajtimi s’është i garantuar, ngaqë disa shërbyes mund t’i trajtojnë ndryshe bllokimet. Psotimet publike mundet të jenë ende të dukshme për përdorues pa bërë hyrje në llogari.",
+  "block_modal.show_less": "اعرض أقلّ",
+  "block_modal.show_more": "أظهر المزيد",
   "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة",
   "bundle_column_error.copy_stacktrace": "انسخ تقرير الخطأ",
   "bundle_column_error.error.body": "لا يمكن تقديم الصفحة المطلوبة. قد يكون بسبب خطأ في التعليمات البرمجية، أو مشكلة توافق المتصفح.",
@@ -201,6 +203,13 @@
   "dismissable_banner.explore_statuses": "هذه هي المنشورات الرائجة على الشبكات الاجتماعيّة اليوم. تظهر المنشورات المعاد نشرها والحائزة على مفضّلات أكثر في مرتبة عليا.",
   "dismissable_banner.explore_tags": "هذه هي الوسوم تكتسب جذب الاهتمام حاليًا على الويب الاجتماعي. الوسوم التي يستخدمها مختلف الناس تحتل مرتبة عليا.",
   "dismissable_banner.public_timeline": "هذه هي أحدث المنشورات العامة من الناس على الشبكة الاجتماعية التي يتبعها الناس على {domain}.",
+  "domain_pill.server": "الخادِم",
+  "domain_pill.their_handle": "مُعرِّفُه:",
+  "domain_pill.their_server": "بيتهم الرقمي، حيث تُستضاف كافة منشوراتهم.",
+  "domain_pill.their_username": "مُعرّفُهم الفريد على الخادم. من الممكن العثور على مستخدمين بنفس اسم المستخدم على خوادم مختلفة.",
+  "domain_pill.username": "اسم المستخدم",
+  "domain_pill.whats_in_a_handle": "ما المقصود بالمُعرِّف؟",
+  "domain_pill.your_handle": "عنوانك الكامل:",
   "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
   "embed.preview": "إليك ما سيبدو عليه:",
   "emoji_button.activity": "الأنشطة",
@@ -395,6 +404,13 @@
   "loading_indicator.label": "جاري التحميل…",
   "media_gallery.toggle_visible": "{number, plural, zero {} one {اخف الصورة} two {اخف الصورتين} few {اخف الصور} many {اخف الصور} other {اخف الصور}}",
   "moved_to_account_banner.text": "حسابك {disabledAccount} معطل حاليًا لأنك انتقلت إلى {movedToAccount}.",
+  "mute_modal.hide_options": "إخفاء الخيارات",
+  "mute_modal.show_options": "إظهار الخيارات",
+  "mute_modal.they_can_mention_and_follow": "سيكون بإمكانه الإشارة إليك ومتابعتك، لكنك لن تره.",
+  "mute_modal.they_wont_know": "لن يَعرف أنه قد تم كتمه.",
+  "mute_modal.title": "أتريد كتم المُستخدم؟",
+  "mute_modal.you_wont_see_mentions": "سوف لن تر المنشورات التي يُشار إليه.",
+  "mute_modal.you_wont_see_posts": "سيكون بإمكانه رؤية منشوراتك، لكنك لن ترى منشوراته.",
   "navigation_bar.about": "عن",
   "navigation_bar.advanced_interface": "افتحه في واجهة الويب المتقدمة",
   "navigation_bar.blocks": "الحسابات المحجوبة",
@@ -430,14 +446,21 @@
   "notification.own_poll": "انتهى استطلاعك للرأي",
   "notification.poll": "لقد انتهى استطلاع رأي شاركتَ فيه",
   "notification.reblog": "قام {name} بمشاركة منشورك",
+  "notification.relationships_severance_event.learn_more": "اعرف المزيد",
   "notification.status": "{name} نشر للتو",
   "notification.update": "عدّلَ {name} منشورًا",
+  "notification_requests.accept": "موافقة",
+  "notification_requests.dismiss": "تخطي",
+  "notification_requests.notifications_from": "إشعارات من {name}",
+  "notification_requests.title": "الإشعارات المصفاة",
   "notifications.clear": "مسح الإشعارات",
   "notifications.clear_confirmation": "متأكد من أنك تود مسح جميع الإشعارات الخاصة بك و المتلقاة إلى حد الآن ؟",
   "notifications.column_settings.admin.report": "التبليغات الجديدة:",
   "notifications.column_settings.admin.sign_up": "التسجيلات الجديدة:",
   "notifications.column_settings.alert": "إشعارات سطح المكتب",
   "notifications.column_settings.favourite": "المفضلة:",
+  "notifications.column_settings.filter_bar.advanced": "عرض جميع الفئات",
+  "notifications.column_settings.filter_bar.category": "شريط التصفية السريعة",
   "notifications.column_settings.follow": "متابعُون جُدُد:",
   "notifications.column_settings.follow_request": "الطلبات الجديد لِمتابَعتك:",
   "notifications.column_settings.mention": "الإشارات:",
@@ -463,6 +486,10 @@
   "notifications.permission_denied": "تنبيهات سطح المكتب غير متوفرة بسبب رفض أذونات المتصفح مسبقاً",
   "notifications.permission_denied_alert": "لا يمكن تفعيل إشعارات سطح المكتب، لأن إذن المتصفح قد تم رفضه سابقاً",
   "notifications.permission_required": "إشعارات سطح المكتب غير متوفرة لأنه لم يتم منح الإذن المطلوب.",
+  "notifications.policy.filter_new_accounts_title": "حسابات جديدة",
+  "notifications.policy.filter_not_followers_title": "أشخاص لا يتابعونك",
+  "notifications.policy.filter_not_following_hint": "حتى توافق عليهم يدويا",
+  "notifications.policy.filter_not_following_title": "أشخاص لا تتابعهم",
   "notifications_permission_banner.enable": "تفعيل إشعارات سطح المكتب",
   "notifications_permission_banner.how_to_control": "لتلقي الإشعارات عندما لا يكون ماستدون مفتوح، قم بتفعيل إشعارات سطح المكتب، يمكنك التحكم بدقة في أنواع التفاعلات التي تولد إشعارات سطح المكتب من خلال زر الـ{icon} أعلاه بمجرد تفعيلها.",
   "notifications_permission_banner.title": "لا تفوت شيئاً أبداً",
diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json
index fe186222a..276f7c712 100644
--- a/app/javascript/mastodon/locales/be.json
+++ b/app/javascript/mastodon/locales/be.json
@@ -471,6 +471,7 @@
   "notification.own_poll": "Ваша апытанне скончылася",
   "notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
   "notification.reblog": "{name} пашырыў ваш допіс",
+  "notification.relationships_severance_event.learn_more": "Даведацца больш",
   "notification.status": "Новы допіс ад {name}",
   "notification.update": "Допіс {name} адрэдагаваны",
   "notification_requests.accept": "Прыняць",
@@ -484,6 +485,7 @@
   "notifications.column_settings.alert": "Апавяшчэнні на працоўным стале",
   "notifications.column_settings.favourite": "Упадабанае:",
   "notifications.column_settings.filter_bar.advanced": "Паказаць усе катэгорыі",
+  "notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі",
   "notifications.column_settings.follow": "Новыя падпісчыкі:",
   "notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
   "notifications.column_settings.mention": "Згадванні:",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 113070511..910d6cb06 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -472,7 +472,10 @@
   "notification.poll": "Анкета, в която гласувахте, приключи",
   "notification.reblog": "{name} подсили ваша публикация",
   "notification.relationships_severance_event": "Изгуби се връзката с {name}",
+  "notification.relationships_severance_event.account_suspension": "Администратор от {from} спря {target}, което значи че повече не може да получавате новости от тях или да взаимодействате с тях.",
+  "notification.relationships_severance_event.domain_block": "Администратор от {from} блокира {target}, вкючващо {followersCount} от последователите ви и {followingCount, plural, one {# акаунт, който} other {# акаунта, които}} следвате.",
   "notification.relationships_severance_event.learn_more": "Научете повече",
+  "notification.relationships_severance_event.user_domain_block": "Блокирахте {target}, премахвайки {followersCount} от последователите си и {followingCount, plural, one {# акаунт, който} other {# акаунта, които}} следвате.",
   "notification.status": "{name} току-що публикува",
   "notification.update": "{name} промени публикация",
   "notification_requests.accept": "Приемам",
diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json
index ab4a3f309..163769253 100644
--- a/app/javascript/mastodon/locales/fr-CA.json
+++ b/app/javascript/mastodon/locales/fr-CA.json
@@ -222,14 +222,14 @@
   "domain_pill.server": "Serveur",
   "domain_pill.their_handle": "Son identifiant :",
   "domain_pill.their_server": "Son foyer numérique, là où tous ses posts résident.",
-  "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateurs avec le même nom sur différents serveurs.",
+  "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.",
   "domain_pill.username": "Nom d’utilisateur",
   "domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?",
   "domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.",
   "domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, vous pouvez interagir avec <button>les autres plateformes sociales implémentant ActivityPub</button>.",
   "domain_pill.your_handle": "Votre identifiant :",
   "domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.",
-  "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de trouver des utilisateurs ayant le même nom d'utilisateur sur différents serveurs.",
+  "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.",
   "embed.instructions": "Intégrez cette publication à votre site en copiant le code ci-dessous.",
   "embed.preview": "Voici comment il apparaîtra:",
   "emoji_button.activity": "Activité",
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrer cette publication",
   "filter_modal.title.status": "Filtrer une publication",
   "filtered_notifications_banner.pending_requests": "Notifications {count, plural, =0 {de personne} one {d’une personne} other {de # personnes}} que vous pouvez connaitre",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mention privée} other {mentions privées}}",
   "filtered_notifications_banner.title": "Notifications filtrées",
   "firehose.all": "Tout",
   "firehose.local": "Ce serveur",
@@ -471,6 +472,11 @@
   "notification.own_poll": "Votre sondage est terminé",
   "notification.poll": "Un sondage auquel vous avez participé est terminé",
   "notification.reblog": "{name} a boosté votre message",
+  "notification.relationships_severance_event": "Connexions perdues avec {name}",
+  "notification.relationships_severance_event.account_suspension": "Un·e administrateur·rice de {from} a suspendu {target}, ce qui signifie que vous ne pourrez plus recevoir de mises à jour ou interagir avec lui.",
+  "notification.relationships_severance_event.domain_block": "Un·e administrateur·rice de {from} en a bloqué {target}, comprenant {followersCount} de vos abonné·e·s et {followingCount, plural, one {# compte} other {# comptes}} vous suivez.",
+  "notification.relationships_severance_event.learn_more": "En savoir plus",
+  "notification.relationships_severance_event.user_domain_block": "Vous avez bloqué {target}, en supprimant {followersCount} de vos abonnés et {followingCount, plural, one {# compte} other {# comptes}} que vous suivez.",
   "notification.status": "{name} vient de publier",
   "notification.update": "{name} a modifié une publication",
   "notification_requests.accept": "Accepter",
@@ -483,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Nouvelles inscriptions:",
   "notifications.column_settings.alert": "Notifications navigateur",
   "notifications.column_settings.favourite": "Favoris:",
+  "notifications.column_settings.filter_bar.advanced": "Afficher toutes les catégories",
+  "notifications.column_settings.filter_bar.category": "Barre de filtre rapide",
   "notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e⋅s:",
   "notifications.column_settings.follow_request": "Nouvelles demandes d’abonnement:",
   "notifications.column_settings.mention": "Mentions:",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 5ae6fac9f..ace3d41e0 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -222,14 +222,14 @@
   "domain_pill.server": "Serveur",
   "domain_pill.their_handle": "Son identifiant :",
   "domain_pill.their_server": "Son foyer numérique, là où tous ses posts résident.",
-  "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateurs avec le même nom sur différents serveurs.",
+  "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.",
   "domain_pill.username": "Nom d’utilisateur",
   "domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?",
   "domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.",
   "domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, vous pouvez interagir avec <button>les autres plateformes sociales implémentant ActivityPub</button>.",
   "domain_pill.your_handle": "Votre identifiant :",
   "domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.",
-  "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de trouver des utilisateurs ayant le même nom d'utilisateur sur différents serveurs.",
+  "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.",
   "embed.instructions": "Intégrez ce message à votre site en copiant le code ci-dessous.",
   "embed.preview": "Il apparaîtra comme cela :",
   "emoji_button.activity": "Activités",
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Filtrer ce message",
   "filter_modal.title.status": "Filtrer un message",
   "filtered_notifications_banner.pending_requests": "Notifications {count, plural, =0 {de personne} one {d’une personne} other {de # personnes}} que vous pouvez connaitre",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {mention privée} other {mentions privées}}",
   "filtered_notifications_banner.title": "Notifications filtrées",
   "firehose.all": "Tout",
   "firehose.local": "Ce serveur",
@@ -471,6 +472,11 @@
   "notification.own_poll": "Votre sondage est terminé",
   "notification.poll": "Un sondage auquel vous avez participé vient de se terminer",
   "notification.reblog": "{name} a partagé votre message",
+  "notification.relationships_severance_event": "Connexions perdues avec {name}",
+  "notification.relationships_severance_event.account_suspension": "Un·e administrateur·rice de {from} a suspendu {target}, ce qui signifie que vous ne pourrez plus recevoir de mises à jour ou interagir avec lui.",
+  "notification.relationships_severance_event.domain_block": "Un·e administrateur·rice de {from} en a bloqué {target}, comprenant {followersCount} de vos abonné·e·s et {followingCount, plural, one {# compte} other {# comptes}} vous suivez.",
+  "notification.relationships_severance_event.learn_more": "En savoir plus",
+  "notification.relationships_severance_event.user_domain_block": "Vous avez bloqué {target}, en supprimant {followersCount} de vos abonnés et {followingCount, plural, one {# compte} other {# comptes}} que vous suivez.",
   "notification.status": "{name} vient de publier",
   "notification.update": "{name} a modifié un message",
   "notification_requests.accept": "Accepter",
@@ -483,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Nouvelles inscriptions :",
   "notifications.column_settings.alert": "Notifications du navigateur",
   "notifications.column_settings.favourite": "Favoris :",
+  "notifications.column_settings.filter_bar.advanced": "Afficher toutes les catégories",
+  "notifications.column_settings.filter_bar.category": "Barre de filtre rapide",
   "notifications.column_settings.follow": "Nouveaux·elles abonné·e·s :",
   "notifications.column_settings.follow_request": "Nouvelles demandes d’abonnement :",
   "notifications.column_settings.mention": "Mentions :",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 0648fde5b..c593ccc9d 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -287,6 +287,7 @@
   "filter_modal.select_filter.title": "Фільтрувати цей допис",
   "filter_modal.title.status": "Фільтрувати допис",
   "filtered_notifications_banner.pending_requests": "Сповіщення від {count, plural, =0 {жодної особи} one {однієї особи} few {# осіб} many {# осіб} other {# особи}}, котрих ви можете знати",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {приватна згадка} few {приватні згадки} many {приватні згадки} other {приватна згадка}}",
   "filtered_notifications_banner.title": "Відфільтровані сповіщення",
   "firehose.all": "Всі",
   "firehose.local": "Цей сервер",
@@ -476,7 +477,7 @@
   "notifications.column_settings.alert": "Сповіщення стільниці",
   "notifications.column_settings.favourite": "Уподобане:",
   "notifications.column_settings.filter_bar.advanced": "Показати всі категорії",
-  "notifications.column_settings.filter_bar.category": "Панель швидкого фільтру",
+  "notifications.column_settings.filter_bar.category": "Панель швидкого фільтра",
   "notifications.column_settings.follow": "Нові підписники:",
   "notifications.column_settings.follow_request": "Нові запити на підписку:",
   "notifications.column_settings.mention": "Згадки:",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index d618b68e2..c5ebf09b1 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "過濾此帖文",
   "filter_modal.title.status": "過濾一則帖文",
   "filtered_notifications_banner.pending_requests": "來自 {count, plural, =0 {0 位} other {# 位}}你可能認識的人的通知",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {則私人提及} other {則私人提及}}",
   "filtered_notifications_banner.title": "已過濾之通知",
   "firehose.all": "全部",
   "firehose.local": "本伺服器",
@@ -471,6 +472,11 @@
   "notification.own_poll": "你的投票已結束",
   "notification.poll": "你參與過的一個投票已經結束",
   "notification.reblog": "{name} 轉推你的文章",
+  "notification.relationships_severance_event": "失去與 {name} 的連結",
+  "notification.relationships_severance_event.account_suspension": "{from} 的管理員已將 {target} 停權,這表示你無法再收到他們的更新或與他們互動。",
+  "notification.relationships_severance_event.domain_block": "{from} 的管理員已封鎖 {target},包括你的 {followersCount} 位追蹤者和 {followingCount, plural, other {# 個你追蹤的帳號}}。",
+  "notification.relationships_severance_event.learn_more": "了解更多",
+  "notification.relationships_severance_event.user_domain_block": "你已封鎖 {target},並移除了你的 {followersCount} 位追蹤者和你追蹤的 {followingCount, plural, other {# 個帳號}}。",
   "notification.status": "{name} 剛發表了文章",
   "notification.update": "{name} 編輯了帖文",
   "notification_requests.accept": "接受",
@@ -483,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "新註冊:",
   "notifications.column_settings.alert": "顯示桌面通知",
   "notifications.column_settings.favourite": "最愛:",
+  "notifications.column_settings.filter_bar.advanced": "顯示所有分類",
+  "notifications.column_settings.filter_bar.category": "快速篩選欄",
   "notifications.column_settings.follow": "新追蹤者:",
   "notifications.column_settings.follow_request": "新的追蹤請求:",
   "notifications.column_settings.mention": "提及你:",
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index b0579c6f3..9043e23b9 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -1962,7 +1962,28 @@ ar:
         silence: الحساب محدود
         suspend: الحساب مُعلَّق
     welcome:
+      apps_android_action: احصل عليه من متجر جوجل للتطبيقات
+      apps_ios_action: التنزيل من App Store
+      apps_step: تنزيل تطبيقاتنا الرسمية.
+      apps_title: تطبيقات مَستُدون
+      checklist_subtitle: 'هيا بنا نبدأ مغامرتنا على الويب الاجتماعي الجديد:'
+      checklist_title: الخطوات الترحيبية الأولى
+      edit_profile_action: تخصيص
+      edit_profile_step: قم بتعزيز تفاعلاتك بامتلاك مِلَفّ تعريفي كامل.
+      edit_profile_title: قم بتخصيص ملفك التعريفي
       explanation: ها هي بعض النصائح قبل بداية الاستخدام
+      feature_action: اعرف المزيد
+      follow_action: تابِع
+      follows_title: مَن عليك متابعته
+      hashtags_title: الوسوم الرائجة
+      hashtags_view_more: عرض المزيد من الوسوم الرائجة
+      post_action: إنشاء
+      post_step: قل مرحبا للعالَم عبر نصّ أو صور أو فيديوهات أو استطلاعات رأي.
+      post_title: قم بإنشاء منشورك الأول
+      share_action: شارِك
+      share_step: أخبر أصدقائك بكيفية العثور عليك على مَستُدون.
+      share_title: شارك مِلَفّ مَستُدون التعريفي الخاص بك
+      sign_in_action: تسجيل الدخول
       subject: أهلًا بك على ماستدون
       title: أهلاً بك، %{name}!
   users:
diff --git a/config/locales/devise.ar.yml b/config/locales/devise.ar.yml
index 4e6adf42e..e8b6ff7d9 100644
--- a/config/locales/devise.ar.yml
+++ b/config/locales/devise.ar.yml
@@ -12,6 +12,7 @@ ar:
       last_attempt: بإمكانك إعادة المحاولة مرة واحدة قبل أن يتم قفل حسابك.
       locked: إن حسابك مقفل.
       not_found_in_database: "%{authentication_keys} أو كلمة سر خاطئة."
+      omniauth_user_creation_failure: خطأ في إنشاء حساب لهذه الهُوِيَّة.
       pending: إنّ حسابك في انتظار مراجعة.
       timeout: لقد انتهت مدة صَلاحِيَة جلستك. قم بتسجيل الدخول من جديد للمواصلة.
       unauthenticated: يجب عليك تسجيل الدخول أو إنشاء حساب قبل المواصلة.
diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml
index 6e422455c..05d6b8864 100644
--- a/config/locales/fr-CA.yml
+++ b/config/locales/fr-CA.yml
@@ -1768,6 +1768,7 @@ fr-CA:
     contrast: Mastodon (Contraste élevé)
     default: Mastodon (Sombre)
     mastodon-light: Mastodon (Clair)
+    system: Automatique (utiliser le thème système)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 31f5bfa51..6ab420880 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -1768,6 +1768,7 @@ fr:
     contrast: Mastodon (Contraste élevé)
     default: Mastodon (Sombre)
     mastodon-light: Mastodon (Clair)
+    system: Automatique (utiliser le thème système)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml
index 896fcbf3f..da27fd8dc 100644
--- a/config/locales/simple_form.ar.yml
+++ b/config/locales/simple_form.ar.yml
@@ -39,12 +39,14 @@ ar:
         text: يمكنك الطعن في عقوبة مرة واحدة فقط
       defaults:
         autofollow: سوف يتابعك تلقائيًا الأشخاص الذين يقومون بالتسجيل من خلال الدعوة
+        avatar: ملف WEBP أو PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تقليصه إلى %{dimensions} بيكسل
         bot: يقوم هذا الحساب أساسا بإجراءات آلية وقد لا يتم مراقبته
         context: واحد أو أكثر من السياقات التي يجب أن ينطبق عليها عامل التصفية
         current_password: لأسباب أمنية ، يرجى إدخال الكلمة السرية الخاصة بالحساب الحالي
         current_username: يرجى إدخال اسم المستخدم الخاص بالحساب الحالي قصد التأكيد
         digest: تُرسَل إليك بعد مُضيّ مدة مِن خمول نشاطك و فقط إذا ما تلقيت رسائل شخصية مباشِرة أثناء فترة غيابك مِن الشبكة
         email: سوف تتلقى رسالة إلكترونية للتأكيد
+        header: ملف WEBP أو PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تقليصه إلى %{dimensions} بيكسل
         inbox_url: نسخ العنوان الذي تريد استخدامه مِن صفحة الاستقبال للمُرحَّل
         irreversible: المنشورات التي تم تصفيتها ستختفي لا محالة حتى و إن تمت إزالة عامِل التصفية لاحقًا
         locale: لغة واجهة المستخدم و الرسائل الإلكترونية و الإشعارات
@@ -114,6 +116,7 @@ ar:
           sign_up_requires_approval: التسجيلات الجديدة سوف تتطلب موافقتك
         severity: اختر ما سيحدث مع الطلبات من هذا الـIP
       rule:
+        hint: اختياري. قدم المزيد من التفاصيل حول القاعدة
         text: صِف قانون أو شرط للمستخدمين على هذا الخادم. حاول أن تُبقيه قصير وبسيط
       sessions:
         otp: 'قم بإدخال رمز المصادقة بخطوتين الذي قام بتوليده تطبيق جهازك أو استخدم أحد رموز النفاذ الاحتياطية:'
@@ -297,6 +300,7 @@ ar:
           patch: إشعاري عند توفّر تحديثات التصحيح
         trending_tag: المتداولة الجديدة تتطلّب مراجعة
       rule:
+        hint: معلومات إضافية
         text: قانون
       settings:
         indexable: السماح لمحركات البحث بفهرسة صفحتك التعريفية
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 8c613e958..d4cd86585 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -585,6 +585,7 @@ sk:
         administration: Spravovanie
         invites: Pozvánky
         moderation: Moderácia
+        special: Špeciálne
       delete: Vymaž
       edit: Uprav postavenie %{name}
       everyone: Východzie oprávnenia
@@ -804,6 +805,7 @@ sk:
     confirmations:
       clicking_this_link: kliknutím na tento odkaz
       login_link: prihlás sa
+      proceed_to_login_html: Teraz môžeš pokračovať na %{login_link}.
       welcome_title: Vitaj, %{name}!
     delete_account: Vymaž účet
     delete_account_html: Pokiaľ chceš svoj účet odtiaľto vymazať, môžeš tak <a href="%{path}">urobiť tu</a>. Budeš požiadaný/á o potvrdenie tohto kroku.
@@ -822,6 +824,7 @@ sk:
     or_log_in_with: Alebo prihlás s
     progress:
       confirm: Potvrď email
+      details: Tvoje údaje
       rules: Súhlas s pravidlami
     register: Zaregistruj sa
     registration_closed: "%{instance} neprijíma nových členov"
@@ -883,6 +886,7 @@ sk:
       username_unavailable: Tvoja prezývka ostane neprístupná
   disputes:
     strikes:
+      action_taken: Vykonaný zákrok
       appeal: Namietni
       appeals:
         submit: Pošli námietku
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index af2b3b869..1dc50c284 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -585,6 +585,9 @@ zh-HK:
       actions_description_html: 決定對此檢舉採取哪種措施。如果對被檢舉帳號採取懲罰措施,除非選取了<strong>垃圾訊息</strong>分類,否則將向他們發送一封電郵通知。
       actions_description_remote_html: 決定對此檢舉採取哪種動作。這只會影響<strong>你的伺服器</strong>與此遠端帳號的通訊和處理其內容的方式。
       add_to_report: 加入更多到檢舉
+      already_suspended_badges:
+        local: 已在此伺服器被停權
+        remote: 已在他們的伺服器被停權
       are_you_sure: 你確認嗎?
       assign_to_self: 指派給自己
       assigned: 指派版主
@@ -1733,6 +1736,7 @@ zh-HK:
     contrast: 高對比
     default: 萬象
     mastodon-light: 萬象(亮色主題)
+    system: 自動(使用系統主題)
   time:
     formats:
       default: "%Y年%-m月%d日 %H:%M"

From 69e5771881037e52380712dfc029c101f76efe74 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Fri, 29 Mar 2024 14:57:39 +0100
Subject: [PATCH 050/173] Handle `createAppAsyncThunk` rejected actions in the
 errors middleware (#29791)

---
 .../mastodon/store/middlewares/errors.ts      | 27 ++++++++++++++-----
 .../mastodon/store/typed_functions.ts         |  8 +++++-
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/app/javascript/mastodon/store/middlewares/errors.ts b/app/javascript/mastodon/store/middlewares/errors.ts
index e11aa7817..977a09a46 100644
--- a/app/javascript/mastodon/store/middlewares/errors.ts
+++ b/app/javascript/mastodon/store/middlewares/errors.ts
@@ -1,16 +1,27 @@
-import { isAction } from '@reduxjs/toolkit';
+import {
+  isAction,
+  isAsyncThunkAction,
+  isRejectedWithValue,
+} from '@reduxjs/toolkit';
 import type { Action, Middleware } from '@reduxjs/toolkit';
 
 import type { RootState } from '..';
 import { showAlertForError } from '../../actions/alerts';
+import type { AsyncThunkRejectValue } from '../typed_functions';
 
 const defaultFailSuffix = 'FAIL';
 const isFailedAction = new RegExp(`${defaultFailSuffix}$`, 'g');
 
-interface ActionWithMaybeAlertParams extends Action {
-  skipAlert?: boolean;
-  skipNotFound?: boolean;
-  error?: unknown;
+interface ActionWithMaybeAlertParams extends Action, AsyncThunkRejectValue {}
+
+interface RejectedAction extends Action {
+  payload: AsyncThunkRejectValue;
+}
+
+function isRejectedActionWithPayload(
+  action: unknown,
+): action is RejectedAction {
+  return isAsyncThunkAction(action) && isRejectedWithValue(action);
 }
 
 function isActionWithmaybeAlertParams(
@@ -23,7 +34,11 @@ export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
   ({ dispatch }) =>
   (next) =>
   (action) => {
-    if (
+    if (isRejectedActionWithPayload(action) && !action.payload.skipAlert) {
+      dispatch(
+        showAlertForError(action.payload.error, action.payload.skipNotFound),
+      );
+    } else if (
       isActionWithmaybeAlertParams(action) &&
       !action.skipAlert &&
       action.type.match(isFailedAction)
diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts
index 4859b8265..b66d7545c 100644
--- a/app/javascript/mastodon/store/typed_functions.ts
+++ b/app/javascript/mastodon/store/typed_functions.ts
@@ -7,8 +7,14 @@ import type { AppDispatch, RootState } from './store';
 export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
 export const useAppSelector = useSelector.withTypes<RootState>();
 
+export interface AsyncThunkRejectValue {
+  skipAlert?: boolean;
+  skipNotFound?: boolean;
+  error?: unknown;
+}
+
 export const createAppAsyncThunk = createAsyncThunk.withTypes<{
   state: RootState;
   dispatch: AppDispatch;
-  rejectValue: string;
+  rejectValue: AsyncThunkRejectValue;
 }>();

From 430da0316062d3fabfb74dec68bb6de9d42ee750 Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Fri, 29 Mar 2024 12:16:51 -0500
Subject: [PATCH 051/173] Fix background tint in single column light theme
 (#29803)

---
 app/javascript/styles/mastodon/components.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 3961db50d..a86cedfe4 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2677,7 +2677,7 @@ $ui-header-logo-wordmark-width: 99px;
 }
 
 .tabs-bar__wrapper {
-  background: var(--background-color-tint);
+  background: var(--background-color);
   backdrop-filter: var(--background-filter);
   position: sticky;
   top: $ui-header-height;

From 90eb4a5d01f1f1e8a76e7dc814eae992a9c1ee16 Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Fri, 29 Mar 2024 16:03:30 -0500
Subject: [PATCH 052/173] Fix light theme header on mobile (#29809)

---
 app/javascript/styles/mastodon/components.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index a86cedfe4..216c0dab0 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2899,7 +2899,7 @@ $ui-header-logo-wordmark-width: 99px;
   .layout-single-column {
     .ui__header {
       display: flex;
-      background: var(--background-color-tint);
+      background: var(--background-color);
       border-bottom: 1px solid var(--background-border-color);
     }
 

From 589e34d00c5bc9a463486e52ec5f51780ff291ac Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 10:53:44 +0200
Subject: [PATCH 053/173] Update dependency selenium-webdriver to v4.19.0
 (#29776)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 Gemfile.lock             | 2 +-
 spec/support/capybara.rb | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 5464dbef7..74dfd3684 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -693,7 +693,7 @@ GEM
     scenic (1.7.0)
       activerecord (>= 4.0.0)
       railties (>= 4.0.0)
-    selenium-webdriver (4.18.1)
+    selenium-webdriver (4.19.0)
       base64 (~> 0.2)
       rexml (~> 3.2, >= 3.2.5)
       rubyzip (>= 1.2.2, < 3.0)
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 4aba65b40..d4f27e209 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -14,7 +14,6 @@ Capybara.register_driver :headless_chrome do |app|
   options = Selenium::WebDriver::Chrome::Options.new
   options.add_argument '--headless=new'
   options.add_argument '--window-size=1680,1050'
-  options.browser_version = '120'
 
   Capybara::Selenium::Driver.new(
     app,

From 173adb04e29faac56258f4b21730ae45aafafb6d Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 08:57:14 +0000
Subject: [PATCH 054/173] Update dependency pg to v8.11.4 (#29813)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 52 ++++++++++++++++++----------------------------------
 1 file changed, 18 insertions(+), 34 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index b4e20cf96..4c24f704c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5620,13 +5620,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"buffer-writer@npm:2.0.0":
-  version: 2.0.0
-  resolution: "buffer-writer@npm:2.0.0"
-  checksum: 10c0/c91b2ab09a200cf0862237e5a4dbd5077003b42d26d4f0c596ec7149f82ef83e0751d670bcdf379ed988d1a08c0fac7759a8cb928cf1a4710a1988a7618b1190
-  languageName: node
-  linkType: hard
-
 "buffer-xor@npm:^1.0.3":
   version: 1.0.3
   resolution: "buffer-xor@npm:1.0.3"
@@ -12594,13 +12587,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"packet-reader@npm:1.0.0":
-  version: 1.0.0
-  resolution: "packet-reader@npm:1.0.0"
-  checksum: 10c0/c86c3321bb07e0f03cc2db59f7701184e0bbfcb914f1fdc963993b03262486deb402292adcef39b64e3530ea66b3b2e2163d6da7b3792a730bdd1c6df3175aaa
-  languageName: node
-  linkType: hard
-
 "pako@npm:~1.0.5":
   version: 1.0.11
   resolution: "pako@npm:1.0.11"
@@ -12816,10 +12802,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.6.2":
-  version: 2.6.2
-  resolution: "pg-connection-string@npm:2.6.2"
-  checksum: 10c0/e8fdea74fcc8bdc3d7c5c6eadd9425fdba7e67fb7fe836f9c0cecad94c8984e435256657d1d8ce0483d1fedef667e7a57e32449a63cb805cb0289fc34b62da35
+"pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.6.3":
+  version: 2.6.3
+  resolution: "pg-connection-string@npm:2.6.3"
+  checksum: 10c0/e7eab3a2bb8dec5067fab8a46c90d8f7920946d46ad771a410de3929490c676ee91950424d4405295dd0fde5acbd39ccd99afd603a15d616d0a4a6fa9bf80ad7
   languageName: node
   linkType: hard
 
@@ -12837,19 +12823,19 @@ __metadata:
   languageName: node
   linkType: hard
 
-"pg-pool@npm:^3.6.1":
-  version: 3.6.1
-  resolution: "pg-pool@npm:3.6.1"
+"pg-pool@npm:^3.6.2":
+  version: 3.6.2
+  resolution: "pg-pool@npm:3.6.2"
   peerDependencies:
     pg: ">=8.0"
-  checksum: 10c0/47837c4e4c2b9e195cec01bd58b6e276acc915537191707ad4d6ed975fd9bc03c73f63cb7fde4cb0e08ed059e35faf60fbd03744dee3af71d4b4631ab40eeb7f
+  checksum: 10c0/14c524549490954b5e48457a4b808df8f619f6deeb3b395b0cd184a8f4ed65a9273fe0697ba0341a41d6745af197f1437eb1cf51fff0cbbf5b0fb3852ebe5392
   languageName: node
   linkType: hard
 
-"pg-protocol@npm:*, pg-protocol@npm:^1.6.0":
-  version: 1.6.0
-  resolution: "pg-protocol@npm:1.6.0"
-  checksum: 10c0/318a4d1e9cebd3927b10a8bc412f5017117a1f9a5fafb628d75847da7d1ab81c33250de58596bd0990029e14e92a995a851286d60fc236692299faf509572213
+"pg-protocol@npm:*, pg-protocol@npm:^1.6.1":
+  version: 1.6.1
+  resolution: "pg-protocol@npm:1.6.1"
+  checksum: 10c0/7eadef4010ac0a3925c460be7332ca4098a5c6d5181725a62193fcfa800000ae6632d98d814f3989b42cf5fdc3b45e34c714a1959d29174e81e30730e140ae5f
   languageName: node
   linkType: hard
 
@@ -12882,15 +12868,13 @@ __metadata:
   linkType: hard
 
 "pg@npm:^8.5.0":
-  version: 8.11.3
-  resolution: "pg@npm:8.11.3"
+  version: 8.11.4
+  resolution: "pg@npm:8.11.4"
   dependencies:
-    buffer-writer: "npm:2.0.0"
-    packet-reader: "npm:1.0.0"
     pg-cloudflare: "npm:^1.1.1"
-    pg-connection-string: "npm:^2.6.2"
-    pg-pool: "npm:^3.6.1"
-    pg-protocol: "npm:^1.6.0"
+    pg-connection-string: "npm:^2.6.3"
+    pg-pool: "npm:^3.6.2"
+    pg-protocol: "npm:^1.6.1"
     pg-types: "npm:^2.1.0"
     pgpass: "npm:1.x"
   peerDependencies:
@@ -12901,7 +12885,7 @@ __metadata:
   peerDependenciesMeta:
     pg-native:
       optional: true
-  checksum: 10c0/07e6967fc8bd5d72bab9be6620626e8e3ab59128ebf56bf0de83d67f10801a19221d88b3317e90b93339ba48d0498b39967b782ae39686aabda6bc647bceb438
+  checksum: 10c0/b3e473c52572be259a7418ee506a0ee9d66121971e73fe8cdf584addb9ef4d34cf66ea5c8a99ad9226c421d31a1848c39225bd201743ddd529276de1dec81e46
   languageName: node
   linkType: hard
 

From 961102338040e9d74bf24ce73e5dd7a0f43a2aaf Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 10:58:00 +0200
Subject: [PATCH 055/173] Update dependency postcss-preset-env to v9.5.3
 (#29816)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 276 +++++++++++++++++++++++++++---------------------------
 1 file changed, 138 insertions(+), 138 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 4c24f704c..877639d3a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1548,10 +1548,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/color-helpers@npm:^4.0.0":
-  version: 4.0.0
-  resolution: "@csstools/color-helpers@npm:4.0.0"
-  checksum: 10c0/fc78871253f8c92789ed64a0e5555bd2873c2b62a49c30baced88487561fe09fe897b0d16fcf7bf2a94f78ff37530773a4395ce5efc016810c094041b5bbcd42
+"@csstools/color-helpers@npm:^4.1.0":
+  version: 4.1.0
+  resolution: "@csstools/color-helpers@npm:4.1.0"
+  checksum: 10c0/0e41fd04dd28361717b161e7000c3a3b64b8b01119e93758297ea0b8a87c04121c3e3ef02e29c56fdd133227dd879163aa4b52e2370853d9fe64af6b6821668d
   languageName: node
   linkType: hard
 
@@ -1565,16 +1565,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/css-color-parser@npm:^1.6.2":
-  version: 1.6.2
-  resolution: "@csstools/css-color-parser@npm:1.6.2"
+"@csstools/css-color-parser@npm:^1.6.3":
+  version: 1.6.3
+  resolution: "@csstools/css-color-parser@npm:1.6.3"
   dependencies:
-    "@csstools/color-helpers": "npm:^4.0.0"
+    "@csstools/color-helpers": "npm:^4.1.0"
     "@csstools/css-calc": "npm:^1.2.0"
   peerDependencies:
     "@csstools/css-parser-algorithms": ^2.6.1
     "@csstools/css-tokenizer": ^2.2.4
-  checksum: 10c0/f587482fd7a40b6bd4cc790771245477d82203ba08f8f85981908680423476b9733c71fb4f1ba655f4dfb77907b4dfbb654dd7ba89e9edf0ba5229c26830ee8f
+  checksum: 10c0/3b15d9974105fe6e5d5e839953ee06153bc308bd62feacdeb88b7da7486ef1625254d0df908c68654596e477ca6be0c312d0c02a62d6dc4bddee61821be17d27
   languageName: node
   linkType: hard
 
@@ -1604,45 +1604,45 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-cascade-layers@npm:^4.0.3":
-  version: 4.0.3
-  resolution: "@csstools/postcss-cascade-layers@npm:4.0.3"
+"@csstools/postcss-cascade-layers@npm:^4.0.4":
+  version: 4.0.4
+  resolution: "@csstools/postcss-cascade-layers@npm:4.0.4"
   dependencies:
-    "@csstools/selector-specificity": "npm:^3.0.2"
+    "@csstools/selector-specificity": "npm:^3.0.3"
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/63f29af21eed000130f6f1268c00188a52eafbdeccc6acf5aa46507e499259631aa89f928b01b4698c41f3f68703db4c6e363c0e6f64b04b20c7e6452a5b259a
+  checksum: 10c0/87fdd1e3d846e45c2e415f24f66076e04c3c4539e8b802f1114b2a0fef9421d562d9eb61464ba3599d73805555ad8e95c51a8827cb3ddacfda01ec0df4afbfe0
   languageName: node
   linkType: hard
 
-"@csstools/postcss-color-function@npm:^3.0.12":
-  version: 3.0.12
-  resolution: "@csstools/postcss-color-function@npm:3.0.12"
+"@csstools/postcss-color-function@npm:^3.0.13":
+  version: 3.0.13
+  resolution: "@csstools/postcss-color-function@npm:3.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/a270aef93e98efb2b184b84a5de8acc28b10aed229807d1e5b5cf43309b281782895322ec98c0c9486b306ec68915e06689d6959c13ea2ab37fbb773ecd02335
+  checksum: 10c0/9d0fa25cd258653ad3227ccf1ee89dfee7099284c28b1d9ae7f7e8b15ed526e4e8cc7724f8e21cc073ed186891c3acb5b9c190a75e3c38d9c75e49197a824db6
   languageName: node
   linkType: hard
 
-"@csstools/postcss-color-mix-function@npm:^2.0.12":
-  version: 2.0.12
-  resolution: "@csstools/postcss-color-mix-function@npm:2.0.12"
+"@csstools/postcss-color-mix-function@npm:^2.0.13":
+  version: 2.0.13
+  resolution: "@csstools/postcss-color-mix-function@npm:2.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/42c7d48eeb1c1e49265505b560b9e034861254c62c5f78d89538255decab67d70f89bf81b269b208aa2103e9f48a51a33bb009eb17774f07c0459929d97f7056
+  checksum: 10c0/6011ce0b328cd3ee1d5720dc6eb23da807ba5a218a4a3c65a4844a82c0ff37e69d27cbee14abf9b928a3068f429ab86f2dd2bebab4ab64cd8fc7e39e562d7073
   languageName: node
   linkType: hard
 
@@ -1671,59 +1671,59 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-gamut-mapping@npm:^1.0.5":
-  version: 1.0.5
-  resolution: "@csstools/postcss-gamut-mapping@npm:1.0.5"
+"@csstools/postcss-gamut-mapping@npm:^1.0.6":
+  version: 1.0.6
+  resolution: "@csstools/postcss-gamut-mapping@npm:1.0.6"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/33e2185ae8f8a229476bd5a60c0523aef8cb4de552a6c532514b9d87bff579f36fb7640dd14c9ea56906996d43f4d5ab969a4f704e1b8a94f7802beb3df31d08
+  checksum: 10c0/a258a2ceac9d9be4374ec5b504895bd1de1196fe7d8c1377863a25c6cb50ee1fb1c65387c5440bae3c5d59e6ebf4e0c1990595c5cd09291224b31a1d23bdc250
   languageName: node
   linkType: hard
 
-"@csstools/postcss-gradients-interpolation-method@npm:^4.0.13":
-  version: 4.0.13
-  resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.13"
+"@csstools/postcss-gradients-interpolation-method@npm:^4.0.14":
+  version: 4.0.14
+  resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/af7c2d9c8e2249ea4cc50c9ef1b5ad75b1ed062020f1a8906ba9baf3143c4e2638b8b2189d7552838558e7b9a8a1ee9aa0baa076f5deabb23c1dc90fd78d7eab
+  checksum: 10c0/88147b2d7067b9bc6c90340c0be8450ca1175a7e927ff7b682c26d377237bec12f1cbe0dd930dd72dec661603348d1e71ca2a56f0a3b6fa2ca7d3f1b962f001d
   languageName: node
   linkType: hard
 
-"@csstools/postcss-hwb-function@npm:^3.0.11":
-  version: 3.0.11
-  resolution: "@csstools/postcss-hwb-function@npm:3.0.11"
+"@csstools/postcss-hwb-function@npm:^3.0.12":
+  version: 3.0.12
+  resolution: "@csstools/postcss-hwb-function@npm:3.0.12"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/d779617ef97ff22a125fbdd65f01dd3dd5bc607dbe7f3b02ae808d2fcccb1d5022b7f8e66e64283f7f9c52b6997bf0dc649566c734f0e3e4f3ba3c66a3b564a8
+  checksum: 10c0/20e0b2a4547fe619f38fe56c33974750d4a8b64a67a4169740ee0e67a9dec9f3a243f2370408901aacc35690aa36135028fafbbc866ff934b66cc4c9e4e89cac
   languageName: node
   linkType: hard
 
-"@csstools/postcss-ic-unit@npm:^3.0.5":
-  version: 3.0.5
-  resolution: "@csstools/postcss-ic-unit@npm:3.0.5"
+"@csstools/postcss-ic-unit@npm:^3.0.6":
+  version: 3.0.6
+  resolution: "@csstools/postcss-ic-unit@npm:3.0.6"
   dependencies:
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/bf21b74e1bdff425481724a36385f1ebe7c8aea6cccfcf6715cad58449d2d19419342e94d33d6626ec09bed8d4ab6e391b8eebaa3bda721e7f41e5c64c485f2a
+  checksum: 10c0/a4b962327d433419fdcfdcf620ce6a5cf09aa3c93029ad08b035df1e2bc35caae31de49f1d14218de0656fced35c0d2e07e5ff7b8099c29dbfb40395fc283234
   languageName: node
   linkType: hard
 
@@ -1736,29 +1736,29 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-is-pseudo-class@npm:^4.0.5":
-  version: 4.0.5
-  resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.5"
+"@csstools/postcss-is-pseudo-class@npm:^4.0.6":
+  version: 4.0.6
+  resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.6"
   dependencies:
-    "@csstools/selector-specificity": "npm:^3.0.2"
+    "@csstools/selector-specificity": "npm:^3.0.3"
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/5f35d5474957be30f54b89cf46b818390754af8094c4d9a083a79d579ccd817452bb7e2cfef8951c664d4c6ba381d8d45cd89f49339a42941f947ccb032f9d45
+  checksum: 10c0/aa071954e08dc9368fbeddbec6a8da2dea3a771b33bad53f67f3bc5a6b2f0a270909948f3e7b29ec885f4cceee245f16388809aeb0620284a1d66ad1f2026f28
   languageName: node
   linkType: hard
 
-"@csstools/postcss-light-dark-function@npm:^1.0.1":
-  version: 1.0.1
-  resolution: "@csstools/postcss-light-dark-function@npm:1.0.1"
+"@csstools/postcss-light-dark-function@npm:^1.0.2":
+  version: 1.0.2
+  resolution: "@csstools/postcss-light-dark-function@npm:1.0.2"
   dependencies:
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/538e809b473b91245cb79418949c4a27c0e82b0ea357f9c93b054e07d3194857e53979693226be9448904a7d9d4ad4732ad34183db82927bb172fe6cab1e53a8
+  checksum: 10c0/c7ed0037e68aa6ede2440a598caa776812e602e12f69d0fd8f0975cf3469a3593bd34fd408ed7d0b73af2ae4498bd6334cb3222fedb2a432a9ab8fa731e07108
   languageName: node
   linkType: hard
 
@@ -1862,44 +1862,44 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-oklab-function@npm:^3.0.12":
-  version: 3.0.12
-  resolution: "@csstools/postcss-oklab-function@npm:3.0.12"
+"@csstools/postcss-oklab-function@npm:^3.0.13":
+  version: 3.0.13
+  resolution: "@csstools/postcss-oklab-function@npm:3.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/1454f57c756bdc882a523b50634823a0c31d7adc35330e13c80f9573c287f2a4ab30bbce48e0e8788dfe5a293d55113db2205373523b202a8828b9088e55e51c
+  checksum: 10c0/26915f65ccc8b631a08542c4b088f9e5155f95a6c1f3a6bd2a33207f96d33438b930de60f493a5bbfee1b9f2abc8dfcab3ecbf20b5c7445d729fc434234fb046
   languageName: node
   linkType: hard
 
-"@csstools/postcss-progressive-custom-properties@npm:^3.1.1":
-  version: 3.1.1
-  resolution: "@csstools/postcss-progressive-custom-properties@npm:3.1.1"
+"@csstools/postcss-progressive-custom-properties@npm:^3.2.0":
+  version: 3.2.0
+  resolution: "@csstools/postcss-progressive-custom-properties@npm:3.2.0"
   dependencies:
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/9303296c8285a8154d2ee22d5a1330c94c5f361d277a1fd27172e868e3511619a6876538beacae0c9e925a9d1e81a32438d405526170faa84cad0c2d2159fdd2
+  checksum: 10c0/829880844fbbeef1c67e0b380057e574659b4caed38c8414c17d7eb4a0cc727afa1cd74a889bc7ca79c819ecae757810356706901cf6bb677a36ca123915cbb7
   languageName: node
   linkType: hard
 
-"@csstools/postcss-relative-color-syntax@npm:^2.0.12":
-  version: 2.0.12
-  resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.12"
+"@csstools/postcss-relative-color-syntax@npm:^2.0.13":
+  version: 2.0.13
+  resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/e12a59b89372fbc5cc460cfeceeea2ddc8b7a8f5639a767dbd6c7ff799bf740ac5dd7ae6797703f74efeadd696801042bff8770117cf5ed70646dcc598637334
+  checksum: 10c0/5c9fdec029e3d9a5c688d2e04995fec0cf6d91b48dbc5f450cf9c9dbb45e2819afbd63b3279676087a13f54914b0ec7d005e478b70b43e94fc8eeef9c5973390
   languageName: node
   linkType: hard
 
@@ -1927,15 +1927,15 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-text-decoration-shorthand@npm:^3.0.4":
-  version: 3.0.4
-  resolution: "@csstools/postcss-text-decoration-shorthand@npm:3.0.4"
+"@csstools/postcss-text-decoration-shorthand@npm:^3.0.5":
+  version: 3.0.5
+  resolution: "@csstools/postcss-text-decoration-shorthand@npm:3.0.5"
   dependencies:
-    "@csstools/color-helpers": "npm:^4.0.0"
+    "@csstools/color-helpers": "npm:^4.1.0"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/2e17535bbeed8ca5f095e6aecfb552004c1920597f16146fe6ec773b46af95f9e0e3cf77181d4216a23528de8e042bd85f82df1562447f52e7687ed8628f0adc
+  checksum: 10c0/e7e08c643c7084e60c0b22982e00ce21c579af3810ebbebac6838801b2ac622026ce96fd0cbca785613b1559f2337833cfc0f525685f8543ee39078a32fd7f89
   languageName: node
   linkType: hard
 
@@ -1970,12 +1970,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/selector-specificity@npm:^3.0.2":
-  version: 3.0.2
-  resolution: "@csstools/selector-specificity@npm:3.0.2"
+"@csstools/selector-specificity@npm:^3.0.2, @csstools/selector-specificity@npm:^3.0.3":
+  version: 3.0.3
+  resolution: "@csstools/selector-specificity@npm:3.0.3"
   peerDependencies:
     postcss-selector-parser: ^6.0.13
-  checksum: 10c0/d0c7dae2f1e9536e3e17f00467320a704f3208c76283c29c57fd69d4b83dcf6d062f492ed687c5ffd5f47fada9f0657c2efc89ea18fd4b038f757669553e0095
+  checksum: 10c0/e4f0355165882ddde8bd4a2f0252868150e67b9fae927fd2d94a91cee31e438e7041059f20b9c755a93b0bd8e527a9f78b01168fe67b3539be32091240aa63bf
   languageName: node
   linkType: hard
 
@@ -5045,7 +5045,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"autoprefixer@npm:^10.4.14, autoprefixer@npm:^10.4.18":
+"autoprefixer@npm:^10.4.14, autoprefixer@npm:^10.4.19":
   version: 10.4.19
   resolution: "autoprefixer@npm:10.4.19"
   dependencies:
@@ -6512,16 +6512,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"css-has-pseudo@npm:^6.0.2":
-  version: 6.0.2
-  resolution: "css-has-pseudo@npm:6.0.2"
+"css-has-pseudo@npm:^6.0.3":
+  version: 6.0.3
+  resolution: "css-has-pseudo@npm:6.0.3"
   dependencies:
-    "@csstools/selector-specificity": "npm:^3.0.2"
+    "@csstools/selector-specificity": "npm:^3.0.3"
     postcss-selector-parser: "npm:^6.0.13"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/96f9a6a4f31e11797e583d458535e11fa513b3f1f430ab566964a2f0792eaaa543213598b0a509516f07464234348ab11d56448b6d0c0c8a36988e0c86cf4ca1
+  checksum: 10c0/bbe663eff5256233c7bcce256cd8de7d93d82f2d4f2ca104af8e39e2159170d67746d3a2954385d03ec4ea7ef2728fe9a7d8cb62c52c0a6df1ad3d3bb1e3439d
   languageName: node
   linkType: hard
 
@@ -6647,10 +6647,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"cssdb@npm:^7.11.1":
-  version: 7.11.2
-  resolution: "cssdb@npm:7.11.2"
-  checksum: 10c0/5cd8dfee703dfbd7b7a8c3a93d65d26007ec1cd9692379b5868a0ceedf23b88e28d4b98f1cb9a4161f8b01e4a229e08ba9603fb94b756a3df6e07c423fff5b5d
+"cssdb@npm:^8.0.0":
+  version: 8.0.0
+  resolution: "cssdb@npm:8.0.0"
+  checksum: 10c0/d9a31b760214624352000b16a8f7194c357f66b6c445e663ab58dd03b6f0f53efaaca6d6f96200d666e205894d2d1c346664ad993d9522ff9fc1c331804a8d62
   languageName: node
   linkType: hard
 
@@ -13116,18 +13116,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-color-functional-notation@npm:^6.0.7":
-  version: 6.0.7
-  resolution: "postcss-color-functional-notation@npm:6.0.7"
+"postcss-color-functional-notation@npm:^6.0.8":
+  version: 6.0.8
+  resolution: "postcss-color-functional-notation@npm:6.0.8"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/bd3c1831e885f395205d503bf4b24f462dc9f4af74be11c5b0ad7b09eb150b2d3f8b2c727ab9e67c474ff05baa8e8e3c950880ffe2085ed39794d308c0297667
+  checksum: 10c0/ae2ff7769970fb403ea71d5613e041d97bb647cfc54e4a428bcc75f98ff06c888b064384df12b18f609bfcc4395c31d6db4ad2b9c9385a829ba594d2692c31d1
   languageName: node
   linkType: hard
 
@@ -13271,16 +13271,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-double-position-gradients@npm:^5.0.5":
-  version: 5.0.5
-  resolution: "postcss-double-position-gradients@npm:5.0.5"
+"postcss-double-position-gradients@npm:^5.0.6":
+  version: 5.0.6
+  resolution: "postcss-double-position-gradients@npm:5.0.6"
   dependencies:
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/02c22ca055ceca1ecc3c6888eab5c84769c9df37f59855f0ff9e9faaedcb4acf6818e927bff18bd57df161045f775ecca4142b13f968332419976c556a769995
+  checksum: 10c0/9b24b13043fe506c0ddd94e707fe4f21f4f9a6c05ca49a4f45e23412951fd6a4cfa0095002d10b322ca8be60df0badae3715a27eefdeb7bf8da4fdd1ecd5d7a2
   languageName: node
   linkType: hard
 
@@ -13336,18 +13336,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-lab-function@npm:^6.0.12":
-  version: 6.0.12
-  resolution: "postcss-lab-function@npm:6.0.12"
+"postcss-lab-function@npm:^6.0.13":
+  version: 6.0.13
+  resolution: "postcss-lab-function@npm:6.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.2"
+    "@csstools/css-color-parser": "npm:^1.6.3"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/1c96c19d0487346445749777df2af7cc828f3e3c4e8a435cac250d03c14efb0d14ee994ac58d966ed07f8f07aa297f0e3311248b78ba1e816bb18386e435a83c
+  checksum: 10c0/3ffb82d0012e49df49b44f38a131f4b13ba3edeeca5ecc0062c1c1b6bd8961c06f05b1dd8ec620c50c2c406fc61a505d79488745185d69ed325603600f0a1bc8
   languageName: node
   linkType: hard
 
@@ -13503,16 +13503,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-nesting@npm:^12.1.0":
-  version: 12.1.0
-  resolution: "postcss-nesting@npm:12.1.0"
+"postcss-nesting@npm:^12.1.1":
+  version: 12.1.1
+  resolution: "postcss-nesting@npm:12.1.1"
   dependencies:
     "@csstools/selector-resolve-nested": "npm:^1.1.0"
-    "@csstools/selector-specificity": "npm:^3.0.2"
+    "@csstools/selector-specificity": "npm:^3.0.3"
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/87902723214ec33a81520f51cce1e52f52c02272f2b7838d3aaa795e226104bf4809ef9dad8840f43852c1f229afb5f480ab1f20c7677bd021cf57739b625871
+  checksum: 10c0/8fac718e69ee2ac93179cc59810a8184581c04715fe34621ec5d504fc680cad4a11219ed0c918cbe15c468994c9aba88e729f35eef698c5d44cadd824425c47d
   languageName: node
   linkType: hard
 
@@ -13667,21 +13667,21 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.2
-  resolution: "postcss-preset-env@npm:9.5.2"
+  version: 9.5.3
+  resolution: "postcss-preset-env@npm:9.5.3"
   dependencies:
-    "@csstools/postcss-cascade-layers": "npm:^4.0.3"
-    "@csstools/postcss-color-function": "npm:^3.0.12"
-    "@csstools/postcss-color-mix-function": "npm:^2.0.12"
+    "@csstools/postcss-cascade-layers": "npm:^4.0.4"
+    "@csstools/postcss-color-function": "npm:^3.0.13"
+    "@csstools/postcss-color-mix-function": "npm:^2.0.13"
     "@csstools/postcss-exponential-functions": "npm:^1.0.5"
     "@csstools/postcss-font-format-keywords": "npm:^3.0.2"
-    "@csstools/postcss-gamut-mapping": "npm:^1.0.5"
-    "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.13"
-    "@csstools/postcss-hwb-function": "npm:^3.0.11"
-    "@csstools/postcss-ic-unit": "npm:^3.0.5"
+    "@csstools/postcss-gamut-mapping": "npm:^1.0.6"
+    "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.14"
+    "@csstools/postcss-hwb-function": "npm:^3.0.12"
+    "@csstools/postcss-ic-unit": "npm:^3.0.6"
     "@csstools/postcss-initial": "npm:^1.0.1"
-    "@csstools/postcss-is-pseudo-class": "npm:^4.0.5"
-    "@csstools/postcss-light-dark-function": "npm:^1.0.1"
+    "@csstools/postcss-is-pseudo-class": "npm:^4.0.6"
+    "@csstools/postcss-light-dark-function": "npm:^1.0.2"
     "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1"
     "@csstools/postcss-logical-overflow": "npm:^1.0.1"
     "@csstools/postcss-logical-overscroll-behavior": "npm:^1.0.1"
@@ -13691,38 +13691,38 @@ __metadata:
     "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^2.0.7"
     "@csstools/postcss-nested-calc": "npm:^3.0.2"
     "@csstools/postcss-normalize-display-values": "npm:^3.0.2"
-    "@csstools/postcss-oklab-function": "npm:^3.0.12"
-    "@csstools/postcss-progressive-custom-properties": "npm:^3.1.1"
-    "@csstools/postcss-relative-color-syntax": "npm:^2.0.12"
+    "@csstools/postcss-oklab-function": "npm:^3.0.13"
+    "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
+    "@csstools/postcss-relative-color-syntax": "npm:^2.0.13"
     "@csstools/postcss-scope-pseudo-class": "npm:^3.0.1"
     "@csstools/postcss-stepped-value-functions": "npm:^3.0.6"
-    "@csstools/postcss-text-decoration-shorthand": "npm:^3.0.4"
+    "@csstools/postcss-text-decoration-shorthand": "npm:^3.0.5"
     "@csstools/postcss-trigonometric-functions": "npm:^3.0.6"
     "@csstools/postcss-unset-value": "npm:^3.0.1"
-    autoprefixer: "npm:^10.4.18"
+    autoprefixer: "npm:^10.4.19"
     browserslist: "npm:^4.22.3"
     css-blank-pseudo: "npm:^6.0.1"
-    css-has-pseudo: "npm:^6.0.2"
+    css-has-pseudo: "npm:^6.0.3"
     css-prefers-color-scheme: "npm:^9.0.1"
-    cssdb: "npm:^7.11.1"
+    cssdb: "npm:^8.0.0"
     postcss-attribute-case-insensitive: "npm:^6.0.3"
     postcss-clamp: "npm:^4.1.0"
-    postcss-color-functional-notation: "npm:^6.0.7"
+    postcss-color-functional-notation: "npm:^6.0.8"
     postcss-color-hex-alpha: "npm:^9.0.4"
     postcss-color-rebeccapurple: "npm:^9.0.3"
     postcss-custom-media: "npm:^10.0.4"
     postcss-custom-properties: "npm:^13.3.6"
     postcss-custom-selectors: "npm:^7.1.8"
     postcss-dir-pseudo-class: "npm:^8.0.1"
-    postcss-double-position-gradients: "npm:^5.0.5"
+    postcss-double-position-gradients: "npm:^5.0.6"
     postcss-focus-visible: "npm:^9.0.1"
     postcss-focus-within: "npm:^8.0.1"
     postcss-font-variant: "npm:^5.0.0"
     postcss-gap-properties: "npm:^5.0.1"
     postcss-image-set-function: "npm:^6.0.3"
-    postcss-lab-function: "npm:^6.0.12"
+    postcss-lab-function: "npm:^6.0.13"
     postcss-logical: "npm:^7.0.1"
-    postcss-nesting: "npm:^12.1.0"
+    postcss-nesting: "npm:^12.1.1"
     postcss-opacity-percentage: "npm:^2.0.0"
     postcss-overflow-shorthand: "npm:^5.0.1"
     postcss-page-break: "npm:^3.0.4"
@@ -13732,7 +13732,7 @@ __metadata:
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/40f94472f2d940cbf1df9974bea29a76ada4c1285b97e7104c0cdf001fcafd0a1f5966822250df0d659ec0ea51e577a1ab78c9f5f8a5683ea9897efe043515c1
+  checksum: 10c0/0f6ed8ec9dc5365d1ca1d29652464f2cfebb6b39dfe39b55712c9251addde3289702ea37e1731da5b16bb70f2fb871d165bb0d33452506fa9121e5f696b63d34
   languageName: node
   linkType: hard
 

From b58666e12e2ca70ce4fa5b6b4fdb821333e4263e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 08:59:05 +0000
Subject: [PATCH 056/173] Update dependency @reduxjs/toolkit to v2.2.3 (#29817)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 877639d3a..4404b24a0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3012,8 +3012,8 @@ __metadata:
   linkType: hard
 
 "@reduxjs/toolkit@npm:^2.0.1":
-  version: 2.2.2
-  resolution: "@reduxjs/toolkit@npm:2.2.2"
+  version: 2.2.3
+  resolution: "@reduxjs/toolkit@npm:2.2.3"
   dependencies:
     immer: "npm:^10.0.3"
     redux: "npm:^5.0.1"
@@ -3027,7 +3027,7 @@ __metadata:
       optional: true
     react-redux:
       optional: true
-  checksum: 10c0/d749181b1bc071698517cba7ce05c42ddfe99363019249722b4dfa3afc71b3a6e4cb9885af574cf81c5d6515f68201ebfedddb5c14b262c941a45112fdc66ce3
+  checksum: 10c0/f10f2c8f4b6c5c7a65d8d60246bdfde86b6cd2f542210ebdda8002223c7f4e99ed32964825e63f37345d9d12532671150fcec2809a40690931ae44afe8aba7f8
   languageName: node
   linkType: hard
 

From 2f7a2d4df702c45022c3e0ea8c349abf4cc9680a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 10:59:26 +0200
Subject: [PATCH 057/173] Update DefinitelyTyped types (non-major) (#29818)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 4404b24a0..508111067 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3746,11 +3746,11 @@ __metadata:
   linkType: hard
 
 "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4":
-  version: 18.2.22
-  resolution: "@types/react-dom@npm:18.2.22"
+  version: 18.2.23
+  resolution: "@types/react-dom@npm:18.2.23"
   dependencies:
     "@types/react": "npm:*"
-  checksum: 10c0/cd85b5f402126e44b8c7b573e74737389816abcc931b2b14d8f946ba81cce8637ea490419488fcae842efb1e2f69853bc30522e43fd8359e1007d4d14b8d8146
+  checksum: 10c0/9348e93558aa67b4b237bd0eab62e72e85f3e17a1c45fde04d874476269730f7c671b3d62390c4fca588da2a026e90cc74148abc349dbfd4ee5535a82ccdf38e
   languageName: node
   linkType: hard
 
@@ -3849,13 +3849,12 @@ __metadata:
   linkType: hard
 
 "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
-  version: 18.2.70
-  resolution: "@types/react@npm:18.2.70"
+  version: 18.2.73
+  resolution: "@types/react@npm:18.2.73"
   dependencies:
     "@types/prop-types": "npm:*"
-    "@types/scheduler": "npm:*"
     csstype: "npm:^3.0.2"
-  checksum: 10c0/2107b1fa8963cabe33d981cf1c0e3b7534c9d12b98c1046cd9f7975851690a0780db011f6a1d637ae4e612ef00c94ebdbe76a9e2f9e0f3baa6aad3213932af41
+  checksum: 10c0/b6645ab3c20efa41cfccf58ce0be45419517a0ba4594e323dd400342fb1c1f9589d169cf9bfa85b5b0605e9097fe9de7734b6d0c533f5b9bc32aaadb624537a4
   languageName: node
   linkType: hard
 
@@ -3885,13 +3884,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/scheduler@npm:*":
-  version: 0.16.5
-  resolution: "@types/scheduler@npm:0.16.5"
-  checksum: 10c0/625b63cd5dcaf6fb88fe03aa7c797f28cb121f03584126d4811b2d03f39bc3e238ce52cf7685ad8adfe8445d679934e6be47347723a6771ca2058c01f0c33760
-  languageName: node
-  linkType: hard
-
 "@types/semver@npm:^7.5.0":
   version: 7.5.4
   resolution: "@types/semver@npm:7.5.4"

From a4158be4d7a8fb599c89cea1544a7e712e179c41 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 08:59:52 +0000
Subject: [PATCH 058/173] Update devDependencies (non-major) (#29819)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 508111067..e58a030c3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2199,16 +2199,16 @@ __metadata:
   linkType: hard
 
 "@formatjs/cli@npm:^6.1.1":
-  version: 6.2.8
-  resolution: "@formatjs/cli@npm:6.2.8"
+  version: 6.2.9
+  resolution: "@formatjs/cli@npm:6.2.9"
   peerDependencies:
-    vue: ^3.3.4
+    vue: ^3.4.0
   peerDependenciesMeta:
     vue:
       optional: true
   bin:
     formatjs: bin/formatjs
-  checksum: 10c0/5d8f95434f4522eee7dd3acf54e5265289ec7e72812448cd7c7547bdedaba8927719800dfa2fc92fb82c609f34255367a80d18bf6c064540d5e11ec6b9d4603e
+  checksum: 10c0/498383bcdca7f8f8a748c1151be17392f71eb1861f6a23bc714280533167cba7cdc35a470a380113f6111236e721ff43cbee7b084939dac67b6a5d9b04c0587c
   languageName: node
   linkType: hard
 
@@ -16418,8 +16418,8 @@ __metadata:
   linkType: hard
 
 "stylelint@npm:^16.0.2":
-  version: 16.3.0
-  resolution: "stylelint@npm:16.3.0"
+  version: 16.3.1
+  resolution: "stylelint@npm:16.3.1"
   dependencies:
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
@@ -16462,7 +16462,7 @@ __metadata:
     write-file-atomic: "npm:^5.0.1"
   bin:
     stylelint: bin/stylelint.mjs
-  checksum: 10c0/98bf770078d727eb7c3ec0932b09c9486481f2d086ea1f4232e00bd1bf58b6b5d3a8d6fc9802df05380cdb06b3d97c5a7c4f27adb221b2a5707ea9829c0ee350
+  checksum: 10c0/1660bb359002ff8e07cea044018b13abc73f48cf02a5062953b086f4d58611cd10677787560774c1acabeb192b6d059ce7fcf4c11defa7f64e50dca908fc664f
   languageName: node
   linkType: hard
 

From 143d9553fa0187b9950a802cdedaea5c8cd12f75 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 11:15:24 +0200
Subject: [PATCH 059/173] Update dependency fastimage to v2.3.1 (#29822)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 74dfd3684..bd15ad73a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -273,7 +273,7 @@ GEM
     faraday_middleware (1.2.0)
       faraday (~> 1.0)
     fast_blank (1.0.1)
-    fastimage (2.3.0)
+    fastimage (2.3.1)
     ffi (1.16.3)
     ffi-compiler (1.0.1)
       ffi (>= 1.0.0)

From fa9574086d1b2cc16a733cd60677054c67eed48d Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Tue, 2 Apr 2024 04:15:31 -0500
Subject: [PATCH 060/173] Fix search box color on light theme (#29808)

---
 app/javascript/styles/mastodon-light/diff.scss | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss
index 493e377d6..1de90e001 100644
--- a/app/javascript/styles/mastodon-light/diff.scss
+++ b/app/javascript/styles/mastodon-light/diff.scss
@@ -80,6 +80,7 @@ html {
 }
 
 .search__input,
+.search__popout,
 .setting-text,
 .report-dialog-modal__textarea,
 .audio-player {
@@ -439,7 +440,8 @@ html {
 .directory__tag > div,
 .card > a,
 .page-header,
-.compose-form .compose-form__warning {
+.compose-form,
+.compose-form__warning {
   box-shadow: none;
 }
 
@@ -475,12 +477,17 @@ html {
   color: $white;
 }
 
-.compose-form .spoiler-input__input {
+.compose-form,
+.spoiler-input__input,
+.search__input,
+.search__popout {
   color: lighten($ui-highlight-color, 8%);
 }
 
 .compose-form .autosuggest-textarea__textarea,
 .compose-form__highlightable,
+.search__input,
+.search__popout,
 .poll__option input[type='text'] {
   background: darken($ui-base-color, 10%);
 }

From c717747603d759c01d638b99146add55d4aa1561 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 11:26:06 +0200
Subject: [PATCH 061/173] New Crowdin Translations (automated) (#29812)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/et.json    |  39 +++++
 app/javascript/mastodon/locales/ia.json    | 168 ++++++++++++---------
 app/javascript/mastodon/locales/ie.json    |  41 +++++
 app/javascript/mastodon/locales/it.json    |  20 +--
 app/javascript/mastodon/locales/ja.json    |  13 ++
 app/javascript/mastodon/locales/lad.json   |   3 +
 app/javascript/mastodon/locales/ru.json    |  58 +++++++
 app/javascript/mastodon/locales/sv.json    |  16 ++
 app/javascript/mastodon/locales/zh-TW.json |   2 +-
 config/locales/activerecord.ia.yml         |   6 +
 config/locales/devise.de.yml               |   4 +-
 config/locales/es-MX.yml                   |   2 +-
 config/locales/et.yml                      |  20 +++
 config/locales/ia.yml                      |  13 ++
 config/locales/ie.yml                      |  16 ++
 config/locales/it.yml                      |   2 +-
 config/locales/lad.yml                     |   4 +
 config/locales/simple_form.et.yml          |   2 +
 config/locales/simple_form.ia.yml          |   7 +
 config/locales/simple_form.ie.yml          |   2 +
 20 files changed, 355 insertions(+), 83 deletions(-)

diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index f617ced6e..74f3f560d 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -92,7 +92,11 @@
   "block_modal.remote_users_caveat": "Serverile {domain} edastatakse palve otsust järgida. Ometi pole see tagatud, kuna mõned serverid võivad blokeeringuid käsitleda omal moel. Avalikud postitused võivad tuvastamata kasutajatele endiselt näha olla.",
   "block_modal.show_less": "Kuva vähem",
   "block_modal.show_more": "Kuva rohkem",
+  "block_modal.they_cant_mention": "Ta ei saa mainida sind ega jälgida.",
+  "block_modal.they_cant_see_posts": "Ta ei näe sinu postitusi ja sa ei näe tema omi.",
+  "block_modal.they_will_know": "Ta näeb, et ta on blokeeritud.",
   "block_modal.title": "Blokeeri kasutaja?",
+  "block_modal.you_wont_see_mentions": "Sa ei näe postitusi, mis mainivad teda.",
   "boost_modal.combo": "Vajutades {combo}, saab selle edaspidi vahele jätta",
   "bundle_column_error.copy_stacktrace": "Kopeeri veateade",
   "bundle_column_error.error.body": "Soovitud lehte ei õnnestunud esitada. See võib olla meie koodiviga või probleem brauseri ühilduvusega.",
@@ -206,8 +210,26 @@
   "dismissable_banner.explore_tags": "Need sildid siit ja teistes serveritest detsentraliseeritud võrgus koguvad tähelepanu just praegu selles serveris.",
   "dismissable_banner.public_timeline": "Need on kõige uuemad avalikud postitused inimestelt sotsiaalvõrgustikus, mida {domain} inimesed jälgivad.",
   "domain_block_modal.block": "Blokeeri server",
+  "domain_block_modal.block_account_instead": "Selle asemel blokeeri @{name}",
+  "domain_block_modal.they_can_interact_with_old_posts": "Inimesed sellest serverist saavad interakteeruda sinu vanade postitustega.",
+  "domain_block_modal.they_cant_follow": "Sellest serverist ei saa keegi sind jälgida.",
+  "domain_block_modal.they_wont_know": "Nad ei tea, et nad on blokeeritud.",
+  "domain_block_modal.title": "Blokeerida domeen?",
+  "domain_block_modal.you_will_lose_followers": "Kõik sinu sellest serverist pärit jälgijad eemaldatakse.",
+  "domain_block_modal.you_wont_see_posts": "Sa ei näe selle serveri kasutajate postitusi ega teavitusi.",
+  "domain_pill.activitypub_lets_connect": "See võimaldab sul ühenduda inimestega ja nendega suhelda mitte ainult Mastodonis, vaid ka teistes suhtlusrakendustes.",
+  "domain_pill.activitypub_like_language": "ActivityPub on nagu keel, mida Mastodon räägib teiste suhtlusvõrgustikega.",
   "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Tema tunnus:",
+  "domain_pill.their_server": "Tema digitaalne kodu, kus kõik tema postitused on.",
+  "domain_pill.their_username": "Tema unikaalne tunnus tema serveris. On võimalik, et mingites teistes serverites on sama kasutajanimega kasutajaid.",
   "domain_pill.username": "Kasutajanimi",
+  "domain_pill.whats_in_a_handle": "Mis on tunnuses?",
+  "domain_pill.who_they_are": "Kuna tunnus ütleb, kes keegi on ja kus, saad suhelda inimestega üle <button>ActivityPub-poolt toetatud sotsiaalvõrkude platvormide</button>.",
+  "domain_pill.who_you_are": "Kuna tunnus ütleb, kes sa oled ja kus, saavad inimesed sinuga suhelda üle <button>ActivityPub-poolt toetatud sotsiaalvõrkude platvormide</button>.",
+  "domain_pill.your_handle": "Sinu tunnus:",
+  "domain_pill.your_server": "Sinu digitaalne kodu, kus on kõik sinu postitused. Sulle ei meeldi see? Vaheta mistahes ajal serverit ja võta jälgijad ka.",
+  "domain_pill.your_username": "Sinu unikaalne identifikaator siin serveris. On võimalik, et leiad teistes serverites samasuguse kasutajanimega kasutajaid.",
   "embed.instructions": "Lisa see postitus oma veebilehele, kopeerides alloleva koodi.",
   "embed.preview": "Nii näeb see välja:",
   "emoji_button.activity": "Tegevus",
@@ -244,6 +266,7 @@
   "empty_column.list": "Siin loetelus pole veel midagi. Kui loetelu liikmed teevad uusi postitusi, näed neid siin.",
   "empty_column.lists": "Pole veel ühtegi nimekirja. Kui lood mõne, näed neid siin.",
   "empty_column.mutes": "Sa pole veel ühtegi kasutajat vaigistanud.",
+  "empty_column.notification_requests": "Kõik tühi! Siin pole mitte midagi. Kui saad uusi teavitusi, ilmuvad need siin vastavalt sinu seadistustele.",
   "empty_column.notifications": "Ei ole veel teateid. Kui keegi suhtleb sinuga, näed seda siin.",
   "empty_column.public": "Siin pole midagi! Kirjuta midagi avalikku või jälgi ise kasutajaid täitmaks seda ruumi",
   "error.unexpected_crash.explanation": "Meie poolse probleemi või veebilehitseja ühilduvusprobleemi tõttu ei suutnud me seda lehekülge korrektselt näidata.",
@@ -275,6 +298,8 @@
   "filter_modal.select_filter.title": "Filtreeri seda postitust",
   "filter_modal.title.status": "Postituse filtreerimine",
   "filtered_notifications_banner.pending_requests": "Teateid {count, plural, =0 {mitte üheltki} one {ühelt} other {#}} inimeselt, keda võid teada",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privaatne teavitus} other {privaatsed teavitused}}",
+  "filtered_notifications_banner.title": "Filtreeritud teavitused",
   "firehose.all": "Kõik",
   "firehose.local": "See server",
   "firehose.remote": "Teised serverid",
@@ -403,8 +428,15 @@
   "loading_indicator.label": "Laadimine…",
   "media_gallery.toggle_visible": "{number, plural, one {Varja pilt} other {Varja pildid}}",
   "moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Peida teavituste hulgast",
   "mute_modal.hide_options": "Peida valikud",
+  "mute_modal.indefinite": "Kuni eemaldan neilt vaigistuse",
   "mute_modal.show_options": "Kuva valikud",
+  "mute_modal.they_can_mention_and_follow": "Ta saab sind mainida ja sind jälgida, kuid sa ei näe teda.",
+  "mute_modal.they_wont_know": "Ta ei tea, et ta on vaigistatud.",
+  "mute_modal.title": "Vaigistada kasutaja?",
+  "mute_modal.you_wont_see_mentions": "Sa ei näe postitusi, mis teda mainivad.",
+  "mute_modal.you_wont_see_posts": "Ta näeb jätkuvalt sinu postitusi, kuid sa ei näe tema omi.",
   "navigation_bar.about": "Teave",
   "navigation_bar.advanced_interface": "Ava kohandatud veebiliides",
   "navigation_bar.blocks": "Blokeeritud kasutajad",
@@ -440,6 +472,10 @@
   "notification.own_poll": "Su küsitlus on lõppenud",
   "notification.poll": "Küsitlus, milles osalesid, on lõppenud",
   "notification.reblog": "{name} jagas edasi postitust",
+  "notification.relationships_severance_event": "Kadunud ühendus kasutajaga {name}",
+  "notification.relationships_severance_event.account_suspension": "{from} admin on kustutanud {target}, mis tähendab, et sa ei saa enam neilt uuendusi või suhelda nendega.",
+  "notification.relationships_severance_event.domain_block": "{from} admin on blokeerinud {target}, sealhulgas {followersCount} sinu jälgijat ja {followingCount, plural, one  {# konto} other {# kontot}}, mida jälgid.",
+  "notification.relationships_severance_event.learn_more": "Saa rohkem teada",
   "notification.status": "{name} just postitas",
   "notification.update": "{name} muutis postitust",
   "notification_requests.accept": "Nõus",
@@ -450,6 +486,8 @@
   "notifications.column_settings.admin.sign_up": "Uued kasutajad:",
   "notifications.column_settings.alert": "Töölauateated",
   "notifications.column_settings.favourite": "Lemmikud:",
+  "notifications.column_settings.filter_bar.advanced": "Näita kõiki kategooriaid",
+  "notifications.column_settings.filter_bar.category": "Kiirfiltri riba",
   "notifications.column_settings.follow": "Uued jälgijad:",
   "notifications.column_settings.follow_request": "Uued jälgimistaotlused:",
   "notifications.column_settings.mention": "Mainimised:",
@@ -475,6 +513,7 @@
   "notifications.permission_denied": "Töölauamärguanded pole saadaval, kuna eelnevalt keelduti lehitsejale teavituste luba andmast",
   "notifications.permission_denied_alert": "Töölaua märguandeid ei saa lubada, kuna brauseri luba on varem keeldutud",
   "notifications.permission_required": "Töölaua märguanded ei ole saadaval, kuna vajalik luba pole antud.",
+  "notifications.policy.filter_new_accounts.hint": "Loodud viimase {days, plural, one {ühe päeva} other {# päeva}} jooksul",
   "notifications.policy.filter_new_accounts_title": "Uued kontod",
   "notifications_permission_banner.enable": "Luba töölaua märguanded",
   "notifications_permission_banner.how_to_control": "Et saada teateid, ajal mil Mastodon pole avatud, luba töölauamärguanded. Saad täpselt määrata, mis tüüpi tegevused tekitavad märguandeid, kasutates peale teadaannete sisse lülitamist üleval olevat nuppu {icon}.",
diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index e587dbc52..d982381c4 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -3,15 +3,15 @@
   "about.contact": "Contacto:",
   "about.disclaimer": "Mastodon es software libere, de codice aperte, e un marca de Mastodon gGmbH.",
   "about.domain_blocks.no_reason_available": "Ration non disponibile",
-  "about.domain_blocks.preamble": "Mastodon generalmente permitte vider contento ab e interacter con usatores ab ulle altere servitor in le fediverso. Iste es le exceptiones que ha essite facite in iste servitor particular.",
-  "about.domain_blocks.silenced.explanation": "Generalmente non videras perfiles e contento de iste servitor, a minus que tu expressemente lo cerca o opta pro lo per sequer.",
+  "about.domain_blocks.preamble": "Mastodon generalmente permitte vider le contento de, e interager con, usatores de qualcunque altere servitor in le fediverso. Istes es le exceptiones que ha essite facite sur iste servitor particular.",
+  "about.domain_blocks.silenced.explanation": "Generalmente, tu non videra le profilos e le contento de iste servitor, excepte si tu expressemente cerca le contento o seque le profilos.",
   "about.domain_blocks.silenced.title": "Limitate",
-  "about.domain_blocks.suspended.explanation": "Nulle data de iste servitor essera processate, immagazinate o scambiate, faciente qualcunque interaction o communication con usatores de iste servitor impossibile.",
+  "about.domain_blocks.suspended.explanation": "Nulle datos de iste servitor essera processate, immagazinate o excambiate, rendente omne interaction o communication con usatores de iste servitor impossibile.",
   "about.domain_blocks.suspended.title": "Suspendite",
-  "about.not_available": "Iste information non faceva disponibile in iste servitor.",
+  "about.not_available": "Iste information non ha essite rendite disponibile sur iste servitor.",
   "about.rules": "Regulas del servitor",
   "account.account_note_header": "Nota",
-  "account.add_or_remove_from_list": "Adder o remover ab listas",
+  "account.add_or_remove_from_list": "Adder a, o remover de listas",
   "account.badges.group": "Gruppo",
   "account.block": "Blocar @{name}",
   "account.block_domain": "Blocar dominio {domain}",
@@ -19,31 +19,31 @@
   "account.blocked": "Blocate",
   "account.browse_more_on_origin_server": "Navigar plus sur le profilo original",
   "account.copy": "Copiar ligamine a profilo",
-  "account.direct": "Mentionar privatemente a @{name}",
-  "account.disable_notifications": "Stoppar le notificationes quando @{name} publica",
+  "account.direct": "Mentionar privatemente @{name}",
+  "account.disable_notifications": "Non plus notificar me quando @{name} publica",
   "account.domain_blocked": "Dominio blocate",
   "account.edit_profile": "Modificar profilo",
-  "account.enable_notifications": "Notifica me quando @{name} publica",
+  "account.enable_notifications": "Notificar me quando @{name} publica",
   "account.endorse": "Evidentiar sur le profilo",
-  "account.featured_tags.last_status_at": "Ultime message in {date}",
+  "account.featured_tags.last_status_at": "Ultime message publicate le {date}",
   "account.featured_tags.last_status_never": "Necun messages",
   "account.featured_tags.title": "Hashtags eminente de {name}",
   "account.follow": "Sequer",
-  "account.follow_back": "Sequer etiam",
+  "account.follow_back": "Sequer in retorno",
   "account.followers": "Sequitores",
-  "account.followers.empty": "Iste usator ancora non ha sequitores.",
+  "account.followers.empty": "Necuno seque ancora iste usator.",
   "account.followers_counter": "{count, plural, one {{counter} sequitor} other {{counter} sequitores}}",
   "account.following": "Sequente",
-  "account.follows.empty": "Iste usator ancora non seque nemo.",
+  "account.follows.empty": "Iste usator non seque ancora alcuno.",
   "account.go_to_profile": "Vader al profilo",
   "account.hide_reblogs": "Celar boosts de @{name}",
-  "account.in_memoriam": "In Memoriam.",
+  "account.in_memoriam": "In memoriam.",
   "account.languages": "Cambiar le linguas subscribite",
-  "account.link_verified_on": "Le proprietate de iste ligamine esseva verificate le {date}",
-  "account.locked_info": "Le stato de confidentialitate de iste conto es definite a blocate. Le proprietario revisa manualmente qui pote sequer lo.",
+  "account.link_verified_on": "Le proprietate de iste ligamine ha essite verificate le {date}",
+  "account.locked_info": "Le stato de confidentialitate de iste conto es definite como serrate. Le proprietario determina manualmente qui pote sequer le.",
   "account.media": "Multimedia",
   "account.mention": "Mentionar @{name}",
-  "account.moved_to": "{name} indicava que lor nove conto ora es:",
+  "account.moved_to": "{name} ha indicate que su nove conto ora es:",
   "account.mute": "Silentiar @{name}",
   "account.mute_notifications_short": "Silentiar le notificationes",
   "account.mute_short": "Silentiar",
@@ -53,9 +53,9 @@
   "account.posts": "Messages",
   "account.posts_with_replies": "Messages e responsas",
   "account.requested": "Attendente le approbation. Clicca pro cancellar le requesta de sequer",
-  "account.requested_follow": "{name} habeva requestate sequer te",
+  "account.requested_follow": "{name} ha requestate de sequer te",
   "account.share": "Compartir profilo de @{name}",
-  "account.show_reblogs": "Monstrar responsas de @{name}",
+  "account.show_reblogs": "Monstrar impulsos de @{name}",
   "account.statuses_counter": "{count, plural, one {{counter} message} other {{counter} messages}}",
   "account.unblock": "Disblocar @{name}",
   "account.unblock_domain": "Disblocar dominio {domain}",
@@ -66,23 +66,26 @@
   "account.unmute_notifications_short": "Non plus silentiar le notificationes",
   "account.unmute_short": "Non plus silentiar",
   "account_note.placeholder": "Clicca pro adder un nota",
-  "admin.dashboard.retention.average": "Median",
+  "admin.dashboard.retention.average": "Media",
   "admin.dashboard.retention.cohort_size": "Nove usatores",
-  "admin.impact_report.instance_followers": "Sequitores que nostre usatores poterea perder",
-  "admin.impact_report.instance_follows": "Sequitores que lor usatores poterea perder",
-  "alert.rate_limited.message": "Retenta depost {retry_time, time, medium}.",
-  "alert.unexpected.message": "Ocurreva un error inexpectate.",
+  "admin.impact_report.instance_followers": "Sequitores que nostre usatores perderea",
+  "admin.impact_report.instance_follows": "Sequitores que lor usatores perderea",
+  "alert.rate_limited.message": "Per favor retenta post {retry_time, time, medium}.",
+  "alert.unexpected.message": "Un error inexpectate ha occurrite.",
   "announcement.announcement": "Annuncio",
   "audio.hide": "Celar audio",
-  "bundle_column_error.error.title": "Oh, non!",
+  "block_modal.show_less": "Monstrar minus",
+  "block_modal.show_more": "Monstrar plus",
+  "block_modal.title": "Blocar usator?",
+  "bundle_column_error.error.title": "Oh, no!",
   "bundle_column_error.network.title": "Error de rete",
   "bundle_column_error.retry": "Tentar novemente",
   "bundle_column_error.return": "Retornar al initio",
   "bundle_modal_error.close": "Clauder",
   "bundle_modal_error.retry": "Tentar novemente",
-  "closed_registrations_modal.description": "Crear un conto in {domain} actualmente non es possibile, ma considera que tu non besonia un conto specific in {domain} pro usar Mastodon.",
-  "closed_registrations_modal.find_another_server": "Trovar altere servitor",
-  "column.about": "A proposito de",
+  "closed_registrations_modal.description": "Crear un conto in {domain} actualmente non es possibile, ma considera que non es necessari haber un conto specificamente sur {domain} pro usar Mastodon.",
+  "closed_registrations_modal.find_another_server": "Cercar un altere servitor",
+  "column.about": "A proposito",
   "column.blocks": "Usatores blocate",
   "column.bookmarks": "Marcapaginas",
   "column.community": "Chronologia local",
@@ -90,7 +93,7 @@
   "column.directory": "Navigar profilos",
   "column.domain_blocks": "Dominios blocate",
   "column.favourites": "Favoritos",
-  "column.firehose": "Fluxos in directe",
+  "column.firehose": "Fluxos in directo",
   "column.home": "Initio",
   "column.lists": "Listas",
   "column.mutes": "Usatores silentiate",
@@ -103,7 +106,7 @@
   "column_header.show_settings": "Monstrar le parametros",
   "column_subheading.settings": "Parametros",
   "community.column_settings.local_only": "Solmente local",
-  "community.column_settings.media_only": "Solmente medios",
+  "community.column_settings.media_only": "Solmente multimedia",
   "compose.language.change": "Cambiar le lingua",
   "compose.language.search": "Cercar linguas...",
   "compose.published.body": "Message publicate.",
@@ -111,14 +114,14 @@
   "compose.saved.body": "Message salvate.",
   "compose_form.direct_message_warning_learn_more": "Apprender plus",
   "compose_form.lock_disclaimer": "Tu conto non es {locked}. Quicunque pote sequer te pro vider tu messages solo pro sequitores.",
-  "compose_form.lock_disclaimer.lock": "blocate",
-  "compose_form.poll.duration": "Duration del inquesta",
+  "compose_form.lock_disclaimer.lock": "serrate",
+  "compose_form.poll.duration": "Durata del sondage",
   "compose_form.poll.multiple": "Selection multiple",
   "compose_form.poll.option_placeholder": "Option {number}",
   "compose_form.poll.single": "Seliger un",
-  "compose_form.poll.switch_to_multiple": "Cambiar inquesta pro permitter selectiones multiple",
-  "compose_form.poll.switch_to_single": "Cambiar inquesta pro permitter selection singule",
-  "compose_form.poll.type": "Stylo",
+  "compose_form.poll.switch_to_multiple": "Cambiar le sondage pro permitter selectiones multiple",
+  "compose_form.poll.switch_to_single": "Cambiar le sondage pro permitter selection singule",
+  "compose_form.poll.type": "Stilo",
   "compose_form.publish": "Publicar",
   "compose_form.publish_form": "Nove message",
   "compose_form.reply": "Responder",
@@ -129,18 +132,19 @@
   "confirmation_modal.cancel": "Cancellar",
   "confirmations.block.confirm": "Blocar",
   "confirmations.cancel_follow_request.confirm": "Retirar requesta",
-  "confirmations.cancel_follow_request.message": "Es tu secur que tu vole retirar tu requesta a sequer a {name}?",
+  "confirmations.cancel_follow_request.message": "Es tu secur que tu vole retirar tu requesta de sequer {name}?",
   "confirmations.delete.confirm": "Deler",
   "confirmations.delete.message": "Es tu secur que tu vole deler iste message?",
   "confirmations.delete_list.confirm": "Deler",
   "confirmations.delete_list.message": "Es tu secur que tu vole deler permanentemente iste lista?",
+  "confirmations.domain_block.confirm": "Blocar le servitor",
   "confirmations.edit.confirm": "Modificar",
-  "confirmations.logout.confirm": "Clauder le session",
+  "confirmations.logout.confirm": "Clauder session",
   "confirmations.logout.message": "Es tu secur que tu vole clauder le session?",
   "confirmations.mute.confirm": "Silentiar",
   "confirmations.reply.confirm": "Responder",
   "confirmations.unfollow.confirm": "Non plus sequer",
-  "confirmations.unfollow.message": "Es tu secur que tu vole non plus sequer {name}?",
+  "confirmations.unfollow.message": "Es tu secur que tu vole cessar de sequer {name}?",
   "conversation.delete": "Deler conversation",
   "conversation.mark_as_read": "Marcar como legite",
   "conversation.open": "Vider conversation",
@@ -155,8 +159,11 @@
   "disabled_account_banner.account_settings": "Parametros de conto",
   "disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.",
   "dismissable_banner.dismiss": "Dimitter",
+  "domain_block_modal.title": "Blocar dominio?",
+  "domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.",
+  "domain_pill.server": "Servitor",
   "domain_pill.username": "Nomine de usator",
-  "embed.preview": "Hic es como il parera:",
+  "embed.preview": "Ecce como illlo parera:",
   "emoji_button.activity": "Activitate",
   "emoji_button.clear": "Rader",
   "emoji_button.custom": "Personalisate",
@@ -170,16 +177,16 @@
   "emoji_button.search_results": "Resultatos de recerca",
   "emoji_button.symbols": "Symbolos",
   "emoji_button.travel": "Viages e locos",
-  "empty_column.account_hides_collections": "Le usator ha seligite non facer iste information disponibile",
+  "empty_column.account_hides_collections": "Le usator non ha rendite iste information disponibile",
   "empty_column.account_suspended": "Conto suspendite",
   "empty_column.account_timeline": "Nulle messages hic!",
   "empty_column.account_unavailable": "Profilo non disponibile",
   "empty_column.blocks": "Tu non ha blocate alcun usator ancora.",
   "empty_column.domain_blocks": "Il non ha dominios blocate ancora.",
-  "empty_column.explore_statuses": "Nihil es in tendentias ora mesme. Retorna postea!",
-  "empty_column.favourited_statuses": "Tu non ha necun messages favorite ancora. Quando tu marca un como favorito, ille essera monstrate hic.",
-  "empty_column.followed_tags": "Tu ancora non ha sequite necun hashtags. Quando tu lo face, illes essera monstrate hic.",
-  "empty_column.hashtag": "Ancora non il ha nihil in iste hashtag.",
+  "empty_column.explore_statuses": "Il non ha tendentias in iste momento. Reveni plus tarde!",
+  "empty_column.favourited_statuses": "Tu non ha alcun message favorite ancora. Quando tu marca un message como favorite, illo apparera hic.",
+  "empty_column.followed_tags": "Tu non ha ancora sequite alcun hashtags. Quando tu lo face, illos apparera hic.",
+  "empty_column.hashtag": "Il non ha ancora alcun cosa in iste hashtag.",
   "errors.unexpected_crash.report_issue": "Signalar un defecto",
   "explore.search_results": "Resultatos de recerca",
   "explore.suggested_follows": "Personas",
@@ -189,7 +196,7 @@
   "explore.trending_tags": "Hashtags",
   "filter_modal.added.review_and_configure_title": "Parametros de filtro",
   "filter_modal.added.settings_link": "pagina de parametros",
-  "filter_modal.added.short_explanation": "Iste message esseva addite al sequente categoria de filtros: {title}.",
+  "filter_modal.added.short_explanation": "Iste message ha essite addite al sequente categoria de filtros: {title}.",
   "filter_modal.added.title": "Filtro addite!",
   "filter_modal.select_filter.prompt_new": "Nove categoria: {name}",
   "filter_modal.select_filter.search": "Cercar o crear",
@@ -203,9 +210,9 @@
   "follow_suggestions.personalized_suggestion": "Suggestion personalisate",
   "follow_suggestions.popular_suggestion": "Suggestion personalisate",
   "follow_suggestions.view_all": "Vider toto",
-  "footer.about": "A proposito de",
+  "footer.about": "A proposito",
   "footer.directory": "Directorio de profilos",
-  "footer.get_app": "Obtene le application",
+  "footer.get_app": "Obtener le application",
   "footer.invite": "Invitar personas",
   "footer.keyboard_shortcuts": "Accessos directe de claviero",
   "footer.privacy_policy": "Politica de confidentialitate",
@@ -221,24 +228,25 @@
   "hashtag.follow": "Sequer hashtag",
   "hashtag.unfollow": "Non sequer plus le hashtag",
   "hashtags.and_other": "…e {count, plural, one {}other {# plus}}",
-  "home.column_settings.show_reblogs": "Monstrar boosts",
+  "home.column_settings.show_reblogs": "Monstrar impulsos",
   "home.column_settings.show_replies": "Monstrar responsas",
   "home.hide_announcements": "Celar annuncios",
   "home.pending_critical_update.body": "Actualisa tu servitor de Mastodon le plus tosto possibile!",
   "home.pending_critical_update.link": "Vider actualisationes",
   "home.pending_critical_update.title": "Actualisation de securitate critic disponibile!",
   "home.show_announcements": "Monstrar annuncios",
-  "interaction_modal.login.prompt": "Dominio de tu servitor, p.e. mastodon.social",
+  "interaction_modal.login.prompt": "Dominio de tu servitor, p.ex. mastodon.social",
   "interaction_modal.no_account_yet": "Non sur Mstodon?",
-  "interaction_modal.on_another_server": "In un servitor differente",
-  "interaction_modal.on_this_server": "In iste servitor",
+  "interaction_modal.on_another_server": "Sur un altere servitor",
+  "interaction_modal.on_this_server": "Sur iste servitor",
   "interaction_modal.title.follow": "Sequer {name}",
-  "interaction_modal.title.reblog": "Facer boost al message de {name}",
+  "interaction_modal.title.reblog": "Impulsar le message de {name}",
   "interaction_modal.title.reply": "Responder al message de {name}",
   "keyboard_shortcuts.blocked": "Aperir lista de usatores blocate",
-  "keyboard_shortcuts.boost": "Facer boost al message",
+  "keyboard_shortcuts.boost": "Impulsar le message",
   "keyboard_shortcuts.description": "Description",
   "keyboard_shortcuts.enter": "Aperir message",
+  "keyboard_shortcuts.favourite": "Message favorite",
   "keyboard_shortcuts.favourites": "Aperir lista de favoritos",
   "keyboard_shortcuts.federated": "Aperir le chronologia federate",
   "keyboard_shortcuts.heading": "Accessos directe de claviero",
@@ -247,22 +255,22 @@
   "keyboard_shortcuts.muted": "Aperir lista de usatores silentiate",
   "keyboard_shortcuts.my_profile": "Aperir tu profilo",
   "keyboard_shortcuts.notifications": "Aperir columna de notificationes",
-  "keyboard_shortcuts.open_media": "Aperir medio",
+  "keyboard_shortcuts.open_media": "Aperir multimedia",
   "keyboard_shortcuts.profile": "Aperir le profilo del autor",
   "keyboard_shortcuts.reply": "Responder al message",
   "keyboard_shortcuts.spoilers": "Monstrar/celar le campo CW",
-  "keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar medios",
+  "keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar multimedia",
   "keyboard_shortcuts.toot": "Initiar un nove message",
   "lightbox.close": "Clauder",
   "lightbox.next": "Sequente",
   "lightbox.previous": "Precedente",
   "link_preview.author": "Per {name}",
   "lists.account.add": "Adder al lista",
-  "lists.account.remove": "Remover ab le lista",
+  "lists.account.remove": "Remover del lista",
   "lists.delete": "Deler lista",
   "lists.edit": "Modificar lista",
   "lists.edit.submit": "Cambiar titulo",
-  "lists.exclusive": "Celar iste messages ab le initio",
+  "lists.exclusive": "Celar iste messages sur le pagina de initio",
   "lists.new.create": "Adder lista",
   "lists.new.title_placeholder": "Nove titulo del lista",
   "lists.replies_policy.none": "Nemo",
@@ -270,8 +278,10 @@
   "lists.subheading": "Tu listas",
   "loading_indicator.label": "Cargante…",
   "media_gallery.toggle_visible": "{number, plural, one {Celar imagine} other {Celar imagines}}",
-  "navigation_bar.about": "A proposito de",
-  "navigation_bar.advanced_interface": "Aperir in un interfacie web avantiate",
+  "mute_modal.hide_options": "Celar optiones",
+  "mute_modal.title": "Silentiar le usator?",
+  "navigation_bar.about": "A proposito",
+  "navigation_bar.advanced_interface": "Aperir in le interfacie web avantiate",
   "navigation_bar.blocks": "Usatores blocate",
   "navigation_bar.bookmarks": "Marcapaginas",
   "navigation_bar.community_timeline": "Chronologia local",
@@ -291,14 +301,18 @@
   "navigation_bar.public_timeline": "Chronologia federate",
   "navigation_bar.search": "Cercar",
   "navigation_bar.security": "Securitate",
-  "notification.own_poll": "Tu inquesta finiva",
-  "notification.update": "{name} modificava un message",
+  "notification.own_poll": "Tu sondage ha finite",
+  "notification.relationships_severance_event.learn_more": "Apprender plus",
+  "notification.update": "{name} ha modificate un message",
+  "notification_requests.notifications_from": "Notificationes de {name}",
   "notifications.clear": "Rader notificationes",
+  "notifications.clear_confirmation": "Es tu secur que tu vole rader permanentemente tote tu notificationes?",
   "notifications.column_settings.alert": "Notificationes de scriptorio",
   "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Monstrar tote le categorias",
   "notifications.column_settings.follow": "Nove sequitores:",
   "notifications.column_settings.mention": "Mentiones:",
-  "notifications.column_settings.poll": "Resultatos del inquesta:",
+  "notifications.column_settings.poll": "Resultatos del sondage:",
   "notifications.column_settings.push": "Notificationes push",
   "notifications.column_settings.show": "Monstrar in columna",
   "notifications.column_settings.sound": "Reproducer sono",
@@ -307,10 +321,11 @@
   "notifications.filter.all": "Toto",
   "notifications.filter.favourites": "Favoritos",
   "notifications.filter.mentions": "Mentiones",
-  "notifications.filter.polls": "Resultatos del inquesta",
+  "notifications.filter.polls": "Resultatos del sondage",
   "notifications.filter.statuses": "Actualisationes de personas que tu seque",
   "notifications.grant_permission": "Conceder permission.",
   "notifications.group": "{count} notificationes",
+  "notifications.policy.filter_new_accounts_title": "Nove contos",
   "notifications_permission_banner.enable": "Activar notificationes de scriptorio",
   "onboarding.compose.template": "Salute #Mastodon!",
   "onboarding.profile.save_and_continue": "Salvar e continuar",
@@ -322,7 +337,7 @@
   "onboarding.steps.share_profile.title": "Compartir tu profilo de Mastodon",
   "poll.closed": "Claudite",
   "poll.reveal": "Vider le resultatos",
-  "privacy.change": "Cambiar privacitate del message",
+  "privacy.change": "Cambiar le confidentialitate del message",
   "privacy.public.short": "Public",
   "privacy_policy.last_updated": "Ultime actualisation {date}",
   "privacy_policy.title": "Politica de confidentialitate",
@@ -333,7 +348,7 @@
   "report.categories.other": "Alteres",
   "report.category.title_account": "profilo",
   "report.category.title_status": "message",
-  "report.close": "Preste",
+  "report.close": "Facite",
   "report.mute": "Silentiar",
   "report.next": "Sequente",
   "report.placeholder": "Commentos additional",
@@ -358,14 +373,14 @@
   "server_banner.learn_more": "Apprender plus",
   "server_banner.server_stats": "Statos del servitor:",
   "sign_in_banner.create_account": "Crear un conto",
-  "sign_in_banner.sign_in": "Initiar le session",
+  "sign_in_banner.sign_in": "Aperir session",
   "status.block": "Blocar @{name}",
   "status.copy": "Copiar ligamine a message",
   "status.delete": "Deler",
-  "status.direct": "Mentionar privatemente a @{name}",
+  "status.direct": "Mentionar privatemente @{name}",
   "status.direct_indicator": "Mention private",
   "status.edit": "Modificar",
-  "status.edited_x_times": "Modificate {count, plural, one {{count} tempore} other {{count} tempores}}",
+  "status.edited_x_times": "Modificate {count, plural, one {{count} vice} other {{count} vices}}",
   "status.favourite": "Adder al favoritos",
   "status.filter": "Filtrar iste message",
   "status.hide": "Celar le message",
@@ -376,20 +391,37 @@
   "status.more": "Plus",
   "status.mute_conversation": "Silentiar conversation",
   "status.read_more": "Leger plus",
+  "status.reblogs.empty": "Necuno ha ancora impulsate iste message. Quando alcuno lo face, le impulsos apparera hic.",
+  "status.redraft": "Deler e reconciper",
+  "status.remove_bookmark": "Remover marcapagina",
+  "status.replied_to": "Respondite a {name}",
+  "status.reply": "Responder",
+  "status.replyAll": "Responder al discussion",
+  "status.report": "Signalar @{name}",
+  "status.sensitive_warning": "Contento sensibile",
   "status.share": "Compartir",
+  "status.show_filter_reason": "Monstrar in omne caso",
   "status.show_less": "Monstrar minus",
+  "status.show_less_all": "Monstrar minus pro totes",
   "status.show_more": "Monstrar plus",
+  "status.show_more_all": "Monstrar plus pro totes",
+  "status.show_original": "Monstrar original",
+  "status.title.with_attachments": "{user} ha publicate {attachmentCount, plural, one {un annexo} other {{attachmentCount} annexos}}",
   "status.translate": "Traducer",
   "status.translated_from_with": "Traducite ab {lang} usante {provider}",
   "status.uncached_media_warning": "Previsualisation non disponibile",
+  "status.unmute_conversation": "Non plus silentiar conversation",
+  "status.unpin": "Disfixar del profilo",
+  "subscribed_languages.lead": "Solmente le messages in le linguas seligite apparera in tu chronologias de initio e de listas post le cambiamento. Selige necun pro reciper messages in tote le linguas.",
   "subscribed_languages.save": "Salveguardar le cambiamentos",
+  "subscribed_languages.target": "Cambiar le linguas subscribite pro {target}",
   "tabs_bar.home": "Initio",
   "tabs_bar.notifications": "Notificationes",
   "timeline_hint.resources.statuses": "Messages ancian",
   "trends.trending_now": "Ora in tendentias",
   "upload_button.label": "Adde imagines, un video o un file de audio",
   "upload_modal.choose_image": "Seliger un imagine",
-  "upload_modal.detect_text": "Deteger texto ab un pictura",
+  "upload_modal.detect_text": "Deteger texto de un imagine",
   "video.close": "Clauder le video",
   "video.download": "Discargar le file",
   "video.fullscreen": "Schermo plen",
diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json
index 17f312418..00b6a36c9 100644
--- a/app/javascript/mastodon/locales/ie.json
+++ b/app/javascript/mastodon/locales/ie.json
@@ -91,6 +91,9 @@
   "audio.hide": "Celar audio",
   "block_modal.show_less": "Monstrar minu",
   "block_modal.show_more": "Monstrar plu",
+  "block_modal.they_cant_mention": "Ne posse mentionar ni sequer te.",
+  "block_modal.they_cant_see_posts": "Ne posse vider tui postas e inversi.",
+  "block_modal.they_will_know": "Va esser conscient que tu ha bloccat.",
   "block_modal.title": "Bloccar usator?",
   "block_modal.you_wont_see_mentions": "Tu ne va vider postas mentionant li usator.",
   "boost_modal.combo": "Li proxim vez tu posse pressar {combo} por passar to-ci",
@@ -206,6 +209,16 @@
   "dismissable_banner.explore_tags": "Tis-ci es hashtags queles es popular che li social retage hodie. Hashtags usat de plu mult persones diferent es monstrat plu alt.",
   "dismissable_banner.public_timeline": "Tis-ci es li max recent public postas de persones che li social retage quem gente che {domain} seque.",
   "domain_block_modal.block": "Bloccar servitor",
+  "domain_block_modal.block_account_instead": "Altrimen, bloccar @{name}",
+  "domain_block_modal.they_can_interact_with_old_posts": "Persones de ti servitor posse interacter con tui old postas.",
+  "domain_block_modal.they_cant_follow": "Nequi de ti-ci servitor posse sequer te.",
+  "domain_pill.activitypub_like_language": "ActivityPub es li lingue usat de Mastodon por parlar con altri social retages.",
+  "domain_pill.server": "Servitor",
+  "domain_pill.their_handle": "Identificator:",
+  "domain_pill.their_server": "Su digital hem e omni su postas.",
+  "domain_pill.username": "Usator-nómine",
+  "domain_pill.whats_in_a_handle": "Ex quo consiste un identificator?",
+  "domain_pill.your_handle": "Tui identificator:",
   "embed.instructions": "Inbedar ti-ci posta per copiar li code in infra.",
   "embed.preview": "Vi qualmen it va aspecter:",
   "emoji_button.activity": "Activitá",
@@ -242,6 +255,7 @@
   "empty_column.list": "Ancor ne hay quocunc in ti-ci liste. Quande membres de ti-ci liste publica nov postas, ili va aparir ci.",
   "empty_column.lists": "Tu ancor have null listes. Quande tu crea un, it va aparir ci.",
   "empty_column.mutes": "Tu ancor ha silentiat null usatores.",
+  "empty_column.notification_requests": "Omnicos clar! Hay necos ci. Nov notificationes va venir ci quande tu recive les secun tui parametres.",
   "empty_column.notifications": "Tu have null notificationes. Quande altri persones interacte con te, tu va vider it ci.",
   "empty_column.public": "Hay nullcos ci! Scri alquo publicmen, o manualmen seque usatores de altri servitores por plenar to-ci",
   "error.unexpected_crash.explanation": "Pro un error in nor code o un problema de compatibilitá in li navigator, ti-ci págine ne posset esser monstrat correctmen.",
@@ -272,6 +286,9 @@
   "filter_modal.select_filter.subtitle": "Usar un existent categorie o crear nov",
   "filter_modal.select_filter.title": "Filtrar ti-ci posta",
   "filter_modal.title.status": "Filtrar un posta",
+  "filtered_notifications_banner.pending_requests": "Notificationes de {count, plural, =0 {nequi} one {un person} other {# persones}} quel tu possibilmen conosse",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat mention} other {privat mentiones}}",
+  "filtered_notifications_banner.title": "Filtrat notificationes",
   "firehose.all": "Omno",
   "firehose.local": "Ti-ci servitor",
   "firehose.remote": "Altri servitores",
@@ -400,6 +417,13 @@
   "loading_indicator.label": "Cargant…",
   "media_gallery.toggle_visible": "{number, plural, one {Celar image} other {Celar images}}",
   "moved_to_account_banner.text": "Tui conto {disabledAccount} es actualmen desactivisat pro que tu movet te a {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Celar de notificationes",
+  "mute_modal.hide_options": "Celar optiones",
+  "mute_modal.indefinite": "Til quande yo dessilentia li usator",
+  "mute_modal.show_options": "Monstrar optiones",
+  "mute_modal.they_can_mention_and_follow": "Posse mentionar e sequer te, ma va esser ínvisibil a te.",
+  "mute_modal.they_wont_know": "Ne va esser conscient pri li silentation.",
+  "mute_modal.title": "Silentiar usator?",
   "navigation_bar.about": "Information",
   "navigation_bar.advanced_interface": "Aperter in li web-interfacie avansat",
   "navigation_bar.blocks": "Bloccat usatores",
@@ -435,14 +459,20 @@
   "notification.own_poll": "Tui balotation ha finit",
   "notification.poll": "Un balotation in quel tu votat ha finit",
   "notification.reblog": "{name} boostat tui posta",
+  "notification.relationships_severance_event.learn_more": "Aprender plu",
   "notification.status": "{name} just postat",
   "notification.update": "{name} modificat un posta",
+  "notification_requests.accept": "Acceptar",
+  "notification_requests.dismiss": "Demisser",
+  "notification_requests.notifications_from": "Notificationes de {name}",
+  "notification_requests.title": "Filtrat notificationes",
   "notifications.clear": "Aclarar notificationes",
   "notifications.clear_confirmation": "Vole tu vermen permanentmen aclarar omni tui notificationes?",
   "notifications.column_settings.admin.report": "Nov raportas:",
   "notifications.column_settings.admin.sign_up": "Nov registrationes:",
   "notifications.column_settings.alert": "Notificationes sur li computator",
   "notifications.column_settings.favourite": "Favorites:",
+  "notifications.column_settings.filter_bar.advanced": "Monstrar omni categories",
   "notifications.column_settings.follow": "Nov sequitores:",
   "notifications.column_settings.follow_request": "Nov petitiones de sequer:",
   "notifications.column_settings.mention": "Mentiones:",
@@ -468,6 +498,15 @@
   "notifications.permission_denied": "Notificationes sur li computator es índisponibil pro que on ha previamen rejectet un petition por navigator-permissiones",
   "notifications.permission_denied_alert": "Notificationes sur li computator ne posse esser activisat, pro que navigator-permission ha esset previamen rejectet",
   "notifications.permission_required": "Notificationes sur li computator es índisponibil pro que li besonat permission ne ha esset dat.",
+  "notifications.policy.filter_new_accounts.hint": "Creat durant li passat {days, plural, one {un die} other {# dies}}",
+  "notifications.policy.filter_new_accounts_title": "Nov contos",
+  "notifications.policy.filter_not_followers_hint": "Includente tis qui ha sequet te minu quam {days, plural, one {un die} other {# dies}}",
+  "notifications.policy.filter_not_followers_title": "Persones qui ne seque te",
+  "notifications.policy.filter_not_following_hint": "Til quande tu manualmen aproba",
+  "notifications.policy.filter_not_following_title": "Persones queles tu ne seque",
+  "notifications.policy.filter_private_mentions_hint": "Filtrat except si it es un response a tui propri mention o si tu seque li missor",
+  "notifications.policy.filter_private_mentions_title": "Ínsolicitat privat mentiones",
+  "notifications.policy.title": "Filtrar notificationes de…",
   "notifications_permission_banner.enable": "Activisar notificationes sur li computator",
   "notifications_permission_banner.how_to_control": "Por reciver notificationes quande Mastodon ne es apert, activisa notificationes sur li computator. Tu posse decider precisimen quel species de interactiones genera notificationes per li buton {icon} in-supra quande ili es activisat.",
   "notifications_permission_banner.title": "Nequande preterlassa quocunc",
@@ -644,9 +683,11 @@
   "status.direct": "Privatmen mentionar @{name}",
   "status.direct_indicator": "Privat mention",
   "status.edit": "Modificar",
+  "status.edited": "Ultimmen actualisat ye {date}",
   "status.edited_x_times": "Modificat {count, plural, one {{count} vez} other {{count} vezes}}",
   "status.embed": "Inbedar",
   "status.favourite": "Favoritisar",
+  "status.favourites": "{count, plural, one {favorit} other {favorites}}",
   "status.filter": "Filtrar ti-ci posta",
   "status.filtered": "Filtrat",
   "status.hide": "Celar posta",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index a6f26bfce..d7e447626 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -174,7 +174,7 @@
   "confirmations.delete.confirm": "Elimina",
   "confirmations.delete.message": "Sei sicuro di voler eliminare questo post?",
   "confirmations.delete_list.confirm": "Elimina",
-  "confirmations.delete_list.message": "Sei sicuro di voler eliminare permanentemente questa lista?",
+  "confirmations.delete_list.message": "Sei sicuro/a di voler eliminare permanentemente questo elenco?",
   "confirmations.discard_edit_media.confirm": "Scarta",
   "confirmations.discard_edit_media.message": "Hai delle modifiche non salvate alla descrizione o anteprima del media, scartarle comunque?",
   "confirmations.domain_block.confirm": "Blocca il server",
@@ -263,8 +263,8 @@
   "empty_column.followed_tags": "Non hai ancora seguito alcun hashtag. Quando lo farai, appariranno qui.",
   "empty_column.hashtag": "Non c'è ancora nulla in questo hashtag.",
   "empty_column.home": "La cronologia della tua home è vuota! Segui altre persone per riempirla. {suggestions}",
-  "empty_column.list": "Non c'è ancora nulla in questa lista. Quando i membri di questa lista pubblicheranno dei nuovi post, appariranno qui.",
-  "empty_column.lists": "Non hai ancora alcuna lista. Quando ne creerai una, apparirà qui.",
+  "empty_column.list": "Non c'è ancora nulla in questo elenco. Quando i membri di questo elenco pubblicheranno nuovi post, appariranno qui.",
+  "empty_column.lists": "Non hai ancora nessun elenco. Quando ne creerai uno, apparirà qui.",
   "empty_column.mutes": "Non hai ancora silenziato alcun utente.",
   "empty_column.notification_requests": "Tutto chiaro! Non c'è niente qui. Quando ricevi nuove notifiche, verranno visualizzate qui in base alle tue impostazioni.",
   "empty_column.notifications": "Non hai ancora nessuna notifica. Quando altre persone interagiranno con te, le vedrai qui.",
@@ -410,20 +410,20 @@
   "limited_account_hint.action": "Mostra comunque il profilo",
   "limited_account_hint.title": "Questo profilo è stato nascosto dai moderatori di {domain}.",
   "link_preview.author": "Di {name}",
-  "lists.account.add": "Aggiungi alla lista",
-  "lists.account.remove": "Togli dalla lista",
-  "lists.delete": "Elimina lista",
-  "lists.edit": "Modifica lista",
+  "lists.account.add": "Aggiungi all'elenco",
+  "lists.account.remove": "Rimuovi dall'elenco",
+  "lists.delete": "Elimina elenco",
+  "lists.edit": "Modifica elenco",
   "lists.edit.submit": "Cambia il titolo",
   "lists.exclusive": "Nascondi questi post dalla home",
   "lists.new.create": "Aggiungi lista",
-  "lists.new.title_placeholder": "Titolo della nuova lista",
+  "lists.new.title_placeholder": "Titolo del nuovo elenco",
   "lists.replies_policy.followed": "Qualsiasi utente seguito",
-  "lists.replies_policy.list": "Membri della lista",
+  "lists.replies_policy.list": "Membri dell'elenco",
   "lists.replies_policy.none": "Nessuno",
   "lists.replies_policy.title": "Mostra risposte a:",
   "lists.search": "Cerca tra le persone che segui",
-  "lists.subheading": "Le tue liste",
+  "lists.subheading": "I tuoi elenchi",
   "load_pending": "{count, plural, one {# nuovo oggetto} other {# nuovi oggetti}}",
   "loading_indicator.label": "Caricamento…",
   "media_gallery.toggle_visible": "{number, plural, one {Nascondi immagine} other {Nascondi immagini}}",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 9dff30527..3bf89fedc 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -217,6 +217,19 @@
   "domain_block_modal.title": "ドメインをブロックしますか?",
   "domain_block_modal.you_will_lose_followers": "このサーバーのフォロワーはすべてフォロー解除されます。",
   "domain_block_modal.you_wont_see_posts": "このサーバーのユーザーからの投稿や通知が閲覧できなくなります。",
+  "domain_pill.activitypub_lets_connect": "Mastodonからほかのソーシャルアプリのユーザーへ、そのまた別のアプリのユーザーへと、それぞれが互いにつながり関わり合うことをこのActivityPubの仕組みが実現しています。",
+  "domain_pill.activitypub_like_language": "ActivityPubとは、Mastodonがほかのサーバーと会話をするときにしゃべる「言葉」のようなものです。",
+  "domain_pill.server": "サーバー",
+  "domain_pill.their_handle": "このユーザーのユーザーID:",
+  "domain_pill.their_server": "ユーザーの仮想の住所です。そのユーザーIDによるすべての投稿を保持しています。",
+  "domain_pill.their_username": "ユーザーを識別する名前です。ユーザー名はひとつのサーバー内においては唯一無二の名前ですが、ほかのサーバーには同名のユーザーがいることもあります。",
+  "domain_pill.username": "ユーザー名",
+  "domain_pill.whats_in_a_handle": "ユーザーIDについて",
+  "domain_pill.who_they_are": "そのユーザーが「誰であるか」「どこに住んでいるか」はユーザーIDから知ることができます。これにより<button>いくつものActivityPub対応のプラットフォーム</button>の集まりからなるネットワークを介してそれぞれのユーザーと関わり合うことができます。",
+  "domain_pill.who_you_are": "ほかのユーザーはあなたが「誰であるか」「どこに住んでいるか」をユーザーIDから認識でき、これにより<button>いくつものActivityPub対応のプラットフォーム</button>の集まりからなるネットワークを介してあなたと関わり合うことができます。",
+  "domain_pill.your_handle": "あなたのユーザーID:",
+  "domain_pill.your_server": "あなたの仮想の住所です。投稿した内容はすべてここに保持されます。もし今いるサーバーが気に入っていない場合は、フォロワーを引き継いで別のサーバーに引っ越すこともできます。",
+  "domain_pill.your_username": "あなたを識別する名前です。ユーザー名はひとつのサーバー内においては唯一無二の名前ですが、ほかのサーバーには同名のユーザーがいることもあります。",
   "embed.instructions": "下記のコードをコピーしてウェブサイトに埋め込みます。",
   "embed.preview": "表示例:",
   "emoji_button.activity": "活動",
diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json
index dd76baaf6..898f3b1ce 100644
--- a/app/javascript/mastodon/locales/lad.json
+++ b/app/javascript/mastodon/locales/lad.json
@@ -457,6 +457,7 @@
   "notification.own_poll": "Tu anketa eskapo",
   "notification.poll": "Anketa en ke votates eskapo",
   "notification.reblog": "{name} repartajo tu publikasyon",
+  "notification.relationships_severance_event.learn_more": "Ambezate mas",
   "notification.status": "{name} publiko algo",
   "notification.update": "{name} edito una publikasyon",
   "notification_requests.accept": "Acheta",
@@ -469,6 +470,8 @@
   "notifications.column_settings.admin.sign_up": "Muevas enrejistrasyones:",
   "notifications.column_settings.alert": "Avizos de ensimameza",
   "notifications.column_settings.favourite": "Te plazen:",
+  "notifications.column_settings.filter_bar.advanced": "Amostra todas las kategorias",
+  "notifications.column_settings.filter_bar.category": "Vara de filtrado rapido",
   "notifications.column_settings.follow": "Muevos suivantes:",
   "notifications.column_settings.follow_request": "Muevas solisitudes de segimiento:",
   "notifications.column_settings.mention": "Enmentaduras:",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 7a60f3bb7..7ff98ba53 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -89,6 +89,14 @@
   "announcement.announcement": "Объявление",
   "attachments_list.unprocessed": "(не обработан)",
   "audio.hide": "Скрыть аудио",
+  "block_modal.remote_users_caveat": "Мы попросим сервер {domain} уважать ваше решение. Однако, соблюдение требований не гарантировано, поскольку некоторые серверы могут работать с блокировками по-разному. Публичные записи по-прежнему могут быть видны неавторизованным пользователям.",
+  "block_modal.show_less": "Показать меньше",
+  "block_modal.show_more": "Показать больше",
+  "block_modal.they_cant_mention": "Он не может упоминать или подписываться на вас.",
+  "block_modal.they_cant_see_posts": "Он не может видеть ваши сообщения, и вы не увидите его.",
+  "block_modal.they_will_know": "Он может видеть, что он заблокирован.",
+  "block_modal.title": "Заблокировать пользователя?",
+  "block_modal.you_wont_see_mentions": "Вы не увидите записи, которые упоминают его.",
   "boost_modal.combo": "{combo}, чтобы пропустить это в следующий раз",
   "bundle_column_error.copy_stacktrace": "Скопировать отчет об ошибке",
   "bundle_column_error.error.body": "Запрошенная страница не может быть отображена. Это может быть вызвано ошибкой в нашем коде или проблемой совместимости браузера.",
@@ -169,6 +177,7 @@
   "confirmations.delete_list.message": "Вы действительно хотите навсегда удалить этот список?",
   "confirmations.discard_edit_media.confirm": "Отменить",
   "confirmations.discard_edit_media.message": "У вас есть несохранённые изменения описания мультимедиа или предпросмотра, отменить их?",
+  "confirmations.domain_block.confirm": "Заблокировать сервер",
   "confirmations.domain_block.message": "Вы точно уверены, что хотите заблокировать {domain} полностью? В большинстве случаев нескольких блокировок и игнорирований вполне достаточно. Вы перестанете видеть публичную ленту и уведомления оттуда. Ваши подписчики из этого домена будут удалены.",
   "confirmations.edit.confirm": "Редактировать",
   "confirmations.edit.message": "В данный момент, редактирование перезапишет составляемое вами сообщение. Вы уверены, что хотите продолжить?",
@@ -200,6 +209,27 @@
   "dismissable_banner.explore_statuses": "Эти сообщения со связанных серверов сети сейчас набирают популярность.",
   "dismissable_banner.explore_tags": "Эти хэштеги привлекают людей на этом и других серверах децентрализованной сети прямо сейчас.",
   "dismissable_banner.public_timeline": "Это самые последние публичные сообщения от людей в социальной сети, за которыми подписались пользователи {domain}.",
+  "domain_block_modal.block": "Заблокировать сервер",
+  "domain_block_modal.block_account_instead": "Заблокировать @{name} вместо",
+  "domain_block_modal.they_can_interact_with_old_posts": "Люди с этого сервера могут взаимодействовать с вашими старыми записями.",
+  "domain_block_modal.they_cant_follow": "Никто из этого сервера не может подписываться на вас.",
+  "domain_block_modal.they_wont_know": "Он не будет знать, что его заблокировали.",
+  "domain_block_modal.title": "Заблокировать домен?",
+  "domain_block_modal.you_will_lose_followers": "Все ваши подписчики с этого сервера будут удалены.",
+  "domain_block_modal.you_wont_see_posts": "Вы не будете видеть записи или уведомления от пользователей на этом сервере.",
+  "domain_pill.activitypub_lets_connect": "Это позволяет вам общаться и взаимодействовать с людьми не только на Mastodon, но и в различных социальных приложениях.",
+  "domain_pill.activitypub_like_language": "ActivityPub как язык Mastodon говорит с другими социальными сетями.",
+  "domain_pill.server": "Сервер",
+  "domain_pill.their_handle": "Его бейдж:",
+  "domain_pill.their_server": "Цифровой дом, где находятся все записи.",
+  "domain_pill.their_username": "Уникальный идентификатор на сервере. Возможно найти пользователей с одним и тем же именем пользователя на разных серверах.",
+  "domain_pill.username": "Имя пользователя",
+  "domain_pill.whats_in_a_handle": "Что такое бейдж?",
+  "domain_pill.who_they_are": "Поскольку бейджи говорят о том, кто и где находится, вы можете взаимодействовать с людьми в социальной сети <button>платформ, работающих на платформе ActivityPub</button>.",
+  "domain_pill.who_you_are": "Поскольку ваш бейдж говорит о том, кто вы и где находитесь, люди могут взаимодействовать с вами через социальную сеть <button>платформ, работающих на платформе ActivityPub</button>.",
+  "domain_pill.your_handle": "Ваш бейдж:",
+  "domain_pill.your_server": "Сервер, где живут все ваши посты. Этот не нравится? Поменяй сервер в любое время вместе со своими подписчиками.",
+  "domain_pill.your_username": "Ваш уникальный идентификатор на этом сервере. Вы можете найти пользователей с одним именем пользователя на разных серверах.",
   "embed.instructions": "Встройте этот пост на свой сайт, скопировав следующий код:",
   "embed.preview": "Так это будет выглядеть:",
   "emoji_button.activity": "Занятия",
@@ -236,6 +266,7 @@
   "empty_column.list": "В этом списке пока ничего нет.",
   "empty_column.lists": "У вас ещё нет списков. Созданные вами списки будут показаны здесь.",
   "empty_column.mutes": "Вы ещё никого не добавляли в список игнорируемых.",
+  "empty_column.notification_requests": "Здесь ничего нет! Когда вы получите новые уведомления, они здесь появятся согласно вашим настройкам.",
   "empty_column.notifications": "У вас пока нет уведомлений. Взаимодействуйте с другими, чтобы завести разговор.",
   "empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту",
   "error.unexpected_crash.explanation": "Из-за несовместимого браузера или ошибки в нашем коде, эта страница не может быть корректно отображена.",
@@ -266,13 +297,22 @@
   "filter_modal.select_filter.subtitle": "Используйте существующую категорию или создайте новую",
   "filter_modal.select_filter.title": "Фильтровать этот пост",
   "filter_modal.title.status": "Фильтровать пост",
+  "filtered_notifications_banner.pending_requests": "Уведомления от {count, plural, =0 {никого} one {# человека} other {# других людей, с кем вы можете быть знакомы}}",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {личное упоминание} other {личные упоминания}}",
+  "filtered_notifications_banner.title": "Отфильтрованные уведомления",
   "firehose.all": "Все",
   "firehose.local": "Текущий сервер",
   "firehose.remote": "Другие серверы",
   "follow_request.authorize": "Авторизовать",
   "follow_request.reject": "Отказать",
   "follow_requests.unlocked_explanation": "Хотя ваша учетная запись не закрыта, команда {domain} подумала, что вы захотите просмотреть запросы от этих учетных записей вручную.",
+  "follow_suggestions.curated_suggestion": "Выбор администрации",
   "follow_suggestions.dismiss": "Больше не показывать",
+  "follow_suggestions.hints.featured": "Этот профиль был вручную выбран командой {domain}.",
+  "follow_suggestions.hints.friends_of_friends": "Этот профиль популярен среди людей, на которых вы подписаны.",
+  "follow_suggestions.hints.most_followed": "Этот профиль один из самых отслеживаемых на {domain}.",
+  "follow_suggestions.hints.most_interactions": "Этот профиль в последнее время привлекает много внимания на {domain}.",
+  "follow_suggestions.hints.similar_to_recently_followed": "Этот профиль похож на другие профили, на которые вы подписывались в последнее время.",
   "follow_suggestions.personalized_suggestion": "Персонализированное предложение",
   "follow_suggestions.popular_suggestion": "Популярное предложение",
   "follow_suggestions.view_all": "Посмотреть все",
@@ -388,6 +428,15 @@
   "loading_indicator.label": "Загрузка…",
   "media_gallery.toggle_visible": "Показать/скрыть {number, plural, =1 {изображение} other {изображения}}",
   "moved_to_account_banner.text": "Ваша учетная запись {disabledAccount} в настоящее время заморожена, потому что вы переехали на {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Скрыть из уведомлений",
+  "mute_modal.hide_options": "Скрыть параметры",
+  "mute_modal.indefinite": "Пока я не разблокирую их",
+  "mute_modal.show_options": "Показать опции",
+  "mute_modal.they_can_mention_and_follow": "Они могут упоминать и следить за вами, но вы не будете их видеть.",
+  "mute_modal.they_wont_know": "Они не будут знать, что их заглушили.",
+  "mute_modal.title": "Заглушить пользователя?",
+  "mute_modal.you_wont_see_mentions": "Вы не увидите постов, которые их упоминают.",
+  "mute_modal.you_wont_see_posts": "Они по-прежнему смогут видеть ваши посты, но вы не сможете видеть их посты.",
   "navigation_bar.about": "О проекте",
   "navigation_bar.advanced_interface": "Включить многоколоночный интерфейс",
   "navigation_bar.blocks": "Заблокированные пользователи",
@@ -423,8 +472,17 @@
   "notification.own_poll": "Ваш опрос закончился",
   "notification.poll": "Опрос, в котором вы приняли участие, завершился",
   "notification.reblog": "{name} продвинул(а) ваш пост",
+  "notification.relationships_severance_event": "Потеряно соединение с {name}",
+  "notification.relationships_severance_event.account_suspension": "Администратор {from} заблокировал {target}, что означает, что вы больше не сможете получать обновления от них или взаймодествовать с ними.",
+  "notification.relationships_severance_event.domain_block": "Администратор {from} заблокировал {target} включая {followersCount} ваших подписчиков и {followingCount, plural, one {# аккаунт} few {# аккаунта} other {# аккаунтов}}, на которые вы подписаны.",
+  "notification.relationships_severance_event.learn_more": "Узнать больше",
+  "notification.relationships_severance_event.user_domain_block": "Вы заблокировали {target} включая {followersCount} ваших подписчиков и {followingCount, plural, one {# аккаунт} few {# аккаунта} other {# аккаунтов}}, на которые вы подписаны.",
   "notification.status": "{name} только что запостил",
   "notification.update": "{name} изменил(а) пост",
+  "notification_requests.accept": "Принять",
+  "notification_requests.dismiss": "Отклонить",
+  "notification_requests.notifications_from": "Уведомления от {name}",
+  "notification_requests.title": "Отфильтрованные уведомления",
   "notifications.clear": "Очистить уведомления",
   "notifications.clear_confirmation": "Вы уверены, что хотите очистить все уведомления?",
   "notifications.column_settings.admin.report": "Новые жалобы:",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 770daf378..85511df8c 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -220,8 +220,15 @@
   "domain_pill.activitypub_lets_connect": "Det låter dig ansluta och interagera med människor inte bara på Mastodon, men även på andra sociala appar.",
   "domain_pill.activitypub_like_language": "ActivityPub är som språket Mastodon talar med andra sociala nätverk.",
   "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Deras handtag:",
+  "domain_pill.their_server": "Deras digitala hem, där alla deras tjänster bor.",
   "domain_pill.their_username": "Deras unika identifierare på deras server. Det är möjligt att hitta användare med samma användarnamn på olika servrar.",
   "domain_pill.username": "Användarnamn",
+  "domain_pill.whats_in_a_handle": "Vad finns i ett handtag?",
+  "domain_pill.who_they_are": "Eftersom handtag säger vem någon är och var de är, kan du interagera med människor på det sociala nätet av <button>ActivityPub-drivna plattformar</button>.",
+  "domain_pill.who_you_are": "Eftersom handtag säger vem någon är och var de är, kan människor interagera med dig på det sociala nätet av <button>ActivityPub-drivna plattformar</button>.",
+  "domain_pill.your_handle": "Ditt handtag:",
+  "domain_pill.your_server": "Ditt digitala hem, där alla dina inlägg bor. Gillar du inte just denna? Byt server när som helst och ta med dina anhängare också.",
   "domain_pill.your_username": "Din unika identifierare på denna server. Det är möjligt att hitta användare med samma användarnamn på olika servrar.",
   "embed.instructions": "Bädda in detta inlägg på din webbplats genom att kopiera koden nedan.",
   "embed.preview": "Så här kommer det att se ut:",
@@ -259,6 +266,7 @@
   "empty_column.list": "Det finns inget i denna lista än. När listmedlemmar publicerar nya inlägg kommer de synas här.",
   "empty_column.lists": "Du har inga listor än. När skapar en kommer den dyka upp här.",
   "empty_column.mutes": "Du har ännu inte tystat några användare.",
+  "empty_column.notification_requests": "Allt klart! Det finns inget mer här. När du får nya meddelanden visas de här enligt dina inställningar.",
   "empty_column.notifications": "Du har inga meddelanden än. Interagera med andra för att starta konversationen.",
   "empty_column.public": "Det finns inget här! Skriv något offentligt, eller följ manuellt användarna från andra instanser för att fylla på det",
   "error.unexpected_crash.explanation": "På grund av en bugg i vår kod eller kompatiblitetsproblem i webbläsaren kan den här sidan inte visas korrekt.",
@@ -289,6 +297,9 @@
   "filter_modal.select_filter.subtitle": "Använd en befintlig kategori eller skapa en ny",
   "filter_modal.select_filter.title": "Filtrera detta inlägg",
   "filter_modal.title.status": "Filtrera ett inlägg",
+  "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omnämnande} other {privat omnämnande}}",
+  "filtered_notifications_banner.title": "Filtrerade aviseringar",
   "firehose.all": "Allt",
   "firehose.local": "Denna server",
   "firehose.remote": "Andra servrar",
@@ -417,7 +428,9 @@
   "loading_indicator.label": "Laddar…",
   "media_gallery.toggle_visible": "Växla synlighet",
   "moved_to_account_banner.text": "Ditt konto {disabledAccount} är för närvarande inaktiverat eftersom du flyttat till {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Dölj från aviseringslistan",
   "mute_modal.hide_options": "Dölj alternativ",
+  "mute_modal.indefinite": "Tills jag avtystar dem",
   "mute_modal.show_options": "Visa alternativ",
   "mute_modal.they_can_mention_and_follow": "De kan nämna och följa dig, men du ser dem inte.",
   "mute_modal.they_wont_know": "De vet inte att de har blivit tysta.",
@@ -459,6 +472,9 @@
   "notification.own_poll": "Din röstning har avslutats",
   "notification.poll": "En omröstning du röstat i har avslutats",
   "notification.reblog": "{name} boostade ditt inlägg",
+  "notification.relationships_severance_event": "Förlorade kontakter med {name}",
+  "notification.relationships_severance_event.account_suspension": "En administratör från {from} har stängt av {target}, vilket innebär att du inte längre kan ta emot uppdateringar från dem eller interagera med dem.",
+  "notification.relationships_severance_event.domain_block": "En administratör från {from} har blockerat {target}, inklusive {followersCount} av dina följare och {followingCount, plural, one {# konto} other {# konton}} du följer.",
   "notification.relationships_severance_event.learn_more": "Läs mer",
   "notification.status": "{name} publicerade just ett inlägg",
   "notification.update": "{name} redigerade ett inlägg",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 22f5420f8..bf1dfb823 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -730,7 +730,7 @@
   "status.reblogs.empty": "還沒有人轉嘟過這則嘟文。當有人轉嘟時,它將於此顯示。",
   "status.redraft": "刪除並重新編輯",
   "status.remove_bookmark": "移除書籤",
-  "status.replied_to": "回覆給 {name}",
+  "status.replied_to": "回覆 {name}",
   "status.reply": "回覆",
   "status.replyAll": "回覆討論串",
   "status.report": "檢舉 @{name}",
diff --git a/config/locales/activerecord.ia.yml b/config/locales/activerecord.ia.yml
index 7d1e7d719..eec89ad52 100644
--- a/config/locales/activerecord.ia.yml
+++ b/config/locales/activerecord.ia.yml
@@ -7,3 +7,9 @@ ia:
         password: Contrasigno
       user/account:
         username: Nomine de usator
+    errors:
+      models:
+        status:
+          attributes:
+            reblog:
+              taken: del message jam existe
diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml
index 7982f8a74..73fa1fa60 100644
--- a/config/locales/devise.de.yml
+++ b/config/locales/devise.de.yml
@@ -28,12 +28,12 @@ de:
         title: Verifiziere E-Mail-Adresse
       email_changed:
         explanation: 'Die E-Mail-Adresse deines Kontos wird geändert zu:'
-        extra: Wenn du deine E-Mail-Adresse nicht geändert hast, ist es wahrscheinlich, dass sich jemand Zugang zu deinem Konto verschafft hat. Bitte ändere sofort dein Passwort oder kontaktiere die Serververwaltung, wenn du aus deinem Konto ausgesperrt bist.
+        extra: Wenn du deine E-Mail-Adresse nicht geändert hast, ist es wahrscheinlich, dass sich jemand Zugang zu deinem Konto verschafft hat. Bitte ändere sofort dein Passwort oder kontaktiere die Administrator*innen des Servers, wenn du aus deinem Konto ausgesperrt bist.
         subject: 'Mastodon: E-Mail-Adresse geändert'
         title: Neue E-Mail-Adresse
       password_change:
         explanation: Das Passwort für dein Konto wurde geändert.
-        extra: Wenn du dein Passwort nicht geändert hast, ist es wahrscheinlich, dass sich jemand Zugang zu deinem Konto verschafft hat. Bitte ändere sofort dein Passwort oder kontaktiere die Serververwaltung, wenn du aus deinem Konto ausgesperrt bist.
+        extra: Wenn du dein Passwort nicht geändert hast, ist es wahrscheinlich, dass sich jemand Zugang zu deinem Konto verschafft hat. Bitte ändere sofort dein Passwort oder kontaktiere die Administrator*innen des Servers, wenn du aus deinem Konto ausgesperrt bist.
         subject: 'Mastodon: Passwort geändert'
         title: Passwort geändert
       reconfirmation_instructions:
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index f4f953a0c..4d17de4d0 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -1674,7 +1674,7 @@ es-MX:
     lost_follows: Cuentas seguidas perdidas
     preamble: Puedes perder cuentas seguidas y seguidores cuando bloqueas un dominio o cuando tus moderadores deciden suspender un servidor remoto. Cuando esto suceda, podrás descargar listas de relaciones cortadas, para ser inspeccionadas y posiblemente importadas en otro servidor.
     purged: La información sobre este servidor ha sido purgada por los administradores de tu servidor.
-    type: Suceso
+    type: Evento
   statuses:
     attached:
       audio:
diff --git a/config/locales/et.yml b/config/locales/et.yml
index 889ddfcff..a544d8063 100644
--- a/config/locales/et.yml
+++ b/config/locales/et.yml
@@ -597,6 +597,9 @@ et:
       actions_description_html: Otsustus, mida raporti lahendamiseks ette võtta. Karistava tegevuse korral saadetakse e-postiga teade, välja arvatud kategooria <strong>rämpspost</strong> puhul.
       actions_description_remote_html: Otsusta, mida teha selle raporti lahendamiseks. See mõjutab ainult seda, kuidas <strong>Sinu</strong> server selle kaugkontoga suhtleb ning selle sisu käsitleb.
       add_to_report: Lisa raportile juurde
+      already_suspended_badges:
+        local: Juba kustutamisel selles serveris
+        remote: Juba kustutamisel tema serveris
       are_you_sure: Oled kindel?
       assign_to_self: Määra mulle
       assigned: Määratud moderaator
@@ -1652,13 +1655,26 @@ et:
     import: Impordi
     import_and_export: Import / eksport
     migrate: Konto kolimine
+    notifications: E-postiteavitused
     preferences: Eelistused
     profile: Profiil
     relationships: Jälgitud ja jälgijad
+    severed_relationships: Katkestatud seos
     statuses_cleanup: Automaatne kustutamine
     strikes: Modereerimisjuhtumid
     two_factor_authentication: Kaheastmeline autentimine
     webauthn_authentication: Turvavõtmed
+  severed_relationships:
+    download: Allalaadimine (%{count})
+    event_type:
+      account_suspension: Konto kustutamisel (%{target_name})
+      domain_block: Server kustutamisel (%{target_name})
+      user_domain_block: Blokeerisid %{target_name}
+    lost_followers: Kadunud jälgijad
+    lost_follows: Kaotatud jälgimised
+    preamble: Võid kaotada jälgijaid ja jälgitavaid, kui blokeerid domeeni või kui su moderaatorid otsustavad kustutada kaugserveri. Kui see juhtub, saad alla laadida katkestatud seoste loetelu, et see üle vaadata ja võib-olla teise serverisse üles laadida.
+    purged: Selle serveri info on sinu serveri administraatorite poolt tühjendatud.
+    type: Sündmus
   statuses:
     attached:
       audio:
@@ -1754,6 +1770,7 @@ et:
     contrast: Mastodon (Kõrge kontrast)
     default: Mastodon (Tume)
     mastodon-light: Mastodon (Hele)
+    system: Automaatne (kasuta süsteemi teemat)
   time:
     formats:
       default: "%d. %B, %Y. aastal, kell %H:%M"
@@ -1866,6 +1883,9 @@ et:
       follows_subtitle: Jälgi teada-tuntud kasutajaid
       follows_title: Keda jälgida
       follows_view_more: Vaata lähemalt, keda jälgida
+      hashtags_recent_count:
+        one: "%{people} isikut viimase 2 päeva jooksul"
+        other: "%{people} inimest viimase 2 päeva jooksul"
       hashtags_subtitle: Avasta, mis viimase 2 päeva jooksul on toimunud
       hashtags_title: Populaarsed märksõnad
       hashtags_view_more: Vaata teisi trendikaid märksõnu
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index 52cf861b4..ecdf73ef9 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -1,7 +1,20 @@
 ---
 ia:
   about:
+    about_mastodon_html: 'Le rete social del futuro: nulle publicitate, nulle surveliantia corporative, conception ethic, e decentralisation! Mantene le controlo de tu datos con Mastodon!'
     contact_missing: Non definite
+    contact_unavailable: N/D
+    hosted_on: Mastodon albergate sur %{domain}
+    title: A proposito
+  accounts:
+    follow: Sequer
+    followers:
+      one: Sequitor
+      other: Sequitores
+    following: Sequente
+    instance_actor_flash: Iste conto es un agente virtual usate pro representar le servitor mesme e non alcun usator individual. Illo es usate pro le federation e non debe esser suspendite.
+    last_active: ultime activitate
+    link_verified_on: Le proprietate de iste ligamine ha essite verificate le %{date}
   admin:
     accounts:
       are_you_sure: Es tu secur?
diff --git a/config/locales/ie.yml b/config/locales/ie.yml
index 6763a8038..46e55b9e1 100644
--- a/config/locales/ie.yml
+++ b/config/locales/ie.yml
@@ -597,6 +597,9 @@ ie:
       actions_description_html: Decider quel action a far por soluer ti raporte. Si tu fa un punitiv action contra li raportat conto, li usator va reciver un notification per email, except in li casu que li <strong>Spam</strong> categorie es selectet.
       actions_description_remote_html: Decider quel action a far por soluer ti raporte. It va afecter solmen qualmen <strong>vor</strong> servitor comunica con ti lontan conto e tractar su contenete.
       add_to_report: Adjunter plu al raporte
+      already_suspended_badges:
+        local: Ja suspendet sur ti-ci servitor
+        remote: Ja suspendet sur su servitor
       are_you_sure: Es tu cert?
       assign_to_self: Assignar it a me
       assigned: Assignat moderator
@@ -1652,6 +1655,7 @@ ie:
     import: Importar
     import_and_export: Importation e exportation
     migrate: Migration de conto
+    notifications: E-postal notificationes
     preferences: Preferenties
     profile: Public profil
     relationships: Sequetes e sequitores
@@ -1659,6 +1663,14 @@ ie:
     strikes: Admonimentes moderatori
     two_factor_authentication: 2-factor autentication
     webauthn_authentication: Claves de securitá
+  severed_relationships:
+    download: Descargar (%{count})
+    event_type:
+      account_suspension: Suspension del conto (%{target_name})
+      user_domain_block: Tu bloccat %{target_name}
+    lost_followers: Perdit sequitores
+    preamble: Tu posse perdir tis queles tu seque e tui sequitores quande tu blocca un domonia o quande tui moderatores decide suspender un lontan servitor. Tande, tu va posser descargar listes de dejuntet relationes, a inspecter e possibilmen importar sur un altri servitor.
+    type: Eveniment
   statuses:
     attached:
       audio:
@@ -1752,6 +1764,7 @@ ie:
     contrast: Mastodon (Alt contraste)
     default: Mastodon (Obscur)
     mastodon-light: Mastodon (Luminosi)
+    system: Automatic (usar tema del sistema)
   time:
     formats:
       default: "%d.%m.%Y ye %H:%M"
@@ -1864,6 +1877,9 @@ ie:
       follows_subtitle: Sequer famosi contos
       follows_title: Persones a sequer
       follows_view_more: Vider plu persones a sequer
+      hashtags_recent_count:
+        one: "%{people} person in li passat 2 dies"
+        other: "%{people} persones in li passat 2 dies"
       hashtags_subtitle: Explorar li postas de tendentie durant li passat 2 dies
       hashtags_title: Populari hashtags
       hashtags_view_more: Vider plu hashtags in tendentie
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 59ccb5f27..f12735cfb 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -1234,7 +1234,7 @@ it:
     bookmarks: Segnalibri
     csv: CSV
     domain_blocks: Blocchi di dominio
-    lists: Liste
+    lists: Elenchi
     mutes: Stai silenziando
     storage: Archiviazione media
   featured_tags:
diff --git a/config/locales/lad.yml b/config/locales/lad.yml
index 3aaac3ab5..e9f18d4be 100644
--- a/config/locales/lad.yml
+++ b/config/locales/lad.yml
@@ -1665,6 +1665,10 @@ lad:
     webauthn_authentication: Yaves de sigurita
   severed_relationships:
     download: Abasha (%{count})
+    event_type:
+      user_domain_block: Blokates a %{target_name}
+    lost_followers: Suivantes pedridos
+    lost_follows: Segimyentos pedridos
     type: Evenimiento
   statuses:
     attached:
diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml
index c2df26c12..1f7d94004 100644
--- a/config/locales/simple_form.et.yml
+++ b/config/locales/simple_form.et.yml
@@ -116,6 +116,7 @@ et:
           sign_up_requires_approval: Uued liitumised vajavad kinnitamist
         severity: Valik, mis juhtub päringutega sellelt IP-aadressilt
       rule:
+        hint: Valikuline. Anna reegli kohta rohkem üksikasju
         text: Reegli või nõude kirjeldus selle serveri kasutajatele. Võimalikult lühidalt ja lihtsalt
       sessions:
         otp: 'Kaheastmelise autentimise kood telefonirakendusest või mõni taastekood:'
@@ -299,6 +300,7 @@ et:
           patch: Teata veaparandusuuendustest
         trending_tag: Uus trend vajab ülevaatust
       rule:
+        hint: Lisainfo
         text: Reegel
       settings:
         indexable: Kaasa profiilileht otsimootoritesse
diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml
index af198d932..16dbcbd18 100644
--- a/config/locales/simple_form.ia.yml
+++ b/config/locales/simple_form.ia.yml
@@ -15,6 +15,7 @@ ia:
         current_password: Contrasigno actual
         new_password: Nove contrasigno
         password: Contrasigno
+        setting_default_language: Lingua de publication
         setting_display_media_default: Predefinite
         setting_display_media_hide_all: Celar toto
         setting_display_media_show_all: Monstrar toto
@@ -35,9 +36,15 @@ ia:
         site_title: Nomine de servitor
         theme: Thema predefinite
         trends: Activar tendentias
+      ip_block:
+        severity: Regula
       notification_emails:
         software_updates:
           label: Un nove version de Mastodon es disponibile
+      rule:
+        text: Regula
+      settings:
+        indexable: Includer pagina de profilo in le motores de recerca
       user:
         time_zone: Fuso horari
       user_role:
diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml
index 3cf5c33f2..e142617fc 100644
--- a/config/locales/simple_form.ie.yml
+++ b/config/locales/simple_form.ie.yml
@@ -116,6 +116,7 @@ ie:
           sign_up_requires_approval: Nov registrationes va besonar tui aprobation
         severity: Selecter quo va evenir con demandes ex ti-ci IP
       rule:
+        hint: Optional. Ples provider plu detallies pri li regul
         text: Descrir un regul o postulation por usatores sur ti-ci servitor. Prova scrir un descrition curt e simplic
       sessions:
         otp: 'Intrar li 2-factor code generat del app sur tui portabile o usar un de tui codes de recuperation:'
@@ -299,6 +300,7 @@ ie:
           patch: Notificar pri problema-fixant actualisationes
         trending_tag: Nov tendentie besonant inspection
       rule:
+        hint: Information in plu
         text: Regul
       settings:
         indexable: Includer profil-pagine in serchatores

From a3fe82e359544047aa8f6a37d253f53abd16ad06 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 05:34:44 -0400
Subject: [PATCH 062/173] Rename cop `RSpec/Rails/HttpStatus` to
 `RSpecRails/HttpStatus` (#29806)

---
 .rubocop.yml | 10 +++++-----
 Gemfile.lock |  5 ++++-
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/.rubocop.yml b/.rubocop.yml
index 541da330c..2aa72d9e5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -142,11 +142,6 @@ RSpec/NamedSubject:
 RSpec/NotToNot:
   EnforcedStyle: to_not
 
-# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
-# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
-RSpec/Rails/HttpStatus:
-  EnforcedStyle: numeric
-
 # Reason: Match overrides from Rspec/FilePath rule above
 # https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat
 RSpec/SpecFilePathFormat:
@@ -157,6 +152,11 @@ RSpec/SpecFilePathFormat:
     OEmbedController: oembed_controller
     OStatus: ostatus
 
+# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
+# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
+RSpecRails/HttpStatus:
+  EnforcedStyle: numeric
+
 # Reason:
 # https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren
 Style/ClassAndModuleChildren:
diff --git a/Gemfile.lock b/Gemfile.lock
index bd15ad73a..9c36daec9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -672,10 +672,13 @@ GEM
       rack (>= 1.1)
       rubocop (>= 1.33.0, < 2.0)
       rubocop-ast (>= 1.31.1, < 2.0)
-    rubocop-rspec (2.27.1)
+    rubocop-rspec (2.28.0)
       rubocop (~> 1.40)
       rubocop-capybara (~> 2.17)
       rubocop-factory_bot (~> 2.22)
+      rubocop-rspec_rails (~> 2.28)
+    rubocop-rspec_rails (2.28.2)
+      rubocop (~> 1.40)
     ruby-prof (1.7.0)
     ruby-progressbar (1.13.0)
     ruby-saml (1.15.0)

From 07635228e2b2182888850cecddd4b09756d9edbc Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 2 Apr 2024 11:56:03 +0200
Subject: [PATCH 063/173] Fix Redux Middleware types (#29800)

---
 app/javascript/mastodon/store/middlewares/errors.ts | 3 ++-
 app/javascript/mastodon/store/middlewares/sounds.ts | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/store/middlewares/errors.ts b/app/javascript/mastodon/store/middlewares/errors.ts
index 977a09a46..e77cec34e 100644
--- a/app/javascript/mastodon/store/middlewares/errors.ts
+++ b/app/javascript/mastodon/store/middlewares/errors.ts
@@ -30,7 +30,8 @@ function isActionWithmaybeAlertParams(
   return isAction(action);
 }
 
-export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
+// eslint-disable-next-line @typescript-eslint/ban-types -- we need to use `{}` here to ensure the dispatch types can be merged
+export const errorsMiddleware: Middleware<{}, RootState> =
   ({ dispatch }) =>
   (next) =>
   (action) => {
diff --git a/app/javascript/mastodon/store/middlewares/sounds.ts b/app/javascript/mastodon/store/middlewares/sounds.ts
index 51839f427..720ee163e 100644
--- a/app/javascript/mastodon/store/middlewares/sounds.ts
+++ b/app/javascript/mastodon/store/middlewares/sounds.ts
@@ -51,7 +51,8 @@ const play = (audio: HTMLAudioElement) => {
 };
 
 export const soundsMiddleware = (): Middleware<
-  Record<string, never>,
+  // eslint-disable-next-line @typescript-eslint/ban-types -- we need to use `{}` here to ensure the dispatch types can be merged
+  {},
   RootState
 > => {
   const soundCache: Record<string, HTMLAudioElement> = {};

From e47a3d00fe21fa51ee1aeffbfb5e152f1f715fef Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 2 Apr 2024 12:03:33 +0200
Subject: [PATCH 064/173] Add API types for status and related objects (#29792)

---
 .../mastodon/api_types/media_attachments.ts   | 22 +++++
 app/javascript/mastodon/api_types/polls.ts    | 23 +++++
 app/javascript/mastodon/api_types/statuses.ts | 91 +++++++++++++++++++
 app/javascript/mastodon/models/status.ts      |  2 +-
 .../rest/media_attachment_serializer.rb       |  2 +
 app/serializers/rest/poll_serializer.rb       |  2 +
 app/serializers/rest/status_serializer.rb     |  2 +
 7 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 app/javascript/mastodon/api_types/media_attachments.ts
 create mode 100644 app/javascript/mastodon/api_types/polls.ts
 create mode 100644 app/javascript/mastodon/api_types/statuses.ts

diff --git a/app/javascript/mastodon/api_types/media_attachments.ts b/app/javascript/mastodon/api_types/media_attachments.ts
new file mode 100644
index 000000000..fc027ccd2
--- /dev/null
+++ b/app/javascript/mastodon/api_types/media_attachments.ts
@@ -0,0 +1,22 @@
+// See app/serializers/rest/media_attachment_serializer.rb
+
+export type MediaAttachmentType =
+  | 'image'
+  | 'gifv'
+  | 'video'
+  | 'unknown'
+  | 'audio';
+
+export interface ApiMediaAttachmentJSON {
+  id: string;
+  type: MediaAttachmentType;
+  url: string;
+  preview_url: string;
+  remoteUrl: string;
+  preview_remote_url: string;
+  text_url: string;
+  // TODO: how to define this?
+  meta: unknown;
+  description?: string;
+  blurhash: string;
+}
diff --git a/app/javascript/mastodon/api_types/polls.ts b/app/javascript/mastodon/api_types/polls.ts
new file mode 100644
index 000000000..8181f7b81
--- /dev/null
+++ b/app/javascript/mastodon/api_types/polls.ts
@@ -0,0 +1,23 @@
+import type { ApiCustomEmojiJSON } from './custom_emoji';
+
+// See app/serializers/rest/poll_serializer.rb
+
+export interface ApiPollOptionJSON {
+  title: string;
+  votes_count: number;
+}
+
+export interface ApiPollJSON {
+  id: string;
+  expires_at: string;
+  expired: boolean;
+  multiple: boolean;
+  votes_count: number;
+  voters_count: number;
+
+  options: ApiPollOptionJSON[];
+  emojis: ApiCustomEmojiJSON[];
+
+  voted: boolean;
+  own_votes: number[];
+}
diff --git a/app/javascript/mastodon/api_types/statuses.ts b/app/javascript/mastodon/api_types/statuses.ts
new file mode 100644
index 000000000..c7dd33b5d
--- /dev/null
+++ b/app/javascript/mastodon/api_types/statuses.ts
@@ -0,0 +1,91 @@
+// See app/serializers/rest/status_serializer.rb
+
+import type { ApiAccountJSON } from './accounts';
+import type { ApiCustomEmojiJSON } from './custom_emoji';
+import type { ApiMediaAttachmentJSON } from './media_attachments';
+import type { ApiPollJSON } from './polls';
+
+// See app/modals/status.rb
+export type StatusVisibility =
+  | 'public'
+  | 'unlisted'
+  | 'private'
+  // | 'limited' // This is never exposed to the API (they become `private`)
+  | 'direct';
+
+export interface ApiStatusApplicationJSON {
+  name: string;
+  website: string;
+}
+
+export interface ApiTagJSON {
+  name: string;
+  url: string;
+}
+
+export interface ApiMentionJSON {
+  id: string;
+  username: string;
+  url: string;
+  acct: string;
+}
+
+export interface ApiPreviewCardJSON {
+  url: string;
+  title: string;
+  description: string;
+  language: string;
+  type: string;
+  author_name: string;
+  author_url: string;
+  provider_name: string;
+  provider_url: string;
+  html: string;
+  width: number;
+  height: number;
+  image: string;
+  image_description: string;
+  embed_url: string;
+  blurhash: string;
+  published_at: string;
+}
+
+export interface ApiStatusJSON {
+  id: string;
+  created_at: string;
+  in_reply_to_id?: string;
+  in_reply_to_account_id?: string;
+  sensitive: boolean;
+  spoiler_text?: string;
+  visibility: StatusVisibility;
+  language: string;
+  uri: string;
+  url: string;
+  replies_count: number;
+  reblogs_count: number;
+  favorites_count: number;
+  edited_at?: string;
+
+  favorited?: boolean;
+  reblogged?: boolean;
+  muted?: boolean;
+  bookmarked?: boolean;
+  pinned?: boolean;
+
+  // filtered: FilterResult[]
+  filtered: unknown; // TODO
+  content?: string;
+  text?: string;
+
+  reblog?: ApiStatusJSON;
+  application?: ApiStatusApplicationJSON;
+  account: ApiAccountJSON;
+  media_attachments: ApiMediaAttachmentJSON[];
+  mentions: ApiMentionJSON[];
+
+  tags: ApiTagJSON[];
+  emojis: ApiCustomEmojiJSON[];
+
+  card?: ApiPreviewCardJSON;
+  poll?: ApiPollJSON;
+}
diff --git a/app/javascript/mastodon/models/status.ts b/app/javascript/mastodon/models/status.ts
index 83e9f6b88..7907fc34f 100644
--- a/app/javascript/mastodon/models/status.ts
+++ b/app/javascript/mastodon/models/status.ts
@@ -1,4 +1,4 @@
-export type StatusVisibility = 'public' | 'unlisted' | 'private' | 'direct';
+export type { StatusVisibility } from 'mastodon/api_types/statuses';
 
 // Temporary until we type it correctly
 export type Status = Immutable.Map<string, unknown>;
diff --git a/app/serializers/rest/media_attachment_serializer.rb b/app/serializers/rest/media_attachment_serializer.rb
index f27dda832..90a2a9727 100644
--- a/app/serializers/rest/media_attachment_serializer.rb
+++ b/app/serializers/rest/media_attachment_serializer.rb
@@ -3,6 +3,8 @@
 class REST::MediaAttachmentSerializer < ActiveModel::Serializer
   include RoutingHelper
 
+  # Please update `app/javascript/mastodon/api_types/media_attachments.ts` when making changes to the attributes
+
   attributes :id, :type, :url, :preview_url,
              :remote_url, :preview_remote_url, :text_url, :meta,
              :description, :blurhash
diff --git a/app/serializers/rest/poll_serializer.rb b/app/serializers/rest/poll_serializer.rb
index df6ebd0d4..6e0006073 100644
--- a/app/serializers/rest/poll_serializer.rb
+++ b/app/serializers/rest/poll_serializer.rb
@@ -1,6 +1,8 @@
 # frozen_string_literal: true
 
 class REST::PollSerializer < ActiveModel::Serializer
+  # Please update `app/javascript/mastodon/api_types/polls.ts` when making changes to the attributes
+
   attributes :id, :expires_at, :expired,
              :multiple, :votes_count, :voters_count
 
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index d32621541..e17e8c823 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -3,6 +3,8 @@
 class REST::StatusSerializer < ActiveModel::Serializer
   include FormattingHelper
 
+  # Please update `app/javascript/mastodon/api_types/statuses.ts` when making changes to the attributes
+
   attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
              :sensitive, :spoiler_text, :visibility, :language,
              :uri, :url, :replies_count, :reblogs_count,

From d05f62391d0f0e2da43de63d888121ad23c479b2 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 10:04:32 +0000
Subject: [PATCH 065/173] Update dependency public_suffix to v5.0.5 (#29824)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 9c36daec9..d38de8e88 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -526,7 +526,7 @@ GEM
       railties (>= 7.0.0)
     psych (5.1.2)
       stringio
-    public_suffix (5.0.4)
+    public_suffix (5.0.5)
     puma (6.4.2)
       nio4r (~> 2.0)
     pundit (2.3.1)

From b4d991adaa82e05a2dd95ae5c08bb374391ef568 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 2 Apr 2024 12:06:26 +0200
Subject: [PATCH 066/173] Use integers and not numbers in notification policy
 API counters (#29810)

---
 .../components/filtered_notifications_banner.jsx          | 2 +-
 app/javascript/mastodon/utils/numbers.ts                  | 8 ++++----
 app/serializers/rest/notification_policy_serializer.rb    | 4 ++--
 spec/requests/api/v1/notifications/policies_spec.rb       | 8 ++++----
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
index ecf4b74e8..f9b8c0be1 100644
--- a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
+++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
@@ -27,7 +27,7 @@ export const FilteredNotificationsBanner = () => {
     };
   }, [dispatch]);
 
-  if (policy === null || policy.getIn(['summary', 'pending_notifications_count']) * 1 === 0) {
+  if (policy === null || policy.getIn(['summary', 'pending_notifications_count']) === 0) {
     return null;
   }
 
diff --git a/app/javascript/mastodon/utils/numbers.ts b/app/javascript/mastodon/utils/numbers.ts
index ee2dabf56..0c11c268d 100644
--- a/app/javascript/mastodon/utils/numbers.ts
+++ b/app/javascript/mastodon/utils/numbers.ts
@@ -70,10 +70,10 @@ export function roundTo10(num: number): number {
   return Math.round(num * 0.1) / 0.1;
 }
 
-export function toCappedNumber(num: string): string {
-  if (parseInt(num) > 99) {
-    return '99+';
+export function toCappedNumber(num: number, max = 99): string {
+  if (num > max) {
+    return `${max}+`;
   } else {
-    return num;
+    return num.toString();
   }
 }
diff --git a/app/serializers/rest/notification_policy_serializer.rb b/app/serializers/rest/notification_policy_serializer.rb
index 4967c3e32..a50ba9e66 100644
--- a/app/serializers/rest/notification_policy_serializer.rb
+++ b/app/serializers/rest/notification_policy_serializer.rb
@@ -9,8 +9,8 @@ class REST::NotificationPolicySerializer < ActiveModel::Serializer
 
   def summary
     {
-      pending_requests_count: object.pending_requests_count.to_s,
-      pending_notifications_count: object.pending_notifications_count.to_s,
+      pending_requests_count: object.pending_requests_count.to_i,
+      pending_notifications_count: object.pending_notifications_count.to_i,
     }
   end
 end
diff --git a/spec/requests/api/v1/notifications/policies_spec.rb b/spec/requests/api/v1/notifications/policies_spec.rb
index 9acd47a7b..d02d2ed0d 100644
--- a/spec/requests/api/v1/notifications/policies_spec.rb
+++ b/spec/requests/api/v1/notifications/policies_spec.rb
@@ -32,8 +32,8 @@ RSpec.describe 'Policies' do
           filter_new_accounts: false,
           filter_private_mentions: true,
           summary: a_hash_including(
-            pending_requests_count: '1',
-            pending_notifications_count: '0'
+            pending_requests_count: 1,
+            pending_notifications_count: 0
           )
         )
       end
@@ -60,8 +60,8 @@ RSpec.describe 'Policies' do
         filter_new_accounts: false,
         filter_private_mentions: true,
         summary: a_hash_including(
-          pending_requests_count: '0',
-          pending_notifications_count: '0'
+          pending_requests_count: 0,
+          pending_notifications_count: 0
         )
       )
     end

From f6e24bbd798b32e683c752c28011fc3b2118d934 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 14:13:43 +0200
Subject: [PATCH 067/173] Update dependency postcss-preset-env to v9.5.4
 (#29825)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index e58a030c3..99f6f99c6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1748,9 +1748,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-light-dark-function@npm:^1.0.2":
-  version: 1.0.2
-  resolution: "@csstools/postcss-light-dark-function@npm:1.0.2"
+"@csstools/postcss-light-dark-function@npm:^1.0.3":
+  version: 1.0.3
+  resolution: "@csstools/postcss-light-dark-function@npm:1.0.3"
   dependencies:
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
@@ -1758,7 +1758,7 @@ __metadata:
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/c7ed0037e68aa6ede2440a598caa776812e602e12f69d0fd8f0975cf3469a3593bd34fd408ed7d0b73af2ae4498bd6334cb3222fedb2a432a9ab8fa731e07108
+  checksum: 10c0/99a1b72aba08a6fa5c7271d42f4459d86f001fe83f533c0ed3d21556f53ee227f65f94cda1feee1aa910890fc42482f15a4dfb3edbc7afdad828ce8897d0c52b
   languageName: node
   linkType: hard
 
@@ -13659,8 +13659,8 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.3
-  resolution: "postcss-preset-env@npm:9.5.3"
+  version: 9.5.4
+  resolution: "postcss-preset-env@npm:9.5.4"
   dependencies:
     "@csstools/postcss-cascade-layers": "npm:^4.0.4"
     "@csstools/postcss-color-function": "npm:^3.0.13"
@@ -13673,7 +13673,7 @@ __metadata:
     "@csstools/postcss-ic-unit": "npm:^3.0.6"
     "@csstools/postcss-initial": "npm:^1.0.1"
     "@csstools/postcss-is-pseudo-class": "npm:^4.0.6"
-    "@csstools/postcss-light-dark-function": "npm:^1.0.2"
+    "@csstools/postcss-light-dark-function": "npm:^1.0.3"
     "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1"
     "@csstools/postcss-logical-overflow": "npm:^1.0.1"
     "@csstools/postcss-logical-overscroll-behavior": "npm:^1.0.1"
@@ -13724,7 +13724,7 @@ __metadata:
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/0f6ed8ec9dc5365d1ca1d29652464f2cfebb6b39dfe39b55712c9251addde3289702ea37e1731da5b16bb70f2fb871d165bb0d33452506fa9121e5f696b63d34
+  checksum: 10c0/6af900ad2f46b640339b626317288543ebb7c47b739f4776e4006513b32eceabe0be78109aa58446fa0f50284a433b3e3a9bd48aa5730fd0ac59ef51153e8f7b
   languageName: node
   linkType: hard
 

From 695dded7ed3afbc50ed60acfc4402c117c40a21c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 15:29:46 +0200
Subject: [PATCH 068/173] Update dependency aws-sdk-s3 to v1.146.1 (#28961)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index d38de8e88..0a6d6036e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -103,7 +103,7 @@ GEM
     awrence (1.2.1)
     aws-eventstream (1.3.0)
     aws-partitions (1.899.0)
-    aws-sdk-core (3.191.4)
+    aws-sdk-core (3.191.5)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.8)
@@ -111,7 +111,7 @@ GEM
     aws-sdk-kms (1.78.0)
       aws-sdk-core (~> 3, >= 3.191.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.146.0)
+    aws-sdk-s3 (1.146.1)
       aws-sdk-core (~> 3, >= 3.191.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.8)

From b0692d994ff77d0832a471e171e8c770b965d7c8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 15:31:03 +0200
Subject: [PATCH 069/173] Update dependency letter_opener to v1.10.0 (#29189)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 0a6d6036e..913164d18 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -398,8 +398,8 @@ GEM
     language_server-protocol (3.17.0.3)
     launchy (2.5.2)
       addressable (~> 2.8)
-    letter_opener (1.8.1)
-      launchy (>= 2.2, < 3)
+    letter_opener (1.10.0)
+      launchy (>= 2.2, < 4)
     letter_opener_web (2.0.0)
       actionmailer (>= 5.2)
       letter_opener (~> 1.7)

From c70c39cad03824c64564fa7d241e6bf01acbab76 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 15:47:15 +0200
Subject: [PATCH 070/173] Update docker/dockerfile Docker tag to v1.7 (#27993)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Dockerfile           | 2 +-
 streaming/Dockerfile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 8778133e0..1b007930e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-# syntax=docker/dockerfile:1.4
+# syntax=docker/dockerfile:1.7
 
 # Please see https://docs.docker.com/engine/reference/builder for information about
 # the extended buildx capabilities used in this file.
diff --git a/streaming/Dockerfile b/streaming/Dockerfile
index 241009fe8..7f373e9cd 100644
--- a/streaming/Dockerfile
+++ b/streaming/Dockerfile
@@ -1,4 +1,4 @@
-# syntax=docker/dockerfile:1.4
+# syntax=docker/dockerfile:1.7
 
 # Please see https://docs.docker.com/engine/reference/builder for information about
 # the extended buildx capabilities used in this file.

From f56309f5f03f28d35c5e36b8cab282a03522370a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 09:51:34 -0400
Subject: [PATCH 071/173] Add `by_latest_used` scope, move admin area recent
 IPs to partial (#29497)

---
 app/models/user_ip.rb                             | 2 ++
 app/views/admin/accounts/_local_account.html.haml | 8 +-------
 app/views/admin/accounts/_user_ip.html.haml       | 5 +++++
 3 files changed, 8 insertions(+), 7 deletions(-)
 create mode 100644 app/views/admin/accounts/_user_ip.html.haml

diff --git a/app/models/user_ip.rb b/app/models/user_ip.rb
index 87b86a24d..a6da2c074 100644
--- a/app/models/user_ip.rb
+++ b/app/models/user_ip.rb
@@ -15,4 +15,6 @@ class UserIp < ApplicationRecord
   self.primary_key = :user_id
 
   belongs_to :user
+
+  scope :by_latest_used, -> { order(used_at: :desc) }
 end
diff --git a/app/views/admin/accounts/_local_account.html.haml b/app/views/admin/accounts/_local_account.html.haml
index 82197cda4..3ed392cd1 100644
--- a/app/views/admin/accounts/_local_account.html.haml
+++ b/app/views/admin/accounts/_local_account.html.haml
@@ -62,13 +62,7 @@
   %td
     %time.formatted{ datetime: account.created_at.iso8601, title: l(account.created_at) }= l account.created_at
   %td
-- recent_ips = account.user.ips.order(used_at: :desc).to_a
-- recent_ips.each_with_index do |recent_ip, i|
-  %tr
-    - if i.zero?
-      %th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
-    %td= recent_ip.ip
-    %td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
+  = render partial: 'admin/accounts/user_ip', collection: account.user.ips.by_latest_used
 %tr
   %th= t('admin.accounts.most_recent_activity')
   %td
diff --git a/app/views/admin/accounts/_user_ip.html.haml b/app/views/admin/accounts/_user_ip.html.haml
new file mode 100644
index 000000000..1938cf7ed
--- /dev/null
+++ b/app/views/admin/accounts/_user_ip.html.haml
@@ -0,0 +1,5 @@
+%tr
+  - if user_ip_iteration.first?
+    %th{ rowspan: user_ip_iteration.size }= t('admin.accounts.most_recent_ip')
+  %td= user_ip.ip
+  %td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: user_ip.ip)

From 34489591ec4d05fa16049e9e99d39a09a80f2d65 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 09:54:11 -0400
Subject: [PATCH 072/173] Add `max_pinned_statuses` to instances serializer and
 api response (#29441)

---
 app/serializers/rest/instance_serializer.rb   |  1 +
 spec/requests/api/v2/instance_spec.rb         | 20 +++++++++++++++++++
 .../rest/instance_serializer_spec.rb          | 11 ++++++++++
 3 files changed, 32 insertions(+)

diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb
index fa926cd28..42b73f438 100644
--- a/app/serializers/rest/instance_serializer.rb
+++ b/app/serializers/rest/instance_serializer.rb
@@ -54,6 +54,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
 
       accounts: {
         max_featured_tags: FeaturedTag::LIMIT,
+        max_pinned_statuses: StatusPinValidator::PIN_LIMIT,
       },
 
       statuses: {
diff --git a/spec/requests/api/v2/instance_spec.rb b/spec/requests/api/v2/instance_spec.rb
index 74574afbc..c5c6a26f4 100644
--- a/spec/requests/api/v2/instance_spec.rb
+++ b/spec/requests/api/v2/instance_spec.rb
@@ -18,6 +18,7 @@ describe 'Instances' do
         expect(body_as_json)
           .to be_present
           .and include(title: 'Mastodon')
+          .and include_configuration_limits
       end
     end
 
@@ -31,7 +32,26 @@ describe 'Instances' do
         expect(body_as_json)
           .to be_present
           .and include(title: 'Mastodon')
+          .and include_configuration_limits
       end
     end
+
+    def include_configuration_limits
+      include(
+        configuration: include(
+          accounts: include(
+            max_featured_tags: FeaturedTag::LIMIT,
+            max_pinned_statuses: StatusPinValidator::PIN_LIMIT
+          ),
+          statuses: include(
+            max_characters: StatusLengthValidator::MAX_CHARS,
+            max_media_attachments: 4 # TODO, move to constant somewhere
+          ),
+          polls: include(
+            max_options: PollValidator::MAX_OPTIONS
+          )
+        )
+      )
+    end
   end
 end
diff --git a/spec/serializers/rest/instance_serializer_spec.rb b/spec/serializers/rest/instance_serializer_spec.rb
index d8f2536d2..39e6b3820 100644
--- a/spec/serializers/rest/instance_serializer_spec.rb
+++ b/spec/serializers/rest/instance_serializer_spec.rb
@@ -10,11 +10,22 @@ describe REST::InstanceSerializer do
     it 'returns recent usage data' do
       expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } })
     end
+  end
 
+  describe 'configuration' do
     it 'returns the VAPID public key' do
       expect(serialization['configuration']['vapid']).to eq({
         'public_key' => Rails.configuration.x.vapid_public_key,
       })
     end
+
+    it 'returns the max pinned statuses limit' do
+      expect(serialization.deep_symbolize_keys)
+        .to include(
+          configuration: include(
+            accounts: include(max_pinned_statuses: StatusPinValidator::PIN_LIMIT)
+          )
+        )
+    end
   end
 end

From 54119570e69456e3f119cc3e3e968506c3fb4967 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 2 Apr 2024 16:02:07 +0200
Subject: [PATCH 073/173] Remove dependency on posix-spawn (#18559)

---
 Gemfile      | 1 -
 Gemfile.lock | 2 --
 2 files changed, 3 deletions(-)

diff --git a/Gemfile b/Gemfile
index 35b9ee91d..e39de40ef 100644
--- a/Gemfile
+++ b/Gemfile
@@ -69,7 +69,6 @@ gem 'nsa'
 gem 'oj', '~> 3.14'
 gem 'ox', '~> 2.14'
 gem 'parslet'
-gem 'posix-spawn'
 gem 'public_suffix', '~> 5.0'
 gem 'pundit', '~> 2.3'
 gem 'premailer-rails'
diff --git a/Gemfile.lock b/Gemfile.lock
index 913164d18..f18e736f2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -509,7 +509,6 @@ GEM
     pg (1.5.6)
     pghero (3.4.1)
       activerecord (>= 6)
-    posix-spawn (0.3.15)
     premailer (1.23.0)
       addressable
       css_parser (>= 1.12.0)
@@ -899,7 +898,6 @@ DEPENDENCIES
   parslet
   pg (~> 1.5)
   pghero
-  posix-spawn
   premailer-rails
   private_address_check (~> 0.5)
   propshaft

From f87959ab501ebb63444832369f0fb452768a0a8a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 10:05:02 -0400
Subject: [PATCH 074/173] Fix `RSpec/LetSetup` cop in api/v1/timelines/public
 spec (#28972)

---
 spec/requests/api/v1/timelines/public_spec.rb | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/spec/requests/api/v1/timelines/public_spec.rb b/spec/requests/api/v1/timelines/public_spec.rb
index 30d1bc00c..364e48d3d 100644
--- a/spec/requests/api/v1/timelines/public_spec.rb
+++ b/spec/requests/api/v1/timelines/public_spec.rb
@@ -22,13 +22,15 @@ describe 'Public' do
       get '/api/v1/timelines/public', headers: headers, params: params
     end
 
-    let!(:private_status) { Fabricate(:status, visibility: :private) } # rubocop:disable RSpec/LetSetup
     let!(:local_status)   { Fabricate(:status, account: Fabricate.build(:account, domain: nil)) }
     let!(:remote_status)  { Fabricate(:status, account: Fabricate.build(:account, domain: 'example.com')) }
     let!(:media_status)   { Fabricate(:status, media_attachments: [Fabricate.build(:media_attachment)]) }
-
     let(:params) { {} }
 
+    before do
+      Fabricate(:status, visibility: :private)
+    end
+
     context 'when the instance allows public preview' do
       let(:expected_statuses) { [local_status, remote_status, media_status] }
 

From 0b9d4103cb5502faee4cc61717aa5454f63bc8f5 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 2 Apr 2024 16:05:46 +0200
Subject: [PATCH 075/173] Fix contrast in notification request badge (#29826)

---
 app/javascript/styles/mastodon/components.scss | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 216c0dab0..a49f162e3 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -10104,9 +10104,10 @@ noscript {
     }
 
     .filtered-notifications-banner__badge {
-      background-color: $highlight-text-color;
+      background: $ui-button-background-color;
       border-radius: 4px;
       padding: 1px 6px;
+      color: $white;
     }
   }
 

From 921c4c12731b927d613766c98797de21dfadef4a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 10:07:31 -0400
Subject: [PATCH 076/173] Match comment style of `FeedManager` list/tags checks
 (#29639)

Co-authored-by: Renaud Chaput <renchap@gmail.com>
---
 app/lib/feed_manager.rb | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 38a177e64..bf6e6db59 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -431,10 +431,10 @@ class FeedManager
   # @param [List] list
   # @return [Boolean]
   def filter_from_list?(status, list)
-    if status.reply? && status.in_reply_to_account_id != status.account_id
-      should_filter = status.in_reply_to_account_id != list.account_id
-      should_filter &&= !list.show_followed?
-      should_filter &&= !(list.show_list? && ListAccount.exists?(list_id: list.id, account_id: status.in_reply_to_account_id))
+    if status.reply? && status.in_reply_to_account_id != status.account_id                                                       # Status is a reply to account other than status account
+      should_filter = status.in_reply_to_account_id != list.account_id                                                           # Status replies to account id other than list account
+      should_filter &&= !list.show_followed?                                                                                     # List show_followed? is false
+      should_filter &&= !(list.show_list? && ListAccount.exists?(list_id: list.id, account_id: status.in_reply_to_account_id))   # If show_list? true, check for a ListAccount with list and reply to account
 
       return !!should_filter
     end
@@ -449,7 +449,11 @@ class FeedManager
   # @param [Hash] crutches
   # @return [Boolean]
   def filter_from_tags?(status, receiver_id, crutches)
-    receiver_id == status.account_id || ((crutches[:active_mentions][status.id] || []) + [status.account_id]).any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } || crutches[:blocked_by][status.account_id] || crutches[:domain_blocking][status.account.domain]
+    receiver_id == status.account_id ||                                                                                          # Receiver is status account?
+      ((crutches[:active_mentions][status.id] || []) + [status.account_id])                                                      # For mentioned accounts or status account:
+        .any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } ||          #   - Target account is muted or blocked?
+      crutches[:blocked_by][status.account_id] ||                                                                                # Blocked by status account?
+      crutches[:domain_blocking][status.account.domain]                                                                          # Blocking domain of status account?
   end
 
   # Adds a status to an account's feed, returning true if a status was

From edde54e991d2f6826c4e7c478bfd03332fb03887 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 11:47:40 -0400
Subject: [PATCH 077/173] Update stoplight to version 4.1.0 (#28366)

---
 Gemfile                                            |  2 +-
 Gemfile.lock                                       |  4 ++--
 app/controllers/concerns/signature_verification.rb | 11 +++++------
 app/services/bulk_import_row_service.rb            | 11 +++++------
 app/workers/activitypub/delivery_worker.rb         | 10 ++++++----
 app/workers/import/relationship_worker.rb          |  9 ++++-----
 config/initializers/stoplight.rb                   |  4 ++--
 lib/paperclip/attachment_extensions.rb             | 12 +++++-------
 8 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/Gemfile b/Gemfile
index e39de40ef..389ae5035 100644
--- a/Gemfile
+++ b/Gemfile
@@ -88,7 +88,7 @@ gem 'sidekiq-unique-jobs', '~> 7.1'
 gem 'sidekiq-bulk', '~> 0.2.0'
 gem 'simple-navigation', '~> 4.4'
 gem 'simple_form', '~> 5.2'
-gem 'stoplight', '~> 3.0.1'
+gem 'stoplight', '~> 4.1'
 gem 'strong_migrations', '1.8.0'
 gem 'tty-prompt', '~> 0.23', require: false
 gem 'twitter-text', '~> 3.1.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index f18e736f2..2cebe0be8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -732,7 +732,7 @@ GEM
     smart_properties (1.17.0)
     stackprof (0.2.26)
     statsd-ruby (1.5.0)
-    stoplight (3.0.2)
+    stoplight (4.1.0)
       redlock (~> 1.0)
     stringio (3.1.0)
     strong_migrations (1.8.0)
@@ -939,7 +939,7 @@ DEPENDENCIES
   simplecov (~> 0.22)
   simplecov-lcov (~> 0.8)
   stackprof
-  stoplight (~> 3.0.1)
+  stoplight (~> 4.1)
   strong_migrations (= 1.8.0)
   test-prof
   thor (~> 1.2)
diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb
index 315586627..68f09ee02 100644
--- a/app/controllers/concerns/signature_verification.rb
+++ b/app/controllers/concerns/signature_verification.rb
@@ -66,7 +66,7 @@ module SignatureVerification
     compare_signed_string = build_signed_string(include_query_string: false)
     return actor unless verify_signature(actor, signature, compare_signed_string).nil?
 
-    actor = stoplight_wrap_request { actor_refresh_key!(actor) }
+    actor = stoplight_wrapper.run { actor_refresh_key!(actor) }
 
     raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil?
 
@@ -226,10 +226,10 @@ module SignatureVerification
     end
 
     if key_id.start_with?('acct:')
-      stoplight_wrap_request { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
+      stoplight_wrapper.run { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
     elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
       account   = ActivityPub::TagManager.instance.uri_to_actor(key_id)
-      account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
+      account ||= stoplight_wrapper.run { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
       account
     end
   rescue Mastodon::PrivateNetworkAddressError => e
@@ -238,12 +238,11 @@ module SignatureVerification
     raise SignatureVerificationError, e.message
   end
 
-  def stoplight_wrap_request(&block)
-    Stoplight("source:#{request.remote_ip}", &block)
+  def stoplight_wrapper
+    Stoplight("source:#{request.remote_ip}")
       .with_threshold(1)
       .with_cool_off_time(5.minutes.seconds)
       .with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
-      .run
   end
 
   def actor_refresh_key!(actor)
diff --git a/app/services/bulk_import_row_service.rb b/app/services/bulk_import_row_service.rb
index ef4c18e78..26909dfe0 100644
--- a/app/services/bulk_import_row_service.rb
+++ b/app/services/bulk_import_row_service.rb
@@ -10,7 +10,7 @@ class BulkImportRowService
     when :following, :blocking, :muting, :lists
       target_acct     = @data['acct']
       target_domain   = domain(target_acct)
-      @target_account = stoplight_wrap_request(target_domain) { ResolveAccountService.new.call(target_acct, { check_delivery_availability: true }) }
+      @target_account = stoplight_wrapper(target_domain).run { ResolveAccountService.new.call(target_acct, { check_delivery_availability: true }) }
       return false if @target_account.nil?
     when :bookmarks
       target_uri      = @data['uri']
@@ -18,7 +18,7 @@ class BulkImportRowService
       @target_status = ActivityPub::TagManager.instance.uri_to_resource(target_uri, Status)
       return false if @target_status.nil? && ActivityPub::TagManager.instance.local_uri?(target_uri)
 
-      @target_status ||= stoplight_wrap_request(target_domain) { ActivityPub::FetchRemoteStatusService.new.call(target_uri) }
+      @target_status ||= stoplight_wrapper(target_domain).run { ActivityPub::FetchRemoteStatusService.new.call(target_uri) }
       return false if @target_status.nil?
     end
 
@@ -51,16 +51,15 @@ class BulkImportRowService
     TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
   end
 
-  def stoplight_wrap_request(domain, &block)
+  def stoplight_wrapper(domain)
     if domain.present?
-      Stoplight("source:#{domain}", &block)
+      Stoplight("source:#{domain}")
         .with_fallback { nil }
         .with_threshold(1)
         .with_cool_off_time(5.minutes.seconds)
         .with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
-        .run
     else
-      yield
+      Stoplight('domain-blank')
     end
   end
 end
diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb
index 376c237a9..0c6ca026b 100644
--- a/app/workers/activitypub/delivery_worker.rb
+++ b/app/workers/activitypub/delivery_worker.rb
@@ -59,7 +59,7 @@ class ActivityPub::DeliveryWorker
   end
 
   def perform_request
-    light = Stoplight(@inbox_url) do
+    stoplight_wrapper.run do
       request_pool.with(@host) do |http_client|
         build_request(http_client).perform do |response|
           raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
@@ -68,10 +68,12 @@ class ActivityPub::DeliveryWorker
         end
       end
     end
+  end
 
-    light.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
-         .with_cool_off_time(STOPLIGHT_COOLDOWN)
-         .run
+  def stoplight_wrapper
+    Stoplight(@inbox_url)
+      .with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
+      .with_cool_off_time(STOPLIGHT_COOLDOWN)
   end
 
   def failure_tracker
diff --git a/app/workers/import/relationship_worker.rb b/app/workers/import/relationship_worker.rb
index a411ab587..2298b095a 100644
--- a/app/workers/import/relationship_worker.rb
+++ b/app/workers/import/relationship_worker.rb
@@ -11,7 +11,7 @@ class Import::RelationshipWorker
   def perform(account_id, target_account_uri, relationship, options)
     from_account   = Account.find(account_id)
     target_domain  = domain(target_account_uri)
-    target_account = stoplight_wrap_request(target_domain) { ResolveAccountService.new.call(target_account_uri, { check_delivery_availability: true }) }
+    target_account = stoplight_wrapper(target_domain).run { ResolveAccountService.new.call(target_account_uri, { check_delivery_availability: true }) }
     options.symbolize_keys!
 
     return if target_account.nil?
@@ -43,16 +43,15 @@ class Import::RelationshipWorker
     TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
   end
 
-  def stoplight_wrap_request(domain, &block)
+  def stoplight_wrapper(domain)
     if domain.present?
-      Stoplight("source:#{domain}", &block)
+      Stoplight("source:#{domain}")
         .with_fallback { nil }
         .with_threshold(1)
         .with_cool_off_time(5.minutes.seconds)
         .with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
-        .run
     else
-      yield
+      Stoplight('domain-blank')
     end
   end
 end
diff --git a/config/initializers/stoplight.rb b/config/initializers/stoplight.rb
index 72fe40600..7c13d5063 100644
--- a/config/initializers/stoplight.rb
+++ b/config/initializers/stoplight.rb
@@ -3,6 +3,6 @@
 require 'stoplight'
 
 Rails.application.reloader.to_prepare do
-  Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(RedisConfiguration.new.connection)
-  Stoplight::Light.default_notifiers  = [Stoplight::Notifier::Logger.new(Rails.logger)]
+  Stoplight.default_data_store = Stoplight::DataStore::Redis.new(RedisConfiguration.new.connection)
+  Stoplight.default_notifiers  = [Stoplight::Notifier::Logger.new(Rails.logger)]
 end
diff --git a/lib/paperclip/attachment_extensions.rb b/lib/paperclip/attachment_extensions.rb
index 7f82138aa..401da1129 100644
--- a/lib/paperclip/attachment_extensions.rb
+++ b/lib/paperclip/attachment_extensions.rb
@@ -84,13 +84,11 @@ module Paperclip
       # Don't go through Stoplight if we don't have anything object-storage-oriented to do
       return super if @queued_for_delete.empty? && @queued_for_write.empty? && !dirty?
 
-      Stoplight('object-storage') { super }.with_threshold(STOPLIGHT_THRESHOLD).with_cool_off_time(STOPLIGHT_COOLDOWN).with_error_handler do |error, handle|
-        if error.is_a?(Seahorse::Client::NetworkingError)
-          handle.call(error)
-        else
-          raise error
-        end
-      end.run
+      Stoplight('object-storage')
+        .with_threshold(STOPLIGHT_THRESHOLD)
+        .with_cool_off_time(STOPLIGHT_COOLDOWN)
+        .with_error_handler { |error, handle| error.is_a?(Seahorse::Client::NetworkingError) ? handle.call(error) : raise(error) }
+        .run { super }
     end
   end
 end

From f8b03c39254ad5c30ed0cf0ea7522e8a5114b38a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 15:48:27 +0000
Subject: [PATCH 078/173] Update dependency faker to v3.3.1 (#29829)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 2cebe0be8..702eb3958 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -245,7 +245,7 @@ GEM
       tzinfo
     excon (0.110.0)
     fabrication (2.31.0)
-    faker (3.3.0)
+    faker (3.3.1)
       i18n (>= 1.8.11, < 2)
     faraday (1.10.3)
       faraday-em_http (~> 1.0)

From d27eb181f6ab419d1745a1fe9b94094be17a618f Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 11:50:57 -0400
Subject: [PATCH 079/173] Reduce `LineLength` from 320 to 300 (#29636)

---
 .haml-lint.yml | 2 +-
 .rubocop.yml   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.haml-lint.yml b/.haml-lint.yml
index 2b553ca56..e493afb85 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -11,6 +11,6 @@ linters:
   MiddleDot:
     enabled: true
   LineLength:
-    max: 320
+    max: 300
   ViewLength:
     max: 200 # Override default value of 100 inherited from rubocop
diff --git a/.rubocop.yml b/.rubocop.yml
index 2aa72d9e5..7fb8ab0c5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -39,7 +39,7 @@ Layout/FirstHashElementIndentation:
 # Reason: Currently disabled in .rubocop_todo.yml
 # https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
 Layout/LineLength:
-  Max: 320 # Default of 120 causes a duplicate entry in generated todo file
+  Max: 300 # Default of 120 causes a duplicate entry in generated todo file
 
 ## Disable most Metrics/*Length cops
 # Reason: those are often triggered and force significant refactors when this happend

From 88c36648895b74b3432a4b8b30fe3820faa2ae3b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 19:00:07 +0200
Subject: [PATCH 080/173] Update dependency rubocop-performance to v1.21.0
 (#29804)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 702eb3958..acc439494 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -663,9 +663,9 @@ GEM
       rubocop (~> 1.41)
     rubocop-factory_bot (2.25.1)
       rubocop (~> 1.41)
-    rubocop-performance (1.20.2)
+    rubocop-performance (1.21.0)
       rubocop (>= 1.48.1, < 2.0)
-      rubocop-ast (>= 1.30.0, < 2.0)
+      rubocop-ast (>= 1.31.1, < 2.0)
     rubocop-rails (2.24.1)
       activesupport (>= 4.2.0)
       rack (>= 1.1)

From a7b637768e65046728e60bb8ffebff5ff3341ec7 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 2 Apr 2024 15:56:54 -0400
Subject: [PATCH 081/173] Regenerate rubocop todo with version 1.62.1 (#29830)

---
 .rubocop_todo.yml | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 11ac57083..ea1dbe57e 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
 # This configuration was generated by
 # `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
-# using RuboCop version 1.60.2.
+# using RuboCop version 1.62.1.
 # The point is for the user to remove these configuration records
 # one by one as the offenses are removed from the code base.
 # Note that changes in the inspected code, or installation of new
@@ -36,7 +36,7 @@ Metrics/PerceivedComplexity:
 
 # Configuration parameters: CountAsOne.
 RSpec/ExampleLength:
-  Max: 20 # Override default of 5
+  Max: 18
 
 RSpec/MultipleExpectations:
   Max: 7
@@ -88,7 +88,6 @@ Style/FetchEnvVar:
   Exclude:
     - 'app/lib/redis_configuration.rb'
     - 'app/lib/translation_service.rb'
-    - 'config/environments/development.rb'
     - 'config/environments/production.rb'
     - 'config/initializers/2_limited_federation_mode.rb'
     - 'config/initializers/3_omniauth.rb'
@@ -144,7 +143,6 @@ Style/GuardClause:
     - 'lib/mastodon/cli/accounts.rb'
     - 'lib/mastodon/cli/maintenance.rb'
     - 'lib/mastodon/cli/media.rb'
-    - 'lib/paperclip/attachment_extensions.rb'
     - 'lib/tasks/repo.rake'
 
 # This cop supports safe autocorrection (--autocorrect).

From 54c7d1ad144ada4765415739a3b48dc5e39de67f Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 23:22:22 +0200
Subject: [PATCH 082/173] Update dependency pg-connection-string to v2.6.4
 (#29814)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 99f6f99c6..bf79e9b8e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12795,9 +12795,9 @@ __metadata:
   linkType: hard
 
 "pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.6.3":
-  version: 2.6.3
-  resolution: "pg-connection-string@npm:2.6.3"
-  checksum: 10c0/e7eab3a2bb8dec5067fab8a46c90d8f7920946d46ad771a410de3929490c676ee91950424d4405295dd0fde5acbd39ccd99afd603a15d616d0a4a6fa9bf80ad7
+  version: 2.6.4
+  resolution: "pg-connection-string@npm:2.6.4"
+  checksum: 10c0/0d0b617df0fc6507bf6a94bdcd56c7a305788a1402d69bff9773350947c8f525d6d8136128065370749a3325e99658ae40fbdcce620fb8e60126181f0591a6a6
   languageName: node
   linkType: hard
 

From 4233ee1f59cfdeaeb96f060aff8bc0826b321e64 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 2 Apr 2024 23:33:43 +0200
Subject: [PATCH 083/173] Update dependency pg to v8.11.5 (#29833)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index bf79e9b8e..8af9bfdb8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12794,7 +12794,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.6.3":
+"pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.6.4":
   version: 2.6.4
   resolution: "pg-connection-string@npm:2.6.4"
   checksum: 10c0/0d0b617df0fc6507bf6a94bdcd56c7a305788a1402d69bff9773350947c8f525d6d8136128065370749a3325e99658ae40fbdcce620fb8e60126181f0591a6a6
@@ -12860,11 +12860,11 @@ __metadata:
   linkType: hard
 
 "pg@npm:^8.5.0":
-  version: 8.11.4
-  resolution: "pg@npm:8.11.4"
+  version: 8.11.5
+  resolution: "pg@npm:8.11.5"
   dependencies:
     pg-cloudflare: "npm:^1.1.1"
-    pg-connection-string: "npm:^2.6.3"
+    pg-connection-string: "npm:^2.6.4"
     pg-pool: "npm:^3.6.2"
     pg-protocol: "npm:^1.6.1"
     pg-types: "npm:^2.1.0"
@@ -12877,7 +12877,7 @@ __metadata:
   peerDependenciesMeta:
     pg-native:
       optional: true
-  checksum: 10c0/b3e473c52572be259a7418ee506a0ee9d66121971e73fe8cdf584addb9ef4d34cf66ea5c8a99ad9226c421d31a1848c39225bd201743ddd529276de1dec81e46
+  checksum: 10c0/20f29a41a99bad5931faf4d4a01e7be7fb27e5b5338fdfb06d2368e295c3d3d4ef49958ad57d2b17bad108e5c84574db6244ed8221e6b77a767f64ef12564119
   languageName: node
   linkType: hard
 

From 56d13069cdfc1d2a4211e40c0303d13514678681 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 3 Apr 2024 11:04:29 +0200
Subject: [PATCH 084/173] New Crowdin Translations (automated) (#29836)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/et.json  | 13 +++++++
 app/javascript/mastodon/locales/fil.json | 23 +++++++++++++
 app/javascript/mastodon/locales/ia.json  | 19 +++++++++++
 app/javascript/mastodon/locales/it.json  |  2 +-
 app/javascript/mastodon/locales/lt.json  |  4 +++
 app/javascript/mastodon/locales/nl.json  |  2 +-
 app/javascript/mastodon/locales/sq.json  |  3 ++
 app/javascript/mastodon/locales/sv.json  |  6 ++++
 config/locales/ia.yml                    | 43 ++++++++++++++++++++++++
 config/locales/sq.yml                    |  6 ++--
 10 files changed, 117 insertions(+), 4 deletions(-)

diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index 74f3f560d..eda209935 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -476,10 +476,13 @@
   "notification.relationships_severance_event.account_suspension": "{from} admin on kustutanud {target}, mis tähendab, et sa ei saa enam neilt uuendusi või suhelda nendega.",
   "notification.relationships_severance_event.domain_block": "{from} admin on blokeerinud {target}, sealhulgas {followersCount} sinu jälgijat ja {followingCount, plural, one  {# konto} other {# kontot}}, mida jälgid.",
   "notification.relationships_severance_event.learn_more": "Saa rohkem teada",
+  "notification.relationships_severance_event.user_domain_block": "Blokeerisid {target}, eemaldades oma jälgijate hulgast {followersCount} ja jälgitavate hulgast {followingCount, plural, one {# konto} other {# kontot}}.",
   "notification.status": "{name} just postitas",
   "notification.update": "{name} muutis postitust",
   "notification_requests.accept": "Nõus",
   "notification_requests.dismiss": "Hülga",
+  "notification_requests.notifications_from": "Teavitus kasutajalt {name}",
+  "notification_requests.title": "Filtreeritud teavitused",
   "notifications.clear": "Puhasta teated",
   "notifications.clear_confirmation": "Oled kindel, et soovid püsivalt kõik oma teated eemaldada?",
   "notifications.column_settings.admin.report": "Uued teavitused:",
@@ -515,6 +518,13 @@
   "notifications.permission_required": "Töölaua märguanded ei ole saadaval, kuna vajalik luba pole antud.",
   "notifications.policy.filter_new_accounts.hint": "Loodud viimase {days, plural, one {ühe päeva} other {# päeva}} jooksul",
   "notifications.policy.filter_new_accounts_title": "Uued kontod",
+  "notifications.policy.filter_not_followers_hint": "Kaasates kasutajad, kes on sind jälginud vähem kui {days, plural, one {ühe päeva} other {# päeva}}",
+  "notifications.policy.filter_not_followers_title": "Sind mittejälgivad kasutajad",
+  "notifications.policy.filter_not_following_hint": "Kuni sa nad käsitsi kinnitad",
+  "notifications.policy.filter_not_following_title": "Inimesed, keda sa ei jälgi",
+  "notifications.policy.filter_private_mentions_hint": "Filtreeritud, kui see pole vastus sinupoolt mainimisele või kui jälgid saatjat",
+  "notifications.policy.filter_private_mentions_title": "Soovimatud privaatsed mainimised",
+  "notifications.policy.title": "Filtreeri välja teavitused kohast…",
   "notifications_permission_banner.enable": "Luba töölaua märguanded",
   "notifications_permission_banner.how_to_control": "Et saada teateid, ajal mil Mastodon pole avatud, luba töölauamärguanded. Saad täpselt määrata, mis tüüpi tegevused tekitavad märguandeid, kasutates peale teadaannete sisse lülitamist üleval olevat nuppu {icon}.",
   "notifications_permission_banner.title": "Ära jää millestki ilma",
@@ -691,9 +701,11 @@
   "status.direct": "Maini privaatselt @{name}",
   "status.direct_indicator": "Privaatne mainimine",
   "status.edit": "Muuda",
+  "status.edited": "Viimati muudetud {date}",
   "status.edited_x_times": "Muudetud {count, plural, one{{count} kord} other {{count} korda}}",
   "status.embed": "Manustamine",
   "status.favourite": "Lemmik",
+  "status.favourites": "{count, plural, one {lemmik} other {lemmikud}}",
   "status.filter": "Filtreeri seda postitust",
   "status.filtered": "Filtreeritud",
   "status.hide": "Peida postitus",
@@ -714,6 +726,7 @@
   "status.reblog": "Jaga",
   "status.reblog_private": "Jaga algse nähtavusega",
   "status.reblogged_by": "{name} jagas",
+  "status.reblogs": "{count, plural, one {jagamine} other {jagamist}}",
   "status.reblogs.empty": "Keegi pole seda postitust veel jaganud. Kui keegi seda teeb, näeb seda siin.",
   "status.redraft": "Kustuta & alga uuesti",
   "status.remove_bookmark": "Eemalda järjehoidja",
diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json
index afa0e5fbc..894d73c8c 100644
--- a/app/javascript/mastodon/locales/fil.json
+++ b/app/javascript/mastodon/locales/fil.json
@@ -50,6 +50,7 @@
   "admin.dashboard.retention.cohort_size": "Mga bagong tagagamit",
   "alert.rate_limited.message": "Mangyaring subukan muli pagkatapos ng {retry_time, time, medium}.",
   "audio.hide": "Itago ang tunog",
+  "block_modal.title": "Harangan ang tagagamit?",
   "bundle_column_error.error.title": "Naku!",
   "bundle_column_error.network.body": "Nagkaroon ng kamalian habang sinusubukang i-karga ang pahinang ito. Maaaring dahil ito sa pansamantalang problema ng iyong koneksyon sa internet o ang server na ito.",
   "bundle_column_error.network.title": "Kamaliang network",
@@ -104,6 +105,7 @@
   "compose_form.poll.multiple": "Maraming pagpipilian",
   "compose_form.poll.single": "Piliin ang isa",
   "compose_form.reply": "Tumugon",
+  "compose_form.spoiler.marked": "Tanggalin ang babala sa nilalaman",
   "compose_form.spoiler.unmarked": "Idagdag ang babala sa nilalaman",
   "confirmation_modal.cancel": "Pagpaliban",
   "confirmations.block.confirm": "Harangan",
@@ -115,6 +117,7 @@
   "confirmations.discard_edit_media.confirm": "Ipagpaliban",
   "confirmations.edit.confirm": "Baguhin",
   "confirmations.reply.confirm": "Tumugon",
+  "conversation.mark_as_read": "Markahan bilang nabasa na",
   "copy_icon_button.copied": "Sinipi sa clipboard",
   "copypaste.copied": "Sinipi",
   "copypaste.copy_to_clipboard": "I-sipi sa clipboard",
@@ -130,6 +133,10 @@
   "dismissable_banner.explore_statuses": "Ito ang mga sumisikat na mga post sa iba't ibang bahagi ng social web ngayon. Ang mga mas bagong post na mas marami ang mga pagpapalakas at paborito ay tinataasan ng antas.",
   "dismissable_banner.explore_tags": "Ito ang mga sumisikat na mga hashtag sa iba't ibang bahagi ng social web ngayon. Ang mga hashtag ginagamit ng mas maraming mga iba't ibang tao ay tinataasan ng antas.",
   "dismissable_banner.public_timeline": "Ito ang mga pinakamakailang nakapublikong post mula sa mga taong nasa social web na sinusundan ng mga tao sa {domain}.",
+  "domain_block_modal.block": "Harangan ang serbiro",
+  "domain_block_modal.title": "Harangan ang domain?",
+  "domain_block_modal.you_will_lose_followers": "Mabubura ang iyong mga tagasunod mula sa serbirong ito.",
+  "domain_pill.server": "Serbiro",
   "embed.instructions": "I-embed ang post na ito sa iyong pook-sapot sa pamamagitan ng pagsipi ng kodigo sa ilalim.",
   "embed.preview": "Ito ang magiging itsura:",
   "emoji_button.activity": "Aktibidad",
@@ -166,6 +173,8 @@
   "empty_column.list": "Wala pang laman ang listahang ito. Kapag naglathala ng mga bagong post ang mga miyembro ng listahang ito, makikita iyon dito.",
   "empty_column.lists": "Wala ka pang mga listahan. Kapag gumawa ka ng isa, makikita yun dito.",
   "explore.search_results": "Mga resulta ng paghahanap",
+  "explore.title": "Tuklasin",
+  "explore.trending_links": "Mga balita",
   "filter_modal.select_filter.search": "Hanapin o gumawa",
   "firehose.all": "Lahat",
   "firehose.local": "Itong serbiro",
@@ -180,6 +189,7 @@
   "generic.saved": "Nakaimbak",
   "hashtag.column_header.tag_mode.all": "at {additional}",
   "hashtag.column_header.tag_mode.any": "o {additional}",
+  "home.column_settings.show_replies": "Ipakita ang mga tugon",
   "home.pending_critical_update.body": "Mangyaring i-update ang iyong serbiro ng Mastodon sa lalong madaling panahon!",
   "interaction_modal.login.action": "Iuwi mo ako",
   "interaction_modal.no_account_yet": "Wala sa Mastodon?",
@@ -216,14 +226,21 @@
   "notification.follow": "Sinundan ka ni {name}",
   "notification.follow_request": "Hinihiling ni {name} na sundan ka",
   "notification.mention": "Binanggit ka ni {name}",
+  "notification.relationships_severance_event.learn_more": "Matuto nang higit pa",
+  "notification_requests.accept": "Tanggapin",
+  "notification_requests.notifications_from": "Mga abiso mula kay/sa {name}",
   "notifications.clear": "Burahin mga abiso",
   "notifications.column_settings.admin.report": "Mga bagong ulat:",
+  "notifications.column_settings.alert": "Mga abiso sa Desktop",
   "notifications.column_settings.favourite": "Mga paborito:",
   "notifications.column_settings.follow": "Mga bagong tagasunod:",
   "notifications.column_settings.unread_notifications.category": "Hindi Nabasang mga Abiso",
   "notifications.column_settings.update": "Mga pagbago:",
   "notifications.filter.all": "Lahat",
+  "notifications.filter.favourites": "Mga paborito",
   "notifications.mark_as_read": "Markahan lahat ng abiso bilang nabasa na",
+  "notifications.policy.filter_not_followers_title": "Mga taong hindi ka susundan",
+  "notifications.policy.filter_not_following_title": "Mga taong hindi mo sinusundan",
   "onboarding.action.back": "Ibalik mo ako",
   "onboarding.actions.back": "Ibalik mo ako",
   "onboarding.profile.note_hint": "Maaari mong @bangitin ang ibang mga tao o mga #hashtag…",
@@ -236,6 +253,8 @@
   "privacy.direct.long": "Lahat ng mga binanggit sa post",
   "privacy.private.long": "Mga tagasunod mo lamang",
   "privacy.private.short": "Mga tagasunod",
+  "privacy.public.long": "Sinumang nasa loob at labas ng Mastodon",
+  "regeneration_indicator.label": "Kumakarga…",
   "relative_time.days": "{number}a",
   "relative_time.full.days": "{number, plural, one {# araw} other {# na araw}} ang nakalipas",
   "relative_time.full.hours": "{number, plural, one {# oras} other {# na oras}} ang nakalipas",
@@ -261,6 +280,10 @@
   "report.thanks.title": "Ayaw mo bang makita ito?",
   "report.thanks.title_actionable": "Salamat sa pag-uulat, titingnan namin ito.",
   "report_notification.categories.other": "Iba pa",
+  "search.quick_action.open_url": "Buksan ang URL sa Mastodon",
+  "search.search_or_paste": "Maghanap o ilagay ang URL",
+  "search_popout.full_text_search_disabled_message": "Hindi magagamit sa {domain}.",
+  "search_popout.full_text_search_logged_out_message": "Magagamit lamang kapag naka-log in.",
   "search_results.all": "Lahat",
   "search_results.see_all": "Ipakita lahat",
   "server_banner.learn_more": "Matuto nang higit pa",
diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index d982381c4..428abb8c5 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -159,8 +159,13 @@
   "disabled_account_banner.account_settings": "Parametros de conto",
   "disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.",
   "dismissable_banner.dismiss": "Dimitter",
+  "domain_block_modal.block": "Blocar le servitor",
+  "domain_block_modal.block_account_instead": "Blocar @{name} in su loco",
+  "domain_block_modal.they_cant_follow": "Nulle persona ab iste servitor pote sequer te.",
+  "domain_block_modal.they_wont_know": "Illes non sapera que illes ha essite blocate.",
   "domain_block_modal.title": "Blocar dominio?",
   "domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.",
+  "domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes ab usatores sur iste servitor.",
   "domain_pill.server": "Servitor",
   "domain_pill.username": "Nomine de usator",
   "embed.preview": "Ecce como illlo parera:",
@@ -202,6 +207,7 @@
   "filter_modal.select_filter.search": "Cercar o crear",
   "filter_modal.select_filter.title": "Filtrar iste message",
   "filter_modal.title.status": "Filtrar un message",
+  "filtered_notifications_banner.pending_requests": "Notificationes ab {count, plural, =0 {nemo} one {un persona} other {# personas}} tu poterea cognoscer",
   "firehose.all": "Toto",
   "firehose.local": "Iste servitor",
   "firehose.remote": "Altere servitores",
@@ -251,7 +257,9 @@
   "keyboard_shortcuts.federated": "Aperir le chronologia federate",
   "keyboard_shortcuts.heading": "Accessos directe de claviero",
   "keyboard_shortcuts.home": "Aperir le chronologia de initio",
+  "keyboard_shortcuts.legend": "Monstrar iste legenda",
   "keyboard_shortcuts.local": "Aperir le chronologia local",
+  "keyboard_shortcuts.mention": "Mentionar le author",
   "keyboard_shortcuts.muted": "Aperir lista de usatores silentiate",
   "keyboard_shortcuts.my_profile": "Aperir tu profilo",
   "keyboard_shortcuts.notifications": "Aperir columna de notificationes",
@@ -264,6 +272,8 @@
   "lightbox.close": "Clauder",
   "lightbox.next": "Sequente",
   "lightbox.previous": "Precedente",
+  "limited_account_hint.action": "Monstrar profilo in omne caso",
+  "limited_account_hint.title": "Iste profilo esseva celate per le moderatores de {domain}.",
   "link_preview.author": "Per {name}",
   "lists.account.add": "Adder al lista",
   "lists.account.remove": "Remover del lista",
@@ -278,8 +288,13 @@
   "lists.subheading": "Tu listas",
   "loading_indicator.label": "Cargante…",
   "media_gallery.toggle_visible": "{number, plural, one {Celar imagine} other {Celar imagines}}",
+  "mute_modal.hide_from_notifications": "Celar ab notificationes",
   "mute_modal.hide_options": "Celar optiones",
+  "mute_modal.show_options": "Monstrar optiones",
+  "mute_modal.they_can_mention_and_follow": "Illes pote mentionar te e sequer te, ma tu non potera vider los.",
+  "mute_modal.they_wont_know": "Illes non sapera que illes ha essite silentiate.",
   "mute_modal.title": "Silentiar le usator?",
+  "mute_modal.you_wont_see_mentions": "Tu non videra messages que los mentiona.",
   "navigation_bar.about": "A proposito",
   "navigation_bar.advanced_interface": "Aperir in le interfacie web avantiate",
   "navigation_bar.blocks": "Usatores blocate",
@@ -304,7 +319,10 @@
   "notification.own_poll": "Tu sondage ha finite",
   "notification.relationships_severance_event.learn_more": "Apprender plus",
   "notification.update": "{name} ha modificate un message",
+  "notification_requests.accept": "Acceptar",
+  "notification_requests.dismiss": "Dimitter",
   "notification_requests.notifications_from": "Notificationes de {name}",
+  "notification_requests.title": "Notificationes filtrate",
   "notifications.clear": "Rader notificationes",
   "notifications.clear_confirmation": "Es tu secur que tu vole rader permanentemente tote tu notificationes?",
   "notifications.column_settings.alert": "Notificationes de scriptorio",
@@ -325,6 +343,7 @@
   "notifications.filter.statuses": "Actualisationes de personas que tu seque",
   "notifications.grant_permission": "Conceder permission.",
   "notifications.group": "{count} notificationes",
+  "notifications.mark_as_read": "Marcar cata notification como legite",
   "notifications.policy.filter_new_accounts_title": "Nove contos",
   "notifications_permission_banner.enable": "Activar notificationes de scriptorio",
   "onboarding.compose.template": "Salute #Mastodon!",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index d7e447626..fd12ee298 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -354,7 +354,7 @@
   "interaction_modal.description.follow": "Con un profilo di Mastodon, puoi seguire {name} per ricevere i suoi post nel feed della tua home.",
   "interaction_modal.description.reblog": "Con un profilo di Mastodon, puoi rebloggare questo post per condividerlo con i tuoi seguaci.",
   "interaction_modal.description.reply": "Con un profilo di Mastodon, puoi rispondere a questo post.",
-  "interaction_modal.login.action": "Torna all’inizio",
+  "interaction_modal.login.action": "Portami alla pagina iniziale",
   "interaction_modal.login.prompt": "Dominio del tuo server principale, ad esempio mastodon.social",
   "interaction_modal.no_account_yet": "Non su Mastodon?",
   "interaction_modal.on_another_server": "Su un altro server",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index f9ef7e242..b43af3c0a 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -442,6 +442,8 @@
   "notification.own_poll": "Tavo apklausa baigėsi",
   "notification.poll": "Apklausa, kurioje balsavai, pasibaigė",
   "notification.reblog": "{name} pakėlė tavo įrašą",
+  "notification.relationships_severance_event.learn_more": "Sužinoti daugiau",
+  "notification.relationships_severance_event.user_domain_block": "Tu užblokavai {target}. Pašalinama {followersCount} savo sekėjų ir {followingCount, plural, one {# paskyrą} few {# paskyrai} many {# paskyros} other {# paskyrų}}, kurios seki.",
   "notification.status": "{name} ką tik paskelbė",
   "notification.update": "{name} redagavo įrašą",
   "notification_requests.accept": "Priimti",
@@ -454,6 +456,8 @@
   "notifications.column_settings.admin.sign_up": "Naujos registracijos:",
   "notifications.column_settings.alert": "Darbalaukio pranešimai",
   "notifications.column_settings.favourite": "Mėgstami:",
+  "notifications.column_settings.filter_bar.advanced": "Rodyti visas kategorijas",
+  "notifications.column_settings.filter_bar.category": "Spartaus filtro juosta",
   "notifications.column_settings.follow": "Nauji sekėjai:",
   "notifications.column_settings.follow_request": "Nauji sekimo prašymai:",
   "notifications.column_settings.mention": "Paminėjimai:",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index c47831b38..23960e9f8 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -705,7 +705,7 @@
   "status.edited_x_times": "{count, plural, one {{count} keer} other {{count} keer}} bewerkt",
   "status.embed": "Embedden",
   "status.favourite": "Favoriet",
-  "status.favourites": "{count, plural, one {# favoriet} other {# favorieten}}",
+  "status.favourites": "{count, plural, one {favoriet} other {favorieten}}",
   "status.filter": "Dit bericht filteren",
   "status.filtered": "Gefilterd",
   "status.hide": "Bericht verbergen",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 026e19820..95768b811 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Përdorni një kategori ekzistuese, ose krijoni një të re",
   "filter_modal.select_filter.title": "Filtroje këtë postim",
   "filter_modal.title.status": "Filtroni një postim",
+  "filtered_notifications_banner.pending_requests": "Njoftime prej {count, plural, =0 {askujt} one {një personi} other {# vetësh}} që mund të njihni",
   "filtered_notifications_banner.private_mentions": "{count, plural, one {përmendje private} other {përmendje private}}",
   "filtered_notifications_banner.title": "Njoftime të filtruar",
   "firehose.all": "Krejt",
@@ -515,7 +516,9 @@
   "notifications.permission_denied": "S’merren dot njoftime në desktop, ngaqë më herët shfletuesit i janë mohuar lejet për këtë",
   "notifications.permission_denied_alert": "S’mund të aktivizohen njoftimet në desktop, ngaqë lejet e shfletuesit për këtë janë mohuar më herët",
   "notifications.permission_required": "S’merren dot njoftime desktop, ngaqë s’është akorduar leja përkatëse.",
+  "notifications.policy.filter_new_accounts.hint": "Krijuar brenda {days, plural, one {një dite} other {# ditësh}} të shkuara",
   "notifications.policy.filter_new_accounts_title": "Llogari të reja",
+  "notifications.policy.filter_not_followers_hint": "Përfshi persona që ju kanë ndjekur brenda më pak se {days, plural, one {një dite} other {# ditësh}}",
   "notifications.policy.filter_not_followers_title": "Persona që s’ju ndjekin",
   "notifications.policy.filter_not_following_hint": "Deri sa t’i miratoni dorazi",
   "notifications.policy.filter_not_following_title": "Persona që s’i ndiqni",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 85511df8c..46a6cb794 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -476,6 +476,7 @@
   "notification.relationships_severance_event.account_suspension": "En administratör från {from} har stängt av {target}, vilket innebär att du inte längre kan ta emot uppdateringar från dem eller interagera med dem.",
   "notification.relationships_severance_event.domain_block": "En administratör från {from} har blockerat {target}, inklusive {followersCount} av dina följare och {followingCount, plural, one {# konto} other {# konton}} du följer.",
   "notification.relationships_severance_event.learn_more": "Läs mer",
+  "notification.relationships_severance_event.user_domain_block": "Du har blockerat {target} och tar därmed bort {followersCount} av dina följare samt {followingCount, plural, one {# konto} other {# konton}} du följer.",
   "notification.status": "{name} publicerade just ett inlägg",
   "notification.update": "{name} redigerade ett inlägg",
   "notification_requests.accept": "Godkänn",
@@ -489,6 +490,7 @@
   "notifications.column_settings.alert": "Skrivbordsaviseringar",
   "notifications.column_settings.favourite": "Favoriter:",
   "notifications.column_settings.filter_bar.advanced": "Visa alla kategorier",
+  "notifications.column_settings.filter_bar.category": "Snabbfilter",
   "notifications.column_settings.follow": "Nya följare:",
   "notifications.column_settings.follow_request": "Ny följ-förfrågan:",
   "notifications.column_settings.mention": "Omnämningar:",
@@ -516,8 +518,11 @@
   "notifications.permission_required": "Skrivbordsaviseringar är otillgängliga eftersom att rättigheten som krävs inte har godkänts.",
   "notifications.policy.filter_new_accounts.hint": "Skapad inom de senaste {days, plural, one {dagen} other {# dagarna}}",
   "notifications.policy.filter_new_accounts_title": "Nya konton",
+  "notifications.policy.filter_not_followers_hint": "Inklusive personer som har följt dig kortare än {days, plural, one {en dag} other {# dagar}}",
   "notifications.policy.filter_not_followers_title": "Personer som inte följer dig",
+  "notifications.policy.filter_not_following_hint": "Tills du manuellt godkänner dem",
   "notifications.policy.filter_not_following_title": "Personer du inte följer",
+  "notifications.policy.filter_private_mentions_hint": "Filtrerat om det inte är som svar på ditt eget omnämnande eller om du följer avsändaren",
   "notifications.policy.filter_private_mentions_title": "Oombedda privata omnämnanden",
   "notifications.policy.title": "Filtrera ut aviseringar från…",
   "notifications_permission_banner.enable": "Aktivera skrivbordsaviseringar",
@@ -721,6 +726,7 @@
   "status.reblog": "Boosta",
   "status.reblog_private": "Boosta med ursprunglig synlighet",
   "status.reblogged_by": "{name} boostade",
+  "status.reblogs": "{count, plural, one {# röst} other {# röster}}",
   "status.reblogs.empty": "Ingen har boostat detta inlägg än. När någon gör det kommer de synas här.",
   "status.redraft": "Radera & gör om",
   "status.remove_bookmark": "Ta bort bokmärke",
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index ecdf73ef9..5065ca7bb 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -15,17 +15,40 @@ ia:
     instance_actor_flash: Iste conto es un agente virtual usate pro representar le servitor mesme e non alcun usator individual. Illo es usate pro le federation e non debe esser suspendite.
     last_active: ultime activitate
     link_verified_on: Le proprietate de iste ligamine ha essite verificate le %{date}
+    posts:
+      one: Message
+      other: Messages
+    posts_tab_heading: Messages
   admin:
+    account_moderation_notes:
+      create: Lassar un nota
     accounts:
+      add_email_domain_block: Blocar dominio de e-mail
       are_you_sure: Es tu secur?
       by_domain: Dominio
+      change_email:
+        changed_msg: Email cambiate con successo!
+        current_email: E-mail actual
+        label: Cambiar e-mail
+        new_email: Nove e-mail
+        submit: Cambiar e-mail
+        title: Cambiar e-mail pro %{username}
+      confirm: Confirmar
+      confirmed: Confirmate
+      confirming: In confirmation
       custom: Personalisate
       delete: Deler datos
       deleted: Delite
+      demote: Degradar
+      destroyed_msg: Le datos de %{username} ora es in cauda pro su imminente deletion
       disable_two_factor_authentication: Disactivar 2FA
       display_name: Nomine visibile
       domain: Dominio
+      edit: Modificar
+      email: E-mail
+      email_status: Stato de e-mail
       enabled: Activate
+      followers: Sequitores
       location:
         all: Toto
         title: Location
@@ -34,31 +57,50 @@ ia:
       most_recent_activity: Activitate plus recente
       most_recent_ip: IP plus recente
       public: Public
+      redownload: Actualisar profilo
+      resend_confirmation:
+        already_confirmed: Iste usator jam es confirmate
+        send: Reinviar ligamine de confirmation
+        success: Ligamine de confirmation inviate con successo!
       reset: Reinitialisar
       reset_password: Reinitialisar contrasigno
       search: Cercar
+      search_same_email_domain: Altere usatores con le mesme dominio de e-mail
+      search_same_ip: Altere usatores con le mesme IP
       security: Securitate
       security_measures:
         only_password: Solmente contrasigno
         password_and_2fa: Contrasigno e 2FA
+      silenced: Limitate
       statuses: Messages
+      subscribe: Subscriber
       title: Contos
+      unblock_email: Disblocar adresse de e-mail
+      unblocked_email_msg: Adresse de e-mail de %{username} disblocate con successo
+      unconfirmed_email: E-mail non confirmate
       username: Nomine de usator
+      view_domain: Vider summario de dominio
     action_logs:
       action_types:
+        confirm_user: Confirmar le usator
         create_announcement: Crear annuncio
         destroy_ip_block: Deler le regula IP
         destroy_status: Deler le message
         destroy_unavailable_domain: Deler le dominio non disponibile
+        disable_2fa_user: Disactivar 2FA
         disable_user: Disactivar le usator
         enable_user: Activar le usator
         reset_password_user: Reinitialisar contrasigno
         update_announcement: Actualisar annuncio
         update_custom_emoji: Actualisar emoji personalisate
+        update_ip_block: Actualisar le regula IP
+        update_status: Actualisar le message
       actions:
         change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}"
         create_announcement_html: "%{name} creava un nove annuncio %{target}"
+      deleted_account: conto delite
     announcements:
+      destroyed_msg: Annuncio delite con successo!
       edit:
         title: Modificar annuncio
       empty: Necun annuncios trovate.
@@ -80,6 +122,7 @@ ia:
       enabled_msg: Emoji activate con successo
       new:
         title: Adder nove emoji personalisate
+      upload: Incargar
     dashboard:
       active_users: usatores active
       media_storage: Immagazinage de medios
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 12627434a..dcacb46bf 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -844,10 +844,10 @@ sq:
       elasticsearch_index_mismatch:
         message_html: Përshoqërimet e treguesit të Elasticsearch-it janë të vjetruara. Ju lutemi, xhironi <code>tootctl search deploy --only=%{value}</code>
       elasticsearch_preset:
-        action: Shihni documentimin
+        action: Shihni dokumentimin
         message_html: Grupi i instancave tuaja Elasticsearch ka më shumë se një nyjë, por Mastodon-i s’është formësuar t’i përdorë ato.
       elasticsearch_preset_single_node:
-        action: Shihni documentimin
+        action: Shihni dokumentimin
         message_html: Grupi i instancave tuaja Elasticsearch ka vetëm një nyjë, <code>ES_PRESET</code> i duhet dhënë vlera <code>single_node_cluster</code>.
       elasticsearch_reset_chewy:
         message_html: Treguesi juaj i sistemit Elasticsearch është i vjetruar, për shkak të një ndryshimi rregullimesh. Për ta përditësuar, ju lutemi, xhironi <code>tootctl search deploy --reset-chewy</code>.
@@ -1666,6 +1666,8 @@ sq:
       account_suspension: Pezullim llogarie (%{target_name})
       domain_block: Pezullim shërbyesi (%{target_name})
       user_domain_block: Bllokuat %{target_name}
+    lost_followers: Ndjekës të humbur
+    lost_follows: Ndjekje të humbura
     preamble: Mund të humbni ndjekje dhe ndjekës, kur bllokoni një përkatësi, ose kur moderatorët tuaj vendosin të pezullojnë një shërbyes të largët. Kur kjo ndodh, do të jeni në gjendje të shkarkoni lista marrëdhëniesh të dëmtuara, për t’i shqyrtuar dhe mundet për t’i importuar në një shërbyes tjetër.
     purged: Hollësitë rreth këtij shërbyesi janë spastuar nga përgjegjësit e shërbyesit tuaj.
     type: Akt

From 5d67247061770bb4228c479dd03845735b849e3a Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Wed, 3 Apr 2024 09:22:50 -0500
Subject: [PATCH 085/173] Fix language and emoji search field background colors
 on light theme (#29828)

---
 app/javascript/styles/mastodon-light/diff.scss | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss
index 1de90e001..07e9d9868 100644
--- a/app/javascript/styles/mastodon-light/diff.scss
+++ b/app/javascript/styles/mastodon-light/diff.scss
@@ -477,10 +477,7 @@ html {
   color: $white;
 }
 
-.compose-form,
-.spoiler-input__input,
-.search__input,
-.search__popout {
+.compose-form .spoiler-input__input {
   color: lighten($ui-highlight-color, 8%);
 }
 
@@ -488,6 +485,8 @@ html {
 .compose-form__highlightable,
 .search__input,
 .search__popout,
+.emoji-mart-search input,
+.language-dropdown__dropdown .emoji-mart-search input,
 .poll__option input[type='text'] {
   background: darken($ui-base-color, 10%);
 }

From e2844173499254bd5f460ca2c205d16de228db62 Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Wed, 3 Apr 2024 10:19:10 -0500
Subject: [PATCH 086/173] Fix blue border on emoji/language search in Safari &
 Chrome (#29832)

---
 app/javascript/styles/mastodon/emoji_picker.scss | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/app/javascript/styles/mastodon/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss
index 14ce6a14b..947385837 100644
--- a/app/javascript/styles/mastodon/emoji_picker.scss
+++ b/app/javascript/styles/mastodon/emoji_picker.scss
@@ -112,10 +112,9 @@
       border: 0;
     }
 
-    &::-moz-focus-inner,
     &:focus,
     &:active {
-      outline: 0 !important;
+      outline: none !important;
     }
 
     &::-webkit-search-cancel-button {

From 37d984b8bf19f86a8a371a97d8a1a000022448b3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 3 Apr 2024 20:05:39 +0200
Subject: [PATCH 087/173] Update eslint (non-major) (#29820)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renaud Chaput <renchap@gmail.com>
---
 .eslintrc.js                                  |   1 +
 .../mastodon/components/hashtag_bar.tsx       |   2 +-
 app/javascript/mastodon/uuid.ts               |   3 +-
 app/javascript/packs/admin.tsx                |   2 +-
 app/javascript/packs/public.tsx               |   8 +-
 yarn.lock                                     | 108 +++++++++---------
 6 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/.eslintrc.js b/.eslintrc.js
index 502b9cefe..759003b55 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -363,6 +363,7 @@ module.exports = defineConfig({
             "message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
           }
         ],
+        "@typescript-eslint/restrict-template-expressions": ['warn', { allowNumber: true }],
         'jsdoc/require-jsdoc': 'off',
 
         // Those rules set stricter rules for TS files
diff --git a/app/javascript/mastodon/components/hashtag_bar.tsx b/app/javascript/mastodon/components/hashtag_bar.tsx
index 91fa92219..ed5de7d3a 100644
--- a/app/javascript/mastodon/components/hashtag_bar.tsx
+++ b/app/javascript/mastodon/components/hashtag_bar.tsx
@@ -24,7 +24,7 @@ export type StatusLike = Record<{
 
 function normalizeHashtag(hashtag: string) {
   return (
-    hashtag && hashtag.startsWith('#') ? hashtag.slice(1) : hashtag
+    !!hashtag && hashtag.startsWith('#') ? hashtag.slice(1) : hashtag
   ).normalize('NFKC');
 }
 
diff --git a/app/javascript/mastodon/uuid.ts b/app/javascript/mastodon/uuid.ts
index 4d0a8a803..0b4d55beb 100644
--- a/app/javascript/mastodon/uuid.ts
+++ b/app/javascript/mastodon/uuid.ts
@@ -4,5 +4,6 @@ export function uuid(a?: string): string {
         (a as unknown as number) ^
         ((Math.random() * 16) >> ((a as unknown as number) / 4))
       ).toString(16)
-    : ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
+    : // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
+      ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
 }
diff --git a/app/javascript/packs/admin.tsx b/app/javascript/packs/admin.tsx
index 9fee56056..225cb1633 100644
--- a/app/javascript/packs/admin.tsx
+++ b/app/javascript/packs/admin.tsx
@@ -363,6 +363,6 @@ ready(() => {
   document.querySelectorAll('[data-admin-component]').forEach((element) => {
     void mountReactComponent(element);
   });
-}).catch((reason) => {
+}).catch((reason: unknown) => {
   throw reason;
 });
diff --git a/app/javascript/packs/public.tsx b/app/javascript/packs/public.tsx
index 044faeb29..d45927226 100644
--- a/app/javascript/packs/public.tsx
+++ b/app/javascript/packs/public.tsx
@@ -69,7 +69,7 @@ window.addEventListener('message', (e) => {
       },
       '*',
     );
-  }).catch((e) => {
+  }).catch((e: unknown) => {
     console.error('Error in setHeightMessage postMessage', e);
   });
 });
@@ -206,7 +206,7 @@ function loaded() {
 
         return true;
       })
-      .catch((error) => {
+      .catch((error: unknown) => {
         console.error(error);
       });
   }
@@ -448,7 +448,7 @@ Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => {
 });
 
 function main() {
-  ready(loaded).catch((error) => {
+  ready(loaded).catch((error: unknown) => {
     console.error(error);
   });
 }
@@ -457,6 +457,6 @@ loadPolyfills()
   .then(loadLocale)
   .then(main)
   .then(loadKeyboardExtensions)
-  .catch((error) => {
+  .catch((error: unknown) => {
     console.error(error);
   });
diff --git a/yarn.lock b/yarn.lock
index 8af9bfdb8..4475cbc5e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4028,14 +4028,14 @@ __metadata:
   linkType: hard
 
 "@typescript-eslint/eslint-plugin@npm:^7.0.0":
-  version: 7.1.1
-  resolution: "@typescript-eslint/eslint-plugin@npm:7.1.1"
+  version: 7.5.0
+  resolution: "@typescript-eslint/eslint-plugin@npm:7.5.0"
   dependencies:
     "@eslint-community/regexpp": "npm:^4.5.1"
-    "@typescript-eslint/scope-manager": "npm:7.1.1"
-    "@typescript-eslint/type-utils": "npm:7.1.1"
-    "@typescript-eslint/utils": "npm:7.1.1"
-    "@typescript-eslint/visitor-keys": "npm:7.1.1"
+    "@typescript-eslint/scope-manager": "npm:7.5.0"
+    "@typescript-eslint/type-utils": "npm:7.5.0"
+    "@typescript-eslint/utils": "npm:7.5.0"
+    "@typescript-eslint/visitor-keys": "npm:7.5.0"
     debug: "npm:^4.3.4"
     graphemer: "npm:^1.4.0"
     ignore: "npm:^5.2.4"
@@ -4048,25 +4048,25 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/041799604176bbee01f6ff029c5e2fcf1196db2737ba219a20b095f095dc0064ea425d15dd6dc22eaef294daa838209601ec7bc19317258dfa89a13afb8126ba
+  checksum: 10c0/932a7b5a09c0138ef5a0bf00f8e6039fa209d4047092ffc187de048543c21f7ce24dc14f25f4c87b6f3bbb62335fc952e259e271fde88baf793217bde6460cfa
   languageName: node
   linkType: hard
 
 "@typescript-eslint/parser@npm:^7.0.0":
-  version: 7.1.1
-  resolution: "@typescript-eslint/parser@npm:7.1.1"
+  version: 7.5.0
+  resolution: "@typescript-eslint/parser@npm:7.5.0"
   dependencies:
-    "@typescript-eslint/scope-manager": "npm:7.1.1"
-    "@typescript-eslint/types": "npm:7.1.1"
-    "@typescript-eslint/typescript-estree": "npm:7.1.1"
-    "@typescript-eslint/visitor-keys": "npm:7.1.1"
+    "@typescript-eslint/scope-manager": "npm:7.5.0"
+    "@typescript-eslint/types": "npm:7.5.0"
+    "@typescript-eslint/typescript-estree": "npm:7.5.0"
+    "@typescript-eslint/visitor-keys": "npm:7.5.0"
     debug: "npm:^4.3.4"
   peerDependencies:
     eslint: ^8.56.0
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/84eb44f3767aaa1d7b26176348c89bd6732bc711f7f24186b1354eba95bf9e9c65b5675838772b831391210e525ff1f3bd4b51a3130ec35413aa362920effc57
+  checksum: 10c0/65521202ff024e79594272fbb7e4731ecf9d2fdd2f58fc81450bfd2bca94ce9c17b0eadd7338c01701f5cf16d38b6c025ed3fc322380b1e4b5424b7484098cda
   languageName: node
   linkType: hard
 
@@ -4080,22 +4080,22 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/scope-manager@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/scope-manager@npm:7.1.1"
+"@typescript-eslint/scope-manager@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/scope-manager@npm:7.5.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.1.1"
-    "@typescript-eslint/visitor-keys": "npm:7.1.1"
-  checksum: 10c0/a955c8529f24945d448b95982d06b5f15a74fc5df97307f5821d55e9861d6c26d61cbd118c1ca41634164ed1d4f6c74fcb8388761341c49e6902a6fb72036afc
+    "@typescript-eslint/types": "npm:7.5.0"
+    "@typescript-eslint/visitor-keys": "npm:7.5.0"
+  checksum: 10c0/a017b151a6b39ef591f8e2e65598e005e1b4b2d5494e4b91bddb5856b3a4d57dd8a58d2bc7a140e627eb574f93a2c8fe55f1307aa264c928ffd31d9e190bc5dd
   languageName: node
   linkType: hard
 
-"@typescript-eslint/type-utils@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/type-utils@npm:7.1.1"
+"@typescript-eslint/type-utils@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/type-utils@npm:7.5.0"
   dependencies:
-    "@typescript-eslint/typescript-estree": "npm:7.1.1"
-    "@typescript-eslint/utils": "npm:7.1.1"
+    "@typescript-eslint/typescript-estree": "npm:7.5.0"
+    "@typescript-eslint/utils": "npm:7.5.0"
     debug: "npm:^4.3.4"
     ts-api-utils: "npm:^1.0.1"
   peerDependencies:
@@ -4103,7 +4103,7 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/6f19dc383718cce42ed7262d134f5f0221bcbf225fea28975cd714c90e57d861608d5187c7ad731f6281813f94b00f22282a99a8a852167366064abc6e256341
+  checksum: 10c0/12915d4d1872638f5281e222a0d191676c478f250699c84864862e95a59e708222acefbf7ffdafc0872a007261219a3a2b1e667ff45eeafea7c4bcc5b955262c
   languageName: node
   linkType: hard
 
@@ -4114,10 +4114,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/types@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/types@npm:7.1.1"
-  checksum: 10c0/2bef95ec0c60e67fada336db3e82fac2be16c21a9e54fc45c7aeda3291abcceefa12aa970025db88bc2b3e113b1e70abd7f89c2a651c16b816dff1a0c46e7907
+"@typescript-eslint/types@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/types@npm:7.5.0"
+  checksum: 10c0/f3394f71f422dbd89f63b230f20e9769c12e47a287ff30ca03a80714e57ea21279b6f12a8ab14bafb00b59926f20a88894b2d1e72679f7ff298bae112679d4b3
   languageName: node
   linkType: hard
 
@@ -4140,12 +4140,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/typescript-estree@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/typescript-estree@npm:7.1.1"
+"@typescript-eslint/typescript-estree@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/typescript-estree@npm:7.5.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.1.1"
-    "@typescript-eslint/visitor-keys": "npm:7.1.1"
+    "@typescript-eslint/types": "npm:7.5.0"
+    "@typescript-eslint/visitor-keys": "npm:7.5.0"
     debug: "npm:^4.3.4"
     globby: "npm:^11.1.0"
     is-glob: "npm:^4.0.3"
@@ -4155,24 +4155,24 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/2cec9d21cfe46e523a6d29aff554e5450edf1ee30ce9cf644ee8f1f5e1cfd44b94afb3632db97a949c86c4a392ae80f264d56d8747b2b0fdbe5c54139433366a
+  checksum: 10c0/ea3a270c725d6be273188b86110e0393052cd64d1c54a56eb5ea405e6d3fbbe84fb3b1ce1b8496a4078ac1eefd37aedcf12be91876764f6de31d5aa5131c7bcd
   languageName: node
   linkType: hard
 
-"@typescript-eslint/utils@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/utils@npm:7.1.1"
+"@typescript-eslint/utils@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/utils@npm:7.5.0"
   dependencies:
     "@eslint-community/eslint-utils": "npm:^4.4.0"
     "@types/json-schema": "npm:^7.0.12"
     "@types/semver": "npm:^7.5.0"
-    "@typescript-eslint/scope-manager": "npm:7.1.1"
-    "@typescript-eslint/types": "npm:7.1.1"
-    "@typescript-eslint/typescript-estree": "npm:7.1.1"
+    "@typescript-eslint/scope-manager": "npm:7.5.0"
+    "@typescript-eslint/types": "npm:7.5.0"
+    "@typescript-eslint/typescript-estree": "npm:7.5.0"
     semver: "npm:^7.5.4"
   peerDependencies:
     eslint: ^8.56.0
-  checksum: 10c0/3e70834c5b49e4643ec8da63fa2acaab54283a566af2cedcd4c2f4210833a59bf71c459dde69e738115633c7de9f1339130552ff246e8e1bb4db26910685408b
+  checksum: 10c0/c815ed6909769648953d6963c069038f7cac0c979051b25718feb30e0d3337b9647b75b8de00ac03fe960f0cc8dc4e8a81d4aac4719090a99785e0068712bd24
   languageName: node
   linkType: hard
 
@@ -4203,13 +4203,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/visitor-keys@npm:7.1.1":
-  version: 7.1.1
-  resolution: "@typescript-eslint/visitor-keys@npm:7.1.1"
+"@typescript-eslint/visitor-keys@npm:7.5.0":
+  version: 7.5.0
+  resolution: "@typescript-eslint/visitor-keys@npm:7.5.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.1.1"
+    "@typescript-eslint/types": "npm:7.5.0"
     eslint-visitor-keys: "npm:^3.4.1"
-  checksum: 10c0/1ab19ec966ff0b86317eddcbfcda645856ec01c3b76a451298031f35e4da0a363e4888ce5ae9e2526e874799a502c49922d83d57d21cb6fef7f3912f51e4a271
+  checksum: 10c0/eecf02b8dd54e83738a143aca87b902af4b357028a90fd34ed7a2f40a3ae2f6a188b9ba53903f23c80e868f1fffbb039e9ddb63525438d659707cc7bfb269317
   languageName: node
   linkType: hard
 
@@ -7793,8 +7793,8 @@ __metadata:
   linkType: hard
 
 "eslint-plugin-jsdoc@npm:^48.0.0":
-  version: 48.2.1
-  resolution: "eslint-plugin-jsdoc@npm:48.2.1"
+  version: 48.2.2
+  resolution: "eslint-plugin-jsdoc@npm:48.2.2"
   dependencies:
     "@es-joy/jsdoccomment": "npm:~0.42.0"
     are-docs-informative: "npm:^0.0.2"
@@ -7807,7 +7807,7 @@ __metadata:
     spdx-expression-parse: "npm:^4.0.0"
   peerDependencies:
     eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
-  checksum: 10c0/92237f08b7dadb21f9eda50eda00bf69ac5e0bfcb9d179bf118e096178d7dc4a62b34fd01b3b7b0ba1142ff6e13814cfe2cf9a60c6cfcc879559b6b509d0d4e1
+  checksum: 10c0/d6911e73d36757de5aef127e795116fbbcdef504f7e91d9c0863faf0b1693271d96188f0f1d54c0d74c56652bfa3fb4f1aa1a2f0876b0c6a5e57a874bcb3ac2b
   languageName: node
   linkType: hard
 
@@ -7856,8 +7856,8 @@ __metadata:
   linkType: hard
 
 "eslint-plugin-react@npm:^7.33.2":
-  version: 7.34.0
-  resolution: "eslint-plugin-react@npm:7.34.0"
+  version: 7.34.1
+  resolution: "eslint-plugin-react@npm:7.34.1"
   dependencies:
     array-includes: "npm:^3.1.7"
     array.prototype.findlast: "npm:^1.2.4"
@@ -7879,7 +7879,7 @@ __metadata:
     string.prototype.matchall: "npm:^4.0.10"
   peerDependencies:
     eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
-  checksum: 10c0/9bf0b959373ace66e799adbbfb493a7ceae54751e8f90fcce1da1a2a67b277ee23ba845571eaa4d4f05d96dba4e4977bf938b350f18bad26201fa616ee6aa4b8
+  checksum: 10c0/7c61b1314d37a4ac2f2474f9571f801f1a1a5d81dcd4abbb5d07145406518722fb792367267757ee116bde254be9753242d6b93c9619110398b3fe1746e4848c
   languageName: node
   linkType: hard
 

From cde3206478341d0723ff13d8600f1754fd61f650 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 3 Apr 2024 16:10:59 -0400
Subject: [PATCH 088/173] Simplify feature loop in welcome mailer (#29760)

---
 app/views/application/mailer/_feature.html.haml | 10 ++++------
 app/views/user_mailer/welcome.html.haml         |  8 ++++----
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/app/views/application/mailer/_feature.html.haml b/app/views/application/mailer/_feature.html.haml
index d051338a9..5facdd086 100644
--- a/app/views/application/mailer/_feature.html.haml
+++ b/app/views/application/mailer/_feature.html.haml
@@ -11,10 +11,8 @@
                 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
                   %tr
                     %td.email-column-td
-                      - if defined?(feature_title)
-                        %h2.email-h2= feature_title
-                      - if defined?(feature_text)
-                        %p.email-p= feature_text
+                      %h2.email-h2= t("user_mailer.welcome.feature_#{feature}_title")
+                      %p.email-p= t("user_mailer.welcome.feature_#{feature}")
                       - if defined?(feature_btn_url)
                         = link_to '', href: feature_btn_url, class: 'email-link-with-arrow' do
                           #{t('user_mailer.welcome.feature_action')} 
@@ -25,8 +23,8 @@
                 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
                   %tr
                     %td.email-column-td
-                      - if defined?(key)
+                      - if defined?(feature)
                         %p{ class: ('email-desktop-text-right' if defined?(text_first_on_desktop) && text_first_on_desktop) }
-                          = image_tag frontend_asset_url("images/mailer-new/welcome/#{key}.png"), alt: '', width: 240, height: 230
+                          = image_tag frontend_asset_url("images/mailer-new/welcome/feature_#{feature}.png"), alt: '', width: 240, height: 230
               /[if mso]
                 </td></tr></table>
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index 0e55707d3..97fb0a2c9 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -68,7 +68,7 @@
 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
   %tr
     %td.email-extra-td
-      = render 'application/mailer/feature', key: 'feature_control', feature_title: t('user_mailer.welcome.feature_control_title'), feature_text: t('user_mailer.welcome.feature_control'), text_first_on_desktop: true
-      = render 'application/mailer/feature', key: 'feature_audience', feature_title: t('user_mailer.welcome.feature_audience_title'), feature_text: t('user_mailer.welcome.feature_audience'), text_first_on_desktop: false
-      = render 'application/mailer/feature', key: 'feature_moderation', feature_title: t('user_mailer.welcome.feature_moderation_title'), feature_text: t('user_mailer.welcome.feature_moderation'), text_first_on_desktop: true
-      = render 'application/mailer/feature', key: 'feature_creativity', feature_title: t('user_mailer.welcome.feature_creativity_title'), feature_text: t('user_mailer.welcome.feature_creativity'), text_first_on_desktop: false
+      = render 'application/mailer/feature', feature: 'control', text_first_on_desktop: true
+      = render 'application/mailer/feature', feature: 'audience', text_first_on_desktop: false
+      = render 'application/mailer/feature', feature: 'moderation', text_first_on_desktop: true
+      = render 'application/mailer/feature', feature: 'creativity', text_first_on_desktop: false

From c6da3ee828ba2f8ddadfbb8b51a6fba90abc6824 Mon Sep 17 00:00:00 2001
From: nicolas <nclm@users.noreply.github.com>
Date: Wed, 3 Apr 2024 23:10:02 +0200
Subject: [PATCH 089/173] Makes the star icon rotate around its actual centre
 axis (#29844)

---
 app/javascript/styles/mastodon/components.scss | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index a49f162e3..e35b69623 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2244,14 +2244,14 @@ a.account__display-name {
   &.activate {
     & > .icon {
       animation: spring-rotate-in 1s linear;
-      transform-origin: 50% 55%;
+      transform-origin: 50% 52%;
     }
   }
 
   &.deactivate {
     & > .icon {
       animation: spring-rotate-out 1s linear;
-      transform-origin: 50% 55%;
+      transform-origin: 50% 52%;
     }
   }
 }

From 58dfc12af21f9b87e8c7c6bec2f5f28ab2bcca59 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 4 Apr 2024 09:23:53 +0200
Subject: [PATCH 090/173] Update babel monorepo to v7.24.4 (#29840)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 101 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 57 insertions(+), 44 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 4475cbc5e..3407619c8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -52,24 +52,24 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/compat-data@npm:7.24.1"
-  checksum: 10c0/8a1935450345c326b14ea632174696566ef9b353bd0d6fb682456c0774342eeee7654877ced410f24a731d386fdcbf980b75083fc764964d6f816b65792af2f5
+"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/compat-data@npm:7.24.4"
+  checksum: 10c0/9cd8a9cd28a5ca6db5d0e27417d609f95a8762b655e8c9c97fd2de08997043ae99f0139007083c5e607601c6122e8432c85fe391731b19bf26ad458fa0c60dd3
   languageName: node
   linkType: hard
 
 "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1":
-  version: 7.24.3
-  resolution: "@babel/core@npm:7.24.3"
+  version: 7.24.4
+  resolution: "@babel/core@npm:7.24.4"
   dependencies:
     "@ampproject/remapping": "npm:^2.2.0"
     "@babel/code-frame": "npm:^7.24.2"
-    "@babel/generator": "npm:^7.24.1"
+    "@babel/generator": "npm:^7.24.4"
     "@babel/helper-compilation-targets": "npm:^7.23.6"
     "@babel/helper-module-transforms": "npm:^7.23.3"
-    "@babel/helpers": "npm:^7.24.1"
-    "@babel/parser": "npm:^7.24.1"
+    "@babel/helpers": "npm:^7.24.4"
+    "@babel/parser": "npm:^7.24.4"
     "@babel/template": "npm:^7.24.0"
     "@babel/traverse": "npm:^7.24.1"
     "@babel/types": "npm:^7.24.0"
@@ -78,19 +78,19 @@ __metadata:
     gensync: "npm:^1.0.0-beta.2"
     json5: "npm:^2.2.3"
     semver: "npm:^6.3.1"
-  checksum: 10c0/e6e756b6de27d0312514a005688fa1915c521ad4269a388913eff2120a546538078f8488d6d16e86f851872f263cb45a6bbae08738297afb9382600d2ac342a9
+  checksum: 10c0/fc136966583e64d6f84f4a676368de6ab4583aa87f867186068655b30ef67f21f8e65a88c6d446a7efd219ad7ffb9185c82e8a90183ee033f6f47b5026641e16
   languageName: node
   linkType: hard
 
-"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.7.2":
-  version: 7.24.1
-  resolution: "@babel/generator@npm:7.24.1"
+"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4, @babel/generator@npm:^7.7.2":
+  version: 7.24.4
+  resolution: "@babel/generator@npm:7.24.4"
   dependencies:
     "@babel/types": "npm:^7.24.0"
     "@jridgewell/gen-mapping": "npm:^0.3.5"
     "@jridgewell/trace-mapping": "npm:^0.3.25"
     jsesc: "npm:^2.5.1"
-  checksum: 10c0/f0eea7497657cdf68cfb4b7d181588e1498eefd1f303d73b0d8ca9b21a6db27136a6f5beb8f988b6bdcd4249870826080950450fd310951de42ecf36df274881
+  checksum: 10c0/67a1b2f7cc985aaaa11b01e8ddd4fffa4f285837bc7a209738eb8203aa34bdafeb8507ed75fd883ddbabd641a036ca0a8d984e760f28ad4a9d60bff29d0a60bb
   languageName: node
   linkType: hard
 
@@ -135,9 +135,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/helper-create-class-features-plugin@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/helper-create-class-features-plugin@npm:7.24.1"
+"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/helper-create-class-features-plugin@npm:7.24.4"
   dependencies:
     "@babel/helper-annotate-as-pure": "npm:^7.22.5"
     "@babel/helper-environment-visitor": "npm:^7.22.20"
@@ -150,7 +150,7 @@ __metadata:
     semver: "npm:^6.3.1"
   peerDependencies:
     "@babel/core": ^7.0.0
-  checksum: 10c0/45372890634c37deefc81f44b7d958fe210f7da7d8a2239c9849c6041a56536f74bf3aa2d115bc06d5680d0dc49c1303f74a045d76ae0dd1592c7d5c0c268ebc
+  checksum: 10c0/6ebb38375dcd44c79f40008c2de4d023376cf436c135439f15c9c54603c2d6a8ada39b2e07be545da684d9e40b602a0cb0d1670f3877d056deb5f0d786c4bf86
   languageName: node
   linkType: hard
 
@@ -342,14 +342,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/helpers@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/helpers@npm:7.24.1"
+"@babel/helpers@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/helpers@npm:7.24.4"
   dependencies:
     "@babel/template": "npm:^7.24.0"
     "@babel/traverse": "npm:^7.24.1"
     "@babel/types": "npm:^7.24.0"
-  checksum: 10c0/b3445860ae749fc664682b291f092285e949114e8336784ae29f88eb4c176279b01cc6740005a017a0389ae4b4e928d5bbbc01de7da7e400c972e3d6f792063a
+  checksum: 10c0/747ef62b7fe87de31a2f3c19ff337a86cbb79be2f6c18af63133b614ab5a8f6da5b06ae4b06fb0e71271cb6a27efec6f8b6c9f44c60b8a18777832dc7929e6c5
   languageName: node
   linkType: hard
 
@@ -365,12 +365,24 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/parser@npm:7.24.1"
+"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1, @babel/parser@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/parser@npm:7.24.4"
   bin:
     parser: ./bin/babel-parser.js
-  checksum: 10c0/d2a8b99aa5f33182b69d5569367403a40e7c027ae3b03a1f81fd8ac9b06ceb85b31f6ee4267fb90726dc2ac99909c6bdaa9cf16c379efab73d8dfe85cee32c50
+  checksum: 10c0/8381e1efead5069cb7ed2abc3a583f4a86289b2f376c75cecc69f59a8eb36df18274b1886cecf2f97a6a0dff5334b27330f58535be9b3e4e26102cc50e12eac8
+  languageName: node
+  linkType: hard
+
+"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4"
+  dependencies:
+    "@babel/helper-environment-visitor": "npm:^7.22.20"
+    "@babel/helper-plugin-utils": "npm:^7.24.0"
+  peerDependencies:
+    "@babel/core": ^7.0.0
+  checksum: 10c0/9aed453a1a21e4fd29add0b4a2d82a2c6f43a47c80d28411f8327f2a714064bc93a6f622c701d263970e0d72d7901d28f7f51e91ba91a31306efe8f17c411182
   languageName: node
   linkType: hard
 
@@ -700,14 +712,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/plugin-transform-block-scoping@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/plugin-transform-block-scoping@npm:7.24.1"
+"@babel/plugin-transform-block-scoping@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/plugin-transform-block-scoping@npm:7.24.4"
   dependencies:
     "@babel/helper-plugin-utils": "npm:^7.24.0"
   peerDependencies:
     "@babel/core": ^7.0.0-0
-  checksum: 10c0/1a230ad95d9672626831e22df9b4838901681fa11d44c3811d71ca64ea53f5e87de2abef865f70fe62657053278d9034cc4ea3bab0fd3300bdf9e73b3f85f97a
+  checksum: 10c0/62f55fd1b60a115506e9553c3bf925179b1ab8a42dc31471c4e3ada20573a488b5c5e3317145da352493ef07f1d9750ce1f8a49cb3f39489ac1ab42e5ddc883d
   languageName: node
   linkType: hard
 
@@ -723,16 +735,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/plugin-transform-class-static-block@npm:^7.24.1":
-  version: 7.24.1
-  resolution: "@babel/plugin-transform-class-static-block@npm:7.24.1"
+"@babel/plugin-transform-class-static-block@npm:^7.24.4":
+  version: 7.24.4
+  resolution: "@babel/plugin-transform-class-static-block@npm:7.24.4"
   dependencies:
-    "@babel/helper-create-class-features-plugin": "npm:^7.24.1"
+    "@babel/helper-create-class-features-plugin": "npm:^7.24.4"
     "@babel/helper-plugin-utils": "npm:^7.24.0"
     "@babel/plugin-syntax-class-static-block": "npm:^7.14.5"
   peerDependencies:
     "@babel/core": ^7.12.0
-  checksum: 10c0/3095d02b7932890b82346d42200a89a56b6ca7d25a69a94242ab5b1772f18138b8e639358dd70d23add2df8b0d1640e1e13729c2c275ecce550cbe89048ba85f
+  checksum: 10c0/19dfeaf4a2ac03695034f7211a8b5ad89103b224608ac3e91791055107c5fe4d7ebe5d9fbb31b4a91265694af78762260642eb270f4b239c175984ee4b253f80
   languageName: node
   linkType: hard
 
@@ -1333,13 +1345,14 @@ __metadata:
   linkType: hard
 
 "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4":
-  version: 7.24.3
-  resolution: "@babel/preset-env@npm:7.24.3"
+  version: 7.24.4
+  resolution: "@babel/preset-env@npm:7.24.4"
   dependencies:
-    "@babel/compat-data": "npm:^7.24.1"
+    "@babel/compat-data": "npm:^7.24.4"
     "@babel/helper-compilation-targets": "npm:^7.23.6"
     "@babel/helper-plugin-utils": "npm:^7.24.0"
     "@babel/helper-validator-option": "npm:^7.23.5"
+    "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.4"
     "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1"
     "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1"
     "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1"
@@ -1366,9 +1379,9 @@ __metadata:
     "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3"
     "@babel/plugin-transform-async-to-generator": "npm:^7.24.1"
     "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1"
-    "@babel/plugin-transform-block-scoping": "npm:^7.24.1"
+    "@babel/plugin-transform-block-scoping": "npm:^7.24.4"
     "@babel/plugin-transform-class-properties": "npm:^7.24.1"
-    "@babel/plugin-transform-class-static-block": "npm:^7.24.1"
+    "@babel/plugin-transform-class-static-block": "npm:^7.24.4"
     "@babel/plugin-transform-classes": "npm:^7.24.1"
     "@babel/plugin-transform-computed-properties": "npm:^7.24.1"
     "@babel/plugin-transform-destructuring": "npm:^7.24.1"
@@ -1418,7 +1431,7 @@ __metadata:
     semver: "npm:^6.3.1"
   peerDependencies:
     "@babel/core": ^7.0.0-0
-  checksum: 10c0/abd6f3b6c6a71d4ff766cda5b51467677a811240d022492e651065e26ce1a8eb2067eabe5653fce80dda9c5c204fb7b89b419578d7e86eaaf7970929ee7b4885
+  checksum: 10c0/72a79d0cd38cb26f143509dd0c58db34b5b1ae90116863f55a404f0eb06a64a3cdcb1abd0b6435fafe463bbf55b82ffcf56aedee91e8d37797bf53e4ae74c413
   languageName: node
   linkType: hard
 
@@ -1483,11 +1496,11 @@ __metadata:
   linkType: hard
 
 "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
-  version: 7.24.1
-  resolution: "@babel/runtime@npm:7.24.1"
+  version: 7.24.4
+  resolution: "@babel/runtime@npm:7.24.4"
   dependencies:
     regenerator-runtime: "npm:^0.14.0"
-  checksum: 10c0/500c6a99ddd84f37c7bc5dbc84777af47b1372b20e879941670451d55484faf18a673c5ebee9ca2b0f36208a729417873b35b1b92e76f811620f6adf7b8cb0f1
+  checksum: 10c0/785aff96a3aa8ff97f90958e1e8a7b1d47f793b204b47c6455eaadc3f694f48c97cd5c0a921fe3596d818e71f18106610a164fb0f1c71fd68c622a58269d537c
   languageName: node
   linkType: hard
 

From 91d3b3fb25fe61cb8ebcea30ea42ee2b5d7c28ed Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 4 Apr 2024 07:25:30 +0000
Subject: [PATCH 091/173] Update dependency sass to v1.74.1 (#29846)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 3407619c8..8d235a719 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15300,15 +15300,15 @@ __metadata:
   linkType: hard
 
 "sass@npm:^1.62.1":
-  version: 1.72.0
-  resolution: "sass@npm:1.72.0"
+  version: 1.74.1
+  resolution: "sass@npm:1.74.1"
   dependencies:
     chokidar: "npm:>=3.0.0 <4.0.0"
     immutable: "npm:^4.0.0"
     source-map-js: "npm:>=0.6.2 <2.0.0"
   bin:
     sass: sass.js
-  checksum: 10c0/7df1bb470648edc4b528976b1b165c78d4c6731f680afac7cdc8324142f1ef4304598d317d98dac747a2ae8eee17271d760def90bba072021a8b19b459336ccd
+  checksum: 10c0/4610257ee27823276ce4998a534b4ee9f313e5a0b3d3899e70e0f87096feeae4cd8dd3c2f765b52f57dd87f5dab22370ef63f95a837a189fbb9401396d5ce717
   languageName: node
   linkType: hard
 

From 4045c069f8f91200d0e7c64a8097e425aee71041 Mon Sep 17 00:00:00 2001
From: Jeong Arm <kjwonmail@gmail.com>
Date: Thu, 4 Apr 2024 16:31:30 +0900
Subject: [PATCH 092/173] Use `public_visibility` (#29847)

---
 app/lib/annual_report/top_statuses.rb           | 2 +-
 app/views/application/mailer/_hashtag.html.haml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/lib/annual_report/top_statuses.rb b/app/lib/annual_report/top_statuses.rb
index 112e5591c..1ab170952 100644
--- a/app/lib/annual_report/top_statuses.rb
+++ b/app/lib/annual_report/top_statuses.rb
@@ -16,6 +16,6 @@ class AnnualReport::TopStatuses < AnnualReport::Source
   end
 
   def base_scope
-    @account.statuses.with_public_visibility.joins(:status_stat).where(id: year_as_snowflake_range).reorder(nil)
+    @account.statuses.public_visibility.joins(:status_stat).where(id: year_as_snowflake_range).reorder(nil)
   end
 end
diff --git a/app/views/application/mailer/_hashtag.html.haml b/app/views/application/mailer/_hashtag.html.haml
index fcedfa80a..74a00e67e 100644
--- a/app/views/application/mailer/_hashtag.html.haml
+++ b/app/views/application/mailer/_hashtag.html.haml
@@ -1,4 +1,4 @@
-- accounts = hashtag.statuses.with_public_visibility.joins(:account).merge(Account.without_suspended.without_silenced).includes(:account).limit(3).map(&:account)
+- accounts = hashtag.statuses.public_visibility.joins(:account).merge(Account.without_suspended.without_silenced).includes(:account).limit(3).map(&:account)
 
 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
   %tr

From 966d7f5bf9b6b7088f63cc7f8dca90496700ac05 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 4 Apr 2024 07:33:17 -0400
Subject: [PATCH 093/173] Add missing snowflake range correction (#29841)

---
 app/lib/admin/metrics/measure/tag_servers_measure.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/lib/admin/metrics/measure/tag_servers_measure.rb b/app/lib/admin/metrics/measure/tag_servers_measure.rb
index e0f1bf344..f273d739d 100644
--- a/app/lib/admin/metrics/measure/tag_servers_measure.rb
+++ b/app/lib/admin/metrics/measure/tag_servers_measure.rb
@@ -46,11 +46,11 @@ class Admin::Metrics::Measure::TagServersMeasure < Admin::Metrics::Measure::Base
   end
 
   def earliest_status_id
-    Mastodon::Snowflake.id_at(@start_at, with_random: false)
+    Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
   end
 
   def latest_status_id
-    Mastodon::Snowflake.id_at(@end_at, with_random: false)
+    Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
   end
 
   def tag

From 1c87cb8019bafd2eb5b126ed0e9186ce20e94b1e Mon Sep 17 00:00:00 2001
From: Michael Stanclift <mx@vmstan.com>
Date: Thu, 4 Apr 2024 06:51:06 -0500
Subject: [PATCH 094/173] Add purple border to active compose field search
 inputs (#29839)

---
 app/javascript/styles/mastodon/emoji_picker.scss | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/javascript/styles/mastodon/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss
index 947385837..b9fdaa584 100644
--- a/app/javascript/styles/mastodon/emoji_picker.scss
+++ b/app/javascript/styles/mastodon/emoji_picker.scss
@@ -112,9 +112,11 @@
       border: 0;
     }
 
-    &:focus,
-    &:active {
+    &:active,
+    &:focus {
       outline: none !important;
+      border-width: 1px !important;
+      border-color: $ui-button-background-color;
     }
 
     &::-webkit-search-cancel-button {

From 191bf5876e73e586a04e642bc9b63e42721d30ad Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 4 Apr 2024 12:07:16 -0400
Subject: [PATCH 095/173] Add coverage for sanitize failure path in
 api/web/embeds spec (#29851)

---
 spec/requests/api/web/embeds_spec.rb | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/spec/requests/api/web/embeds_spec.rb b/spec/requests/api/web/embeds_spec.rb
index 6314f43aa..0e6195204 100644
--- a/spec/requests/api/web/embeds_spec.rb
+++ b/spec/requests/api/web/embeds_spec.rb
@@ -137,6 +137,18 @@ RSpec.describe '/api/web/embed' do
         end
       end
 
+      context 'when sanitizing the fragment fails' do
+        let(:call_result) { { html: 'ok' } }
+
+        before { allow(Sanitize).to receive(:fragment).and_raise(ArgumentError) }
+
+        it 'returns http not found' do
+          subject
+
+          expect(response).to have_http_status(404)
+        end
+      end
+
       context 'when failing to fetch OEmbed' do
         let(:call_result) { nil }
 

From 601834d74646955ad878024a8b32d35ad3ac0a56 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 4 Apr 2024 12:13:10 -0400
Subject: [PATCH 096/173] Use partial collection render for welcome mailer
 features (#29843)

---
 app/views/application/mailer/_feature.html.haml | 4 ++--
 app/views/user_mailer/welcome.html.haml         | 5 +----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/app/views/application/mailer/_feature.html.haml b/app/views/application/mailer/_feature.html.haml
index 5facdd086..94dd4b9cf 100644
--- a/app/views/application/mailer/_feature.html.haml
+++ b/app/views/application/mailer/_feature.html.haml
@@ -4,7 +4,7 @@
       %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
         %tr
           %td.email-feature-td
-            .email-desktop-flex{ class: ('email-dir-rtl' if defined?(text_first_on_desktop) && !text_first_on_desktop) }
+            .email-desktop-flex{ class: ('email-dir-rtl' if feature_iteration.index.odd?) }
               /[if mso]
                 <table border="0" cellpadding="0" cellspacing="0" align="center" style="width:100%;" role="presentation"><tr><td style="width:50%; vertical-align:top;">
               .email-desktop-column
@@ -24,7 +24,7 @@
                   %tr
                     %td.email-column-td
                       - if defined?(feature)
-                        %p{ class: ('email-desktop-text-right' if defined?(text_first_on_desktop) && text_first_on_desktop) }
+                        %p{ class: ('email-desktop-text-right' if feature_iteration.index.even?) }
                           = image_tag frontend_asset_url("images/mailer-new/welcome/feature_#{feature}.png"), alt: '', width: 240, height: 230
               /[if mso]
                 </td></tr></table>
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index 97fb0a2c9..0f9cbf36f 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -68,7 +68,4 @@
 %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
   %tr
     %td.email-extra-td
-      = render 'application/mailer/feature', feature: 'control', text_first_on_desktop: true
-      = render 'application/mailer/feature', feature: 'audience', text_first_on_desktop: false
-      = render 'application/mailer/feature', feature: 'moderation', text_first_on_desktop: true
-      = render 'application/mailer/feature', feature: 'creativity', text_first_on_desktop: false
+      = render partial: 'application/mailer/feature', collection: %w(control audience moderation creativity)

From 1f11aa5f042542cbac1191df4e7b657ecda99280 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 5 Apr 2024 09:48:07 +0200
Subject: [PATCH 097/173] Add stub for trending tags in user mailer spec
 (#29850)

---
 spec/mailers/user_mailer_spec.rb | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 404b83470..5a8c29374 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -247,6 +247,12 @@ describe UserMailer do
   describe '#welcome' do
     let(:mail) { described_class.welcome(receiver) }
 
+    before do
+      # This is a bit hacky and low-level but this allows stubbing trending tags
+      tag_ids = Fabricate.times(5, :tag).pluck(:id)
+      allow(Trends.tags).to receive(:query).and_return(instance_double(Trends::Query, allowed: Tag.where(id: tag_ids)))
+    end
+
     it 'renders welcome mail' do
       expect(mail)
         .to be_present

From 38b9d31f632a93a57b03061d573a9c0e4b55bdfd Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 5 Apr 2024 09:48:45 +0200
Subject: [PATCH 098/173] Improve email address validation (#29838)

---
 Gemfile                                   |  2 ++
 Gemfile.lock                              |  1 +
 app/models/user.rb                        |  2 ++
 app/validators/email_address_validator.rb | 18 ++++++++++++++++++
 spec/models/user_spec.rb                  |  6 ++++++
 5 files changed, 29 insertions(+)
 create mode 100644 app/validators/email_address_validator.rb

diff --git a/Gemfile b/Gemfile
index 389ae5035..a9affea41 100644
--- a/Gemfile
+++ b/Gemfile
@@ -206,3 +206,5 @@ gem 'net-http', '~> 0.4.0'
 gem 'rubyzip', '~> 2.3'
 
 gem 'hcaptcha', '~> 7.1'
+
+gem 'mail', '~> 2.8'
diff --git a/Gemfile.lock b/Gemfile.lock
index acc439494..ac5027022 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -880,6 +880,7 @@ DEPENDENCIES
   letter_opener_web (~> 2.0)
   link_header (~> 0.0)
   lograge (~> 0.12)
+  mail (~> 2.8)
   mario-redis-lock (~> 1.2)
   md-paperclip-azure (~> 2.2)
   memory_profiler
diff --git a/app/models/user.rb b/app/models/user.rb
index 17ec90c9e..c62a6d0de 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -95,6 +95,8 @@ class User < ApplicationRecord
   accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text }
   validates :invite_request, presence: true, on: :create, if: :invite_text_required?
 
+  validates :email, presence: true, email_address: true
+
   validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
   validates_with EmailMxValidator, if: :validate_email_dns?
   validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
diff --git a/app/validators/email_address_validator.rb b/app/validators/email_address_validator.rb
new file mode 100644
index 000000000..ed0bb1165
--- /dev/null
+++ b/app/validators/email_address_validator.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# NOTE: I initially wrote this as `EmailValidator` but it ended up clashing
+# with an indirect dependency of ours, `validate_email`, which, turns out,
+# has the same approach as we do, but with an extra check disallowing
+# single-label domains. Decided to not switch to `validate_email` because
+# we do want to allow at least `localhost`.
+
+class EmailAddressValidator < ActiveModel::EachValidator
+  def validate_each(record, attribute, value)
+    value = value.strip
+
+    address = Mail::Address.new(value)
+    record.errors.add(attribute, :invalid) if address.address != value
+  rescue Mail::Field::FieldError
+    record.errors.add(attribute, :invalid)
+  end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 39986f476..2a0726306 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -38,6 +38,12 @@ RSpec.describe User do
       user.save(validate: false)
       expect(user.valid?).to be true
     end
+
+    it 'is valid with a localhost e-mail address' do
+      user = Fabricate.build(:user, email: 'admin@localhost')
+      user.valid?
+      expect(user.valid?).to be true
+    end
   end
 
   describe 'Normalizations' do

From c7378218ba7d3bac764625b461166fd60eef12fd Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 5 Apr 2024 09:57:20 +0200
Subject: [PATCH 099/173] Update dependency rubocop-rspec to v2.29.1 (#29858)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index ac5027022..07d2fc4c4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -356,7 +356,7 @@ GEM
       rdoc
       reline (>= 0.4.2)
     jmespath (1.6.2)
-    json (2.7.1)
+    json (2.7.2)
     json-canonicalization (1.0.0)
     json-jwt (1.15.3.1)
       activesupport (>= 4.2)
@@ -671,7 +671,7 @@ GEM
       rack (>= 1.1)
       rubocop (>= 1.33.0, < 2.0)
       rubocop-ast (>= 1.31.1, < 2.0)
-    rubocop-rspec (2.28.0)
+    rubocop-rspec (2.29.1)
       rubocop (~> 1.40)
       rubocop-capybara (~> 2.17)
       rubocop-factory_bot (~> 2.22)

From 906a3996343a9f94b79dc8ef91fc0ca3c04f1719 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Fri, 5 Apr 2024 09:57:44 +0200
Subject: [PATCH 100/173] Fix wrong extension for a test file (#29853)

---
 .../mastodon/utils/__tests__/{html-test.s => html-test.ts}    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
 rename app/javascript/mastodon/utils/__tests__/{html-test.s => html-test.ts} (67%)

diff --git a/app/javascript/mastodon/utils/__tests__/html-test.s b/app/javascript/mastodon/utils/__tests__/html-test.ts
similarity index 67%
rename from app/javascript/mastodon/utils/__tests__/html-test.s
rename to app/javascript/mastodon/utils/__tests__/html-test.ts
index d948cf4c5..99bfdcb80 100644
--- a/app/javascript/mastodon/utils/__tests__/html-test.s
+++ b/app/javascript/mastodon/utils/__tests__/html-test.ts
@@ -3,7 +3,9 @@ import * as html from '../html';
 describe('html', () => {
   describe('unescapeHTML', () => {
     it('returns unescaped HTML', () => {
-      const output = html.unescapeHTML('<p>lorem</p><p>ipsum</p><br>&lt;br&gt;');
+      const output = html.unescapeHTML(
+        '<p>lorem</p><p>ipsum</p><br>&lt;br&gt;',
+      );
       expect(output).toEqual('lorem\n\nipsum\n<br>');
     });
   });

From 6ac90d4c5da2cf82fff4a6b1403db15b68d79883 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Fri, 5 Apr 2024 10:06:31 +0200
Subject: [PATCH 101/173] Add tests for our number formatting function (#29852)

---
 .../mastodon/utils/__tests__/numbers.ts       | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 app/javascript/mastodon/utils/__tests__/numbers.ts

diff --git a/app/javascript/mastodon/utils/__tests__/numbers.ts b/app/javascript/mastodon/utils/__tests__/numbers.ts
new file mode 100644
index 000000000..d1d1444e8
--- /dev/null
+++ b/app/javascript/mastodon/utils/__tests__/numbers.ts
@@ -0,0 +1,24 @@
+import { DECIMAL_UNITS, toShortNumber } from '../numbers';
+
+interface TableRow {
+  input: number;
+  base: number;
+  unit: number;
+  digits: number;
+}
+
+describe.each`
+  input             | base         | unit                      | digits
+  ${10_000_000}     | ${10}        | ${DECIMAL_UNITS.MILLION}  | ${0}
+  ${2_789_123}      | ${2.789123}  | ${DECIMAL_UNITS.MILLION}  | ${1}
+  ${12_345_789}     | ${12.345789} | ${DECIMAL_UNITS.MILLION}  | ${0}
+  ${10_000_000_000} | ${10}        | ${DECIMAL_UNITS.BILLION}  | ${0}
+  ${12}             | ${12}        | ${DECIMAL_UNITS.ONE}      | ${0}
+  ${123}            | ${123}       | ${DECIMAL_UNITS.ONE}      | ${0}
+  ${1234}           | ${1.234}     | ${DECIMAL_UNITS.THOUSAND} | ${1}
+  ${6666}           | ${6.666}     | ${DECIMAL_UNITS.THOUSAND} | ${1}
+`('toShortNumber', ({ input, base, unit, digits }: TableRow) => {
+  test(`correctly formats ${input}`, () => {
+    expect(toShortNumber(input)).toEqual([base, unit, digits]);
+  });
+});

From 59da591d13e666f5426b72fd4079530c886d9657 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 5 Apr 2024 04:54:11 -0400
Subject: [PATCH 102/173] Improve spec for dimension/languages admin metric
 (#29842)

---
 .../dimension/languages_dimension_spec.rb     | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb b/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
index 1722c4c61..9d8097069 100644
--- a/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::LanguagesDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
@@ -11,8 +11,21 @@ describe Admin::Metrics::Dimension::LanguagesDimension do
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:alice) { Fabricate(:user, locale: 'en', current_sign_in_at: 1.day.ago) }
+    let(:bob) { Fabricate(:user, locale: 'en', current_sign_in_at: 30.days.ago) }
+
+    before do
+      alice.update(current_sign_in_at: 1.day.ago)
+      bob.update(current_sign_in_at: 30.days.ago)
+    end
+
+    it 'returns locales with sign in counts' do
+      expect(subject.data.size)
+        .to eq(1)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: 'en', value: '1')
+        )
     end
   end
 end

From 285a87a77f947cc7085fab45376c21a4b33eac37 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 5 Apr 2024 11:04:10 +0200
Subject: [PATCH 103/173] Update dependency scenic to v1.8.0 (#29794)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 07d2fc4c4..3508ad8d5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -607,7 +607,7 @@ GEM
     redlock (1.3.2)
       redis (>= 3.0.0, < 6.0)
     regexp_parser (2.9.0)
-    reline (0.4.3)
+    reline (0.5.0)
       io-console (~> 0.5)
     request_store (1.5.1)
       rack (>= 1.4)
@@ -692,7 +692,7 @@ GEM
     sanitize (6.1.0)
       crass (~> 1.0.2)
       nokogiri (>= 1.12.0)
-    scenic (1.7.0)
+    scenic (1.8.0)
       activerecord (>= 4.0.0)
       railties (>= 4.0.0)
     selenium-webdriver (4.19.0)

From c0fe8a9f1363ae0c34f10f4119f5df407ed58fa0 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 5 Apr 2024 05:17:58 -0400
Subject: [PATCH 104/173] Extract shared callback behaviour to
 `CustomFilterCache` concern (#29695)

---
 app/models/concerns/custom_filter_cache.rb | 17 +++++++++++++++++
 app/models/custom_filter_keyword.rb        | 14 ++------------
 app/models/custom_filter_status.rb         | 14 ++------------
 3 files changed, 21 insertions(+), 24 deletions(-)
 create mode 100644 app/models/concerns/custom_filter_cache.rb

diff --git a/app/models/concerns/custom_filter_cache.rb b/app/models/concerns/custom_filter_cache.rb
new file mode 100644
index 000000000..79b22f11f
--- /dev/null
+++ b/app/models/concerns/custom_filter_cache.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module CustomFilterCache
+  extend ActiveSupport::Concern
+
+  included do
+    after_commit :invalidate_cache!
+    before_destroy :prepare_cache_invalidation!
+    before_save :prepare_cache_invalidation!
+
+    delegate(
+      :invalidate_cache!,
+      :prepare_cache_invalidation!,
+      to: :custom_filter
+    )
+  end
+end
diff --git a/app/models/custom_filter_keyword.rb b/app/models/custom_filter_keyword.rb
index 979d0b822..112798b10 100644
--- a/app/models/custom_filter_keyword.rb
+++ b/app/models/custom_filter_keyword.rb
@@ -13,16 +13,14 @@
 #
 
 class CustomFilterKeyword < ApplicationRecord
+  include CustomFilterCache
+
   belongs_to :custom_filter
 
   validates :keyword, presence: true
 
   alias_attribute :phrase, :keyword
 
-  before_save :prepare_cache_invalidation!
-  before_destroy :prepare_cache_invalidation!
-  after_commit :invalidate_cache!
-
   def to_regex
     if whole_word?
       /(?mix:#{to_regex_sb}#{Regexp.escape(keyword)}#{to_regex_eb})/
@@ -40,12 +38,4 @@ class CustomFilterKeyword < ApplicationRecord
   def to_regex_eb
     /[[:word:]]\z/.match?(keyword) ? '\b' : ''
   end
-
-  def prepare_cache_invalidation!
-    custom_filter.prepare_cache_invalidation!
-  end
-
-  def invalidate_cache!
-    custom_filter.invalidate_cache!
-  end
 end
diff --git a/app/models/custom_filter_status.rb b/app/models/custom_filter_status.rb
index 0a5650204..58b61cd79 100644
--- a/app/models/custom_filter_status.rb
+++ b/app/models/custom_filter_status.rb
@@ -12,27 +12,17 @@
 #
 
 class CustomFilterStatus < ApplicationRecord
+  include CustomFilterCache
+
   belongs_to :custom_filter
   belongs_to :status
 
   validates :status, uniqueness: { scope: :custom_filter }
   validate :validate_status_access
 
-  before_save :prepare_cache_invalidation!
-  before_destroy :prepare_cache_invalidation!
-  after_commit :invalidate_cache!
-
   private
 
   def validate_status_access
     errors.add(:status_id, :invalid) unless StatusPolicy.new(custom_filter.account, status).show?
   end
-
-  def prepare_cache_invalidation!
-    custom_filter.prepare_cache_invalidation!
-  end
-
-  def invalidate_cache!
-    custom_filter.invalidate_cache!
-  end
 end

From 52ab8a59c6e77b6409a7d4d81b15751732b3af91 Mon Sep 17 00:00:00 2001
From: ache <ache@ache.one>
Date: Fri, 5 Apr 2024 11:19:43 +0200
Subject: [PATCH 105/173] Forward 3035 port (#29710)

---
 Vagrantfile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Vagrantfile b/Vagrantfile
index 12bd1ba67..8a95e91f3 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -173,6 +173,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
 
   # Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080
   config.vm.network :forwarded_port, guest: 3000, host: 3000
+  config.vm.network :forwarded_port, guest: 3035, host: 3035
   config.vm.network :forwarded_port, guest: 4000, host: 4000
   config.vm.network :forwarded_port, guest: 8080, host: 8080
   config.vm.network :forwarded_port, guest: 9200, host: 9200

From b61ae28f8d4b6f269f50a05c3e65ec7f2c846d32 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 5 Apr 2024 05:52:43 -0400
Subject: [PATCH 106/173] Separate methods for theme style and meta color tags
 (#29802)

---
 app/helpers/application_helper.rb       | 12 ----
 app/helpers/theme_helper.rb             | 27 ++++++++
 app/lib/themes.rb                       |  6 +-
 app/views/layouts/application.html.haml |  1 +
 spec/helpers/theme_helper_spec.rb       | 91 +++++++++++++++++++++++++
 5 files changed, 123 insertions(+), 14 deletions(-)
 create mode 100644 app/helpers/theme_helper.rb
 create mode 100644 spec/helpers/theme_helper_spec.rb

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index c3ee0d930..668afe7fd 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -160,18 +160,6 @@ module ApplicationHelper
     output.compact_blank.join(' ')
   end
 
-  def theme_style_tags(theme)
-    if theme == 'system'
-      concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
-      concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
-      concat tag.meta name: 'theme-color', content: Themes::MASTODON_DARK_THEME_COLOR, media: '(prefers-color-scheme: dark)'
-      concat tag.meta name: 'theme-color', content: Themes::MASTODON_LIGHT_THEME_COLOR, media: '(prefers-color-scheme: light)'
-    else
-      concat stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
-      concat tag.meta name: 'theme-color', content: theme == 'mastodon-light' ? Themes::MASTODON_LIGHT_THEME_COLOR : Themes::MASTODON_DARK_THEME_COLOR
-    end
-  end
-
   def cdn_host
     Rails.configuration.action_controller.asset_host
   end
diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb
new file mode 100644
index 000000000..83527ce61
--- /dev/null
+++ b/app/helpers/theme_helper.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ThemeHelper
+  def theme_style_tags(theme)
+    if theme == 'system'
+      concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
+      concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
+    else
+      stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
+    end
+  end
+
+  def theme_color_tags(theme)
+    if theme == 'system'
+      concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)')
+      concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)')
+    else
+      tag.meta name: 'theme-color', content: theme_color_for(theme)
+    end
+  end
+
+  private
+
+  def theme_color_for(theme)
+    theme == 'mastodon-light' ? Themes::THEME_COLORS[:light] : Themes::THEME_COLORS[:dark]
+  end
+end
diff --git a/app/lib/themes.rb b/app/lib/themes.rb
index 3ad230497..b6da98073 100644
--- a/app/lib/themes.rb
+++ b/app/lib/themes.rb
@@ -6,8 +6,10 @@ require 'yaml'
 class Themes
   include Singleton
 
-  MASTODON_DARK_THEME_COLOR = '#191b22'
-  MASTODON_LIGHT_THEME_COLOR = '#f3f5f7'
+  THEME_COLORS = {
+    dark: '#191b22',
+    light: '#f3f5f7',
+  }.freeze
 
   def initialize
     @conf = YAML.load_file(Rails.root.join('config', 'themes.yml'))
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index c353b1d87..9d7669d68 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -21,6 +21,7 @@
 
     %link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/
     %link{ rel: 'manifest', href: manifest_path(format: :json) }/
+    = theme_color_tags current_theme
     %meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
 
     %title= html_title
diff --git a/spec/helpers/theme_helper_spec.rb b/spec/helpers/theme_helper_spec.rb
new file mode 100644
index 000000000..c0b6380a1
--- /dev/null
+++ b/spec/helpers/theme_helper_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe ThemeHelper do
+  describe 'theme_style_tags' do
+    let(:result) { helper.theme_style_tags(theme) }
+
+    context 'when using system theme' do
+      let(:theme) { 'system' }
+
+      it 'returns the mastodon-light and default stylesheets with correct color schemes' do
+        expect(html_links.first.attributes.symbolize_keys)
+          .to include(
+            href: have_attributes(value: match(/mastodon-light/)),
+            media: have_attributes(value: 'not all and (prefers-color-scheme: dark)')
+          )
+        expect(html_links.last.attributes.symbolize_keys)
+          .to include(
+            href: have_attributes(value: match(/default/)),
+            media: have_attributes(value: '(prefers-color-scheme: dark)')
+          )
+      end
+    end
+
+    context 'when using other theme' do
+      let(:theme) { 'contrast' }
+
+      it 'returns the theme stylesheet without color scheme information' do
+        expect(html_links.first.attributes.symbolize_keys)
+          .to include(
+            href: have_attributes(value: match(/contrast/)),
+            media: have_attributes(value: 'all')
+          )
+      end
+    end
+  end
+
+  describe 'theme_color_tags' do
+    let(:result) { helper.theme_color_tags(theme) }
+
+    context 'when using system theme' do
+      let(:theme) { 'system' }
+
+      it 'returns the mastodon-light and default stylesheets with correct color schemes' do
+        expect(html_theme_colors.first.attributes.symbolize_keys)
+          .to include(
+            content: have_attributes(value: Themes::THEME_COLORS[:dark]),
+            media: have_attributes(value: '(prefers-color-scheme: dark)')
+          )
+        expect(html_theme_colors.last.attributes.symbolize_keys)
+          .to include(
+            content: have_attributes(value: Themes::THEME_COLORS[:light]),
+            media: have_attributes(value: '(prefers-color-scheme: light)')
+          )
+      end
+    end
+
+    context 'when using mastodon-light theme' do
+      let(:theme) { 'mastodon-light' }
+
+      it 'returns the theme stylesheet without color scheme information' do
+        expect(html_theme_colors.first.attributes.symbolize_keys)
+          .to include(
+            content: have_attributes(value: Themes::THEME_COLORS[:light])
+          )
+      end
+    end
+
+    context 'when using other theme' do
+      let(:theme) { 'contrast' }
+
+      it 'returns the theme stylesheet without color scheme information' do
+        expect(html_theme_colors.first.attributes.symbolize_keys)
+          .to include(
+            content: have_attributes(value: Themes::THEME_COLORS[:dark])
+          )
+      end
+    end
+  end
+
+  private
+
+  def html_links
+    Nokogiri::HTML5.fragment(result).css('link')
+  end
+
+  def html_theme_colors
+    Nokogiri::HTML5.fragment(result).css('meta[name=theme-color]')
+  end
+end

From e73cf356d2f7dc38ef30e5465635c4c0813f4ade Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 5 Apr 2024 18:52:05 +0200
Subject: [PATCH 107/173] Move OAuth flow tests from feature tests to system
 tests (#29837)

---
 spec/{features => system}/oauth_spec.rb | 32 ++++++++++++-------------
 1 file changed, 16 insertions(+), 16 deletions(-)
 rename spec/{features => system}/oauth_spec.rb (94%)

diff --git a/spec/features/oauth_spec.rb b/spec/system/oauth_spec.rb
similarity index 94%
rename from spec/features/oauth_spec.rb
rename to spec/system/oauth_spec.rb
index 720c26289..060978217 100644
--- a/spec/features/oauth_spec.rb
+++ b/spec/system/oauth_spec.rb
@@ -3,13 +3,14 @@
 require 'rails_helper'
 
 describe 'Using OAuth from an external app' do
-  let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
+  let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/health', scopes: 'read') }
 
   context 'when the user is already logged in' do
     let!(:user) { Fabricate(:user) }
 
     before do
-      sign_in user, scope: :user
+      visit new_user_session_path
+      fill_in_auth_details(user.email, user.password)
     end
 
     it 'when accepting the authorization request' do
@@ -164,20 +165,19 @@ describe 'Using OAuth from an external app' do
         expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be false
       end
     end
-
-    private
-
-    def fill_in_auth_details(email, password)
-      fill_in 'user_email', with: email
-      fill_in 'user_password', with: password
-      click_on I18n.t('auth.login')
-    end
-
-    def fill_in_otp_details(value)
-      fill_in 'user_otp_attempt', with: value
-      click_on I18n.t('auth.login')
-    end
-
     # TODO: external auth
   end
+
+  private
+
+  def fill_in_auth_details(email, password)
+    fill_in 'user_email', with: email
+    fill_in 'user_password', with: password
+    click_on I18n.t('auth.login')
+  end
+
+  def fill_in_otp_details(value)
+    fill_in 'user_otp_attempt', with: value
+    click_on I18n.t('auth.login')
+  end
 end

From 79bbb2023da903a72cb8698ff1b6430c6ca4583b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 10:15:46 +0200
Subject: [PATCH 108/173] Update dependency react-intl to v6.6.5 (#29864)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 8d235a719..86c0c3eeb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14320,8 +14320,8 @@ __metadata:
   linkType: hard
 
 "react-intl@npm:^6.4.2":
-  version: 6.6.4
-  resolution: "react-intl@npm:6.6.4"
+  version: 6.6.5
+  resolution: "react-intl@npm:6.6.5"
   dependencies:
     "@formatjs/ecma402-abstract": "npm:1.18.2"
     "@formatjs/icu-messageformat-parser": "npm:2.7.6"
@@ -14339,7 +14339,7 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/bd874ad3a56b0198903c02c878cfa23b5ae9a44d2c74fd4f01ddb602c97a8115de8cebed00b44f7dc5fb3031e5ef0f9cfb4bdabd105b99a785352462deb106d3
+  checksum: 10c0/31f231701af080bc923fdf25ff22ae7ad56bd7892602879fe6fa3de0c6ab95aab10ff86595372be155e0be45a7130a2cca91dbab73e558359cebc1785711ded2
   languageName: node
   linkType: hard
 

From 499b184fcdca2d97999785d77226a6d689987a7e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 10:16:20 +0200
Subject: [PATCH 109/173] Update dependency pino to v8.20.0 (#29865)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 86c0c3eeb..a4ee14835 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12963,7 +12963,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:v1.1.0":
+"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.1.0":
   version: 1.1.0
   resolution: "pino-abstract-transport@npm:1.1.0"
   dependencies:
@@ -13017,13 +13017,13 @@ __metadata:
   linkType: hard
 
 "pino@npm:^8.17.1, pino@npm:^8.17.2":
-  version: 8.19.0
-  resolution: "pino@npm:8.19.0"
+  version: 8.20.0
+  resolution: "pino@npm:8.20.0"
   dependencies:
     atomic-sleep: "npm:^1.0.0"
     fast-redact: "npm:^3.1.1"
     on-exit-leak-free: "npm:^2.1.0"
-    pino-abstract-transport: "npm:v1.1.0"
+    pino-abstract-transport: "npm:^1.1.0"
     pino-std-serializers: "npm:^6.0.0"
     process-warning: "npm:^3.0.0"
     quick-format-unescaped: "npm:^4.0.3"
@@ -13033,7 +13033,7 @@ __metadata:
     thread-stream: "npm:^2.0.0"
   bin:
     pino: bin.js
-  checksum: 10c0/53e6e9db91e451163e93294b0a7c5c8135742d58909dfc4a6fa1afc155b2b0dc44448ec3d057e08351951f9a3ea67e6ea8e72e952b64a1d889f4d5376cbd1a5d
+  checksum: 10c0/6b973474160e1fa01fa150de0f69b7db9c6c06ae15f992d369669751825c8f2af3bb5600348eaf9be65b4952326bbdfa226f51e425820eb511f0f594fbddbaa7
   languageName: node
   linkType: hard
 

From b06510d579bb1eccccc7e4881f17cac09f9c44a3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 08:16:36 +0000
Subject: [PATCH 110/173] Update DefinitelyTyped types (non-major) (#29874)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index a4ee14835..257a1729b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3759,11 +3759,11 @@ __metadata:
   linkType: hard
 
 "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4":
-  version: 18.2.23
-  resolution: "@types/react-dom@npm:18.2.23"
+  version: 18.2.24
+  resolution: "@types/react-dom@npm:18.2.24"
   dependencies:
     "@types/react": "npm:*"
-  checksum: 10c0/9348e93558aa67b4b237bd0eab62e72e85f3e17a1c45fde04d874476269730f7c671b3d62390c4fca588da2a026e90cc74148abc349dbfd4ee5535a82ccdf38e
+  checksum: 10c0/9ec38e5ab4727c56ef17bd8e938ead88748ba19db314b8d9807714a5cae430f5b799514667b221b4f2dc8d9b4ca17dd1c3da8c41c083c2de9eddcc31bec6b8ff
   languageName: node
   linkType: hard
 
@@ -3862,12 +3862,12 @@ __metadata:
   linkType: hard
 
 "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
-  version: 18.2.73
-  resolution: "@types/react@npm:18.2.73"
+  version: 18.2.74
+  resolution: "@types/react@npm:18.2.74"
   dependencies:
     "@types/prop-types": "npm:*"
     csstype: "npm:^3.0.2"
-  checksum: 10c0/b6645ab3c20efa41cfccf58ce0be45419517a0ba4594e323dd400342fb1c1f9589d169cf9bfa85b5b0605e9097fe9de7734b6d0c533f5b9bc32aaadb624537a4
+  checksum: 10c0/347e38b4c5dc20d50ff71bf04b7caaef490e5ff695e74a0088a13fbb2a0c5d125a5ecfd142adfa30f0176da0e2734942c91ba61d95ce269c43b3265bd7379361
   languageName: node
   linkType: hard
 

From 2441fe6fd4863f12d5b9af445a08b36c5f6edb21 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 08:16:57 +0000
Subject: [PATCH 111/173] Update dependency stylelint-config-standard-scss to
 v13.1.0 (#29876)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 257a1729b..bb521f1c9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16389,18 +16389,18 @@ __metadata:
   linkType: hard
 
 "stylelint-config-standard-scss@npm:^13.0.0":
-  version: 13.0.0
-  resolution: "stylelint-config-standard-scss@npm:13.0.0"
+  version: 13.1.0
+  resolution: "stylelint-config-standard-scss@npm:13.1.0"
   dependencies:
     stylelint-config-recommended-scss: "npm:^14.0.0"
     stylelint-config-standard: "npm:^36.0.0"
   peerDependencies:
     postcss: ^8.3.3
-    stylelint: ^16.1.0
+    stylelint: ^16.3.1
   peerDependenciesMeta:
     postcss:
       optional: true
-  checksum: 10c0/4abf317676184f4aaace6ce72b9fc9e2dffe051d43dd5637afc5803b062ea381e2807ae983c045dff22e96af58388a8b1fe9a8bdda9f97bc3660280cf24fb4d3
+  checksum: 10c0/d07cae806ee8b3e77684f019a8b22cc32642373da8053e6ae7ed716f8ddbe6ea1f7323633a6a1bbc9aa08c6a3dceb1dcf053d83fdd10d076b5a01da6e86801ae
   languageName: node
   linkType: hard
 

From a1277a9b2b2a47f274725802ce120a90bfb1bcf0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 08:17:23 +0000
Subject: [PATCH 112/173] Update eslint (non-major) (#29877)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index bb521f1c9..49d36702d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7758,8 +7758,8 @@ __metadata:
   linkType: hard
 
 "eslint-plugin-formatjs@npm:^4.10.1":
-  version: 4.12.2
-  resolution: "eslint-plugin-formatjs@npm:4.12.2"
+  version: 4.13.0
+  resolution: "eslint-plugin-formatjs@npm:4.13.0"
   dependencies:
     "@formatjs/icu-messageformat-parser": "npm:2.7.6"
     "@formatjs/ts-transformer": "npm:3.13.12"
@@ -7774,7 +7774,7 @@ __metadata:
     unicode-emoji-utils: "npm:^1.2.0"
   peerDependencies:
     eslint: 7 || 8
-  checksum: 10c0/77cc1a2959903fcb6639d9fec89e7dfc55cf1e4ea58fca7d3bd6d12fa540aa173cbf5f90fc629b6aaf2ea3b8e61ed0a3cfce940fd2bec6f0796353315e2dbeef
+  checksum: 10c0/3dbe4ffd3e72d4ce5b14afdcf6dd5db889dd09cb15bc875f29bcc5b49295e0ae4a3eb672ed89ed33f22aacbfe655151398ca4307fd0610508e568a6e4db50aa8
   languageName: node
   linkType: hard
 
@@ -7806,8 +7806,8 @@ __metadata:
   linkType: hard
 
 "eslint-plugin-jsdoc@npm:^48.0.0":
-  version: 48.2.2
-  resolution: "eslint-plugin-jsdoc@npm:48.2.2"
+  version: 48.2.3
+  resolution: "eslint-plugin-jsdoc@npm:48.2.3"
   dependencies:
     "@es-joy/jsdoccomment": "npm:~0.42.0"
     are-docs-informative: "npm:^0.0.2"
@@ -7820,7 +7820,7 @@ __metadata:
     spdx-expression-parse: "npm:^4.0.0"
   peerDependencies:
     eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
-  checksum: 10c0/d6911e73d36757de5aef127e795116fbbcdef504f7e91d9c0863faf0b1693271d96188f0f1d54c0d74c56652bfa3fb4f1aa1a2f0876b0c6a5e57a874bcb3ac2b
+  checksum: 10c0/e755923d96118890c6fd28b1c2298e1fe67ccbce08060ffc091b29ced59d0058ad8820323c56eef6f85c2954c783fc4076e78c0e5bc64838ae099b4e62ea702e
   languageName: node
   linkType: hard
 

From 730e2127e1fa0e81952bb83d91cede91d8b47b72 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Mon, 8 Apr 2024 10:17:51 +0200
Subject: [PATCH 113/173] Fix webpack warnings due to unhandled extensions
 (`LICENCE` and `README.md`) (#29869)

---
 app/javascript/mastodon/common.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/javascript/mastodon/common.js b/app/javascript/mastodon/common.js
index 0ec844934..511568aa0 100644
--- a/app/javascript/mastodon/common.js
+++ b/app/javascript/mastodon/common.js
@@ -2,7 +2,7 @@ import Rails from '@rails/ujs';
 import 'font-awesome/css/font-awesome.css';
 
 export function start() {
-  require.context('../images/', true);
+  require.context('../images/', true, /\.(jpg|png|svg)$/);
 
   try {
     Rails.start();

From 13faf26315f9ee7b03326fe8dfdf979d2a06191d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 15:44:54 +0200
Subject: [PATCH 114/173] New Crowdin Translations (automated) (#29859)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ar.json | 18 ++++++++++++++++++
 app/javascript/mastodon/locales/bg.json |  1 +
 app/javascript/mastodon/locales/de.json |  2 +-
 app/javascript/mastodon/locales/gd.json | 12 ++++++++++--
 app/javascript/mastodon/locales/ja.json |  5 +++++
 app/javascript/mastodon/locales/lt.json |  1 +
 config/locales/ar.yml                   | 16 ++++++++++++++++
 config/locales/devise.es.yml            |  4 ++--
 config/locales/devise.lt.yml            |  8 ++++----
 config/locales/doorkeeper.lt.yml        | 12 ++++++------
 config/locales/doorkeeper.sr.yml        |  4 ++--
 config/locales/gd.yml                   |  1 +
 config/locales/ja.yml                   |  1 +
 config/locales/lt.yml                   |  5 +++--
 config/locales/simple_form.ko.yml       |  2 +-
 config/locales/sr-Latn.yml              |  2 +-
 config/locales/sr.yml                   | 18 +++++++++---------
 config/locales/sv.yml                   | 12 ++++++++++++
 18 files changed, 94 insertions(+), 30 deletions(-)

diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index a231e5e21..dd13f10aa 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -92,6 +92,11 @@
   "block_modal.remote_users_caveat": "Do t’i kërkojmë shërbyesit {domain} të respektojë vendimin tuaj. Por, pajtimi s’është i garantuar, ngaqë disa shërbyes mund t’i trajtojnë ndryshe bllokimet. Psotimet publike mundet të jenë ende të dukshme për përdorues pa bërë hyrje në llogari.",
   "block_modal.show_less": "اعرض أقلّ",
   "block_modal.show_more": "أظهر المزيد",
+  "block_modal.they_cant_mention": "لن يستطيع ذِكرك أو متابعتك.",
+  "block_modal.they_cant_see_posts": "لن يستطيع رؤية منشوراتك ولن ترى منشوراته.",
+  "block_modal.they_will_know": "يمكنه أن يرى أنه قد تم حجبه.",
+  "block_modal.title": "أتريد حظر المستخدم؟",
+  "block_modal.you_wont_see_mentions": "لن تر المنشورات التي يُشار فيهم إليه.",
   "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة",
   "bundle_column_error.copy_stacktrace": "انسخ تقرير الخطأ",
   "bundle_column_error.error.body": "لا يمكن تقديم الصفحة المطلوبة. قد يكون بسبب خطأ في التعليمات البرمجية، أو مشكلة توافق المتصفح.",
@@ -172,6 +177,7 @@
   "confirmations.delete_list.message": "هل أنتَ مُتأكدٌ أنكَ تُريدُ حَذفَ هذِهِ القائمة بشكلٍ دائم؟",
   "confirmations.discard_edit_media.confirm": "تجاهل",
   "confirmations.discard_edit_media.message": "لديك تغييرات غير محفوظة لوصف الوسائط أو معاينتها، أتريد تجاهلها على أي حال؟",
+  "confirmations.domain_block.confirm": "حظر الخادم",
   "confirmations.domain_block.message": "متأكد من أنك تود حظر اسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.\nلن تتمكن مِن رؤية محتوى هذا النطاق لا على خيوطك العمومية و لا في إشعاراتك. سوف يتم كذلك إزالة كافة متابعيك المنتمين إلى هذا النطاق.",
   "confirmations.edit.confirm": "تعديل",
   "confirmations.edit.message": "التعديل في الحين سوف يُعيد كتابة الرسالة التي أنت بصدد تحريرها. متأكد من أنك تريد المواصلة؟",
@@ -203,6 +209,16 @@
   "dismissable_banner.explore_statuses": "هذه هي المنشورات الرائجة على الشبكات الاجتماعيّة اليوم. تظهر المنشورات المعاد نشرها والحائزة على مفضّلات أكثر في مرتبة عليا.",
   "dismissable_banner.explore_tags": "هذه هي الوسوم تكتسب جذب الاهتمام حاليًا على الويب الاجتماعي. الوسوم التي يستخدمها مختلف الناس تحتل مرتبة عليا.",
   "dismissable_banner.public_timeline": "هذه هي أحدث المنشورات العامة من الناس على الشبكة الاجتماعية التي يتبعها الناس على {domain}.",
+  "domain_block_modal.block": "حظر الخادم",
+  "domain_block_modal.block_account_instead": "أحجب @{name} بدلاً من ذلك",
+  "domain_block_modal.they_can_interact_with_old_posts": "يمكن للأشخاص من هذا الخادم التفاعل مع منشوراتك القديمة.",
+  "domain_block_modal.they_cant_follow": "لا أحد من هذا الخادم يمكنه متابعتك.",
+  "domain_block_modal.they_wont_know": "لن يَعرف أنه قد تم حظره.",
+  "domain_block_modal.title": "أتريد حظر النطاق؟",
+  "domain_block_modal.you_will_lose_followers": "سيتم إزالة جميع متابعيك من هذا الخادم.",
+  "domain_block_modal.you_wont_see_posts": "لن ترى منشورات أو إشعارات من المستخدمين على هذا الخادم.",
+  "domain_pill.activitypub_lets_connect": "يتيح لك التواصل والتفاعل مع الناس ليس فقط على ماستدون، ولكن عبر تطبيقات اجتماعية مختلفة أيضا.",
+  "domain_pill.activitypub_like_language": "إنّ ActivityPub مثل لغة ماستدون التي يتحدث بها مع شبكات اجتماعية أخرى.",
   "domain_pill.server": "الخادِم",
   "domain_pill.their_handle": "مُعرِّفُه:",
   "domain_pill.their_server": "بيتهم الرقمي، حيث تُستضاف كافة منشوراتهم.",
@@ -276,6 +292,7 @@
   "filter_modal.select_filter.subtitle": "استخدم فئة موجودة أو قم بإنشاء فئة جديدة",
   "filter_modal.select_filter.title": "تصفية هذا المنشور",
   "filter_modal.title.status": "تصفية منشور",
+  "filtered_notifications_banner.title": "الإشعارات المصفاة",
   "firehose.all": "الكل",
   "firehose.local": "هذا الخادم",
   "firehose.remote": "خوادم أخرى",
@@ -666,6 +683,7 @@
   "status.direct": "إشارة خاصة لـ @{name}",
   "status.direct_indicator": "إشارة خاصة",
   "status.edit": "تعديل",
+  "status.edited": "آخر تعديل يوم {date}",
   "status.edited_x_times": "عُدّل {count, plural, zero {} one {مرةً واحدة} two {مرّتان} few {{count} مرات} many {{count} مرة} other {{count} مرة}}",
   "status.embed": "إدماج",
   "status.favourite": "فضّل",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 910d6cb06..2acedbc4d 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Филтриране на публ.",
   "filter_modal.title.status": "Филтриране на публ.",
   "filtered_notifications_banner.pending_requests": "Известията от {count, plural, =0 {никого, когото може да познавате} one {едно лице, което може да познавате} other {# души, които може да познавате}}",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {частно споменаване} other {частни споменавания}}",
   "filtered_notifications_banner.title": "Филтрирани известия",
   "firehose.all": "Всичко",
   "firehose.local": "Този сървър",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index b1d0b3ec1..5a5acb383 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -85,7 +85,7 @@
   "alert.rate_limited.message": "Bitte versuche es nach {retry_time, time, medium} erneut.",
   "alert.rate_limited.title": "Anfragelimit überschritten",
   "alert.unexpected.message": "Ein unerwarteter Fehler ist aufgetreten.",
-  "alert.unexpected.title": "Ups!",
+  "alert.unexpected.title": "Oha!",
   "announcement.announcement": "Ankündigung",
   "attachments_list.unprocessed": "(ausstehend)",
   "audio.hide": "Audio ausblenden",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index d835a4686..4aaa0cbf7 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -12,7 +12,7 @@
   "about.powered_by": "Lìonra sòisealta sgaoilte le cumhachd {mastodon}",
   "about.rules": "Riaghailtean an fhrithealaiche",
   "account.account_note_header": "Nòta",
-  "account.add_or_remove_from_list": "Cuir ris no thoir air falbh o na liostaichean",
+  "account.add_or_remove_from_list": "Cuir ris no thoir air falbh o liostaichean",
   "account.badges.bot": "Fèin-obrachail",
   "account.badges.group": "Buidheann",
   "account.block": "Bac @{name}",
@@ -298,6 +298,7 @@
   "filter_modal.select_filter.title": "Criathraich am post seo",
   "filter_modal.title.status": "Criathraich post",
   "filtered_notifications_banner.pending_requests": "{count, plural, =0 {Chan eil brath ann o dhaoine} one {Tha brathan ann o # neach} two {Tha brathan ann o # neach} few {Tha brathan ann o # daoine} other {Tha brathan ann o # duine}} air a bheil thu eòlach ’s dòcha",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {iomradh prìobhaideach} two {iomradh prìobhaideach} few {iomraidhean prìobhaideach} other {iomradh prìobhaideach}}",
   "filtered_notifications_banner.title": "Brathan criathraichte",
   "firehose.all": "Na h-uile",
   "firehose.local": "Am frithealaiche seo",
@@ -471,6 +472,11 @@
   "notification.own_poll": "Thàinig an cunntas-bheachd agad gu crìoch",
   "notification.poll": "Thàinig cunntas-bheachd sa bhòt thu gu crìoch",
   "notification.reblog": "Bhrosnaich {name} am post agad",
+  "notification.relationships_severance_event": "Chaill thu dàimhean le {name}",
+  "notification.relationships_severance_event.account_suspension": "Chuir rianaire aig {from} {target} à rèim agus is ciall dha sin nach fhaigh thu naidheachdan uapa ’s nach urrainn dhut conaltradh leotha.",
+  "notification.relationships_severance_event.domain_block": "Bhac rianaire aig {from} {target}, a’ gabhail a-staigh {followersCount} dhen luchd-leantainn agad agus {followingCount, plural, one {# chunntas} two {# chunntas} few {# cunntasan} other {# cunntas}} a tha thu fhèin a’ leantainn.",
+  "notification.relationships_severance_event.learn_more": "Barrachd fiosrachaidh",
+  "notification.relationships_severance_event.user_domain_block": "Bhac thu {target} agus thug sin air falbh {followersCount} dhen luchd-leantainn agad agus {followingCount, plural, one {# chunntas} two {# chunntas} few {# cunntasan} other {# cunntas}} a tha thu fhèin a’ leantainn.",
   "notification.status": "Phostaich {name} rud",
   "notification.update": "Dheasaich {name} post",
   "notification_requests.accept": "Gabh ris",
@@ -483,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Clàraidhean ùra:",
   "notifications.column_settings.alert": "Brathan deasga",
   "notifications.column_settings.favourite": "Annsachdan:",
+  "notifications.column_settings.filter_bar.advanced": "Seall a h-uile roinn-seòrsa",
+  "notifications.column_settings.filter_bar.category": "Bàr-criathraidh luath",
   "notifications.column_settings.follow": "Luchd-leantainn ùr:",
   "notifications.column_settings.follow_request": "Iarrtasan leantainn ùra:",
   "notifications.column_settings.mention": "Iomraidhean:",
@@ -508,7 +516,7 @@
   "notifications.permission_denied": "Chan eil brathan deasga ri fhaighinn on a chaidh iarrtas ceadan a’ bhrabhsair a dhiùltadh cheana",
   "notifications.permission_denied_alert": "Cha ghabh brathan deasga a chur an comas on a chaidh iarrtas ceadan a’ bhrabhsair a dhiùltadh cheana",
   "notifications.permission_required": "Chan eil brathan deasga ri fhaighinn on nach deach an cead riatanach a thoirt seachad.",
-  "notifications.policy.filter_new_accounts.hint": "Chaidh a chruthachadh o chionn {days, plural, one {# latha} two {# latha} few {# làithean} other {# latha}}",
+  "notifications.policy.filter_new_accounts.hint": "A chaidh a chruthachadh o chionn {days, plural, one {# latha} two {# latha} few {# làithean} other {# latha}}",
   "notifications.policy.filter_new_accounts_title": "Cunntasan ùra",
   "notifications.policy.filter_not_followers_hint": "A’ gabhail a-staigh an fheadhainn a lean ort nas lugha na {days, plural, one {# latha} two {# latha} few {# làithean} other {# latha}} seo chaidh",
   "notifications.policy.filter_not_followers_title": "Daoine nach eil gad leantainn",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 3bf89fedc..16e7e6c44 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -471,6 +471,11 @@
   "notification.own_poll": "アンケートが終了しました",
   "notification.poll": "アンケートが終了しました",
   "notification.reblog": "{name}さんがあなたの投稿をブーストしました",
+  "notification.relationships_severance_event": "{name} との関係が失われました",
+  "notification.relationships_severance_event.account_suspension": "{from} の管理者が {target} さんを停止したため、今後このユーザーとの交流や新しい投稿の受け取りができなくなりました。",
+  "notification.relationships_severance_event.domain_block": "{from} の管理者が {target} をブロックしました。これにより{followersCount}フォロワーと{followingCount, plural, other {#フォロー}}が失われました。",
+  "notification.relationships_severance_event.learn_more": "詳細を確認",
+  "notification.relationships_severance_event.user_domain_block": "{target} のブロックにより{followersCount}フォロワーと{followingCount, plural, other {#フォロー}}が解除されました。",
   "notification.status": "{name}さんが投稿しました",
   "notification.update": "{name}さんが投稿を編集しました",
   "notification_requests.accept": "受け入れる",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index b43af3c0a..0d416be2a 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -279,6 +279,7 @@
   "filter_modal.select_filter.subtitle": "Naudok esamą kategoriją arba sukurk naują.",
   "filter_modal.select_filter.title": "Filtruoti šį įrašą",
   "filter_modal.title.status": "Filtruoti įrašą",
+  "filtered_notifications_banner.private_mentions": "{count, plural, one {privatus paminėjimas} few {privatūs paminėjimai} many {privataus paminėjimo} other {privačių paminėjimų}}",
   "firehose.all": "Visi",
   "firehose.local": "Šis serveris",
   "firehose.remote": "Kiti serveriai",
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index 9043e23b9..93a0720b8 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -1751,13 +1751,17 @@ ar:
     import: استيراد
     import_and_export: استيراد وتصدير
     migrate: تهجير الحساب
+    notifications: إشعارات البريد الإلكتروني
     preferences: التفضيلات
     profile: الملف التعريفي
     relationships: المتابِعون والمتابَعون
+    severed_relationships: العلاقات المنفصلة
     statuses_cleanup: الحذف الآلي للمنشورات
     strikes: عقوبات الإشراف
     two_factor_authentication: المُصادقة بخُطوَتَيْن
     webauthn_authentication: مفاتيح الأمان
+  severed_relationships:
+    download: تنزيل (%{count})
   statuses:
     attached:
       audio:
@@ -1875,6 +1879,7 @@ ar:
     contrast: ماستدون (تباين عالٍ)
     default: ماستدون (داكن)
     mastodon-light: ماستدون (فاتح)
+    system: تلقائي (استخدم سمة النظام)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
@@ -1973,8 +1978,19 @@ ar:
       edit_profile_title: قم بتخصيص ملفك التعريفي
       explanation: ها هي بعض النصائح قبل بداية الاستخدام
       feature_action: اعرف المزيد
+      feature_audience_title: اِبنوا جُمهورَكم بِثِقَة
+      feature_control: أنتم الأدرى بالمحتوى الذي تريدون أن تطالعوه في فيض المنشورات الرئيس. لا خوارزميات تتحكم فيما يظهر لكم ولا إعلانات تضيع وقتكم. بحساب واحد تمكنكم متابعة من تشاؤون على أيّ خادوم ماستدون، وتلقّى منشوراتهم بترتيبها الزمني، لتصنعوا ركنكم الأليف في الإنترنت.
+      feature_control_title: تحكَّموا في فيض المنشورات الخاص بكم
+      feature_creativity: ماستدون يدعم المشاركات الصوتية والفيديو والصورة، وصوفات الوصولية، واستطلاعات الرأي، وتحذيرات المحتوى، والصور الرمزية المتحركة، ورموز الإيموجي المطوّعة، والتحكم في قص مصغّرات الصور، والمزيد، لأجل مساعدتكم على التعبير عن أنفسكم عبر الإنترنت. فسواء كنتم تنشرون فنونكم البصرية أو الموسيقية أو البودكاستات، فستجدون ماستدون مفيدًا.
+      feature_creativity_title: إبداعٌ بلا نظير
+      feature_moderation: ماستدون يُرجع القرار لكم، حيث يضع كل خادوم قواعده ولوائحه الخاصة لإدارة المحتوى ومجتمع المشاركين، وهي تُطبّق محليا، ليس من أعلى إلى أسفل مثل منصات التواصل الاجتماعي التجارية. هذا يجعلها أكثر مرونة في الاستجابة لاحتياجات مختلف فئات الناس. انضم إلى خادوم يُطبّق القواعد التي توافق عليها، وإلا فشغّلوا خادومكم بأنفسكم.
+      feature_moderation_title: الإشرَافُ كما يَنبغي أن يكون
       follow_action: تابِع
+      follow_step: إن متابعة الأشخاص المثيرين للاهتمام هي غاية ماستدون.
+      follow_title: أضفِ طابعا شخصيا على موجزات خيطك الرئيس
+      follows_subtitle: اتبع الحسابات المشهورة
       follows_title: مَن عليك متابعته
+      follows_view_more: متابعة المزيد من الأشخاص
       hashtags_title: الوسوم الرائجة
       hashtags_view_more: عرض المزيد من الوسوم الرائجة
       post_action: إنشاء
diff --git a/config/locales/devise.es.yml b/config/locales/devise.es.yml
index 0d8fc0ac6..0fc329e0b 100644
--- a/config/locales/devise.es.yml
+++ b/config/locales/devise.es.yml
@@ -32,8 +32,8 @@ es:
         subject: 'Mastodon: Correo electrónico cambiado'
         title: Nueva dirección de correo electrónico
       password_change:
-        explanation: La contraseña de su cuenta a sido cambiada.
-        extra: Si usted no a cambiado su contraseña. es probable que alguien a conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte a el administrador de la instancia si usted esta bloqueado de su cuenta.
+        explanation: La contraseña de su cuenta ha sido cambiada.
+        extra: Si usted no ha cambiado su contraseña, es probable que alguien a conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte al administrador de la instancia si usted está bloqueado de su cuenta.
         subject: 'Mastodon: Contraseña cambiada'
         title: Contraseña cambiada
       reconfirmation_instructions:
diff --git a/config/locales/devise.lt.yml b/config/locales/devise.lt.yml
index 548894cca..ec5b85272 100644
--- a/config/locales/devise.lt.yml
+++ b/config/locales/devise.lt.yml
@@ -54,9 +54,9 @@ lt:
         title: 2FA išjungta
       two_factor_enabled:
         explanation: Prisijungiant reikės susietos TOTP programėlės sugeneruoto priegos rakto.
-        subject: 'Mastodon: dviejų tapatybės patikrinimas įgalintas'
+        subject: 'Mastodon: dviejų tapatybės patvirtinimas įjungtas'
         subtitle: Tavo paskyrai įjungtas dviejų tapatybės patikrinimas.
-        title: 2FA įgalinta
+        title: 2FA įjungta
       two_factor_recovery_codes_changed:
         explanation: Ankstesnieji atkūrimo kodai yra negaliojantys ir sugeneruojami nauji.
         subject: 'Mastodon: dviejų tapatybės atkūrimo kodai iš naujo sugeneruoti'
@@ -81,8 +81,8 @@ lt:
       webauthn_enabled:
         explanation: Tavo paskyrai įjungtas saugumo rakto tapatybės nustatymas.
         extra: Tavo saugumo raktą dabar galima naudoti prisijungimui.
-        subject: 'Mastodon: saugumo rakto tapatybės nustatymas įgalintas'
-        title: Saugumo raktai įgalinti
+        subject: 'Mastodon: saugumo rakto tapatybės nustatymas įjungtas'
+        title: Saugumo raktai įjungti
     omniauth_callbacks:
       failure: Nepavyko nustatyti tapatybės iš %{kind}, nes „%{reason}“.
       success: Sėkmingai nustatyta tapatybė iš %{kind} paskyros.
diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml
index 1012160f6..6f63e0309 100644
--- a/config/locales/doorkeeper.lt.yml
+++ b/config/locales/doorkeeper.lt.yml
@@ -19,7 +19,7 @@ lt:
   doorkeeper:
     applications:
       buttons:
-        authorize: Įgalinti
+        authorize: Leisti
         cancel: Atšaukti
         destroy: Sunaikinti
         edit: Redaguoti
@@ -55,14 +55,14 @@ lt:
         title: 'Programėlė: %{name}'
     authorizations:
       buttons:
-        authorize: Įgalinti
+        authorize: Leisti
         deny: Atmesti
       error:
         title: Įvyko klaida.
       new:
-        prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum jai leisti.</strong>"
+        prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum leisti.</strong>"
         review_permissions: Peržiūrėti leidimus
-        title: Reikalingas įgaliojimas
+        title: Reikalingas leidimas
       show:
         title: Nukopijuok šį įgaliojimo kodą ir įklijuok jį į programėlę.
     authorized_applications:
@@ -77,7 +77,7 @@ lt:
         never_used: Niekada nenaudotas
         scopes: Leidimai
         superapp: Vidinis
-        title: Tavo įgaliotos programėlės
+        title: Tavo leidžiamos programėlės
     errors:
       messages:
         access_denied: Išteklių savininkas (-ė) arba įgaliojimų serveris atmetė užklausą.
@@ -145,7 +145,7 @@ lt:
           applications: Programėlės
           oauth2_provider: OAuth2 teikėjas
       application:
-        title: Reikalingas OAuth įgaliojimas
+        title: Reikalingas OAuth leidimas
     scopes:
       admin:read: skaityti visus serveryje esančius duomenis
       admin:read:accounts: skaityti neskelbtiną visų paskyrų informaciją
diff --git a/config/locales/doorkeeper.sr.yml b/config/locales/doorkeeper.sr.yml
index a0439d606..010eb23eb 100644
--- a/config/locales/doorkeeper.sr.yml
+++ b/config/locales/doorkeeper.sr.yml
@@ -22,12 +22,12 @@ sr:
         authorize: Ауторизуј
         cancel: Поништи
         destroy: Уништи
-        edit: Измени
+        edit: Уреди
         submit: Пошаљи
       confirmations:
         destroy: Да ли сте сигурни?
       edit:
-        title: Измени апликацију
+        title: Уреди апликацију
       form:
         error: Опс! Проверите формулар за евентуалне грешке
       help:
diff --git a/config/locales/gd.yml b/config/locales/gd.yml
index 11402d3f5..70bace05c 100644
--- a/config/locales/gd.yml
+++ b/config/locales/gd.yml
@@ -1832,6 +1832,7 @@ gd:
     contrast: Mastodon (iomsgaradh àrd)
     default: Mastodon (dorcha)
     mastodon-light: Mastodon (soilleir)
+    system: Fèin-obrachail (cleachd ùrlar an t-siostaim)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index b7c6813a7..0d585131e 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1723,6 +1723,7 @@ ja:
     contrast: Mastodon (ハイコントラスト)
     default: Mastodon (ダーク)
     mastodon-light: Mastodon (ライト)
+    system: 自動 (システムのテーマを使用)
   time:
     formats:
       default: "%Y年%m月%d日 %H:%M"
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 832d9e9db..9664a4ab5 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -410,9 +410,9 @@ lt:
           silence: Riboti
           suspend: Pristabdyti
         title: Naujos domeno blokas
-      reject_media: Atmesti medijos failai
+      reject_media: Atmesti medijos failus
       reject_media_hint: Panaikina lokaliai saugomus medijos failus bei atsisako jų parsisiuntimo ateityje. Neliečia užblokavimu
-      reject_reports: Atmesti skundai
+      reject_reports: Atmesti ataskaitas
       reject_reports_hint: Ignoruoti visus skundus, kurie siunčiami iš šio domeno. Neliečia užblokavimu
       undo: Atkurti domeno bloką
     email_domain_blocks:
@@ -799,6 +799,7 @@ lt:
     contrast: Mastodon (Didelio Kontrasto)
     default: Mastodon (Tamsus)
     mastodon-light: Mastodon (Šviesus)
+    system: Automatinis (naudoti sistemos temą)
   two_factor_authentication:
     disable: Išjungti
     enabled: Dviejų veiksnių autentikacija įjungta
diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml
index 627d96df0..790bcd061 100644
--- a/config/locales/simple_form.ko.yml
+++ b/config/locales/simple_form.ko.yml
@@ -295,7 +295,7 @@ ko:
         software_updates:
           all: 모든 업데이트에 대해 알림
           critical: 긴급 업데이트에 대해서만 알림
-          label: 새 마스토돈 버전이 사용 가능합니다
+          label: 새 마스토돈 버전이 있을 때
           none: 업데이트에 대해 알리지 않기 (비추천)
           patch: 버그픽스 업데이트에 대해 알림
         trending_tag: 검토해야 할 새 유행
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 4f10fe864..8b876b8a1 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -1396,7 +1396,7 @@ sr-Latn:
       '43200': 12 sati
       '604800': 1 nedelja
       '86400': 1 dan
-    expires_in_prompt: Nikad
+    expires_in_prompt: Nikada
     generate: Generiši
     invalid: Ova pozivnica nije važeća
     invited_by: 'Pozvao Vas je:'
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 382f196bd..faed5854f 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -65,7 +65,7 @@ sr:
       disabled: Замрзнут
       display_name: Име за приказ
       domain: Домен
-      edit: Измени
+      edit: Уреди
       email: Е-пошта
       email_status: Статус е-поште
       enable: Омогући
@@ -402,7 +402,7 @@ sr:
       created_msg: Блокирање домена се обрађује
       destroyed_msg: Блокирање домена је опозвано
       domain: Домен
-      edit: Измени блок домена
+      edit: Уреди блок домена
       existing_domain_block: Већ сте успоставили строжа ограничења према кориснику %{name}.
       existing_domain_block_html: Већ сте успоставили строжа ограничења према %{name}, потребно је да га прво <a href="%{unblock_url}">одблокирате</a>.
       export: Извоз
@@ -690,7 +690,7 @@ sr:
         special: Посебно
       delete: Избриши
       description_html: Помоћу <strong>корисничких улога</strong> можете да подесите којим функцијама и деловима Mastodon-а ваши корисници могу да приступе.
-      edit: Измени улогу '%{name}'
+      edit: Уреди улогу '%{name}
       everyone: Подразумевана овлашћења
       everyone_full_description_html: Ово је <strong>основна улога</strong> која се односи на <strong>све кориснике</strong>, чак и оне којима није додељена улога. Све друге улоге наслеђују овлашћења од основне улоге.
       permissions_count:
@@ -970,7 +970,7 @@ sr:
       description_html: "<strong>Webhook</strong> омогућава Mastodon-у да вашој апликацији испоручује <strong>обавештења у реалном времену</strong> о одабраним догађајима, тако да ваша апликација може да <strong>aутоматски изазове реакцију</strong>."
       disable: Онемогући
       disabled: Онемогућено
-      edit: Измени крајњу тачку
+      edit: Уреди крајњу тачку
       empty: Још увек немате ниједну конфигурисану webhook крајњу тачку.
       enable: Омогући
       enabled: Активно
@@ -1267,7 +1267,7 @@ sr:
       keywords: Кључне речи
       statuses: Засебне објаве
       statuses_hint_html: Овај филтер важи за одабране засебне објаве без обзира на то да ли садрже кључне речи наведене испод. <a href="%{path}">Прегледајте или уклоните објаве из филтера</a>.
-      title: Измени филтер
+      title: Уреди филтер
     errors:
       deprecated_api_multiple_keywords: Ови параметри не могу бити промењени у овој апликацији зато што се односе на више од једне кључне речи. Користите ажурнију апликацију или веб интерфејс.
       invalid_context: Ниједан или неважећи контекст испоручен
@@ -1396,7 +1396,7 @@ sr:
       '43200': 12 сати
       '604800': 1 недеља
       '86400': 1 дан
-    expires_in_prompt: Никад
+    expires_in_prompt: Никада
     generate: Генериши
     invalid: Ова позивница није важећа
     invited_by: 'Позвао Вас је:'
@@ -1516,7 +1516,7 @@ sr:
     status:
       subject: "%{name} jе управо поставио/-ла објаву"
     update:
-      subject: "%{name} је изменио/-ла објаву"
+      subject: "%{name} је уредио/-ла објаву"
   notifications:
     administration_emails: Обавештења е-поштом од администратора
     email_events: Догађаји за обавештења е-поштом
@@ -1707,7 +1707,7 @@ sr:
       few: 'садржи забрањене хеш ознаке: %{tags}'
       one: 'садржи забрањену хеш ознаку: %{tags}'
       other: 'садржи забрањене хеш ознаке: %{tags}'
-    edited_at_html: Измењено %{date}
+    edited_at_html: Уређено %{date}
     errors:
       in_reply_not_found: Објава на коју покушавате да одговорите наизглед не постоји.
     open_in_web: Отвори у вебу
@@ -1798,7 +1798,7 @@ sr:
     add: Додај
     disable: Искључи
     disabled_success: Двофакторска аутентификација је успешно онемогућена
-    edit: Измени
+    edit: Уреди
     enabled: Двофакторска идентификација је укључена
     enabled_success: Двофакторска идентификација је успешно укључена
     generate_recovery_codes: Генериши кодове за опоравак
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 02c4b8c55..d078cf720 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -597,6 +597,9 @@ sv:
       actions_description_html: Välj vilken åtgärd som skall vidtas för att lösa denna rapport. Om du vidtar en bestraffningsåtgärd mot det rapporterade kontot kommer en e-postnotis att skickas till dem, förutom om du valt kategorin <strong>Skräppost</strong>.
       actions_description_remote_html: Bestäm vilka åtgärder som ska vidtas för att lösa denna rapport. Detta kommer bara att påverka hur <strong>din</strong> server kommunicerar med detta fjärrkonto och hanterar dess innehåll.
       add_to_report: Lägg till mer i rapporten
+      already_suspended_badges:
+        local: Redan avstängd på denna server
+        remote: Redan avstängd på deras server
       are_you_sure: Är du säker?
       assign_to_self: Tilldela till mig
       assigned: Tilldelad moderator
@@ -1656,12 +1659,21 @@ sv:
     preferences: Inställningar
     profile: Profil
     relationships: Följer och följare
+    severed_relationships: Avbrutna relationer
     statuses_cleanup: Automatisk radering av inlägg
     strikes: Modereringsprickar
     two_factor_authentication: Tvåfaktorsautentisering
     webauthn_authentication: Säkerhetsnycklar
   severed_relationships:
+    download: Hämta (%{count})
+    event_type:
+      account_suspension: Kontoavstängning (%{target_name})
+      domain_block: Serveravstängning (%{target_name})
+      user_domain_block: Du blockerade %{target_name}
+    lost_followers: Förlorade följare
     lost_follows: Förlorade följare
+    preamble: Du kan förlora följer och följare när du blockerar en domän eller när din moderator väljer att stänga av en fjärrserver. När det händer kommer du kunna hämta listor över avbrutna relationer som kan inspekteras och eventuellt importeras på en annan server.
+    purged: Information om denna server har rensats av din servers administratörer.
     type: Händelse
   statuses:
     attached:

From f3430eebbb3256a9037827d5e6c3d6c9013e8b43 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Mon, 8 Apr 2024 15:45:25 +0200
Subject: [PATCH 115/173] Fix hashtag string interpolation in welcome email
 (#29879)

---
 app/views/application/mailer/_hashtag.html.haml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/views/application/mailer/_hashtag.html.haml b/app/views/application/mailer/_hashtag.html.haml
index 74a00e67e..b740ba31b 100644
--- a/app/views/application/mailer/_hashtag.html.haml
+++ b/app/views/application/mailer/_hashtag.html.haml
@@ -17,4 +17,5 @@
                           %span.email-mini-hashtag-img-span
                             = image_tag full_asset_url(account.avatar.url), alt: '', width: 16, height: 16
                       %td
-                        %p= t('user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(hashtag.history.aggregate(2.days.ago.to_date..Time.zone.today).accounts))
+                        - people = hashtag.history.aggregate(2.days.ago.to_date..Time.zone.today).accounts
+                        %p= t('user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people)

From babbf6017d3f00e730f2c1e28542b3af3967acde Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Mon, 8 Apr 2024 15:46:13 +0200
Subject: [PATCH 116/173] Remove caching in `cache_collection` (#29862)

---
 app/controllers/concerns/cache_concern.rb     | 22 ++++--------
 app/models/concerns/cacheable.rb              |  4 +++
 app/models/feed.rb                            |  2 +-
 app/models/public_feed.rb                     |  2 +-
 app/models/status.rb                          | 32 -----------------
 app/models/tag_feed.rb                        |  2 +-
 .../application_controller_spec.rb            | 35 -------------------
 spec/models/home_feed_spec.rb                 |  1 -
 8 files changed, 14 insertions(+), 86 deletions(-)

diff --git a/app/controllers/concerns/cache_concern.rb b/app/controllers/concerns/cache_concern.rb
index 62f763fe2..4656539f8 100644
--- a/app/controllers/concerns/cache_concern.rb
+++ b/app/controllers/concerns/cache_concern.rb
@@ -46,27 +46,19 @@ module CacheConcern
     end
   end
 
+  # TODO: Rename this method, as it does not perform any caching anymore.
   def cache_collection(raw, klass)
-    return raw unless klass.respond_to?(:with_includes)
+    return raw unless klass.respond_to?(:preload_cacheable_associations)
 
-    raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
-    return [] if raw.empty?
+    records = raw.to_a
 
-    cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id)
+    klass.preload_cacheable_associations(records)
 
-    uncached_ids = raw.map(&:id) - cached_keys_with_value.keys
-
-    klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)
-
-    unless uncached_ids.empty?
-      uncached = klass.where(id: uncached_ids).with_includes.index_by(&:id)
-      Rails.cache.write_multi(uncached.values.to_h { |i| [i, i] })
-    end
-
-    raw.filter_map { |item| cached_keys_with_value[item.id] || uncached[item.id] }
+    records
   end
 
+  # TODO: Rename this method, as it does not perform any caching anymore.
   def cache_collection_paginated_by_id(raw, klass, limit, options)
-    cache_collection raw.cache_ids.to_a_paginated_by_id(limit, options), klass
+    cache_collection raw.to_a_paginated_by_id(limit, options), klass
   end
 end
diff --git a/app/models/concerns/cacheable.rb b/app/models/concerns/cacheable.rb
index d7524cdfd..0633f20c7 100644
--- a/app/models/concerns/cacheable.rb
+++ b/app/models/concerns/cacheable.rb
@@ -14,6 +14,10 @@ module Cacheable
       includes(@cache_associated)
     end
 
+    def preload_cacheable_associations(records)
+      ActiveRecord::Associations::Preloader.new(records: records, associations: @cache_associated).call
+    end
+
     def cache_ids
       select(:id, :updated_at)
     end
diff --git a/app/models/feed.rb b/app/models/feed.rb
index d9cab2cd1..27e128099 100644
--- a/app/models/feed.rb
+++ b/app/models/feed.rb
@@ -28,7 +28,7 @@ class Feed
       unhydrated = redis.zrangebyscore(key, "(#{min_id}", "(#{max_id}", limit: [0, limit], with_scores: true).map { |id| id.first.to_i }
     end
 
-    Status.where(id: unhydrated).cache_ids
+    Status.where(id: unhydrated)
   end
 
   def key
diff --git a/app/models/public_feed.rb b/app/models/public_feed.rb
index 1e2cca4d3..ba9473db0 100644
--- a/app/models/public_feed.rb
+++ b/app/models/public_feed.rb
@@ -29,7 +29,7 @@ class PublicFeed
     scope.merge!(media_only_scope) if media_only?
     scope.merge!(language_scope) if account&.chosen_languages.present?
 
-    scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
+    scope.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
   end
 
   private
diff --git a/app/models/status.rb b/app/models/status.rb
index ae53513ee..78186623c 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -346,38 +346,6 @@ class Status < ApplicationRecord
       StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |p, h| h[p.status_id] = true }
     end
 
-    def reload_stale_associations!(cached_items)
-      account_ids = []
-
-      cached_items.each do |item|
-        account_ids << item.account_id
-        account_ids << item.reblog.account_id if item.reblog?
-      end
-
-      account_ids.uniq!
-
-      status_ids = cached_items.map { |item| item.reblog? ? item.reblog_of_id : item.id }.uniq
-
-      return if account_ids.empty?
-
-      accounts = Account.where(id: account_ids).includes(:account_stat, :user).index_by(&:id)
-
-      status_stats = StatusStat.where(status_id: status_ids).index_by(&:status_id)
-
-      cached_items.each do |item|
-        item.account = accounts[item.account_id]
-        item.reblog.account = accounts[item.reblog.account_id] if item.reblog?
-
-        if item.reblog?
-          status_stat = status_stats[item.reblog.id]
-          item.reblog.status_stat = status_stat if status_stat.present?
-        else
-          status_stat = status_stats[item.id]
-          item.status_stat = status_stat if status_stat.present?
-        end
-      end
-    end
-
     def from_text(text)
       return [] if text.blank?
 
diff --git a/app/models/tag_feed.rb b/app/models/tag_feed.rb
index b8cd63557..6b5831d24 100644
--- a/app/models/tag_feed.rb
+++ b/app/models/tag_feed.rb
@@ -33,7 +33,7 @@ class TagFeed < PublicFeed
     scope.merge!(account_filters_scope) if account?
     scope.merge!(media_only_scope) if media_only?
 
-    scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
+    scope.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
   end
 
   private
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index a309e933e..f595e8ca1 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -218,39 +218,4 @@ describe ApplicationController do
 
     include_examples 'respond_with_error', 422
   end
-
-  describe 'cache_collection' do
-    subject do
-      Class.new(ApplicationController) do
-        public :cache_collection
-      end
-    end
-
-    shared_examples 'receives :with_includes' do |fabricator, klass|
-      it 'uses raw if it is not an ActiveRecord::Relation' do
-        record = Fabricate(fabricator)
-        expect(subject.new.cache_collection([record], klass)).to eq [record]
-      end
-    end
-
-    shared_examples 'cacheable' do |fabricator, klass|
-      include_examples 'receives :with_includes', fabricator, klass
-
-      it 'calls cache_ids of raw if it is an ActiveRecord::Relation' do
-        record = Fabricate(fabricator)
-        relation = klass.none
-        allow(relation).to receive(:cache_ids).and_return([record])
-        expect(subject.new.cache_collection(relation, klass)).to eq [record]
-      end
-    end
-
-    it 'returns raw unless class responds to :with_includes' do
-      raw = Object.new
-      expect(subject.new.cache_collection(raw, Object)).to eq raw
-    end
-
-    context 'with a Status' do
-      include_examples 'cacheable', :status, Status
-    end
-  end
 end
diff --git a/spec/models/home_feed_spec.rb b/spec/models/home_feed_spec.rb
index bd649d826..06bb63b1a 100644
--- a/spec/models/home_feed_spec.rb
+++ b/spec/models/home_feed_spec.rb
@@ -27,7 +27,6 @@ RSpec.describe HomeFeed do
         results = subject.get(3)
 
         expect(results.map(&:id)).to eq [3, 2]
-        expect(results.first.attributes.keys).to eq %w(id updated_at)
       end
     end
 

From 285f63c02ed34c5faa99c08713fa77fbf8ed4318 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 8 Apr 2024 09:53:49 -0400
Subject: [PATCH 117/173] Use composable query in `User.active` scope (#29775)

---
 app/lib/feed_manager.rb                     |  2 +-
 app/lib/vacuum/feeds_vacuum.rb              |  2 +-
 app/models/concerns/account/interactions.rb |  4 +-
 app/models/user.rb                          |  6 ++-
 spec/models/user_spec.rb                    | 42 ++++++++++++++++++---
 5 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index bf6e6db59..9ddc54c16 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -18,7 +18,7 @@ class FeedManager
   # @yield [Account]
   # @return [void]
   def with_active_accounts(&block)
-    Account.joins(:user).where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago).find_each(&block)
+    Account.joins(:user).merge(User.signed_in_recently).find_each(&block)
   end
 
   # Redis key of a feed
diff --git a/app/lib/vacuum/feeds_vacuum.rb b/app/lib/vacuum/feeds_vacuum.rb
index fb0b8a847..429215760 100644
--- a/app/lib/vacuum/feeds_vacuum.rb
+++ b/app/lib/vacuum/feeds_vacuum.rb
@@ -21,7 +21,7 @@ class Vacuum::FeedsVacuum
   end
 
   def inactive_users
-    User.confirmed.inactive
+    User.confirmed.not_signed_in_recently
   end
 
   def inactive_users_lists
diff --git a/app/models/concerns/account/interactions.rb b/app/models/concerns/account/interactions.rb
index a32697b66..536afba17 100644
--- a/app/models/concerns/account/interactions.rb
+++ b/app/models/concerns/account/interactions.rb
@@ -255,13 +255,13 @@ module Account::Interactions
   def followers_for_local_distribution
     followers.local
              .joins(:user)
-             .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
+             .merge(User.signed_in_recently)
   end
 
   def lists_for_local_distribution
     scope = lists.joins(account: :user)
     scope.where.not(list_accounts: { follow_id: nil }).or(scope.where(account_id: id))
-         .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
+         .merge(User.signed_in_recently)
   end
 
   def remote_followers_hash(url)
diff --git a/app/models/user.rb b/app/models/user.rb
index c62a6d0de..584120cf2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -109,14 +109,16 @@ class User < ApplicationRecord
   validates :confirm_password, absence: true, on: :create
   validate :validate_role_elevation
 
+  scope :account_not_suspended, -> { joins(:account).merge(Account.without_suspended) }
   scope :recent, -> { order(id: :desc) }
   scope :pending, -> { where(approved: false) }
   scope :approved, -> { where(approved: true) }
   scope :confirmed, -> { where.not(confirmed_at: nil) }
   scope :enabled, -> { where(disabled: false) }
   scope :disabled, -> { where(disabled: true) }
-  scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
-  scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) }
+  scope :active, -> { confirmed.signed_in_recently.account_not_suspended }
+  scope :signed_in_recently, -> { where(current_sign_in_at: ACTIVE_DURATION.ago..) }
+  scope :not_signed_in_recently, -> { where(current_sign_in_at: ...ACTIVE_DURATION.ago) }
   scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
   scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') }
 
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 2a0726306..714d595dc 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -107,12 +107,36 @@ RSpec.describe User do
       end
     end
 
-    describe 'inactive' do
-      it 'returns a relation of inactive users' do
-        specified = Fabricate(:user, current_sign_in_at: 15.days.ago)
-        Fabricate(:user, current_sign_in_at: 6.days.ago)
+    describe 'signed_in_recently' do
+      it 'returns a relation of users who have signed in during the recent period' do
+        recent_sign_in_user = Fabricate(:user, current_sign_in_at: within_duration_window_days.ago)
+        Fabricate(:user, current_sign_in_at: exceed_duration_window_days.ago)
 
-        expect(described_class.inactive).to contain_exactly(specified)
+        expect(described_class.signed_in_recently)
+          .to contain_exactly(recent_sign_in_user)
+      end
+    end
+
+    describe 'not_signed_in_recently' do
+      it 'returns a relation of users who have not signed in during the recent period' do
+        no_recent_sign_in_user = Fabricate(:user, current_sign_in_at: exceed_duration_window_days.ago)
+        Fabricate(:user, current_sign_in_at: within_duration_window_days.ago)
+
+        expect(described_class.not_signed_in_recently)
+          .to contain_exactly(no_recent_sign_in_user)
+      end
+    end
+
+    describe 'account_not_suspended' do
+      it 'returns with linked accounts that are not suspended' do
+        suspended_account = Fabricate(:account, suspended_at: 10.days.ago)
+        non_suspended_account = Fabricate(:account, suspended_at: nil)
+        suspended_user = Fabricate(:user, account: suspended_account)
+        non_suspended_user = Fabricate(:user, account: non_suspended_account)
+
+        expect(described_class.account_not_suspended)
+          .to include(non_suspended_user)
+          .and not_include(suspended_user)
       end
     end
 
@@ -137,6 +161,14 @@ RSpec.describe User do
         expect(described_class.matches_ip('2160:2160::/32')).to contain_exactly(user1)
       end
     end
+
+    def exceed_duration_window_days
+      described_class::ACTIVE_DURATION + 2.days
+    end
+
+    def within_duration_window_days
+      described_class::ACTIVE_DURATION - 2.days
+    end
   end
 
   describe 'blacklist' do

From b8dca8d22a7b8d41b6512ac4174152ae5115788c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 8 Apr 2024 16:08:32 +0200
Subject: [PATCH 118/173] Update dependency typescript to v5.4.4 (#29875)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 49d36702d..c4efdb4ad 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -17083,22 +17083,22 @@ __metadata:
   linkType: hard
 
 "typescript@npm:5, typescript@npm:^5.0.4":
-  version: 5.4.3
-  resolution: "typescript@npm:5.4.3"
+  version: 5.4.4
+  resolution: "typescript@npm:5.4.4"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/22443a8760c3668e256c0b34b6b45c359ef6cecc10c42558806177a7d500ab1a7d7aac1f976d712e26989ddf6731d2fbdd3212b7c73290a45127c1c43ba2005a
+  checksum: 10c0/4d8de0291204ed61ca97ad0cba2ce064e09c4988ca1c451c787e4653ba76296ba35177a52694e8a00cf4ef899d0ee83338663b926d8b7d55167ff0ba81549999
   languageName: node
   linkType: hard
 
 "typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>":
-  version: 5.4.3
-  resolution: "typescript@patch:typescript@npm%3A5.4.3#optional!builtin<compat/typescript>::version=5.4.3&hash=5adc0c"
+  version: 5.4.4
+  resolution: "typescript@patch:typescript@npm%3A5.4.4#optional!builtin<compat/typescript>::version=5.4.4&hash=5adc0c"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/6e51f8b7e6ec55b897b9e56b67e864fe8f44e30f4a14357aad5dc0f7432db2f01efc0522df0b6c36d361c51f2dc3dcac5c832efd96a404cfabf884e915d38828
+  checksum: 10c0/1fa41b9964a9ff0ed913b339c90b46031b2d2da3cb1a192af516610733f7f1d5f7f9754a8e22b9ac7076d3d8aedd2c4f84db3f113bad060eac3a95962443a1bf
   languageName: node
   linkType: hard
 

From 4948a063d20c94cf9eb6dc60c2c30898cb05f4c1 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 10 Apr 2024 05:20:21 -0400
Subject: [PATCH 119/173] Use `tt` extension for form scaffold template
 (#29676)

---
 .haml-lint.yml                                                   | 1 -
 .../haml/scaffold/{_form.html.haml => _form.html.haml.tt}        | 0
 2 files changed, 1 deletion(-)
 rename lib/templates/haml/scaffold/{_form.html.haml => _form.html.haml.tt} (100%)

diff --git a/.haml-lint.yml b/.haml-lint.yml
index e493afb85..74d243a3a 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -1,6 +1,5 @@
 exclude:
   - 'vendor/**/*'
-  - lib/templates/haml/scaffold/_form.html.haml
 
 require:
   - ./lib/linter/haml_middle_dot.rb
diff --git a/lib/templates/haml/scaffold/_form.html.haml b/lib/templates/haml/scaffold/_form.html.haml.tt
similarity index 100%
rename from lib/templates/haml/scaffold/_form.html.haml
rename to lib/templates/haml/scaffold/_form.html.haml.tt

From b57ee5cf5ba312b6e5f5df9208be8e2b02e13242 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 10 Apr 2024 08:46:39 -0400
Subject: [PATCH 120/173] Fix `Style/MapIntoArray` cop in context helper
 (#29885)

---
 app/helpers/context_helper.rb | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/app/helpers/context_helper.rb b/app/helpers/context_helper.rb
index 2d7a4f98f..cbefe0fe5 100644
--- a/app/helpers/context_helper.rb
+++ b/app/helpers/context_helper.rb
@@ -48,13 +48,11 @@ module ContextHelper
   end
 
   def serialized_context(named_contexts_map, context_extensions_map)
-    context_array = []
-
     named_contexts     = named_contexts_map.keys
     context_extensions = context_extensions_map.keys
 
-    named_contexts.each do |key|
-      context_array << NAMED_CONTEXT_MAP[key]
+    context_array = named_contexts.map do |key|
+      NAMED_CONTEXT_MAP[key]
     end
 
     extensions = context_extensions.each_with_object({}) do |key, h|

From 45650156159ad2e71ac5cf04c8b780455ca90deb Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 10 Apr 2024 08:46:43 -0400
Subject: [PATCH 121/173] Fix `Style/MapIntoArray` cop in cli progress helper
 (#29884)

---
 lib/mastodon/cli/progress_helper.rb | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/lib/mastodon/cli/progress_helper.rb b/lib/mastodon/cli/progress_helper.rb
index 4fcc47a7f..f22492afc 100644
--- a/lib/mastodon/cli/progress_helper.rb
+++ b/lib/mastodon/cli/progress_helper.rb
@@ -35,10 +35,8 @@ module Mastodon::CLI
       aggregate = Concurrent::AtomicFixnum.new(0)
 
       scope.reorder(nil).find_in_batches do |items|
-        futures = []
-
-        items.each do |item|
-          futures << Concurrent::Future.execute(executor: pool) do
+        futures = items.map do |item|
+          Concurrent::Future.execute(executor: pool) do
             if !progress.total.nil? && progress.progress + 1 > progress.total
               # The number of items has changed between start and now,
               # since there is no good way to predict the final count from

From db5a5636d97aa754ac7cc1fb4cd974ff9d953335 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 10 Apr 2024 15:03:40 +0200
Subject: [PATCH 122/173] New Crowdin Translations (automated) (#29888)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ca.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 37990cdb2..6f0dd9376 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -705,7 +705,7 @@
   "status.edited_x_times": "Editat {count, plural, one {{count} vegada} other {{count} vegades}}",
   "status.embed": "Incrusta",
   "status.favourite": "Favorit",
-  "status.favourites": "{count, plural, one {# favorit} other {# favorits}}",
+  "status.favourites": "{count, plural, one {favorit} other {favorits}}",
   "status.filter": "Filtra aquest tut",
   "status.filtered": "Filtrada",
   "status.hide": "Amaga el tut",
@@ -726,7 +726,7 @@
   "status.reblog": "Impulsa",
   "status.reblog_private": "Impulsa amb la visibilitat original",
   "status.reblogged_by": "impulsat per {name}",
-  "status.reblogs": "{count, plural, one {# impuls} other {# impulsos}}",
+  "status.reblogs": "{count, plural, one {impuls} other {impulsos}}",
   "status.reblogs.empty": "Encara no ha impulsat ningú aquest tut. Quan algú ho faci, apareixerà aquí.",
   "status.redraft": "Esborra i reescriu",
   "status.remove_bookmark": "Elimina el marcador",

From 96bdeeed0eeaed2c06c9e5c59049a35171ff798a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 10:50:34 +0200
Subject: [PATCH 123/173] Update dependency nokogiri to v1.16.4 (#29900)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 3508ad8d5..af80af306 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -456,7 +456,7 @@ GEM
     net-smtp (0.4.0.1)
       net-protocol
     nio4r (2.7.1)
-    nokogiri (1.16.3)
+    nokogiri (1.16.4)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     nsa (0.3.0)

From 576554b19bea0f95d110be0df779bf220d9f5b0b Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 11 Apr 2024 04:59:01 -0400
Subject: [PATCH 124/173] Use fabrication sequence in domain values (#29895)

---
 spec/fabricators/preview_card_provider_fabricator.rb | 2 +-
 spec/fabricators/unavailable_domain_fabricator.rb    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/fabricators/preview_card_provider_fabricator.rb b/spec/fabricators/preview_card_provider_fabricator.rb
index 78db71000..3a027623f 100644
--- a/spec/fabricators/preview_card_provider_fabricator.rb
+++ b/spec/fabricators/preview_card_provider_fabricator.rb
@@ -1,5 +1,5 @@
 # frozen_string_literal: true
 
 Fabricator(:preview_card_provider) do
-  domain { Faker::Internet.domain_name }
+  domain { sequence(:domain) { |i| "#{i}#{Faker::Internet.domain_name}" } }
 end
diff --git a/spec/fabricators/unavailable_domain_fabricator.rb b/spec/fabricators/unavailable_domain_fabricator.rb
index cb9707020..88e605c36 100644
--- a/spec/fabricators/unavailable_domain_fabricator.rb
+++ b/spec/fabricators/unavailable_domain_fabricator.rb
@@ -1,5 +1,5 @@
 # frozen_string_literal: true
 
 Fabricator(:unavailable_domain) do
-  domain { Faker::Internet.domain_name }
+  domain { sequence(:domain) { |i| "#{i}#{Faker::Internet.domain_name}" } }
 end

From 4826c1da8ab2ede258ec0e5913fd7523eec7a607 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 11:00:15 +0200
Subject: [PATCH 125/173] Update dependency devise to v4.9.4 (#29890)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index af80af306..3de5ab5c7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -198,7 +198,7 @@ GEM
       irb (~> 1.10)
       reline (>= 0.3.8)
     debug_inspector (1.2.0)
-    devise (4.9.3)
+    devise (4.9.4)
       bcrypt (~> 3.0)
       orm_adapter (~> 0.1)
       railties (>= 4.1.0)
@@ -607,7 +607,7 @@ GEM
     redlock (1.3.2)
       redis (>= 3.0.0, < 6.0)
     regexp_parser (2.9.0)
-    reline (0.5.0)
+    reline (0.5.1)
       io-console (~> 0.5)
     request_store (1.5.1)
       rack (>= 1.4)

From 20b1e55f24a87868d661fc7b033bbbbd48b1a918 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 12:30:31 +0200
Subject: [PATCH 126/173] New Crowdin Translations (automated) (#29903)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/it.json |  2 +-
 app/javascript/mastodon/locales/tt.json |  6 +++---
 config/locales/tt.yml                   | 18 +++++++++---------
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index fd12ee298..4679d8341 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -83,7 +83,7 @@
   "admin.impact_report.instance_follows": "I seguaci che i loro utenti perderebbero",
   "admin.impact_report.title": "Riepilogo dell'impatto",
   "alert.rate_limited.message": "Sei pregato di riprovare dopo le {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Tasso limitato",
+  "alert.rate_limited.title": "Limitazione per eccesso di richieste",
   "alert.unexpected.message": "Si è verificato un errore imprevisto.",
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Annuncio",
diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json
index 82d45205c..9a402472d 100644
--- a/app/javascript/mastodon/locales/tt.json
+++ b/app/javascript/mastodon/locales/tt.json
@@ -449,9 +449,9 @@
   "time_remaining.seconds": "{number, plural, one {# секунд} other {# секунд}} калды",
   "timeline_hint.resources.statuses": "Older toots",
   "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}",
-  "units.short.billion": "{count}Млрд",
-  "units.short.million": "{count}Млн",
-  "units.short.thousand": "{count}М",
+  "units.short.billion": "{count} млрд",
+  "units.short.million": "{count} млн",
+  "units.short.thousand": "{count} мең",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
   "upload_form.edit": "Үзгәртү",
diff --git a/config/locales/tt.yml b/config/locales/tt.yml
index c1a22a4ca..82bb18c9a 100644
--- a/config/locales/tt.yml
+++ b/config/locales/tt.yml
@@ -6,7 +6,7 @@ tt:
   accounts:
     follow: Языл
     followers:
-      other: Язылучы
+      other: язылучы
     following: Язылгансыз
     posts:
       other: Язма
@@ -137,14 +137,14 @@ tt:
       new_users: яңа кулланучылар
       software: Программа тәэминаты
       title: Идарә аслыгы
-      website: Вебсайт
+      website: Веб-сайт
     domain_allows:
-      export: Экспортлау
-      import: Импортлау
+      export: Экспорт
+      import: Импорт
     domain_blocks:
       domain: Домен
-      export: Экспортлау
-      import: Импортлау
+      export: Экспорт
+      import: Импорт
       new:
         severity:
           noop: Бернинди дә
@@ -438,8 +438,8 @@ tt:
       decimal_units:
         format: "%n %u"
         units:
-          billion: Млрд
-          million: Млн
+          billion: млрд
+          million: млн
           quadrillion: Квадрлн
           thousand: Мең
           trillion: Трлн
@@ -455,7 +455,7 @@ tt:
   preferences:
     other: Башка
   privacy_policy:
-    title: Хосусыйлык Сәясәте
+    title: Хосусыйлык сәясәте
   relationships:
     dormant: Актив түгел
     followers: Язылучылар

From 449f99e168b8048c82fd6014c029705c061018bd Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 11 Apr 2024 19:37:07 -0400
Subject: [PATCH 127/173] Fix repeated concat output buffer duplicating layout
 markup (#29918)

---
 app/helpers/theme_helper.rb             | 8 ++++----
 spec/requests/account_show_page_spec.rb | 6 ++++++
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb
index 83527ce61..d15259851 100644
--- a/app/helpers/theme_helper.rb
+++ b/app/helpers/theme_helper.rb
@@ -3,8 +3,8 @@
 module ThemeHelper
   def theme_style_tags(theme)
     if theme == 'system'
-      concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
-      concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
+      stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous') +
+        stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
     else
       stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
     end
@@ -12,8 +12,8 @@ module ThemeHelper
 
   def theme_color_tags(theme)
     if theme == 'system'
-      concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)')
-      concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)')
+      tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)') +
+        tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)')
     else
       tag.meta name: 'theme-color', content: theme_color_for(theme)
     end
diff --git a/spec/requests/account_show_page_spec.rb b/spec/requests/account_show_page_spec.rb
index e84c46c47..81e965e6e 100644
--- a/spec/requests/account_show_page_spec.rb
+++ b/spec/requests/account_show_page_spec.rb
@@ -9,12 +9,18 @@ describe 'The account show page' do
 
     get '/@alice'
 
+    expect(head_link_icons.size).to eq(4) # One general favicon and three with sizes
+
     expect(head_meta_content('og:title')).to match alice.display_name
     expect(head_meta_content('og:type')).to eq 'profile'
     expect(head_meta_content('og:image')).to match '.+'
     expect(head_meta_content('og:url')).to match 'http://.+'
   end
 
+  def head_link_icons
+    head_section.css('link[rel=icon]')
+  end
+
   def head_meta_content(property)
     head_section.meta("[@property='#{property}']")[:content]
   end

From 5992df07622e00c9bfcdcac95ef834c955ca60a7 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 12 Apr 2024 10:19:48 +0200
Subject: [PATCH 128/173] New Crowdin Translations (automated) (#29920)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/en-GB.json | 22 ++++++++
 app/javascript/mastodon/locales/eu.json    |  8 +--
 app/javascript/mastodon/locales/ko.json    |  2 +-
 app/javascript/mastodon/locales/th.json    |  4 +-
 config/locales/devise.en-GB.yml            |  1 +
 config/locales/en-GB.yml                   | 59 ++++++++++++++++++++++
 config/locales/simple_form.en-GB.yml       |  4 ++
 config/locales/simple_form.eu.yml          |  2 +-
 config/locales/simple_form.tr.yml          |  4 +-
 config/locales/th.yml                      |  1 +
 10 files changed, 97 insertions(+), 10 deletions(-)

diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json
index 228a16def..80a3479b4 100644
--- a/app/javascript/mastodon/locales/en-GB.json
+++ b/app/javascript/mastodon/locales/en-GB.json
@@ -89,6 +89,14 @@
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
   "audio.hide": "Hide audio",
+  "block_modal.remote_users_caveat": "We will ask the server {domain} to respect your decision. However, compliance is not guaranteed since some servers may handle blocks differently. Public posts may still be visible to non-logged-in users.",
+  "block_modal.show_less": "Show less",
+  "block_modal.show_more": "Show more",
+  "block_modal.they_cant_mention": "They can't mention or follow you.",
+  "block_modal.they_cant_see_posts": "They can't see your posts and you won't see theirs.",
+  "block_modal.they_will_know": "They can see that they're blocked.",
+  "block_modal.title": "Block user?",
+  "block_modal.you_wont_see_mentions": "You won't see posts that mention them.",
   "boost_modal.combo": "You can press {combo} to skip this next time",
   "bundle_column_error.copy_stacktrace": "Copy error report",
   "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.",
@@ -169,6 +177,7 @@
   "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
   "confirmations.discard_edit_media.confirm": "Discard",
   "confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
+  "confirmations.domain_block.confirm": "Block server",
   "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
   "confirmations.edit.confirm": "Edit",
   "confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?",
@@ -431,6 +440,7 @@
   "notifications.column_settings.admin.sign_up": "New sign-ups:",
   "notifications.column_settings.alert": "Desktop notifications",
   "notifications.column_settings.favourite": "Favourites:",
+  "notifications.column_settings.filter_bar.category": "Quick filter bar",
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.follow_request": "New follow requests:",
   "notifications.column_settings.mention": "Mentions:",
@@ -456,6 +466,15 @@
   "notifications.permission_denied": "Desktop notifications are unavailable due to previously denied browser permissions request",
   "notifications.permission_denied_alert": "Desktop notifications can't be enabled, as browser permission has been denied before",
   "notifications.permission_required": "Desktop notifications are unavailable because the required permission has not been granted.",
+  "notifications.policy.filter_new_accounts.hint": "Created within the past {days, plural, one {one day} other {# days}}",
+  "notifications.policy.filter_new_accounts_title": "New accounts",
+  "notifications.policy.filter_not_followers_hint": "Including people who have been following you fewer than {days, plural, one {one day} other {# days}}",
+  "notifications.policy.filter_not_followers_title": "People not following you",
+  "notifications.policy.filter_not_following_hint": "Until you manually approve them",
+  "notifications.policy.filter_not_following_title": "People you don't follow",
+  "notifications.policy.filter_private_mentions_hint": "Filtered unless it's in reply to your own mention or if you follow the sender",
+  "notifications.policy.filter_private_mentions_title": "Unsolicited private mentions",
+  "notifications.policy.title": "Filter out notifications from…",
   "notifications_permission_banner.enable": "Enable desktop notifications",
   "notifications_permission_banner.how_to_control": "To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled.",
   "notifications_permission_banner.title": "Never miss a thing",
@@ -632,9 +651,11 @@
   "status.direct": "Privately mention @{name}",
   "status.direct_indicator": "Private mention",
   "status.edit": "Edit",
+  "status.edited": "Last edited {date}",
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.favourites": "{count, plural, one {favorite} other {favorites}}",
   "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide post",
@@ -655,6 +676,7 @@
   "status.reblog": "Boost",
   "status.reblog_private": "Boost with original visibility",
   "status.reblogged_by": "{name} boosted",
+  "status.reblogs": "{count, plural, one {boost} other {boosts}}",
   "status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.",
   "status.redraft": "Delete & re-draft",
   "status.remove_bookmark": "Remove bookmark",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 40fec4f49..bc57c4cee 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -148,7 +148,7 @@
   "compose.published.open": "Ireki",
   "compose.saved.body": "Argitalpena gorde da.",
   "compose_form.direct_message_warning_learn_more": "Ikasi gehiago",
-  "compose_form.encryption_warning": "Mastodoneko bidalketak ez daude muturretik muturrera enkriptatuta. Ez partekatu informazio sentikorrik Mastodonen.",
+  "compose_form.encryption_warning": "Mastodon-go bidalketak ez daude muturretik muturrera enkriptatuta. Ez partekatu informazio sentikorrik Mastodonen.",
   "compose_form.hashtag_warning": "Tut hau ez da inolako traolatan zerrendatuko, ez baita publikoa. Tut publikoak soilik traolen bitartez bila daitezke.",
   "compose_form.lock_disclaimer": "Zure kontua ez dago {locked}. Edonork jarraitu zaitzake zure jarraitzaileentzako soilik diren bidalketak ikusteko.",
   "compose_form.lock_disclaimer.lock": "giltzapetuta",
@@ -345,7 +345,7 @@
   "home.column_settings.show_reblogs": "Erakutsi bultzadak",
   "home.column_settings.show_replies": "Erakutsi erantzunak",
   "home.hide_announcements": "Ezkutatu iragarpenak",
-  "home.pending_critical_update.body": "Eguneratu zure Mastodoneko zerbitzaria leheinbailehen!",
+  "home.pending_critical_update.body": "Eguneratu zure Mastodon-go zerbitzaria leheinbailehen!",
   "home.pending_critical_update.link": "Ikusi eguneraketak",
   "home.pending_critical_update.title": "Segurtasun eguneraketa kritikoa eskuragarri!",
   "home.show_announcements": "Erakutsi iragarpenak",
@@ -548,7 +548,7 @@
   "onboarding.share.message": "{username} naiz #Mastodon-en! Jarrai nazazu hemen: {url}",
   "onboarding.share.next_steps": "Hurrengo urrats posibleak:",
   "onboarding.share.title": "Partekatu zure profila",
-  "onboarding.start.lead": "Mastodonen parte zara orain, bakarra eta deszentralizatua den sare-sozialaren plataforma, non zuk, eta ez algoritmo batek, zeure esperientzia pertsonaliza dezakezun. Igaro ezazu muga soziala:",
+  "onboarding.start.lead": "Mastodon-en parte zara orain, bakarra eta deszentralizatua den sare sozialaren plataforma, non zuk, eta ez algoritmo batek, zeure esperientzia pertsonaliza dezakezun. Igaro ezazu muga soziala:",
   "onboarding.start.skip": "Urrats guztiak saltatu nahi dituzu?",
   "onboarding.start.title": "Lortu duzu!",
   "onboarding.steps.follow_people.body": "Zure jarioa zuk pertsonalizatzen duzu. Bete dezagun jende interesgarriaz.",
@@ -562,7 +562,7 @@
   "onboarding.tips.2fa": "<strong>Bazenekien?</strong> Zure kontua babes dezakezu, bi faktoreko autentifikazioa zure kontuko ezarpenetan ezarriaz. Edozein TOTP aplikaziorekin dabil, ez da telefono-zenbakirik behar!",
   "onboarding.tips.accounts_from_other_servers": "<strong>Badakizu?</strong> Mastodon deszentralizatua denez, beste zerbitzarietako profilak topatuko dituzu. Eta, hala ere, arazorik gabe jardun dezakezu haiekin! Haien zerbitzaria erabiltzaile-izenaren bigarren erdian dago!",
   "onboarding.tips.migration": "<strong>Bazenekien?</strong> Uste baduzu {domain} ez dela aukera on bat zuretzako etorkizunari begira, beste Mastodon zerbitzari batera alda zaitezke, zure jarraitzaileak galdu gabe. Zure zerbitzaria propioa ere ostata dezakezu!",
-  "onboarding.tips.verification": "<strong>Bazenekien?</strong> Zure kontua egiazta dezakezu zure webgunean zure Mastodoneko profilaren esteka jarriz, eta profilean webgunea gehituz. Ordainketa edo dokumenturik gabe!",
+  "onboarding.tips.verification": "<strong>Bazenekien?</strong> Zure kontua egiazta dezakezu zure webgunean zure Mastodon-go profilaren esteka jarriz, eta profilean webgunea gehituz. Ordainketa edo dokumenturik gabe!",
   "password_confirmation.exceeds_maxlength": "Pasahitzaren berrespenak pasahitzaren gehienezko luzera gainditzen du",
   "password_confirmation.mismatching": "Pasahitzaren berrespena ez dator bat",
   "picture_in_picture.restore": "Leheneratu",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 249ba6632..f1e1074ff 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -701,7 +701,7 @@
   "status.direct": "@{name} 님에게 개인적으로 멘션",
   "status.direct_indicator": "개인적인 멘션",
   "status.edit": "수정",
-  "status.edited": "%{date}에 마지막으로 편집됨",
+  "status.edited": "{date}에 마지막으로 편집됨",
   "status.edited_x_times": "{count}번 수정됨",
   "status.embed": "임베드",
   "status.favourite": "좋아요",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 952ed5adf..4a7c22439 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -16,12 +16,12 @@
   "account.badges.bot": "อัตโนมัติ",
   "account.badges.group": "กลุ่ม",
   "account.block": "ปิดกั้น @{name}",
-  "account.block_domain": "ปิดกั้นโดเมน {domain}",
+  "account.block_domain": "เลิกปิดกั้นโดเมน {domain} แล้ว",
   "account.block_short": "ปิดกั้น",
   "account.blocked": "ปิดกั้นอยู่",
   "account.browse_more_on_origin_server": "เรียกดูเพิ่มเติมในโปรไฟล์ดั้งเดิม",
   "account.cancel_follow_request": "ยกเลิกการติดตาม",
-  "account.copy": "คัดลอกลิงก์ไปยังโปรไฟล์",
+  "account.copy": "Copy link to profile",
   "account.direct": "กล่าวถึง @{name} แบบส่วนตัว",
   "account.disable_notifications": "หยุดแจ้งเตือนฉันเมื่อ @{name} โพสต์",
   "account.domain_blocked": "ปิดกั้นโดเมนอยู่",
diff --git a/config/locales/devise.en-GB.yml b/config/locales/devise.en-GB.yml
index 823be9aa6..3e8a534e1 100644
--- a/config/locales/devise.en-GB.yml
+++ b/config/locales/devise.en-GB.yml
@@ -12,6 +12,7 @@ en-GB:
       last_attempt: You have one more attempt before your account is locked.
       locked: Your account is locked.
       not_found_in_database: Invalid %{authentication_keys} or password.
+      omniauth_user_creation_failure: Error creating an account for this identity.
       pending: Your account is still under review.
       timeout: Your session expired. Please log in again to continue.
       unauthenticated: You need to log in or sign up before continuing.
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index a2f84b093..df956902a 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -597,6 +597,9 @@ en-GB:
       actions_description_html: Decide which action to take to resolve this report. If you take a punitive action against the reported account, an e-mail notification will be sent to them, except when the <strong>Spam</strong> category is selected.
       actions_description_remote_html: Decide which action to take to resolve this report. This will only affect how <strong>your</strong> server communicates with this remote account and handle its content.
       add_to_report: Add more to report
+      already_suspended_badges:
+        local: Already suspended on this server
+        remote: Already suspended on their server
       are_you_sure: Are you sure?
       assign_to_self: Assign to me
       assigned: Assigned moderator
@@ -767,6 +770,7 @@ en-GB:
         disabled: To no one
         users: To logged-in local users
       registrations:
+        moderation_recommandation: Please make sure you have an adequate and reactive moderation team before you open registrations to everyone!
         preamble: Control who can create an account on your server.
         title: Registrations
       registrations_mode:
@@ -774,6 +778,7 @@ en-GB:
           approved: Approval required for sign up
           none: Nobody can sign up
           open: Anyone can sign up
+        warning_hint: We recommend using “Approval required for sign up” unless you are confident your moderation team can handle spam and malicious registrations in a timely fashion.
       security:
         authorized_fetch: Require authentication from federated servers
         authorized_fetch_hint: Requiring authentication from federated servers enables stricter enforcement of both user-level and server-level blocks. However, this comes at the cost of a performance penalty, reduces the reach of your replies, and may introduce compatibility issues with some federated services. In addition, this will not prevent dedicated actors from fetching your public posts and accounts.
@@ -966,6 +971,9 @@ en-GB:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Due to a lack of recent moderator activity, registrations on %{instance} have been automatically switched to requiring manual review, to prevent %{instance} from being used as a platform for potential bad actors. You can switch it back to open registrations at any time.
+      subject: Registrations for %{instance} have been automatically switched to requiring approval
     new_appeal:
       actions:
         delete_statuses: to delete their posts
@@ -1647,13 +1655,26 @@ en-GB:
     import: Import
     import_and_export: Import and export
     migrate: Account migration
+    notifications: E-mail notifications
     preferences: Preferences
     profile: Profile
     relationships: Follows and followers
+    severed_relationships: Severed relationships
     statuses_cleanup: Automated post deletion
     strikes: Moderation strikes
     two_factor_authentication: Two-factor Auth
     webauthn_authentication: Security keys
+  severed_relationships:
+    download: Download (%{count})
+    event_type:
+      account_suspension: Account suspension (%{target_name})
+      domain_block: Server suspension (%{target_name})
+      user_domain_block: You blocked %{target_name}
+    lost_followers: Lost followers
+    lost_follows: Lost follows
+    preamble: You may lose follows and followers when you block a domain or when your moderators decide to suspend a remote server. When that happens, you will be able to download lists of severed relationships, to be inspected and possibly imported on another server.
+    purged: Information about this server has been purged by your server's administrators.
+    type: Event
   statuses:
     attached:
       audio:
@@ -1747,6 +1768,7 @@ en-GB:
     contrast: Mastodon (High contrast)
     default: Mastodon (Dark)
     mastodon-light: Mastodon (Light)
+    system: Automatic (use system theme)
   time:
     formats:
       default: "%b %d, %Y, %H:%M"
@@ -1834,7 +1856,44 @@ en-GB:
         silence: Account limited
         suspend: Account suspended
     welcome:
+      apps_android_action: Get it on Google Play
+      apps_ios_action: Download on the App Store
+      apps_step: Download our official apps.
+      apps_title: Mastodon apps
+      checklist_subtitle: 'Let''s get you started on this new social frontier:'
+      checklist_title: Welcome Checklist
+      edit_profile_action: Personalise
+      edit_profile_step: Boost your interactions by having a comprehensive profile.
+      edit_profile_title: Personalise your profile
       explanation: Here are some tips to get you started
+      feature_action: Learn more
+      feature_audience: Mastodon provides you with a unique possibility of managing your audience without middlemen. Mastodon deployed on your own infrastructure allows you to follow and be followed from any other Mastodon server online and is under no one's control but yours.
+      feature_audience_title: Build your audience in confidence
+      feature_control: You know best what you want to see on your home feed. No algorithms or ads to waste your time. Follow anyone across any Mastodon server from a single account and receive their posts in chronological order, and make your corner of the Internet a little more like you.
+      feature_control_title: Stay in control of your own timeline
+      feature_creativity: Mastodon supports audio, video and picture posts, accessibility descriptions, polls, content warnings, animated avatars, custom emojis, thumbnail crop control, and more, to help you express yourself online. Whether you're publishing your art, your music, or your podcast, Mastodon is there for you.
+      feature_creativity_title: Unparalleled creativity
+      feature_moderation: Mastodon puts decision making back in your hands. Each server creates their own rules and regulations, which are enforced locally and not top-down like corporate social media, making it the most flexible in responding to the needs of different groups of people. Join a server with the rules you agree with, or host your own.
+      feature_moderation_title: Moderating the way it should be
+      follow_action: Follow
+      follow_step: Following interesting people is what Mastodon is all about.
+      follow_title: Personalise your home feed
+      follows_subtitle: Follow well-known accounts
+      follows_title: Who to follow
+      follows_view_more: View more people to follow
+      hashtags_recent_count:
+        one: "%{people} person in the past 2 days"
+        other: "%{people} people in the past 2 days"
+      hashtags_subtitle: Explore what’s trending since past 2 days
+      hashtags_title: Trending hashtags
+      hashtags_view_more: View more trending hashtags
+      post_action: Compose
+      post_step: Say hello to the world with text, photos, videos, or polls.
+      post_title: Make your first post
+      share_action: Share
+      share_step: Let your friends know how to find you on Mastodon.
+      share_title: Share your Mastodon profile
+      sign_in_action: Sign in
       subject: Welcome to Mastodon
       title: Welcome aboard, %{name}!
   users:
diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml
index 2ac4508b0..e5c9b1b2b 100644
--- a/config/locales/simple_form.en-GB.yml
+++ b/config/locales/simple_form.en-GB.yml
@@ -39,12 +39,14 @@ en-GB:
         text: You can only appeal a strike once
       defaults:
         autofollow: People who sign up through the invite will automatically follow you
+        avatar: WEBP, PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
         bot: Signal to others that the account mainly performs automated actions and might not be monitored
         context: One or multiple contexts where the filter should apply
         current_password: For security purposes please enter the password of the current account
         current_username: To confirm, please enter the username of the current account
         digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence
         email: You will be sent a confirmation e-mail
+        header: WEBP, PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
         inbox_url: Copy the URL from the frontpage of the relay you want to use
         irreversible: Filtered posts will disappear irreversibly, even if filter is later removed
         locale: The language of the user interface, e-mails and push notifications
@@ -114,6 +116,7 @@ en-GB:
           sign_up_requires_approval: New sign-ups will require your approval
         severity: Choose what will happen with requests from this IP
       rule:
+        hint: Optional. Provide more details about the rule
         text: Describe a rule or requirement for users on this server. Try to keep it short and simple
       sessions:
         otp: 'Enter the two-factor code generated by your phone app or use one of your recovery codes:'
@@ -297,6 +300,7 @@ en-GB:
           patch: Notify on bugfix updates
         trending_tag: New trend requires review
       rule:
+        hint: Additional information
         text: Rule
       settings:
         indexable: Include profile page in search engines
diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml
index 03ba1aea6..5ed3b9efa 100644
--- a/config/locales/simple_form.eu.yml
+++ b/config/locales/simple_form.eu.yml
@@ -3,7 +3,7 @@ eu:
   simple_form:
     hints:
       account:
-        discoverable: Zure bidalketa publikoak eta profila nabarmendu edo gomendatu egin daitezke Mastodoneko hainbat eremutan eta zure profila beste erabiltzaile batzuei iradoki dakieke.
+        discoverable: Zure bidalketa publikoak eta profila nabarmendu edo gomendatu egin daitezke Mastodon-go hainbat eremutan eta zure profila beste erabiltzaile batzuei iradoki dakieke.
         display_name: Zure izena edo ezizena.
         fields: Zure webgunea, izenordainak, adina, nahi duzun guztia.
         indexable: Zure argitalpen publikoak bilaketa-emaitzetan ager daitezke Mastodonen. Zure argitalpenekin elkarregin duten jendeak ikusi ahal izango dituzte, hala ere.
diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml
index 16c23caeb..758d1dc4d 100644
--- a/config/locales/simple_form.tr.yml
+++ b/config/locales/simple_form.tr.yml
@@ -228,7 +228,7 @@ tr:
         title: Başlık
         type: İçeri aktarma türü
         username: Kullanıcı adı
-        username_or_email: Kullanıcı adı ya da e-posta
+        username_or_email: Kullanıcı adı veya e-posta
         whole_word: Tam sözcük
       email_domain_block:
         with_dns_records: Alan adının MX kayıtlarını ve IP'lerini ekleyin
@@ -269,7 +269,7 @@ tr:
       interactions:
         must_be_follower: Takipçim olmayan kişilerden gelen bildirimleri engelle
         must_be_following: Takip etmediğim kişilerden gelen bildirimleri engelle
-        must_be_following_dm: Takip etmediğiniz kişilerden gelen direkt mesajları engelle
+        must_be_following_dm: Takip etmediğiniz kişilerden gelen doğrudan iletileri engelle
       invite:
         comment: Yorum
       invite_request:
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 2a05c892e..17ff6a5cc 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -1835,6 +1835,7 @@ th:
       edit_profile_title: ปรับแต่งโปรไฟล์ของคุณ
       explanation: นี่คือเคล็ดลับบางส่วนที่จะช่วยให้คุณเริ่มต้นใช้งาน
       feature_action: เรียนรู้เพิ่มเติม
+      feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ
       follow_action: ติดตาม
       follow_step: การติดตามผู้คนที่น่าสนใจคือสิ่งที่ Mastodon ให้ความสำคัญ
       follow_title: ปรับแต่งฟีดหน้าแรกของคุณ

From 13bbde22469c6217878e64e458f1ce6f8f18a93f Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 12 Apr 2024 05:04:23 -0400
Subject: [PATCH 129/173] Use existing `DEFAULT_FIELDS_SIZE` constant to limit
 `Account#fields` (#29911)

---
 app/models/account.rb | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/app/models/account.rb b/app/models/account.rb
index 3739709a1..2bf00b2be 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -64,6 +64,7 @@ class Account < ApplicationRecord
   )
 
   BACKGROUND_REFRESH_INTERVAL = 1.week.freeze
+  DEFAULT_FIELDS_SIZE = 4
   INSTANCE_ACTOR_ID = -99
 
   USERNAME_RE   = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i
@@ -103,7 +104,7 @@ class Account < ApplicationRecord
   validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
   validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
   validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
-  validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
+  validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? }
   validates :uri, absence: true, if: :local?, on: :create
   validates :inbox_url, absence: true, if: :local?, on: :create
   validates :shared_inbox_url, absence: true, if: :local?, on: :create
@@ -353,8 +354,6 @@ class Account < ApplicationRecord
     self[:fields] = fields
   end
 
-  DEFAULT_FIELDS_SIZE = 4
-
   def build_fields
     return if fields.size >= DEFAULT_FIELDS_SIZE
 

From ec5a0e0f5e14a512f8e247a22742ec0f85e14f5c Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 12 Apr 2024 05:18:35 -0400
Subject: [PATCH 130/173] Expand coverage for admin/metrics/dimension/* classes
 (#29913)

---
 .../instance_accounts_dimension_spec.rb       | 24 ++++++++++++---
 .../instance_languages_dimension_spec.rb      | 22 +++++++++++---
 .../dimension/servers_dimension_spec.rb       | 22 ++++++++++++--
 .../software_versions_dimension_spec.rb       | 10 +++++--
 .../dimension/sources_dimension_spec.rb       | 19 ++++++++++--
 .../dimension/space_usage_dimension_spec.rb   | 11 +++++--
 .../dimension/tag_languages_dimension_spec.rb | 28 +++++++++++++++---
 .../dimension/tag_servers_dimension_spec.rb   | 29 ++++++++++++++++---
 8 files changed, 137 insertions(+), 28 deletions(-)

diff --git a/spec/lib/admin/metrics/dimension/instance_accounts_dimension_spec.rb b/spec/lib/admin/metrics/dimension/instance_accounts_dimension_spec.rb
index 106717f97..2b14e6956 100644
--- a/spec/lib/admin/metrics/dimension/instance_accounts_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/instance_accounts_dimension_spec.rb
@@ -3,16 +3,32 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::InstanceAccountsDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
   let(:limit) { 10 }
-  let(:params) { ActionController::Parameters.new }
+  let(:params) { ActionController::Parameters.new(domain: domain) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:domain) { 'host.example' }
+    let(:alice) { Fabricate(:account, domain: domain) }
+    let(:bob) { Fabricate(:account) }
+
+    before do
+      Fabricate :follow, target_account: alice
+      Fabricate :follow, target_account: bob
+      Fabricate :status, account: alice
+      Fabricate :status, account: bob
+    end
+
+    it 'returns instances with follow counts' do
+      expect(subject.data.size)
+        .to eq(1)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: alice.username, value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/instance_languages_dimension_spec.rb b/spec/lib/admin/metrics/dimension/instance_languages_dimension_spec.rb
index f9f6430ca..e4e9fbe2b 100644
--- a/spec/lib/admin/metrics/dimension/instance_languages_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/instance_languages_dimension_spec.rb
@@ -3,16 +3,30 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::InstanceLanguagesDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
   let(:limit) { 10 }
-  let(:params) { ActionController::Parameters.new }
+  let(:params) { ActionController::Parameters.new(domain: domain) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:domain) { 'host.example' }
+    let(:alice) { Fabricate(:account, domain: domain) }
+    let(:bob) { Fabricate(:account) }
+
+    before do
+      Fabricate :status, account: alice, language: 'en'
+      Fabricate :status, account: bob, language: 'es'
+    end
+
+    it 'returns locales with status counts' do
+      expect(subject.data.size)
+        .to eq(1)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: 'en', value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/servers_dimension_spec.rb b/spec/lib/admin/metrics/dimension/servers_dimension_spec.rb
index 7e2bb9ac0..5661441d5 100644
--- a/spec/lib/admin/metrics/dimension/servers_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/servers_dimension_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::ServersDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
@@ -11,8 +11,24 @@ describe Admin::Metrics::Dimension::ServersDimension do
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:domain) { 'host.example' }
+    let(:alice) { Fabricate(:account, domain: domain) }
+    let(:bob) { Fabricate(:account) }
+
+    before do
+      Fabricate :status, account: alice, created_at: 1.day.ago
+      Fabricate :status, account: alice, created_at: 30.days.ago
+      Fabricate :status, account: bob, created_at: 1.day.ago
+    end
+
+    it 'returns domains with status counts' do
+      expect(subject.data.size)
+        .to eq(2)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: domain, value: '1'),
+          include(key: Rails.configuration.x.local_domain, value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/software_versions_dimension_spec.rb b/spec/lib/admin/metrics/dimension/software_versions_dimension_spec.rb
index ee1491733..5d31121ab 100644
--- a/spec/lib/admin/metrics/dimension/software_versions_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/software_versions_dimension_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::SoftwareVersionsDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
@@ -11,8 +11,12 @@ describe Admin::Metrics::Dimension::SoftwareVersionsDimension do
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    it 'reports on the running software' do
+      expect(subject.data.map(&:symbolize_keys))
+        .to include(
+          include(key: 'mastodon', value: Mastodon::Version.to_s),
+          include(key: 'ruby', value: include(RUBY_VERSION))
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/sources_dimension_spec.rb b/spec/lib/admin/metrics/dimension/sources_dimension_spec.rb
index d6b581a9b..5fa5aa8af 100644
--- a/spec/lib/admin/metrics/dimension/sources_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/sources_dimension_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::SourcesDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
@@ -11,8 +11,21 @@ describe Admin::Metrics::Dimension::SourcesDimension do
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:app) { Fabricate(:application) }
+    let(:alice) { Fabricate(:user) }
+    let(:bob) { Fabricate(:user) }
+
+    before do
+      alice.update(created_by_application: app)
+    end
+
+    it 'returns OAuth applications with user counts' do
+      expect(subject.data.size)
+        .to eq(1)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: app.name, value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/space_usage_dimension_spec.rb b/spec/lib/admin/metrics/dimension/space_usage_dimension_spec.rb
index 65d04cfed..96ff9c66d 100644
--- a/spec/lib/admin/metrics/dimension/space_usage_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/space_usage_dimension_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::SpaceUsageDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
@@ -11,8 +11,13 @@ describe Admin::Metrics::Dimension::SpaceUsageDimension do
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    it 'reports on used storage space' do
+      expect(subject.data.map(&:symbolize_keys))
+        .to include(
+          include(key: 'media', value: /\d/),
+          include(key: 'postgresql', value: /\d/),
+          include(key: 'redis', value: /\d/)
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/tag_languages_dimension_spec.rb b/spec/lib/admin/metrics/dimension/tag_languages_dimension_spec.rb
index 721d24fa1..c1dfd0eaf 100644
--- a/spec/lib/admin/metrics/dimension/tag_languages_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/tag_languages_dimension_spec.rb
@@ -3,16 +3,36 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::TagLanguagesDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
   let(:limit) { 10 }
-  let(:params) { ActionController::Parameters.new }
+  let(:params) { ActionController::Parameters.new(id: tag.id) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:alice) { Fabricate(:account) }
+    let(:bob) { Fabricate(:account) }
+    let(:tag) { Fabricate(:tag) }
+
+    before do
+      alice_status_recent = Fabricate :status, account: alice, created_at: 1.day.ago, language: 'en'
+      alice_status_older = Fabricate :status, account: alice, created_at: 30.days.ago, language: 'en'
+      bob_status_recent = Fabricate :status, account: bob, created_at: 1.day.ago, language: 'es'
+
+      alice_status_older.tags << tag
+      alice_status_recent.tags << tag
+      bob_status_recent.tags << tag
+    end
+
+    it 'returns languages with tag usage counts' do
+      expect(subject.data.size)
+        .to eq(2)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: 'en', value: '1'),
+          include(key: 'es', value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/dimension/tag_servers_dimension_spec.rb b/spec/lib/admin/metrics/dimension/tag_servers_dimension_spec.rb
index 305471681..025cf1b7e 100644
--- a/spec/lib/admin/metrics/dimension/tag_servers_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/tag_servers_dimension_spec.rb
@@ -3,16 +3,37 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Dimension::TagServersDimension do
-  subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+  subject { described_class.new(start_at, end_at, limit, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at) { Time.now.utc }
   let(:limit) { 10 }
-  let(:params) { ActionController::Parameters.new }
+  let(:params) { ActionController::Parameters.new(id: tag.id) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { dimension.data }.to_not raise_error
+    let(:alice) { Fabricate(:account, domain: domain) }
+    let(:bob) { Fabricate(:account) }
+    let(:domain) { 'host.example' }
+    let(:tag) { Fabricate(:tag) }
+
+    before do
+      alice_status_recent = Fabricate :status, account: alice, created_at: 1.day.ago
+      alice_status_older = Fabricate :status, account: alice, created_at: 30.days.ago
+      bob_status_recent = Fabricate :status, account: bob, created_at: 1.day.ago
+
+      alice_status_older.tags << tag
+      alice_status_recent.tags << tag
+      bob_status_recent.tags << tag
+    end
+
+    it 'returns servers with tag usage counts' do
+      expect(subject.data.size)
+        .to eq(2)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(key: domain, value: '1'),
+          include(key: Rails.configuration.x.local_domain, value: '1')
+        )
     end
   end
 end

From da6b9238f53c6660e6cd9feedaa96a1b7ce01f92 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 12 Apr 2024 05:38:24 -0400
Subject: [PATCH 131/173] Expand coverage for admin/metrics/measure/* classes
 (#29914)

---
 .../measure/active_users_measure_spec.rb      | 29 +++++++++++++--
 .../measure/instance_accounts_measure_spec.rb | 20 +++++++---
 .../instance_followers_measure_spec.rb        | 21 ++++++++---
 .../measure/instance_follows_measure_spec.rb  | 19 +++++++---
 ...instance_media_attachments_measure_spec.rb | 23 +++++++++---
 .../measure/instance_reports_measure_spec.rb  | 19 +++++++---
 .../measure/instance_statuses_measure_spec.rb | 19 +++++++---
 .../measure/interactions_measure_spec.rb      | 29 +++++++++++++--
 .../metrics/measure/new_users_measure_spec.rb | 21 +++++++++--
 .../measure/opened_reports_measure_spec.rb    | 21 +++++++++--
 .../measure/resolved_reports_measure_spec.rb  | 21 +++++++++--
 .../measure/tag_accounts_measure_spec.rb      | 37 +++++++++++++++++--
 .../measure/tag_servers_measure_spec.rb       | 36 ++++++++++++++++--
 .../metrics/measure/tag_uses_measure_spec.rb  | 37 +++++++++++++++++--
 14 files changed, 292 insertions(+), 60 deletions(-)

diff --git a/spec/lib/admin/metrics/measure/active_users_measure_spec.rb b/spec/lib/admin/metrics/measure/active_users_measure_spec.rb
index 55164ed88..38ee14075 100644
--- a/spec/lib/admin/metrics/measure/active_users_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/active_users_measure_spec.rb
@@ -3,15 +3,38 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::ActiveUsersMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at)   { Time.now.utc }
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with activity tracking records' do
+      before do
+        3.times do
+          travel_to(2.days.ago) { record_login_activity }
+        end
+        2.times do
+          travel_to(1.day.ago) { record_login_activity }
+        end
+        travel_to(0.days.ago) { record_login_activity }
+      end
+
+      it 'returns correct activity tracker counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
+
+      def record_login_activity
+        ActivityTracker.record('activity:logins', Fabricate(:user).id)
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_accounts_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_accounts_measure_spec.rb
index 8e414963f..0d2ad31c3 100644
--- a/spec/lib/admin/metrics/measure/instance_accounts_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_accounts_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceAccountsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -20,12 +20,13 @@ describe Admin::Metrics::Measure::InstanceAccountsMeasure do
     Fabricate(:account, domain: "foo.#{domain}", created_at: 1.year.ago)
     Fabricate(:account, domain: "foo.#{domain}")
     Fabricate(:account, domain: "bar.#{domain}")
+    Fabricate(:account, domain: 'other-host.example')
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 3
+        expect(subject.total).to eq 3
       end
     end
 
@@ -33,14 +34,21 @@ describe Admin::Metrics::Measure::InstanceAccountsMeasure do
       let(:params) { ActionController::Parameters.new(domain: domain, include_subdomains: 'true') }
 
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 6
+        expect(subject.total).to eq 6
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct instance_accounts counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: '1')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_followers_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_followers_measure_spec.rb
index c627e6ced..27bf30d17 100644
--- a/spec/lib/admin/metrics/measure/instance_followers_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_followers_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceFollowersMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -22,12 +22,14 @@ describe Admin::Metrics::Measure::InstanceFollowersMeasure do
     Fabricate(:account, domain: "foo.#{domain}").follow!(local_account)
     Fabricate(:account, domain: "foo.#{domain}").follow!(local_account)
     Fabricate(:account, domain: "bar.#{domain}")
+
+    Fabricate(:account, domain: 'other.example').follow!(local_account)
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 2
+        expect(subject.total).to eq 2
       end
     end
 
@@ -35,14 +37,21 @@ describe Admin::Metrics::Measure::InstanceFollowersMeasure do
       let(:params) { ActionController::Parameters.new(domain: domain, include_subdomains: 'true') }
 
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 4
+        expect(subject.total).to eq 4
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct instance_followers counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: '2')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_follows_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_follows_measure_spec.rb
index 42f33dfc3..9961ea56c 100644
--- a/spec/lib/admin/metrics/measure/instance_follows_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_follows_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceFollowsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -24,10 +24,10 @@ describe Admin::Metrics::Measure::InstanceFollowsMeasure do
     Fabricate(:account, domain: "bar.#{domain}")
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 2
+        expect(subject.total).to eq 2
       end
     end
 
@@ -35,14 +35,21 @@ describe Admin::Metrics::Measure::InstanceFollowsMeasure do
       let(:params) { ActionController::Parameters.new(domain: domain, include_subdomains: 'true') }
 
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 4
+        expect(subject.total).to eq 4
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct instance_followers counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: '2')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_media_attachments_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_media_attachments_measure_spec.rb
index c103307f9..363445093 100644
--- a/spec/lib/admin/metrics/measure/instance_media_attachments_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_media_attachments_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -20,11 +20,11 @@ describe Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure do
     remote_account_on_subdomain.media_attachments.create!(file: attachment_fixture('attachment.jpg'))
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
         expected_total = remote_account.media_attachments.sum(:file_file_size) + remote_account.media_attachments.sum(:thumbnail_file_size)
-        expect(measure.total).to eq expected_total
+        expect(subject.total).to eq expected_total
       end
     end
 
@@ -36,14 +36,25 @@ describe Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure do
           account.media_attachments.sum(:file_file_size) + account.media_attachments.sum(:thumbnail_file_size)
         end
 
-        expect(measure.total).to eq expected_total
+        expect(subject.total).to eq expected_total
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct media_attachments counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: expected_domain_only_total.to_s)
+        )
+    end
+
+    def expected_domain_only_total
+      remote_account.media_attachments.sum(:file_file_size) + remote_account.media_attachments.sum(:thumbnail_file_size)
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_reports_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_reports_measure_spec.rb
index 62fcf84ac..ca64049d9 100644
--- a/spec/lib/admin/metrics/measure/instance_reports_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_reports_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceReportsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -21,10 +21,10 @@ describe Admin::Metrics::Measure::InstanceReportsMeasure do
     Fabricate(:report, target_account: Fabricate(:account, domain: "bar.#{domain}"))
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 2
+        expect(subject.total).to eq 2
       end
     end
 
@@ -32,14 +32,21 @@ describe Admin::Metrics::Measure::InstanceReportsMeasure do
       let(:params) { ActionController::Parameters.new(domain: domain, include_subdomains: 'true') }
 
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 5
+        expect(subject.total).to eq 5
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct instance_reports counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: '2')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/instance_statuses_measure_spec.rb b/spec/lib/admin/metrics/measure/instance_statuses_measure_spec.rb
index df4cfe207..ac28658ea 100644
--- a/spec/lib/admin/metrics/measure/instance_statuses_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/instance_statuses_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InstanceStatusesMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:domain) { 'example.com' }
 
@@ -21,10 +21,10 @@ describe Admin::Metrics::Measure::InstanceStatusesMeasure do
     Fabricate(:status, account: Fabricate(:account, domain: "bar.#{domain}"))
   end
 
-  describe 'total' do
+  describe '#total' do
     context 'without include_subdomains' do
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 2
+        expect(subject.total).to eq 2
       end
     end
 
@@ -32,14 +32,21 @@ describe Admin::Metrics::Measure::InstanceStatusesMeasure do
       let(:params) { ActionController::Parameters.new(domain: domain, include_subdomains: 'true') }
 
       it 'returns the expected number of accounts' do
-        expect(measure.total).to eq 5
+        expect(subject.total).to eq 5
       end
     end
   end
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    it 'returns correct instance_statuses counts' do
+      expect(subject.data.size)
+        .to eq(3)
+      expect(subject.data.map(&:symbolize_keys))
+        .to contain_exactly(
+          include(date: 2.days.ago.midnight.to_time, value: '0'),
+          include(date: 1.day.ago.midnight.to_time, value: '0'),
+          include(date: 0.days.ago.midnight.to_time, value: '2')
+        )
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/interactions_measure_spec.rb b/spec/lib/admin/metrics/measure/interactions_measure_spec.rb
index e98c83059..ed333380c 100644
--- a/spec/lib/admin/metrics/measure/interactions_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/interactions_measure_spec.rb
@@ -3,15 +3,38 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::InteractionsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at)   { Time.now.utc }
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with activity tracking records' do
+      before do
+        3.times do
+          travel_to(2.days.ago) { record_interaction_activity }
+        end
+        2.times do
+          travel_to(1.day.ago) { record_interaction_activity }
+        end
+        travel_to(0.days.ago) { record_interaction_activity }
+      end
+
+      it 'returns correct activity tracker counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
+
+      def record_interaction_activity
+        ActivityTracker.increment('activity:interactions')
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/new_users_measure_spec.rb b/spec/lib/admin/metrics/measure/new_users_measure_spec.rb
index fe82f8219..085acbced 100644
--- a/spec/lib/admin/metrics/measure/new_users_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/new_users_measure_spec.rb
@@ -3,15 +3,30 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::NewUsersMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at)   { Time.now.utc }
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with user records' do
+      before do
+        3.times { Fabricate :user, created_at: 2.days.ago }
+        2.times { Fabricate :user, created_at: 1.day.ago }
+        Fabricate :user, created_at: 0.days.ago
+      end
+
+      it 'returns correct user counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/opened_reports_measure_spec.rb b/spec/lib/admin/metrics/measure/opened_reports_measure_spec.rb
index deed64ae8..d5ba78527 100644
--- a/spec/lib/admin/metrics/measure/opened_reports_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/opened_reports_measure_spec.rb
@@ -3,15 +3,30 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::OpenedReportsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at)   { Time.now.utc }
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with report records' do
+      before do
+        3.times { Fabricate :report, created_at: 2.days.ago }
+        2.times { Fabricate :report, created_at: 1.day.ago }
+        Fabricate :report, created_at: 0.days.ago
+      end
+
+      it 'returns correct report counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/resolved_reports_measure_spec.rb b/spec/lib/admin/metrics/measure/resolved_reports_measure_spec.rb
index cb98df2dc..f7b497590 100644
--- a/spec/lib/admin/metrics/measure/resolved_reports_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/resolved_reports_measure_spec.rb
@@ -3,15 +3,30 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::ResolvedReportsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let(:start_at) { 2.days.ago }
   let(:end_at)   { Time.now.utc }
   let(:params) { ActionController::Parameters.new }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with report records' do
+      before do
+        3.times { Fabricate :report, action_taken_at: 2.days.ago }
+        2.times { Fabricate :report, action_taken_at: 1.day.ago }
+        Fabricate :report, action_taken_at: 0.days.ago
+      end
+
+      it 'returns correct report counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/tag_accounts_measure_spec.rb b/spec/lib/admin/metrics/measure/tag_accounts_measure_spec.rb
index 938b67afa..b33ae7bb7 100644
--- a/spec/lib/admin/metrics/measure/tag_accounts_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/tag_accounts_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::TagAccountsMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let!(:tag) { Fabricate(:tag) }
 
@@ -12,8 +12,39 @@ describe Admin::Metrics::Measure::TagAccountsMeasure do
   let(:params) { ActionController::Parameters.new(id: tag.id) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with tagged accounts' do
+      let(:alice) { Fabricate(:account, domain: 'alice.example') }
+      let(:bob) { Fabricate(:account, domain: 'bob.example') }
+
+      before do
+        3.times do
+          travel_to(2.days.ago) { add_tag_history(alice) }
+        end
+
+        2.times do
+          travel_to(1.day.ago) do
+            add_tag_history(alice)
+            add_tag_history(bob)
+          end
+        end
+
+        add_tag_history(bob)
+      end
+
+      it 'returns correct tag_accounts counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '1'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
+
+      def add_tag_history(account)
+        tag.history.add(account.id)
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/tag_servers_measure_spec.rb b/spec/lib/admin/metrics/measure/tag_servers_measure_spec.rb
index e09a2b04e..e1e2ced43 100644
--- a/spec/lib/admin/metrics/measure/tag_servers_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/tag_servers_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::TagServersMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let!(:tag) { Fabricate(:tag) }
 
@@ -12,8 +12,38 @@ describe Admin::Metrics::Measure::TagServersMeasure do
   let(:params) { ActionController::Parameters.new(id: tag.id) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with tagged statuses' do
+      let(:alice) { Fabricate(:account, domain: 'alice.example') }
+      let(:bob) { Fabricate(:account, domain: 'bob.example') }
+
+      before do
+        3.times do
+          status_alice = Fabricate(:status, account: alice, created_at: 2.days.ago)
+          status_alice.tags << tag
+        end
+
+        2.times do
+          status_alice = Fabricate(:status, account: alice, created_at: 1.day.ago)
+          status_alice.tags << tag
+
+          status_bob = Fabricate(:status, account: bob, created_at: 1.day.ago)
+          status_bob.tags << tag
+        end
+
+        status_bob = Fabricate(:status, account: bob, created_at: 0.days.ago)
+        status_bob.tags << tag
+      end
+
+      it 'returns correct tag counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '1'),
+            include(date: 1.day.ago.midnight.to_time, value: '2'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
     end
   end
 end
diff --git a/spec/lib/admin/metrics/measure/tag_uses_measure_spec.rb b/spec/lib/admin/metrics/measure/tag_uses_measure_spec.rb
index 869e93744..dd66f00de 100644
--- a/spec/lib/admin/metrics/measure/tag_uses_measure_spec.rb
+++ b/spec/lib/admin/metrics/measure/tag_uses_measure_spec.rb
@@ -3,7 +3,7 @@
 require 'rails_helper'
 
 describe Admin::Metrics::Measure::TagUsesMeasure do
-  subject(:measure) { described_class.new(start_at, end_at, params) }
+  subject { described_class.new(start_at, end_at, params) }
 
   let!(:tag) { Fabricate(:tag) }
 
@@ -12,8 +12,39 @@ describe Admin::Metrics::Measure::TagUsesMeasure do
   let(:params) { ActionController::Parameters.new(id: tag.id) }
 
   describe '#data' do
-    it 'runs data query without error' do
-      expect { measure.data }.to_not raise_error
+    context 'with tagged accounts' do
+      let(:alice) { Fabricate(:account, domain: 'alice.example') }
+      let(:bob) { Fabricate(:account, domain: 'bob.example') }
+
+      before do
+        3.times do
+          travel_to(2.days.ago) { add_tag_history(alice) }
+        end
+
+        2.times do
+          travel_to(1.day.ago) do
+            add_tag_history(alice)
+            add_tag_history(bob)
+          end
+        end
+
+        add_tag_history(bob)
+      end
+
+      it 'returns correct tag_uses counts' do
+        expect(subject.data.size)
+          .to eq(3)
+        expect(subject.data.map(&:symbolize_keys))
+          .to contain_exactly(
+            include(date: 2.days.ago.midnight.to_time, value: '3'),
+            include(date: 1.day.ago.midnight.to_time, value: '4'),
+            include(date: 0.days.ago.midnight.to_time, value: '1')
+          )
+      end
+
+      def add_tag_history(account)
+        tag.history.add(account.id)
+      end
     end
   end
 end

From 3f821e0d5e7b518370661b442b99840092ca9451 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 12 Apr 2024 11:41:44 +0200
Subject: [PATCH 132/173] Update dependency postcss-preset-env to v9.5.5
 (#29912)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index c4efdb4ad..3b8e522d5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -13200,9 +13200,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-custom-properties@npm:^13.3.6":
-  version: 13.3.6
-  resolution: "postcss-custom-properties@npm:13.3.6"
+"postcss-custom-properties@npm:^13.3.7":
+  version: 13.3.7
+  resolution: "postcss-custom-properties@npm:13.3.7"
   dependencies:
     "@csstools/cascade-layer-name-parser": "npm:^1.0.9"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
@@ -13211,7 +13211,7 @@ __metadata:
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/faa3b692966314a6dfcba93e74d91f20f2484ea328f88c809b1d0daa8ecc0d8d5125e06d1d7c18b5455ac30cb3501c7069b6e56e5efac61523a6ed75c3d73a30
+  checksum: 10c0/5d8767efae956f98d9a62a8f54d913c9ea95eaab1c906679ddeee64d87f0fb37d99c8ac1d16ec199794ed7c13a42d39ca2ea0a98df1056d400d4cbc9f31d6b94
   languageName: node
   linkType: hard
 
@@ -13672,8 +13672,8 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.4
-  resolution: "postcss-preset-env@npm:9.5.4"
+  version: 9.5.5
+  resolution: "postcss-preset-env@npm:9.5.5"
   dependencies:
     "@csstools/postcss-cascade-layers": "npm:^4.0.4"
     "@csstools/postcss-color-function": "npm:^3.0.13"
@@ -13716,7 +13716,7 @@ __metadata:
     postcss-color-hex-alpha: "npm:^9.0.4"
     postcss-color-rebeccapurple: "npm:^9.0.3"
     postcss-custom-media: "npm:^10.0.4"
-    postcss-custom-properties: "npm:^13.3.6"
+    postcss-custom-properties: "npm:^13.3.7"
     postcss-custom-selectors: "npm:^7.1.8"
     postcss-dir-pseudo-class: "npm:^8.0.1"
     postcss-double-position-gradients: "npm:^5.0.6"
@@ -13737,7 +13737,7 @@ __metadata:
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/6af900ad2f46b640339b626317288543ebb7c47b739f4776e4006513b32eceabe0be78109aa58446fa0f50284a433b3e3a9bd48aa5730fd0ac59ef51153e8f7b
+  checksum: 10c0/afc31fb75bc5e8e223d38fd34b81da08ee340818f5e392df1781728f2ff2a9dbc75e458673ce9f52deafefa90bbc99e0bd1453271498f5e02746c785180bad07
   languageName: node
   linkType: hard
 

From c386c36866881ac3bd3d0b156264231f7b4c8053 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 12 Apr 2024 11:42:12 +0200
Subject: [PATCH 133/173] Add `/` keyboard shortcut to focus the search field
 (#29921)

---
 app/javascript/mastodon/features/keyboard_shortcuts/index.jsx | 2 +-
 app/javascript/mastodon/features/ui/index.jsx                 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx
index 622ca525c..e34295848 100644
--- a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx
+++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx
@@ -107,7 +107,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
                 <td><FormattedMessage id='keyboard_shortcuts.back' defaultMessage='to navigate back' /></td>
               </tr>
               <tr>
-                <td><kbd>s</kbd></td>
+                <td><kbd>s</kbd>, <kbd>/</kbd></td>
                 <td><FormattedMessage id='keyboard_shortcuts.search' defaultMessage='to focus search' /></td>
               </tr>
               <tr>
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx
index 77f26fed9..c84a2c51a 100644
--- a/app/javascript/mastodon/features/ui/index.jsx
+++ b/app/javascript/mastodon/features/ui/index.jsx
@@ -89,7 +89,7 @@ const mapStateToProps = state => ({
 const keyMap = {
   help: '?',
   new: 'n',
-  search: 's',
+  search: ['s', '/'],
   forceNew: 'option+n',
   toggleComposeSpoilers: 'option+x',
   focusColumn: ['1', '2', '3', '4', '5', '6', '7', '8', '9'],

From 8986e3b088db901e64a7cd3faa23dbb3b5ca9116 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 12 Apr 2024 11:48:13 +0200
Subject: [PATCH 134/173] Update dependency webpack-bundle-analyzer to v4.10.2
 (#29909)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 3b8e522d5..f4e99c075 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -17619,8 +17619,8 @@ __metadata:
   linkType: hard
 
 "webpack-bundle-analyzer@npm:^4.8.0":
-  version: 4.10.1
-  resolution: "webpack-bundle-analyzer@npm:4.10.1"
+  version: 4.10.2
+  resolution: "webpack-bundle-analyzer@npm:4.10.2"
   dependencies:
     "@discoveryjs/json-ext": "npm:0.5.7"
     acorn: "npm:^8.0.4"
@@ -17630,14 +17630,13 @@ __metadata:
     escape-string-regexp: "npm:^4.0.0"
     gzip-size: "npm:^6.0.0"
     html-escaper: "npm:^2.0.2"
-    is-plain-object: "npm:^5.0.0"
     opener: "npm:^1.5.2"
     picocolors: "npm:^1.0.0"
     sirv: "npm:^2.0.3"
     ws: "npm:^7.3.1"
   bin:
     webpack-bundle-analyzer: lib/bin/analyzer.js
-  checksum: 10c0/6a94c8f6aa03296fb2eb00d6ad3b27bd5c551590fd253772bc61debf3177414d42701014079d4f85c74ba1ca685ae9f0cb4063812b58c21f294d108e9908e5cd
+  checksum: 10c0/00603040e244ead15b2d92981f0559fa14216381349412a30070a7358eb3994cd61a8221d34a3b3fb8202dc3d1c5ee1fbbe94c5c52da536e5b410aa1cf279a48
   languageName: node
   linkType: hard
 

From 61d108f415bc4689c52f6d0ae693568f2f25ad97 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 12 Apr 2024 05:50:46 -0400
Subject: [PATCH 135/173] Extract `header_tags` method in statuses/show view
 spec (#29907)

---
 spec/views/statuses/show.html.haml_spec.rb | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/spec/views/statuses/show.html.haml_spec.rb b/spec/views/statuses/show.html.haml_spec.rb
index 92ba678b6..c74377d98 100644
--- a/spec/views/statuses/show.html.haml_spec.rb
+++ b/spec/views/statuses/show.html.haml_spec.rb
@@ -21,12 +21,11 @@ describe 'statuses/show.html.haml', :without_verify_partial_doubles do
 
     render
 
-    header_tags = view.content_for(:header_tags)
-
-    expect(header_tags).to match(/<meta content=".+" property="og:title">/)
-    expect(header_tags).to match(/<meta content="article" property="og:type">/)
-    expect(header_tags).to match(/<meta content=".+" property="og:image">/)
-    expect(header_tags).to match(%r{<meta content="http://.+" property="og:url">})
+    expect(header_tags)
+      .to match(/<meta content=".+" property="og:title">/)
+      .and match(/<meta content="article" property="og:type">/)
+      .and match(/<meta content=".+" property="og:image">/)
+      .and match(%r{<meta content="http://.+" property="og:url">})
   end
 
   it 'has twitter player tag' do
@@ -40,9 +39,12 @@ describe 'statuses/show.html.haml', :without_verify_partial_doubles do
 
     render
 
-    header_tags = view.content_for(:header_tags)
+    expect(header_tags)
+      .to match(%r{<meta content="http://.+/media/.+/player" property="twitter:player">})
+      .and match(/<meta content="player" property="twitter:card">/)
+  end
 
-    expect(header_tags).to match(%r{<meta content="http://.+/media/.+/player" property="twitter:player">})
-    expect(header_tags).to match(/<meta content="player" property="twitter:card">/)
+  def header_tags
+    view.content_for(:header_tags)
   end
 end

From 67a37c72794be929b8dbfb182dbbda164aed99ec Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 12 Apr 2024 12:56:49 +0200
Subject: [PATCH 136/173] Update dependency sass to v1.75.0 (#29919)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index f4e99c075..6e5330af5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15300,15 +15300,15 @@ __metadata:
   linkType: hard
 
 "sass@npm:^1.62.1":
-  version: 1.74.1
-  resolution: "sass@npm:1.74.1"
+  version: 1.75.0
+  resolution: "sass@npm:1.75.0"
   dependencies:
     chokidar: "npm:>=3.0.0 <4.0.0"
     immutable: "npm:^4.0.0"
     source-map-js: "npm:>=0.6.2 <2.0.0"
   bin:
     sass: sass.js
-  checksum: 10c0/4610257ee27823276ce4998a534b4ee9f313e5a0b3d3899e70e0f87096feeae4cd8dd3c2f765b52f57dd87f5dab22370ef63f95a837a189fbb9401396d5ce717
+  checksum: 10c0/1564ab2c8041c99a330cec93127fe8abcf65ac63eecb471610ed7f3126a2599a58b788a3a98eb8719f7f40b9b04e00c92bc9e11a9c2180ad582b8cba9fb030b0
   languageName: node
   linkType: hard
 

From c4d6e10115bfe5f336476058b44405d72dc57b2b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 12 Apr 2024 10:57:37 +0000
Subject: [PATCH 137/173] Update dependency rubocop to v1.63.1 (#29878)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 3de5ab5c7..9df16248c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -646,7 +646,7 @@ GEM
       rspec-mocks (~> 3.0)
       sidekiq (>= 5, < 8)
     rspec-support (3.13.1)
-    rubocop (1.62.1)
+    rubocop (1.63.1)
       json (~> 2.3)
       language_server-protocol (>= 3.17.0)
       parallel (~> 1.10)

From 86c53e175d5473ad49e5c321aab67465c81fabac Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:26:41 +0200
Subject: [PATCH 138/173] Update dependency @testing-library/react to v14.3.1
 (#29947)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 6e5330af5..38cb311f8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3331,8 +3331,8 @@ __metadata:
   linkType: hard
 
 "@testing-library/react@npm:^14.0.0":
-  version: 14.2.2
-  resolution: "@testing-library/react@npm:14.2.2"
+  version: 14.3.1
+  resolution: "@testing-library/react@npm:14.3.1"
   dependencies:
     "@babel/runtime": "npm:^7.12.5"
     "@testing-library/dom": "npm:^9.0.0"
@@ -3340,7 +3340,7 @@ __metadata:
   peerDependencies:
     react: ^18.0.0
     react-dom: ^18.0.0
-  checksum: 10c0/ab36707f6701a4a56dd217e16e00d6326e0f760bb2e716245422c7500a0b94efcd351d0aa89c4fab2916e6ebc68c983cec6b3ae0804de813cafc913a612668f6
+  checksum: 10c0/1ccf4eb1510500cc20a805cb0244c9098dca28a8745173a8f71ea1274d63774f0b7898a35c878b43c797b89c13621548909ff37843b835c1a27ee1efbbdd098c
   languageName: node
   linkType: hard
 

From e3dd60cce1b865d20e90875657d90638476216d5 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:26:57 +0200
Subject: [PATCH 139/173] Update peter-evans/create-pull-request action to
 v6.0.3 (#29946)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 .github/workflows/crowdin-download.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml
index e3ad7371a..14b0542d7 100644
--- a/.github/workflows/crowdin-download.yml
+++ b/.github/workflows/crowdin-download.yml
@@ -52,7 +52,7 @@ jobs:
 
       # Create or update the pull request
       - name: Create Pull Request
-        uses: peter-evans/create-pull-request@v6.0.2
+        uses: peter-evans/create-pull-request@v6.0.3
         with:
           commit-message: 'New Crowdin translations'
           title: 'New Crowdin Translations (automated)'

From 80edd7a317ba76ffb740db27442016030babf3a9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:27:33 +0200
Subject: [PATCH 140/173] Update DefinitelyTyped types (non-major) (#29944)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 38cb311f8..46f904a4f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3699,13 +3699,13 @@ __metadata:
   linkType: hard
 
 "@types/pg@npm:^8.6.6":
-  version: 8.11.4
-  resolution: "@types/pg@npm:8.11.4"
+  version: 8.11.5
+  resolution: "@types/pg@npm:8.11.5"
   dependencies:
     "@types/node": "npm:*"
     pg-protocol: "npm:*"
     pg-types: "npm:^4.0.1"
-  checksum: 10c0/81158ffa9d2f9b2b299a1650756b90fc418e0040e654d7d9ee46734a3c874d07b638af86d765e22e9c8246054c30a0274ee4dea58a0a7ed5c0c4aa01964a09ef
+  checksum: 10c0/d64d183bee2df96cd0558231190ff629558e8c0fd3203b880f48a7d34b1eaea528d20c09b57b19c0939f369136e6c6941533592eadd71174be78d1ec0ca5e60e
   languageName: node
   linkType: hard
 
@@ -3759,11 +3759,11 @@ __metadata:
   linkType: hard
 
 "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4":
-  version: 18.2.24
-  resolution: "@types/react-dom@npm:18.2.24"
+  version: 18.2.25
+  resolution: "@types/react-dom@npm:18.2.25"
   dependencies:
     "@types/react": "npm:*"
-  checksum: 10c0/9ec38e5ab4727c56ef17bd8e938ead88748ba19db314b8d9807714a5cae430f5b799514667b221b4f2dc8d9b4ca17dd1c3da8c41c083c2de9eddcc31bec6b8ff
+  checksum: 10c0/87604407eca6884c5b4d4657cb511dc5ba28ea1cfa5d0ce1fc2d659a7ad1b64ae85dcda60e3f010641f9a52a6a60dfcaa6be3b0d0de9d624475052a13dae01f4
   languageName: node
   linkType: hard
 
@@ -3862,12 +3862,12 @@ __metadata:
   linkType: hard
 
 "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
-  version: 18.2.74
-  resolution: "@types/react@npm:18.2.74"
+  version: 18.2.78
+  resolution: "@types/react@npm:18.2.78"
   dependencies:
     "@types/prop-types": "npm:*"
     csstype: "npm:^3.0.2"
-  checksum: 10c0/347e38b4c5dc20d50ff71bf04b7caaef490e5ff695e74a0088a13fbb2a0c5d125a5ecfd142adfa30f0176da0e2734942c91ba61d95ce269c43b3265bd7379361
+  checksum: 10c0/5eb8e1dd98c29aeddf40b90f466d1a9ce83b113d42a096633d632b834e7ae9821f24ba7999928de9d98cca37764532a7ea35355a8103a377d8baa750f1841b5c
   languageName: node
   linkType: hard
 

From 1906330d1389ebf88223c86f58812a32d903b73d Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:27:56 +0200
Subject: [PATCH 141/173] Update dependency react-redux to v9.1.1 (#29943)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 46f904a4f..6be5b6cbe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14430,8 +14430,8 @@ __metadata:
   linkType: hard
 
 "react-redux@npm:^9.0.4":
-  version: 9.1.0
-  resolution: "react-redux@npm:9.1.0"
+  version: 9.1.1
+  resolution: "react-redux@npm:9.1.1"
   dependencies:
     "@types/use-sync-external-store": "npm:^0.0.3"
     use-sync-external-store: "npm:^1.0.0"
@@ -14447,7 +14447,7 @@ __metadata:
       optional: true
     redux:
       optional: true
-  checksum: 10c0/53161b5dc4d109020fbc42d26906ace92fed9ba1d7ab6274af60e9c0684583d20d1c8ec6d58601ac7b833c6468a652bbf3d4a102149d1793cb8a28b05b042f73
+  checksum: 10c0/40ccdc8d48aefeed02c025f46e4a2e6641a2996fe985feb70d25feaaf8f101f6ef937cd1420909cad4c8869a8c79323ee071f5b090b011b950e5ae09100f5767
   languageName: node
   linkType: hard
 

From 34e826f373d20f6230d1ef0aa03ad41a3bdf5998 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:28:29 +0200
Subject: [PATCH 142/173] Update dependency typescript to v5.4.5 (#29945)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 6be5b6cbe..7504e3d93 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -17083,22 +17083,22 @@ __metadata:
   linkType: hard
 
 "typescript@npm:5, typescript@npm:^5.0.4":
-  version: 5.4.4
-  resolution: "typescript@npm:5.4.4"
+  version: 5.4.5
+  resolution: "typescript@npm:5.4.5"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/4d8de0291204ed61ca97ad0cba2ce064e09c4988ca1c451c787e4653ba76296ba35177a52694e8a00cf4ef899d0ee83338663b926d8b7d55167ff0ba81549999
+  checksum: 10c0/2954022ada340fd3d6a9e2b8e534f65d57c92d5f3989a263754a78aba549f7e6529acc1921913560a4b816c46dce7df4a4d29f9f11a3dc0d4213bb76d043251e
   languageName: node
   linkType: hard
 
 "typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>":
-  version: 5.4.4
-  resolution: "typescript@patch:typescript@npm%3A5.4.4#optional!builtin<compat/typescript>::version=5.4.4&hash=5adc0c"
+  version: 5.4.5
+  resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin<compat/typescript>::version=5.4.5&hash=5adc0c"
   bin:
     tsc: bin/tsc
     tsserver: bin/tsserver
-  checksum: 10c0/1fa41b9964a9ff0ed913b339c90b46031b2d2da3cb1a192af516610733f7f1d5f7f9754a8e22b9ac7076d3d8aedd2c4f84db3f113bad060eac3a95962443a1bf
+  checksum: 10c0/db2ad2a16ca829f50427eeb1da155e7a45e598eec7b086d8b4e8ba44e5a235f758e606d681c66992230d3fc3b8995865e5fd0b22a2c95486d0b3200f83072ec9
   languageName: node
   linkType: hard
 

From ee4ea83a879ca755c38fa374dea05b5d8b973f3e Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Mon, 15 Apr 2024 11:05:19 +0200
Subject: [PATCH 143/173] Remove `image_pack_tag` usage (#29925)

---
 app/helpers/branding_helper.rb      | 2 +-
 app/views/shared/_web_app.html.haml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/helpers/branding_helper.rb b/app/helpers/branding_helper.rb
index f72d6df5d..8201f36e3 100644
--- a/app/helpers/branding_helper.rb
+++ b/app/helpers/branding_helper.rb
@@ -19,6 +19,6 @@ module BrandingHelper
   end
 
   def render_logo
-    image_pack_tag('logo.svg', alt: 'Mastodon', class: 'logo logo--icon')
+    image_tag(frontend_asset_path('images/logo.svg'), alt: 'Mastodon', class: 'logo logo--icon')
   end
 end
diff --git a/app/views/shared/_web_app.html.haml b/app/views/shared/_web_app.html.haml
index e9ca54169..89d6ee567 100644
--- a/app/views/shared/_web_app.html.haml
+++ b/app/views/shared/_web_app.html.haml
@@ -12,7 +12,7 @@
 
 .notranslate.app-holder#mastodon{ data: { props: Oj.dump(default_props) } }
   %noscript
-    = image_pack_tag 'logo.svg', alt: 'Mastodon'
+    = image_tag frontend_asset_path('images/logo.svg'), alt: 'Mastodon'
 
     %div
       = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps')

From 67dd1763bb79cf6441cdd1eac15edcac72397ceb Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Mon, 15 Apr 2024 11:06:06 +0200
Subject: [PATCH 144/173] Fix PostCSS config (#29926)

---
 postcss.config.js | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/postcss.config.js b/postcss.config.js
index b6ea8130b..63aeafb36 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,7 +1,10 @@
-module.exports = ({ env }) => ({
+/** @type {import('postcss-load-config').Config} */
+const config = ({ env }) => ({
   plugins: [
-    'postcss-preset-env',
-    'autoprefixer',
-    env === 'production' ? 'cssnano' : '',
+    require('postcss-preset-env'),
+    require('autoprefixer'),
+    env === 'production' ? require('cssnano') : '',
   ],
 });
+
+module.exports = config;

From bf5d948237ae9e48ba38666b58ce8baee477d0df Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 15 Apr 2024 05:15:32 -0400
Subject: [PATCH 145/173] Fix `Style/SingleArgumentDig` cop in
 webpacker/manifest_extensions (#29929)

---
 .rubocop_todo.yml                    | 5 -----
 lib/webpacker/manifest_extensions.rb | 4 ++--
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index ea1dbe57e..d7320aa9f 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -250,11 +250,6 @@ Style/SignalException:
     - 'lib/devise/strategies/two_factor_ldap_authenticatable.rb'
     - 'lib/devise/strategies/two_factor_pam_authenticatable.rb'
 
-# This cop supports unsafe autocorrection (--autocorrect-all).
-Style/SingleArgumentDig:
-  Exclude:
-    - 'lib/webpacker/manifest_extensions.rb'
-
 # This cop supports unsafe autocorrection (--autocorrect-all).
 # Configuration parameters: Mode.
 Style/StringConcatenation:
diff --git a/lib/webpacker/manifest_extensions.rb b/lib/webpacker/manifest_extensions.rb
index 789eb81cc..8a184bc52 100644
--- a/lib/webpacker/manifest_extensions.rb
+++ b/lib/webpacker/manifest_extensions.rb
@@ -5,9 +5,9 @@ module Webpacker::ManifestExtensions
     asset = super
 
     if pack_type[:with_integrity] && asset.respond_to?(:dig)
-      [asset.dig('src'), asset.dig('integrity')]
+      [asset['src'], asset['integrity']]
     elsif asset.respond_to?(:dig)
-      asset.dig('src')
+      asset['src']
     else
       asset
     end

From 0d9ad96d3fbbc3c88cba78d1e1e1a1e5d2a3ad79 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 15 Apr 2024 05:16:59 -0400
Subject: [PATCH 146/173] Rename `PremailerWebpackStrategy` ->
 `PremailerBundledAssetStrategy` (#29934)

---
 .rubocop_todo.yml                                             | 1 -
 config/initializers/premailer_rails.rb                        | 4 ++--
 ...ebpack_strategy.rb => premailer_bundled_asset_strategy.rb} | 4 ++--
 3 files changed, 4 insertions(+), 5 deletions(-)
 rename lib/{premailer_webpack_strategy.rb => premailer_bundled_asset_strategy.rb} (80%)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index d7320aa9f..63d9d6757 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -97,7 +97,6 @@ Style/FetchEnvVar:
     - 'config/initializers/paperclip.rb'
     - 'config/initializers/vapid.rb'
     - 'lib/mastodon/redis_config.rb'
-    - 'lib/premailer_webpack_strategy.rb'
     - 'lib/tasks/repo.rake'
     - 'spec/features/profile_spec.rb'
 
diff --git a/config/initializers/premailer_rails.rb b/config/initializers/premailer_rails.rb
index 5e9576be7..1c8df970d 100644
--- a/config/initializers/premailer_rails.rb
+++ b/config/initializers/premailer_rails.rb
@@ -1,9 +1,9 @@
 # frozen_string_literal: true
 
-require_relative '../../lib/premailer_webpack_strategy'
+require_relative '../../lib/premailer_bundled_asset_strategy'
 
 Premailer::Rails.config.merge!(remove_ids: true,
                                adapter: :nokogiri,
                                generate_text_part: false,
                                css_to_attributes: false,
-                               strategies: [PremailerWebpackStrategy])
+                               strategies: [PremailerBundledAssetStrategy])
diff --git a/lib/premailer_webpack_strategy.rb b/lib/premailer_bundled_asset_strategy.rb
similarity index 80%
rename from lib/premailer_webpack_strategy.rb
rename to lib/premailer_bundled_asset_strategy.rb
index 6816d0474..fbe50cd4f 100644
--- a/lib/premailer_webpack_strategy.rb
+++ b/lib/premailer_bundled_asset_strategy.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
-module PremailerWebpackStrategy
+module PremailerBundledAssetStrategy
   def load(url)
-    asset_host = ENV['CDN_HOST'] || ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']
+    asset_host = ENV['CDN_HOST'] || ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
 
     if Webpacker.dev_server.running?
       asset_host = "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}"

From 4e78cb99886f550b7f91848ea2b5bd97bce1893d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 15 Apr 2024 11:29:39 +0200
Subject: [PATCH 147/173] New Crowdin Translations (automated) (#29939)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/lt.json |  5 ++++-
 app/javascript/mastodon/locales/pa.json | 14 ++++++++++++++
 app/javascript/mastodon/locales/ru.json |  1 +
 app/javascript/mastodon/locales/th.json |  4 ++--
 config/locales/ja.yml                   | 13 +++++++++++++
 config/locales/pt-BR.yml                |  6 ++++++
 6 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index 0d416be2a..580af4f3d 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -83,12 +83,15 @@
   "admin.impact_report.instance_follows": "Sekėjai, kuriuos prarastų jų naudotojai",
   "admin.impact_report.title": "Poveikio apibendrinimas",
   "alert.rate_limited.message": "Pabandyk vėliau po {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Sparta ribota",
+  "alert.rate_limited.title": "Sparta ribota.",
   "alert.unexpected.message": "Įvyko netikėta klaida.",
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Skelbimas",
   "attachments_list.unprocessed": "(neapdorotas)",
   "audio.hide": "Slėpti garsą",
+  "block_modal.remote_users_caveat": "Paprašysime serverio {domain} gerbti tavo sprendimą. Tačiau atitiktis negarantuojama, nes kai kurie serveriai gali skirtingai tvarkyti blokavimus. Vieši įrašai vis tiek gali būti matomi neprisijungusiems naudotojams.",
+  "block_modal.show_less": "Rodyti mažiau",
+  "block_modal.show_more": "Rodyti daugiau",
   "boost_modal.combo": "Galima paspausti {combo}, kad praleisti kitą kartą.",
   "bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą",
   "bundle_column_error.error.body": "Paprašytos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.",
diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json
index e09dd9067..c693c2472 100644
--- a/app/javascript/mastodon/locales/pa.json
+++ b/app/javascript/mastodon/locales/pa.json
@@ -15,21 +15,32 @@
   "account.cancel_follow_request": "ਫ਼ਾਲੋ ਕਰਨ ਨੂੰ ਰੱਦ ਕਰੋ",
   "account.copy": "ਪਰੋਫਾਇਲ ਲਈ ਲਿੰਕ ਕਾਪੀ ਕਰੋ",
   "account.direct": "ਨਿੱਜੀ ਜ਼ਿਕਰ @{name}",
+  "account.domain_blocked": "ਡੋਮੇਨ ਉੱਤੇ ਪਾਬੰਦੀ",
   "account.edit_profile": "ਪਰੋਫਾਈਲ ਨੂੰ ਸੋਧੋ",
+  "account.enable_notifications": "ਜਦੋਂ {name} ਪੋਸਟ ਕਰੇ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦਿਓ",
+  "account.endorse": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਫ਼ੀਚਰ",
   "account.featured_tags.last_status_at": "{date} ਨੂੰ ਆਖਰੀ ਪੋਸਟ",
   "account.featured_tags.last_status_never": "ਕੋਈ ਪੋਸਟ ਨਹੀਂ",
   "account.follow": "ਫ਼ਾਲੋ",
+  "account.follow_back": "ਵਾਪਸ ਫਾਲ਼ੋ ਕਰੋ",
   "account.followers": "ਫ਼ਾਲੋਅਰ",
   "account.followers.empty": "ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਾਲੇ ਕੋਈ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
+  "account.followers_counter": "{count, plural, one {{counter} ਫ਼ਾਲੋਅਰ} other {{counter} ਫ਼ਾਲੋਅਰ}}",
   "account.following": "ਫ਼ਾਲੋ ਕੀਤਾ",
+  "account.following_counter": "{count, plural, one {{counter} ਨੂੰ ਫ਼ਾਲੋ} other {{counter} ਨੂੰ ਫ਼ਾਲੋ}}",
   "account.follows.empty": "ਇਹ ਵਰਤੋਂਕਾਰ ਹਾਲੇ ਕਿਸੇ ਨੂੰ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
   "account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ",
   "account.media": "ਮੀਡੀਆ",
   "account.muted": "ਮੌਨ ਕੀਤੀਆਂ",
+  "account.mutual": "ਸਾਂਝੇ",
+  "account.no_bio": "ਕੋਈ ਵਰਣਨ ਨਹੀਂ ਦਿੱਤਾ।",
+  "account.open_original_page": "ਅਸਲ ਸਫ਼ੇ ਨੂੰ ਖੋਲ੍ਹੋ",
   "account.posts": "ਪੋਸਟਾਂ",
   "account.posts_with_replies": "ਪੋਸਤਾਂ ਅਤੇ ਜਵਾਬ",
+  "account.report": "{name} ਬਾਰੇ ਰਿਪੋਰਟ ਕਰੋ",
   "account.requested": "ਮਨਜ਼ੂਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ। ਫ਼ਾਲੋ ਬੇਨਤੀਆਂ ਨੂੰ ਰੱਦ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ",
   "account.requested_follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ",
+  "account.share": "{name} ਦਾ ਪਰੋਫ਼ਾਇਲ ਸਾਂਝਾ ਕਰੋ",
   "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}",
   "account.unblock": "@{name} ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
   "account.unblock_domain": "{domain} ਡੋਮੇਨ ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
@@ -41,6 +52,9 @@
   "admin.dashboard.retention.cohort_size": "ਨਵੇਂ ਵਰਤੋਂਕਾਰ",
   "alert.unexpected.title": "ਓਹੋ!",
   "announcement.announcement": "ਹੋਕਾ",
+  "block_modal.show_less": "ਘੱਟ ਦਿਖਾਓ",
+  "block_modal.show_more": "ਵੱਧ ਦਿਖਾਓ",
+  "block_modal.title": "ਵਰਤੋਂਕਾਰ ਉੱਤੇ ਪਾਬੰਦੀ ਲਾਉਣੀ ਹੈ?",
   "bundle_column_error.error.title": "ਓਹ ਹੋ!",
   "bundle_column_error.network.title": "ਨੈੱਟਵਰਕ ਦੀ ਸਮੱਸਿਆ",
   "bundle_column_error.retry": "ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰੋ",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 7ff98ba53..16c4d1998 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -514,6 +514,7 @@
   "notifications.permission_denied": "Уведомления на рабочем столе недоступны, так как вы запретили их отправку в браузере. Проверьте настройки для сайта, чтобы включить их обратно.",
   "notifications.permission_denied_alert": "Уведомления на рабочем столе недоступны, так как вы ранее отклонили запрос на их отправку.",
   "notifications.permission_required": "Чтобы включить уведомления на рабочем столе, необходимо разрешить их в браузере.",
+  "notifications.policy.filter_new_accounts_title": "Новые учётные записи",
   "notifications_permission_banner.enable": "Включить уведомления",
   "notifications_permission_banner.how_to_control": "Получайте уведомления даже когда Mastodon закрыт, включив уведомления на рабочем столе. А чтобы лишний шум не отвлекал, вы можете настроить какие уведомления вы хотите получать, нажав на кнопку {icon} выше.",
   "notifications_permission_banner.title": "Будьте в курсе происходящего",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 4a7c22439..952ed5adf 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -16,12 +16,12 @@
   "account.badges.bot": "อัตโนมัติ",
   "account.badges.group": "กลุ่ม",
   "account.block": "ปิดกั้น @{name}",
-  "account.block_domain": "เลิกปิดกั้นโดเมน {domain} แล้ว",
+  "account.block_domain": "ปิดกั้นโดเมน {domain}",
   "account.block_short": "ปิดกั้น",
   "account.blocked": "ปิดกั้นอยู่",
   "account.browse_more_on_origin_server": "เรียกดูเพิ่มเติมในโปรไฟล์ดั้งเดิม",
   "account.cancel_follow_request": "ยกเลิกการติดตาม",
-  "account.copy": "Copy link to profile",
+  "account.copy": "คัดลอกลิงก์ไปยังโปรไฟล์",
   "account.direct": "กล่าวถึง @{name} แบบส่วนตัว",
   "account.disable_notifications": "หยุดแจ้งเตือนฉันเมื่อ @{name} โพสต์",
   "account.domain_blocked": "ปิดกั้นโดเมนอยู่",
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 0d585131e..f9cbb6a75 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1629,13 +1629,26 @@ ja:
     import: データのインポート
     import_and_export: インポート・エクスポート
     migrate: アカウントの引っ越し
+    notifications: メール通知
     preferences: ユーザー設定
     profile: プロフィール
     relationships: フォロー・フォロワー
+    severed_relationships: 途切れたフォロー関係
     statuses_cleanup: 投稿の自動削除
     strikes: モデレーションストライク
     two_factor_authentication: 二要素認証
     webauthn_authentication: セキュリティキー
+  severed_relationships:
+    download: 取り出す (%{count}件)
+    event_type:
+      account_suspension: アカウントの停止 (%{target_name})
+      domain_block: 管理者によるサーバーの停止 (%{target_name})
+      user_domain_block: ユーザーによるドメインブロック (%{target_name})
+    lost_followers: 解除されたフォロワー
+    lost_follows: 解除されたフォロー
+    preamble: ドメインをブロックしたりモデレーターによってリモートのサーバーが停止された場合、巻き込みでフォロー・フォロワー関係が失われることがあります。このようにして解除されたフォロー・フォロワーはリスト形式で取り出して内容を確認したり、対応している場合は他のサーバーでインポートできます。
+    purged: 管理者がサーバーの情報を削除したため表示できません。
+    type: 理由
   statuses:
     attached:
       audio:
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 0b28c8c1b..4c22335ea 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -1669,6 +1669,9 @@ pt-BR:
     event_type:
       account_suspension: Suspensão da conta (%{target_name})
       domain_block: Suspensão do servidor (%{target_name})
+      user_domain_block: Você bloqueou %{target_name}
+    lost_followers: Seguidores perdidos
+    type: Evento
   statuses:
     attached:
       audio:
@@ -1874,6 +1877,9 @@ pt-BR:
       follows_subtitle: Siga contas conhecidas
       follows_title: Quem seguir
       follows_view_more: Veja mais pessoas para seguir
+      hashtags_recent_count:
+        one: "%{people} Pessoas nos últimos 2 dias"
+        other: "%{people} pessoas nos últimos 2 dias"
       hashtags_subtitle: Explorar o que está em alta nos últimos 2 dias
       hashtags_title: Hashtags em alta
       hashtags_view_more: Ver mais hashtags em alta

From 1549e6a9dc46c31c723216041d798b470b708080 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 15 Apr 2024 06:19:23 -0400
Subject: [PATCH 148/173] Drop support for Ruby 3.0 (reaching EOL) (#29702)

---
 .github/workflows/test-ruby.yml | 3 ---
 .rubocop.yml                    | 8 +++++++-
 Gemfile                         | 2 +-
 README.md                       | 2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml
index 624c3b7a2..172b5271d 100644
--- a/.github/workflows/test-ruby.yml
+++ b/.github/workflows/test-ruby.yml
@@ -111,7 +111,6 @@ jobs:
       fail-fast: false
       matrix:
         ruby-version:
-          - '3.0'
           - '3.1'
           - '.ruby-version'
           - '3.3'
@@ -187,7 +186,6 @@ jobs:
       fail-fast: false
       matrix:
         ruby-version:
-          - '3.0'
           - '3.1'
           - '.ruby-version'
           - '3.3'
@@ -287,7 +285,6 @@ jobs:
       fail-fast: false
       matrix:
         ruby-version:
-          - '3.0'
           - '3.1'
           - '.ruby-version'
           - '3.3'
diff --git a/.rubocop.yml b/.rubocop.yml
index 7fb8ab0c5..e80f3b293 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -14,7 +14,7 @@ require:
   - ./lib/linter/rubocop_middle_dot
 
 AllCops:
-  TargetRubyVersion: 3.0 # Set to minimum supported version of CI
+  TargetRubyVersion: 3.1 # Set to minimum supported version of CI
   DisplayCopNames: true
   DisplayStyleGuide: true
   ExtraDetails: true
@@ -80,6 +80,11 @@ Metrics/CyclomaticComplexity:
 Metrics/ParameterLists:
   CountKeywordArgs: false
 
+# Reason: Prefer seeing a variable name
+# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding
+Naming/BlockForwarding:
+  EnforcedStyle: explicit
+
 # Reason: Prevailing style is argument file paths
 # https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath
 Rails/FilePath:
@@ -180,6 +185,7 @@ Style/FormatStringToken:
 # https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
 Style/HashSyntax:
   EnforcedStyle: ruby19_no_mixed_keys
+  EnforcedShorthandSyntax: either
 
 # Reason:
 # https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals
diff --git a/Gemfile b/Gemfile
index a9affea41..35e0b2928 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 source 'https://rubygems.org'
-ruby '>= 3.0.0'
+ruby '>= 3.1.0'
 
 gem 'puma', '~> 6.3'
 gem 'rails', '~> 7.1.1'
diff --git a/README.md b/README.md
index 7f9b115c4..1d0e75dab 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre
 
 - **PostgreSQL** 12+
 - **Redis** 4+
-- **Ruby** 3.0+
+- **Ruby** 3.1+
 - **Node.js** 16+
 
 The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.

From 4117c8f6b88f72a9f2a3177f2c02708b7e05c772 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Mon, 15 Apr 2024 13:56:48 +0200
Subject: [PATCH 149/173] Fix unfollow button being out of frame on small
 screens on old browsers (#29923)

---
 app/javascript/styles/mastodon/components.scss | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index e35b69623..87e13ee45 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -7863,8 +7863,13 @@ noscript {
         }
       }
 
-      @container account-header (max-width: 372px) {
-        .optional {
+      .optional {
+        @container account-header (max-width: 372px) {
+          display: none;
+        }
+
+        // Fallback for older browsers with no container queries support
+        @media screen and (max-width: 372px + 55px) {
           display: none;
         }
       }

From 7fed4a974096ddbbbf23f8b0bb2b672f922b8b47 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 15 Apr 2024 11:24:31 -0400
Subject: [PATCH 150/173] Pull out repeated setup to shared setup in
 statusus/show view spec (#29927)

---
 spec/views/statuses/show.html.haml_spec.rb | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/spec/views/statuses/show.html.haml_spec.rb b/spec/views/statuses/show.html.haml_spec.rb
index c74377d98..1c408db6c 100644
--- a/spec/views/statuses/show.html.haml_spec.rb
+++ b/spec/views/statuses/show.html.haml_spec.rb
@@ -3,22 +3,23 @@
 require 'rails_helper'
 
 describe 'statuses/show.html.haml', :without_verify_partial_doubles do
+  let(:alice) { Fabricate(:account, username: 'alice', display_name: 'Alice') }
+  let(:status) { Fabricate(:status, account: alice, text: 'Hello World') }
+
   before do
     allow(view).to receive_messages(api_oembed_url: '', site_title: 'example site', site_hostname: 'example.com', full_asset_url: '//asset.host/image.svg', current_account: nil, single_user_mode?: false)
     allow(view).to receive(:local_time)
     allow(view).to receive(:local_time_ago)
     assign(:instance_presenter, InstancePresenter.new)
-  end
 
-  it 'has valid opengraph tags' do
-    alice  = Fabricate(:account, username: 'alice', display_name: 'Alice')
-    status = Fabricate(:status, account: alice, text: 'Hello World')
     Fabricate(:media_attachment, account: alice, status: status, type: :video)
 
     assign(:status, status)
     assign(:account, alice)
     assign(:descendant_threads, [])
+  end
 
+  it 'has valid opengraph tags' do
     render
 
     expect(header_tags)
@@ -29,14 +30,6 @@ describe 'statuses/show.html.haml', :without_verify_partial_doubles do
   end
 
   it 'has twitter player tag' do
-    alice  = Fabricate(:account, username: 'alice', display_name: 'Alice')
-    status = Fabricate(:status, account: alice, text: 'Hello World')
-    Fabricate(:media_attachment, account: alice, status: status, type: :video)
-
-    assign(:status, status)
-    assign(:account, alice)
-    assign(:descendant_threads, [])
-
     render
 
     expect(header_tags)

From 285d4123b5e8cf4b9cfc51a8ce506054f481ce95 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 16 Apr 2024 10:36:21 +0200
Subject: [PATCH 151/173] New Crowdin Translations (automated) (#29955)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/eu.json  |  2 +-
 app/javascript/mastodon/locales/fr.json  |  2 +-
 app/javascript/mastodon/locales/fy.json  | 32 ++++++++++-
 app/javascript/mastodon/locales/ia.json  | 73 ++++++++++++++++++++++--
 app/javascript/mastodon/locales/nl.json  |  4 +-
 app/javascript/mastodon/locales/tok.json | 23 ++++++--
 config/locales/de.yml                    |  2 +-
 7 files changed, 124 insertions(+), 14 deletions(-)

diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index bc57c4cee..529c1ab9c 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -408,7 +408,7 @@
   "lightbox.previous": "Aurrekoa",
   "limited_account_hint.action": "Erakutsi profila hala ere",
   "limited_account_hint.title": "Profil hau ezkutatu egin dute {domain} zerbitzariko moderatzaileek.",
-  "link_preview.author": "{name}(r)en eskutik",
+  "link_preview.author": "Egilea: {name}",
   "lists.account.add": "Gehitu zerrendara",
   "lists.account.remove": "Kendu zerrendatik",
   "lists.delete": "Ezabatu zerrenda",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index ace3d41e0..18fce401b 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -534,7 +534,7 @@
   "onboarding.actions.go_to_home": "Allers vers mon flux principal",
   "onboarding.compose.template": "Bonjour #Mastodon !",
   "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer d'utiliser la recherche ou parcourir la page de découverte pour trouver des personnes à suivre, ou réessayez plus tard.",
-  "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
+  "onboarding.follows.lead": "Votre flux principal est le principal moyen de découvrir Mastodon. Plus vous suivez de personnes, plus il sera actif et intéressant. Pour commencer, voici quelques suggestions :",
   "onboarding.follows.title": "Personnaliser votre flux principal",
   "onboarding.profile.discoverable": "Rendre mon profil découvrable",
   "onboarding.profile.discoverable_hint": "Lorsque vous acceptez d'être découvert sur Mastodon, vos messages peuvent apparaître dans les résultats de recherche et les tendances, et votre profil peut être suggéré à des personnes ayant des intérêts similaires aux vôtres.",
diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json
index 97119e30c..a22f4767a 100644
--- a/app/javascript/mastodon/locales/fy.json
+++ b/app/javascript/mastodon/locales/fy.json
@@ -13,7 +13,7 @@
   "about.rules": "Serverrigels",
   "account.account_note_header": "Opmerking",
   "account.add_or_remove_from_list": "Tafoegje oan of fuortsmite út listen",
-  "account.badges.bot": "Bot",
+  "account.badges.bot": "Automatisearre",
   "account.badges.group": "Groep",
   "account.block": "@{name} blokkearje",
   "account.block_domain": "Domein {domain} blokkearje",
@@ -89,6 +89,11 @@
   "announcement.announcement": "Oankundiging",
   "attachments_list.unprocessed": "(net ferwurke)",
   "audio.hide": "Audio ferstopje",
+  "block_modal.show_less": "Minder toane",
+  "block_modal.show_more": "Mear toane",
+  "block_modal.they_cant_mention": "Sy kinne jo net fermelde of folgje.",
+  "block_modal.title": "Brûker blokkearje?",
+  "block_modal.you_wont_see_mentions": "Jo sjogge gjin berjochten mear dy’t dizze account fermelde.",
   "boost_modal.combo": "Jo kinne op {combo} drukke om dit de folgjende kear oer te slaan",
   "bundle_column_error.copy_stacktrace": "Flaterrapport kopiearje",
   "bundle_column_error.error.body": "De opfrege side koe net werjûn wurde. It kin wêze troch in flater yn ús koade, of in probleem mei browserkompatibiliteit.",
@@ -169,6 +174,7 @@
   "confirmations.delete_list.message": "Binne jo wis dat jo dizze list foar permanint fuortsmite wolle?",
   "confirmations.discard_edit_media.confirm": "Fuortsmite",
   "confirmations.discard_edit_media.message": "Jo hawwe net-bewarre wizigingen yn de mediabeskriuwing of foarfertoaning, wolle jo dizze dochs fuortsmite?",
+  "confirmations.domain_block.confirm": "Server blokkearje",
   "confirmations.domain_block.message": "Binne jo echt wis dat jo alles fan {domain} negearje wolle? Yn de measte gefallen is it blokkearjen of negearjen fan in pear spesifike persoanen genôch en better. Jo sille gjin berjochten fan dizze server op iepenbiere tiidlinen sjen of yn jo meldingen. Jo folgers fan dizze server wurde fuortsmiten.",
   "confirmations.edit.confirm": "Bewurkje",
   "confirmations.edit.message": "Troch no te bewurkjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
@@ -200,6 +206,20 @@
   "dismissable_banner.explore_statuses": "Dizze berjochten winne oan populariteit op dizze en oare servers binnen it desintrale netwurk. Nijere berjochten mei mear boosts en favoriten stean heger.",
   "dismissable_banner.explore_tags": "Dizze hashtags winne oan populariteit op dizze en oare servers binnen it desintrale netwurk.",
   "dismissable_banner.public_timeline": "Dit binne de meast resinte iepenbiere berjochten fan accounts op it sosjale web dy’t troch minsken op {domain} folge wurde.",
+  "domain_block_modal.block": "Server blokkearje",
+  "domain_block_modal.block_account_instead": "Yn stee hjirfan {name} blokkearje",
+  "domain_block_modal.they_can_interact_with_old_posts": "Minsken op dizze server kinne ynteraksje hawwe mei jo âlde berjochten.",
+  "domain_block_modal.they_cant_follow": "Net ien op dizze server kin jo folgje.",
+  "domain_block_modal.they_wont_know": "Se krije net te witten dat se blokkearre wurde.",
+  "domain_block_modal.title": "Domein blokkearje?",
+  "domain_block_modal.you_will_lose_followers": "Al jo folgers fan dizze server wurde ûntfolge.",
+  "domain_block_modal.you_wont_see_posts": "Jo sjogge gjin berjochten of meldingen mear fan brûkers op dizze server.",
+  "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Harren fediverse-adres:",
+  "domain_pill.their_server": "Harren digitale thús, wer’t al harren berjochten binne.",
+  "domain_pill.username": "Brûkersnamme",
+  "domain_pill.whats_in_a_handle": "Wat is in fediverse-adres?",
+  "domain_pill.your_handle": "Jo fediverse-adres:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Sa komt it der út te sjen:",
   "emoji_button.activity": "Aktiviteiten",
@@ -266,6 +286,7 @@
   "filter_modal.select_filter.subtitle": "In besteande kategory brûke of in nije oanmeitsje",
   "filter_modal.select_filter.title": "Dit berjocht filterje",
   "filter_modal.title.status": "In berjocht filterje",
+  "filtered_notifications_banner.title": "Filtere meldingen",
   "firehose.all": "Alles",
   "firehose.local": "Dizze server",
   "firehose.remote": "Oare servers",
@@ -394,6 +415,9 @@
   "loading_indicator.label": "Lade…",
   "media_gallery.toggle_visible": "{number, plural, one {ôfbylding ferstopje} other {ôfbyldingen ferstopje}}",
   "moved_to_account_banner.text": "Omdat jo nei {movedToAccount} ferhuze binne is jo account {disabledAccount} op dit stuit útskeakele.",
+  "mute_modal.hide_options": "Opsjes ferstopje",
+  "mute_modal.indefinite": "Oant ik se net mear negearje",
+  "mute_modal.show_options": "Opsjes toane",
   "navigation_bar.about": "Oer",
   "navigation_bar.advanced_interface": "Yn avansearre webomjouwing iepenje",
   "navigation_bar.blocks": "Blokkearre brûkers",
@@ -429,14 +453,20 @@
   "notification.own_poll": "Jo poll is beëinige",
   "notification.poll": "In enkête dêr’t jo yn stimd hawwe is beëinige",
   "notification.reblog": "{name} hat jo berjocht boost",
+  "notification.relationships_severance_event.learn_more": "Mear ynfo",
   "notification.status": "{name} hat in berjocht pleatst",
   "notification.update": "{name} hat in berjocht bewurke",
+  "notification_requests.accept": "Akseptearje",
+  "notification_requests.dismiss": "Ofwize",
+  "notification_requests.notifications_from": "Meldingen fan {name}",
+  "notification_requests.title": "Filtere meldingen",
   "notifications.clear": "Meldingen wiskje",
   "notifications.clear_confirmation": "Binne jo wis dat jo al jo meldingen permanint fuortsmite wolle?",
   "notifications.column_settings.admin.report": "Nije rapportaazjes:",
   "notifications.column_settings.admin.sign_up": "Nije registraasjes:",
   "notifications.column_settings.alert": "Desktopmeldingen",
   "notifications.column_settings.favourite": "Favoriten:",
+  "notifications.column_settings.filter_bar.advanced": "Alle kategoryen toane",
   "notifications.column_settings.follow": "Nije folgers:",
   "notifications.column_settings.follow_request": "Nij folchfersyk:",
   "notifications.column_settings.mention": "Fermeldingen:",
diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index 428abb8c5..af28f9ce3 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -9,15 +9,18 @@
   "about.domain_blocks.suspended.explanation": "Nulle datos de iste servitor essera processate, immagazinate o excambiate, rendente omne interaction o communication con usatores de iste servitor impossibile.",
   "about.domain_blocks.suspended.title": "Suspendite",
   "about.not_available": "Iste information non ha essite rendite disponibile sur iste servitor.",
+  "about.powered_by": "Rete social decentralisate, actionate per {mastodon}",
   "about.rules": "Regulas del servitor",
   "account.account_note_header": "Nota",
   "account.add_or_remove_from_list": "Adder a, o remover de listas",
+  "account.badges.bot": "Automatisate",
   "account.badges.group": "Gruppo",
   "account.block": "Blocar @{name}",
   "account.block_domain": "Blocar dominio {domain}",
   "account.block_short": "Blocar",
   "account.blocked": "Blocate",
   "account.browse_more_on_origin_server": "Navigar plus sur le profilo original",
+  "account.cancel_follow_request": "Cancellar sequimento",
   "account.copy": "Copiar ligamine a profilo",
   "account.direct": "Mentionar privatemente @{name}",
   "account.disable_notifications": "Non plus notificar me quando @{name} publica",
@@ -26,7 +29,7 @@
   "account.enable_notifications": "Notificar me quando @{name} publica",
   "account.endorse": "Evidentiar sur le profilo",
   "account.featured_tags.last_status_at": "Ultime message publicate le {date}",
-  "account.featured_tags.last_status_never": "Necun messages",
+  "account.featured_tags.last_status_never": "Necun message",
   "account.featured_tags.title": "Hashtags eminente de {name}",
   "account.follow": "Sequer",
   "account.follow_back": "Sequer in retorno",
@@ -34,9 +37,10 @@
   "account.followers.empty": "Necuno seque ancora iste usator.",
   "account.followers_counter": "{count, plural, one {{counter} sequitor} other {{counter} sequitores}}",
   "account.following": "Sequente",
+  "account.following_counter": "{count, plural, one {{counter} sequite} other {{counter} sequites}}",
   "account.follows.empty": "Iste usator non seque ancora alcuno.",
   "account.go_to_profile": "Vader al profilo",
-  "account.hide_reblogs": "Celar boosts de @{name}",
+  "account.hide_reblogs": "Celar impulsos de @{name}",
   "account.in_memoriam": "In memoriam.",
   "account.languages": "Cambiar le linguas subscribite",
   "account.link_verified_on": "Le proprietate de iste ligamine ha essite verificate le {date}",
@@ -74,9 +78,13 @@
   "alert.unexpected.message": "Un error inexpectate ha occurrite.",
   "announcement.announcement": "Annuncio",
   "audio.hide": "Celar audio",
+  "block_modal.remote_users_caveat": "Nos demandera al servitor {domain} de respectar tu decision. Nonobstante, le conformitate non es garantite perque alcun servitores pote tractar le blocadas de maniera differente. Le messages public pote esser totevia visibile pro le usatores non authenticate.",
   "block_modal.show_less": "Monstrar minus",
   "block_modal.show_more": "Monstrar plus",
+  "block_modal.they_cant_see_posts": "Iste persona non potera vider tu messages e tu non videra le sues.",
   "block_modal.title": "Blocar usator?",
+  "block_modal.you_wont_see_mentions": "Tu non videra le messages que mentiona iste persona.",
+  "boost_modal.combo": "Tu pote premer {combo} pro saltar isto le proxime vice",
   "bundle_column_error.error.title": "Oh, no!",
   "bundle_column_error.network.title": "Error de rete",
   "bundle_column_error.retry": "Tentar novemente",
@@ -98,6 +106,7 @@
   "column.lists": "Listas",
   "column.mutes": "Usatores silentiate",
   "column.notifications": "Notificationes",
+  "column.pins": "Messages fixate",
   "column.public": "Chronologia federate",
   "column_back_button.label": "Retro",
   "column_header.hide_settings": "Celar le parametros",
@@ -113,6 +122,8 @@
   "compose.published.open": "Aperir",
   "compose.saved.body": "Message salvate.",
   "compose_form.direct_message_warning_learn_more": "Apprender plus",
+  "compose_form.encryption_warning": "Le messages sur Mastodon non es cryptate de puncta a puncta. Non condivide alcun information sensibile usante Mastodon.",
+  "compose_form.hashtag_warning": "Iste message non essera listate sub alcun hashtag perque illo non es public. Solmente le messages public pote esser cercate per hashtag.",
   "compose_form.lock_disclaimer": "Tu conto non es {locked}. Quicunque pote sequer te pro vider tu messages solo pro sequitores.",
   "compose_form.lock_disclaimer.lock": "serrate",
   "compose_form.poll.duration": "Durata del sondage",
@@ -142,6 +153,7 @@
   "confirmations.logout.confirm": "Clauder session",
   "confirmations.logout.message": "Es tu secur que tu vole clauder le session?",
   "confirmations.mute.confirm": "Silentiar",
+  "confirmations.redraft.message": "Es tu secur de voler deler iste message e rescriber lo? Le favorites e le impulsos essera perdite, e le responsas al message original essera orphanate.",
   "confirmations.reply.confirm": "Responder",
   "confirmations.unfollow.confirm": "Non plus sequer",
   "confirmations.unfollow.message": "Es tu secur que tu vole cessar de sequer {name}?",
@@ -158,16 +170,24 @@
   "directory.recently_active": "Recentemente active",
   "disabled_account_banner.account_settings": "Parametros de conto",
   "disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.",
+  "dismissable_banner.community_timeline": "Ecce le messages public le plus recente del personas con contos sur {domain}.",
   "dismissable_banner.dismiss": "Dimitter",
+  "dismissable_banner.explore_links": "Istes es le articulos de novas que se condivide le plus sur le rete social hodie. Le articulos de novas le plus recente, publicate per plus personas differente, se classifica plus in alto.",
+  "dismissable_banner.explore_statuses": "Ecce le messages de tote le rete social que gania popularitate hodie. Le messages plus nove con plus impulsos e favorites se classifica plus in alto.",
+  "dismissable_banner.public_timeline": "Istes es le messages public le plus recente del personas sur le rete social que le gente sur {domain} seque.",
   "domain_block_modal.block": "Blocar le servitor",
   "domain_block_modal.block_account_instead": "Blocar @{name} in su loco",
+  "domain_block_modal.they_can_interact_with_old_posts": "Le personas de iste servitor pote interager con tu messages ancian.",
   "domain_block_modal.they_cant_follow": "Nulle persona ab iste servitor pote sequer te.",
   "domain_block_modal.they_wont_know": "Illes non sapera que illes ha essite blocate.",
   "domain_block_modal.title": "Blocar dominio?",
   "domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.",
   "domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes ab usatores sur iste servitor.",
   "domain_pill.server": "Servitor",
+  "domain_pill.their_server": "Su casa digital, ubi vive tote su messages.",
   "domain_pill.username": "Nomine de usator",
+  "domain_pill.your_server": "Tu casa digital, ubi vive tote tu messages. Non te place? Cambia de servitor a omne momento e porta tu sequitores con te.",
+  "embed.instructions": "Incorpora iste message sur tu sito web con le codice sequente.",
   "embed.preview": "Ecce como illlo parera:",
   "emoji_button.activity": "Activitate",
   "emoji_button.clear": "Rader",
@@ -187,11 +207,15 @@
   "empty_column.account_timeline": "Nulle messages hic!",
   "empty_column.account_unavailable": "Profilo non disponibile",
   "empty_column.blocks": "Tu non ha blocate alcun usator ancora.",
+  "empty_column.bookmarked_statuses": "Tu non ha ancora messages in marcapaginas. Quando tu adde un message al marcapaginas, illo apparera hic.",
   "empty_column.domain_blocks": "Il non ha dominios blocate ancora.",
   "empty_column.explore_statuses": "Il non ha tendentias in iste momento. Reveni plus tarde!",
   "empty_column.favourited_statuses": "Tu non ha alcun message favorite ancora. Quando tu marca un message como favorite, illo apparera hic.",
+  "empty_column.favourites": "Necuno ha ancora marcate iste message como favorite. Quando alcuno lo face, ille apparera hic.",
   "empty_column.followed_tags": "Tu non ha ancora sequite alcun hashtags. Quando tu lo face, illos apparera hic.",
   "empty_column.hashtag": "Il non ha ancora alcun cosa in iste hashtag.",
+  "empty_column.home": "Tu chronologia de initio es vacue! Seque plus personas pro plenar lo.",
+  "empty_column.list": "Iste lista es ancora vacue. Quando le membros de iste lista publica nove messages, illos apparera hic.",
   "errors.unexpected_crash.report_issue": "Signalar un defecto",
   "explore.search_results": "Resultatos de recerca",
   "explore.suggested_follows": "Personas",
@@ -199,6 +223,7 @@
   "explore.trending_links": "Novas",
   "explore.trending_statuses": "Messages",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "Iste categoria de filtros non se applica al contexto in le qual tu ha accedite a iste message. Pro filtrar le message in iste contexto tamben, modifica le filtro.",
   "filter_modal.added.review_and_configure_title": "Parametros de filtro",
   "filter_modal.added.settings_link": "pagina de parametros",
   "filter_modal.added.short_explanation": "Iste message ha essite addite al sequente categoria de filtros: {title}.",
@@ -231,6 +256,8 @@
   "hashtag.column_header.tag_mode.none": "sin {additional}",
   "hashtag.column_settings.select.no_options_message": "Nulle suggestiones trovate",
   "hashtag.column_settings.select.placeholder": "Insere hashtags…",
+  "hashtag.counter_by_uses": "{count, plural, one {{counter} message} other {{counter} messages}}",
+  "hashtag.counter_by_uses_today": "{count, plural, one {{counter} message} other {{counter} messages}} hodie",
   "hashtag.follow": "Sequer hashtag",
   "hashtag.unfollow": "Non sequer plus le hashtag",
   "hashtags.and_other": "…e {count, plural, one {}other {# plus}}",
@@ -241,10 +268,16 @@
   "home.pending_critical_update.link": "Vider actualisationes",
   "home.pending_critical_update.title": "Actualisation de securitate critic disponibile!",
   "home.show_announcements": "Monstrar annuncios",
+  "interaction_modal.description.favourite": "Con un conto sur Mastodon, tu pote marcar iste message como favorite pro informar le autor que tu lo apprecia e salveguarda pro plus tarde.",
+  "interaction_modal.description.follow": "Con un conto sur Mastodon, tu pote sequer {name} e reciper su messages in tu fluxo de initio.",
+  "interaction_modal.description.reblog": "Con un conto sur Mastodon, tu pote impulsar iste message pro condivider lo con tu proprie sequitores.",
+  "interaction_modal.description.reply": "Con un conto sur Mastodon, tu pote responder a iste message.",
+  "interaction_modal.login.action": "Porta me a casa",
   "interaction_modal.login.prompt": "Dominio de tu servitor, p.ex. mastodon.social",
   "interaction_modal.no_account_yet": "Non sur Mstodon?",
   "interaction_modal.on_another_server": "Sur un altere servitor",
   "interaction_modal.on_this_server": "Sur iste servitor",
+  "interaction_modal.title.favourite": "Marcar le message de {name} como favorite",
   "interaction_modal.title.follow": "Sequer {name}",
   "interaction_modal.title.reblog": "Impulsar le message de {name}",
   "interaction_modal.title.reply": "Responder al message de {name}",
@@ -264,6 +297,7 @@
   "keyboard_shortcuts.my_profile": "Aperir tu profilo",
   "keyboard_shortcuts.notifications": "Aperir columna de notificationes",
   "keyboard_shortcuts.open_media": "Aperir multimedia",
+  "keyboard_shortcuts.pinned": "Aperir le lista de messages fixate",
   "keyboard_shortcuts.profile": "Aperir le profilo del autor",
   "keyboard_shortcuts.reply": "Responder al message",
   "keyboard_shortcuts.spoilers": "Monstrar/celar le campo CW",
@@ -294,7 +328,8 @@
   "mute_modal.they_can_mention_and_follow": "Illes pote mentionar te e sequer te, ma tu non potera vider los.",
   "mute_modal.they_wont_know": "Illes non sapera que illes ha essite silentiate.",
   "mute_modal.title": "Silentiar le usator?",
-  "mute_modal.you_wont_see_mentions": "Tu non videra messages que los mentiona.",
+  "mute_modal.you_wont_see_mentions": "Tu non videra le messages que mentiona iste persona.",
+  "mute_modal.you_wont_see_posts": "Iste persona pote totevia vider tu messages, ma tu non videra le sues.",
   "navigation_bar.about": "A proposito",
   "navigation_bar.advanced_interface": "Aperir in le interfacie web avantiate",
   "navigation_bar.blocks": "Usatores blocate",
@@ -312,12 +347,16 @@
   "navigation_bar.mutes": "Usatores silentiate",
   "navigation_bar.opened_in_classic_interface": "Messages, contos e altere paginas specific es aperite per predefinition in le interfacie web classic.",
   "navigation_bar.personal": "Personal",
+  "navigation_bar.pins": "Messages fixate",
   "navigation_bar.preferences": "Preferentias",
   "navigation_bar.public_timeline": "Chronologia federate",
   "navigation_bar.search": "Cercar",
   "navigation_bar.security": "Securitate",
+  "notification.favourite": "{name} ha marcate tu message como favorite",
   "notification.own_poll": "Tu sondage ha finite",
+  "notification.reblog": "{name} ha impulsate tu message",
   "notification.relationships_severance_event.learn_more": "Apprender plus",
+  "notification.status": "{name} ha justo ora publicate",
   "notification.update": "{name} ha modificate un message",
   "notification_requests.accept": "Acceptar",
   "notification_requests.dismiss": "Dimitter",
@@ -332,11 +371,13 @@
   "notifications.column_settings.mention": "Mentiones:",
   "notifications.column_settings.poll": "Resultatos del sondage:",
   "notifications.column_settings.push": "Notificationes push",
+  "notifications.column_settings.reblog": "Impulsos:",
   "notifications.column_settings.show": "Monstrar in columna",
   "notifications.column_settings.sound": "Reproducer sono",
   "notifications.column_settings.status": "Nove messages:",
   "notifications.column_settings.unread_notifications.category": "Notificationes non legite",
   "notifications.filter.all": "Toto",
+  "notifications.filter.boosts": "Impulsos",
   "notifications.filter.favourites": "Favoritos",
   "notifications.filter.mentions": "Mentiones",
   "notifications.filter.polls": "Resultatos del sondage",
@@ -346,38 +387,52 @@
   "notifications.mark_as_read": "Marcar cata notification como legite",
   "notifications.policy.filter_new_accounts_title": "Nove contos",
   "notifications_permission_banner.enable": "Activar notificationes de scriptorio",
+  "onboarding.actions.go_to_home": "Porta me a mi fluxo de initio",
   "onboarding.compose.template": "Salute #Mastodon!",
+  "onboarding.follows.lead": "Le fluxo de initio es le maniera principal de discoperir Mastodon. Quanto plus personas tu seque, tanto plus active e interessante illo essera. Pro comenciar, ecce alcun suggestiones:",
+  "onboarding.follows.title": "Personalisar tu fluxo de initio",
+  "onboarding.profile.discoverable_hint": "Quando tu opta pro devenir discoperibile sur Mastodon, tu messages pote apparer in resultatos de recerca e in tendentias, e tu profilo pote esser suggerite al personas con interesses simile al tues.",
   "onboarding.profile.save_and_continue": "Salvar e continuar",
   "onboarding.share.next_steps": "Sequente passos possibile:",
   "onboarding.share.title": "Compartir tu profilo",
-  "onboarding.steps.follow_people.title": "Personalisa tu fluxo de initio",
+  "onboarding.steps.follow_people.title": "Personalisar tu fluxo de initio",
   "onboarding.steps.publish_status.title": "Face tu prime message",
+  "onboarding.steps.setup_profile.body": "Impulsa tu interactiones con un profilo comprehensive.",
   "onboarding.steps.setup_profile.title": "Personalisa tu profilo",
   "onboarding.steps.share_profile.title": "Compartir tu profilo de Mastodon",
   "poll.closed": "Claudite",
   "poll.reveal": "Vider le resultatos",
   "privacy.change": "Cambiar le confidentialitate del message",
+  "privacy.direct.long": "Tote le personas mentionate in le message",
   "privacy.public.short": "Public",
+  "privacy.unlisted.additional": "Isto es exactemente como public, excepte que le message non apparera in fluxos in directo, in hashtags, in Explorar, o in le recerca de Mastodon, mesmo si tu ha optate pro render tote le conto discoperibile.",
   "privacy_policy.last_updated": "Ultime actualisation {date}",
   "privacy_policy.title": "Politica de confidentialitate",
+  "regeneration_indicator.sublabel": "Tu fluxo de initio es in preparation!",
   "relative_time.just_now": "ora",
   "relative_time.today": "hodie",
   "reply_indicator.cancel": "Cancellar",
   "report.block": "Blocar",
+  "report.block_explanation": "Tu non videra le messages de iste persona. Ille non potera vider tu messages o sequer te. Ille potera saper de esser blocate.",
   "report.categories.other": "Alteres",
   "report.category.title_account": "profilo",
   "report.category.title_status": "message",
   "report.close": "Facite",
   "report.mute": "Silentiar",
+  "report.mute_explanation": "Tu non videra le messages de iste persona. Ille pote totevia sequer te e vider tu messages e non sapera de esser silentiate.",
   "report.next": "Sequente",
   "report.placeholder": "Commentos additional",
   "report.reasons.dislike": "Non me place",
+  "report.statuses.title": "Existe alcun messages que appoia iste reporto?",
+  "report.unfollow_explanation": "Tu seque iste conto. Pro non plus vider su messages in tu fluxo de initio, cessa de sequer lo.",
+  "report_notification.attached_statuses": "{count, plural, one {{count} message} other {{count} messages}} annexate",
   "report_notification.categories.other": "Alteres",
   "report_notification.open": "Aperir reporto",
   "search.no_recent_searches": "Nulle recercas recente",
   "search.quick_action.go_to_account": "Vader al profilo {x}",
   "search.quick_action.go_to_hashtag": "Vader al hashtag {x}",
   "search.quick_action.open_url": "Aperir URL in Mastodon",
+  "search.quick_action.status_search": "Messages correspondente a {x}",
   "search_popout.full_text_search_disabled_message": "Non disponibile sur {domain}.",
   "search_popout.language_code": "Codice de lingua ISO",
   "search_popout.options": "Optiones de recerca",
@@ -393,7 +448,11 @@
   "server_banner.server_stats": "Statos del servitor:",
   "sign_in_banner.create_account": "Crear un conto",
   "sign_in_banner.sign_in": "Aperir session",
+  "sign_in_banner.text": "Aperi session pro sequer profilos o hashtags, marcar messages como favorite, e condivider e responder a messages. Tu pote etiam interager desde tu conto sur un altere servitor.",
+  "status.admin_status": "Aperir iste message in le interfacie de moderation",
   "status.block": "Blocar @{name}",
+  "status.cancel_reblog_private": "Disfacer impulso",
+  "status.cannot_reblog": "Iste message non pote esser impulsate",
   "status.copy": "Copiar ligamine a message",
   "status.delete": "Deler",
   "status.direct": "Mentionar privatemente @{name}",
@@ -409,7 +468,13 @@
   "status.media.show": "Clicca pro monstrar",
   "status.more": "Plus",
   "status.mute_conversation": "Silentiar conversation",
+  "status.open": "Expander iste message",
+  "status.pinned": "Message fixate",
   "status.read_more": "Leger plus",
+  "status.reblog": "Impulsar",
+  "status.reblog_private": "Impulsar con visibilitate original",
+  "status.reblogged_by": "Impulsate per {name}",
+  "status.reblogs": "{count, plural, one {impulso} other {impulsos}}",
   "status.reblogs.empty": "Necuno ha ancora impulsate iste message. Quando alcuno lo face, le impulsos apparera hic.",
   "status.redraft": "Deler e reconciper",
   "status.remove_bookmark": "Remover marcapagina",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 23960e9f8..1025c3204 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -225,8 +225,8 @@
   "domain_pill.their_username": "Hun unieke identificatie-adres op hun server. Het is mogelijk dat er gebruikers met dezelfde gebruikersnaam op verschillende servers te vinden zijn.",
   "domain_pill.username": "Gebruikersnaam",
   "domain_pill.whats_in_a_handle": "Wat is een fediverse-adres?",
-  "domain_pill.who_they_are": "Omdat je aan een fediverse-adres kunt zien wie iemand is en waar die zich bevindt, kun je met mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) communiceren.",
-  "domain_pill.who_you_are": "Omdat je aan jouw fediverse-adres kunt zien wie jij bent is en waar je je bevindt, kunnen mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) met jou communiceren.",
+  "domain_pill.who_they_are": "Omdat je aan een fediverse-adres kunt zien hoe iemand heet en op welke server die zich bevindt, kun je met mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) communiceren.",
+  "domain_pill.who_you_are": "Omdat je aan jouw fediverse-adres kunt zien hoe je heet en op welke server je je bevindt, kunnen mensen op het door <button>ActivityPub aangedreven</button> sociale web (fediverse) met jou communiceren.",
   "domain_pill.your_handle": "Jouw fediverse-adres:",
   "domain_pill.your_server": "Jouw digitale thuis, waar al jouw berichten zich bevinden. Is deze server toch niet naar jouw wens? Dan kun je op elk moment naar een andere server verhuizen en ook jouw volgers overbrengen.",
   "domain_pill.your_username": "Jouw unieke identificatie-adres op deze server. Het is mogelijk dat er gebruikers met dezelfde gebruikersnaam op verschillende servers te vinden zijn.",
diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json
index c3f184e15..80d412a20 100644
--- a/app/javascript/mastodon/locales/tok.json
+++ b/app/javascript/mastodon/locales/tok.json
@@ -36,6 +36,7 @@
   "account.go_to_profile": "o tawa lipu jan",
   "account.hide_reblogs": "o lukin ala e pana toki tan @{name}",
   "account.in_memoriam": "jan ni li moli. pona o tawa ona.",
+  "account.joined_short": "li kama",
   "account.languages": "sina wile lukin e sitelen pi toki seme",
   "account.locked_info": "sina wile kute e jan ni la ona o toki e ken",
   "account.media": "sitelen",
@@ -70,6 +71,10 @@
   "alert.unexpected.title": "pakala a!",
   "announcement.announcement": "toki suli",
   "audio.hide": "o len e kalama",
+  "block_modal.show_less": "o lili e lukin",
+  "block_modal.show_more": "o mute e lukin",
+  "block_modal.they_cant_mention": "ona li ken ala toki e sina li ken ala alasa e sina",
+  "block_modal.title": "o weka ala weka e jan",
   "boost_modal.combo": "sina ken luka e nena {combo} tawa ni: sina wile ala luka e nena lon tenpo kama",
   "bundle_column_error.copy_stacktrace": "o awen e sona pakala lon ilo sina",
   "bundle_column_error.error.body": "ilo li ken ala pana e lipu ni. ni li ken tan pakala ilo.",
@@ -86,10 +91,15 @@
   "column.about": "sona",
   "column.blocks": "kulupu pi jan weka",
   "column.bookmarks": "awen toki",
+  "column.community": "linja tenpo pi ma ni",
+  "column.favourites": "ijo pona",
+  "column.firehose": "toki pi tenpo ni",
+  "column.follow_requests": "wile alasa pi jan ante",
   "column.home": "lipu open",
   "column.lists": "kulupu lipu",
   "column.mutes": "jan len",
   "column.pins": "toki sewi",
+  "column_back_button.label": "o tawa monsi",
   "column_header.hide_settings": "o len e lawa",
   "column_header.pin": "o sewi",
   "column_header.show_settings": "o lukin e lawa",
@@ -157,6 +167,9 @@
   "dismissable_banner.explore_statuses": "suni ni la jan mute li lukin e toki ni. jan mute li wawa e toki li suli e toki la toki ni li lon sewi. toki li sin la toki ni li lon sewi.",
   "dismissable_banner.explore_tags": "suni ni la jan mute li lukin e toki pi toki ni. jan mute li kepeken toki la toki ni li lon sewi.",
   "dismissable_banner.public_timeline": "toki ni li sin. jan li pali e toki ni la jan ante mute pi ma {domain} li kute e jan ni.",
+  "domain_block_modal.block": "o weka e ma",
+  "domain_block_modal.you_will_lose_followers": "ma ni la jan alasa ale sina li weka",
+  "domain_block_modal.you_wont_see_posts": "sina ken ala lukin e toki tan jan pi ma ni",
   "embed.preview": "ni li jo e sitelen ni:",
   "emoji_button.activity": "musi",
   "emoji_button.flags": "len ma",
@@ -232,7 +245,7 @@
   "keyboard_shortcuts.boost": "o pana sin e toki",
   "keyboard_shortcuts.down": "o tawa anpa lon lipu",
   "keyboard_shortcuts.enter": "o lukin e toki",
-  "keyboard_shortcuts.favourite": "o suli e toki",
+  "keyboard_shortcuts.favourite": "o sitelen pona e toki",
   "keyboard_shortcuts.favourites": "o lukin e lipu sina pi toki suli",
   "keyboard_shortcuts.muted": "o lukin e lipu sina pi jan len",
   "keyboard_shortcuts.my_profile": "o lukin e lipu sina",
@@ -264,7 +277,7 @@
   "navigation_bar.about": "sona",
   "navigation_bar.blocks": "jan weka",
   "navigation_bar.compose": "o pali e toki sin",
-  "navigation_bar.favourites": "toki suli",
+  "navigation_bar.favourites": "ijo pona",
   "navigation_bar.filters": "nimi len",
   "navigation_bar.lists": "kulupu lipu",
   "navigation_bar.mutes": "sina wile ala kute e jan ni",
@@ -273,7 +286,7 @@
   "navigation_bar.search": "o alasa",
   "notification.admin.report": "jan {name} li toki e jan {target} tawa lawa",
   "notification.admin.sign_up": "{name} li kama",
-  "notification.favourite": "{name} li suli e toki sina",
+  "notification.favourite": "toki sina li pona tawa {name}",
   "notification.follow": " {name} li kute e sina",
   "notification.follow_request": "{name} li wile kute e sina",
   "notification.mention": "jan {name} li toki e sina",
@@ -281,11 +294,13 @@
   "notification.reblog": "{name} li wawa e toki sina",
   "notification.status": "{name} li toki",
   "notification.update": "{name} li ante e toki",
+  "notifications.column_settings.favourite": "ijo pona:",
   "notifications.column_settings.follow": "jan kute sin",
   "notifications.column_settings.poll": "pana lon pana ni:",
   "notifications.column_settings.reblog": "wawa:",
   "notifications.column_settings.update": "ante toki:",
   "notifications.filter.all": "ale",
+  "notifications.filter.favourites": "ijo pona",
   "notifications.filter.polls": "pana lon pana ni",
   "onboarding.compose.template": "toki a, #Mastodon o!",
   "onboarding.profile.display_name": "nimi tawa jan ante",
@@ -333,7 +348,7 @@
   "status.delete": "o weka",
   "status.edit": "o ante",
   "status.embed": "ni o lon insa pi lipu ante",
-  "status.favourite": "o suli",
+  "status.favourite": "o sitelen pona",
   "status.hide": "o len",
   "status.history.created": "{name} li pali e ni lon {date}",
   "status.history.edited": "{name} li ante lon {date}",
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 22710265f..67aad1587 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -615,7 +615,7 @@ de:
       created_at: Gemeldet
       delete_and_resolve: Beiträge löschen
       forwarded: Weitergeleitet
-      forwarded_replies_explanation: Diese Meldung stammt von einem externen Profil und betrifft einen externen Inhalt. Der Inhalt wurde an Dich weitergeleitet, weil er eine Antwort auf ein bei Dir registriertes Profil ist.
+      forwarded_replies_explanation: Diese Meldung stammt von einem externen Profil und betrifft einen externen Inhalt. Der Inhalt wurde an dich weitergeleitet, weil er eine Antwort auf ein bei dir registriertes Profil ist.
       forwarded_to: Weitergeleitet an %{domain}
       mark_as_resolved: Als geklärt markieren
       mark_as_sensitive: Mit einer Inhaltswarnung versehen

From 6ee1b034b649d0089596d8162902dc9699dd5f75 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 16 Apr 2024 10:45:20 +0200
Subject: [PATCH 152/173] Update dependency prom-client to v15.1.2 (#29957)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index 7504e3d93..0ee399a9d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14012,12 +14012,12 @@ __metadata:
   linkType: hard
 
 "prom-client@npm:^15.0.0":
-  version: 15.1.1
-  resolution: "prom-client@npm:15.1.1"
+  version: 15.1.2
+  resolution: "prom-client@npm:15.1.2"
   dependencies:
     "@opentelemetry/api": "npm:^1.4.0"
     tdigest: "npm:^0.1.1"
-  checksum: 10c0/b3e6a58fc0ef87cf5b0badf06d7d79c24ac93ba47cccfaad95faeba79824c6a7724d74a257e7268d691245c847173818c16c8153054cccf16b8f033c37c74129
+  checksum: 10c0/a221db148fa64e29dfd4c6cdcaaae14635495a4272b68917e2b44fcfd988bc57027d275b04489ceeea4d0c4d64d058af842c1300966d2c1ffa255f1fa6af1277
   languageName: node
   linkType: hard
 

From e6927db2fe167202d234e029cadaeca1b0b17899 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 16 Apr 2024 10:58:04 +0200
Subject: [PATCH 153/173] Update dependency rubocop to v1.63.2 (#29959)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 9df16248c..9c0adce16 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -646,7 +646,7 @@ GEM
       rspec-mocks (~> 3.0)
       sidekiq (>= 5, < 8)
     rspec-support (3.13.1)
-    rubocop (1.63.1)
+    rubocop (1.63.2)
       json (~> 2.3)
       language_server-protocol (>= 3.17.0)
       parallel (~> 1.10)

From 3159c0a54784f808f90a549a87b6440fee03a412 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 16 Apr 2024 05:17:03 -0400
Subject: [PATCH 154/173] Add scope `Status.list_eligible_visibility` (#29951)

---
 app/lib/feed_manager.rb | 6 +++---
 app/models/status.rb    | 1 +
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 9ddc54c16..95a687fa4 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -109,7 +109,7 @@ class FeedManager
   def merge_into_home(from_account, into_account)
     timeline_key = key(:home, into_account.id)
     aggregate    = into_account.user&.aggregates_reblogs?
-    query        = from_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
+    query        = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
 
     if redis.zcard(timeline_key) >= FeedManager::MAX_ITEMS / 4
       oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i
@@ -135,7 +135,7 @@ class FeedManager
   def merge_into_list(from_account, list)
     timeline_key = key(:list, list.id)
     aggregate    = list.account.user&.aggregates_reblogs?
-    query        = from_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
+    query        = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
 
     if redis.zcard(timeline_key) >= FeedManager::MAX_ITEMS / 4
       oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i
@@ -274,7 +274,7 @@ class FeedManager
         next if last_status_score < oldest_home_score
       end
 
-      statuses = target_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, :account, reblog: :account).limit(limit)
+      statuses = target_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, :account, reblog: :account).limit(limit)
       crutches = build_crutches(account.id, statuses)
 
       statuses.each do |status|
diff --git a/app/models/status.rb b/app/models/status.rb
index 78186623c..8ab78d09d 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -121,6 +121,7 @@ class Status < ApplicationRecord
   scope :tagged_with_none, lambda { |tag_ids|
     where('NOT EXISTS (SELECT * FROM statuses_tags forbidden WHERE forbidden.status_id = statuses.id AND forbidden.tag_id IN (?))', tag_ids)
   }
+  scope :list_eligible_visibility, -> { where(visibility: %i(public unlisted private)) }
 
   after_create_commit :trigger_create_webhooks
   after_update_commit :trigger_update_webhooks

From 66ee0d4a1f35ce4455418921879b8d2f96538d57 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 16 Apr 2024 11:25:23 +0200
Subject: [PATCH 155/173] Fix incorrect label for filtered notifications badge
 (#29922)

---
 .../notifications/components/filtered_notifications_banner.jsx  | 2 +-
 app/javascript/mastodon/locales/en.json                         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
index f9b8c0be1..56da7ba62 100644
--- a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
+++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx
@@ -42,7 +42,7 @@ export const FilteredNotificationsBanner = () => {
 
       <div className='filtered-notifications-banner__badge'>
         <div className='filtered-notifications-banner__badge__badge'>{toCappedNumber(policy.getIn(['summary', 'pending_notifications_count']))}</div>
-        <FormattedMessage id='filtered_notifications_banner.private_mentions' defaultMessage='{count, plural, one {private mention} other {private mentions}}' values={{ count: policy.getIn(['summary', 'pending_notifications_count']) }} />
+        <FormattedMessage id='filtered_notifications_banner.mentions' defaultMessage='{count, plural, one {mention} other {mentions}}' values={{ count: policy.getIn(['summary', 'pending_notifications_count']) }} />
       </div>
     </Link>
   );
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 881ed19e0..fd44b3952 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
   "filter_modal.select_filter.title": "Filter this post",
   "filter_modal.title.status": "Filter a post",
+  "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}",
   "filtered_notifications_banner.pending_requests": "Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {private mention} other {private mentions}}",
   "filtered_notifications_banner.title": "Filtered notifications",
   "firehose.all": "All",
   "firehose.local": "This server",

From 6b33d3f81be36b772c0f0436c14a7a742062e2de Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 16 Apr 2024 05:29:34 -0400
Subject: [PATCH 156/173] Add `CustomFilter.unexpired` scope (#29896)

---
 app/models/custom_filter.rb | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb
index 7c148e877..2d8f5b6cb 100644
--- a/app/models/custom_filter.rb
+++ b/app/models/custom_filter.rb
@@ -42,6 +42,7 @@ class CustomFilter < ApplicationRecord
   validate :context_must_be_valid
 
   normalizes :context, with: ->(context) { context.map(&:strip).filter_map(&:presence) }
+  scope :unexpired, -> { where(expires_at: nil).or where.not(expires_at: ..Time.zone.now) }
 
   before_save :prepare_cache_invalidation!
   before_destroy :prepare_cache_invalidation!
@@ -66,14 +67,16 @@ class CustomFilter < ApplicationRecord
     active_filters = Rails.cache.fetch("filters:v3:#{account_id}") do
       filters_hash = {}
 
-      scope = CustomFilterKeyword.includes(:custom_filter).where(custom_filter: { account_id: account_id }).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()'))
+      scope = CustomFilterKeyword.left_outer_joins(:custom_filter).merge(unexpired.where(account_id: account_id))
+
       scope.to_a.group_by(&:custom_filter).each do |filter, keywords|
         keywords.map!(&:to_regex)
 
         filters_hash[filter.id] = { keywords: Regexp.union(keywords), filter: filter }
       end.to_h
 
-      scope = CustomFilterStatus.includes(:custom_filter).where(custom_filter: { account_id: account_id }).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()'))
+      scope = CustomFilterStatus.left_outer_joins(:custom_filter).merge(unexpired.where(account_id: account_id))
+
       scope.to_a.group_by(&:custom_filter).each do |filter, statuses|
         filters_hash[filter.id] ||= { filter: filter }
         filters_hash[filter.id].merge!(status_ids: statuses.map(&:status_id))

From 0622107449e72d35b22afeeba2f0ba983e914803 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 16 Apr 2024 11:44:02 +0200
Subject: [PATCH 157/173] Update dependency @testing-library/react to v15
 (#29893)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 package.json |   2 +-
 yarn.lock    | 101 ++++++++++-----------------------------------------
 2 files changed, 21 insertions(+), 82 deletions(-)

diff --git a/package.json b/package.json
index ed59a68a4..787ca3600 100644
--- a/package.json
+++ b/package.json
@@ -139,7 +139,7 @@
   "devDependencies": {
     "@formatjs/cli": "^6.1.1",
     "@testing-library/jest-dom": "^6.0.0",
-    "@testing-library/react": "^14.0.0",
+    "@testing-library/react": "^15.0.0",
     "@types/babel__core": "^7.20.1",
     "@types/emoji-mart": "^3.0.9",
     "@types/escape-html": "^1.0.2",
diff --git a/yarn.lock b/yarn.lock
index 0ee399a9d..af17402bc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2738,7 +2738,7 @@ __metadata:
     "@reduxjs/toolkit": "npm:^2.0.1"
     "@svgr/webpack": "npm:^5.5.0"
     "@testing-library/jest-dom": "npm:^6.0.0"
-    "@testing-library/react": "npm:^14.0.0"
+    "@testing-library/react": "npm:^15.0.0"
     "@types/babel__core": "npm:^7.20.1"
     "@types/emoji-mart": "npm:^3.0.9"
     "@types/escape-html": "npm:^1.0.2"
@@ -3281,19 +3281,19 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@testing-library/dom@npm:^9.0.0":
-  version: 9.3.1
-  resolution: "@testing-library/dom@npm:9.3.1"
+"@testing-library/dom@npm:^10.0.0":
+  version: 10.0.0
+  resolution: "@testing-library/dom@npm:10.0.0"
   dependencies:
     "@babel/code-frame": "npm:^7.10.4"
     "@babel/runtime": "npm:^7.12.5"
     "@types/aria-query": "npm:^5.0.1"
-    aria-query: "npm:5.1.3"
+    aria-query: "npm:5.3.0"
     chalk: "npm:^4.1.0"
     dom-accessibility-api: "npm:^0.5.9"
     lz-string: "npm:^1.5.0"
     pretty-format: "npm:^27.0.2"
-  checksum: 10c0/25d1deddba014c107fd9703181fbb7063ed376d3ad42d7918ee752e7e677edfb5abaf672b22afc5257ffe760c9c7e5cc981656297c328bc61578d23c6b65b4dc
+  checksum: 10c0/2d12d2a6018a6f1d15e91834180bc068932c699ff1fcbfb80aa21aba519a4f5329c861dfa852e06ee5615bcb92ef2a0f0e755e32684ea3dada63bc34248382ab
   languageName: node
   linkType: hard
 
@@ -3330,17 +3330,17 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@testing-library/react@npm:^14.0.0":
-  version: 14.3.1
-  resolution: "@testing-library/react@npm:14.3.1"
+"@testing-library/react@npm:^15.0.0":
+  version: 15.0.2
+  resolution: "@testing-library/react@npm:15.0.2"
   dependencies:
     "@babel/runtime": "npm:^7.12.5"
-    "@testing-library/dom": "npm:^9.0.0"
+    "@testing-library/dom": "npm:^10.0.0"
     "@types/react-dom": "npm:^18.0.0"
   peerDependencies:
     react: ^18.0.0
     react-dom: ^18.0.0
-  checksum: 10c0/1ccf4eb1510500cc20a805cb0244c9098dca28a8745173a8f71ea1274d63774f0b7898a35c878b43c797b89c13621548909ff37843b835c1a27ee1efbbdd098c
+  checksum: 10c0/8d75e4850f8f749244bf4f30b0f99a5d4aa1156ee5a59eea0772f47971c38535d1fb31d021c4f0f0b816346ae664870dc223d5d997ab399dfb1b6211f0e2acf1
   languageName: node
   linkType: hard
 
@@ -4712,16 +4712,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"aria-query@npm:5.1.3":
-  version: 5.1.3
-  resolution: "aria-query@npm:5.1.3"
-  dependencies:
-    deep-equal: "npm:^2.0.5"
-  checksum: 10c0/edcbc8044c4663d6f88f785e983e6784f98cb62b4ba1e9dd8d61b725d0203e4cfca38d676aee984c31f354103461102a3d583aa4fbe4fd0a89b679744f4e5faf
-  languageName: node
-  linkType: hard
-
-"aria-query@npm:^5.0.0, aria-query@npm:^5.3.0":
+"aria-query@npm:5.3.0, aria-query@npm:^5.0.0, aria-query@npm:^5.3.0":
   version: 5.3.0
   resolution: "aria-query@npm:5.3.0"
   dependencies:
@@ -4751,7 +4742,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1":
+"array-buffer-byte-length@npm:^1.0.1":
   version: 1.0.1
   resolution: "array-buffer-byte-length@npm:1.0.1"
   dependencies:
@@ -6905,32 +6896,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"deep-equal@npm:^2.0.5":
-  version: 2.2.1
-  resolution: "deep-equal@npm:2.2.1"
-  dependencies:
-    array-buffer-byte-length: "npm:^1.0.0"
-    call-bind: "npm:^1.0.2"
-    es-get-iterator: "npm:^1.1.3"
-    get-intrinsic: "npm:^1.2.0"
-    is-arguments: "npm:^1.1.1"
-    is-array-buffer: "npm:^3.0.2"
-    is-date-object: "npm:^1.0.5"
-    is-regex: "npm:^1.1.4"
-    is-shared-array-buffer: "npm:^1.0.2"
-    isarray: "npm:^2.0.5"
-    object-is: "npm:^1.1.5"
-    object-keys: "npm:^1.1.1"
-    object.assign: "npm:^4.1.4"
-    regexp.prototype.flags: "npm:^1.5.0"
-    side-channel: "npm:^1.0.4"
-    which-boxed-primitive: "npm:^1.0.2"
-    which-collection: "npm:^1.0.1"
-    which-typed-array: "npm:^1.1.9"
-  checksum: 10c0/9e32606f0e24ef4d6b100c68cadae81495c3638944e933afc4b8389b042e95c5fe1381492cf7a6d385bcbae564c9cfb7086f37f277e37521a632b008a6b208dc
-  languageName: node
-  linkType: hard
-
 "deep-is@npm:^0.1.3":
   version: 0.1.4
   resolution: "deep-is@npm:0.1.4"
@@ -7585,23 +7550,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"es-get-iterator@npm:^1.1.3":
-  version: 1.1.3
-  resolution: "es-get-iterator@npm:1.1.3"
-  dependencies:
-    call-bind: "npm:^1.0.2"
-    get-intrinsic: "npm:^1.1.3"
-    has-symbols: "npm:^1.0.3"
-    is-arguments: "npm:^1.1.1"
-    is-map: "npm:^2.0.2"
-    is-set: "npm:^2.0.2"
-    is-string: "npm:^1.0.7"
-    isarray: "npm:^2.0.5"
-    stop-iteration-iterator: "npm:^1.0.0"
-  checksum: 10c0/ebd11effa79851ea75d7f079405f9d0dc185559fd65d986c6afea59a0ff2d46c2ed8675f19f03dce7429d7f6c14ff9aede8d121fbab78d75cfda6a263030bac0
-  languageName: node
-  linkType: hard
-
 "es-iterator-helpers@npm:^1.0.15, es-iterator-helpers@npm:^1.0.17":
   version: 1.0.17
   resolution: "es-iterator-helpers@npm:1.0.17"
@@ -8755,7 +8703,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4":
+"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4":
   version: 1.2.4
   resolution: "get-intrinsic@npm:1.2.4"
   dependencies:
@@ -9594,7 +9542,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5, internal-slot@npm:^1.0.7":
+"internal-slot@npm:^1.0.5, internal-slot@npm:^1.0.7":
   version: 1.0.7
   resolution: "internal-slot@npm:1.0.7"
   dependencies:
@@ -9710,7 +9658,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.1":
+"is-arguments@npm:^1.0.4":
   version: 1.1.1
   resolution: "is-arguments@npm:1.1.1"
   dependencies:
@@ -9720,7 +9668,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4":
+"is-array-buffer@npm:^3.0.4":
   version: 3.0.4
   resolution: "is-array-buffer@npm:3.0.4"
   dependencies:
@@ -9967,7 +9915,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"is-map@npm:^2.0.1, is-map@npm:^2.0.2":
+"is-map@npm:^2.0.1":
   version: 2.0.2
   resolution: "is-map@npm:2.0.2"
   checksum: 10c0/119ff9137a37fd131a72fab3f4ab8c9d6a24b0a1ee26b4eff14dc625900d8675a97785eea5f4174265e2006ed076cc24e89f6e57ebd080a48338d914ec9168a5
@@ -10092,7 +10040,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"is-set@npm:^2.0.1, is-set@npm:^2.0.2":
+"is-set@npm:^2.0.1":
   version: 2.0.2
   resolution: "is-set@npm:2.0.2"
   checksum: 10c0/5f8bd1880df8c0004ce694e315e6e1e47a3452014be792880bb274a3b2cdb952fdb60789636ca6e084c7947ca8b7ae03ccaf54c93a7fcfed228af810559e5432
@@ -12288,7 +12236,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"object-is@npm:^1.0.1, object-is@npm:^1.1.5":
+"object-is@npm:^1.0.1":
   version: 1.1.5
   resolution: "object-is@npm:1.1.5"
   dependencies:
@@ -16075,15 +16023,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"stop-iteration-iterator@npm:^1.0.0":
-  version: 1.0.0
-  resolution: "stop-iteration-iterator@npm:1.0.0"
-  dependencies:
-    internal-slot: "npm:^1.0.4"
-  checksum: 10c0/c4158d6188aac510d9e92925b58709207bd94699e9c31186a040c80932a687f84a51356b5895e6dc72710aad83addb9411c22171832c9ae0e6e11b7d61b0dfb9
-  languageName: node
-  linkType: hard
-
 "stream-browserify@npm:^2.0.1":
   version: 2.0.2
   resolution: "stream-browserify@npm:2.0.2"

From caad1e2628c78d2dfcd86e3a79b0849dc89baf16 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 16 Apr 2024 09:16:54 -0400
Subject: [PATCH 158/173] Add scope `Status.distributable_visibility` (#29950)

---
 app/controllers/accounts_controller.rb                          | 2 +-
 app/controllers/activitypub/replies_controller.rb               | 2 +-
 .../api/v1/statuses/reblogged_by_accounts_controller.rb         | 2 +-
 app/lib/account_statuses_filter.rb                              | 2 +-
 app/models/admin/status_filter.rb                               | 2 +-
 app/models/announcement.rb                                      | 2 +-
 app/models/concerns/status/threading_concern.rb                 | 2 +-
 app/models/featured_tag.rb                                      | 2 +-
 app/models/status.rb                                            | 1 +
 9 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 4e475fe78..32549e151 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -46,7 +46,7 @@ class AccountsController < ApplicationController
   end
 
   def default_statuses
-    @account.statuses.where(visibility: [:public, :unlisted])
+    @account.statuses.distributable_visibility
   end
 
   def only_media_scope
diff --git a/app/controllers/activitypub/replies_controller.rb b/app/controllers/activitypub/replies_controller.rb
index 3f43e89a5..11aac48c9 100644
--- a/app/controllers/activitypub/replies_controller.rb
+++ b/app/controllers/activitypub/replies_controller.rb
@@ -31,7 +31,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
 
   def set_replies
     @replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
-    @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
+    @replies = @replies.distributable_visibility.where(in_reply_to_id: @status.id)
     @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
   end
 
diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
index eaa5ef725..bac96b032 100644
--- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
@@ -23,7 +23,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::Base
   end
 
   def paginated_statuses
-    Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id(
+    Status.where(reblog_of_id: @status.id).distributable_visibility.paginate_by_max_id(
       limit_param(DEFAULT_ACCOUNTS_LIMIT),
       params[:max_id],
       params[:since_id]
diff --git a/app/lib/account_statuses_filter.rb b/app/lib/account_statuses_filter.rb
index eb7592cdc..cfc9be966 100644
--- a/app/lib/account_statuses_filter.rb
+++ b/app/lib/account_statuses_filter.rb
@@ -35,7 +35,7 @@ class AccountStatusesFilter
     return Status.none if account.unavailable?
 
     if anonymous?
-      account.statuses.where(visibility: %i(public unlisted))
+      account.statuses.distributable_visibility
     elsif author?
       account.statuses.all # NOTE: #merge! does not work without the #all
     elsif blocked?
diff --git a/app/models/admin/status_filter.rb b/app/models/admin/status_filter.rb
index 4708785e7..8d20e4f6a 100644
--- a/app/models/admin/status_filter.rb
+++ b/app/models/admin/status_filter.rb
@@ -16,7 +16,7 @@ class Admin::StatusFilter
   end
 
   def results
-    scope = @account.statuses.where(visibility: [:public, :unlisted])
+    scope = @account.statuses.distributable_visibility
 
     params.each do |key, value|
       next if IGNORED_PARAMS.include?(key.to_s)
diff --git a/app/models/announcement.rb b/app/models/announcement.rb
index e63057002..5ce382dc1 100644
--- a/app/models/announcement.rb
+++ b/app/models/announcement.rb
@@ -62,7 +62,7 @@ class Announcement < ApplicationRecord
     @statuses ||= if status_ids.nil?
                     []
                   else
-                    Status.where(id: status_ids, visibility: [:public, :unlisted])
+                    Status.where(id: status_ids).distributable_visibility
                   end
   end
 
diff --git a/app/models/concerns/status/threading_concern.rb b/app/models/concerns/status/threading_concern.rb
index 2606fd2f2..ca8c44814 100644
--- a/app/models/concerns/status/threading_concern.rb
+++ b/app/models/concerns/status/threading_concern.rb
@@ -12,7 +12,7 @@ module Status::ThreadingConcern
   end
 
   def self_replies(limit)
-    account.statuses.where(in_reply_to_id: id, visibility: [:public, :unlisted]).reorder(id: :asc).limit(limit)
+    account.statuses.distributable_visibility.where(in_reply_to_id: id).reorder(id: :asc).limit(limit)
   end
 
   private
diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb
index ea8aa4787..cdd97205e 100644
--- a/app/models/featured_tag.rb
+++ b/app/models/featured_tag.rb
@@ -74,6 +74,6 @@ class FeaturedTag < ApplicationRecord
   end
 
   def visible_tagged_account_statuses
-    account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag)
+    account.statuses.distributable_visibility.tagged_with(tag)
   end
 end
diff --git a/app/models/status.rb b/app/models/status.rb
index 8ab78d09d..c2d7985b4 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -121,6 +121,7 @@ class Status < ApplicationRecord
   scope :tagged_with_none, lambda { |tag_ids|
     where('NOT EXISTS (SELECT * FROM statuses_tags forbidden WHERE forbidden.status_id = statuses.id AND forbidden.tag_id IN (?))', tag_ids)
   }
+  scope :distributable_visibility, -> { where(visibility: %i(public unlisted)) }
   scope :list_eligible_visibility, -> { where(visibility: %i(public unlisted private)) }
 
   after_create_commit :trigger_create_webhooks

From 5915bd7f455aeffd539536f40c09810c8b1c3177 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 16 Apr 2024 19:30:32 +0200
Subject: [PATCH 159/173] Fix development environment admin account not being
 auto-approved (#29958)

---
 db/seeds/04_admin.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/db/seeds/04_admin.rb b/db/seeds/04_admin.rb
index c9b0369c9..887b4a221 100644
--- a/db/seeds/04_admin.rb
+++ b/db/seeds/04_admin.rb
@@ -7,5 +7,7 @@ if Rails.env.development?
   admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
   admin.save(validate: false)
 
-  User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true).save!
+  user = User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true)
+  user.save!
+  user.approve!
 end

From 6fed108703c88d5c8e44658cc7fec82dde53454c Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 04:16:51 -0400
Subject: [PATCH 160/173] Use Rails `upsert` to generate update_count! query in
 Counters concern (#28738)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 app/models/concerns/account/counters.rb       | 55 ++++++++-----------
 spec/models/concerns/account/counters_spec.rb | 13 +++++
 2 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/app/models/concerns/account/counters.rb b/app/models/concerns/account/counters.rb
index 448839812..536d5ca7b 100644
--- a/app/models/concerns/account/counters.rb
+++ b/app/models/concerns/account/counters.rb
@@ -35,40 +35,11 @@ module Account::Counters
     raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key)
     raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id)
 
-    value = value.to_i
-    default_value = value.positive? ? value : 0
-
-    # We do an upsert using manually written SQL, as Rails' upsert method does
-    # not seem to support writing expressions in the UPDATE clause, but only
-    # re-insert the provided values instead.
-    # Even ARel seem to be missing proper handling of upserts.
-    sql = if value.positive? && key == :statuses_count
-            <<-SQL.squish
-              INSERT INTO account_stats(account_id, #{key}, created_at, updated_at, last_status_at)
-                VALUES (:account_id, :default_value, now(), now(), now())
-              ON CONFLICT (account_id) DO UPDATE
-              SET #{key} = account_stats.#{key} + :value,
-                  last_status_at = now(),
-                  updated_at = now()
-              RETURNING id;
-            SQL
-          else
-            <<-SQL.squish
-              INSERT INTO account_stats(account_id, #{key}, created_at, updated_at)
-                VALUES (:account_id, :default_value, now(), now())
-              ON CONFLICT (account_id) DO UPDATE
-              SET #{key} = account_stats.#{key} + :value,
-                  updated_at = now()
-              RETURNING id;
-            SQL
-          end
-
-    sql = AccountStat.sanitize_sql([sql, account_id: id, default_value: default_value, value: value])
-    account_stat_id = AccountStat.connection.exec_query(sql)[0]['id']
+    result = updated_account_stat(key, value.to_i)
 
     # Reload account_stat if it was loaded, taking into account newly-created unsaved records
     if association(:account_stat).loaded?
-      account_stat.id = account_stat_id if account_stat.new_record?
+      account_stat.id = result.first['id'] if account_stat.new_record?
       account_stat.reload
     end
   end
@@ -79,6 +50,28 @@ module Account::Counters
 
   private
 
+  def updated_account_stat(key, value)
+    AccountStat.upsert(
+      initial_values(key, value),
+      on_duplicate: Arel.sql(
+        duplicate_values(key, value).join(', ')
+      ),
+      unique_by: :account_id
+    )
+  end
+
+  def initial_values(key, value)
+    { :account_id => id, key => [value, 0].max }.tap do |values|
+      values.merge!(last_status_at: Time.current) if key == :statuses_count
+    end
+  end
+
+  def duplicate_values(key, value)
+    ["#{key} = (account_stats.#{key} + #{value})", 'updated_at = CURRENT_TIMESTAMP'].tap do |values|
+      values << 'last_status_at = CURRENT_TIMESTAMP' if key == :statuses_count && value.positive?
+    end
+  end
+
   def save_account_stat
     return unless association(:account_stat).loaded? && account_stat&.changed?
 
diff --git a/spec/models/concerns/account/counters_spec.rb b/spec/models/concerns/account/counters_spec.rb
index 3c063a2fa..ccac9e95d 100644
--- a/spec/models/concerns/account/counters_spec.rb
+++ b/spec/models/concerns/account/counters_spec.rb
@@ -44,5 +44,18 @@ describe Account::Counters do
 
       expect(account.statuses_count).to eq 5
     end
+
+    it 'preserves last_status_at when decrementing statuses_count' do
+      account_stat = Fabricate(
+        :account_stat,
+        account: account,
+        last_status_at: 3.days.ago,
+        statuses_count: 10
+      )
+
+      expect { account.decrement_count!(:statuses_count) }
+        .to change(account_stat.reload, :statuses_count).by(-1)
+        .and not_change(account_stat.reload, :last_status_at)
+    end
   end
 end

From 9ce2db4136c109798b76adb82c1d12479d29018b Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 04:23:25 -0400
Subject: [PATCH 161/173] Combine double subject runs and DRY up change check
 in bulk import service spec (#29402)

---
 spec/services/bulk_import_row_service_spec.rb | 50 +++++++------------
 1 file changed, 18 insertions(+), 32 deletions(-)

diff --git a/spec/services/bulk_import_row_service_spec.rb b/spec/services/bulk_import_row_service_spec.rb
index d295c2806..b9af795a5 100644
--- a/spec/services/bulk_import_row_service_spec.rb
+++ b/spec/services/bulk_import_row_service_spec.rb
@@ -95,23 +95,27 @@ RSpec.describe BulkImportRowService do
     context 'when importing a list row' do
       let(:import_type) { 'lists' }
       let(:target_account) { Fabricate(:account) }
+      let(:list_name) { 'my list' }
       let(:data) do
-        { 'acct' => target_account.acct, 'list_name' => 'my list' }
+        { 'acct' => target_account.acct, 'list_name' => list_name }
       end
 
       shared_examples 'common behavior' do
+        shared_examples 'row import success and list addition' do
+          it 'returns true and adds the target account to the list' do
+            result = nil
+            expect { result = subject.call(import_row) }
+              .to change { result }.from(nil).to(true)
+              .and add_target_account_to_list
+          end
+        end
+
         context 'when the target account is already followed' do
           before do
             account.follow!(target_account)
           end
 
-          it 'returns true' do
-            expect(subject.call(import_row)).to be true
-          end
-
-          it 'adds the target account to the list' do
-            expect { subject.call(import_row) }.to add_target_account_to_list
-          end
+          include_examples 'row import success and list addition'
         end
 
         context 'when the user already requested to follow the target account' do
@@ -119,35 +123,17 @@ RSpec.describe BulkImportRowService do
             account.request_follow!(target_account)
           end
 
-          it 'returns true' do
-            expect(subject.call(import_row)).to be true
-          end
-
-          it 'adds the target account to the list' do
-            expect { subject.call(import_row) }.to add_target_account_to_list
-          end
+          include_examples 'row import success and list addition'
         end
 
         context 'when the target account is neither followed nor requested' do
-          it 'returns true' do
-            expect(subject.call(import_row)).to be true
-          end
-
-          it 'adds the target account to the list' do
-            expect { subject.call(import_row) }.to add_target_account_to_list
-          end
+          include_examples 'row import success and list addition'
         end
 
         context 'when the target account is the user themself' do
           let(:target_account) { account }
 
-          it 'returns true' do
-            expect(subject.call(import_row)).to be true
-          end
-
-          it 'adds the target account to the list' do
-            expect { subject.call(import_row) }.to add_target_account_to_list
-          end
+          include_examples 'row import success and list addition'
         end
 
         def add_target_account_to_list
@@ -161,7 +147,7 @@ RSpec.describe BulkImportRowService do
             .joins(:list)
             .exists?(
               account_id: target_account.id,
-              list: { title: 'my list' }
+              list: { title: list_name }
             )
         end
       end
@@ -172,7 +158,7 @@ RSpec.describe BulkImportRowService do
 
       context 'when the list exists' do
         before do
-          Fabricate(:list, account: account, title: 'my list')
+          Fabricate(:list, account: account, title: list_name)
         end
 
         include_examples 'common behavior'
@@ -180,7 +166,7 @@ RSpec.describe BulkImportRowService do
         it 'does not create a new list' do
           account.follow!(target_account)
 
-          expect { subject.call(import_row) }.to_not(change { List.where(title: 'my list').count })
+          expect { subject.call(import_row) }.to_not(change { List.where(title: list_name).count })
         end
       end
     end

From 03abff3b30be2d8efe478a714fcccd0b1375f722 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 10:30:58 +0200
Subject: [PATCH 162/173] Update dependency aws-sdk-s3 to v1.147.0 (#29967)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 9c0adce16..ffeeebe9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -102,17 +102,17 @@ GEM
     attr_required (1.0.2)
     awrence (1.2.1)
     aws-eventstream (1.3.0)
-    aws-partitions (1.899.0)
-    aws-sdk-core (3.191.5)
+    aws-partitions (1.914.0)
+    aws-sdk-core (3.192.0)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.8)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.78.0)
+    aws-sdk-kms (1.79.0)
       aws-sdk-core (~> 3, >= 3.191.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.146.1)
-      aws-sdk-core (~> 3, >= 3.191.0)
+    aws-sdk-s3 (1.147.0)
+      aws-sdk-core (~> 3, >= 3.192.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.8)
     aws-sigv4 (1.8.0)

From 9ae25947263cd4cc376fc210240e7b0f984a05d3 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 05:00:08 -0400
Subject: [PATCH 163/173] Add reusable duplicate ID finder methods in
 maintenance CLI (#28910)

---
 lib/mastodon/cli/maintenance.rb | 61 ++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 23 deletions(-)

diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb
index d16d55eae..0b84047a1 100644
--- a/lib/mastodon/cli/maintenance.rb
+++ b/lib/mastodon/cli/maintenance.rb
@@ -254,7 +254,7 @@ module Mastodon::CLI
 
       say 'Deduplicating accounts… for local accounts, you will be asked to chose which account to keep unchanged.'
 
-      find_duplicate_accounts.each do |row|
+      duplicate_record_ids(:accounts, "lower(username), COALESCE(lower(domain), '')").each do |row|
         accounts = Account.where(id: row['ids'].split(','))
 
         if accounts.first.local?
@@ -306,7 +306,7 @@ module Mastodon::CLI
     end
 
     def deduplicate_users_process_email
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users GROUP BY email HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:users, 'email').each do |row|
         users = User.where(id: row['ids'].split(',')).order(updated_at: :desc).includes(:account).to_a
         ref_user = users.shift
         say "Multiple users registered with e-mail address #{ref_user.email}.", :yellow
@@ -320,7 +320,7 @@ module Mastodon::CLI
     end
 
     def deduplicate_users_process_confirmation_token
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE confirmation_token IS NOT NULL GROUP BY confirmation_token HAVING count(*) > 1").each do |row|
+      duplicate_record_ids_without_nulls(:users, 'confirmation_token').each do |row|
         users = User.where(id: row['ids'].split(',')).order(created_at: :desc).includes(:account).to_a.drop(1)
         say "Unsetting confirmation token for those accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow
 
@@ -332,7 +332,7 @@ module Mastodon::CLI
 
     def deduplicate_users_process_remember_token
       if migrator_version < 2022_01_18_183010
-        database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
+        duplicate_record_ids_without_nulls(:users, 'remember_token').each do |row|
           users = User.where(id: row['ids'].split(',')).order(updated_at: :desc).to_a.drop(1)
           say "Unsetting remember token for those accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow
 
@@ -344,7 +344,7 @@ module Mastodon::CLI
     end
 
     def deduplicate_users_process_password_token
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE reset_password_token IS NOT NULL GROUP BY reset_password_token HAVING count(*) > 1").each do |row|
+      duplicate_record_ids_without_nulls(:users, 'reset_password_token').each do |row|
         users = User.where(id: row['ids'].split(',')).order(updated_at: :desc).includes(:account).to_a.drop(1)
         say "Unsetting password reset token for those accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow
 
@@ -358,7 +358,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:account_domain_blocks, 'index_account_domain_blocks_on_account_id_and_domain')
 
       say 'Removing duplicate account domain blocks…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM account_domain_blocks GROUP BY account_id, domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:account_domain_blocks, 'account_id, domain').each do |row|
         AccountDomainBlock.where(id: row['ids'].split(',').drop(1)).delete_all
       end
 
@@ -372,7 +372,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:account_identity_proofs, 'index_account_proofs_on_account_and_provider_and_username')
 
       say 'Removing duplicate account identity proofs…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM account_identity_proofs GROUP BY account_id, provider, provider_username HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:account_identity_proofs, 'account_id, provider, provider_username').each do |row|
         AccountIdentityProof.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -386,7 +386,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:announcement_reactions, 'index_announcement_reactions_on_account_id_and_announcement_id')
 
       say 'Removing duplicate announcement reactions…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM announcement_reactions GROUP BY account_id, announcement_id, name HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:announcement_reactions, 'account_id, announcement_id, name').each do |row|
         AnnouncementReaction.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -398,7 +398,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:conversations, 'index_conversations_on_uri')
 
       say 'Deduplicating conversations…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM conversations WHERE uri IS NOT NULL GROUP BY uri HAVING count(*) > 1").each do |row|
+      duplicate_record_ids_without_nulls(:conversations, 'uri').each do |row|
         conversations = Conversation.where(id: row['ids'].split(',')).order(id: :desc).to_a
 
         ref_conversation = conversations.shift
@@ -421,7 +421,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:custom_emojis, 'index_custom_emojis_on_shortcode_and_domain')
 
       say 'Deduplicating custom_emojis…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM custom_emojis GROUP BY shortcode, domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:custom_emojis, 'shortcode, domain').each do |row|
         emojis = CustomEmoji.where(id: row['ids'].split(',')).order(id: :desc).to_a
 
         ref_emoji = emojis.shift
@@ -440,7 +440,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:custom_emoji_categories, 'index_custom_emoji_categories_on_name')
 
       say 'Deduplicating custom_emoji_categories…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM custom_emoji_categories GROUP BY name HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:custom_emoji_categories, 'name').each do |row|
         categories = CustomEmojiCategory.where(id: row['ids'].split(',')).order(id: :desc).to_a
 
         ref_category = categories.shift
@@ -459,7 +459,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:domain_allows, 'index_domain_allows_on_domain')
 
       say 'Deduplicating domain_allows…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM domain_allows GROUP BY domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:domain_allows, 'domain').each do |row|
         DomainAllow.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -471,7 +471,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:domain_blocks, 'index_domain_blocks_on_domain')
 
       say 'Deduplicating domain_blocks…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM domain_blocks GROUP BY domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:domain_blocks, 'domain').each do |row|
         domain_blocks = DomainBlock.where(id: row['ids'].split(',')).by_severity.reverse.to_a
 
         reject_media = domain_blocks.any?(&:reject_media?)
@@ -497,7 +497,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:unavailable_domains, 'index_unavailable_domains_on_domain')
 
       say 'Deduplicating unavailable_domains…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM unavailable_domains GROUP BY domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:unavailable_domains, 'domain').each do |row|
         UnavailableDomain.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -509,7 +509,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:email_domain_blocks, 'index_email_domain_blocks_on_domain')
 
       say 'Deduplicating email_domain_blocks…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM email_domain_blocks GROUP BY domain HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:email_domain_blocks, 'domain').each do |row|
         domain_blocks = EmailDomainBlock.where(id: row['ids'].split(',')).order(EmailDomainBlock.arel_table[:parent_id].asc.nulls_first).to_a
         domain_blocks.drop(1).each(&:destroy)
       end
@@ -522,7 +522,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:media_attachments, 'index_media_attachments_on_shortcode')
 
       say 'Deduplicating media_attachments…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM media_attachments WHERE shortcode IS NOT NULL GROUP BY shortcode HAVING count(*) > 1").each do |row|
+      duplicate_record_ids_without_nulls(:media_attachments, 'shortcode').each do |row|
         MediaAttachment.where(id: row['ids'].split(',').drop(1)).update_all(shortcode: nil)
       end
 
@@ -538,7 +538,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:preview_cards, 'index_preview_cards_on_url')
 
       say 'Deduplicating preview_cards…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM preview_cards GROUP BY url HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:preview_cards, 'url').each do |row|
         PreviewCard.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -550,7 +550,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:statuses, 'index_statuses_on_uri')
 
       say 'Deduplicating statuses…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM statuses WHERE uri IS NOT NULL GROUP BY uri HAVING count(*) > 1").each do |row|
+      duplicate_record_ids_without_nulls(:statuses, 'uri').each do |row|
         statuses = Status.where(id: row['ids'].split(',')).order(id: :asc).to_a
         ref_status = statuses.shift
         statuses.each do |status|
@@ -572,7 +572,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:tags, 'index_tags_on_name_lower_btree')
 
       say 'Deduplicating tags…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM tags GROUP BY lower((name)::text) HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:tags, 'lower((name)::text)').each do |row|
         tags = Tag.where(id: row['ids'].split(',')).order(Arel.sql('(usable::int + trendable::int + listable::int) desc')).to_a
         ref_tag = tags.shift
         tags.each do |tag|
@@ -595,7 +595,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:webauthn_credentials, 'index_webauthn_credentials_on_external_id')
 
       say 'Deduplicating webauthn_credentials…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM webauthn_credentials GROUP BY external_id HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:webauthn_credentials, 'external_id').each do |row|
         WebauthnCredential.where(id: row['ids'].split(',')).order(id: :desc).to_a.drop(1).each(&:destroy)
       end
 
@@ -609,7 +609,7 @@ module Mastodon::CLI
       remove_index_if_exists!(:webhooks, 'index_webhooks_on_url')
 
       say 'Deduplicating webhooks…'
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM webhooks GROUP BY url HAVING count(*) > 1").each do |row|
+      duplicate_record_ids(:webhooks, 'url').each do |row|
         Webhook.where(id: row['ids'].split(',')).order(id: :desc).drop(1).each(&:destroy)
       end
 
@@ -746,8 +746,23 @@ module Mastodon::CLI
       ActiveRecord::Migrator.current_version
     end
 
-    def find_duplicate_accounts
-      database_connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM accounts GROUP BY lower(username), COALESCE(lower(domain), '') HAVING count(*) > 1")
+    def duplicate_record_ids_without_nulls(table, group_by)
+      database_connection.select_all(<<~SQL.squish)
+        SELECT string_agg(id::text, ',') AS ids
+        FROM #{table}
+        WHERE #{group_by} IS NOT NULL
+        GROUP BY #{group_by}
+        HAVING COUNT(*) > 1
+      SQL
+    end
+
+    def duplicate_record_ids(table, group_by)
+      database_connection.select_all(<<~SQL.squish)
+        SELECT string_agg(id::text, ',') AS ids
+        FROM #{table}
+        GROUP BY #{group_by}
+        HAVING COUNT(*) > 1
+      SQL
     end
 
     def remove_index_if_exists!(table, name)

From fc89ecc6cace1362d40158e9614494a242a7b06a Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 17 Apr 2024 11:06:23 +0200
Subject: [PATCH 164/173] Change `/api/v1/announcements` to return regular
 `Status` entities (#26736)

---
 app/models/announcement.rb                      | 12 +++++++-----
 app/serializers/rest/announcement_serializer.rb | 14 +-------------
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/app/models/announcement.rb b/app/models/announcement.rb
index 5ce382dc1..54923ed08 100644
--- a/app/models/announcement.rb
+++ b/app/models/announcement.rb
@@ -59,11 +59,13 @@ class Announcement < ApplicationRecord
   end
 
   def statuses
-    @statuses ||= if status_ids.nil?
-                    []
-                  else
-                    Status.where(id: status_ids).distributable_visibility
-                  end
+    @statuses ||= begin
+      if status_ids.nil?
+        []
+      else
+        Status.with_includes.distributable_visibility.where(id: status_ids)
+      end
+    end
   end
 
   def tags
diff --git a/app/serializers/rest/announcement_serializer.rb b/app/serializers/rest/announcement_serializer.rb
index 8cee27127..d1a011425 100644
--- a/app/serializers/rest/announcement_serializer.rb
+++ b/app/serializers/rest/announcement_serializer.rb
@@ -9,7 +9,7 @@ class REST::AnnouncementSerializer < ActiveModel::Serializer
   attribute :read, if: :current_user?
 
   has_many :mentions
-  has_many :statuses
+  has_many :statuses, serializer: REST::StatusSerializer
   has_many :tags, serializer: REST::StatusSerializer::TagSerializer
   has_many :emojis, serializer: REST::CustomEmojiSerializer
   has_many :reactions, serializer: REST::ReactionSerializer
@@ -49,16 +49,4 @@ class REST::AnnouncementSerializer < ActiveModel::Serializer
       object.pretty_acct
     end
   end
-
-  class StatusSerializer < ActiveModel::Serializer
-    attributes :id, :url
-
-    def id
-      object.id.to_s
-    end
-
-    def url
-      ActivityPub::TagManager.instance.url_for(object)
-    end
-  end
 end

From c35042b7eb4ff969a504d47d97d5201f18d8ec40 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 09:07:13 +0000
Subject: [PATCH 165/173] New Crowdin Translations (automated) (#29972)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/bg.json      |  1 -
 app/javascript/mastodon/locales/br.json      |  1 +
 app/javascript/mastodon/locales/ca.json      |  2 +-
 app/javascript/mastodon/locales/cs.json      | 37 ++++++++
 app/javascript/mastodon/locales/da.json      |  2 +-
 app/javascript/mastodon/locales/de.json      |  2 +-
 app/javascript/mastodon/locales/es-AR.json   |  2 +-
 app/javascript/mastodon/locales/es-MX.json   |  1 -
 app/javascript/mastodon/locales/es.json      |  1 -
 app/javascript/mastodon/locales/et.json      |  1 -
 app/javascript/mastodon/locales/eu.json      |  1 +
 app/javascript/mastodon/locales/fi.json      |  2 +-
 app/javascript/mastodon/locales/fo.json      |  2 +-
 app/javascript/mastodon/locales/fr-CA.json   |  1 -
 app/javascript/mastodon/locales/fr.json      |  1 -
 app/javascript/mastodon/locales/gd.json      |  1 -
 app/javascript/mastodon/locales/gl.json      |  2 +-
 app/javascript/mastodon/locales/he.json      |  2 +-
 app/javascript/mastodon/locales/hu.json      |  2 +-
 app/javascript/mastodon/locales/ie.json      |  1 -
 app/javascript/mastodon/locales/is.json      |  2 +-
 app/javascript/mastodon/locales/it.json      |  2 +-
 app/javascript/mastodon/locales/ko.json      |  2 +-
 app/javascript/mastodon/locales/lad.json     |  1 +
 app/javascript/mastodon/locales/lt.json      |  1 -
 app/javascript/mastodon/locales/nl.json      |  2 +-
 app/javascript/mastodon/locales/nn.json      |  1 -
 app/javascript/mastodon/locales/pl.json      |  2 +-
 app/javascript/mastodon/locales/pt-BR.json   |  1 -
 app/javascript/mastodon/locales/pt-PT.json   |  2 +-
 app/javascript/mastodon/locales/ru.json      |  1 -
 app/javascript/mastodon/locales/sl.json      |  2 +-
 app/javascript/mastodon/locales/sq.json      |  1 -
 app/javascript/mastodon/locales/sr-Latn.json | 93 +++++++++++++++-----
 app/javascript/mastodon/locales/sr.json      | 15 ++++
 app/javascript/mastodon/locales/sv.json      |  1 -
 app/javascript/mastodon/locales/th.json      |  1 -
 app/javascript/mastodon/locales/tr.json      |  8 +-
 app/javascript/mastodon/locales/uk.json      |  1 -
 app/javascript/mastodon/locales/vi.json      |  2 +-
 app/javascript/mastodon/locales/zh-CN.json   |  2 +-
 app/javascript/mastodon/locales/zh-HK.json   |  1 -
 app/javascript/mastodon/locales/zh-TW.json   |  2 +-
 config/locales/sr-Latn.yml                   | 21 +++++
 config/locales/sr.yml                        | 17 ++++
 45 files changed, 186 insertions(+), 63 deletions(-)

diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 2acedbc4d..910d6cb06 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Филтриране на публ.",
   "filter_modal.title.status": "Филтриране на публ.",
   "filtered_notifications_banner.pending_requests": "Известията от {count, plural, =0 {никого, когото може да познавате} one {едно лице, което може да познавате} other {# души, които може да познавате}}",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {частно споменаване} other {частни споменавания}}",
   "filtered_notifications_banner.title": "Филтрирани известия",
   "firehose.all": "Всичко",
   "firehose.local": "Този сървър",
diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json
index 609e7f715..f51121bcd 100644
--- a/app/javascript/mastodon/locales/br.json
+++ b/app/javascript/mastodon/locales/br.json
@@ -256,6 +256,7 @@
   "filter_modal.select_filter.subtitle": "Implijout ur rummad a zo anezhañ pe krouiñ unan nevez",
   "filter_modal.select_filter.title": "Silañ an toud-mañ",
   "filter_modal.title.status": "Silañ un toud",
+  "filtered_notifications_banner.mentions": "{count, plural, one {meneg} two {veneg} few {meneg} other {a venegoù}}",
   "firehose.all": "Pep tra",
   "firehose.local": "Ar servijer-mañ",
   "firehose.remote": "Servijerioù all",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 6f0dd9376..40d9771df 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Usa una categoria existent o crea'n una de nova",
   "filter_modal.select_filter.title": "Filtra aquest tut",
   "filter_modal.title.status": "Filtra un tut",
+  "filtered_notifications_banner.mentions": "{count, plural, one {menció} other {mencions}}",
   "filtered_notifications_banner.pending_requests": "Notificacions {count, plural, =0 {de ningú} one {d'una persona} other {de # persones}} que potser coneixes",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {menció privada} other {mencions privades}}",
   "filtered_notifications_banner.title": "Notificacions filtrades",
   "firehose.all": "Tots",
   "firehose.local": "Aquest servidor",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 273e8bf49..f55caf14b 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -89,6 +89,14 @@
   "announcement.announcement": "Oznámení",
   "attachments_list.unprocessed": "(nezpracováno)",
   "audio.hide": "Skrýt zvuk",
+  "block_modal.remote_users_caveat": "Požádáme server {domain}, aby respektoval vaše rozhodnutí. Úplné dodržování nastavení však není zaručeno, protože některé servery mohou řešit blokování různě. Veřejné příspěvky mohou být stále viditelné pro nepřihlášené uživatele.",
+  "block_modal.show_less": "Zobrazit méně",
+  "block_modal.show_more": "Zobrazit více",
+  "block_modal.they_cant_mention": "Nemůže vás zmiňovat ani sledovat.",
+  "block_modal.they_cant_see_posts": "Nemůže vidět vaše příspěvky a vy neuvidíte jeho.",
+  "block_modal.they_will_know": "Může vidět, že je zablokovaný.",
+  "block_modal.title": "Zablokovat uživatele?",
+  "block_modal.you_wont_see_mentions": "Neuvidíte příspěvky, které ho zmiňují.",
   "boost_modal.combo": "Příště můžete pro přeskočení stisknout {combo}",
   "bundle_column_error.copy_stacktrace": "Zkopírovat zprávu o chybě",
   "bundle_column_error.error.body": "Požadovanou stránku nelze vykreslit. Může to být způsobeno chybou v našem kódu nebo problémem s kompatibilitou prohlížeče.",
@@ -169,6 +177,7 @@
   "confirmations.delete_list.message": "Opravdu chcete tento seznam navždy smazat?",
   "confirmations.discard_edit_media.confirm": "Zahodit",
   "confirmations.discard_edit_media.message": "Máte neuložené změny popisku médií nebo náhledu, chcete je přesto zahodit?",
+  "confirmations.domain_block.confirm": "Blokovat server",
   "confirmations.domain_block.message": "Opravdu chcete blokovat celou doménu {domain}? Ve většině případů stačí blokovat nebo skrýt pár konkrétních uživatelů, což také doporučujeme. Z této domény neuvidíte obsah v žádné veřejné časové ose ani v oznámeních. Vaši sledující z této domény budou odstraněni.",
   "confirmations.edit.confirm": "Upravit",
   "confirmations.edit.message": "Editovat teď znamená přepsání zprávy, kterou právě tvoříte. Opravdu chcete pokračovat?",
@@ -200,6 +209,27 @@
   "dismissable_banner.explore_statuses": "Toto jsou příspěvky ze sociálních sítí, které dnes získávají na popularitě. Novější příspěvky s větším počtem boostů a oblíbení jsou hodnoceny výše.",
   "dismissable_banner.explore_tags": "Tyto hashtagy právě teď získávají na popularitě mezi lidmi na tomto a dalších serverech decentralizované sítě.",
   "dismissable_banner.public_timeline": "Toto jsou nejnovější veřejné příspěvky od lidí na sociální síti, které sledují lidé na {domain}.",
+  "domain_block_modal.block": "Blokovat server",
+  "domain_block_modal.block_account_instead": "Raději blokovat @{name}",
+  "domain_block_modal.they_can_interact_with_old_posts": "Lidé z tohoto serveru mohou interagovat s vašimi starými příspěvky.",
+  "domain_block_modal.they_cant_follow": "Nikdo z tohoto serveru vás nemůže sledovat.",
+  "domain_block_modal.they_wont_know": "Nebude vědět, že je zablokován.",
+  "domain_block_modal.title": "Blokovat doménu?",
+  "domain_block_modal.you_will_lose_followers": "Všichni vaši sledující z tohoto serveru budou odstraněni.",
+  "domain_block_modal.you_wont_see_posts": "Neuvidíte příspěvky ani upozornění od uživatelů z tohoto serveru.",
+  "domain_pill.activitypub_lets_connect": "Umožňuje vám spojit se a komunikovat s lidmi nejen na Mastodonu, ale i s dalšími sociálními aplikacemi.",
+  "domain_pill.activitypub_like_language": "ActivityPub je jako jazyk, kterým Mastodon mluví s jinými sociálními sítěmi.",
+  "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Handle:",
+  "domain_pill.their_server": "Digitální domov, kde žijí všechny příspěvky.",
+  "domain_pill.their_username": "Jedinečný identikátor na serveru. Je možné najít uživatele se stejným uživatelským jménem na různých serverech.",
+  "domain_pill.username": "Uživatelské jméno",
+  "domain_pill.whats_in_a_handle": "Co obsahuje handle?",
+  "domain_pill.who_they_are": "Protože handle říkají kdo je kdo a také kde, je možné interagovat s lidmi napříč sociálními weby <button>platforem postavených na ActivityPub</button>.",
+  "domain_pill.who_you_are": "Protože handle říká kdo jsi a kde jsi, mohou s tebou lidé komunikovat napříč sociálními weby <button>platforem postavených na ActivityPub</button>.",
+  "domain_pill.your_handle": "Tvůj handle:",
+  "domain_pill.your_server": "Tvůj digitální domov, kde žijí všechny tvé příspěvky. Nelíbí se ti? Kdykoliv se přesuň na jiný server a vezmi si sebou i své sledující.",
+  "domain_pill.your_username": "Tvůj jedinečný identifikátor na tomto serveru. Je možné najít uživatele se stejným uživatelským jménem na jiných serverech.",
   "embed.instructions": "Pro přidání příspěvku na vaši webovou stránku zkopírujte níže uvedený kód.",
   "embed.preview": "Takhle to bude vypadat:",
   "emoji_button.activity": "Aktivita",
@@ -236,6 +266,7 @@
   "empty_column.list": "V tomto seznamu zatím nic není. Až nějaký člen z tohoto seznamu zveřejní nový příspěvek, objeví se zde.",
   "empty_column.lists": "Zatím nemáte žádné seznamy. Až nějaký vytvoříte, zobrazí se zde.",
   "empty_column.mutes": "Zatím jste neskryli žádného uživatele.",
+  "empty_column.notification_requests": "Vyčištěno! Nic tu není. Jakmile obdržíš nové notifikace, objeví se zde podle tvého nastavení.",
   "empty_column.notifications": "Zatím nemáte žádná oznámení. Až s vámi někdo bude interagovat, uvidíte to zde.",
   "empty_column.public": "Tady nic není! Napište něco veřejně, nebo začněte ručně sledovat uživatele z jiných serverů, aby tu něco přibylo",
   "error.unexpected_crash.explanation": "Kvůli chybě v našem kódu nebo problému s kompatibilitou prohlížeče nemohla být tato stránka správně zobrazena.",
@@ -266,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Použít existující kategorii nebo vytvořit novou kategorii",
   "filter_modal.select_filter.title": "Filtrovat tento příspěvek",
   "filter_modal.title.status": "Filtrovat příspěvek",
+  "filtered_notifications_banner.title": "Filtrovaná oznámení",
   "firehose.all": "Vše",
   "firehose.local": "Tento server",
   "firehose.remote": "Ostatní servery",
@@ -394,6 +426,8 @@
   "loading_indicator.label": "Načítání…",
   "media_gallery.toggle_visible": "{number, plural, one {Skrýt obrázek} few {Skrýt obrázky} many {Skrýt obrázky} other {Skrýt obrázky}}",
   "moved_to_account_banner.text": "Váš účet {disabledAccount} je momentálně deaktivován, protože jste se přesunul/a na {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Skrýt z notifikací",
+  "mute_modal.title": "Ztlumit uživatele?",
   "navigation_bar.about": "O aplikaci",
   "navigation_bar.advanced_interface": "Otevřít pokročilé webové rozhraní",
   "navigation_bar.blocks": "Blokovaní uživatelé",
@@ -429,8 +463,11 @@
   "notification.own_poll": "Vaše anketa skončila",
   "notification.poll": "Anketa, ve které jste hlasovali, skončila",
   "notification.reblog": "Uživatel {name} boostnul váš příspěvek",
+  "notification.relationships_severance_event.learn_more": "Zjistit více",
   "notification.status": "Uživatel {name} právě přidal příspěvek",
   "notification.update": "Uživatel {name} upravil příspěvek",
+  "notification_requests.accept": "Přijmout",
+  "notification_requests.dismiss": "Zamítnout",
   "notifications.clear": "Vyčistit oznámení",
   "notifications.clear_confirmation": "Opravdu chcete trvale smazat všechna vaše oznámení?",
   "notifications.column_settings.admin.report": "Nová hlášení:",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 2e5fb21fe..a7c8a049e 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -295,8 +295,8 @@
   "filter_modal.select_filter.subtitle": "Vælg en eksisterende kategori eller opret en ny",
   "filter_modal.select_filter.title": "Filtrér dette indlæg",
   "filter_modal.title.status": "Filtrér et indlæg",
+  "filtered_notifications_banner.mentions": "{count, plural, one {omtale} other {omtaler}}",
   "filtered_notifications_banner.pending_requests": "Notifikationer fra {count, plural, =0 {ingen} one {én person} other {# personer}} du måske kender",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omtale} other {private omtaler}}",
   "filtered_notifications_banner.title": "Filtrerede notifikationer",
   "firehose.all": "Alle",
   "firehose.local": "Denne server",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 5a5acb383..a1ba25fed 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Einem vorhandenen Filter hinzufügen oder einen neuen erstellen",
   "filter_modal.select_filter.title": "Diesen Beitrag filtern",
   "filter_modal.title.status": "Beitrag per Filter ausblenden",
+  "filtered_notifications_banner.mentions": "{count, plural, one {Erwähnung} other {Erwähnungen}}",
   "filtered_notifications_banner.pending_requests": "Benachrichtigungen von {count, plural, =0 {keinem Profil, das du möglicherweise kennst} one {einem Profil, das du möglicherweise kennst} other {# Profilen, die du möglicherweise kennst}}",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {private Erwähnung} other {private Erwähnungen}}",
   "filtered_notifications_banner.title": "Gefilterte Benachrichtigungen",
   "firehose.all": "Alles",
   "firehose.local": "Dieser Server",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index c14edac6b..2cf419862 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Usar una categoría existente o crear una nueva",
   "filter_modal.select_filter.title": "Filtrar este mensaje",
   "filter_modal.title.status": "Filtrar un mensaje",
+  "filtered_notifications_banner.mentions": "{count, plural, one {mención} other {menciones}}",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todos",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index 78746d8b4..fd32d9d90 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index e3ed560b5..9c15a3cae 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
   "filtered_notifications_banner.pending_requests": "Notificaciones de {count, plural, =0 {nadie} one {una persona} other {# personas}} que podrías conocer",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {menciones privadas}}",
   "filtered_notifications_banner.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index eda209935..b2759d66c 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtreeri seda postitust",
   "filter_modal.title.status": "Postituse filtreerimine",
   "filtered_notifications_banner.pending_requests": "Teateid {count, plural, =0 {mitte üheltki} one {ühelt} other {#}} inimeselt, keda võid teada",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privaatne teavitus} other {privaatsed teavitused}}",
   "filtered_notifications_banner.title": "Filtreeritud teavitused",
   "firehose.all": "Kõik",
   "firehose.local": "See server",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 529c1ab9c..7e2ecf69c 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Hautatu lehendik dagoen kategoria bat edo sortu berria",
   "filter_modal.select_filter.title": "Iragazi bidalketa hau",
   "filter_modal.title.status": "Iragazi bidalketa bat",
+  "filtered_notifications_banner.mentions": "{count, plural, one {aipamen} other {aipamen}}",
   "filtered_notifications_banner.pending_requests": "Ezagutu {count, plural, =0 {dezakezun inoren} one {dezakezun pertsona baten} other {ditzakezun # pertsonen}} jakinarazpenak",
   "filtered_notifications_banner.title": "Iragazitako jakinarazpenak",
   "firehose.all": "Guztiak",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index b23f1254e..a32bb1315 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Käytä olemassa olevaa luokkaa tai luo uusi",
   "filter_modal.select_filter.title": "Suodata tämä julkaisu",
   "filter_modal.title.status": "Suodata julkaisu",
+  "filtered_notifications_banner.mentions": "{count, plural, one {maininta} other {mainintaa}}",
   "filtered_notifications_banner.pending_requests": "Ilmoitukset {count, plural, =0 {ei keltään} one {yhdeltä henkilöltä} other {# henkilöltä}}, jonka saatat tuntea",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {yksityismaininta} other {yksityismainintaa}}",
   "filtered_notifications_banner.title": "Suodatetut ilmoitukset",
   "firehose.all": "Kaikki",
   "firehose.local": "Tämä palvelin",
diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json
index b8722ee31..68faf6d81 100644
--- a/app/javascript/mastodon/locales/fo.json
+++ b/app/javascript/mastodon/locales/fo.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Brúka ein verandi bólk ella skapa ein nýggjan",
   "filter_modal.select_filter.title": "Filtrera hendan postin",
   "filter_modal.title.status": "Filtrera ein post",
+  "filtered_notifications_banner.mentions": "{count, plural, one {umrøða} other {umrøður}}",
   "filtered_notifications_banner.pending_requests": "Fráboðanir frá {count, plural, =0 {ongum} one {einum persóni} other {# persónum}}, sum tú kanska kennir",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat umrøða} other {privatar umrøður}}",
   "filtered_notifications_banner.title": "Sáldaðar fráboðanir",
   "firehose.all": "Allar",
   "firehose.local": "Hesin ambætarin",
diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json
index 163769253..9e2985290 100644
--- a/app/javascript/mastodon/locales/fr-CA.json
+++ b/app/javascript/mastodon/locales/fr-CA.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrer cette publication",
   "filter_modal.title.status": "Filtrer une publication",
   "filtered_notifications_banner.pending_requests": "Notifications {count, plural, =0 {de personne} one {d’une personne} other {de # personnes}} que vous pouvez connaitre",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mention privée} other {mentions privées}}",
   "filtered_notifications_banner.title": "Notifications filtrées",
   "firehose.all": "Tout",
   "firehose.local": "Ce serveur",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 18fce401b..58ab46d5c 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrer ce message",
   "filter_modal.title.status": "Filtrer un message",
   "filtered_notifications_banner.pending_requests": "Notifications {count, plural, =0 {de personne} one {d’une personne} other {de # personnes}} que vous pouvez connaitre",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mention privée} other {mentions privées}}",
   "filtered_notifications_banner.title": "Notifications filtrées",
   "firehose.all": "Tout",
   "firehose.local": "Ce serveur",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index 4aaa0cbf7..8ab515e1a 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Criathraich am post seo",
   "filter_modal.title.status": "Criathraich post",
   "filtered_notifications_banner.pending_requests": "{count, plural, =0 {Chan eil brath ann o dhaoine} one {Tha brathan ann o # neach} two {Tha brathan ann o # neach} few {Tha brathan ann o # daoine} other {Tha brathan ann o # duine}} air a bheil thu eòlach ’s dòcha",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {iomradh prìobhaideach} two {iomradh prìobhaideach} few {iomraidhean prìobhaideach} other {iomradh prìobhaideach}}",
   "filtered_notifications_banner.title": "Brathan criathraichte",
   "firehose.all": "Na h-uile",
   "firehose.local": "Am frithealaiche seo",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index c7fed4ed0..901bca749 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Usar unha categoría existente ou crear unha nova",
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar unha publicación",
+  "filtered_notifications_banner.mentions": "{count, plural, one {mención} other {mencións}}",
   "filtered_notifications_banner.pending_requests": "Notificacións de {count, plural, =0 {ninguén} one {unha persoa} other {# persoas}} que poderías coñecer",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {mención privada} other {mencións privadas}}",
   "filtered_notifications_banner.title": "Notificacións filtradas",
   "firehose.all": "Todo",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 155708cfa..d696186bf 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "שימוש בקטגורייה קיימת או יצירת אחת חדשה",
   "filter_modal.select_filter.title": "סינון ההודעה הזו",
   "filter_modal.title.status": "סנן הודעה",
+  "filtered_notifications_banner.mentions": "{count, plural, one {איזכור} other {איזכורים} two {איזכוריים}}",
   "filtered_notifications_banner.pending_requests": "{count, plural,=0 {אין התראות ממשתמשים ה}one {התראה אחת ממישהו/מישהי ה}two {יש התראותיים ממשתמשים }other {יש # התראות ממשתמשים }}מוכרים לך",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {איזכור פרטי} other {איזכורים פרטיים}}",
   "filtered_notifications_banner.title": "התראות מסוננות",
   "firehose.all": "הכל",
   "firehose.local": "שרת זה",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 1de040a65..16dcea642 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Válassz egy meglévő kategóriát, vagy hozz létre egy újat",
   "filter_modal.select_filter.title": "E bejegyzés szűrése",
   "filter_modal.title.status": "Egy bejegyzés szűrése",
+  "filtered_notifications_banner.mentions": "{count, plural, one {említés} other {említés}}",
   "filtered_notifications_banner.pending_requests": "Értesítések {count, plural, =0 {nincsenek} one {egy valósztínűleg ismerős személytől} other {# valószínűleg ismerős személytől}}",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privát említés} other {privát említés}}",
   "filtered_notifications_banner.title": "Szűrt értesítések",
   "firehose.all": "Összes",
   "firehose.local": "Ez a kiszolgáló",
diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json
index 00b6a36c9..8d491412c 100644
--- a/app/javascript/mastodon/locales/ie.json
+++ b/app/javascript/mastodon/locales/ie.json
@@ -287,7 +287,6 @@
   "filter_modal.select_filter.title": "Filtrar ti-ci posta",
   "filter_modal.title.status": "Filtrar un posta",
   "filtered_notifications_banner.pending_requests": "Notificationes de {count, plural, =0 {nequi} one {un person} other {# persones}} quel tu possibilmen conosse",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat mention} other {privat mentiones}}",
   "filtered_notifications_banner.title": "Filtrat notificationes",
   "firehose.all": "Omno",
   "firehose.local": "Ti-ci servitor",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index c9a354f4b..435f98f30 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Notaðu fyrirliggjandi flokk eða útbúðu nýjan",
   "filter_modal.select_filter.title": "Sía þessa færslu",
   "filter_modal.title.status": "Sía færslu",
+  "filtered_notifications_banner.mentions": "{count, plural, one {tilvísun} other {tilvísanir}}",
   "filtered_notifications_banner.pending_requests": "Tilkynningar frá {count, plural, =0 {engum} one {einum aðila} other {# aðilum}} sem þú gætir þekkt",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {einkaspjall} other {einkaspjöll}}",
   "filtered_notifications_banner.title": "Síaðar tilkynningar",
   "firehose.all": "Allt",
   "firehose.local": "þessum netþjóni",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 4679d8341..fcfd09d75 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Usa una categoria esistente o creane una nuova",
   "filter_modal.select_filter.title": "Filtra questo post",
   "filter_modal.title.status": "Filtra un post",
+  "filtered_notifications_banner.mentions": "{count, plural, one {menzione} other {menzioni}}",
   "filtered_notifications_banner.pending_requests": "Notifiche da {count, plural, =0 {nessuno} one {una persona} other {# persone}} che potresti conoscere",
-  "filtered_notifications_banner.private_mentions": "{count, plural,one {menzione privata} other {menzioni private}}",
   "filtered_notifications_banner.title": "Notifiche filtrate",
   "firehose.all": "Tutto",
   "firehose.local": "Questo server",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index f1e1074ff..8628dbb33 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "기존의 카테고리를 사용하거나 새로 하나를 만듧니다",
   "filter_modal.select_filter.title": "이 게시물을 필터",
   "filter_modal.title.status": "게시물 필터",
+  "filtered_notifications_banner.mentions": "{count, plural, other {멘션}}",
   "filtered_notifications_banner.pending_requests": "알 수도 있는 {count, plural, =0 {0 명} one {한 명} other {# 명}}의 사람들로부터의 알림",
-  "filtered_notifications_banner.private_mentions": "{count, plural, other {개인적인 멘션}}",
   "filtered_notifications_banner.title": "걸러진 알림",
   "firehose.all": "모두",
   "firehose.local": "이 서버",
diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json
index 898f3b1ce..cf6c3f772 100644
--- a/app/javascript/mastodon/locales/lad.json
+++ b/app/javascript/mastodon/locales/lad.json
@@ -457,6 +457,7 @@
   "notification.own_poll": "Tu anketa eskapo",
   "notification.poll": "Anketa en ke votates eskapo",
   "notification.reblog": "{name} repartajo tu publikasyon",
+  "notification.relationships_severance_event": "Koneksyones pedridas kon {name}",
   "notification.relationships_severance_event.learn_more": "Ambezate mas",
   "notification.status": "{name} publiko algo",
   "notification.update": "{name} edito una publikasyon",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index 580af4f3d..7b3511cfe 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -282,7 +282,6 @@
   "filter_modal.select_filter.subtitle": "Naudok esamą kategoriją arba sukurk naują.",
   "filter_modal.select_filter.title": "Filtruoti šį įrašą",
   "filter_modal.title.status": "Filtruoti įrašą",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privatus paminėjimas} few {privatūs paminėjimai} many {privataus paminėjimo} other {privačių paminėjimų}}",
   "firehose.all": "Visi",
   "firehose.local": "Šis serveris",
   "firehose.remote": "Kiti serveriai",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 1025c3204..46d1f9783 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Een bestaande categorie gebruiken of een nieuwe aanmaken",
   "filter_modal.select_filter.title": "Dit bericht filteren",
   "filter_modal.title.status": "Een bericht filteren",
+  "filtered_notifications_banner.mentions": "{count, plural, one {vermelding} other {vermeldingen}}",
   "filtered_notifications_banner.pending_requests": "Meldingen van {count, plural, =0 {niemand} one {één persoon} other {# mensen}} die je misschien kent",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privébericht} other {privéberichten}}",
   "filtered_notifications_banner.title": "Gefilterde meldingen",
   "firehose.all": "Alles",
   "firehose.local": "Deze server",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index ab44c691d..2cfb0d124 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrer dette innlegget",
   "filter_modal.title.status": "Filtrer eit innlegg",
   "filtered_notifications_banner.pending_requests": "Varsel frå {count, plural, =0 {ingen} one {ein person} other {# folk}} du kanskje kjenner",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omtale} other {private omtaler}}",
   "filtered_notifications_banner.title": "Filtrerte varslingar",
   "firehose.all": "Alle",
   "firehose.local": "Denne tenaren",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 718aa32d2..72f1ba58f 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Użyj istniejącej kategorii lub utwórz nową",
   "filter_modal.select_filter.title": "Filtruj ten wpis",
   "filter_modal.title.status": "Filtruj wpis",
+  "filtered_notifications_banner.mentions": "{count, plural, one {wzmianka} few {wzmianki} other {wzmianek}}",
   "filtered_notifications_banner.pending_requests": "Powiadomienia od {count, plural, =0 {żadnej osoby którą możesz znać} one {# osoby którą możesz znać} other {# osób które możesz znać}}",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {prywatna wzmianka} few {prywatne wzmianki} other {prywatnych wzmianek}}",
   "filtered_notifications_banner.title": "Powiadomienia filtrowane",
   "firehose.all": "Wszystko",
   "firehose.local": "Ten serwer",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 08ed5c021..1bb73db23 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrar esta publicação",
   "filter_modal.title.status": "Filtrar uma publicação",
   "filtered_notifications_banner.pending_requests": "Notificações de {count, plural, =0 {no one} one {one person} other {# people}} que você talvez conheça",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {private mention} other {private mentions}}",
   "filtered_notifications_banner.title": "Notificações filtradas",
   "firehose.all": "Tudo",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 39dfba819..7e98cde5f 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Utilize uma categoria existente ou crie uma nova",
   "filter_modal.select_filter.title": "Filtrar esta publicação",
   "filter_modal.title.status": "Filtrar uma publicação",
+  "filtered_notifications_banner.mentions": "{count, plural, one {menção} other {menções}}",
   "filtered_notifications_banner.pending_requests": "Notificações de {count, plural, =0 {ninguém} one {uma pessoa} other {# pessoas}} que talvez conheça",
-  "filtered_notifications_banner.private_mentions": "{count, plural,one {menção privada} other {menções privadas}}",
   "filtered_notifications_banner.title": "Notificações filtradas",
   "firehose.all": "Todas",
   "firehose.local": "Este servidor",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 16c4d1998..cd09a505b 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Фильтровать этот пост",
   "filter_modal.title.status": "Фильтровать пост",
   "filtered_notifications_banner.pending_requests": "Уведомления от {count, plural, =0 {никого} one {# человека} other {# других людей, с кем вы можете быть знакомы}}",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {личное упоминание} other {личные упоминания}}",
   "filtered_notifications_banner.title": "Отфильтрованные уведомления",
   "firehose.all": "Все",
   "firehose.local": "Текущий сервер",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 55091dbee..ed4fa8dfa 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Uporabite obstoječo kategorijo ali ustvarite novo",
   "filter_modal.select_filter.title": "Filtriraj to objavo",
   "filter_modal.title.status": "Filtrirajte objavo",
+  "filtered_notifications_banner.mentions": "{count, plural, one {omemba} two {omembi} few {omembe} other {omemb}}",
   "filtered_notifications_banner.pending_requests": "Obvestila od {count, plural, =0 {nikogar, ki bi ga} one {# človeka, ki bi ga} two {# ljudi, ki bi ju} few {# ljudi, ki bi jih} other {# ljudi, ki bi jih}} lahko poznali",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {zasebna omemba} two {zasebni omembi} few {zasebne omembe} other {zasebnih omemb}}",
   "filtered_notifications_banner.title": "Filtrirana obvestila",
   "firehose.all": "Vse",
   "firehose.local": "Ta strežnik",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 95768b811..da35b3d43 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtroje këtë postim",
   "filter_modal.title.status": "Filtroni një postim",
   "filtered_notifications_banner.pending_requests": "Njoftime prej {count, plural, =0 {askujt} one {një personi} other {# vetësh}} që mund të njihni",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {përmendje private} other {përmendje private}}",
   "filtered_notifications_banner.title": "Njoftime të filtruar",
   "firehose.all": "Krejt",
   "firehose.local": "Këtë shërbyes",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 2d795c76c..3eea87d5e 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -13,14 +13,14 @@
   "about.rules": "Pravila servera",
   "account.account_note_header": "Napomena",
   "account.add_or_remove_from_list": "Dodaj ili ukloni sa lista",
-  "account.badges.bot": "Bot",
+  "account.badges.bot": "Automatizovano",
   "account.badges.group": "Grupa",
   "account.block": "Blokiraj @{name}",
   "account.block_domain": "Blokiraj domen {domain}",
   "account.block_short": "Blokiraj",
   "account.blocked": "Blokiran",
   "account.browse_more_on_origin_server": "Pregledajte još na originalnom profilu",
-  "account.cancel_follow_request": "Povuci zahtev za praćenje",
+  "account.cancel_follow_request": "Otkaži praćenje",
   "account.copy": "Kopiraj vezu u profil",
   "account.direct": "Privatno pomeni @{name}",
   "account.disable_notifications": "Zaustavi obaveštavanje za objave korisnika @{name}",
@@ -89,6 +89,14 @@
   "announcement.announcement": "Najava",
   "attachments_list.unprocessed": "(neobrađeno)",
   "audio.hide": "Sakrij audio",
+  "block_modal.remote_users_caveat": "Zamolićemo server {domain} da poštuje vašu odluku. Međutim, usklađenost nije zagarantovana jer neki serveri mogu drugačije da obrađuju blokove. Javne objave mogu i dalje biti vidljive korisnicima koji nisu prijavljeni.",
+  "block_modal.show_less": "Prikaži manje",
+  "block_modal.show_more": "Prikaži više",
+  "block_modal.they_cant_mention": "Ne mogu da vas pominju ili prate.",
+  "block_modal.they_cant_see_posts": "Ne mogu da vide vaše objave, a vi nećete videti njihove.",
+  "block_modal.they_will_know": "Mogu da vide da su blokirani.",
+  "block_modal.title": "Blokirati korisnika?",
+  "block_modal.you_wont_see_mentions": "Nećete videti objave koje ih pominju.",
   "boost_modal.combo": "Možete pritisnuti {combo} da preskočite ovo sledeći put",
   "bundle_column_error.copy_stacktrace": "Kopiraj izveštaj o grešci",
   "bundle_column_error.error.body": "Nije moguće prikazati traženu stranicu. Razlog može biti greška u našem kodu ili problem sa kompatibilnošću pretraživača.",
@@ -153,7 +161,7 @@
   "compose_form.poll.switch_to_single": "Promenite anketu da biste omogućili jedan izbor",
   "compose_form.poll.type": "Stil",
   "compose_form.publish": "Objavi",
-  "compose_form.publish_form": "Objavi",
+  "compose_form.publish_form": "Nova objava",
   "compose_form.reply": "Odgovori",
   "compose_form.save_changes": "Ažuriraj",
   "compose_form.spoiler.marked": "Ukloni upozorenje o sadržaju",
@@ -169,6 +177,7 @@
   "confirmations.delete_list.message": "Da li ste sigurni da želite da trajno izbrišete ovu listu?",
   "confirmations.discard_edit_media.confirm": "Odbaci",
   "confirmations.discard_edit_media.message": "Imate nesačuvane promene u opisu ili pregledu medija, da li ipak hoćete da ih odbacite?",
+  "confirmations.domain_block.confirm": "Blokiraj server",
   "confirmations.domain_block.message": "Da li ste zaista sigurni da želite da blokirate ceo domen {domain}? U većini slučajeva, dovoljno je i poželjno nekoliko ciljanih blokiranja ili ignorisanja. Nećete videti sadržaj sa tog domena ni u jednoj javnoj vremenskoj liniji ili u vašim obaveštenjima. Vaši pratioci sa tog domena će biti uklonjeni.",
   "confirmations.edit.confirm": "Uredi",
   "confirmations.edit.message": "Uređivanjem će se obrisati poruka koju trenutno sastavljate. Da li ste sigurni da želite da nastavite?",
@@ -196,10 +205,31 @@
   "disabled_account_banner.text": "Vaš nalog {disabledAccount} je trenutno onemogućen.",
   "dismissable_banner.community_timeline": "Ovo su najnovije javne objave ljudi čije naloge hostuje {domain}.",
   "dismissable_banner.dismiss": "Odbaci",
-  "dismissable_banner.explore_links": "O ovim vestima trenutno razgovaraju ljudi na ovom i drugim serverima decentralizovane mreže.",
+  "dismissable_banner.explore_links": "Ovo su vesti koje se danas najviše dele na društvenoj mreži. Novije vesti koje je objavilo više različitih ljudi su bolje rangirane.",
   "dismissable_banner.explore_statuses": "Ovo su objave širom društvenog veba koje danas postaju sve popularnije. Novije objave sa više podržavanja i omiljene su rangirane više.",
-  "dismissable_banner.explore_tags": "Ove heš oznake postaju sve popularnije među ljudima na ovom i drugim serverima decentralizovane mreže.",
+  "dismissable_banner.explore_tags": "Ovo su heš oznake koje danas postaju sve popularnije na društvenoj mreži. Heš oznake koje koristi više različitih ljudi su rangirane više.",
   "dismissable_banner.public_timeline": "Ovo su najnovije javne objave ljudi sa društvenog veba koje ljudi na {domain}-u prate.",
+  "domain_block_modal.block": "Blokiraj server",
+  "domain_block_modal.block_account_instead": "Umesto toga, blokiraj @{name}",
+  "domain_block_modal.they_can_interact_with_old_posts": "Ljudi sa ovog servera mogu da imaju interakciju sa vašim starim objavama.",
+  "domain_block_modal.they_cant_follow": "Niko sa ovog servera ne može da vas prati.",
+  "domain_block_modal.they_wont_know": "Neće znati da su blokirani.",
+  "domain_block_modal.title": "Blokirati domen?",
+  "domain_block_modal.you_will_lose_followers": "Svi vaši pratioci sa ovog servera će biti uklonjeni.",
+  "domain_block_modal.you_wont_see_posts": "Nećete videti objave ili obaveštenja korisnika na ovom serveru.",
+  "domain_pill.activitypub_lets_connect": "Omogućuje vam da se povežete i komunicirate sa ljudima ne samo na Mastodon-u, već i u različitim društvenim aplikacijama.",
+  "domain_pill.activitypub_like_language": "ActivityPub je kao jezik kojim Mastodon govori sa drugim društvenim mrežama.",
+  "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Njegov regulator:",
+  "domain_pill.their_server": "Njihov digitalni dom, gde žive sve njihove objave.",
+  "domain_pill.their_username": "Njihov jedinstveni identifikator na njihovom serveru. Moguće je pronaći korisnike sa istim korisničkim imenom na različitim serverima.",
+  "domain_pill.username": "Korisničko ime",
+  "domain_pill.whats_in_a_handle": "Šta je regulator?",
+  "domain_pill.who_they_are": "Pošto regulatori govore ko je neko i gde se nalazi, možete da komunicirate sa ljudima širom društvenog veba na <button>platformama koje pokreće ActivityPub</button>.",
+  "domain_pill.who_you_are": "Pošto vaši regulatori govori ko ste i gde ste, ljudi mogu da komuniciraju sa vama širom društvenog veba na <button>platformama koje pokreće ActivityPub</button>.",
+  "domain_pill.your_handle": "Vaš regulator:",
+  "domain_pill.your_server": "Vaš digitalni dom, gde žive sve vaše objave. Ne sviđa vam se ovaj? Prenesite servere u bilo koje vreme i dovedite i svoje pratioce.",
+  "domain_pill.your_username": "Njihov jedinstveni identifikator na njihovom serveru. Moguće je pronaći korisnike sa istim korisničkim imenom na različitim serverima.",
   "embed.instructions": "Ugradite ovu objavu na svoj veb sajt kopiranjem koda ispod.",
   "embed.preview": "Evo kako će to izgledati:",
   "emoji_button.activity": "Aktivnosti",
@@ -232,11 +262,11 @@
   "empty_column.follow_requests": "Još uvek nemate nijedan zahtev za praćenje. Kada primite zahtev, on će se pojaviti ovde.",
   "empty_column.followed_tags": "Još uvek niste zapratili nijednu heš oznaku. Kada to uradite, one će se pojaviti ovde.",
   "empty_column.hashtag": "Još uvek nema ničega u ovoj heš oznaci.",
-  "empty_column.home": "Vaša početna vremenska linija je prazna! Pratite više ljudi da biste je popunili. {suggestions}",
+  "empty_column.home": "Vaša početna vremenska linija je prazna! Pratite više ljudi da biste je popunili.",
   "empty_column.list": "U ovoj listi još nema ničega. Kada članovi ove liste objave nešto novo, pojaviće se ovde.",
   "empty_column.lists": "Još uvek nemate nijednu listu. Kada napravite jednu, ona će se pojaviti ovde.",
   "empty_column.mutes": "Još uvek ne ignorišete nijednog korisnika.",
-  "empty_column.notification_requests": "Sve je čisto! Ovde nema ničega. Kada dobijete nova obaveštenja, ona će se pojaviti ovde u skladu sa vašim podešavanjima.",
+  "empty_column.notification_requests": "Sve je čisto! Ovde nema ničega. Kada dobijete nova obaveštenja, ona će se pojaviti ovde u skladu sa vašim podešavanjima.",
   "empty_column.notifications": "Još uvek nemate nikakva obaveštenja. Kada drugi ljudi budu u interakciji sa vama, videćete to ovde.",
   "empty_column.public": "Ovde nema ničega! Napišite nešto javno ili ručno pratite korisnike sa drugih servera da biste ovo popunili",
   "error.unexpected_crash.explanation": "Zbog greške u našem kodu ili problema sa kompatibilnošću pregledača, ova stranica se nije mogla pravilno prikazati.",
@@ -267,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Koristite postojeću kategoriju ili kreirajte novu",
   "filter_modal.select_filter.title": "Filtriraj ovu objavu",
   "filter_modal.title.status": "Filtriraj objavu",
+  "filtered_notifications_banner.mentions": "{count, plural, one {pominjanje} few {pominjanja} other {pominjanja}}",
   "filtered_notifications_banner.pending_requests": "Obaveštenja od {count, plural, =0 {nikoga koga možda poznajete} one {# osobe koju možda poznajete} few {# osobe koje možda poznajete} other {# osoba koje možda poznajete}}",
   "filtered_notifications_banner.title": "Filtrirana obaveštenja",
   "firehose.all": "Sve",
@@ -279,7 +310,7 @@
   "follow_suggestions.dismiss": "Ne prikazuj ponovo",
   "follow_suggestions.hints.featured": "Ovaj profil je ručno izabrao tim {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Ovaj profil je popularan među ljudima koje pratite.",
-  "follow_suggestions.hints.most_followed": "Ovaj profil je jedan od najpraćenijih na {domain}.",
+  "follow_suggestions.hints.most_followed": "Ovaj profil je jedan od najpraćenijih na {domain}.",
   "follow_suggestions.hints.most_interactions": "Ovaj profil je nedavno dobio veliku pažnju na {domain}.",
   "follow_suggestions.hints.similar_to_recently_followed": "Ovaj profil je sličan profilima koje ste nedavno zapratili.",
   "follow_suggestions.personalized_suggestion": "Personalizovani predlog",
@@ -315,7 +346,7 @@
   "home.column_settings.show_reblogs": "Prikaži podržavanja",
   "home.column_settings.show_replies": "Prikaži odgovore",
   "home.hide_announcements": "Sakrij najave",
-  "home.pending_critical_update.body": "Ažurirajte svoj Mastodon server što je pre moguće!",
+  "home.pending_critical_update.body": "Ažurirajte svoj Mastodon server što je pre moguće!",
   "home.pending_critical_update.link": "Pogledajte ažuriranja",
   "home.pending_critical_update.title": "Dostupno je kritično bezbednosno ažuriranje!",
   "home.show_announcements": "Prijaži najave",
@@ -329,7 +360,7 @@
   "interaction_modal.on_another_server": "Na drugom serveru",
   "interaction_modal.on_this_server": "Na ovom serveru",
   "interaction_modal.sign_in": "Niste prijavljeni na ovaj server. Gde je hostovan vaš nalog?",
-  "interaction_modal.sign_in_hint": "Savet: To je veb sajt na kome ste se registrovali. Ako se ne sećate, potražite e-poruku dobrodošlice u svom prijemnom sandučetu. Takođe možete uneti svoje puno korisničko ime! (npr. @Mastodon@mastodon.social)",
+  "interaction_modal.sign_in_hint": "Savet: To je veb sajt na kome ste se registrovali. Ako se ne sećate, potražite e-poruku dobrodošlice u svom prijemnom sandučetu. Takođe možete uneti svoje puno korisničko ime! (npr. @Mastodon@mastodon.social)",
   "interaction_modal.title.favourite": "Označi objavu korisnika {name} kao omiljenu",
   "interaction_modal.title.follow": "Zaprati {name}",
   "interaction_modal.title.reblog": "Podrži objavu korisnika {name}",
@@ -397,6 +428,15 @@
   "loading_indicator.label": "Učitavanje…",
   "media_gallery.toggle_visible": "{number, plural, one {Sakrij sliku} few {Sakrij slike} other {Sakrij slike}}",
   "moved_to_account_banner.text": "Vaš nalog {disabledAccount} je trenutno onemogućen jer ste prešli na {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Sakrij iz obaveštenja",
+  "mute_modal.hide_options": "Sakrij opcije",
+  "mute_modal.indefinite": "Dok ih ne uklonim iz ignorisanih",
+  "mute_modal.show_options": "Prikaži opcije",
+  "mute_modal.they_can_mention_and_follow": "Mogu da vas pominju i prate, ali ih nećete videti.",
+  "mute_modal.they_wont_know": "Neće znati da su ignorisani.",
+  "mute_modal.title": "Ignorisati korisnika?",
+  "mute_modal.you_wont_see_mentions": "Nećete videti objave koje ga pominju.",
+  "mute_modal.you_wont_see_posts": "I dalje može da vidi vaše objave, ali vi nećete videti njegove.",
   "navigation_bar.about": "Osnovni podaci",
   "navigation_bar.advanced_interface": "Otvori u naprednom veb okruženju",
   "navigation_bar.blocks": "Blokirani korisnici",
@@ -432,6 +472,11 @@
   "notification.own_poll": "Vaša anketa je završena",
   "notification.poll": "Završena je anketa u kojoj ste glasali",
   "notification.reblog": "{name} je podržao vašu objavu",
+  "notification.relationships_severance_event": "Izgubljena veza sa {name}",
+  "notification.relationships_severance_event.account_suspension": "Administrator sa {from} je suspendovao {target}, što znači da više ne možete da primate ažuriranja od njih niti da komunicirate sa njima.",
+  "notification.relationships_severance_event.domain_block": "Administrator sa {from} je blokirao {target}, uključujući vaše pratioce: {followersCount} i {followingCount, plural, one {# nalog} few {# naloga} other {# naloga}} koje pratite.",
+  "notification.relationships_severance_event.learn_more": "Saznajte više",
+  "notification.relationships_severance_event.user_domain_block": "Blokirači ste {target}, uključujući vaše pratioce: {followersCount} i {followingCount, plural, one {# nalog} few {# naloga} other {# naloga}} koje pratite.",
   "notification.status": "{name} je upravo objavio",
   "notification.update": "{name} je uredio objavu",
   "notification_requests.accept": "Prihvati",
@@ -444,6 +489,8 @@
   "notifications.column_settings.admin.sign_up": "Nove ragistracije:",
   "notifications.column_settings.alert": "Obaveštenja na radnoj površini",
   "notifications.column_settings.favourite": "Omiljeno:",
+  "notifications.column_settings.filter_bar.advanced": "Prikaži sve kategorije",
+  "notifications.column_settings.filter_bar.category": "Traka za brzo filtriranje",
   "notifications.column_settings.follow": "Novi pratioci:",
   "notifications.column_settings.follow_request": "Novi zahtevi za praćenje:",
   "notifications.column_settings.mention": "Pominjanja:",
@@ -471,7 +518,7 @@
   "notifications.permission_required": "Obaveštenja na radnoj površini nisu dostupna jer potrebna dozvola nije dodeljena.",
   "notifications.policy.filter_new_accounts.hint": "Kreirano {days, plural, one {u poslednjeg # dana} few {u poslednja # dana} other {u poslednjih # dana}}",
   "notifications.policy.filter_new_accounts_title": "Novi nalozi",
-  "notifications.policy.filter_not_followers_hint": "Uključujući ljude koji su vas pratili manje od {days, plural, one {# dana} few {# dana} other {# dana}}",
+  "notifications.policy.filter_not_followers_hint": "Uključujući ljude koji su vas pratili manje od {days, plural, one {# dana} few {# dana} other {# dana}}",
   "notifications.policy.filter_not_followers_title": "Ljudi koji vas ne prate",
   "notifications.policy.filter_not_following_hint": "Dok ih ručno ne odobrite",
   "notifications.policy.filter_not_following_title": "Ljudi koje ne pratite",
@@ -483,14 +530,14 @@
   "notifications_permission_banner.title": "Nikada ništa ne propustite",
   "onboarding.action.back": "Vrati me nazad",
   "onboarding.actions.back": "Vrati me nazad",
-  "onboarding.actions.go_to_explore": "Pogledaj šta je u trendu",
-  "onboarding.actions.go_to_home": "Idi na početnu stranicu",
+  "onboarding.actions.go_to_explore": "Odvedi me u trending",
+  "onboarding.actions.go_to_home": "Odvedi me na početnu stranicu",
   "onboarding.compose.template": "Zdravo #Mastodon!",
   "onboarding.follows.empty": "Nažalost, trenutno se ne mogu prikazati rezultati. Možete pokušati sa korišćenjem pretrage ili pregledanjem stranice za istraživanje da biste pronašli ljude koje ćete pratiti ili pokušajte ponovo kasnije.",
-  "onboarding.follows.lead": "Vi sami birate svoju početnu stranicu. Što više ljudi pratite, to će biti aktivnije i zanimljivije. Ovi profili mogu biti dobra polazna tačka—uvek možete da ih prestanete pratiti kasnije!",
+  "onboarding.follows.lead": "Vaša početna stranica je primarni način da doživite Mastodon. Što više ljudi budete pratili, to će biti aktivnije i zanimljivije. Da biste započeli, evo nekoliko predloga:",
   "onboarding.follows.title": "Personalizujte svoju početnu stranicu",
   "onboarding.profile.discoverable": "Neka se moj profil može otkriti drugima",
-  "onboarding.profile.discoverable_hint": "Kada omogućite mogućnost otkrivanja na Mastodon-u, vaše objave se mogu pojaviti u rezultatima pretrage i u trendu, a vaš profil može biti predložen ljudima sa sličnim interesovanjima.",
+  "onboarding.profile.discoverable_hint": "Kada omogućite mogućnost otkrivanja na Mastodon-u, vaše objave se mogu pojaviti u rezultatima pretrage i u trendu, a vaš profil može biti predložen ljudima sa sličnim interesovanjima.",
   "onboarding.profile.display_name": "Ime za prikaz",
   "onboarding.profile.display_name_hint": "Vaše puno ime ili nadimak…",
   "onboarding.profile.lead": "Ovo možete uvek dovršiti kasnije u podešavanjima, gde je dostupno još više opcija prilagođavanja.",
@@ -504,17 +551,17 @@
   "onboarding.share.message": "Ja sam {username} na #Mastodon-u! Pratite me na {url}",
   "onboarding.share.next_steps": "Mogući sledeći koraci:",
   "onboarding.share.title": "Podelite svoj profil",
-  "onboarding.start.lead": "Vaš novi Mastodon nalog je spreman. Evo kako to možete iskoristiti na najbolji način:",
-  "onboarding.start.skip": "Želite da preskočite?",
+  "onboarding.start.lead": "Sada ste deo Mastodon-a, jedinstvene, decentralizovane platforme društvenih medija na kojoj vi – a ne algoritam – birate svoje iskustvo. Hajde da počnemo na ovoj novoj društvenoj granici:",
+  "onboarding.start.skip": "Ne treba vam pomoć za početak?",
   "onboarding.start.title": "Uspeli ste!",
-  "onboarding.steps.follow_people.body": "Vi sami birate svoju početnu stranicu. Hajde da ga ispunimo zanimljivim ljudima.",
+  "onboarding.steps.follow_people.body": "Praćenje zanimljivih ljudi je ono o čemu se radi u Mastodon-u.",
   "onboarding.steps.follow_people.title": "Personalizujte svoju početnu stranicu",
-  "onboarding.steps.publish_status.body": "Reci zdravo svetu.",
+  "onboarding.steps.publish_status.body": "Pozdravite svet tekstom, slikama, video snimcima ili anketama {emoji}",
   "onboarding.steps.publish_status.title": "Napišite svoju prvu objavu",
-  "onboarding.steps.setup_profile.body": "Veća je verovatnoća da će drugi komunicirati sa vama sa popunjenim profilom.",
-  "onboarding.steps.setup_profile.title": "Prilagodite svoj profil",
+  "onboarding.steps.setup_profile.body": "Pojačajte svoje interakcije tako što ćete imati sveobuhvatan profil.",
+  "onboarding.steps.setup_profile.title": "Personalizujte svoj profil",
   "onboarding.steps.share_profile.body": "Neka vaši prijatelji znaju kako da vas pronađu na Mastodon-u!",
-  "onboarding.steps.share_profile.title": "Podelite svoj profil",
+  "onboarding.steps.share_profile.title": "Podelite svoj Mastodon profil",
   "onboarding.tips.2fa": "<strong>Da li ste znali?</strong> Možete da zaštitite svoj nalog podešavanjem dvostruke potvrde identiteta u podešavanjima naloga. Radi sa bilo kojom TOTP aplikacijom po vašem izboru, nije potreban broj telefona!",
   "onboarding.tips.accounts_from_other_servers": "<strong>Da li ste znali?</strong> Pošto je Mastodon decentralizovan, neki profili na koje naiđete biće smešteni na serverima različitim od vašeg. A ipak možete da komunicirate sa njima besprekorno! Njihov server je u drugoj polovini njihovog korisničkog imena!",
   "onboarding.tips.migration": "<strong>Da li ste znali?</strong> Ako smatrate da {domain} nije odličan izbor servera za vas u budućnosti, možete da pređete na drugi Mastodon server bez gubitka pratilaca. Možete čak i da hostujete sopstveni server!",
@@ -539,7 +586,7 @@
   "privacy.private.short": "Pratioci",
   "privacy.public.long": "Bilo ko na Mastodon-u i van njega",
   "privacy.public.short": "Javno",
-  "privacy.unlisted.additional": "Ovo se ponaša potpuno kao javno, osim što se objava neće pojavljivati u izvorima uživo ili heš oznakama, istraživanjima ili pretrazi Mastodon-a, čak i ako ste uključeni u celom nalogu.",
+  "privacy.unlisted.additional": "Ovo se ponaša potpuno kao javno, osim što se objava neće pojavljivati u izvorima uživo ili heš oznakama, istraživanjima ili pretrazi Mastodon-a, čak i ako ste uključeni u celom nalogu.",
   "privacy.unlisted.long": "Manje algoritamskih fanfara",
   "privacy.unlisted.short": "Tiha javnost",
   "privacy_policy.last_updated": "Poslednje ažuriranje {date}",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 17ee71099..69f755a0b 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -220,7 +220,16 @@
   "domain_pill.activitypub_lets_connect": "Омогућује вам да се повежете и комуницирате са људима не само на Mastodon-у, већ и у различитим друштвеним апликацијама.",
   "domain_pill.activitypub_like_language": "ActivityPub је као језик којим Mastodon говори са другим друштвеним мрежама.",
   "domain_pill.server": "Сервер",
+  "domain_pill.their_handle": "Његов регулатор:",
+  "domain_pill.their_server": "Њихов дигитални дом, где живе све њихове објаве.",
+  "domain_pill.their_username": "Њихов јединствени идентификатор на њиховом серверу. Могуће је пронаћи кориснике са истим корисничким именом на различитим серверима.",
   "domain_pill.username": "Корисничко име",
+  "domain_pill.whats_in_a_handle": "Шта је регулатор?",
+  "domain_pill.who_they_are": "Пошто регулатори говоре ко је неко и где се налази, можете да комуницирате са људима широм друштвеног веба на <button>платформама које покреће ActivityPub</button>.",
+  "domain_pill.who_you_are": "Пошто ваши регулатори говори ко сте и где сте, људи могу да комуницирају са вама широм друштвеног веба на <button>платформама које покреће ActivityPub</button>.",
+  "domain_pill.your_handle": "Ваш регулатор:",
+  "domain_pill.your_server": "Ваш дигитални дом, где живе све ваше објаве. Не свиђа вам се овај? Пренесите сервере у било које време и доведите и своје пратиоце.",
+  "domain_pill.your_username": "Њихов јединствени идентификатор на њиховом серверу. Могуће је пронаћи кориснике са истим корисничким именом на различитим серверима.",
   "embed.instructions": "Уградите ову објаву на свој веб сајт копирањем кода испод.",
   "embed.preview": "Ево како ће то изгледати:",
   "emoji_button.activity": "Активности",
@@ -288,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Користите постојећу категорију или креирајте нову",
   "filter_modal.select_filter.title": "Филтрирај ову објаву",
   "filter_modal.title.status": "Филтрирај објаву",
+  "filtered_notifications_banner.mentions": "{count, plural, one {помињање} few {помињања} other {помињања}}",
   "filtered_notifications_banner.pending_requests": "Обавештења од {count, plural, =0 {никога кога можда познајете} one {# особе коју можда познајете} few {# особе које можда познајете} other {# особа које можда познајете}}",
   "filtered_notifications_banner.title": "Филтрирана обавештења",
   "firehose.all": "Све",
@@ -462,7 +472,11 @@
   "notification.own_poll": "Ваша анкета је завршена",
   "notification.poll": "Завршена је анкета у којој сте гласали",
   "notification.reblog": "{name} је подржао вашу објаву",
+  "notification.relationships_severance_event": "Изгубљена веза са {name}",
+  "notification.relationships_severance_event.account_suspension": "Администратор са {from} је суспендовао {target}, што значи да више не можете да примате ажурирања од њих нити да комуницирате са њима.",
+  "notification.relationships_severance_event.domain_block": "Администратор са {from} је блокирао {target}, укључујући ваше пратиоце: {followersCount} и {followingCount, plural, one {# налог} few {# налогa} other {# налога}} које пратите.",
   "notification.relationships_severance_event.learn_more": "Сазнајте више",
+  "notification.relationships_severance_event.user_domain_block": "Блокирачи сте {target}, укључујући ваше пратиоце: {followersCount} и {followingCount, plural, one {# налог} few {# налогa} other {# налога}} које пратите.",
   "notification.status": "{name} је управо објавио",
   "notification.update": "{name} је уредио објаву",
   "notification_requests.accept": "Прихвати",
@@ -476,6 +490,7 @@
   "notifications.column_settings.alert": "Обавештења на радној површини",
   "notifications.column_settings.favourite": "Омиљено:",
   "notifications.column_settings.filter_bar.advanced": "Прикажи све категорије",
+  "notifications.column_settings.filter_bar.category": "Трака за брзо филтрирање",
   "notifications.column_settings.follow": "Нови пратиоци:",
   "notifications.column_settings.follow_request": "Нови захтеви за праћење:",
   "notifications.column_settings.mention": "Помињања:",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 46a6cb794..80c203112 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "Filtrera detta inlägg",
   "filter_modal.title.status": "Filtrera ett inlägg",
   "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {privat omnämnande} other {privat omnämnande}}",
   "filtered_notifications_banner.title": "Filtrerade aviseringar",
   "firehose.all": "Allt",
   "firehose.local": "Denna server",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 952ed5adf..c43bf8581 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "กรองโพสต์นี้",
   "filter_modal.title.status": "กรองโพสต์",
   "filtered_notifications_banner.pending_requests": "การแจ้งเตือนจาก {count, plural, =0 {ไม่มีใคร} other {# คน}} ที่คุณอาจรู้จัก",
-  "filtered_notifications_banner.private_mentions": "{count, plural, other {การกล่าวถึงแบบส่วนตัว}}",
   "filtered_notifications_banner.title": "การแจ้งเตือนที่กรองอยู่",
   "firehose.all": "ทั้งหมด",
   "firehose.local": "เซิร์ฟเวอร์นี้",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 8dcd2d202..76739fe31 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Mevcut bir kategoriyi kullan veya yeni bir tane oluştur",
   "filter_modal.select_filter.title": "Bu gönderiyi süzgeçle",
   "filter_modal.title.status": "Bir gönderi süzgeçle",
+  "filtered_notifications_banner.mentions": "{count, plural, one {bahsetme} other {bahsetme}}",
   "filtered_notifications_banner.pending_requests": "Bildiğiniz {count, plural, =0 {hiç kimseden} one {bir kişiden} other {# kişiden}} bildirim",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {özel değinme} other {özel değinme}}",
   "filtered_notifications_banner.title": "Filtrelenmiş bildirimler",
   "firehose.all": "Tümü",
   "firehose.local": "Bu sunucu",
@@ -468,7 +468,7 @@
   "notification.favourite": "{name} gönderinizi beğendi",
   "notification.follow": "{name} seni takip etti",
   "notification.follow_request": "{name} size takip isteği gönderdi",
-  "notification.mention": "{name} sana değindi",
+  "notification.mention": "{name} senden bahsetti",
   "notification.own_poll": "Anketiniz sona erdi",
   "notification.poll": "Oy verdiğiniz bir anket sona erdi",
   "notification.reblog": "{name} gönderini yeniden paylaştı",
@@ -493,7 +493,7 @@
   "notifications.column_settings.filter_bar.category": "Hızlı filtre çubuğu",
   "notifications.column_settings.follow": "Yeni takipçiler:",
   "notifications.column_settings.follow_request": "Yeni takip istekleri:",
-  "notifications.column_settings.mention": "Değinmeler:",
+  "notifications.column_settings.mention": "Bahsetmeler:",
   "notifications.column_settings.poll": "Anket sonuçları:",
   "notifications.column_settings.push": "Anlık bildirimler",
   "notifications.column_settings.reblog": "Yeniden paylaşanlar:",
@@ -507,7 +507,7 @@
   "notifications.filter.boosts": "Yeniden paylaşımlar",
   "notifications.filter.favourites": "Favorilerin",
   "notifications.filter.follows": "Takip edilenler",
-  "notifications.filter.mentions": "Değinmeler",
+  "notifications.filter.mentions": "Bahsetmeler",
   "notifications.filter.polls": "Anket sonuçları",
   "notifications.filter.statuses": "Takip ettiğiniz kişilerden gelen güncellemeler",
   "notifications.grant_permission": "İzin ver.",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index c593ccc9d..6ae4e162b 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -287,7 +287,6 @@
   "filter_modal.select_filter.title": "Фільтрувати цей допис",
   "filter_modal.title.status": "Фільтрувати допис",
   "filtered_notifications_banner.pending_requests": "Сповіщення від {count, plural, =0 {жодної особи} one {однієї особи} few {# осіб} many {# осіб} other {# особи}}, котрих ви можете знати",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {приватна згадка} few {приватні згадки} many {приватні згадки} other {приватна згадка}}",
   "filtered_notifications_banner.title": "Відфільтровані сповіщення",
   "firehose.all": "Всі",
   "firehose.local": "Цей сервер",
diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json
index 58c025494..e1f886b1f 100644
--- a/app/javascript/mastodon/locales/vi.json
+++ b/app/javascript/mastodon/locales/vi.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "Sử dụng một danh mục hiện có hoặc tạo một danh mục mới",
   "filter_modal.select_filter.title": "Lọc tút này",
   "filter_modal.title.status": "Lọc một tút",
+  "filtered_notifications_banner.mentions": "{count, plural, other {lượt nhắc}}",
   "filtered_notifications_banner.pending_requests": "Thông báo từ {count, plural, =0 {không ai} other {# người}} bạn có thể biết",
-  "filtered_notifications_banner.private_mentions": "{count, plural, other {lượt nhắc}}",
   "filtered_notifications_banner.title": "Thông báo đã lọc",
   "firehose.all": "Toàn bộ",
   "firehose.local": "Máy chủ này",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index ca82c8d7c..83fa72338 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "使用一个已存在类别,或创建一个新类别",
   "filter_modal.select_filter.title": "过滤此嘟文",
   "filter_modal.title.status": "过滤一条嘟文",
+  "filtered_notifications_banner.mentions": "{count, plural, other {提及}}",
   "filtered_notifications_banner.pending_requests": "来自你可能认识的 {count, plural, =0 {0 个人} other {# 个人}}的通知",
-  "filtered_notifications_banner.private_mentions": "{count, plural, other {私下提及}}",
   "filtered_notifications_banner.title": "通知(已过滤)",
   "firehose.all": "全部",
   "firehose.local": "此服务器",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index c5ebf09b1..0b328c738 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -298,7 +298,6 @@
   "filter_modal.select_filter.title": "過濾此帖文",
   "filter_modal.title.status": "過濾一則帖文",
   "filtered_notifications_banner.pending_requests": "來自 {count, plural, =0 {0 位} other {# 位}}你可能認識的人的通知",
-  "filtered_notifications_banner.private_mentions": "{count, plural, one {則私人提及} other {則私人提及}}",
   "filtered_notifications_banner.title": "已過濾之通知",
   "firehose.all": "全部",
   "firehose.local": "本伺服器",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index bf1dfb823..33a7070a5 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -297,8 +297,8 @@
   "filter_modal.select_filter.subtitle": "使用既有的類別或是新增",
   "filter_modal.select_filter.title": "過濾此嘟文",
   "filter_modal.title.status": "過濾一則嘟文",
+  "filtered_notifications_banner.mentions": "{count, plural, other {# 則提及}}",
   "filtered_notifications_banner.pending_requests": "來自您可能認識的 {count, plural, =0 {0 人} other {# 人}} 之通知",
-  "filtered_notifications_banner.private_mentions": "{count, plural, other {# 則私訊}}",
   "filtered_notifications_banner.title": "已過濾之通知",
   "firehose.all": "全部",
   "firehose.local": "本站",
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 8b876b8a1..e0fe9a710 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -609,6 +609,9 @@ sr-Latn:
       actions_description_html: Odlučite koju radnju da sprovedete radi rešavanja ove prijave. Ukoliko sprovedete kaznenu radnju protiv prijavljenog naloga, vlasnik naloga će biti obavešten putem i-mejla, osim ukoliko oznaka <strong>„Nepoželjne poruke”</strong> nije odabrana.
       actions_description_remote_html: Odlučite koju radnju da preduzmete radi rešavanja ove prijave. Ovo će uticati samo na to kako <strong>Vaš</strong> server komunicira sa ovim udaljenim nalogom i obrađuje njegov sadržaj.
       add_to_report: Dodaj još u prijavu
+      already_suspended_badges:
+        local: Već suspendovan na ovom serveru
+        remote: Već suspendovan na njihovom serveru
       are_you_sure: Da li ste sigurni?
       assign_to_self: Dodeli meni
       assigned: Dodeljeni moderator
@@ -1678,13 +1681,26 @@ sr-Latn:
     import: Uvoz
     import_and_export: Uvoz i izvoz
     migrate: Prebacivanje naloga
+    notifications: Obaveštenja e-poštom
     preferences: Podešavanja
     profile: Javni profil
     relationships: Praćenja i pratioci
+    severed_relationships: Prekinute veze
     statuses_cleanup: Automatsko brisanje objava
     strikes: Moderacijski prestupi
     two_factor_authentication: Dvofaktorska identifikacija
     webauthn_authentication: Sigurnosni ključevi
+  severed_relationships:
+    download: Preuzmi (%{count})
+    event_type:
+      account_suspension: Suspenzija naloga (%{target_name})
+      domain_block: Suspenzija servera (%{target_name})
+      user_domain_block: Blokirali ste %{target_name}
+    lost_followers: Izgubljeni pratioci
+    lost_follows: Izgubljena praćenja
+    preamble: Možete izgubiti praćenja i pratioce kada blokirate domen ili kada vaši moderatori odluče da suspenduju udaljeni server. Kada se to desi, moći ćete da preuzmete liste prekinutih veza, koje treba pregledati i eventualno uvesti na drugi server.
+    purged: Administratori vašeg servera su obrisali informacije o ovom serveru.
+    type: Događaj
   statuses:
     attached:
       audio:
@@ -1784,6 +1800,7 @@ sr-Latn:
     contrast: Veliki kontrast
     default: Mastodon (tamna)
     mastodon-light: Mastodon (svetla)
+    system: Automatski (korišćenje sistemske teme)
   time:
     formats:
       default: "%d %b %Y, %H:%M"
@@ -1896,6 +1913,10 @@ sr-Latn:
       follows_subtitle: Pratite dobro poznate naloge
       follows_title: Koga pratiti
       follows_view_more: Pogledajte još ljudi za praćenje
+      hashtags_recent_count:
+        few: "%{people} osobe u poslednja 2 dana"
+        one: "%{people} osoba u poslednja 2 dana"
+        other: "%{people} osoba u poslednja 2 dana"
       hashtags_subtitle: Istražite šta je u trendu u poslednja 2 dana
       hashtags_title: Heš oznake u trendu
       hashtags_view_more: Pogledajte još heš oznaka u trendu
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index faed5854f..1c4ffc8c0 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -609,6 +609,9 @@ sr:
       actions_description_html: Одлучите коју радњу да спроведете ради решавања ове пријаве. Уколико спроведете казнену радњу против пријављеног налога, власник налога ће бити обавештен путем и-мејла, осим уколико ознака <strong>„Непожељне поруке”</strong> није одабрана.
       actions_description_remote_html: Одлучите коју радњу да предузмете ради решавања ове пријаве. Ово ће утицати само на то како <strong>Ваш</strong> сервер комуницира са овим удаљеним налогом и обрађује његов садржај.
       add_to_report: Додај још у пријаву
+      already_suspended_badges:
+        local: Већ суспендован на овом серверу
+        remote: Већ суспендован на њиховом серверу
       are_you_sure: Да ли сте сигурни?
       assign_to_self: Додели мени
       assigned: Додељени модератор
@@ -1678,13 +1681,26 @@ sr:
     import: Увоз
     import_and_export: Увоз и извоз
     migrate: Пребацивање налога
+    notifications: Обавештења е-поштом
     preferences: Подешавања
     profile: Јавни профил
     relationships: Праћења и пратиоци
+    severed_relationships: Прекинуте везе
     statuses_cleanup: Аутоматско брисање објава
     strikes: Модерацијски преступи
     two_factor_authentication: Двофакторска идентификација
     webauthn_authentication: Сигурносни кључеви
+  severed_relationships:
+    download: Преузми (%{count})
+    event_type:
+      account_suspension: Суспензија налога (%{target_name})
+      domain_block: Суспензија сервера (%{target_name})
+      user_domain_block: Блокирали сте %{target_name}
+    lost_followers: Изгубљени пратиоци
+    lost_follows: Изгубљена праћења
+    preamble: Можете изгубити праћења и пратиоце када блокирате домен или када ваши модератори одлуче да суспендују удаљени сервер. Када се то деси, моћи ћете да преузмете листе прекинутих веза, које треба прегледати и евентуално увести на други сервер.
+    purged: Администратори вашег сервера су обрисали информације о овом серверу.
+    type: Догађај
   statuses:
     attached:
       audio:
@@ -1784,6 +1800,7 @@ sr:
     contrast: Велики контраст
     default: Mastodon (тамна)
     mastodon-light: Mastodon (светла)
+    system: Аутоматски (коришћење системске теме)
   time:
     formats:
       default: "%d %b %Y, %H:%M"

From ee8f999a7bdec6092e7e2d4895206614cbd6dca6 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 11:08:08 +0200
Subject: [PATCH 166/173] Update dependency core-js to v3.37.0 (#29968)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index af17402bc..e323b75cb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6312,9 +6312,9 @@ __metadata:
   linkType: hard
 
 "core-js@npm:^3.30.2":
-  version: 3.36.1
-  resolution: "core-js@npm:3.36.1"
-  checksum: 10c0/4f0ad2464535d809ba659226feca15bff14b9b5452518bddff8d81b9c94b0227b3027d9838f22f1dce664958acb4107b935cc0037695ae545edc2a303bca98bf
+  version: 3.37.0
+  resolution: "core-js@npm:3.37.0"
+  checksum: 10c0/7e00331f346318ca3f595c08ce9e74ddae744715aef137486c1399163afd79792fb94c3161280863adfdc3e30f8026912d56bd3036f93cacfc689d33e185f2ee
   languageName: node
   linkType: hard
 

From a3902997440c71f161e392f1ad6c5cdcf6aba95d Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 11:08:19 +0200
Subject: [PATCH 167/173] Update dependency ioredis to v5.4.0 (#29969)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 yarn.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/yarn.lock b/yarn.lock
index e323b75cb..e2f741c5b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9589,8 +9589,8 @@ __metadata:
   linkType: hard
 
 "ioredis@npm:^5.3.2":
-  version: 5.3.2
-  resolution: "ioredis@npm:5.3.2"
+  version: 5.4.0
+  resolution: "ioredis@npm:5.4.0"
   dependencies:
     "@ioredis/commands": "npm:^1.1.1"
     cluster-key-slot: "npm:^1.1.0"
@@ -9601,7 +9601,7 @@ __metadata:
     redis-errors: "npm:^1.2.0"
     redis-parser: "npm:^3.0.0"
     standard-as-callback: "npm:^2.1.0"
-  checksum: 10c0/0dd2b5b8004e891f5b62edf18ac223194f1f5204698ec827c903e789ea05b0b36f73395491749ec63c66470485bdfb228ccdf1714fbf631a0f78f33211f2c883
+  checksum: 10c0/a0214a004928cd35f7103179c8d236a8df609265994d554046fd130446b9989125b7133177936015a31925190f66c90bec4de7303819fe81383dc4576d947d47
   languageName: node
   linkType: hard
 

From 828299e71c127d4406de3add93afa5b28bdb116a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 05:19:02 -0400
Subject: [PATCH 168/173] Enable AR Encryption (#29831)

---
 .env.development                              |  4 +++
 .env.test                                     |  5 ++++
 .github/workflows/test-ruby.yml               |  3 +++
 .gitignore                                    |  1 -
 Dockerfile                                    |  7 ++++-
 .../initializers/active_record_encryption.rb  | 26 +++++++++++++++++++
 lib/tasks/mastodon.rake                       |  9 +++++++
 7 files changed, 53 insertions(+), 2 deletions(-)
 create mode 100644 .env.development
 create mode 100644 config/initializers/active_record_encryption.rb

diff --git a/.env.development b/.env.development
new file mode 100644
index 000000000..0330da837
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,4 @@
+# Required by ActiveRecord encryption feature
+ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR
+ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E
+ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr
diff --git a/.env.test b/.env.test
index 2f8c1afd6..9e6abea5c 100644
--- a/.env.test
+++ b/.env.test
@@ -3,3 +3,8 @@ NODE_ENV=production
 # Federation
 LOCAL_DOMAIN=cb6e6126.ngrok.io
 LOCAL_HTTPS=true
+
+# Required by ActiveRecord encryption feature
+ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR
+ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E
+ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr
diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml
index 172b5271d..3a78f8b43 100644
--- a/.github/workflows/test-ruby.yml
+++ b/.github/workflows/test-ruby.yml
@@ -28,6 +28,9 @@ jobs:
     env:
       RAILS_ENV: ${{ matrix.mode }}
       BUNDLE_WITH: ${{ matrix.mode }}
+      ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: precompile_placeholder
+      ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: precompile_placeholder
+      ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: precompile_placeholder
       OTP_SECRET: precompile_placeholder
       SECRET_KEY_BASE: precompile_placeholder
 
diff --git a/.gitignore b/.gitignore
index c5af8eb67..2f94b751a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,7 +24,6 @@
 /public/packs-test
 .env
 .env.production
-.env.development
 /node_modules/
 /build/
 
diff --git a/Dockerfile b/Dockerfile
index 1b007930e..43bc24295 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -205,7 +205,12 @@ ARG TARGETPLATFORM
 
 RUN \
 # Use Ruby on Rails to create Mastodon assets
-  OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
+  ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=precompile_placeholder \
+  ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=precompile_placeholder \
+  ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=precompile_placeholder \
+  OTP_SECRET=precompile_placeholder \
+  SECRET_KEY_BASE=precompile_placeholder \
+  bundle exec rails assets:precompile; \
 # Cleanup temporary files
   rm -fr /opt/mastodon/tmp;
 
diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb
new file mode 100644
index 000000000..f99585b4a
--- /dev/null
+++ b/config/initializers/active_record_encryption.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+%w(
+  ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
+  ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
+  ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
+).each do |key|
+  ENV.fetch(key) do
+    raise <<~MESSAGE
+
+      The ActiveRecord encryption feature requires that these variables are set:
+
+        - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
+        - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
+        - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
+
+      Run `bin/rails db:encryption:init` to generate values and then assign the environment variables.
+    MESSAGE
+  end
+end
+
+Rails.application.configure do
+  config.active_record.encryption.deterministic_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY')
+  config.active_record.encryption.key_derivation_salt = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT')
+  config.active_record.encryption.primary_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY')
+end
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index cb364b302..2822f2eeb 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -36,6 +36,15 @@ namespace :mastodon do
         env[key] = SecureRandom.hex(64)
       end
 
+      # Required by ActiveRecord encryption feature
+      %w(
+        ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
+        ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
+        ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
+      ).each do |key|
+        env[key] = SecureRandom.alphanumeric(32)
+      end
+
       vapid_key = Webpush.generate_key
 
       env['VAPID_PRIVATE_KEY'] = vapid_key.private_key

From 1d3ecd3fbaf15450890c1ece7955846fba82a58d Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 05:22:45 -0400
Subject: [PATCH 169/173] Add `API::Pagination` concern (#28826)

---
 app/controllers/api/base_controller.rb     | 28 +----------------
 app/controllers/concerns/api/pagination.rb | 36 ++++++++++++++++++++++
 2 files changed, 37 insertions(+), 27 deletions(-)
 create mode 100644 app/controllers/concerns/api/pagination.rb

diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index f87d596ce..c1a5e43f8 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -9,6 +9,7 @@ class Api::BaseController < ApplicationController
   include Api::CachingConcern
   include Api::ContentSecurityPolicy
   include Api::ErrorHandling
+  include Api::Pagination
 
   skip_before_action :require_functional!, unless: :limited_federation_mode?
 
@@ -29,21 +30,6 @@ class Api::BaseController < ApplicationController
 
   protected
 
-  def pagination_max_id
-    pagination_collection.last.id
-  end
-
-  def pagination_since_id
-    pagination_collection.first.id
-  end
-
-  def set_pagination_headers(next_path = nil, prev_path = nil)
-    links = []
-    links << [next_path, [%w(rel next)]] if next_path
-    links << [prev_path, [%w(rel prev)]] if prev_path
-    response.headers['Link'] = LinkHeader.new(links) unless links.empty?
-  end
-
   def limit_param(default_limit)
     return default_limit unless params[:limit]
 
@@ -72,10 +58,6 @@ class Api::BaseController < ApplicationController
     render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.unavailable?
   end
 
-  def require_valid_pagination_options!
-    render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid?
-  end
-
   def require_user!
     if !current_user
       render json: { error: 'This method requires an authenticated user' }, status: 422
@@ -104,14 +86,6 @@ class Api::BaseController < ApplicationController
 
   private
 
-  def insert_pagination_headers
-    set_pagination_headers(next_path, prev_path)
-  end
-
-  def pagination_options_invalid?
-    params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
-  end
-
   def respond_with_error(code)
     render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code
   end
diff --git a/app/controllers/concerns/api/pagination.rb b/app/controllers/concerns/api/pagination.rb
new file mode 100644
index 000000000..d84a1d99f
--- /dev/null
+++ b/app/controllers/concerns/api/pagination.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Api::Pagination
+  extend ActiveSupport::Concern
+
+  protected
+
+  def pagination_max_id
+    pagination_collection.last.id
+  end
+
+  def pagination_since_id
+    pagination_collection.first.id
+  end
+
+  def set_pagination_headers(next_path = nil, prev_path = nil)
+    links = []
+    links << [next_path, [%w(rel next)]] if next_path
+    links << [prev_path, [%w(rel prev)]] if prev_path
+    response.headers['Link'] = LinkHeader.new(links) unless links.empty?
+  end
+
+  def require_valid_pagination_options!
+    render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid?
+  end
+
+  private
+
+  def insert_pagination_headers
+    set_pagination_headers(next_path, prev_path)
+  end
+
+  def pagination_options_invalid?
+    params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
+  end
+end

From 650c548c31b993990f38c9a29570bf7c82e4b15e Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 06:05:38 -0400
Subject: [PATCH 170/173] Add `not_featured_by` scope to Tag (#28815)

---
 .../featured_tags/suggestions_controller.rb   |  6 +-----
 .../settings/featured_tags_controller.rb      |  2 +-
 app/models/tag.rb                             |  2 ++
 spec/models/tag_spec.rb                       | 19 +++++++++++++++++++
 4 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/app/controllers/api/v1/featured_tags/suggestions_controller.rb b/app/controllers/api/v1/featured_tags/suggestions_controller.rb
index 4f732ed2d..9c72e4380 100644
--- a/app/controllers/api/v1/featured_tags/suggestions_controller.rb
+++ b/app/controllers/api/v1/featured_tags/suggestions_controller.rb
@@ -12,10 +12,6 @@ class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
   private
 
   def set_recently_used_tags
-    @recently_used_tags = Tag.recently_used(current_account).where.not(id: featured_tag_ids).limit(10)
-  end
-
-  def featured_tag_ids
-    current_account.featured_tags.pluck(:tag_id)
+    @recently_used_tags = Tag.suggestions_for_account(current_account).limit(10)
   end
 end
diff --git a/app/controllers/settings/featured_tags_controller.rb b/app/controllers/settings/featured_tags_controller.rb
index c38440265..90c112e21 100644
--- a/app/controllers/settings/featured_tags_controller.rb
+++ b/app/controllers/settings/featured_tags_controller.rb
@@ -38,7 +38,7 @@ class Settings::FeaturedTagsController < Settings::BaseController
   end
 
   def set_recently_used_tags
-    @recently_used_tags = Tag.recently_used(current_account).where.not(id: @featured_tags.map(&:id)).limit(10)
+    @recently_used_tags = Tag.suggestions_for_account(current_account).limit(10)
   end
 
   def featured_tag_params
diff --git a/app/models/tag.rb b/app/models/tag.rb
index f2168ae90..58baa48c0 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -53,6 +53,8 @@ class Tag < ApplicationRecord
   scope :listable, -> { where(listable: [true, nil]) }
   scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) }
   scope :not_trendable, -> { where(trendable: false) }
+  scope :suggestions_for_account, ->(account) { recently_used(account).not_featured_by(account) }
+  scope :not_featured_by, ->(account) { where.not(id: account.featured_tags.select(:tag_id)) }
   scope :recently_used, lambda { |account|
                           joins(:statuses)
                             .where(statuses: { id: account.statuses.select(:id).limit(RECENT_STATUS_LIMIT) })
diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb
index 5a1d62088..4c2bdd52f 100644
--- a/spec/models/tag_spec.rb
+++ b/spec/models/tag_spec.rb
@@ -142,6 +142,25 @@ RSpec.describe Tag do
     end
   end
 
+  describe '.not_featured_by' do
+    let!(:account) { Fabricate(:account) }
+    let!(:fun) { Fabricate(:tag, name: 'fun') }
+    let!(:games) { Fabricate(:tag, name: 'games') }
+
+    before do
+      Fabricate :featured_tag, account: account, name: 'games'
+      Fabricate :featured_tag, name: 'fun'
+    end
+
+    it 'returns tags not featured by the account' do
+      results = described_class.not_featured_by(account)
+
+      expect(results)
+        .to include(fun)
+        .and not_include(games)
+    end
+  end
+
   describe '.matches_name' do
     it 'returns tags for multibyte case-insensitive names' do
       upcase_string   = 'abcABCabcABCやゆよ'

From 013671f29f3ebe791078d9e1ea92950a608d0ecb Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 17 Apr 2024 06:23:07 -0400
Subject: [PATCH 171/173] Rename JS testing section in GH Actions config
 (#29931)

---
 .github/workflows/test-js.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml
index 79622b6c1..481afdba3 100644
--- a/.github/workflows/test-js.yml
+++ b/.github/workflows/test-js.yml
@@ -38,5 +38,5 @@ jobs:
       - name: Set up Javascript environment
         uses: ./.github/actions/setup-javascript
 
-      - name: Jest testing
+      - name: JavaScript testing
         run: yarn jest --reporters github-actions summary

From 8bece467f821e587208284188d8c517118cd87b0 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 17 Apr 2024 13:13:52 +0200
Subject: [PATCH 172/173] Change `have_enqueued_sidekiq_job` usage to always
 make argument expectations explicit (#29974)

---
 spec/services/create_featured_tag_service_spec.rb | 2 +-
 spec/services/unmute_service_spec.rb              | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/spec/services/create_featured_tag_service_spec.rb b/spec/services/create_featured_tag_service_spec.rb
index 29a7c5b30..f057bc853 100644
--- a/spec/services/create_featured_tag_service_spec.rb
+++ b/spec/services/create_featured_tag_service_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe CreateFeaturedTagService do
         expect { subject.call(account, tag) }
           .to change(FeaturedTag, :count).by(1)
         expect(ActivityPub::AccountRawDistributionWorker)
-          .to_not have_enqueued_sidekiq_job
+          .to_not have_enqueued_sidekiq_job(any_args)
       end
     end
   end
diff --git a/spec/services/unmute_service_spec.rb b/spec/services/unmute_service_spec.rb
index 00135b5ac..92c7a70d6 100644
--- a/spec/services/unmute_service_spec.rb
+++ b/spec/services/unmute_service_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe UnmuteService do
         it 'removes the account mute and does not create a merge' do
           expect { subject.call(account, target_account) }
             .to remove_account_mute
-          expect(MergeWorker).to_not have_enqueued_sidekiq_job
+          expect(MergeWorker).to_not have_enqueued_sidekiq_job(any_args)
         end
       end
 
@@ -39,7 +39,7 @@ RSpec.describe UnmuteService do
       it 'does nothing and returns' do
         expect { subject.call(account, target_account) }
           .to_not(change { account.reload.muting?(target_account) })
-        expect(MergeWorker).to_not have_enqueued_sidekiq_job
+        expect(MergeWorker).to_not have_enqueued_sidekiq_job(any_args)
       end
     end
   end

From 1ad119941ff672b93f2b04dc29f82443349bb69c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 13:14:09 +0200
Subject: [PATCH 173/173] Update dependency rspec-sidekiq to v4.2.0 (#29964)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index ffeeebe9d..752d4e05e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -640,7 +640,7 @@ GEM
       rspec-expectations (~> 3.13)
       rspec-mocks (~> 3.13)
       rspec-support (~> 3.13)
-    rspec-sidekiq (4.1.0)
+    rspec-sidekiq (4.2.0)
       rspec-core (~> 3.0)
       rspec-expectations (~> 3.0)
       rspec-mocks (~> 3.0)