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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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/223] 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)

From 630572323f95b382c552d18fa8bba23898cbd9c3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 17 Apr 2024 23:52:26 +0200
Subject: [PATCH 174/223] Update dependency ioredis to v5.4.1 (#29977)

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 e2f741c5b..bf217a074 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9589,8 +9589,8 @@ __metadata:
   linkType: hard
 
 "ioredis@npm:^5.3.2":
-  version: 5.4.0
-  resolution: "ioredis@npm:5.4.0"
+  version: 5.4.1
+  resolution: "ioredis@npm:5.4.1"
   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/a0214a004928cd35f7103179c8d236a8df609265994d554046fd130446b9989125b7133177936015a31925190f66c90bec4de7303819fe81383dc4576d947d47
+  checksum: 10c0/5d28b7c89a3cab5b76d75923d7d4ce79172b3a1ca9be690133f6e8e393a7a4b4ffd55513e618bbb5504fed80d9e1395c9d9531a7c5c5c84aa4c4e765cca75456
   languageName: node
   linkType: hard
 

From 11e0049b08c721eb98d8220405c2ffc16041ed17 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 18 Apr 2024 06:13:35 -0400
Subject: [PATCH 175/223] Use enum-generated scopes/queries for `BulkImport`
 (#29975)

---
 app/controllers/settings/imports_controller.rb | 4 ++--
 app/lib/vacuum/imports_vacuum.rb               | 2 +-
 app/models/bulk_import.rb                      | 2 +-
 app/views/settings/imports/index.html.haml     | 4 ++--
 spec/models/form/import_spec.rb                | 2 +-
 spec/services/bulk_import_service_spec.rb      | 4 ++--
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/app/controllers/settings/imports_controller.rb b/app/controllers/settings/imports_controller.rb
index 983caf22f..569aa07c5 100644
--- a/app/controllers/settings/imports_controller.rb
+++ b/app/controllers/settings/imports_controller.rb
@@ -31,7 +31,7 @@ class Settings::ImportsController < Settings::BaseController
   def show; end
 
   def failures
-    @bulk_import = current_account.bulk_imports.where(state: :finished).find(params[:id])
+    @bulk_import = current_account.bulk_imports.state_finished.find(params[:id])
 
     respond_to do |format|
       format.csv do
@@ -92,7 +92,7 @@ class Settings::ImportsController < Settings::BaseController
   end
 
   def set_bulk_import
-    @bulk_import = current_account.bulk_imports.where(state: :unconfirmed).find(params[:id])
+    @bulk_import = current_account.bulk_imports.state_unconfirmed.find(params[:id])
   end
 
   def set_recent_imports
diff --git a/app/lib/vacuum/imports_vacuum.rb b/app/lib/vacuum/imports_vacuum.rb
index ffb9449a4..8c8bb783a 100644
--- a/app/lib/vacuum/imports_vacuum.rb
+++ b/app/lib/vacuum/imports_vacuum.rb
@@ -9,7 +9,7 @@ class Vacuum::ImportsVacuum
   private
 
   def clean_unconfirmed_imports!
-    BulkImport.where(state: :unconfirmed).where('created_at <= ?', 10.minutes.ago).reorder(nil).in_batches.delete_all
+    BulkImport.state_unconfirmed.where('created_at <= ?', 10.minutes.ago).reorder(nil).in_batches.delete_all
   end
 
   def clean_old_imports!
diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb
index 4cd228705..9b3f4c8a3 100644
--- a/app/models/bulk_import.rb
+++ b/app/models/bulk_import.rb
@@ -38,7 +38,7 @@ class BulkImport < ApplicationRecord
     scheduled: 1,
     in_progress: 2,
     finished: 3,
-  }
+  }, prefix: true
 
   validates :type, presence: true
 
diff --git a/app/views/settings/imports/index.html.haml b/app/views/settings/imports/index.html.haml
index d5ca252dc..ca815720f 100644
--- a/app/views/settings/imports/index.html.haml
+++ b/app/views/settings/imports/index.html.haml
@@ -49,7 +49,7 @@
           %tr
             %td= t("imports.types.#{import.type}")
             %td
-              - if import.unconfirmed?
+              - if import.state_unconfirmed?
                 = link_to t("imports.states.#{import.state}"), settings_import_path(import)
               - else
                 = t("imports.states.#{import.state}")
@@ -59,7 +59,7 @@
             %td
               - num_failed = import.processed_items - import.imported_items
               - if num_failed.positive?
-                - if import.finished?
+                - if import.state_finished?
                   = link_to num_failed, failures_settings_import_path(import, format: 'csv')
                 - else
                   = num_failed
diff --git a/spec/models/form/import_spec.rb b/spec/models/form/import_spec.rb
index c2f41d442..22ffdfd87 100644
--- a/spec/models/form/import_spec.rb
+++ b/spec/models/form/import_spec.rb
@@ -281,7 +281,7 @@ RSpec.describe Form::Import do
         end
 
         it 'defaults to unconfirmed true' do
-          expect(bulk_import.unconfirmed?).to be true
+          expect(bulk_import.state_unconfirmed?).to be true
         end
       end
     end
diff --git a/spec/services/bulk_import_service_spec.rb b/spec/services/bulk_import_service_spec.rb
index c3a716058..e8bec96c8 100644
--- a/spec/services/bulk_import_service_spec.rb
+++ b/spec/services/bulk_import_service_spec.rb
@@ -291,7 +291,7 @@ RSpec.describe BulkImportService do
 
       it 'marks the import as finished' do
         subject.call(import)
-        expect(import.reload.finished?).to be true
+        expect(import.reload.state_finished?).to be true
       end
     end
 
@@ -319,7 +319,7 @@ RSpec.describe BulkImportService do
 
       it 'marks the import as finished' do
         subject.call(import)
-        expect(import.reload.finished?).to be true
+        expect(import.reload.state_finished?).to be true
       end
     end
 

From 443186ff405112520e95836916eb2731b6a64c03 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 18 Apr 2024 13:18:39 +0200
Subject: [PATCH 176/223] New Crowdin Translations (automated) (#29980)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/en-GB.json | 50 ++++++++++++
 app/javascript/mastodon/locales/es-MX.json |  1 +
 app/javascript/mastodon/locales/es.json    |  1 +
 app/javascript/mastodon/locales/ia.json    | 91 ++++++++++++++++++++++
 config/locales/cs.yml                      | 56 +++++++++++++
 config/locales/eu.yml                      |  4 +-
 config/locales/simple_form.cs.yml          |  2 +
 7 files changed, 203 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json
index 80a3479b4..6c24d5a26 100644
--- a/app/javascript/mastodon/locales/en-GB.json
+++ b/app/javascript/mastodon/locales/en-GB.json
@@ -209,6 +209,27 @@
   "dismissable_banner.explore_statuses": "These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favourites are ranked higher.",
   "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralised network right now.",
   "dismissable_banner.public_timeline": "These are the most recent public posts from people on the social web that people on {domain} follow.",
+  "domain_block_modal.block": "Block server",
+  "domain_block_modal.block_account_instead": "Block @{name} instead",
+  "domain_block_modal.they_can_interact_with_old_posts": "People from this server can interact with your old posts.",
+  "domain_block_modal.they_cant_follow": "Nobody from this server can follow you.",
+  "domain_block_modal.they_wont_know": "They won't know they've been blocked.",
+  "domain_block_modal.title": "Block domain?",
+  "domain_block_modal.you_will_lose_followers": "All your followers from this server will be removed.",
+  "domain_block_modal.you_wont_see_posts": "You won't see posts or notifications from users on this server.",
+  "domain_pill.activitypub_lets_connect": "It lets you connect and interact with people not just on Mastodon, but across different social apps too.",
+  "domain_pill.activitypub_like_language": "ActivityPub is like the language Mastodon speaks with other social networks.",
+  "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Their handle:",
+  "domain_pill.their_server": "Their digital home, where all of their posts live.",
+  "domain_pill.their_username": "Their unique identifier on their server. It’s possible to find users with the same username on different servers.",
+  "domain_pill.username": "Username",
+  "domain_pill.whats_in_a_handle": "What's in a handle?",
+  "domain_pill.who_they_are": "Since handles say who someone is and where they are, you can interact with people across the social web of <button>ActivityPub-powered platforms</button>.",
+  "domain_pill.who_you_are": "Because your handle says who you are and where you are, people can interact with you across the social web of <button>ActivityPub-powered platforms</button>.",
+  "domain_pill.your_handle": "Your handle:",
+  "domain_pill.your_server": "Your digital home, where all of your posts live. Don’t like this one? Transfer servers at any time and bring your followers, too.",
+  "domain_pill.your_username": "Your unique identifier on this server. It’s possible to find users with the same username on different servers.",
   "embed.instructions": "Embed this post on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
@@ -245,6 +266,7 @@
   "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
   "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
   "empty_column.mutes": "You haven't muted any users yet.",
+  "empty_column.notification_requests": "All clear! There is nothing here. When you receive new notifications, they will appear here according to your settings.",
   "empty_column.notifications": "You don't have any notifications yet. When other people interact with you, you will see it here.",
   "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up",
   "error.unexpected_crash.explanation": "Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.",
@@ -275,13 +297,22 @@
   "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.title": "Filtered notifications",
   "firehose.all": "All",
   "firehose.local": "This server",
   "firehose.remote": "Other servers",
   "follow_request.authorize": "Authorise",
   "follow_request.reject": "Reject",
   "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.",
+  "follow_suggestions.curated_suggestion": "Staff pick",
   "follow_suggestions.dismiss": "Don't show again",
+  "follow_suggestions.hints.featured": "This profile has been hand-picked by the {domain} team.",
+  "follow_suggestions.hints.friends_of_friends": "This profile is popular among the people you follow.",
+  "follow_suggestions.hints.most_followed": "This profile is one of the most followed on {domain}.",
+  "follow_suggestions.hints.most_interactions": "This profile has been recently getting a lot of attention on {domain}.",
+  "follow_suggestions.hints.similar_to_recently_followed": "This profile is similar to the profiles you have most recently followed.",
   "follow_suggestions.personalized_suggestion": "Personalised suggestion",
   "follow_suggestions.popular_suggestion": "Popular suggestion",
   "follow_suggestions.view_all": "View all",
@@ -397,6 +428,15 @@
   "loading_indicator.label": "Loading…",
   "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}",
   "moved_to_account_banner.text": "Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.",
+  "mute_modal.hide_from_notifications": "Hide from notifications",
+  "mute_modal.hide_options": "Hide options",
+  "mute_modal.indefinite": "Until I unmute them",
+  "mute_modal.show_options": "Show options",
+  "mute_modal.they_can_mention_and_follow": "They can mention and follow you, but you won't see them.",
+  "mute_modal.they_wont_know": "They won't know they've been muted.",
+  "mute_modal.title": "Mute user?",
+  "mute_modal.you_wont_see_mentions": "You won't see posts that mention them.",
+  "mute_modal.you_wont_see_posts": "They can still see your posts, but you won't see theirs.",
   "navigation_bar.about": "About",
   "navigation_bar.advanced_interface": "Open in advanced web interface",
   "navigation_bar.blocks": "Blocked users",
@@ -432,14 +472,24 @@
   "notification.own_poll": "Your poll has ended",
   "notification.poll": "A poll you have voted in has ended",
   "notification.reblog": "{name} boosted your status",
+  "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",
+  "notification_requests.dismiss": "Dismiss",
+  "notification_requests.notifications_from": "Notifications from {name}",
+  "notification_requests.title": "Filtered notifications",
   "notifications.clear": "Clear notifications",
   "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
   "notifications.column_settings.admin.report": "New reports:",
   "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.advanced": "Display all categories",
   "notifications.column_settings.filter_bar.category": "Quick filter bar",
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.follow_request": "New follow requests:",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index fd32d9d90..1d8d4cedf 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Usar una categoría existente o crear una nueva",
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
+  "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.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 9c15a3cae..68e5349a5 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Usar una categoría existente o crear una nueva",
   "filter_modal.select_filter.title": "Filtrar esta publicación",
   "filter_modal.title.status": "Filtrar una publicación",
+  "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.title": "Notificaciones filtradas",
   "firehose.all": "Todas",
diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index af28f9ce3..e0ae8b58c 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -42,6 +42,7 @@
   "account.go_to_profile": "Vader al profilo",
   "account.hide_reblogs": "Celar impulsos de @{name}",
   "account.in_memoriam": "In memoriam.",
+  "account.joined_short": "Inscribite",
   "account.languages": "Cambiar le linguas subscribite",
   "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.",
@@ -52,10 +53,12 @@
   "account.mute_notifications_short": "Silentiar le notificationes",
   "account.mute_short": "Silentiar",
   "account.muted": "Silentiate",
+  "account.mutual": "Mutue",
   "account.no_bio": "Nulle description fornite.",
   "account.open_original_page": "Aperir le pagina original",
   "account.posts": "Messages",
   "account.posts_with_replies": "Messages e responsas",
+  "account.report": "Signalar @{name}",
   "account.requested": "Attendente le approbation. Clicca pro cancellar le requesta de sequer",
   "account.requested_follow": "{name} ha requestate de sequer te",
   "account.share": "Compartir profilo de @{name}",
@@ -70,29 +73,48 @@
   "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.daily_retention": "Retention de usatores per die post inscription",
+  "admin.dashboard.monthly_retention": "Retention de usatores per mense post inscription",
   "admin.dashboard.retention.average": "Media",
+  "admin.dashboard.retention.cohort": "Mense de inscription",
   "admin.dashboard.retention.cohort_size": "Nove usatores",
+  "admin.impact_report.instance_accounts": "Numero de contos que isto delerea",
   "admin.impact_report.instance_followers": "Sequitores que nostre usatores perderea",
   "admin.impact_report.instance_follows": "Sequitores que lor usatores perderea",
+  "admin.impact_report.title": "Summario de impacto",
   "alert.rate_limited.message": "Per favor retenta post {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Excesso de requestas",
   "alert.unexpected.message": "Un error inexpectate ha occurrite.",
+  "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Annuncio",
+  "attachments_list.unprocessed": "(non processate)",
   "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_mention": "Le persona non pote mentionar te o sequer te.",
   "block_modal.they_cant_see_posts": "Iste persona non potera vider tu messages e tu non videra le sues.",
+  "block_modal.they_will_know": "Le persona pote saper de esser blocate.",
   "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.copy_stacktrace": "Copiar reporto de error",
+  "bundle_column_error.error.body": "Le pagina requestate non pote esser visualisate. Pote esser a causa de un defecto in nostre codice o de un problema de compatibilitate del navigator.",
   "bundle_column_error.error.title": "Oh, no!",
+  "bundle_column_error.network.body": "Un error ha occurrite durante le cargamento de iste pagina. Isto pote esser a causa de un problema temporari con tu connexion a internet o con iste servitor.",
   "bundle_column_error.network.title": "Error de rete",
   "bundle_column_error.retry": "Tentar novemente",
   "bundle_column_error.return": "Retornar al initio",
+  "bundle_column_error.routing.body": "Le pagina requestate non pote esser trovate. Es tu secur que le URL in le barra de adresse es correcte?",
+  "bundle_column_error.routing.title": "404",
   "bundle_modal_error.close": "Clauder",
+  "bundle_modal_error.message": "Un error ha occurrite durante le cargamento de iste componente.",
   "bundle_modal_error.retry": "Tentar novemente",
+  "closed_registrations.other_server_instructions": "Perque Mastodon es decentralisate, tu pote crear un conto sur un altere servitor e totevia interager con iste servitor.",
   "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",
+  "closed_registrations_modal.preamble": "Mastodon es decentralisate, dunque, non importa ubi tu crea tu conto, tu pote sequer e communicar con omne persona sur iste servitor. Tu pote mesmo hospitar tu proprie servitor!",
+  "closed_registrations_modal.title": "Crear un conto sur Mastodon",
   "column.about": "A proposito",
   "column.blocks": "Usatores blocate",
   "column.bookmarks": "Marcapaginas",
@@ -102,6 +124,7 @@
   "column.domain_blocks": "Dominios blocate",
   "column.favourites": "Favoritos",
   "column.firehose": "Fluxos in directo",
+  "column.follow_requests": "Requestas de sequimento",
   "column.home": "Initio",
   "column.lists": "Listas",
   "column.mutes": "Usatores silentiate",
@@ -112,10 +135,13 @@
   "column_header.hide_settings": "Celar le parametros",
   "column_header.moveLeft_settings": "Mover columna al sinistra",
   "column_header.moveRight_settings": "Mover columna al dextra",
+  "column_header.pin": "Fixar",
   "column_header.show_settings": "Monstrar le parametros",
+  "column_header.unpin": "Disfixar",
   "column_subheading.settings": "Parametros",
   "community.column_settings.local_only": "Solmente local",
   "community.column_settings.media_only": "Solmente multimedia",
+  "community.column_settings.remote_only": "A distantia solmente",
   "compose.language.change": "Cambiar le lingua",
   "compose.language.search": "Cercar linguas...",
   "compose.published.body": "Message publicate.",
@@ -126,6 +152,7 @@
   "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.placeholder": "Que ha tu in mente?",
   "compose_form.poll.duration": "Durata del sondage",
   "compose_form.poll.multiple": "Selection multiple",
   "compose_form.poll.option_placeholder": "Option {number}",
@@ -148,13 +175,19 @@
   "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.discard_edit_media.confirm": "Abandonar",
+  "confirmations.discard_edit_media.message": "Tu ha cambiamentos non salvate in le description o previsualisation del objecto multimedial. Abandonar los?",
   "confirmations.domain_block.confirm": "Blocar le servitor",
+  "confirmations.domain_block.message": "Es tu realmente, absolutemente secur de voler blocar tote le dominio {domain}? In le major parte del casos es preferibile blocar o silentiar alcun personas specific. Si tu bloca tote le dominio, tu non videra alcun contento de ille dominio in alcun chronologia public o in tu notificationes, e tu sequitores de ille dominio essera removite.",
   "confirmations.edit.confirm": "Modificar",
+  "confirmations.edit.message": "Si tu modifica isto ora, le message in curso de composition essera perdite. Es tu secur de voler continuar?",
   "confirmations.logout.confirm": "Clauder session",
   "confirmations.logout.message": "Es tu secur que tu vole clauder le session?",
   "confirmations.mute.confirm": "Silentiar",
+  "confirmations.redraft.confirm": "Deler e rescriber",
   "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.reply.message": "Si tu responde ora, le message in curso de composition essera perdite. Es tu secur de voler continuar?",
   "confirmations.unfollow.confirm": "Non plus sequer",
   "confirmations.unfollow.message": "Es tu secur que tu vole cessar de sequer {name}?",
   "conversation.delete": "Deler conversation",
@@ -174,6 +207,7 @@
   "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.explore_tags": "Ecce le hashtags que gania popularitate sur le rete social hodie. Le hashtags usate per plus personas differente 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",
@@ -183,10 +217,19 @@
   "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.activitypub_lets_connect": "Illo te permitte connecter e interager con personas non solmente sur Mastodon, ma tamben sur altere applicationes social.",
+  "domain_pill.activitypub_like_language": "ActivityPub es como le linguage commun que Mastodon parla con altere retes social.",
   "domain_pill.server": "Servitor",
+  "domain_pill.their_handle": "Su pseudonymo:",
   "domain_pill.their_server": "Su casa digital, ubi vive tote su messages.",
+  "domain_pill.their_username": "Su identificator unic sur su servitor. Es possibile trovar usatores con le mesme nomine de usator sur servitores differente.",
   "domain_pill.username": "Nomine de usator",
+  "domain_pill.whats_in_a_handle": "Que significa un pseudonymo?",
+  "domain_pill.who_they_are": "Un pseudonymo indica qui un persona es e ubi se trova, de maniera que tu pote interager con personas sur tote le rete social de <button>platteformas basate sur ActivityPub</button>.",
+  "domain_pill.who_you_are": "Perque tu pseudonymo indica qui tu es e ubi tu te trova, le gente pote interager con te desde tote le rete social de <button>platteformas basate sur ActivityPub</button>.",
+  "domain_pill.your_handle": "Tu pseudonymo:",
   "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.",
+  "domain_pill.your_username": "Tu identificator unic sur iste servitor. Es possibile trovar usatores con le mesme nomine de usator sur servitores differente.",
   "embed.instructions": "Incorpora iste message sur tu sito web con le codice sequente.",
   "embed.preview": "Ecce como illlo parera:",
   "emoji_button.activity": "Activitate",
@@ -196,6 +239,8 @@
   "emoji_button.food": "Alimentos e bibitas",
   "emoji_button.label": "Inserer emoji",
   "emoji_button.nature": "Natura",
+  "emoji_button.not_found": "Necun emoji correspondente trovate",
+  "emoji_button.objects": "Objectos",
   "emoji_button.people": "Personas",
   "emoji_button.recent": "Frequentemente usate",
   "emoji_button.search": "Cercar...",
@@ -208,14 +253,27 @@
   "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.community": "Le chronologia local es vacue. Scribe qualcosa public pro poner le cosas in marcha!",
+  "empty_column.direct": "Tu non ha ancora mentiones private. Quando tu invia o recipe un mention, 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.follow_requests": "Tu non ha ancora requestas de sequimento. Quando tu recipe un, 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.",
   "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.",
+  "empty_column.lists": "Tu non ha ancora listas. Quando tu crea un, illo apparera hic.",
+  "empty_column.mutes": "Tu non ha ancora silentiate alcun usator.",
+  "empty_column.notification_requests": "Iste lista es toto vacue! Quando tu recipe notificationes, illos apparera hic como configurate in tu parametros.",
+  "empty_column.notifications": "Tu non ha ancora notificationes. Quando altere personas interage con te, tu lo videra hic.",
+  "empty_column.public": "Il ha nihil hic! Scribe qualcosa public, o manualmente seque usatores de altere servitores, pro plenar lo",
+  "error.unexpected_crash.explanation": "A causa de un defecto in nostre codice o de un problema de compatibilitate del navigator, iste pagina non pote esser visualisate correctemente.",
+  "error.unexpected_crash.explanation_addons": "Iste pagina non pote esser visualisate correctemente. Iste error es probabilemente causate per un additivo al navigator o per un utensile de traduction automatic.",
+  "error.unexpected_crash.next_steps": "Tenta refrescar le pagina. Si isto non remedia le problema, es possibile que tu pote totevia usar Mastodon per medio de un altere navigator o application native.",
+  "error.unexpected_crash.next_steps_addons": "Tenta disactivar istes e refrescar le pagina. Si isto non remedia le problema, es possibile que tu pote totevia usar Mastodon per medio de un altere navigator o application native.",
+  "errors.unexpected_crash.copy_stacktrace": "Copiar le traciamento del pila al area de transferentia",
   "errors.unexpected_crash.report_issue": "Signalar un defecto",
   "explore.search_results": "Resultatos de recerca",
   "explore.suggested_follows": "Personas",
@@ -224,23 +282,42 @@
   "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.context_mismatch_title": "Contexto incoherente!",
+  "filter_modal.added.expired_explanation": "Iste categoria de filtros ha expirate. Tu debe modificar le data de expiration pro applicar lo.",
+  "filter_modal.added.expired_title": "Filtro expirate!",
+  "filter_modal.added.review_and_configure": "Pro revider e configurar ulteriormente iste categoria de filtros, visita le {settings_link}.",
   "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}.",
   "filter_modal.added.title": "Filtro addite!",
+  "filter_modal.select_filter.context_mismatch": "non se applica a iste contexto",
+  "filter_modal.select_filter.expired": "expirate",
   "filter_modal.select_filter.prompt_new": "Nove categoria: {name}",
   "filter_modal.select_filter.search": "Cercar o crear",
+  "filter_modal.select_filter.subtitle": "Usa un categoria existente o crea un nove",
   "filter_modal.select_filter.title": "Filtrar iste message",
   "filter_modal.title.status": "Filtrar un message",
+  "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentiones}}",
   "filtered_notifications_banner.pending_requests": "Notificationes ab {count, plural, =0 {nemo} one {un persona} other {# personas}} tu poterea cognoscer",
+  "filtered_notifications_banner.title": "Notificationes filtrate",
   "firehose.all": "Toto",
   "firehose.local": "Iste servitor",
   "firehose.remote": "Altere servitores",
+  "follow_request.authorize": "Autorisar",
   "follow_request.reject": "Rejectar",
+  "follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.",
+  "follow_suggestions.curated_suggestion": "Selection del equipa",
   "follow_suggestions.dismiss": "Non monstrar novemente",
+  "follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.",
+  "follow_suggestions.hints.friends_of_friends": "Iste profilo es popular inter le gente que tu seque.",
+  "follow_suggestions.hints.most_followed": "Iste profilo es un del plus sequites sur {domain}.",
+  "follow_suggestions.hints.most_interactions": "Iste profilo ha recentemente recipite multe attention sur {domain}.",
+  "follow_suggestions.hints.similar_to_recently_followed": "Iste profilo es similar al profilos que tu ha recentemente sequite.",
   "follow_suggestions.personalized_suggestion": "Suggestion personalisate",
   "follow_suggestions.popular_suggestion": "Suggestion personalisate",
   "follow_suggestions.view_all": "Vider toto",
+  "follow_suggestions.who_to_follow": "Qui sequer",
+  "followed_tags": "Hashtags sequite",
   "footer.about": "A proposito",
   "footer.directory": "Directorio de profilos",
   "footer.get_app": "Obtener le application",
@@ -256,6 +333,11 @@
   "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.column_settings.tag_mode.all": "Tote istes",
+  "hashtag.column_settings.tag_mode.any": "Un o plus de istes",
+  "hashtag.column_settings.tag_mode.none": "Necun de istes",
+  "hashtag.column_settings.tag_toggle": "Includer etiquettas additional pro iste columna",
+  "hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
   "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",
@@ -277,13 +359,22 @@
   "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.sign_in": "Tu non es in session sur iste servitor. Sur qual servitor se trova tu conto?",
+  "interaction_modal.sign_in_hint": "Consilio: Se tracta del sito web ubi tu te ha inscribite. Si tu non te lo rememora, cerca le e-mail de benvenita in tu cassa de entrata. Tu pote etiam inserer tu pseudonymo complete! (p.ex. @Mastodon@mastodon.social)",
   "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}",
+  "intervals.full.days": "{number, plural, one {# die} other {# dies}}",
+  "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
+  "intervals.full.minutes": "{number, plural, one {# minuta} other {# minutas}}",
+  "keyboard_shortcuts.back": "Navigar retro",
   "keyboard_shortcuts.blocked": "Aperir lista de usatores blocate",
   "keyboard_shortcuts.boost": "Impulsar le message",
+  "keyboard_shortcuts.column": "Focalisar al columna",
+  "keyboard_shortcuts.compose": "Focalisar al area de composition de texto",
   "keyboard_shortcuts.description": "Description",
+  "keyboard_shortcuts.direct": "aperir le columna de mentiones private",
   "keyboard_shortcuts.enter": "Aperir message",
   "keyboard_shortcuts.favourite": "Message favorite",
   "keyboard_shortcuts.favourites": "Aperir lista de favoritos",
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index b44b01bee..bccbb75c4 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -621,6 +621,9 @@ cs:
       actions_description_html: Rozhodněte, který krok učinit pro vyřešení tohoto hlášení. Pokud podniknete kárný krok proti nahlášenému účtu, bude mu zasláno e-mailové oznámení, s výjimkou případu, kdy je zvolena kategorie <strong>Spam</strong>.
       actions_description_remote_html: Rozhodněte, co podniknout pro vyřešení tohoto hlášení. Toto ovlivní pouze to, jak <strong>váš</strong> server komunikuje s tímto vzdáleným účtem, a zpracuje jeho obsah.
       add_to_report: Přidat do hlášení další
+      already_suspended_badges:
+        local: Již pozastaveno na tomto serveru
+        remote: Již pozastaveno na jejich serveru
       are_you_sure: Jste si jisti?
       assign_to_self: Přidělit ke mně
       assigned: Přiřazený moderátor
@@ -1704,13 +1707,26 @@ cs:
     import: Import
     import_and_export: Import a export
     migrate: Přesun účtu
+    notifications: E-mailová upozornění
     preferences: Předvolby
     profile: Profil
     relationships: Sledovaní a sledující
+    severed_relationships: Přerušené vztahy
     statuses_cleanup: Automatické mazání příspěvků
     strikes: Moderační prohřešky
     two_factor_authentication: Dvoufázové ověřování
     webauthn_authentication: Bezpečnostní klíče
+  severed_relationships:
+    download: Stáhnout (%{count})
+    event_type:
+      account_suspension: Pozastavení účtu (%{target_name})
+      domain_block: Pozastavení serveru (%{target_name})
+      user_domain_block: Zablokovali jste %{target_name}
+    lost_followers: Ztracení sledující
+    lost_follows: Ztracená sledování
+    preamble: Když zablokujete doménu nebo když se moderátoři rozhodnou pozastavit vzdálený server, můžete přijít o sledování a sledující. Když k tomu dojde, budete si moci stáhnout seznamy přerušených vztahů, abyste je mohli zkontrolovat a případně importovat na jiný server.
+    purged: Informace o tomto serveru byly správci serveru vymazány.
+    type: Událost
   statuses:
     attached:
       audio:
@@ -1816,6 +1832,7 @@ cs:
     contrast: Mastodon (vysoký kontrast)
     default: Mastodon (tmavý)
     mastodon-light: Mastodon (světlý)
+    system: Automaticky (dle motivu systému)
   time:
     formats:
       default: "%d. %b %Y, %H:%M"
@@ -1903,7 +1920,46 @@ cs:
         silence: Účet omezen
         suspend: Účet pozastaven
     welcome:
+      apps_android_action: Získejte na Google Play
+      apps_ios_action: Stáhnout z App Store
+      apps_step: Stáhněte si naše oficiální aplikace.
+      apps_title: Aplikace Mastodon
+      checklist_subtitle: 'Začněme na této nové sociální hranici:'
+      checklist_title: Uvítací kontrolní seznam
+      edit_profile_action: Přizpůsobit
+      edit_profile_step: Zlepšete své interakce tím, že si vytvoříte komplexní profil.
+      edit_profile_title: Přizpůsobte si svůj profil
       explanation: Zde je pár tipů do začátku
+      feature_action: Zjistit více
+      feature_audience: Mastodon vám nabízí jedinečnou možnost správy publika bez prostředníků. Mastodon nasazený na vaší vlastní infrastruktuře vám umožňuje sledovat a být sledován z jakéhokoli jiného Mastodon serveru online a není pod kontrolou nikoho jiného než vás.
+      feature_audience_title: Vytvořte si svědomě své publikum
+      feature_control: Sami nejlépe víte, co chcete vidět na svém domovském kanálu. Žádné algoritmy ani reklamy, které by plýtvaly vaším časem. Sledujte kohokoli z libovolného Mastodon serveru z jediného účtu, dostávejte jejich příspěvky v chronologickém pořadí a udělejte si svůj kout internetu trochu více podle sebe.
+      feature_control_title: Mějte pod kontrolou vlastní časovou osu
+      feature_creativity: Mastodon podporuje zvukové, video a obrázkové příspěvky, popisy přístupnosti, ankety, upozornění na obsah, animované avatary, vlastní emotikony, ovládání ořezu miniatur a další funkce, které vám pomohou vyjádřit se online. Ať už publikujete své umění, hudbu nebo podcast, Mastodon je tu pro vás.
+      feature_creativity_title: Bezkonkurenční kreativita
+      feature_moderation: Mastodon dává rozhodování zpět do vašich rukou. Každý server si vytváří svá vlastní pravidla a předpisy, které jsou prosazovány lokálně, nikoli shora jako v případě firemních sociálních médií, díky čemuž lze nejpružněji reagovat na potřeby různých skupin lidí. Připojte se k serveru s pravidly, se kterými souhlasíte, nebo si založte vlastní.
+      feature_moderation_title: Moderování způsobem, jakým by to mělo být
+      follow_action: Sledovat
+      follow_step: Mastodon je o sledování zajimavých lidí.
+      follow_title: Přizpůsobte si svůj domovský kanál
+      follows_subtitle: Sledujte známé účty
+      follows_title: Koho sledovat
+      follows_view_more: Zobrazit více lidí ke sledování
+      hashtags_recent_count:
+        few: "%{people} osoby v posledních 2 dnech"
+        many: "%{people} osob v posledních 2 dnech"
+        one: "%{people} osoba v posledních 2 dnech"
+        other: "%{people} osob v posledních 2 dnech"
+      hashtags_subtitle: Prozkoumejte, co je populární od posledních 2 dnů
+      hashtags_title: Populární hashtagy
+      hashtags_view_more: Zobrazit více populárních hashtagů
+      post_action: Sepsat
+      post_step: Řekněte světu ahoj pomocí textu, fotografií, videí nebo anket.
+      post_title: Vytvořte svůj první příspěvek
+      share_action: Sdílet
+      share_step: Dejte přátelům vědět, jak vás mohou na Mastodonu najít.
+      share_title: Sdílejte svůj Mastodon profil
+      sign_in_action: Přihlásit se
       subject: Vítejte na Mastodonu
       title: Vítejte na palubě, %{name}!
   users:
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 523b60197..a05aa3c92 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -1241,7 +1241,7 @@ eu:
     add_new: Gehitu berria
     errors:
       limit: Gehienezko traola kopurua erakutsi duzu jada
-    hint_html: "<strong>Zer dira nabarmendutako traolak?</strong> Zure profilean toki nabarmendu batean agertzen dira eta jendeari traola hau daukaten bidalketa publikoak arakatzea ahalbidetzen diote. Sormen lana edo epe luzerako proiektuak jarraitzeko primerakoak dira."
+    hint_html: "<strong>Zer dira nabarmendutako traolak?</strong> Zure profileko toki nabarmendu batean agertzen dira eta jendeari traola haue dituzten bidalketa publikoak arakatzea ahalbidetzen diote. Sormen-lanak edo epe luzerako proiektuak jarraitzeko primerakoak dira."
   filters:
     contexts:
       account: Profilak
@@ -1910,7 +1910,7 @@ eu:
     signed_in_as: 'Saioa honela hasita:'
   verification:
     extra_instructions_html: <strong>Aholkua:</strong> webguneko esteka ikusezina izan daiteke. Muina <code>rel="me"</code> da, erabiltzaileak sortutako edukia duten webguneetan beste inor zure burutzat aurkeztea eragozten duena. <code>a</code> beharrean <code>esteka</code> motako etiketa bat ere erabil dezakezu orriaren goiburuan, baina HTMLak erabilgarri egon behar du JavaScript exekutatu gabe.
-    here_is_how: Hemen duzu nola
+    here_is_how: Argibidea
     hint_html: "<strong>Mastodonen nortasun-egiaztapena guztiontzat da.</strong> Web estandar irekietan oinarritua, orain eta betiko doan. Behar duzun guztia jendeak ezagutzen duen webgune pertsonal bat da. Mastodon profiletik webgune honetara estekatzen duzunean, webguneak Mastodon profilera estekatzen duela egiaztatuko dugu eta adierazle bat erakutsiko du."
     instructions_html: Kopiatu eta itsatsi ondoko kodea zure webguneko HTMLan. Ondoren, gehitu zure webgunearen helbidea zure profileko eremu gehigarrietako batean, "Editatu profila" fitxatik eta gorde aldaketak.
     verification: Egiaztaketa
diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml
index ca8cc49a9..f91f82673 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -116,6 +116,7 @@ cs:
           sign_up_requires_approval: Nové registrace budou vyžadovat schválení
         severity: Zvolte, jak naložit s požadavky z dané IP
       rule:
+        hint: Nepovinné. Uveďte další podrobnosti o pravidle
         text: Popište pravidlo nebo požadavek uživatelům tohoto serveru. Snažte se ho držet krátký a jednoduchý
       sessions:
         otp: 'Zadejte kód pro dvoufázové ověření vygenerovaný vaší mobilní aplikací, nebo použijte jeden z vašich záložních kódů:'
@@ -299,6 +300,7 @@ cs:
           patch: Upozornit na aktualizace chyb
         trending_tag: Nový trend vyžaduje posouzení
       rule:
+        hint: Další informace
         text: Pravidlo
       settings:
         indexable: Zahrnout stránku profilu do vyhledávačů

From 75f9c652e21c0fbb76c90820646b66516d12ad9b Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 18 Apr 2024 12:24:22 -0400
Subject: [PATCH 177/223] Fix `Bundler/OrderedGems` cop (#28400)

---
 .rubocop_todo.yml |  7 -------
 Gemfile           | 30 +++++++++++++++---------------
 2 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 63d9d6757..9ca7ba6f1 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -6,13 +6,6 @@
 # Note that changes in the inspected code, or installation of new
 # versions of RuboCop, may require this file to be generated again.
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
-# Include: **/*.gemfile, **/Gemfile, **/gems.rb
-Bundler/OrderedGems:
-  Exclude:
-    - 'Gemfile'
-
 Lint/NonLocalExitFromIterator:
   Exclude:
     - 'app/helpers/jsonld_helper.rb'
diff --git a/Gemfile b/Gemfile
index 35e0b2928..3361f2dc3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,26 +3,26 @@
 source 'https://rubygems.org'
 ruby '>= 3.1.0'
 
-gem 'puma', '~> 6.3'
-gem 'rails', '~> 7.1.1'
 gem 'propshaft'
-gem 'thor', '~> 1.2'
+gem 'puma', '~> 6.3'
 gem 'rack', '~> 2.2.7'
+gem 'rails', '~> 7.1.1'
+gem 'thor', '~> 1.2'
 
 # For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182
 gem 'irb', '~> 1.8'
 
+gem 'dotenv-rails', '~> 2.8'
 gem 'haml-rails', '~>2.0'
 gem 'pg', '~> 1.5'
 gem 'pghero'
-gem 'dotenv-rails', '~> 2.8'
 
 gem 'aws-sdk-s3', '~> 1.123', require: false
+gem 'blurhash', '~> 0.1'
 gem 'fog-core', '<= 2.4.0'
 gem 'fog-openstack', '~> 1.0', require: false
 gem 'kt-paperclip', '~> 7.2'
 gem 'md-paperclip-azure', '~> 2.2', require: false
-gem 'blurhash', '~> 0.1'
 
 gem 'active_model_serializers', '~> 0.10'
 gem 'addressable', '~> 2.8'
@@ -39,11 +39,11 @@ end
 
 gem 'net-ldap', '~> 0.18'
 
-gem 'omniauth-cas', '~> 3.0.0.beta.1'
-gem 'omniauth-saml', '~> 2.0'
-gem 'omniauth_openid_connect', '~> 0.6.1'
 gem 'omniauth', '~> 2.0'
+gem 'omniauth-cas', '~> 3.0.0.beta.1'
+gem 'omniauth_openid_connect', '~> 0.6.1'
 gem 'omniauth-rails_csrf_protection', '~> 1.0'
+gem 'omniauth-saml', '~> 2.0'
 
 gem 'color_diff', '~> 0.1'
 gem 'csv', '~> 3.2'
@@ -53,7 +53,6 @@ gem 'ed25519', '~> 1.3'
 gem 'fast_blank', '~> 1.0'
 gem 'fastimage'
 gem 'hiredis', '~> 0.6'
-gem 'redis-namespace', '~> 1.10'
 gem 'htmlentities', '~> 4.3'
 gem 'http', '~> 5.1'
 gem 'http_accept_language', '~> 2.1'
@@ -63,39 +62,40 @@ gem 'idn-ruby', require: 'idn'
 gem 'inline_svg'
 gem 'kaminari', '~> 1.2'
 gem 'link_header', '~> 0.0'
+gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
 gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
 gem 'nokogiri', '~> 1.15'
 gem 'nsa'
 gem 'oj', '~> 3.14'
 gem 'ox', '~> 2.14'
 gem 'parslet'
+gem 'premailer-rails'
 gem 'public_suffix', '~> 5.0'
 gem 'pundit', '~> 2.3'
-gem 'premailer-rails'
 gem 'rack-attack', '~> 6.6'
 gem 'rack-cors', '~> 2.0', require: 'rack/cors'
 gem 'rails-i18n', '~> 7.0'
 gem 'redcarpet', '~> 3.6'
 gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis']
-gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
+gem 'redis-namespace', '~> 1.10'
 gem 'rqrcode', '~> 2.2'
 gem 'ruby-progressbar', '~> 1.13'
 gem 'sanitize', '~> 6.0'
 gem 'scenic', '~> 1.7'
 gem 'sidekiq', '~> 6.5'
+gem 'sidekiq-bulk', '~> 0.2.0'
 gem 'sidekiq-scheduler', '~> 5.0'
 gem 'sidekiq-unique-jobs', '~> 7.1'
-gem 'sidekiq-bulk', '~> 0.2.0'
-gem 'simple-navigation', '~> 4.4'
 gem 'simple_form', '~> 5.2'
+gem 'simple-navigation', '~> 4.4'
 gem 'stoplight', '~> 4.1'
 gem 'strong_migrations', '1.8.0'
 gem 'tty-prompt', '~> 0.23', require: false
 gem 'twitter-text', '~> 3.1.0'
 gem 'tzinfo-data', '~> 1.2023'
+gem 'webauthn', '~> 3.0'
 gem 'webpacker', '~> 5.4'
 gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9'
-gem 'webauthn', '~> 3.0'
 
 gem 'json-ld'
 gem 'json-ld-preloaded', '~> 3.2'
@@ -197,10 +197,10 @@ group :production do
   gem 'lograge', '~> 0.12'
 end
 
+gem 'cocoon', '~> 1.2'
 gem 'concurrent-ruby', require: false
 gem 'connection_pool', require: false
 gem 'xorcist', '~> 1.1'
-gem 'cocoon', '~> 1.2'
 
 gem 'net-http', '~> 0.4.0'
 gem 'rubyzip', '~> 2.3'

From e5d5bd7ff114c43babc4ca563112bf31c5fee65a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 18 Apr 2024 18:24:55 +0200
Subject: [PATCH 178/223] Update dependency postcss-preset-env to v9.5.6
 (#29983)

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 bf217a074..c0d1e91b6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6481,14 +6481,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"css-blank-pseudo@npm:^6.0.1":
-  version: 6.0.1
-  resolution: "css-blank-pseudo@npm:6.0.1"
+"css-blank-pseudo@npm:^6.0.2":
+  version: 6.0.2
+  resolution: "css-blank-pseudo@npm:6.0.2"
   dependencies:
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/04f2dc1c39a429cb4958b60a9d00b03e29a78e3e55fe111b3a0660b7c6c478455d5907eda7c7a495cf72dbe83ae3c80b409e0468ca1ba5ccef992e69a8f49df8
+  checksum: 10c0/609303551c2a518ca23ed12fed43945ca4f7af04140da68a5536f5dc9d42f33412c13ac3fe5c616d7401a9e13a23d80b4cfa87149a45f94b244d8067bb11f3dd
   languageName: node
   linkType: hard
 
@@ -13620,8 +13620,8 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.5
-  resolution: "postcss-preset-env@npm:9.5.5"
+  version: 9.5.6
+  resolution: "postcss-preset-env@npm:9.5.6"
   dependencies:
     "@csstools/postcss-cascade-layers": "npm:^4.0.4"
     "@csstools/postcss-color-function": "npm:^3.0.13"
@@ -13654,7 +13654,7 @@ __metadata:
     "@csstools/postcss-unset-value": "npm:^3.0.1"
     autoprefixer: "npm:^10.4.19"
     browserslist: "npm:^4.22.3"
-    css-blank-pseudo: "npm:^6.0.1"
+    css-blank-pseudo: "npm:^6.0.2"
     css-has-pseudo: "npm:^6.0.3"
     css-prefers-color-scheme: "npm:^9.0.1"
     cssdb: "npm:^8.0.0"
@@ -13685,7 +13685,7 @@ __metadata:
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/afc31fb75bc5e8e223d38fd34b81da08ee340818f5e392df1781728f2ff2a9dbc75e458673ce9f52deafefa90bbc99e0bd1453271498f5e02746c785180bad07
+  checksum: 10c0/21738ecac400cca9a96841959308538516ed00ca80d4c53beb20e080c7d963120fa77b7435b02e1beefc20043abce666419b81eccf6dacdc4298f540778c111d
   languageName: node
   linkType: hard
 

From 4837bfcc6ab38dc86c619167b7c2e260a92a270a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 09:57:32 -0400
Subject: [PATCH 179/223] Use shared `form` partial for `admin/announcements`
 views (#29608)

---
 app/views/admin/announcements/_form.html.haml | 28 +++++++++++++++
 app/views/admin/announcements/edit.html.haml  | 35 +++---------------
 app/views/admin/announcements/new.html.haml   | 36 +++----------------
 3 files changed, 38 insertions(+), 61 deletions(-)
 create mode 100644 app/views/admin/announcements/_form.html.haml

diff --git a/app/views/admin/announcements/_form.html.haml b/app/views/admin/announcements/_form.html.haml
new file mode 100644
index 000000000..3a9b37190
--- /dev/null
+++ b/app/views/admin/announcements/_form.html.haml
@@ -0,0 +1,28 @@
+.fields-group
+  = form.input :starts_at,
+               html5: true,
+               include_blank: true,
+               input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
+               wrapper: :with_block_label
+  = form.input :ends_at,
+               html5: true,
+               include_blank: true,
+               input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
+               wrapper: :with_block_label
+
+.fields-group
+  = form.input :all_day,
+               as: :boolean,
+               wrapper: :with_label
+
+.fields-group
+  = form.input :text,
+               wrapper: :with_block_label
+
+- unless form.object.published?
+  .fields-group
+    = form.input :scheduled_at,
+                 html5: true,
+                 include_blank: true,
+                 input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
+                 wrapper: :with_block_label
diff --git a/app/views/admin/announcements/edit.html.haml b/app/views/admin/announcements/edit.html.haml
index 23c568a88..8cec7d36c 100644
--- a/app/views/admin/announcements/edit.html.haml
+++ b/app/views/admin/announcements/edit.html.haml
@@ -1,37 +1,12 @@
 - content_for :page_title do
   = t('.title')
 
-= simple_form_for @announcement, url: admin_announcement_path(@announcement), html: { novalidate: false } do |f|
+= simple_form_for @announcement, url: admin_announcement_path(@announcement), html: { novalidate: false } do |form|
   = render 'shared/error_messages', object: @announcement
 
-  .fields-group
-    = f.input :starts_at,
-              html5: true,
-              include_blank: true,
-              input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-              wrapper: :with_block_label
-    = f.input :ends_at,
-              html5: true,
-              include_blank: true,
-              input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-              wrapper: :with_block_label
-
-  .fields-group
-    = f.input :all_day,
-              as: :boolean,
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :text,
-              wrapper: :with_block_label
-
-  - unless @announcement.published?
-    .fields-group
-      = f.input :scheduled_at,
-                html5: true,
-                include_blank: true,
-                input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-                wrapper: :with_block_label
+  = render form
 
   .actions
-    = f.button :button, t('generic.save_changes'), type: :submit
+    = form.button :button,
+                  t('generic.save_changes'),
+                  type: :submit
diff --git a/app/views/admin/announcements/new.html.haml b/app/views/admin/announcements/new.html.haml
index a681ed789..266ca65e8 100644
--- a/app/views/admin/announcements/new.html.haml
+++ b/app/views/admin/announcements/new.html.haml
@@ -1,38 +1,12 @@
 - content_for :page_title do
   = t('.title')
 
-= simple_form_for @announcement, url: admin_announcements_path, html: { novalidate: false } do |f|
+= simple_form_for @announcement, url: admin_announcements_path, html: { novalidate: false } do |form|
   = render 'shared/error_messages', object: @announcement
 
-  .fields-group
-    = f.input :starts_at,
-              html5: true,
-              include_blank: true,
-              input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-              wrapper: :with_block_label
-    = f.input :ends_at,
-              html5: true,
-              include_blank: true,
-              input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-              wrapper: :with_block_label
-
-  .fields-group
-    = f.input :all_day,
-              as: :boolean,
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :text,
-              wrapper: :with_block_label
-
-  .fields-group
-    = f.input :scheduled_at,
-              html5: true,
-              include_blank: true,
-              input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder },
-              wrapper: :with_block_label
+  = render form
 
   .actions
-    = f.button :button,
-               t('.create'),
-               type: :submit
+    = form.button :button,
+                  t('.create'),
+                  type: :submit

From ec71c02c4b028c3541742f023729aeb295a51559 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 19 Apr 2024 15:57:43 +0200
Subject: [PATCH 180/223] New Crowdin Translations (automated) (#29994)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/cs.json | 29 +++++++++++++++++++++++++
 app/javascript/mastodon/locales/th.json |  1 +
 app/javascript/mastodon/locales/tr.json |  4 ++--
 config/locales/fi.yml                   |  6 ++---
 config/locales/ko.yml                   |  8 +++----
 5 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index f55caf14b..2fc01f3ac 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -297,6 +297,8 @@
   "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.mentions": "{count, plural, one {zmínka} few {zmínky} many {zmínek} other {zmínek}}",
+  "filtered_notifications_banner.pending_requests": "Oznámení od {count, plural, =0 {nikoho} one {jednoho člověka, kterého znáte} few {# lidí, které znáte} many {# lidí, které znáte} other {# lidí, které znáte}}",
   "filtered_notifications_banner.title": "Filtrovaná oznámení",
   "firehose.all": "Vše",
   "firehose.local": "Tento server",
@@ -427,7 +429,14 @@
   "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.hide_options": "Skrýt možnosti",
+  "mute_modal.indefinite": "Dokud je neodkryju",
+  "mute_modal.show_options": "Zobrazit možnosti",
+  "mute_modal.they_can_mention_and_follow": "Mohou vás zmínit a sledovat, ale neuvidíte je.",
+  "mute_modal.they_wont_know": "Nebudou vědět, že byli skryti.",
   "mute_modal.title": "Ztlumit uživatele?",
+  "mute_modal.you_wont_see_mentions": "Neuvidíte příspěvky, které je zmiňují.",
+  "mute_modal.you_wont_see_posts": "Stále budou moci vidět vaše příspěvky, ale vy jejich neuvidíte.",
   "navigation_bar.about": "O aplikaci",
   "navigation_bar.advanced_interface": "Otevřít pokročilé webové rozhraní",
   "navigation_bar.blocks": "Blokovaní uživatelé",
@@ -463,17 +472,25 @@
   "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": "Kontakt ztracen s {name}",
+  "notification.relationships_severance_event.account_suspension": "Administrátor z {from} pozastavil {target}, což znamená, že již od nich nemůžete přijímat aktualizace nebo s nimi interagovat.",
+  "notification.relationships_severance_event.domain_block": "Administrátor z {from} pozastavil {target}, včetně {followersCount} z vašich sledujících a {followingCount, plural, one {# účet, který sledujete} few {# účty, které sledujete} many {# účtů, které sledujete} other {# účtů, které sledujete}}.",
   "notification.relationships_severance_event.learn_more": "Zjistit více",
+  "notification.relationships_severance_event.user_domain_block": "Zablokovali jste {target}, čímž jste odebrali {followersCount} z vašich sledujících a {followingCount, plural, one {# účet, který sledujete} few {# účty, které sledujete} many {# účtů, které sledujete} other {# účtů, které sledujete}}.",
   "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",
+  "notification_requests.notifications_from": "Oznámení od {name}",
+  "notification_requests.title": "Vyfiltrovaná oznámení",
   "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í:",
   "notifications.column_settings.admin.sign_up": "Nové registrace:",
   "notifications.column_settings.alert": "Oznámení na počítači",
   "notifications.column_settings.favourite": "Oblíbené:",
+  "notifications.column_settings.filter_bar.advanced": "Zobrazit všechny kategorie",
+  "notifications.column_settings.filter_bar.category": "Panel rychlého filtrování",
   "notifications.column_settings.follow": "Noví sledující:",
   "notifications.column_settings.follow_request": "Nové žádosti o sledování:",
   "notifications.column_settings.mention": "Zmínky:",
@@ -499,6 +516,15 @@
   "notifications.permission_denied": "Oznámení na ploše nejsou k dispozici, protože byla zamítnuta žádost o oprávnění je zobrazovat",
   "notifications.permission_denied_alert": "Oznámení na ploše není možné zapnout, protože oprávnění bylo v minulosti zamítnuto",
   "notifications.permission_required": "Oznámení na ploše nejsou k dispozici, protože nebylo uděleno potřebné oprávnění.",
+  "notifications.policy.filter_new_accounts.hint": "Vytvořeno během {days, plural, one {včerejška} few {posledních # dnů} many {posledních # dní} other {posledních # dní}}",
+  "notifications.policy.filter_new_accounts_title": "Nové účty",
+  "notifications.policy.filter_not_followers_hint": "Včetně lidí, kteří vás sledovali méně než {days, plural, one {jeden den} few {# dny} many {# dní} other {# dní}}",
+  "notifications.policy.filter_not_followers_title": "Lidé, kteří vás nesledují",
+  "notifications.policy.filter_not_following_hint": "Dokud je ručně neschválíte",
+  "notifications.policy.filter_not_following_title": "Lidé, které nesledujete",
+  "notifications.policy.filter_private_mentions_hint": "Vyfiltrováno, pokud to není odpověď na vaši zmínku nebo pokud sledujete odesílatele",
+  "notifications.policy.filter_private_mentions_title": "Nevyžádané soukromé zmínky",
+  "notifications.policy.title": "Vyfiltrovat oznámení od…",
   "notifications_permission_banner.enable": "Povolit oznámení na ploše",
   "notifications_permission_banner.how_to_control": "Chcete-li dostávat oznámení, i když nemáte Mastodon otevřený, povolte oznámení na ploše. Můžete si zvolit, o kterých druzích interakcí chcete být oznámením na ploše informování pod tlačítkem {icon} výše.",
   "notifications_permission_banner.title": "Nenechte si nic uniknout",
@@ -675,9 +701,11 @@
   "status.direct": "Soukromě zmínit @{name}",
   "status.direct_indicator": "Soukromá zmínka",
   "status.edit": "Upravit",
+  "status.edited": "Naposledy upraveno {date}",
   "status.edited_x_times": "Upraveno {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
   "status.embed": "Vložit na web",
   "status.favourite": "Oblíbit",
+  "status.favourites": "{count, plural, one {oblíbený} few {oblíbené} many {oblíbených} other {oblíbených}}",
   "status.filter": "Filtrovat tento příspěvek",
   "status.filtered": "Filtrováno",
   "status.hide": "Skrýt příspěvek",
@@ -698,6 +726,7 @@
   "status.reblog": "Boostnout",
   "status.reblog_private": "Boostnout s původní viditelností",
   "status.reblogged_by": "Uživatel {name} boostnul",
+  "status.reblogs": "{count, plural, one {boost} few {boosty} many {boostů} other {boostů}}",
   "status.reblogs.empty": "Tento příspěvek ještě nikdo neboostnul. Pokud to někdo udělá, zobrazí se zde.",
   "status.redraft": "Smazat a přepsat",
   "status.remove_bookmark": "Odstranit ze záložek",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index c43bf8581..379aebbb1 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -297,6 +297,7 @@
   "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 {ไม่มีใคร} other {# คน}} ที่คุณอาจรู้จัก",
   "filtered_notifications_banner.title": "การแจ้งเตือนที่กรองอยู่",
   "firehose.all": "ทั้งหมด",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 76739fe31..dc07480ef 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -777,10 +777,10 @@
   "upload_form.edit": "Düzenle",
   "upload_form.thumbnail": "Küçük resmi değiştir",
   "upload_form.video_description": "İşitme kaybı veya görme engeli olan kişiler için açıklama ekleyiniz",
-  "upload_modal.analyzing_picture": "Resim analiz ediliyor…",
+  "upload_modal.analyzing_picture": "Görsel analiz ediliyor…",
   "upload_modal.apply": "Uygula",
   "upload_modal.applying": "Uygulanıyor…",
-  "upload_modal.choose_image": "Resim seç",
+  "upload_modal.choose_image": "Görsel seç",
   "upload_modal.description_placeholder": "Pijamalı hasta yağız şoföre çabucak güvendi",
   "upload_modal.detect_text": "Resimdeki metni algıla",
   "upload_modal.edit_media": "Medyayı düzenle",
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 155e4473b..ab92e106a 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -1765,9 +1765,9 @@ fi:
   tags:
     does_not_match_previous_name: ei vastaa edellistä nimeä
   themes:
-    contrast: Mastodon (Korkea kontrasti)
-    default: Mastodon (Tumma)
-    mastodon-light: Mastodon (Vaalea)
+    contrast: Mastodon (suuri kontrasti)
+    default: Mastodon (tumma)
+    mastodon-light: Mastodon (vaalea)
     system: Automaattinen (käytä järjestelmän teemaa)
   time:
     formats:
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 5ca0324dc..0e90cc723 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -979,7 +979,7 @@ ko:
     new_report:
       body: "%{reporter} 님이 %{target}를 신고했습니다"
       body_remote: "%{domain}의 누군가가 %{target}을 신고했습니다"
-      subject: "%{instance} 에 새 신고 등록됨 (#%{id})"
+      subject: "%{instance}의 새로운 신고(#%{id})"
     new_software_updates:
       body: 새 마스토돈 버전이 릴리스되었습니다. 업데이트 할 수 있습니다!
       subject: "%{instance}에 대해 새 마스토돈 버전이 사용 가능합니다!"
@@ -1118,7 +1118,7 @@ ko:
   date:
     formats:
       default: "%Y-%m-%d"
-      with_month_name: "%Y년 %f월 %e일"
+      with_month_name: "%Y년 %B %d일"
   datetime:
     distance_in_words:
       about_x_hours: "%{count}시간"
@@ -1742,7 +1742,7 @@ ko:
   time:
     formats:
       default: "%Y-%m-%d %H:%M"
-      month: "%Y년 %f월"
+      month: "%Y년 %b"
       time: "%H:%M"
       with_time_zone: "%Y-%m-%d %H:%M %Z"
   translation:
@@ -1896,4 +1896,4 @@ ko:
     not_enabled: 아직 WebAuthn을 활성화 하지 않았습니다.
     not_supported: 이 브라우저는 보안 키를 지원하지 않습니다
     otp_required: 보안 키를 사용하기 위해서는 2단계 인증을 먼저 활성화 해 주세요
-    registered_on: "%{date} 에 등록됨"
+    registered_on: "%{date}에 등록됨"

From f386eb6c6300440cd96e47af4b19481d2ee2f219 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 10:25:14 -0400
Subject: [PATCH 181/223] Replace deprecated `dotenv-rails` gem with `dotenv`
 gem (#29173)

---
 Gemfile               | 2 +-
 Gemfile.lock          | 7 ++-----
 config/application.rb | 2 +-
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/Gemfile b/Gemfile
index 3361f2dc3..3f621ddc5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem 'thor', '~> 1.2'
 # For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182
 gem 'irb', '~> 1.8'
 
-gem 'dotenv-rails', '~> 2.8'
+gem 'dotenv'
 gem 'haml-rails', '~>2.0'
 gem 'pg', '~> 1.5'
 gem 'pghero'
diff --git a/Gemfile.lock b/Gemfile.lock
index 752d4e05e..6e5611b23 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -220,10 +220,7 @@ GEM
     domain_name (0.6.20240107)
     doorkeeper (5.6.9)
       railties (>= 5)
-    dotenv (2.8.1)
-    dotenv-rails (2.8.1)
-      dotenv (= 2.8.1)
-      railties (>= 3.2)
+    dotenv (3.1.0)
     drb (2.2.1)
     ed25519 (1.3.0)
     elasticsearch (7.13.3)
@@ -848,7 +845,7 @@ DEPENDENCIES
   devise_pam_authenticatable2 (~> 9.2)
   discard (~> 1.2)
   doorkeeper (~> 5.6)
-  dotenv-rails (~> 2.8)
+  dotenv
   ed25519 (~> 1.3)
   email_spec
   fabrication (~> 2.30)
diff --git a/config/application.rb b/config/application.rb
index bab1b46cb..a17a48b09 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -52,7 +52,7 @@ require_relative '../lib/active_record/batches'
 require_relative '../lib/simple_navigation/item_extensions'
 require_relative '../lib/http_extensions'
 
-Dotenv::Railtie.load
+Dotenv::Rails.load
 
 Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'
 

From f5d341382e549c00e40d6f280444de40064d910a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 15:44:59 -0400
Subject: [PATCH 182/223] Add `any_args` to have_enqueued_sidekiq_job call
 (quiets deprecation) (#29999)

---
 spec/services/remove_featured_tag_service_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/spec/services/remove_featured_tag_service_spec.rb b/spec/services/remove_featured_tag_service_spec.rb
index 6cf5388c7..2f0694bc6 100644
--- a/spec/services/remove_featured_tag_service_spec.rb
+++ b/spec/services/remove_featured_tag_service_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe RemoveFeaturedTagService do
           expect { featured_tag.reload }
             .to raise_error(ActiveRecord::RecordNotFound)
           expect(ActivityPub::AccountRawDistributionWorker)
-            .to_not have_enqueued_sidekiq_job
+            .to_not have_enqueued_sidekiq_job(any_args)
         end
       end
     end

From fa5e154ee379b3f84c032b692b1f7bb774a844e9 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 15:45:41 -0400
Subject: [PATCH 183/223] Indirect deps gem version bumps (#29998)

---
 Gemfile.lock | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 6e5611b23..78fe1faf7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -102,8 +102,8 @@ GEM
     attr_required (1.0.2)
     awrence (1.2.1)
     aws-eventstream (1.3.0)
-    aws-partitions (1.914.0)
-    aws-sdk-core (3.192.0)
+    aws-partitions (1.916.0)
+    aws-sdk-core (3.192.1)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.8)
@@ -186,7 +186,7 @@ GEM
       bigdecimal
       rexml
     crass (1.0.6)
-    css_parser (1.16.0)
+    css_parser (1.17.1)
       addressable
     csv (3.3.0)
     database_cleaner-active_record (2.1.0)
@@ -238,7 +238,7 @@ GEM
       mail (~> 2.7)
     encryptor (3.0.0)
     erubi (1.12.0)
-    et-orbi (1.2.10)
+    et-orbi (1.2.11)
       tzinfo
     excon (0.110.0)
     fabrication (2.31.0)
@@ -272,8 +272,8 @@ GEM
     fast_blank (1.0.1)
     fastimage (2.3.1)
     ffi (1.16.3)
-    ffi-compiler (1.0.1)
-      ffi (>= 1.0.0)
+    ffi-compiler (1.3.2)
+      ffi (>= 1.15.5)
       rake
     fog-core (2.4.0)
       builder
@@ -314,7 +314,7 @@ GEM
     hashie (5.0.0)
     hcaptcha (7.1.0)
       json
-    highline (2.1.0)
+    highline (3.0.1)
     hiredis (0.6.3)
     hkdf (0.3.0)
     htmlentities (4.3.4)
@@ -432,11 +432,11 @@ GEM
       mime-types-data (~> 3.2015)
     mime-types-data (3.2024.0305)
     mini_mime (1.1.5)
-    mini_portile2 (2.8.5)
+    mini_portile2 (2.8.6)
     minitest (5.22.3)
     msgpack (1.7.2)
     multi_json (1.15.0)
-    multipart-post (2.3.0)
+    multipart-post (2.4.0)
     mutex_m (0.2.0)
     net-http (0.4.1)
       uri
@@ -450,7 +450,7 @@ GEM
       net-protocol
     net-protocol (0.2.2)
       timeout
-    net-smtp (0.4.0.1)
+    net-smtp (0.5.0)
       net-protocol
     nio4r (2.7.1)
     nokogiri (1.16.4)
@@ -543,7 +543,7 @@ GEM
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)
-    rack-proxy (0.7.6)
+    rack-proxy (0.7.7)
       rack
     rack-session (1.0.2)
       rack (< 3)
@@ -589,7 +589,7 @@ GEM
       thor (~> 1.0, >= 1.2.2)
       zeitwerk (~> 2.6)
     rainbow (3.1.1)
-    rake (13.1.0)
+    rake (13.2.1)
     rdf (3.3.1)
       bcp47_spec (~> 0.2)
       link_header (~> 0.0, >= 0.0.8)
@@ -604,9 +604,9 @@ GEM
     redlock (1.3.2)
       redis (>= 3.0.0, < 6.0)
     regexp_parser (2.9.0)
-    reline (0.5.1)
+    reline (0.5.2)
       io-console (~> 0.5)
-    request_store (1.5.1)
+    request_store (1.6.0)
       rack (>= 1.4)
     responders (3.1.1)
       actionpack (>= 5.2)
@@ -673,11 +673,11 @@ GEM
       rubocop-capybara (~> 2.17)
       rubocop-factory_bot (~> 2.22)
       rubocop-rspec_rails (~> 2.28)
-    rubocop-rspec_rails (2.28.2)
+    rubocop-rspec_rails (2.28.3)
       rubocop (~> 1.40)
     ruby-prof (1.7.0)
     ruby-progressbar (1.13.0)
-    ruby-saml (1.15.0)
+    ruby-saml (1.16.0)
       nokogiri (>= 1.13.10)
       rexml
     ruby2_keywords (0.0.5)
@@ -773,7 +773,7 @@ GEM
       unf_ext
     unf_ext (0.0.9.1)
     unicode-display_width (2.5.0)
-    uri (0.12.2)
+    uri (0.13.0)
     validate_email (0.1.6)
       activemodel (>= 3.0)
       mail (>= 2.2.5)

From d24462c81adbf289077f70e6f836b82d3adf5cb4 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 19 Apr 2024 19:46:13 +0000
Subject: [PATCH 184/223] Update dependency test-prof to v1.3.3 (#30000)

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 78fe1faf7..aadd52d64 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -744,7 +744,7 @@ GEM
       unicode-display_width (>= 1.1.1, < 3)
     terrapin (1.0.1)
       climate_control
-    test-prof (1.3.2)
+    test-prof (1.3.3)
     thor (1.3.1)
     tilt (2.3.0)
     timeout (0.4.1)

From 8d47ba893a714a52183b57be83eb38bcb7ffef57 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:32:26 -0400
Subject: [PATCH 185/223] Fix `Style/PercentLiteralDelimiters` cop (#30006)

---
 .rubocop_todo.yml                 | 7 -------
 config/deploy.rb                  | 4 ++--
 config/initializers/doorkeeper.rb | 2 +-
 3 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 9ca7ba6f1..ac65c1589 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -197,13 +197,6 @@ Style/OptionalBooleanParameter:
     - 'app/workers/unfollow_follow_worker.rb'
     - 'lib/mastodon/redis_config.rb'
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: PreferredDelimiters.
-Style/PercentLiteralDelimiters:
-  Exclude:
-    - 'config/deploy.rb'
-    - 'config/initializers/doorkeeper.rb'
-
 # This cop supports unsafe autocorrection (--autocorrect-all).
 # Configuration parameters: EnforcedStyle.
 # SupportedStyles: short, verbose
diff --git a/config/deploy.rb b/config/deploy.rb
index 75bfcc26f..28c838770 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -13,8 +13,8 @@ set :migration_role, :app
 append :linked_files, '.env.production', 'public/robots.txt'
 append :linked_dirs, 'vendor/bundle', 'node_modules', 'public/system'
 
-SYSTEMD_SERVICES = %i[sidekiq streaming web].freeze
-SERVICE_ACTIONS = %i[reload restart status].freeze
+SYSTEMD_SERVICES = %i(sidekiq streaming web).freeze
+SERVICE_ACTIONS = %i(reload restart status).freeze
 
 namespace :systemd do
   SYSTEMD_SERVICES.each do |service|
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index f9d47a205..428e47391 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -150,7 +150,7 @@ Doorkeeper.configure do
   #
   # You can use this option in order to forbid URI's with 'javascript' scheme
   # for example.
-  forbid_redirect_uri { |uri| %w[data vbscript javascript].include?(uri.scheme.to_s.downcase) }
+  forbid_redirect_uri { |uri| %w(data vbscript javascript).include?(uri.scheme.to_s.downcase) }
 
   # Specify what grant flows are enabled in array of Strings. The valid
   # strings and the flows they enable are:

From 933189887bcfa9d84e0d4176446a99002a80ebb8 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:33:00 -0400
Subject: [PATCH 186/223] Fix `Style/StringLiterals` cop (#30005)

---
 .rubocop_todo.yml                          | 12 ------------
 config/environments/production.rb          |  4 ++--
 config/initializers/backtrace_silencers.rb |  2 +-
 config/initializers/http_client_proxy.rb   |  4 ++--
 config/initializers/rack_attack.rb         |  2 +-
 config/initializers/webauthn.rb            |  2 +-
 config/routes.rb                           |  2 +-
 7 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index ac65c1589..13f7b8c09 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -241,18 +241,6 @@ Style/StringConcatenation:
   Exclude:
     - 'config/initializers/paperclip.rb'
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
-# SupportedStyles: single_quotes, double_quotes
-Style/StringLiterals:
-  Exclude:
-    - 'config/environments/production.rb'
-    - 'config/initializers/backtrace_silencers.rb'
-    - 'config/initializers/http_client_proxy.rb'
-    - 'config/initializers/rack_attack.rb'
-    - 'config/initializers/webauthn.rb'
-    - 'config/routes.rb'
-
 # This cop supports safe autocorrection (--autocorrect).
 # Configuration parameters: EnforcedStyleForMultiline.
 # SupportedStylesForMultiline: comma, consistent_comma, no_comma
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 11da32f18..6587acfb3 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-require "active_support/core_ext/integer/time"
+require 'active_support/core_ext/integer/time'
 
 Rails.application.configure do
   # Settings specified here will take precedence over those in config/application.rb.
@@ -44,7 +44,7 @@ Rails.application.configure do
   config.force_ssl = true
   config.ssl_options = {
     redirect: {
-      exclude: ->(request) { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
+      exclude: ->(request) { request.path.start_with?('/health') || request.headers['Host'].end_with?('.onion') || request.headers['Host'].end_with?('.i2p') }
     }
   }
 
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
index 74f30e887..d43cc1d2f 100644
--- a/config/initializers/backtrace_silencers.rb
+++ b/config/initializers/backtrace_silencers.rb
@@ -7,4 +7,4 @@
 
 # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
 # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
-Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
+Rails.backtrace_cleaner.remove_silencers! if ENV['BACKTRACE']
diff --git a/config/initializers/http_client_proxy.rb b/config/initializers/http_client_proxy.rb
index 7332ffb53..93a8d33ff 100644
--- a/config/initializers/http_client_proxy.rb
+++ b/config/initializers/http_client_proxy.rb
@@ -7,7 +7,7 @@ Rails.application.configure do
     proxy = URI.parse(ENV['http_proxy'])
 
     raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme
-    raise "No proxy host" unless proxy.host
+    raise 'No proxy host' unless proxy.host
 
     host = proxy.host
     host = host[1...-1] if host[0] == '[' # for IPv6 address
@@ -24,7 +24,7 @@ Rails.application.configure do
     proxy = URI.parse(ENV['http_hidden_proxy'])
 
     raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme
-    raise "No proxy host" unless proxy.host
+    raise 'No proxy host' unless proxy.host
 
     host = proxy.host
     host = host[1...-1] if host[0] == '[' # for IPv6 address
diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb
index 429dbd324..fa1bdca54 100644
--- a/config/initializers/rack_attack.rb
+++ b/config/initializers/rack_attack.rb
@@ -14,7 +14,7 @@ class Rack::Attack
     end
 
     def remote_ip
-      @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
+      @remote_ip ||= (@env['action_dispatch.remote_ip'] || ip).to_s
     end
 
     def throttleable_remote_ip
diff --git a/config/initializers/webauthn.rb b/config/initializers/webauthn.rb
index 924ce6d87..40dfeb831 100644
--- a/config/initializers/webauthn.rb
+++ b/config/initializers/webauthn.rb
@@ -6,7 +6,7 @@ WebAuthn.configure do |config|
   config.origin = "#{Rails.configuration.x.use_https ? 'https' : 'http'}://#{Rails.configuration.x.web_domain}"
 
   # Relying Party name for display purposes
-  config.rp_name = "Mastodon"
+  config.rp_name = 'Mastodon'
 
   # Optionally configure a client timeout hint, in milliseconds.
   # This hint specifies how long the browser should wait for an
diff --git a/config/routes.rb b/config/routes.rb
index d032b5110..3d3c94096 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -139,7 +139,7 @@ Rails.application.routes.draw do
 
   resource :inbox, only: [:create], module: :activitypub
 
-  get '/:encoded_at(*path)', to: redirect("/@%{path}"), constraints: { encoded_at: /%40/ }
+  get '/:encoded_at(*path)', to: redirect('/@%{path}'), constraints: { encoded_at: /%40/ }
 
   constraints(username: %r{[^@/.]+}) do
     with_options to: 'accounts#show' do

From b6f04aed356e5e588dc4fe9d1e3adf82c2b12994 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:35:00 -0400
Subject: [PATCH 187/223] Silence warning about requiring `rubocop-rspec_rails`
 (#30002)

---
 .rubocop.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.rubocop.yml b/.rubocop.yml
index e80f3b293..1b5ce67ee 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -9,6 +9,7 @@ inherit_mode:
 require:
   - rubocop-rails
   - rubocop-rspec
+  - rubocop-rspec_rails
   - rubocop-performance
   - rubocop-capybara
   - ./lib/linter/rubocop_middle_dot

From c7384adc0087cb91d60b0f572aab14420271e608 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:37:18 -0400
Subject: [PATCH 188/223] Fix `Style/TrailingCommaInArguments` cop (#30003)

---
 .rubocop_todo.yml                | 7 -------
 config/initializers/paperclip.rb | 4 ++--
 2 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 13f7b8c09..5354c5488 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -241,13 +241,6 @@ Style/StringConcatenation:
   Exclude:
     - 'config/initializers/paperclip.rb'
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: EnforcedStyleForMultiline.
-# SupportedStylesForMultiline: comma, consistent_comma, no_comma
-Style/TrailingCommaInArguments:
-  Exclude:
-    - 'config/initializers/paperclip.rb'
-
 # This cop supports safe autocorrection (--autocorrect).
 # Configuration parameters: EnforcedStyleForMultiline.
 # SupportedStylesForMultiline: comma, consistent_comma, no_comma
diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb
index a44c2ab84..b54fc6cf0 100644
--- a/config/initializers/paperclip.rb
+++ b/config/initializers/paperclip.rb
@@ -73,7 +73,7 @@ if ENV['S3_ENABLED'] == 'true'
   if ENV.has_key?('S3_ENDPOINT')
     Paperclip::Attachment.default_options[:s3_options].merge!(
       endpoint: ENV['S3_ENDPOINT'],
-      force_path_style: ENV['S3_OVERRIDE_PATH_STYLE'] != 'true',
+      force_path_style: ENV['S3_OVERRIDE_PATH_STYLE'] != 'true'
     )
 
     Paperclip::Attachment.default_options[:url] = ':s3_path_url'
@@ -159,7 +159,7 @@ else
   Paperclip::Attachment.default_options.merge!(
     storage: :filesystem,
     path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'),
-    url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename',
+    url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename'
   )
 end
 

From 369b2ef0ed666686958cdbf81d52b5173c108e61 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:52:01 -0400
Subject: [PATCH 189/223] Fix `Style/TrailingCommaInHashLiteral` cop (#30004)

---
 .rubocop_todo.yml                 | 8 --------
 config/environments/production.rb | 4 ++--
 config/environments/test.rb       | 2 +-
 3 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 5354c5488..0bc9d2831 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -241,14 +241,6 @@ Style/StringConcatenation:
   Exclude:
     - 'config/initializers/paperclip.rb'
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: EnforcedStyleForMultiline.
-# SupportedStylesForMultiline: comma, consistent_comma, no_comma
-Style/TrailingCommaInHashLiteral:
-  Exclude:
-    - 'config/environments/production.rb'
-    - 'config/environments/test.rb'
-
 # This cop supports safe autocorrection (--autocorrect).
 # Configuration parameters: WordRegex.
 # SupportedStyles: percent, brackets
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 6587acfb3..49e02b53d 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -44,8 +44,8 @@ Rails.application.configure do
   config.force_ssl = true
   config.ssl_options = {
     redirect: {
-      exclude: ->(request) { request.path.start_with?('/health') || request.headers['Host'].end_with?('.onion') || request.headers['Host'].end_with?('.i2p') }
-    }
+      exclude: ->(request) { request.path.start_with?('/health') || request.headers['Host'].end_with?('.onion') || request.headers['Host'].end_with?('.i2p') },
+    },
   }
 
   # Info include generic and useful information about system operation, but avoids logging too much
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 0b2f57fba..13e197338 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -88,7 +88,7 @@ if ENV['PAM_ENABLED'] == 'true'
       usernames: Set['pam_user1', 'pam_user2'],
       servicenames: Set['pam_test', 'pam_test_controlled'],
       password: '123456',
-      env: { email: 'pam@example.com' }
+      env: { email: 'pam@example.com' },
     }
 end
 

From 35b517c207a5a5b24d5ac67ed9ad98943dcc3d7f Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Fri, 19 Apr 2024 16:53:01 -0400
Subject: [PATCH 190/223] Remove remnants of capistrano (#30009)

---
 config/deploy.rb | 35 -----------------------------------
 1 file changed, 35 deletions(-)
 delete mode 100644 config/deploy.rb

diff --git a/config/deploy.rb b/config/deploy.rb
deleted file mode 100644
index 28c838770..000000000
--- a/config/deploy.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-lock '3.17.2'
-
-set :repo_url, ENV.fetch('REPO', 'https://github.com/mastodon/mastodon.git')
-set :branch, ENV.fetch('BRANCH', 'main')
-
-set :application, 'mastodon'
-set :rbenv_type, :user
-set :rbenv_ruby, File.read('.ruby-version').strip
-set :migration_role, :app
-
-append :linked_files, '.env.production', 'public/robots.txt'
-append :linked_dirs, 'vendor/bundle', 'node_modules', 'public/system'
-
-SYSTEMD_SERVICES = %i(sidekiq streaming web).freeze
-SERVICE_ACTIONS = %i(reload restart status).freeze
-
-namespace :systemd do
-  SYSTEMD_SERVICES.each do |service|
-    SERVICE_ACTIONS.each do |action|
-      desc "Perform a #{action} on #{service} service"
-      task :"#{service}:#{action}" do
-        on roles(:app) do
-          # runs e.g. "sudo restart mastodon-sidekiq.service"
-          sudo :systemctl, action, "#{fetch(:application)}-#{service}.service"
-        end
-      end
-    end
-  end
-end
-
-after 'deploy:publishing', 'systemd:web:reload'
-after 'deploy:publishing', 'systemd:sidekiq:restart'
-after 'deploy:publishing', 'systemd:streaming:restart'

From 2ec9bff36e3a7efef501ec796d27cd73cede904c Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 04:04:05 -0400
Subject: [PATCH 191/223] Fix Rubocop `Rails/UniqueValidationWithoutIndex` cop
 (#27461)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 .rubocop_todo.yml                             |  9 ----
 ...o_webauthn_credentials_user_id_nickname.rb | 49 +++++++++++++++++++
 ...d_index_to_account_alias_uri_account_id.rb | 49 +++++++++++++++++++
 ...om_filter_statuses_status_custom_filter.rb | 49 +++++++++++++++++++
 ...59_add_index_to_identities_uid_provider.rb | 49 +++++++++++++++++++
 db/schema.rb                                  |  4 ++
 lib/tasks/tests.rake                          | 39 +++++++++++++++
 7 files changed, 239 insertions(+), 9 deletions(-)
 create mode 100644 db/migrate/20231018192110_add_index_to_webauthn_credentials_user_id_nickname.rb
 create mode 100644 db/migrate/20231018193209_add_index_to_account_alias_uri_account_id.rb
 create mode 100644 db/migrate/20231018193355_add_index_to_custom_filter_statuses_status_custom_filter.rb
 create mode 100644 db/migrate/20231018193659_add_index_to_identities_uid_provider.rb

diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 0bc9d2831..3f2e9aee6 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -54,15 +54,6 @@ Rails/OutputSafety:
   Exclude:
     - 'config/initializers/simple_form.rb'
 
-# Configuration parameters: Include.
-# Include: app/models/**/*.rb
-Rails/UniqueValidationWithoutIndex:
-  Exclude:
-    - 'app/models/account_alias.rb'
-    - 'app/models/custom_filter_status.rb'
-    - 'app/models/identity.rb'
-    - 'app/models/webauthn_credential.rb'
-
 # This cop supports unsafe autocorrection (--autocorrect-all).
 # Configuration parameters: AllowedMethods, AllowedPatterns.
 # AllowedMethods: ==, equal?, eql?
diff --git a/db/migrate/20231018192110_add_index_to_webauthn_credentials_user_id_nickname.rb b/db/migrate/20231018192110_add_index_to_webauthn_credentials_user_id_nickname.rb
new file mode 100644
index 000000000..2e608eead
--- /dev/null
+++ b/db/migrate/20231018192110_add_index_to_webauthn_credentials_user_id_nickname.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddIndexToWebauthnCredentialsUserIdNickname < ActiveRecord::Migration[7.0]
+  disable_ddl_transaction!
+
+  def up
+    add_index_to_table
+  rescue ActiveRecord::RecordNotUnique
+    remove_duplicates_and_reindex
+  end
+
+  def down
+    remove_index_from_table
+  end
+
+  private
+
+  def remove_duplicates_and_reindex
+    deduplicate_records
+    reindex_records
+  rescue ActiveRecord::RecordNotUnique
+    retry
+  end
+
+  def reindex_records
+    remove_index_from_table
+    add_index_to_table
+  end
+
+  def add_index_to_table
+    add_index :webauthn_credentials, [:user_id, :nickname], unique: true, algorithm: :concurrently
+  end
+
+  def remove_index_from_table
+    remove_index :webauthn_credentials, [:user_id, :nickname]
+  end
+
+  def deduplicate_records
+    safety_assured do
+      execute <<~SQL.squish
+        DELETE FROM webauthn_credentials
+          WHERE id NOT IN (
+          SELECT DISTINCT ON(user_id, nickname) id FROM webauthn_credentials
+          ORDER BY user_id, nickname, id ASC
+        )
+      SQL
+    end
+  end
+end
diff --git a/db/migrate/20231018193209_add_index_to_account_alias_uri_account_id.rb b/db/migrate/20231018193209_add_index_to_account_alias_uri_account_id.rb
new file mode 100644
index 000000000..4d9036fdf
--- /dev/null
+++ b/db/migrate/20231018193209_add_index_to_account_alias_uri_account_id.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddIndexToAccountAliasUriAccountId < ActiveRecord::Migration[7.0]
+  disable_ddl_transaction!
+
+  def up
+    add_index_to_table
+  rescue ActiveRecord::RecordNotUnique
+    remove_duplicates_and_reindex
+  end
+
+  def down
+    remove_index_from_table
+  end
+
+  private
+
+  def remove_duplicates_and_reindex
+    deduplicate_records
+    reindex_records
+  rescue ActiveRecord::RecordNotUnique
+    retry
+  end
+
+  def reindex_records
+    remove_index_from_table
+    add_index_to_table
+  end
+
+  def add_index_to_table
+    add_index :account_aliases, [:account_id, :uri], unique: true, algorithm: :concurrently
+  end
+
+  def remove_index_from_table
+    remove_index :account_aliases, [:account_id, :uri]
+  end
+
+  def deduplicate_records
+    safety_assured do
+      execute <<~SQL.squish
+        DELETE FROM account_aliases
+          WHERE id NOT IN (
+          SELECT DISTINCT ON(account_id, uri) id FROM account_aliases
+          ORDER BY account_id, uri, id ASC
+        )
+      SQL
+    end
+  end
+end
diff --git a/db/migrate/20231018193355_add_index_to_custom_filter_statuses_status_custom_filter.rb b/db/migrate/20231018193355_add_index_to_custom_filter_statuses_status_custom_filter.rb
new file mode 100644
index 000000000..4a23a8a94
--- /dev/null
+++ b/db/migrate/20231018193355_add_index_to_custom_filter_statuses_status_custom_filter.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddIndexToCustomFilterStatusesStatusCustomFilter < ActiveRecord::Migration[7.0]
+  disable_ddl_transaction!
+
+  def up
+    add_index_to_table
+  rescue ActiveRecord::RecordNotUnique
+    remove_duplicates_and_reindex
+  end
+
+  def down
+    remove_index_from_table
+  end
+
+  private
+
+  def remove_duplicates_and_reindex
+    deduplicate_records
+    reindex_records
+  rescue ActiveRecord::RecordNotUnique
+    retry
+  end
+
+  def reindex_records
+    remove_index_from_table
+    add_index_to_table
+  end
+
+  def add_index_to_table
+    add_index :custom_filter_statuses, [:status_id, :custom_filter_id], unique: true, algorithm: :concurrently
+  end
+
+  def remove_index_from_table
+    remove_index :custom_filter_statuses, [:status_id, :custom_filter_id]
+  end
+
+  def deduplicate_records
+    safety_assured do
+      execute <<~SQL.squish
+        DELETE FROM custom_filter_statuses
+          WHERE id NOT IN (
+          SELECT DISTINCT ON(status_id, custom_filter_id) id FROM custom_filter_statuses
+          ORDER BY status_id, custom_filter_id, id ASC
+        )
+      SQL
+    end
+  end
+end
diff --git a/db/migrate/20231018193659_add_index_to_identities_uid_provider.rb b/db/migrate/20231018193659_add_index_to_identities_uid_provider.rb
new file mode 100644
index 000000000..f0ba08b57
--- /dev/null
+++ b/db/migrate/20231018193659_add_index_to_identities_uid_provider.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddIndexToIdentitiesUidProvider < ActiveRecord::Migration[7.0]
+  disable_ddl_transaction!
+
+  def up
+    add_index_to_table
+  rescue ActiveRecord::RecordNotUnique
+    remove_duplicates_and_reindex
+  end
+
+  def down
+    remove_index_from_table
+  end
+
+  private
+
+  def remove_duplicates_and_reindex
+    deduplicate_records
+    reindex_records
+  rescue ActiveRecord::RecordNotUnique
+    retry
+  end
+
+  def reindex_records
+    remove_index_from_table
+    add_index_to_table
+  end
+
+  def add_index_to_table
+    add_index :identities, [:uid, :provider], unique: true, algorithm: :concurrently
+  end
+
+  def remove_index_from_table
+    remove_index :identities, [:uid, :provider]
+  end
+
+  def deduplicate_records
+    safety_assured do
+      execute <<~SQL.squish
+        DELETE FROM identities
+          WHERE id NOT IN (
+          SELECT DISTINCT ON(uid, provider) id FROM identities
+          ORDER BY uid, provider, id ASC
+        )
+      SQL
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 27c486487..6a52333a8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -20,6 +20,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
     t.string "uri", default: "", null: false
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
+    t.index ["account_id", "uri"], name: "index_account_aliases_on_account_id_and_uri", unique: true
     t.index ["account_id"], name: "index_account_aliases_on_account_id"
   end
 
@@ -395,6 +396,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.index ["custom_filter_id"], name: "index_custom_filter_statuses_on_custom_filter_id"
+    t.index ["status_id", "custom_filter_id"], name: "index_custom_filter_statuses_on_status_id_and_custom_filter_id", unique: true
     t.index ["status_id"], name: "index_custom_filter_statuses_on_status_id"
   end
 
@@ -545,6 +547,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
     t.bigint "user_id"
+    t.index ["uid", "provider"], name: "index_identities_on_uid_and_provider", unique: true
     t.index ["user_id"], name: "index_identities_on_user_id"
   end
 
@@ -1235,6 +1238,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
     t.index ["external_id"], name: "index_webauthn_credentials_on_external_id", unique: true
+    t.index ["user_id", "nickname"], name: "index_webauthn_credentials_on_user_id_and_nickname", unique: true
     t.index ["user_id"], name: "index_webauthn_credentials_on_user_id"
   end
 
diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake
index 6afc013ed..0caebf92a 100644
--- a/lib/tasks/tests.rake
+++ b/lib/tasks/tests.rake
@@ -8,6 +8,7 @@ namespace :tests do
         '2' => 2017_10_10_025614,
         '2_4' => 2018_05_14_140000,
         '2_4_3' => 2018_07_07_154237,
+        '3_3_0' => 2020_12_18_054746,
       }.each do |release, version|
         ActiveRecord::Tasks::DatabaseTasks
           .migration_connection
@@ -111,9 +112,41 @@ namespace :tests do
         exit(1)
       end
 
+      unless Identity.where(provider: 'foo', uid: 0).count == 1
+        puts 'Identities not deduplicated as expected'
+        exit(1)
+      end
+
+      unless WebauthnCredential.where(user_id: 1, nickname: 'foo').count == 1
+        puts 'Webauthn credentials not deduplicated as expected'
+        exit(1)
+      end
+
+      unless AccountAlias.where(account_id: 1, uri: 'https://example.com/users/foobar').count == 1
+        puts 'Account aliases not deduplicated as expected'
+        exit(1)
+      end
+
       puts 'No errors found. Database state is consistent with a successful migration process.'
     end
 
+    desc 'Populate the database with test data for 3.3.0'
+    task populate_v3_3_0: :environment do # rubocop:disable Naming/VariableNumber
+      ActiveRecord::Base.connection.execute(<<~SQL.squish)
+        INSERT INTO "webauthn_credentials"
+          (user_id, nickname, external_id, public_key, created_at, updated_at)
+        VALUES
+          (1, 'foo', 1, 'foo', now(), now()),
+          (1, 'foo', 2, 'bar', now(), now());
+
+        INSERT INTO "account_aliases"
+          (account_id, uri, acct, created_at, updated_at)
+        VALUES
+          (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()),
+          (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now());
+      SQL
+    end
+
     desc 'Populate the database with test data for 2.4.3'
     task populate_v2_4_3: :environment do # rubocop:disable Naming/VariableNumber
       user_key = OpenSSL::PKey::RSA.new(2048)
@@ -189,6 +222,12 @@ namespace :tests do
         VALUES
           (5, 'User', 4, 'default_language', E'--- kmr\n', now(), now()),
           (6, 'User', 1, 'interactions', E'--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nmust_be_follower: false\nmust_be_following: true\nmust_be_following_dm: false\n', now(), now());
+
+        INSERT INTO "identities"
+          (provider, uid, user_id, created_at, updated_at)
+        VALUES
+          ('foo', 0, 1, now(), now()),
+          ('foo', 0, 1, now(), now());
       SQL
     end
 

From 223936c2e8237d83fcf403c8dcca80aa201157f0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 10:13:04 +0200
Subject: [PATCH 192/223] Update eslint (non-major) to v7.7.0 (#30026)

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

diff --git a/yarn.lock b/yarn.lock
index c0d1e91b6..e0001120a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2154,7 +2154,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1":
+"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1":
   version: 4.10.0
   resolution: "@eslint-community/regexpp@npm:4.10.0"
   checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4
@@ -3619,10 +3619,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8":
-  version: 7.0.14
-  resolution: "@types/json-schema@npm:7.0.14"
-  checksum: 10c0/da68689ccd44cb93ca4c9a4af3b25c6091ecf45fb370d1ed0d0ac5b780e235bf0b9bdc1f7e28f19e6713b22567c3db11fefcbcc6d48ac6b356d035a8f9f4ea30
+"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8":
+  version: 7.0.15
+  resolution: "@types/json-schema@npm:7.0.15"
+  checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db
   languageName: node
   linkType: hard
 
@@ -3897,10 +3897,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/semver@npm:^7.5.0":
-  version: 7.5.4
-  resolution: "@types/semver@npm:7.5.4"
-  checksum: 10c0/dee66a71d9f089c118be74b5937d4fef42864d68d9472a3f4f5399b9e3ad74d56a8e155020c846667b9ecf9de78fdb9ea55a53fff5067af28e06779b282b6c40
+"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.8":
+  version: 7.5.8
+  resolution: "@types/semver@npm:7.5.8"
+  checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa
   languageName: node
   linkType: hard
 
@@ -4041,45 +4041,45 @@ __metadata:
   linkType: hard
 
 "@typescript-eslint/eslint-plugin@npm:^7.0.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/eslint-plugin@npm:7.5.0"
+  version: 7.7.0
+  resolution: "@typescript-eslint/eslint-plugin@npm:7.7.0"
   dependencies:
-    "@eslint-community/regexpp": "npm:^4.5.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"
+    "@eslint-community/regexpp": "npm:^4.10.0"
+    "@typescript-eslint/scope-manager": "npm:7.7.0"
+    "@typescript-eslint/type-utils": "npm:7.7.0"
+    "@typescript-eslint/utils": "npm:7.7.0"
+    "@typescript-eslint/visitor-keys": "npm:7.7.0"
     debug: "npm:^4.3.4"
     graphemer: "npm:^1.4.0"
-    ignore: "npm:^5.2.4"
+    ignore: "npm:^5.3.1"
     natural-compare: "npm:^1.4.0"
-    semver: "npm:^7.5.4"
-    ts-api-utils: "npm:^1.0.1"
+    semver: "npm:^7.6.0"
+    ts-api-utils: "npm:^1.3.0"
   peerDependencies:
     "@typescript-eslint/parser": ^7.0.0
     eslint: ^8.56.0
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/932a7b5a09c0138ef5a0bf00f8e6039fa209d4047092ffc187de048543c21f7ce24dc14f25f4c87b6f3bbb62335fc952e259e271fde88baf793217bde6460cfa
+  checksum: 10c0/d1f4c40523d284bce4b8272750c68aae5c0289ddb1c9267dd3477e0bfb8c8855bfb0c6e86dfec9911ca8302ef729d5f4e47d686a566f363b0f89bf7dc7670b5c
   languageName: node
   linkType: hard
 
 "@typescript-eslint/parser@npm:^7.0.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/parser@npm:7.5.0"
+  version: 7.7.0
+  resolution: "@typescript-eslint/parser@npm:7.7.0"
   dependencies:
-    "@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"
+    "@typescript-eslint/scope-manager": "npm:7.7.0"
+    "@typescript-eslint/types": "npm:7.7.0"
+    "@typescript-eslint/typescript-estree": "npm:7.7.0"
+    "@typescript-eslint/visitor-keys": "npm:7.7.0"
     debug: "npm:^4.3.4"
   peerDependencies:
     eslint: ^8.56.0
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/65521202ff024e79594272fbb7e4731ecf9d2fdd2f58fc81450bfd2bca94ce9c17b0eadd7338c01701f5cf16d38b6c025ed3fc322380b1e4b5424b7484098cda
+  checksum: 10c0/d756c2292737499a93913647af7493aded5dc720a5f4ab6f8e96d6cc81f19cf6a1769a1df0f516f8facd276d34f8464f1711e57b0216082e32eb6b75da81b12e
   languageName: node
   linkType: hard
 
@@ -4093,30 +4093,30 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/scope-manager@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/scope-manager@npm:7.5.0"
+"@typescript-eslint/scope-manager@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/scope-manager@npm:7.7.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.5.0"
-    "@typescript-eslint/visitor-keys": "npm:7.5.0"
-  checksum: 10c0/a017b151a6b39ef591f8e2e65598e005e1b4b2d5494e4b91bddb5856b3a4d57dd8a58d2bc7a140e627eb574f93a2c8fe55f1307aa264c928ffd31d9e190bc5dd
+    "@typescript-eslint/types": "npm:7.7.0"
+    "@typescript-eslint/visitor-keys": "npm:7.7.0"
+  checksum: 10c0/014a3631c12bfbd5e33146a48e4b9eb5cc1c5c95bb458de33f8847eed33c04d7b9e66283971e48297673c4b92c3239d67e6dc3717efbe5836e0269a538c13d2e
   languageName: node
   linkType: hard
 
-"@typescript-eslint/type-utils@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/type-utils@npm:7.5.0"
+"@typescript-eslint/type-utils@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/type-utils@npm:7.7.0"
   dependencies:
-    "@typescript-eslint/typescript-estree": "npm:7.5.0"
-    "@typescript-eslint/utils": "npm:7.5.0"
+    "@typescript-eslint/typescript-estree": "npm:7.7.0"
+    "@typescript-eslint/utils": "npm:7.7.0"
     debug: "npm:^4.3.4"
-    ts-api-utils: "npm:^1.0.1"
+    ts-api-utils: "npm:^1.3.0"
   peerDependencies:
     eslint: ^8.56.0
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/12915d4d1872638f5281e222a0d191676c478f250699c84864862e95a59e708222acefbf7ffdafc0872a007261219a3a2b1e667ff45eeafea7c4bcc5b955262c
+  checksum: 10c0/064c28d4087a97fd175e07e02c0a9cf4526f61cc6a17b4199fba626932979210037643a30f868bda8174fad567a8ac6aed34120631d1ecfd502e0ea1e830f9e9
   languageName: node
   linkType: hard
 
@@ -4127,10 +4127,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/types@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/types@npm:7.5.0"
-  checksum: 10c0/f3394f71f422dbd89f63b230f20e9769c12e47a287ff30ca03a80714e57ea21279b6f12a8ab14bafb00b59926f20a88894b2d1e72679f7ff298bae112679d4b3
+"@typescript-eslint/types@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/types@npm:7.7.0"
+  checksum: 10c0/eb50793650c9a911c73586150807912e7b7a0ae12eeb26c7a322ac8ebb8edef15960cc9a4b7049dbb89b82500079963145f67d15583f5de270fe8290974db533
   languageName: node
   linkType: hard
 
@@ -4153,39 +4153,39 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/typescript-estree@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/typescript-estree@npm:7.5.0"
+"@typescript-eslint/typescript-estree@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/typescript-estree@npm:7.7.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.5.0"
-    "@typescript-eslint/visitor-keys": "npm:7.5.0"
+    "@typescript-eslint/types": "npm:7.7.0"
+    "@typescript-eslint/visitor-keys": "npm:7.7.0"
     debug: "npm:^4.3.4"
     globby: "npm:^11.1.0"
     is-glob: "npm:^4.0.3"
-    minimatch: "npm:9.0.3"
-    semver: "npm:^7.5.4"
-    ts-api-utils: "npm:^1.0.1"
+    minimatch: "npm:^9.0.4"
+    semver: "npm:^7.6.0"
+    ts-api-utils: "npm:^1.3.0"
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10c0/ea3a270c725d6be273188b86110e0393052cd64d1c54a56eb5ea405e6d3fbbe84fb3b1ce1b8496a4078ac1eefd37aedcf12be91876764f6de31d5aa5131c7bcd
+  checksum: 10c0/19da9bf0948c9800fde19c5a408a80a3a4cf357ff67d47b516df5d2a05701a4fdd2b9ab5b692866bd84bfc17cea9132d1575a1423e01763a4c2918b5d77d0b34
   languageName: node
   linkType: hard
 
-"@typescript-eslint/utils@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/utils@npm:7.5.0"
+"@typescript-eslint/utils@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/utils@npm:7.7.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.5.0"
-    "@typescript-eslint/types": "npm:7.5.0"
-    "@typescript-eslint/typescript-estree": "npm:7.5.0"
-    semver: "npm:^7.5.4"
+    "@types/json-schema": "npm:^7.0.15"
+    "@types/semver": "npm:^7.5.8"
+    "@typescript-eslint/scope-manager": "npm:7.7.0"
+    "@typescript-eslint/types": "npm:7.7.0"
+    "@typescript-eslint/typescript-estree": "npm:7.7.0"
+    semver: "npm:^7.6.0"
   peerDependencies:
     eslint: ^8.56.0
-  checksum: 10c0/c815ed6909769648953d6963c069038f7cac0c979051b25718feb30e0d3337b9647b75b8de00ac03fe960f0cc8dc4e8a81d4aac4719090a99785e0068712bd24
+  checksum: 10c0/c5f18ce198b420bdc201fd4278b4fa97bfe86178db565f3c4e1991bb452c9ea0b657e7980572555e2ec2fe218d07c42c794d217b9369903019cf784eea7e2164
   languageName: node
   linkType: hard
 
@@ -4216,13 +4216,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/visitor-keys@npm:7.5.0":
-  version: 7.5.0
-  resolution: "@typescript-eslint/visitor-keys@npm:7.5.0"
+"@typescript-eslint/visitor-keys@npm:7.7.0":
+  version: 7.7.0
+  resolution: "@typescript-eslint/visitor-keys@npm:7.7.0"
   dependencies:
-    "@typescript-eslint/types": "npm:7.5.0"
-    eslint-visitor-keys: "npm:^3.4.1"
-  checksum: 10c0/eecf02b8dd54e83738a143aca87b902af4b357028a90fd34ed7a2f40a3ae2f6a188b9ba53903f23c80e868f1fffbb039e9ddb63525438d659707cc7bfb269317
+    "@typescript-eslint/types": "npm:7.7.0"
+    eslint-visitor-keys: "npm:^3.4.3"
+  checksum: 10c0/0f3b9720a962c04462a75d4872714c07320c8f672841881ada797ae960f9f6bd0e5f7494178917034f42635ef76f0f09fa3c8d4bd84f31ec58ee968fe75bada7
   languageName: node
   linkType: hard
 
@@ -9397,7 +9397,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1":
+"ignore@npm:^5.2.0, ignore@npm:^5.3.1":
   version: 5.3.1
   resolution: "ignore@npm:5.3.1"
   checksum: 10c0/703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd
@@ -11761,7 +11761,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"minimatch@npm:9.0.3, minimatch@npm:^9.0.1":
+"minimatch@npm:9.0.3":
   version: 9.0.3
   resolution: "minimatch@npm:9.0.3"
   dependencies:
@@ -11788,6 +11788,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"minimatch@npm:^9.0.1, minimatch@npm:^9.0.4":
+  version: 9.0.4
+  resolution: "minimatch@npm:9.0.4"
+  dependencies:
+    brace-expansion: "npm:^2.0.1"
+  checksum: 10c0/2c16f21f50e64922864e560ff97c587d15fd491f65d92a677a344e970fe62aafdbeafe648965fa96d33c061b4d0eabfe0213466203dd793367e7f28658cf6414
+  languageName: node
+  linkType: hard
+
 "minimist@npm:^1.2.0, minimist@npm:^1.2.6":
   version: 1.2.8
   resolution: "minimist@npm:1.2.8"
@@ -16861,12 +16870,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ts-api-utils@npm:^1.0.1":
-  version: 1.0.3
-  resolution: "ts-api-utils@npm:1.0.3"
+"ts-api-utils@npm:^1.0.1, ts-api-utils@npm:^1.3.0":
+  version: 1.3.0
+  resolution: "ts-api-utils@npm:1.3.0"
   peerDependencies:
     typescript: ">=4.2.0"
-  checksum: 10c0/9408338819c3aca2a709f0bc54e3f874227901506cacb1163612a6c8a43df224174feb965a5eafdae16f66fc68fd7bfee8d3275d0fa73fbb8699e03ed26520c9
+  checksum: 10c0/f54a0ba9ed56ce66baea90a3fa087a484002e807f28a8ccb2d070c75e76bde64bd0f6dce98b3802834156306050871b67eec325cb4e918015a360a3f0868c77c
   languageName: node
   linkType: hard
 

From 88f946890d29cd78dd71e4bd17a13da93d9e92ee Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 10:13:28 +0200
Subject: [PATCH 193/223] Update peter-evans/create-pull-request action to
 v6.0.4 (#30025)

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 14b0542d7..256dcffc7 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.3
+        uses: peter-evans/create-pull-request@v6.0.4
         with:
           commit-message: 'New Crowdin translations'
           title: 'New Crowdin Translations (automated)'

From 3e21af3e4aecef9298c0e2392750b2d005f75c0a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 08:14:09 +0000
Subject: [PATCH 194/223] Update dependency @types/react to v18.2.79 (#30024)

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 e0001120a..1f5a3275b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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.78
-  resolution: "@types/react@npm:18.2.78"
+  version: 18.2.79
+  resolution: "@types/react@npm:18.2.79"
   dependencies:
     "@types/prop-types": "npm:*"
     csstype: "npm:^3.0.2"
-  checksum: 10c0/5eb8e1dd98c29aeddf40b90f466d1a9ce83b113d42a096633d632b834e7ae9821f24ba7999928de9d98cca37764532a7ea35355a8103a377d8baa750f1841b5c
+  checksum: 10c0/c8a8a005d8830a48cc1ef93c3510c4935a2a03e5557dbecaa8f1038450cbfcb18eb206fa7fba7077d54b8da21faeb25577e897a333392770a7797f625b62c78a
   languageName: node
   linkType: hard
 

From 24e67c4394bc545fc4b3e9bc4c3b87b0d98f36ee Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 10:24:08 +0200
Subject: [PATCH 195/223] Update dependency postcss-preset-env to v9.5.8
 (#30018)

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

diff --git a/yarn.lock b/yarn.lock
index 1f5a3275b..e6e130e2d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1561,10 +1561,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/color-helpers@npm:^4.1.0":
-  version: 4.1.0
-  resolution: "@csstools/color-helpers@npm:4.1.0"
-  checksum: 10c0/0e41fd04dd28361717b161e7000c3a3b64b8b01119e93758297ea0b8a87c04121c3e3ef02e29c56fdd133227dd879163aa4b52e2370853d9fe64af6b6821668d
+"@csstools/color-helpers@npm:^4.2.0":
+  version: 4.2.0
+  resolution: "@csstools/color-helpers@npm:4.2.0"
+  checksum: 10c0/3f1feac43c2ef35f38b3b06fe74e0acc130283d7efb6874f6624e45e178c1a7b3c7e39816c7421cddbffc2666430906aa6f0d3dd7c7209db1369c0afd4a29b1b
   languageName: node
   linkType: hard
 
@@ -1578,16 +1578,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/css-color-parser@npm:^1.6.3":
-  version: 1.6.3
-  resolution: "@csstools/css-color-parser@npm:1.6.3"
+"@csstools/css-color-parser@npm:^2.0.0":
+  version: 2.0.0
+  resolution: "@csstools/css-color-parser@npm:2.0.0"
   dependencies:
-    "@csstools/color-helpers": "npm:^4.1.0"
+    "@csstools/color-helpers": "npm:^4.2.0"
     "@csstools/css-calc": "npm:^1.2.0"
   peerDependencies:
     "@csstools/css-parser-algorithms": ^2.6.1
     "@csstools/css-tokenizer": ^2.2.4
-  checksum: 10c0/3b15d9974105fe6e5d5e839953ee06153bc308bd62feacdeb88b7da7486ef1625254d0df908c68654596e477ca6be0c312d0c02a62d6dc4bddee61821be17d27
+  checksum: 10c0/295f844a194dec4f51439e8760dbb4a142901b8b60cd9d676a62c15c0e8408eb7bcdcbb40be52cdd5f67d020e655a1c3267a28923cfc4f6bae2b74aa48fce426
   languageName: node
   linkType: hard
 
@@ -1629,33 +1629,33 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-color-function@npm:^3.0.13":
-  version: 3.0.13
-  resolution: "@csstools/postcss-color-function@npm:3.0.13"
+"@csstools/postcss-color-function@npm:^3.0.14":
+  version: 3.0.14
+  resolution: "@csstools/postcss-color-function@npm:3.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/9d0fa25cd258653ad3227ccf1ee89dfee7099284c28b1d9ae7f7e8b15ed526e4e8cc7724f8e21cc073ed186891c3acb5b9c190a75e3c38d9c75e49197a824db6
+  checksum: 10c0/81592b0eb3ad7022313ecafd028908b167de42acc6765f708c9b10631f86123c2b803aca27378f021c2b3dab8cc47770c0364fe5a3c1e18ec006deaf72e17c38
   languageName: node
   linkType: hard
 
-"@csstools/postcss-color-mix-function@npm:^2.0.13":
-  version: 2.0.13
-  resolution: "@csstools/postcss-color-mix-function@npm:2.0.13"
+"@csstools/postcss-color-mix-function@npm:^2.0.14":
+  version: 2.0.14
+  resolution: "@csstools/postcss-color-mix-function@npm:2.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/6011ce0b328cd3ee1d5720dc6eb23da807ba5a218a4a3c65a4844a82c0ff37e69d27cbee14abf9b928a3068f429ab86f2dd2bebab4ab64cd8fc7e39e562d7073
+  checksum: 10c0/1dd3c63bbbbb9d3094699f169bbb9d26e86a49accb5f9abaa2441b54cb8a6f4cd332409666684a275eca867e3ef0ea3f6eafdf9fb87f2cbfa17c6296fb1ed4d7
   languageName: node
   linkType: hard
 
@@ -1684,46 +1684,46 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-gamut-mapping@npm:^1.0.6":
-  version: 1.0.6
-  resolution: "@csstools/postcss-gamut-mapping@npm:1.0.6"
+"@csstools/postcss-gamut-mapping@npm:^1.0.7":
+  version: 1.0.7
+  resolution: "@csstools/postcss-gamut-mapping@npm:1.0.7"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/a258a2ceac9d9be4374ec5b504895bd1de1196fe7d8c1377863a25c6cb50ee1fb1c65387c5440bae3c5d59e6ebf4e0c1990595c5cd09291224b31a1d23bdc250
+  checksum: 10c0/7b349db44fcd697d57172ab63b7a02a56c0b49bce17e48cb72aa0fa246bd2be83fe693c507fd400a9ed83597a711d18ece9319ee3af8000c8fd3a2761e228a11
   languageName: node
   linkType: hard
 
-"@csstools/postcss-gradients-interpolation-method@npm:^4.0.14":
-  version: 4.0.14
-  resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.14"
+"@csstools/postcss-gradients-interpolation-method@npm:^4.0.15":
+  version: 4.0.15
+  resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.15"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/88147b2d7067b9bc6c90340c0be8450ca1175a7e927ff7b682c26d377237bec12f1cbe0dd930dd72dec661603348d1e71ca2a56f0a3b6fa2ca7d3f1b962f001d
+  checksum: 10c0/dc0bbf6a4787d5ad3f9fe268dfa9776ecdc25b6cc0a49486bf53238341a339647f1e475240ead3cec1f4af9a237f6518ace015103e90ce8afe4d44539a566e04
   languageName: node
   linkType: hard
 
-"@csstools/postcss-hwb-function@npm:^3.0.12":
-  version: 3.0.12
-  resolution: "@csstools/postcss-hwb-function@npm:3.0.12"
+"@csstools/postcss-hwb-function@npm:^3.0.13":
+  version: 3.0.13
+  resolution: "@csstools/postcss-hwb-function@npm:3.0.13"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/20e0b2a4547fe619f38fe56c33974750d4a8b64a67a4169740ee0e67a9dec9f3a243f2370408901aacc35690aa36135028fafbbc866ff934b66cc4c9e4e89cac
+  checksum: 10c0/684c3d408ceb027e7276c4f25c9a17ef9bd52f0948268cf58b5184097e9b71f5364a41b42bab44691938c6fadffcba0c8e66f809a339a8b282f4a432d32d00ef
   languageName: node
   linkType: hard
 
@@ -1875,18 +1875,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-oklab-function@npm:^3.0.13":
-  version: 3.0.13
-  resolution: "@csstools/postcss-oklab-function@npm:3.0.13"
+"@csstools/postcss-oklab-function@npm:^3.0.14":
+  version: 3.0.14
+  resolution: "@csstools/postcss-oklab-function@npm:3.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/26915f65ccc8b631a08542c4b088f9e5155f95a6c1f3a6bd2a33207f96d33438b930de60f493a5bbfee1b9f2abc8dfcab3ecbf20b5c7445d729fc434234fb046
+  checksum: 10c0/dfe0b12c2256dded995c64825fac9507be9c747d776cfa09eeefff6dee0efa5eed6a92a1ecba39069a751a7fc3cefa8891c34209a7a3c7ea33d356c95d01a02d
   languageName: node
   linkType: hard
 
@@ -1901,18 +1901,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-relative-color-syntax@npm:^2.0.13":
-  version: 2.0.13
-  resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.13"
+"@csstools/postcss-relative-color-syntax@npm:^2.0.14":
+  version: 2.0.14
+  resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/5c9fdec029e3d9a5c688d2e04995fec0cf6d91b48dbc5f450cf9c9dbb45e2819afbd63b3279676087a13f54914b0ec7d005e478b70b43e94fc8eeef9c5973390
+  checksum: 10c0/64cd5f8054e4403f4e25ed11a5b9d157098af639dbc30ac25b94660b3af489c0bacc49fc439cba1ccceefa4caa5831a913e3d1d889a9796cc6fbf3902c7c31c1
   languageName: node
   linkType: hard
 
@@ -1940,15 +1940,15 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@csstools/postcss-text-decoration-shorthand@npm:^3.0.5":
-  version: 3.0.5
-  resolution: "@csstools/postcss-text-decoration-shorthand@npm:3.0.5"
+"@csstools/postcss-text-decoration-shorthand@npm:^3.0.6":
+  version: 3.0.6
+  resolution: "@csstools/postcss-text-decoration-shorthand@npm:3.0.6"
   dependencies:
-    "@csstools/color-helpers": "npm:^4.1.0"
+    "@csstools/color-helpers": "npm:^4.2.0"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/e7e08c643c7084e60c0b22982e00ce21c579af3810ebbebac6838801b2ac622026ce96fd0cbca785613b1559f2337833cfc0f525685f8543ee39078a32fd7f89
+  checksum: 10c0/5abdc4fad1c3f15e9d47c7af3995dec9cdf4e6f87c5857eb2e149764779b8389f4f4b21d11e6f2509c57c554a0dc5c11f68f212acd04bbc47defa15911ac3eb9
   languageName: node
   linkType: hard
 
@@ -13078,18 +13078,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-color-functional-notation@npm:^6.0.8":
-  version: 6.0.8
-  resolution: "postcss-color-functional-notation@npm:6.0.8"
+"postcss-color-functional-notation@npm:^6.0.9":
+  version: 6.0.9
+  resolution: "postcss-color-functional-notation@npm:6.0.9"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/ae2ff7769970fb403ea71d5613e041d97bb647cfc54e4a428bcc75f98ff06c888b064384df12b18f609bfcc4395c31d6db4ad2b9c9385a829ba594d2692c31d1
+  checksum: 10c0/120f7bc23bf46dd1c008b3aa806fb02dd988ae180f9c0c10dca9f5ea3473bf20d7743aafae1441df5b4a3945a63ebb0dae1d4d55f7c8bcd34540529b627c4e3e
   languageName: node
   linkType: hard
 
@@ -13298,18 +13298,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-lab-function@npm:^6.0.13":
-  version: 6.0.13
-  resolution: "postcss-lab-function@npm:6.0.13"
+"postcss-lab-function@npm:^6.0.14":
+  version: 6.0.14
+  resolution: "postcss-lab-function@npm:6.0.14"
   dependencies:
-    "@csstools/css-color-parser": "npm:^1.6.3"
+    "@csstools/css-color-parser": "npm:^2.0.0"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
     "@csstools/css-tokenizer": "npm:^2.2.4"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
     "@csstools/utilities": "npm:^1.0.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/3ffb82d0012e49df49b44f38a131f4b13ba3edeeca5ecc0062c1c1b6bd8961c06f05b1dd8ec620c50c2c406fc61a505d79488745185d69ed325603600f0a1bc8
+  checksum: 10c0/0b5d998ddb98ec6243448f1eca216f6e23872431885b152843feef1e844fc5b6b3ebe16ea8940f3d6abea732aa0c51b2ec0e57437e4326e5b2cb2bcb949e6d9f
   languageName: node
   linkType: hard
 
@@ -13465,16 +13465,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-nesting@npm:^12.1.1":
-  version: 12.1.1
-  resolution: "postcss-nesting@npm:12.1.1"
+"postcss-nesting@npm:^12.1.2":
+  version: 12.1.2
+  resolution: "postcss-nesting@npm:12.1.2"
   dependencies:
     "@csstools/selector-resolve-nested": "npm:^1.1.0"
     "@csstools/selector-specificity": "npm:^3.0.3"
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/8fac718e69ee2ac93179cc59810a8184581c04715fe34621ec5d504fc680cad4a11219ed0c918cbe15c468994c9aba88e729f35eef698c5d44cadd824425c47d
+  checksum: 10c0/39d1d100f61863f904393b17169be83cdf82bd50d530efb3e3ae0c7b0f838b254e10e5d12e25119cf31dce9e351a2b770a03f9b2029ff33bef0ec924c0d2f642
   languageName: node
   linkType: hard
 
@@ -13629,17 +13629,17 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.6
-  resolution: "postcss-preset-env@npm:9.5.6"
+  version: 9.5.8
+  resolution: "postcss-preset-env@npm:9.5.8"
   dependencies:
     "@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-color-function": "npm:^3.0.14"
+    "@csstools/postcss-color-mix-function": "npm:^2.0.14"
     "@csstools/postcss-exponential-functions": "npm:^1.0.5"
     "@csstools/postcss-font-format-keywords": "npm:^3.0.2"
-    "@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-gamut-mapping": "npm:^1.0.7"
+    "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.15"
+    "@csstools/postcss-hwb-function": "npm:^3.0.13"
     "@csstools/postcss-ic-unit": "npm:^3.0.6"
     "@csstools/postcss-initial": "npm:^1.0.1"
     "@csstools/postcss-is-pseudo-class": "npm:^4.0.6"
@@ -13653,12 +13653,12 @@ __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.13"
+    "@csstools/postcss-oklab-function": "npm:^3.0.14"
     "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0"
-    "@csstools/postcss-relative-color-syntax": "npm:^2.0.13"
+    "@csstools/postcss-relative-color-syntax": "npm:^2.0.14"
     "@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.5"
+    "@csstools/postcss-text-decoration-shorthand": "npm:^3.0.6"
     "@csstools/postcss-trigonometric-functions": "npm:^3.0.6"
     "@csstools/postcss-unset-value": "npm:^3.0.1"
     autoprefixer: "npm:^10.4.19"
@@ -13669,7 +13669,7 @@ __metadata:
     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.8"
+    postcss-color-functional-notation: "npm:^6.0.9"
     postcss-color-hex-alpha: "npm:^9.0.4"
     postcss-color-rebeccapurple: "npm:^9.0.3"
     postcss-custom-media: "npm:^10.0.4"
@@ -13682,30 +13682,30 @@ __metadata:
     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.13"
+    postcss-lab-function: "npm:^6.0.14"
     postcss-logical: "npm:^7.0.1"
-    postcss-nesting: "npm:^12.1.1"
+    postcss-nesting: "npm:^12.1.2"
     postcss-opacity-percentage: "npm:^2.0.0"
     postcss-overflow-shorthand: "npm:^5.0.1"
     postcss-page-break: "npm:^3.0.4"
     postcss-place: "npm:^9.0.1"
-    postcss-pseudo-class-any-link: "npm:^9.0.1"
+    postcss-pseudo-class-any-link: "npm:^9.0.2"
     postcss-replace-overflow-wrap: "npm:^4.0.0"
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/21738ecac400cca9a96841959308538516ed00ca80d4c53beb20e080c7d963120fa77b7435b02e1beefc20043abce666419b81eccf6dacdc4298f540778c111d
+  checksum: 10c0/5f77272eb7a938e5bedc3a0877f3fb0cdc6f20c8829730ccafbbd999db78ba4e6ac60f485aa7c292f70e011cf3edfadb7d2cc5459cbf9851abc25139eeb061b7
   languageName: node
   linkType: hard
 
-"postcss-pseudo-class-any-link@npm:^9.0.1":
-  version: 9.0.1
-  resolution: "postcss-pseudo-class-any-link@npm:9.0.1"
+"postcss-pseudo-class-any-link@npm:^9.0.2":
+  version: 9.0.2
+  resolution: "postcss-pseudo-class-any-link@npm:9.0.2"
   dependencies:
     postcss-selector-parser: "npm:^6.0.13"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/2d33f486af442a0ee095b7b8875701ed3f54ea3f80d2c4d1c1b35d105088b569c847e1c71fde2adf6cefb4920e8fb7d057ff1ad56e62c65892c7b68e26213b98
+  checksum: 10c0/cc2cb455a793b1f5dc0ac290e02296eafb317d9ce987dc9f2102027e22f265299666dbd1e78f1d7836fce549dead73f41e24251c08a2dd0cf482f3cc43cf7909
   languageName: node
   linkType: hard
 

From a15139bc02d279b9ef85e95990f41e3e88838d20 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 04:30:38 -0400
Subject: [PATCH 196/223] Fix intermittent order based failure in
 `UpdateStatusService` spec (#30008)

---
 spec/services/update_status_service_spec.rb | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb
index 930f673e1..47be53f4f 100644
--- a/spec/services/update_status_service_spec.rb
+++ b/spec/services/update_status_service_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe UpdateStatusService do
     end
 
     it 'saves edit history' do
-      expect(status.edits.pluck(:text)).to eq %w(Foo Bar)
+      expect(status.edits.ordered.pluck(:text)).to eq %w(Foo Bar)
     end
   end
 
@@ -58,7 +58,7 @@ RSpec.describe UpdateStatusService do
     end
 
     it 'saves edit history' do
-      expect(status.edits.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']]
+      expect(status.edits.ordered.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']]
     end
   end
 
@@ -85,7 +85,7 @@ RSpec.describe UpdateStatusService do
     end
 
     it 'saves edit history' do
-      expect(status.edits.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
+      expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
     end
   end
 
@@ -107,7 +107,7 @@ RSpec.describe UpdateStatusService do
     end
 
     it 'saves edit history' do
-      expect(status.edits.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']]
+      expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']]
     end
   end
 
@@ -136,7 +136,7 @@ RSpec.describe UpdateStatusService do
     end
 
     it 'saves edit history' do
-      expect(status.edits.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
+      expect(status.edits.ordered.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
     end
 
     it 'requeues expiration notification' do

From 18737aad49911f00b94f9cf6fc582670cbdeda93 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 04:31:20 -0400
Subject: [PATCH 197/223] Rely on dotenv autoload instead of explicit call
 (#30007)

---
 config/application.rb | 2 --
 1 file changed, 2 deletions(-)

diff --git a/config/application.rb b/config/application.rb
index a17a48b09..b777018b5 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -52,8 +52,6 @@ require_relative '../lib/active_record/batches'
 require_relative '../lib/simple_navigation/item_extensions'
 require_relative '../lib/http_extensions'
 
-Dotenv::Rails.load
-
 Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'
 
 require_relative '../lib/mastodon/redis_config'

From 3655fb6a22576ac1b0e0fed4910483f8550c6529 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 10:42:35 +0200
Subject: [PATCH 198/223] New Crowdin Translations (automated) (#30014)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/be.json |   1 +
 app/javascript/mastodon/locales/es.json |   2 +-
 app/javascript/mastodon/locales/fi.json |  14 +-
 app/javascript/mastodon/locales/fr.json |   4 +-
 app/javascript/mastodon/locales/ia.json | 195 ++++++++++++++++++++++++
 app/javascript/mastodon/locales/id.json |  17 +++
 app/javascript/mastodon/locales/ja.json |   6 +
 config/locales/devise.ia.yml            |   2 +
 config/locales/fi.yml                   |   8 +-
 config/locales/ia.yml                   |  61 ++++++++
 config/locales/ja.yml                   |   2 +
 config/locales/simple_form.fi.yml       |   2 +-
 config/locales/simple_form.ia.yml       |  45 ++++++
 13 files changed, 344 insertions(+), 15 deletions(-)

diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json
index 276f7c712..2b7673312 100644
--- a/app/javascript/mastodon/locales/be.json
+++ b/app/javascript/mastodon/locales/be.json
@@ -297,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 {згадванні} many {згадванняў} other {згадвання}}",
   "filtered_notifications_banner.pending_requests": "Апавяшчэнні ад {count, plural, =0 {# людзей якіх} one {# чалавека якіх} few {# чалавек якіх} many {# людзей якіх} other {# чалавека якіх}} вы магчыма ведаеце",
   "filtered_notifications_banner.title": "Адфільтраваныя апавяшчэнні",
   "firehose.all": "Усе",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 68e5349a5..149a37d74 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -642,7 +642,7 @@
   "report.statuses.subtitle": "Selecciona todos los que correspondan",
   "report.statuses.title": "¿Hay alguna publicación que respalde este informe?",
   "report.submit": "Enviar",
-  "report.target": "Reportando",
+  "report.target": "Reportando {target}",
   "report.thanks.take_action": "Aquí están tus opciones para controlar lo que ves en Mastodon:",
   "report.thanks.take_action_actionable": "Mientras revisamos esto, puedes tomar medidas contra @{name}:",
   "report.thanks.title": "¿No quieres esto?",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index a32bb1315..246bb56fc 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -298,7 +298,7 @@
   "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.pending_requests": "Sinulle on ilmoituksia mahdollisesti tuntemiltasi henkilöiltä seuraavasti: {count, plural, =0 {Ei keltään} one {Yhdeltä henkilöltä} other {# henkilöltä}}",
   "filtered_notifications_banner.title": "Suodatetut ilmoitukset",
   "firehose.all": "Kaikki",
   "firehose.local": "Tämä palvelin",
@@ -306,11 +306,11 @@
   "follow_request.authorize": "Valtuuta",
   "follow_request.reject": "Hylkää",
   "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, palvelimen {domain} ylläpito on arvioinut, että saatat olla halukas tarkistamaan nämä seuraamispyynnöt erikseen.",
-  "follow_suggestions.curated_suggestion": "Ylläpidon valinta",
+  "follow_suggestions.curated_suggestion": "Ehdotus ylläpidolta",
   "follow_suggestions.dismiss": "Älä näytä uudelleen",
   "follow_suggestions.hints.featured": "Tämän profiilin on valinnut palvelimen {domain} tiimi.",
-  "follow_suggestions.hints.friends_of_friends": "Tämä profiili on suosittu seuraamiesi henkilöiden parissa.",
-  "follow_suggestions.hints.most_followed": "Tämä profiili on yksi seuratuimmista palvelimella {domain}.",
+  "follow_suggestions.hints.friends_of_friends": "Seuraamasi käyttäjät suosivat tätä profiilia.",
+  "follow_suggestions.hints.most_followed": "Tämä profiili on palvelimen {domain} seuratuimpia.",
   "follow_suggestions.hints.most_interactions": "Tämä profiili on viime aikoina saanut paljon huomiota palvelimella {domain}.",
   "follow_suggestions.hints.similar_to_recently_followed": "Tämä profiili on samankaltainen kuin profiilit, joita olet viimeksi seurannut.",
   "follow_suggestions.personalized_suggestion": "Mukautettu ehdotus",
@@ -473,10 +473,10 @@
   "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.account_suspension": "Palvelimen {from} ylläpitäjä on jäädyttänyt palvelimen {target} vuorovaikutuksen. Enää et voi siis vastaanottaa päivityksiä heiltä tai olla yhteyksissä heidän kanssaan.",
+  "notification.relationships_severance_event.domain_block": "Palvelimen {from} ylläpitäjä on estänyt palvelimen {target} vuorovaikutuksen – 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.relationships_severance_event.user_domain_block": "Olet estänyt palvelimen {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/fr.json b/app/javascript/mastodon/locales/fr.json
index 58ab46d5c..1a5803623 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -550,10 +550,10 @@
   "onboarding.share.message": "Je suis {username} sur #Mastodon ! Suivez-moi sur {url}",
   "onboarding.share.next_steps": "Étapes suivantes possibles :",
   "onboarding.share.title": "Partager votre profil",
-  "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
+  "onboarding.start.lead": "Vous faites désormais partie de Mastodon, une plateforme de médias sociaux unique et décentralisée où c'est vous, et non un algorithme, qui créez votre propre expérience. Nous allons vous aider à vous lancer dans cette nouvelle frontière sociale :",
   "onboarding.start.skip": "Vous n’avez donc pas besoin d’aide pour commencer ?",
   "onboarding.start.title": "Vous avez réussi !",
-  "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
+  "onboarding.steps.follow_people.body": "Suivre des personnes intéressantes, c'est la raison d'être de Mastodon.",
   "onboarding.steps.follow_people.title": "Personnaliser votre flux principal",
   "onboarding.steps.publish_status.body": "Dites bonjour au monde avec du texte, des photos, des vidéos ou des sondages {emoji}",
   "onboarding.steps.publish_status.title": "Rédigez votre premier message",
diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index e0ae8b58c..808b57278 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -375,12 +375,14 @@
   "keyboard_shortcuts.compose": "Focalisar al area de composition de texto",
   "keyboard_shortcuts.description": "Description",
   "keyboard_shortcuts.direct": "aperir le columna de mentiones private",
+  "keyboard_shortcuts.down": "Displaciar a basso in le lista",
   "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",
   "keyboard_shortcuts.home": "Aperir le chronologia de initio",
+  "keyboard_shortcuts.hotkey": "Clave accelerator",
   "keyboard_shortcuts.legend": "Monstrar iste legenda",
   "keyboard_shortcuts.local": "Aperir le chronologia local",
   "keyboard_shortcuts.mention": "Mentionar le author",
@@ -391,10 +393,18 @@
   "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.requests": "Aperir le lista de requestas de sequimento",
+  "keyboard_shortcuts.search": "Focalisar barra de recerca",
   "keyboard_shortcuts.spoilers": "Monstrar/celar le campo CW",
+  "keyboard_shortcuts.start": "Aperir columna “comenciar”",
+  "keyboard_shortcuts.toggle_hidden": "Monstrar/celar texto detra advertimento de contento",
   "keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar multimedia",
   "keyboard_shortcuts.toot": "Initiar un nove message",
+  "keyboard_shortcuts.unfocus": "Disfocalisar le area de composition de texto/de recerca",
+  "keyboard_shortcuts.up": "Displaciar in alto in le lista",
   "lightbox.close": "Clauder",
+  "lightbox.compress": "Comprimer le quadro de visualisation de imagine",
+  "lightbox.expand": "Expander le quadro de visualisation de imagine",
   "lightbox.next": "Sequente",
   "lightbox.previous": "Precedente",
   "limited_account_hint.action": "Monstrar profilo in omne caso",
@@ -408,13 +418,19 @@
   "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.followed": "Qualcunque usator sequite",
+  "lists.replies_policy.list": "Membros del lista",
   "lists.replies_policy.none": "Nemo",
   "lists.replies_policy.title": "Monstrar responsas a:",
+  "lists.search": "Cercar inter le gente que tu seque",
   "lists.subheading": "Tu listas",
+  "load_pending": "{count, plural, one {# nove entrata} other {# nove entratas}}",
   "loading_indicator.label": "Cargante…",
   "media_gallery.toggle_visible": "{number, plural, one {Celar imagine} other {Celar imagines}}",
+  "moved_to_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate perque tu ha cambiate de conto a {movedToAccount}.",
   "mute_modal.hide_from_notifications": "Celar ab notificationes",
   "mute_modal.hide_options": "Celar optiones",
+  "mute_modal.indefinite": "Usque io dissilentia iste persona",
   "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.",
@@ -433,6 +449,9 @@
   "navigation_bar.explore": "Explorar",
   "navigation_bar.favourites": "Favoritos",
   "navigation_bar.filters": "Parolas silentiate",
+  "navigation_bar.follow_requests": "Requestas de sequimento",
+  "navigation_bar.followed_tags": "Hashtags sequite",
+  "navigation_bar.follows_and_followers": "Sequites e sequitores",
   "navigation_bar.lists": "Listas",
   "navigation_bar.logout": "Clauder le session",
   "navigation_bar.mutes": "Usatores silentiate",
@@ -443,10 +462,21 @@
   "navigation_bar.public_timeline": "Chronologia federate",
   "navigation_bar.search": "Cercar",
   "navigation_bar.security": "Securitate",
+  "not_signed_in_indicator.not_signed_in": "Es necessari aperir session pro acceder a iste ressource.",
+  "notification.admin.report": "{name} ha signalate {target}",
+  "notification.admin.sign_up": "{name} se ha inscribite",
   "notification.favourite": "{name} ha marcate tu message como favorite",
+  "notification.follow": "{name} te ha sequite",
+  "notification.follow_request": "{name} ha requestate de sequer te",
+  "notification.mention": "{name} te ha mentionate",
   "notification.own_poll": "Tu sondage ha finite",
+  "notification.poll": "Un sondage in le qual tu ha votate ha finite",
   "notification.reblog": "{name} ha impulsate tu message",
+  "notification.relationships_severance_event": "Connexiones perdite con {name}",
+  "notification.relationships_severance_event.account_suspension": "Un administrator de {from} ha suspendiute {target}. Isto significa que tu non pote plus reciper actualisationes de iste persona o interager con ille.",
+  "notification.relationships_severance_event.domain_block": "Un administrator de {from} ha blocate {target}, includente {followersCount} de tu sequitores e {followingCount, plural, one {# conto} other {# contos}} que tu seque.",
   "notification.relationships_severance_event.learn_more": "Apprender plus",
+  "notification.relationships_severance_event.user_domain_block": "Tu ha blocate {target}, assi removente {followersCount} de tu sequitores e {followingCount, plural, one {# conto} other {# contos}} que tu seque.",
   "notification.status": "{name} ha justo ora publicate",
   "notification.update": "{name} ha modificate un message",
   "notification_requests.accept": "Acceptar",
@@ -455,10 +485,14 @@
   "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.admin.report": "Nove signalationes:",
+  "notifications.column_settings.admin.sign_up": "Nove inscriptiones:",
   "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.filter_bar.category": "Barra de filtro rapide",
   "notifications.column_settings.follow": "Nove sequitores:",
+  "notifications.column_settings.follow_request": "Nove requestas de sequimento:",
   "notifications.column_settings.mention": "Mentiones:",
   "notifications.column_settings.poll": "Resultatos del sondage:",
   "notifications.column_settings.push": "Notificationes push",
@@ -467,99 +501,226 @@
   "notifications.column_settings.sound": "Reproducer sono",
   "notifications.column_settings.status": "Nove messages:",
   "notifications.column_settings.unread_notifications.category": "Notificationes non legite",
+  "notifications.column_settings.unread_notifications.highlight": "Marcar le notificationes non legite",
+  "notifications.column_settings.update": "Modificationes:",
   "notifications.filter.all": "Toto",
   "notifications.filter.boosts": "Impulsos",
   "notifications.filter.favourites": "Favoritos",
+  "notifications.filter.follows": "Sequites",
   "notifications.filter.mentions": "Mentiones",
   "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.mark_as_read": "Marcar cata notification como legite",
+  "notifications.permission_denied": "Le notificationes de scriptorio es indisponibile a causa de un requesta anteriormente refusate de permissiones del navigator",
+  "notifications.permission_denied_alert": "Le notificationes de scriptorio non pote esser activate perque le permission del navigator ha essite refusate anteriormente",
+  "notifications.permission_required": "Le notificationes de scriptorio es indisponibile perque le permission necessari non ha essite concedite.",
+  "notifications.policy.filter_new_accounts.hint": "Create in le ultime {days, plural, one {die} other {# dies}}",
   "notifications.policy.filter_new_accounts_title": "Nove contos",
+  "notifications.policy.filter_not_followers_hint": "Includente le personas que te ha sequite durante minus de {days, plural, one {un die} other {# dies}}",
+  "notifications.policy.filter_not_followers_title": "Personas qui non te seque",
+  "notifications.policy.filter_not_following_hint": "Usque tu les approba manualmente",
+  "notifications.policy.filter_not_following_title": "Personas que tu non seque",
+  "notifications.policy.filter_private_mentions_hint": "Filtrate, excepte si es in responsa a tu proprie mention o si tu seque le expeditor",
+  "notifications.policy.filter_private_mentions_title": "Mentiones private indesirate",
+  "notifications.policy.title": "Filtrar notificationes de…",
   "notifications_permission_banner.enable": "Activar notificationes de scriptorio",
+  "notifications_permission_banner.how_to_control": "Pro reciper notificationes quando Mastodon non es aperte, activa le notificationes de scriptorio. Post lor activation, es possibile controlar precisemente qual typos de interaction genera notificationes de scriptorio per medio del button {icon} hic supra.",
+  "notifications_permission_banner.title": "Non mancar jammais a un cosa",
+  "onboarding.action.back": "Porta me retro",
+  "onboarding.actions.back": "Porta me retro",
+  "onboarding.actions.go_to_explore": "Porta me al tendentias",
   "onboarding.actions.go_to_home": "Porta me a mi fluxo de initio",
   "onboarding.compose.template": "Salute #Mastodon!",
+  "onboarding.follows.empty": "Regrettabilemente, non es possibile monstrar resultatos al momento. Tu pote tentar usar le recerca o percurrer le pagina de exploration pro cercar personas a sequer, o tentar lo de novo plus tarde.",
   "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": "Render mi profilo discoperibile",
   "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.display_name": "Nomine a monstrar",
+  "onboarding.profile.display_name_hint": "Tu nomine complete o tu supernomine…",
+  "onboarding.profile.lead": "Tu pote sempre completar isto plus tarde in le parametros, ubi se trova mesmo plus optiones de personalisation.",
+  "onboarding.profile.note": "Bio",
+  "onboarding.profile.note_hint": "Tu pote @mentionar altere personas o #hashtags…",
   "onboarding.profile.save_and_continue": "Salvar e continuar",
+  "onboarding.profile.title": "Configuration del profilo",
+  "onboarding.profile.upload_avatar": "Incargar imagine de profilo",
+  "onboarding.profile.upload_header": "Actualisar capite de profilo",
+  "onboarding.share.lead": "Face saper al gente como illes pote trovar te sur Mastodon!",
+  "onboarding.share.message": "Io es {username} sur Mastodon! Veni sequer me a {url}",
   "onboarding.share.next_steps": "Sequente passos possibile:",
   "onboarding.share.title": "Compartir tu profilo",
+  "onboarding.start.lead": "Tu face ora parte de Mastodon, un platteforma de medios social unic e decentralisate ubi es tu, e non un algorithmo, qui crea tu proprie experientia. Nos va adjutar te a lancear te in iste nove frontiera social:",
+  "onboarding.start.skip": "Non require adjuta a comenciar?",
+  "onboarding.start.title": "Tu ha arrivate!",
+  "onboarding.steps.follow_people.body": "Sequer personas interessante es le ration de esser de Mastodon.",
   "onboarding.steps.follow_people.title": "Personalisar tu fluxo de initio",
+  "onboarding.steps.publish_status.body": "Saluta le mundo con texto, photos, videos o sondages {emoji}",
   "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.body": "Face saper a tu amicos como trovar te sur Mastodon",
   "onboarding.steps.share_profile.title": "Compartir tu profilo de Mastodon",
+  "onboarding.tips.2fa": "<strong>Lo sapeva tu?</strong> Tu pote securisar tu conto configurante le authentication bifactorial in le parametros de tu conto. Isto functiona con le application TOTP de tu preferentia, sin necessitate de un numero de telephono!",
+  "onboarding.tips.accounts_from_other_servers": "<strong>Lo sapeva tu?</strong> Perque Mastodon es decentralisate, le profilos que tu incontra pote esser hospitate sur servitores altere que le tue. Nonobstante, tu pote interager con illos sin problema! Lor servitor se trova in le secunde medietate de lor nomine de usator!",
+  "onboarding.tips.migration": "<strong>Lo sapeva tu?</strong> Si tu pensa que {domain} non es un bon servitor pro te in le futuro, tu pote cambiar a un altere servitor Mastodon sin perder tu sequitores. Tu pote mesmo hospitar tu proprie servitor!",
+  "onboarding.tips.verification": "<strong>Lo sapeva tu?</strong> Pro verificar tu conto, insere un ligamine a tu profilo Mastodon sur tu proprie sito web e adde le sito web a tu profilo. Nulle moneta o documentos necessari!",
+  "password_confirmation.exceeds_maxlength": "Le confirmation del contrasigno excede le longitude maxime del contrasigno",
+  "password_confirmation.mismatching": "Le confirmation del contrasigno non corresponde",
+  "picture_in_picture.restore": "Restaurar",
   "poll.closed": "Claudite",
+  "poll.refresh": "Refrescar",
   "poll.reveal": "Vider le resultatos",
+  "poll.total_people": "{count, plural, one {# persona} other {# personas}}",
+  "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
+  "poll.vote": "Votar",
+  "poll.voted": "Tu ha votate pro iste responsa",
+  "poll.votes": "{votes, plural, one {# voto} other {# votos}}",
+  "poll_button.add_poll": "Adder un inquesta",
+  "poll_button.remove_poll": "Remover un inquesta",
   "privacy.change": "Cambiar le confidentialitate del message",
   "privacy.direct.long": "Tote le personas mentionate in le message",
+  "privacy.direct.short": "Personas specific",
+  "privacy.private.long": "Solmente tu sequitores",
+  "privacy.private.short": "Sequitores",
+  "privacy.public.long": "Quicunque, sur Mastodon o non",
   "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.unlisted.long": "Minus fanfares algorithmic",
+  "privacy.unlisted.short": "Public, non listate",
   "privacy_policy.last_updated": "Ultime actualisation {date}",
   "privacy_policy.title": "Politica de confidentialitate",
+  "recommended": "Recommendate",
+  "refresh": "Refrescar",
+  "regeneration_indicator.label": "Cargamento…",
   "regeneration_indicator.sublabel": "Tu fluxo de initio es in preparation!",
+  "relative_time.days": "{number}d",
+  "relative_time.full.days": "{number, plural, one {# die} other {# dies}} retro",
+  "relative_time.full.hours": "{number, plural, one {# hora} other {# horas}} retro",
+  "relative_time.full.just_now": "justo ora",
+  "relative_time.full.minutes": "{number, plural, one {# minuta} other {# minutas}} retro",
+  "relative_time.full.seconds": "{number, plural, one {# secunda} other {# secundas}} retro",
+  "relative_time.hours": "{number}h",
   "relative_time.just_now": "ora",
+  "relative_time.minutes": "{number}m",
+  "relative_time.seconds": "{number}s",
   "relative_time.today": "hodie",
+  "reply_indicator.attachments": "{count, plural, one {# annexo} other {# annexos}}",
   "reply_indicator.cancel": "Cancellar",
+  "reply_indicator.poll": "Inquesta",
   "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.legal": "Juridic",
   "report.categories.other": "Alteres",
+  "report.categories.spam": "Spam",
+  "report.categories.violation": "Le contento viola un o plus regulas del servitor",
+  "report.category.subtitle": "Elige le option plus adequate",
+  "report.category.title": "Describe le problema con iste {type}",
   "report.category.title_account": "profilo",
   "report.category.title_status": "message",
   "report.close": "Facite",
+  "report.comment.title": "Ha il altere cosas que nos deberea saper?",
+  "report.forward": "Reinviar a {target}",
+  "report.forward_hint": "Le conto es de un altere servitor. Inviar un copia anonymisate del signalation a illo tamben?",
   "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.reasons.dislike_description": "Non es qualcosa que tu vole vider",
+  "report.reasons.legal": "Es illegal",
+  "report.reasons.legal_description": "Tu crede que viola le lege de tu pais o del pais del servitor",
+  "report.reasons.other": "Es altere cosa",
+  "report.reasons.other_description": "Le problema non entra in altere categorias",
+  "report.reasons.spam": "Es spam",
+  "report.reasons.spam_description": "Ligamines malevolente, interaction false, o responsas repetitive",
+  "report.reasons.violation": "Viola le regulas del servitor",
+  "report.reasons.violation_description": "Tu sape que viola regulas specific",
+  "report.rules.subtitle": "Selige tote le responsas appropriate",
+  "report.rules.title": "Qual regulas es violate?",
+  "report.statuses.subtitle": "Selige tote le responsas appropriate",
   "report.statuses.title": "Existe alcun messages que appoia iste reporto?",
+  "report.submit": "Submitter",
+  "report.target": "Signalamento de {target}",
+  "report.thanks.take_action": "Ecce tu optiones pro controlar lo que tu vide sur Mastodon:",
+  "report.thanks.take_action_actionable": "Durante que nos revide isto, tu pote prender mesuras contra @{name}:",
+  "report.thanks.title": "Non vole vider isto?",
+  "report.thanks.title_actionable": "Gratias pro signalar, nos investigara isto.",
+  "report.unfollow": "Cessar de sequer @{name}",
   "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.legal": "Juridic",
   "report_notification.categories.other": "Alteres",
+  "report_notification.categories.spam": "Spam",
+  "report_notification.categories.violation": "Violation del regulas",
   "report_notification.open": "Aperir reporto",
   "search.no_recent_searches": "Nulle recercas recente",
+  "search.placeholder": "Cercar",
+  "search.quick_action.account_search": "Profilos correspondente a {x}",
   "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.search_or_paste": "Cerca o colla un URL",
   "search_popout.full_text_search_disabled_message": "Non disponibile sur {domain}.",
+  "search_popout.full_text_search_logged_out_message": "Solmente disponibile al initiar le session.",
   "search_popout.language_code": "Codice de lingua ISO",
   "search_popout.options": "Optiones de recerca",
   "search_popout.quick_actions": "Actiones rapide",
   "search_popout.recent": "Recercas recente",
+  "search_popout.specific_date": "data specific",
   "search_popout.user": "usator",
   "search_results.accounts": "Profilos",
+  "search_results.all": "Toto",
   "search_results.hashtags": "Hashtags",
+  "search_results.nothing_found": "Nihil trovate pro iste terminos de recerca",
   "search_results.see_all": "Vider toto",
   "search_results.statuses": "Messages",
+  "search_results.title": "Cercar {q}",
+  "server_banner.about_active_users": "Personas que ha usate iste servitor in le ultime 30 dies (usatores active per mense)",
   "server_banner.active_users": "usatores active",
+  "server_banner.administered_by": "Administrate per:",
+  "server_banner.introduction": "{domain} face parte del rete social decentralisate actionate per {mastodon}.",
   "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": "Aperir session",
+  "sign_in_banner.sso_redirect": "Aperir session o crear conto",
   "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_account": "Aperir le interfacie de moderation pro @{name}",
+  "status.admin_domain": "Aperir le interfacie de moderation pro {domain}",
   "status.admin_status": "Aperir iste message in le interfacie de moderation",
   "status.block": "Blocar @{name}",
+  "status.bookmark": "Adder al marcapaginas",
   "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.detailed_status": "Vista detaliate del conversation",
   "status.direct": "Mentionar privatemente @{name}",
   "status.direct_indicator": "Mention private",
   "status.edit": "Modificar",
+  "status.edited": "Ultime modification le {date}",
   "status.edited_x_times": "Modificate {count, plural, one {{count} vice} other {{count} vices}}",
+  "status.embed": "Incastrar",
   "status.favourite": "Adder al favoritos",
+  "status.favourites": "{count, plural, one {favorite} other {favorites}}",
   "status.filter": "Filtrar iste message",
+  "status.filtered": "Filtrate",
   "status.hide": "Celar le message",
   "status.history.created": "create per {name} le {date}",
   "status.history.edited": "modificate per {name} le {date}",
+  "status.load_more": "Cargar plus",
   "status.media.open": "Clicca pro aperir",
   "status.media.show": "Clicca pro monstrar",
+  "status.media_hidden": "Medios celate",
+  "status.mention": "Mentionar @{name}",
   "status.more": "Plus",
+  "status.mute": "Silentiar @{name}",
   "status.mute_conversation": "Silentiar conversation",
   "status.open": "Expander iste message",
+  "status.pin": "Fixar sur profilo",
   "status.pinned": "Message fixate",
   "status.read_more": "Leger plus",
   "status.reblog": "Impulsar",
@@ -592,13 +753,47 @@
   "subscribed_languages.target": "Cambiar le linguas subscribite pro {target}",
   "tabs_bar.home": "Initio",
   "tabs_bar.notifications": "Notificationes",
+  "time_remaining.days": "{number, plural, one {# die} other {# dies}} restante",
+  "time_remaining.hours": "{number, plural, one {# hora} other {# horas}} restante",
+  "time_remaining.minutes": "{number, plural, one {# minuta} other {# minutas}} restante",
+  "time_remaining.moments": "Qualque momentos restante",
+  "time_remaining.seconds": "{number, plural, one {# secunda} other {# secundas}} restante",
+  "timeline_hint.remote_resource_not_displayed": "Le {resource} de altere servitores non appare hic.",
+  "timeline_hint.resources.followers": "Sequitores",
+  "timeline_hint.resources.follows": "Sequites",
   "timeline_hint.resources.statuses": "Messages ancian",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} personas}} in le passate {days, plural, one {die} other {{days} dies}}",
   "trends.trending_now": "Ora in tendentias",
+  "ui.beforeunload": "Tu esbosso essera predite si tu exi de Mastodon.",
+  "units.short.billion": "{count}B",
+  "units.short.million": "{count}M",
+  "units.short.thousand": "{count}K",
+  "upload_area.title": "Traher e deponer pro incargar",
   "upload_button.label": "Adde imagines, un video o un file de audio",
+  "upload_error.limit": "Limite de incargamento de files excedite.",
+  "upload_error.poll": "Incargamento de files non permittite con sondages.",
+  "upload_form.audio_description": "Describe lo pro le gente con difficultates auditive",
+  "upload_form.description": "Describe lo pro le gente con difficultates visual",
+  "upload_form.edit": "Modificar",
+  "upload_form.thumbnail": "Cambiar le miniatura",
+  "upload_form.video_description": "Describe lo pro le gente con difficultates auditive o visual",
+  "upload_modal.analyzing_picture": "Analysa imagine…",
+  "upload_modal.apply": "Applicar",
+  "upload_modal.applying": "Applicante…",
   "upload_modal.choose_image": "Seliger un imagine",
+  "upload_modal.description_placeholder": "Le clown uzbek dogmatic justo foras quasi se asphyxiava",
   "upload_modal.detect_text": "Deteger texto de un imagine",
+  "upload_modal.edit_media": "Modificar le medio",
+  "upload_modal.hint": "Clicca o trahe le circulo sur le previsualisation pro eliger le puncto focal que essera sempre visibile sur tote le miniaturas.",
+  "upload_modal.preparing_ocr": "Preparation del OCR…",
+  "upload_modal.preview_label": "Previsualisation ({ratio})",
+  "upload_progress.label": "Incargante...",
+  "upload_progress.processing": "Processante…",
+  "username.taken": "Iste nomine de usator es ja in uso. Proba con un altere",
   "video.close": "Clauder le video",
   "video.download": "Discargar le file",
+  "video.exit_fullscreen": "Sortir del schermo plen",
+  "video.expand": "Expander video",
   "video.fullscreen": "Schermo plen",
   "video.hide": "Celar video",
   "video.mute": "Silentiar le sono",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 764c08111..90a48b634 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -21,6 +21,7 @@
   "account.blocked": "Terblokir",
   "account.browse_more_on_origin_server": "Lihat lebih lanjut di profil asli",
   "account.cancel_follow_request": "Batalkan permintaan ikut",
+  "account.copy": "Salin tautan ke profil",
   "account.direct": "Sebut secara pribadi @{name}",
   "account.disable_notifications": "Berhenti memberitahu saya ketika @{name} memposting",
   "account.domain_blocked": "Domain diblokir",
@@ -31,6 +32,7 @@
   "account.featured_tags.last_status_never": "Tidak ada kiriman",
   "account.featured_tags.title": "Tagar {name} yang difiturkan",
   "account.follow": "Ikuti",
+  "account.follow_back": "Ikuti balik",
   "account.followers": "Pengikut",
   "account.followers.empty": "Pengguna ini belum ada pengikut.",
   "account.followers_counter": "{count, plural, other {{counter} Pengikut}}",
@@ -51,6 +53,7 @@
   "account.mute_notifications_short": "Senyapkan Notifikasi",
   "account.mute_short": "Senyapkan",
   "account.muted": "Dibisukan",
+  "account.mutual": "Saling ikuti",
   "account.no_bio": "Tidak ada deskripsi yang diberikan.",
   "account.open_original_page": "Buka halaman asli",
   "account.posts": "Kiriman",
@@ -75,6 +78,10 @@
   "admin.dashboard.retention.average": "Rata-rata",
   "admin.dashboard.retention.cohort": "Bulan pendaftaran",
   "admin.dashboard.retention.cohort_size": "Pengguna baru",
+  "admin.impact_report.instance_accounts": "Akun profil yang akan terhapus",
+  "admin.impact_report.instance_followers": "Pengikut yang akan kehilangan oleh pengguna kita",
+  "admin.impact_report.instance_follows": "Pengikut yang akan kehilangan oleh pengguna lain",
+  "admin.impact_report.title": "Ringkasan dampak",
   "alert.rate_limited.message": "Mohon ulangi setelah {retry_time, time, medium}.",
   "alert.rate_limited.title": "Jumlah akses dibatasi",
   "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.",
@@ -82,6 +89,14 @@
   "announcement.announcement": "Pengumuman",
   "attachments_list.unprocessed": "(tidak diproses)",
   "audio.hide": "Sembunyikan audio",
+  "block_modal.remote_users_caveat": "Kami akan meminta {domain} server untuk menghargai keputusan Anda. Namun, kepatuhan tak dapat dipastikan karena beberapa server dapat menangani blokir secara beragam. Postingan publik masih dapat terlihat oleh pengguna tanpa masuk.",
+  "block_modal.show_less": "Tampilkan lebih sedikit",
+  "block_modal.show_more": "Tampilkan lebih banyak",
+  "block_modal.they_cant_mention": "Mereka tidak dapat menyebut atau mengikuti Anda.",
+  "block_modal.they_cant_see_posts": "Mereka tidak dapat melihat postingan Anda dan Anda tidak dapat melihat postingan mereka.",
+  "block_modal.they_will_know": "Mereka dapat melihat bahwa mereka diblokir.",
+  "block_modal.title": "Blokir pengguna?",
+  "block_modal.you_wont_see_mentions": "Anda tidak akan melihat kiriman yang menyebutkan mereka.",
   "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini",
   "bundle_column_error.copy_stacktrace": "Salin laporan kesalahan",
   "bundle_column_error.error.body": "Laman yang diminta tidak dapat ditampilkan. Mungkin karena sebuah kutu dalam kode kami, atau masalah kompatibilitas peramban.",
@@ -104,8 +119,10 @@
   "column.blocks": "Pengguna yang diblokir",
   "column.bookmarks": "Markah",
   "column.community": "Linimasa Lokal",
+  "column.direct": "Sebut secara pribadi",
   "column.directory": "Jelajahi profil",
   "column.domain_blocks": "Domain tersembunyi",
+  "column.favourites": "Favorit",
   "column.follow_requests": "Permintaan mengikuti",
   "column.home": "Beranda",
   "column.lists": "List",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 16e7e6c44..30c9eb77a 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "既存のカテゴリーを使用するか新規作成します",
   "filter_modal.select_filter.title": "この投稿をフィルターする",
   "filter_modal.title.status": "投稿をフィルターする",
+  "filtered_notifications_banner.mentions": "{count, plural, one {メンション} other {メンション}}",
   "filtered_notifications_banner.pending_requests": "{count, plural, =0 {アカウント} other {#アカウント}}からの通知がブロックされています",
   "filtered_notifications_banner.title": "ブロック済みの通知",
   "firehose.all": "すべて",
@@ -488,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": "返信:",
@@ -698,9 +701,11 @@
   "status.direct": "@{name}さんに非公開で投稿",
   "status.direct_indicator": "非公開の返信",
   "status.edit": "編集",
+  "status.edited": "最終更新日 {date}",
   "status.edited_x_times": "{count}回編集",
   "status.embed": "埋め込み",
   "status.favourite": "お気に入り",
+  "status.favourites": "{count, plural, one {お気に入り} other {お気に入り}}",
   "status.filter": "この投稿をフィルターする",
   "status.filtered": "フィルターされました",
   "status.hide": "投稿を非表示",
@@ -721,6 +726,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/config/locales/devise.ia.yml b/config/locales/devise.ia.yml
index 4b4d1f441..62f106bcf 100644
--- a/config/locales/devise.ia.yml
+++ b/config/locales/devise.ia.yml
@@ -2,6 +2,8 @@
 ia:
   devise:
     failure:
+      already_authenticated: Tu jam initiava le session.
+      inactive: Tu conto ancora non es activate.
       locked: Tu conto es blocate.
     mailer:
       confirmation_instructions:
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index ab92e106a..f82a592ec 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -770,7 +770,7 @@ fi:
         disabled: Ei kenellekkään
         users: Kirjautuneille paikallisille käyttäjille
       registrations:
-        moderation_recommandation: Varmista, että sinulla on riittävä ja toimintavalmis joukko moderaattoreita ennen kuin avaat rekisteröitymiset kaikille!
+        moderation_recommandation: Varmista, että sinulla on riittävä ja toimintavalmis joukko moderaattoreita, ennen kuin vapautat rekisteröitymismenettelyn kaikille!
         preamble: Määritä, kuka voi luoda tilin palvelimellesi.
         title: Rekisteröityminen
       registrations_mode:
@@ -972,7 +972,7 @@ fi:
       webhook: Webhook
   admin_mailer:
     auto_close_registrations:
-      body: Viimeaikaisen moderaattoritoiminnan puutteen vuoksi palvelimen %{instance} rekisteröitymiset on vaihdettu automaattisesti manuaaliseen tarkasteluun, jotta palvelinta %{instance} ei käytetä mahdollisten huonojen toimijoiden alustana. Voit vaihtaa takaisin avoimiin rekisteröitymisiin milloin tahansa.
+      body: Palvelimen %{instance} moderaattorit eivät ole olleet viime aikoina aktiivisia. Tästä syystä rekisteröitymismenettely on automaattisesti vaihdettu erillishyväksyntöjä edellyttäväksi. Näin vähennetään riskiä palvelimen %{instance} käyttöön haitallisten toimijoiden alustana. Voit koska tahansa palauttaa käyttöön vapaat rekisteröitymiset.
       subject: Rekisteröitymiset palvelimelle %{instance} on automaattisesti vaihdettu vaatimaan hyväksyntää
     new_appeal:
       actions:
@@ -1882,8 +1882,8 @@ fi:
       follows_title: Ehdotuksia seurattavaksi
       follows_view_more: Näytä lisää seurattavia henkilöitä
       hashtags_recent_count:
-        one: "%{people} henkilö viimeisenä 2 päivänä"
-        other: "%{people} henkilöä viimeisenä 2 päivänä"
+        one: "%{people} henkilö viimeisen 2 päivän aikana"
+        other: "%{people} henkilöä viimeisen 2 päivän aikana"
       hashtags_subtitle: Tutki, mikä on ollut suosittua viimeisenä 2 päivänä
       hashtags_title: Suositut aihetunnisteet
       hashtags_view_more: Näytä lisää suosittuja aihetunnisteita
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index 5065ca7bb..3ba7a5148 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -53,7 +53,10 @@ ia:
         all: Toto
         title: Location
       moderation:
+        active: Active
+        all: Toto
         disabled: Disactivate
+      moderation_notes: Notas de moderation
       most_recent_activity: Activitate plus recente
       most_recent_ip: IP plus recente
       public: Public
@@ -83,13 +86,19 @@ ia:
     action_logs:
       action_types:
         confirm_user: Confirmar le usator
+        create_account_warning: Crear un advertimento
         create_announcement: Crear annuncio
+        create_ip_block: Crear un regula IP
+        destroy_announcement: Deler 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_custom_emoji: Disactivar emoji personalisate
         disable_user: Disactivar le usator
+        enable_custom_emoji: Activar emoji personalisate
         enable_user: Activar le usator
+        promote_user: Promover usator
         reset_password_user: Reinitialisar contrasigno
         update_announcement: Actualisar annuncio
         update_custom_emoji: Actualisar emoji personalisate
@@ -112,8 +121,10 @@ ia:
       title: Annuncios
     custom_emojis:
       by_domain: Dominio
+      copied_msg: Copia local del emoji create con successo
       copy: Copiar
       create_new_category: Crear nove categoria
+      created_msg: Emoji create con successo!
       delete: Deler
       disable: Disactivar
       disabled: Disactivate
@@ -125,16 +136,22 @@ ia:
       upload: Incargar
     dashboard:
       active_users: usatores active
+      interactions: interactiones
       media_storage: Immagazinage de medios
       new_users: nove usatores
       opened_reports: reportos aperte
+      top_languages: Linguas le plus active
+      top_servers: Servitores le plus active
       website: Sito web
     domain_allows:
       add_new: Permitter federation con dominio
+      export: Exportar
+      import: Importar
     domain_blocks:
       confirm_suspension:
         cancel: Cancellar
       domain: Dominio
+      edit: Modificar un bloco de dominio
       export: Exportar
       import: Importar
       private_comment: Commento private
@@ -145,19 +162,31 @@ ia:
       domain: Dominio
       new:
         create: Adder un dominio
+        title: Blocar un nove dominio de e-mail
+      title: Dominios de e-mail blocate
     export_domain_allows:
       no_file: Necun file seligite
+    export_domain_blocks:
+      no_file: Necun file seligite
     follow_recommendations:
       language: Per lingua
       status: Stato
+      title: Sequer le recommendationes
     instances:
+      back_to_warning: Advertimento
+      by_domain: Dominio
+      content_policies:
+        reason: Ration public
       dashboard:
+        instance_accounts_dimension: Contos le plus sequite
         instance_languages_dimension: Linguas principal
       delivery:
         unavailable: Non disponibile
       empty: Necun dominios trovate.
       private_comment: Commento private
       public_comment: Commento public
+      total_blocked_by_us: Blocate per nos
+      total_followed_by_us: Sequite per nos
     invites:
       deactivate_all: Disactivar toto
       filter:
@@ -179,12 +208,17 @@ ia:
       disabled: Disactivate
       enable: Activar
       enabled: Activate
+      save_and_enable: Salveguardar e activar
+      status: Stato
     reports:
       add_to_report: Adder plus al reporto
       are_you_sure: Es tu secur?
       cancel: Cancellar
+      category: Categoria
+      confirm: Confirmar
       delete_and_resolve: Deler le messages
       notes:
+        create: Adder un nota
         delete: Deler
       skip_to_actions: Saltar al actiones
       status: Stato
@@ -193,6 +227,11 @@ ia:
     roles:
       everyone: Permissiones predefinite
       privileges:
+        delete_user_data: Deler le datos de usator
+        manage_announcements: Gerer le annuncios
+        manage_invites: Gerer le invitationes
+        manage_rules: Gerer le regulas
+        manage_settings: Gerer le parametros
         manage_users: Gerer usatores
     rules:
       delete: Deler
@@ -294,6 +333,13 @@ ia:
       not_found: non poterea esser trovate
   preferences:
     public_timelines: Chronologias public
+  statuses:
+    poll:
+      vote: Votar
+    show_more: Monstrar plus
+    visibilities:
+      private_long: Solmente monstrar a sequitores
+      public: Public
   statuses_cleanup:
     min_age:
       '1209600': 2 septimanas
@@ -307,11 +353,26 @@ ia:
   themes:
     default: Mastodon (Obscur)
     mastodon-light: Mastodon (Clar)
+    system: Automatic (usar thema del systema)
   two_factor_authentication:
     add: Adder
     disable: Disactivar 2FA
+    edit: Modificar
   user_mailer:
+    appeal_approved:
+      action: Parametros de conto
     welcome:
+      apps_android_action: Obtene lo sur Google Play
+      apps_ios_action: Discargar sur le App Store
+      apps_step: Discarga nostre applicationes official.
+      apps_title: Applicationes de Mastodon
+      edit_profile_action: Personalisar
+      edit_profile_title: Personalisar tu profilo
+      feature_action: Apprender plus
+      share_title: Compartir tu profilo de Mastodon
       subject: Benvenite in Mastodon
+  verification:
+    verified_links: Tu ligamines verificate
   webauthn_credentials:
+    add: Adder un nove clave de securitate
     delete: Deler
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index f9cbb6a75..da9a42141 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1849,6 +1849,8 @@ ja:
       follows_subtitle: 人気アカウントをフォロー
       follows_title: フォローを増やしてみませんか?
       follows_view_more: フォローするユーザーを探す
+      hashtags_recent_count:
+        other: 過去 2 日間で %{people} 人が共有
       hashtags_subtitle: 過去2日間のトレンドを見る
       hashtags_title: トレンドのハッシュタグ
       hashtags_view_more: トレンドのハッシュタグをもっと見る
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index b1c2e91a1..c3fbd4372 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -116,7 +116,7 @@ fi:
           sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi
         severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille
       rule:
-        hint: Valinnainen. Anna lisätietoja säännöstä
+        hint: Vapaaehtoinen. Anna yksityiskohtaisempia tietoja säännöstä
         text: Kuvaile sääntöä tai edellytystä palvelimesi käyttäjille. Suosi tiivistä, yksinkertaista ilmaisua
       sessions:
         otp: 'Näppäile mobiilisovelluksessa näkyvä kaksivaiheisen todennuksen tunnusluku, tai käytä tarvittaessa palautuskoodia:'
diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml
index 16dbcbd18..2f04ce982 100644
--- a/config/locales/simple_form.ia.yml
+++ b/config/locales/simple_form.ia.yml
@@ -1,20 +1,44 @@
 ---
 ia:
   simple_form:
+    hints:
+      account:
+        note: 'Tu pote @mentionar altere personas o #hashtags.'
+      defaults:
+        setting_display_media_hide_all: Sempre celar le medios
+        setting_display_media_show_all: Sempre monstrar le medios
+      webhook:
+        events: Selige le eventos a inviar
+        url: Ubi le eventos essera inviate
     labels:
       account:
+        discoverable: Evidentiar le profilo e messages in le algorithmos de discoperta
         fields:
           name: Etiquetta
           value: Contento
+        indexable: Includer messages public in le resultatos de recerca
+        show_collections: Monstrar sequites e sequitores in le profilo
+        unlocked: Acceptar automaticamente nove sequitores
+      account_warning_preset:
+        title: Titulo
       admin_account_action:
         type: Action
+        types:
+          none: Inviar un advertimento
+      announcement:
+        text: Annuncio
       defaults:
+        autofollow: Invitar a sequer tu conto
         avatar: Pictura de profilo
         confirm_new_password: Confirmar nove contrasigno
         confirm_password: Confirmar contrasigno
         current_password: Contrasigno actual
+        display_name: Nomine a monstrar
+        email: Adresse de e-mail
+        locale: Lingua de interfacie
         new_password: Nove contrasigno
         password: Contrasigno
+        setting_advanced_layout: Activar le interfacie web avantiate
         setting_default_language: Lingua de publication
         setting_display_media_default: Predefinite
         setting_display_media_hide_all: Celar toto
@@ -26,29 +50,50 @@ ia:
         title: Titulo
         username: Nomine de usator
         username_or_email: Nomine de usator o e-mail
+      featured_tag:
+        name: Hashtag
+      filters:
+        actions:
+          hide: Celar completemente
+          warn: Celar con un advertimento
       form_admin_settings:
         bootstrap_timeline_accounts: Recommenda sempre iste contos a nove usatores
         custom_css: CSS personalisate
         profile_directory: Activar directorio de profilos
         site_contact_email: Adresse de e-mail de contacto
         site_contact_username: Nomine de usator de contacto
+        site_short_description: Description de servitor
         site_terms: Politica de confidentialitate
         site_title: Nomine de servitor
+        status_page_url: URL del pagina de stato
         theme: Thema predefinite
         trends: Activar tendentias
       ip_block:
+        comment: Commento
         severity: Regula
       notification_emails:
         software_updates:
+          all: Notificar sur tote le actualisationes
+          critical: Notificar solmente sur actualisationes critic
           label: Un nove version de Mastodon es disponibile
+          none: Nunquam notificar sur actualisationes (non recommendate)
       rule:
+        hint: Information additional
         text: Regula
       settings:
         indexable: Includer pagina de profilo in le motores de recerca
+      tag:
+        listable: Permitter a iste hashtag apparer in le recercas e suggestiones
+        name: Hashtag
+        usable: Permitter al messages usar iste hashtag
       user:
         time_zone: Fuso horari
       user_role:
         name: Nomine
         permissions_as_keys: Permissiones
         position: Prioritate
+    not_recommended: Non recommendate
+    recommended: Recommendate
+    required:
+      text: requirite
     'yes': Si

From 75163d9daf831a0562bcf35bffb883c2e7b239b7 Mon Sep 17 00:00:00 2001
From: Tim Rogers <rogers.timothy.john@gmail.com>
Date: Mon, 22 Apr 2024 03:53:08 -0500
Subject: [PATCH 199/223] Fixed rendering error on /start when not logged in
 (#30023)

---
 .../mastodon/features/onboarding/index.jsx    | 71 ++++++++++---------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/app/javascript/mastodon/features/onboarding/index.jsx b/app/javascript/mastodon/features/onboarding/index.jsx
index 5900b9ec7..529d53f25 100644
--- a/app/javascript/mastodon/features/onboarding/index.jsx
+++ b/app/javascript/mastodon/features/onboarding/index.jsx
@@ -16,6 +16,7 @@ import EditNoteIcon from '@/material-icons/400-24px/edit_note.svg?react';
 import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
 import { focusCompose } from 'mastodon/actions/compose';
 import { Icon }  from 'mastodon/components/icon';
+import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
 import Column from 'mastodon/features/ui/components/column';
 import { me } from 'mastodon/initial_state';
 import { useAppSelector } from 'mastodon/store';
@@ -42,42 +43,44 @@ const Onboarding = () => {
 
   return (
     <Column>
-      <Switch>
-        <Route path='/start' exact>
-          <div className='scrollable privacy-policy'>
-            <div className='column-title'>
-              <img src={illustration} alt='' className='onboarding__illustration' />
-              <h3><FormattedMessage id='onboarding.start.title' defaultMessage="You've made it!" /></h3>
-              <p><FormattedMessage id='onboarding.start.lead' defaultMessage="Your new Mastodon account is ready to go. Here's how you can make the most of it:" /></p>
+      {account ? (
+        <Switch>
+          <Route path='/start' exact>
+            <div className='scrollable privacy-policy'>
+              <div className='column-title'>
+                <img src={illustration} alt='' className='onboarding__illustration' />
+                <h3><FormattedMessage id='onboarding.start.title' defaultMessage="You've made it!" /></h3>
+                <p><FormattedMessage id='onboarding.start.lead' defaultMessage="Your new Mastodon account is ready to go. Here's how you can make the most of it:" /></p>
+              </div>
+
+              <div className='onboarding__steps'>
+                <Step to='/start/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
+                <Step to='/start/follows' completed={(account.get('following_count') * 1) >= 1} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
+                <Step onClick={handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
+                <Step to='/start/share' icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
+              </div>
+
+              <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p>
+
+              <div className='onboarding__links'>
+                <Link to='/explore' className='onboarding__link'>
+                  <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
+                  <Icon icon={ArrowRightAltIcon} />
+                </Link>
+
+                <Link to='/home' className='onboarding__link'>
+                  <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
+                  <Icon icon={ArrowRightAltIcon} />
+                </Link>
+              </div>
             </div>
+          </Route>
 
-            <div className='onboarding__steps'>
-              <Step to='/start/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
-              <Step to='/start/follows' completed={(account.get('following_count') * 1) >= 1} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
-              <Step onClick={handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
-              <Step to='/start/share' icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
-            </div>
-
-            <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p>
-
-            <div className='onboarding__links'>
-              <Link to='/explore' className='onboarding__link'>
-                <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
-                <Icon icon={ArrowRightAltIcon} />
-              </Link>
-
-              <Link to='/home' className='onboarding__link'>
-                <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
-                <Icon icon={ArrowRightAltIcon} />
-              </Link>
-            </div>
-          </div>
-        </Route>
-
-        <Route path='/start/profile' component={Profile} />
-        <Route path='/start/follows' component={Follows} />
-        <Route path='/start/share' component={Share} />
-      </Switch>
+          <Route path='/start/profile' component={Profile} />
+          <Route path='/start/follows' component={Follows} />
+          <Route path='/start/share' component={Share} />
+        </Switch>
+      ) : <NotSignedInIndicator />}
 
       <Helmet>
         <meta name='robots' content='noindex' />

From 1ca6ff8ca537a51dc2ed83ee3a262e7ec01b9f00 Mon Sep 17 00:00:00 2001
From: Tim Rogers <rogers.timothy.john@gmail.com>
Date: Mon, 22 Apr 2024 04:00:24 -0500
Subject: [PATCH 200/223] Fixed crash when supplying FFMPEG_BINARY environment
 variable (#30022)

---
 app/lib/video_metadata_extractor.rb | 2 +-
 config/initializers/ffmpeg.rb       | 5 +++--
 lib/paperclip/image_extractor.rb    | 2 +-
 lib/paperclip/transcoder.rb         | 2 +-
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/app/lib/video_metadata_extractor.rb b/app/lib/video_metadata_extractor.rb
index f27d34868..df5409375 100644
--- a/app/lib/video_metadata_extractor.rb
+++ b/app/lib/video_metadata_extractor.rb
@@ -22,7 +22,7 @@ class VideoMetadataExtractor
   private
 
   def ffmpeg_command_output
-    command = Terrapin::CommandLine.new('ffprobe', '-i :path -print_format :format -show_format -show_streams -show_error -loglevel :loglevel')
+    command = Terrapin::CommandLine.new(Rails.configuration.x.ffprobe_binary, '-i :path -print_format :format -show_format -show_streams -show_error -loglevel :loglevel')
     command.run(path: @path, format: 'json', loglevel: 'fatal')
   end
 
diff --git a/config/initializers/ffmpeg.rb b/config/initializers/ffmpeg.rb
index 30ea617fc..87f85eeec 100644
--- a/config/initializers/ffmpeg.rb
+++ b/config/initializers/ffmpeg.rb
@@ -1,5 +1,6 @@
 # frozen_string_literal: true
 
-if ENV['FFMPEG_BINARY'].present?
-  FFMPEG.ffmpeg_binary = ENV['FFMPEG_BINARY']
+Rails.application.configure do
+  config.x.ffmpeg_binary = ENV['FFMPEG_BINARY'] || 'ffmpeg'
+  config.x.ffprobe_binary = ENV['FFPROBE_BINARY'] || 'ffprobe'
 end
diff --git a/lib/paperclip/image_extractor.rb b/lib/paperclip/image_extractor.rb
index 17fe4326f..8a565d046 100644
--- a/lib/paperclip/image_extractor.rb
+++ b/lib/paperclip/image_extractor.rb
@@ -35,7 +35,7 @@ module Paperclip
       dst.binmode
 
       begin
-        command = Terrapin::CommandLine.new('ffmpeg', '-i :source -loglevel :loglevel -y :destination', logger: Paperclip.logger)
+        command = Terrapin::CommandLine.new(Rails.configuration.x.ffmpeg_binary, '-i :source -loglevel :loglevel -y :destination', logger: Paperclip.logger)
         command.run(source: @file.path, destination: dst.path, loglevel: 'fatal')
       rescue Terrapin::ExitStatusError
         dst.close(true)
diff --git a/lib/paperclip/transcoder.rb b/lib/paperclip/transcoder.rb
index d2d946d3a..3efffa355 100644
--- a/lib/paperclip/transcoder.rb
+++ b/lib/paperclip/transcoder.rb
@@ -61,7 +61,7 @@ module Paperclip
       command_arguments, interpolations = prepare_command(destination)
 
       begin
-        command = Terrapin::CommandLine.new('ffmpeg', command_arguments.join(' '), logger: Paperclip.logger)
+        command = Terrapin::CommandLine.new(Rails.configuration.x.ffmpeg_binary, command_arguments.join(' '), logger: Paperclip.logger)
         command.run(interpolations)
       rescue Terrapin::ExitStatusError => e
         raise Paperclip::Error, "Error while transcoding #{@basename}: #{e}"

From 56b095edebebfcb0931edebd27ecd36504e19c5c Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 05:01:24 -0400
Subject: [PATCH 201/223] Update Gemfile.lock ruby and bundler versions
 (#30011)

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index aadd52d64..990994a48 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -951,7 +951,7 @@ DEPENDENCIES
   xorcist (~> 1.1)
 
 RUBY VERSION
-   ruby 3.2.2p53
+   ruby 3.2.3p157
 
 BUNDLED WITH
-   2.5.7
+   2.5.9

From ffbbf74c50bc6a3d91e194ee7ac446dae2db5c76 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 05:01:36 -0400
Subject: [PATCH 202/223] Limit `http` gem version to 5.1.x series (#30010)

---
 Gemfile      | 2 +-
 Gemfile.lock | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile b/Gemfile
index 3f621ddc5..e26efcbd5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -54,7 +54,7 @@ gem 'fast_blank', '~> 1.0'
 gem 'fastimage'
 gem 'hiredis', '~> 0.6'
 gem 'htmlentities', '~> 4.3'
-gem 'http', '~> 5.1'
+gem 'http', '~> 5.1.0'
 gem 'http_accept_language', '~> 2.1'
 gem 'httplog', '~> 1.6.2'
 gem 'i18n', '1.14.1' # TODO: Remove version when resolved: https://github.com/glebm/i18n-tasks/issues/552 / https://github.com/ruby-i18n/i18n/pull/688
diff --git a/Gemfile.lock b/Gemfile.lock
index 990994a48..2198efa79 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -860,7 +860,7 @@ DEPENDENCIES
   hcaptcha (~> 7.1)
   hiredis (~> 0.6)
   htmlentities (~> 4.3)
-  http (~> 5.1)
+  http (~> 5.1.0)
   http_accept_language (~> 2.1)
   httplog (~> 1.6.2)
   i18n (= 1.14.1)

From 33e829763dd7e4629ce62389c488aee12c35e94b Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Mon, 22 Apr 2024 08:22:16 -0400
Subject: [PATCH 203/223] Use shared `form` partial for `admin/domain_blocks`
 views (#29609)

---
 app/views/admin/domain_blocks/_form.html.haml | 46 ++++++++++++++
 app/views/admin/domain_blocks/edit.html.haml  | 61 ++-----------------
 app/views/admin/domain_blocks/new.html.haml   | 59 ++----------------
 3 files changed, 56 insertions(+), 110 deletions(-)
 create mode 100644 app/views/admin/domain_blocks/_form.html.haml

diff --git a/app/views/admin/domain_blocks/_form.html.haml b/app/views/admin/domain_blocks/_form.html.haml
new file mode 100644
index 000000000..f1785a1fd
--- /dev/null
+++ b/app/views/admin/domain_blocks/_form.html.haml
@@ -0,0 +1,46 @@
+.fields-row
+  .fields-row__column.fields-row__column-6.fields-group
+    = form.input :domain,
+                 disabled: form.object.persisted?,
+                 hint: t('admin.domain_blocks.new.hint'),
+                 label: t('admin.domain_blocks.domain'),
+                 readonly: form.object.persisted?,
+                 required: true,
+                 wrapper: :with_label
+  .fields-row__column.fields-row__column-6.fields-group
+    = form.input :severity,
+                 collection: DomainBlock.severities.keys,
+                 hint: t('admin.domain_blocks.new.severity.desc_html'),
+                 include_blank: false,
+                 label_method: ->(type) { t("admin.domain_blocks.new.severity.#{type}") },
+                 wrapper: :with_label
+.fields-group
+  = form.input :reject_media,
+               as: :boolean,
+               hint: I18n.t('admin.domain_blocks.reject_media_hint'),
+               label: I18n.t('admin.domain_blocks.reject_media'),
+               wrapper: :with_label
+.fields-group
+  = form.input :reject_reports,
+               as: :boolean,
+               hint: I18n.t('admin.domain_blocks.reject_reports_hint'),
+               label: I18n.t('admin.domain_blocks.reject_reports'),
+               wrapper: :with_label
+.fields-group
+  = form.input :obfuscate,
+               as: :boolean,
+               hint: I18n.t('admin.domain_blocks.obfuscate_hint'),
+               label: I18n.t('admin.domain_blocks.obfuscate'),
+               wrapper: :with_label
+.field-group
+  = form.input :private_comment,
+               as: :string,
+               hint: t('admin.domain_blocks.private_comment_hint'),
+               label: I18n.t('admin.domain_blocks.private_comment'),
+               wrapper: :with_label
+.field-group
+  = form.input :public_comment,
+               as: :string,
+               hint: t('admin.domain_blocks.public_comment_hint'),
+               label: I18n.t('admin.domain_blocks.public_comment'),
+               wrapper: :with_label
diff --git a/app/views/admin/domain_blocks/edit.html.haml b/app/views/admin/domain_blocks/edit.html.haml
index 7c0a9823a..40c46b8b6 100644
--- a/app/views/admin/domain_blocks/edit.html.haml
+++ b/app/views/admin/domain_blocks/edit.html.haml
@@ -1,63 +1,12 @@
 - content_for :page_title do
   = t('admin.domain_blocks.edit')
 
-= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :put do |f|
+= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :put do |form|
   = render 'shared/error_messages', object: @domain_block
 
-  .fields-row
-    .fields-row__column.fields-row__column-6.fields-group
-      = f.input :domain,
-                disabled: true,
-                hint: t('admin.domain_blocks.new.hint'),
-                label: t('admin.domain_blocks.domain'),
-                readonly: true,
-                required: true,
-                wrapper: :with_label
-
-    .fields-row__column.fields-row__column-6.fields-group
-      = f.input :severity,
-                collection: DomainBlock.severities.keys,
-                hint: t('admin.domain_blocks.new.severity.desc_html'),
-                include_blank: false,
-                label_method: ->(type) { t("admin.domain_blocks.new.severity.#{type}") },
-                wrapper: :with_label
-
-  .fields-group
-    = f.input :reject_media,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.reject_media_hint'),
-              label: I18n.t('admin.domain_blocks.reject_media'),
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :reject_reports,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.reject_reports_hint'),
-              label: I18n.t('admin.domain_blocks.reject_reports'),
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :obfuscate,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.obfuscate_hint'),
-              label: I18n.t('admin.domain_blocks.obfuscate'),
-              wrapper: :with_label
-
-  .field-group
-    = f.input :private_comment,
-              as: :string,
-              hint: t('admin.domain_blocks.private_comment_hint'),
-              label: I18n.t('admin.domain_blocks.private_comment'),
-              wrapper: :with_label
-
-  .field-group
-    = f.input :public_comment,
-              as: :string,
-              hint: t('admin.domain_blocks.public_comment_hint'),
-              label: I18n.t('admin.domain_blocks.public_comment'),
-              wrapper: :with_label
+  = render form
 
   .actions
-    = f.button :button,
-               t('generic.save_changes'),
-               type: :submit
+    = form.button :button,
+                  t('generic.save_changes'),
+                  type: :submit
diff --git a/app/views/admin/domain_blocks/new.html.haml b/app/views/admin/domain_blocks/new.html.haml
index 6a9855529..78bcfcba8 100644
--- a/app/views/admin/domain_blocks/new.html.haml
+++ b/app/views/admin/domain_blocks/new.html.haml
@@ -1,61 +1,12 @@
 - content_for :page_title do
   = t('.title')
 
-= simple_form_for @domain_block, url: admin_domain_blocks_path do |f|
+= simple_form_for @domain_block, url: admin_domain_blocks_path do |form|
   = render 'shared/error_messages', object: @domain_block
 
-  .fields-row
-    .fields-row__column.fields-row__column-6.fields-group
-      = f.input :domain,
-                hint: t('.hint'),
-                label: t('admin.domain_blocks.domain'),
-                required: true,
-                wrapper: :with_label
-
-    .fields-row__column.fields-row__column-6.fields-group
-      = f.input :severity,
-                collection: DomainBlock.severities.keys,
-                hint: t('.severity.desc_html'),
-                include_blank: false,
-                label_method: ->(type) { t(".severity.#{type}") },
-                wrapper: :with_label
-
-  .fields-group
-    = f.input :reject_media,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.reject_media_hint'),
-              label: I18n.t('admin.domain_blocks.reject_media'),
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :reject_reports,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.reject_reports_hint'),
-              label: I18n.t('admin.domain_blocks.reject_reports'),
-              wrapper: :with_label
-
-  .fields-group
-    = f.input :obfuscate,
-              as: :boolean,
-              hint: I18n.t('admin.domain_blocks.obfuscate_hint'),
-              label: I18n.t('admin.domain_blocks.obfuscate'),
-              wrapper: :with_label
-
-  .field-group
-    = f.input :private_comment,
-              as: :string,
-              hint: t('admin.domain_blocks.private_comment_hint'),
-              label: I18n.t('admin.domain_blocks.private_comment'),
-              wrapper: :with_label
-
-  .field-group
-    = f.input :public_comment,
-              as: :string,
-              hint: t('admin.domain_blocks.public_comment_hint'),
-              label: I18n.t('admin.domain_blocks.public_comment'),
-              wrapper: :with_label
+  = render form
 
   .actions
-    = f.button :button,
-               t('.create'),
-               type: :submit
+    = form.button :button,
+                  t('.create'),
+                  type: :submit

From 2ef098d01c69f667383f5d523a48ce7a09405957 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Mon, 22 Apr 2024 16:02:24 +0200
Subject: [PATCH 204/223] Revert "Rely on dotenv autoload instead of explicit
 call (#30007)" (#30028)

---
 config/application.rb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/config/application.rb b/config/application.rb
index b777018b5..a17a48b09 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -52,6 +52,8 @@ require_relative '../lib/active_record/batches'
 require_relative '../lib/simple_navigation/item_extensions'
 require_relative '../lib/http_extensions'
 
+Dotenv::Rails.load
+
 Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'
 
 require_relative '../lib/mastodon/redis_config'

From 483fabf48a0a89aed405e6472ad07552bc8befd5 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 22 Apr 2024 16:02:47 +0200
Subject: [PATCH 205/223] Update dependency http to '~> 5.2.0' (#30027)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 Gemfile                | 2 +-
 Gemfile.lock           | 9 +++++----
 config/application.rb  | 1 -
 lib/http_extensions.rb | 8 --------
 4 files changed, 6 insertions(+), 14 deletions(-)
 delete mode 100644 lib/http_extensions.rb

diff --git a/Gemfile b/Gemfile
index e26efcbd5..a10613b30 100644
--- a/Gemfile
+++ b/Gemfile
@@ -54,7 +54,7 @@ gem 'fast_blank', '~> 1.0'
 gem 'fastimage'
 gem 'hiredis', '~> 0.6'
 gem 'htmlentities', '~> 4.3'
-gem 'http', '~> 5.1.0'
+gem 'http', '~> 5.2.0'
 gem 'http_accept_language', '~> 2.1'
 gem 'httplog', '~> 1.6.2'
 gem 'i18n', '1.14.1' # TODO: Remove version when resolved: https://github.com/glebm/i18n-tasks/issues/552 / https://github.com/ruby-i18n/i18n/pull/688
diff --git a/Gemfile.lock b/Gemfile.lock
index 2198efa79..ab7375460 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -318,11 +318,12 @@ GEM
     hiredis (0.6.3)
     hkdf (0.3.0)
     htmlentities (4.3.4)
-    http (5.1.1)
+    http (5.2.0)
       addressable (~> 2.8)
+      base64 (~> 0.1)
       http-cookie (~> 1.0)
       http-form_data (~> 2.2)
-      llhttp-ffi (~> 0.4.0)
+      llhttp-ffi (~> 0.5.0)
     http-cookie (1.0.5)
       domain_name (~> 0.5)
     http-form_data (2.3.0)
@@ -403,7 +404,7 @@ GEM
       railties (>= 5.2)
       rexml
     link_header (0.0.8)
-    llhttp-ffi (0.4.0)
+    llhttp-ffi (0.5.0)
       ffi-compiler (~> 1.0)
       rake (~> 13.0)
     lograge (0.14.0)
@@ -860,7 +861,7 @@ DEPENDENCIES
   hcaptcha (~> 7.1)
   hiredis (~> 0.6)
   htmlentities (~> 4.3)
-  http (~> 5.1.0)
+  http (~> 5.2.0)
   http_accept_language (~> 2.1)
   httplog (~> 1.6.2)
   i18n (= 1.14.1)
diff --git a/config/application.rb b/config/application.rb
index a17a48b09..1b3878992 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -50,7 +50,6 @@ require_relative '../lib/rails/engine_extensions'
 require_relative '../lib/active_record/database_tasks_extensions'
 require_relative '../lib/active_record/batches'
 require_relative '../lib/simple_navigation/item_extensions'
-require_relative '../lib/http_extensions'
 
 Dotenv::Rails.load
 
diff --git a/lib/http_extensions.rb b/lib/http_extensions.rb
deleted file mode 100644
index 048f85f87..000000000
--- a/lib/http_extensions.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-# Monkey patching until https://github.com/httprb/http/pull/757 is merged
-unless HTTP::Request::METHODS.include?(:purge)
-  methods = HTTP::Request::METHODS.dup
-  HTTP::Request.send(:remove_const, :METHODS)
-  HTTP::Request.const_set(:METHODS, methods.push(:purge).freeze)
-end

From 1471c0d4e060efcc9f3cb7be72151dc95c81029c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:41:33 +0200
Subject: [PATCH 206/223] Update dependency rubocop to v1.63.3 (#30031)

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 ab7375460..7068f5dd5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -644,7 +644,7 @@ GEM
       rspec-mocks (~> 3.0)
       sidekiq (>= 5, < 8)
     rspec-support (3.13.1)
-    rubocop (1.63.2)
+    rubocop (1.63.3)
       json (~> 2.3)
       language_server-protocol (>= 3.17.0)
       parallel (~> 1.10)

From 91c7406b599f1b09a68fe38c6e812b338478841a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:41:50 +0200
Subject: [PATCH 207/223] Update dependency postcss-preset-env to v9.5.9
 (#30029)

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 e6e130e2d..b9f1c3d4d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -13157,9 +13157,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-custom-properties@npm:^13.3.7":
-  version: 13.3.7
-  resolution: "postcss-custom-properties@npm:13.3.7"
+"postcss-custom-properties@npm:^13.3.8":
+  version: 13.3.8
+  resolution: "postcss-custom-properties@npm:13.3.8"
   dependencies:
     "@csstools/cascade-layer-name-parser": "npm:^1.0.9"
     "@csstools/css-parser-algorithms": "npm:^2.6.1"
@@ -13168,7 +13168,7 @@ __metadata:
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/5d8767efae956f98d9a62a8f54d913c9ea95eaab1c906679ddeee64d87f0fb37d99c8ac1d16ec199794ed7c13a42d39ca2ea0a98df1056d400d4cbc9f31d6b94
+  checksum: 10c0/03dd1918f897005b23d09615ebb2c3faf4a01cac67462069c9cfa87c024b2a878f64948b0cf668971bc0ca00cfc349080879b3864deb3808a32d52ff2b473319
   languageName: node
   linkType: hard
 
@@ -13629,8 +13629,8 @@ __metadata:
   linkType: hard
 
 "postcss-preset-env@npm:^9.5.2":
-  version: 9.5.8
-  resolution: "postcss-preset-env@npm:9.5.8"
+  version: 9.5.9
+  resolution: "postcss-preset-env@npm:9.5.9"
   dependencies:
     "@csstools/postcss-cascade-layers": "npm:^4.0.4"
     "@csstools/postcss-color-function": "npm:^3.0.14"
@@ -13673,7 +13673,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.7"
+    postcss-custom-properties: "npm:^13.3.8"
     postcss-custom-selectors: "npm:^7.1.8"
     postcss-dir-pseudo-class: "npm:^8.0.1"
     postcss-double-position-gradients: "npm:^5.0.6"
@@ -13694,7 +13694,7 @@ __metadata:
     postcss-selector-not: "npm:^7.0.2"
   peerDependencies:
     postcss: ^8.4
-  checksum: 10c0/5f77272eb7a938e5bedc3a0877f3fb0cdc6f20c8829730ccafbbd999db78ba4e6ac60f485aa7c292f70e011cf3edfadb7d2cc5459cbf9851abc25139eeb061b7
+  checksum: 10c0/dbe020e3fc08f0b71a3ee9d3c8a66a93bb6ba62281ac89fa59c82b8632ca58d6a911ddd9c65f15355c36aad63477633fc101cc0f3ce494dbc757193ba42eb61c
   languageName: node
   linkType: hard
 

From d754b15afb01dfbccb25ca1a4d01127a7c0ac919 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 23 Apr 2024 11:07:05 +0200
Subject: [PATCH 208/223] New Crowdin Translations (automated) (#30034)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ia.json |  2 +-
 config/locales/activerecord.ia.yml      | 44 +++++++++++++++++++++++++
 config/locales/devise.ia.yml            | 11 +++++++
 config/locales/doorkeeper.ia.yml        | 18 ++++++++++
 config/locales/ia.yml                   | 12 +++++++
 5 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json
index 808b57278..73634b99c 100644
--- a/app/javascript/mastodon/locales/ia.json
+++ b/app/javascript/mastodon/locales/ia.json
@@ -781,7 +781,7 @@
   "upload_modal.apply": "Applicar",
   "upload_modal.applying": "Applicante…",
   "upload_modal.choose_image": "Seliger un imagine",
-  "upload_modal.description_placeholder": "Le clown uzbek dogmatic justo foras quasi se asphyxiava",
+  "upload_modal.description_placeholder": "Cinque expertos del zoo jam bibeva whisky frigide",
   "upload_modal.detect_text": "Deteger texto de un imagine",
   "upload_modal.edit_media": "Modificar le medio",
   "upload_modal.hint": "Clicca o trahe le circulo sur le previsualisation pro eliger le puncto focal que essera sempre visibile sur tote le miniaturas.",
diff --git a/config/locales/activerecord.ia.yml b/config/locales/activerecord.ia.yml
index eec89ad52..b1dd90bc3 100644
--- a/config/locales/activerecord.ia.yml
+++ b/config/locales/activerecord.ia.yml
@@ -2,14 +2,58 @@
 ia:
   activerecord:
     attributes:
+      poll:
+        expires_at: Data limite
+        options: Optiones
       user:
+        agreement: Accordo de servicio
         email: Adresse de e-mail
+        locale: Region
         password: Contrasigno
       user/account:
         username: Nomine de usator
+      user/invite_request:
+        text: Motivo
     errors:
       models:
+        account:
+          attributes:
+            username:
+              invalid: debe continer solmente litteras, numeros e tractos de sublineamento
+              reserved: es reservate
+        admin/webhook:
+          attributes:
+            url:
+              invalid: non es un URL valide
+        doorkeeper/application:
+          attributes:
+            website:
+              invalid: non es un URL valide
+        import:
+          attributes:
+            data:
+              malformed: es mal formate
         status:
           attributes:
             reblog:
               taken: del message jam existe
+        user:
+          attributes:
+            email:
+              blocked: usa un fornitor de e-mail prohibite
+              unreachable: non pare exister
+            role_id:
+              elevated: non pote esser superior a tu rolo actual
+        user_role:
+          attributes:
+            permissions_as_keys:
+              dangerous: includer permissiones non secur pro le rolo de base
+              elevated: non pote includer permissiones que tu rolo actual non possede
+              own_role: non pote esser cambiate con tu rolo actual
+            position:
+              elevated: non pote esser superior a tu rolo actual
+              own_role: non pote esser cambiate con tu rolo actual
+        webhook:
+          attributes:
+            events:
+              invalid_permissions: non pote includer eventos pro le quales tu non ha le derectos
diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml
index 62f106bcf..d180a46a6 100644
--- a/config/locales/devise.ia.yml
+++ b/config/locales/devise.ia.yml
@@ -1,10 +1,21 @@
 ---
 ia:
   devise:
+    confirmations:
+      confirmed: Tu conto de e-mail ha essite confirmate con successo.
+      send_instructions: Tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
+      send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
     failure:
       already_authenticated: Tu jam initiava le session.
       inactive: Tu conto ancora non es activate.
+      invalid: "%{authentication_keys} o contrasigno non valide."
+      last_attempt: Tu ha solmente un altere tentativa ante que tu conto es serrate.
       locked: Tu conto es blocate.
+      not_found_in_database: "%{authentication_keys} o contrasigno non valide."
+      omniauth_user_creation_failure: Error creante un conto pro iste identitate.
+      pending: Tu conto es ancora sub revision.
+      timeout: Tu session ha expirate. Per favor reaperi session pro continuar.
+      unauthenticated: Es necessari aperir session o crear un conto ante de continuar.
     mailer:
       confirmation_instructions:
         action: Verificar adresse de e-mail
diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml
index 443342b40..b41531a1b 100644
--- a/config/locales/doorkeeper.ia.yml
+++ b/config/locales/doorkeeper.ia.yml
@@ -5,9 +5,16 @@ ia:
       doorkeeper/application:
         name: Nomine de application
         website: Sito web de application
+    errors:
+      models:
+        doorkeeper/application:
+          attributes:
+            redirect_uri:
+              invalid_uri: debe esser un URI valide.
   doorkeeper:
     applications:
       buttons:
+        authorize: Autorisar
         cancel: Cancellar
         edit: Modificar
       confirmations:
@@ -28,6 +35,8 @@ ia:
         actions: Actiones
         title: 'Application: %{name}'
     authorizations:
+      buttons:
+        authorize: Autorisar
       error:
         title: Ocurreva un error
     authorized_applications:
@@ -50,14 +59,17 @@ ia:
       title:
         accounts: Contos
         admin/accounts: Gestion de contos
+        admin/reports: Gestion de reportos
         all: Accesso plen a tu conto de Mastodon
         bookmarks: Marcapaginas
         conversations: Conversationes
         favourites: Favoritos
+        filters: Filtros
         lists: Listas
         mutes: Silentiates
         notifications: Notificationes
         push: Notificationes push
+        reports: Reportos
         search: Cercar
         statuses: Messages
     layouts:
@@ -67,16 +79,21 @@ ia:
           oauth2_provider: Fornitor OAuth2
     scopes:
       admin:read: leger tote le datos in le servitor
+      admin:write: modificar tote le datos in le servitor
       read: leger tote le datos de tu conto
       read:accounts: vider informationes de conto
+      read:bookmarks: vider tu marcapaginas
       read:favourites: vider tu favoritos
       read:filters: vider tu filtros
+      read:follows: vider tu sequites
       read:lists: vider tu listas
       read:notifications: vider tu notificationes
       read:reports: vider tu reportos
       read:statuses: vider tote le messages
+      write: modificar tote le datos de tu conto
       write:accounts: modificar tu profilo
       write:blocks: blocar contos e dominios
+      write:bookmarks: adder messages al marcapaginas
       write:conversations: silentiar e deler conversationes
       write:favourites: messages favorite
       write:filters: crear filtros
@@ -85,4 +102,5 @@ ia:
       write:media: incargar files de medios
       write:mutes: silentiar personas e conversationes
       write:notifications: rader tu notificationes
+      write:reports: signalar altere personas
       write:statuses: publicar messages
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index 3ba7a5148..a167b5d8c 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -22,6 +22,7 @@ ia:
   admin:
     account_moderation_notes:
       create: Lassar un nota
+      created_msg: Nota de moderation create con successo!
     accounts:
       add_email_domain_block: Blocar dominio de e-mail
       are_you_sure: Es tu secur?
@@ -74,13 +75,19 @@ ia:
       security_measures:
         only_password: Solmente contrasigno
         password_and_2fa: Contrasigno e 2FA
+      show:
+        created_reports: Reportos facite
+        targeted_reports: Signalate per alteres
       silenced: Limitate
       statuses: Messages
       subscribe: Subscriber
+      suspended: Suspendite
       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
+      undo_silenced: Disfacer le limite
+      undo_suspension: Disfacer le suspension
       username: Nomine de usator
       view_domain: Vider summario de dominio
     action_logs:
@@ -100,6 +107,9 @@ ia:
         enable_user: Activar le usator
         promote_user: Promover usator
         reset_password_user: Reinitialisar contrasigno
+        silence_account: Limitar conto
+        unblock_email_account: Disblocar adresse de e-mail
+        unsilence_account: Disfacer le limite de conto
         update_announcement: Actualisar annuncio
         update_custom_emoji: Actualisar emoji personalisate
         update_ip_block: Actualisar le regula IP
@@ -133,6 +143,7 @@ ia:
       enabled_msg: Emoji activate con successo
       new:
         title: Adder nove emoji personalisate
+      title: Emojis personalisate
       upload: Incargar
     dashboard:
       active_users: usatores active
@@ -150,6 +161,7 @@ ia:
     domain_blocks:
       confirm_suspension:
         cancel: Cancellar
+        stop_communication: Tu servitor stoppara le communication con iste servitores.
       domain: Dominio
       edit: Modificar un bloco de dominio
       export: Exportar

From 049b159beb672ca50b239a2275f78870ee7787da Mon Sep 17 00:00:00 2001
From: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
Date: Tue, 23 Apr 2024 13:47:00 +0200
Subject: [PATCH 209/223] Add read:me OAuth 2.0 scope, allowing more limited
 access to user data (#29087)

---
 .../api/v1/accounts/credentials_controller.rb      |  2 +-
 config/initializers/doorkeeper.rb                  |  1 +
 config/locales/doorkeeper.en.yml                   |  1 +
 spec/requests/api/v1/accounts/credentials_spec.rb  | 14 ++++++++++++++
 4 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb
index 8f31336b9..e8f712457 100644
--- a/app/controllers/api/v1/accounts/credentials_controller.rb
+++ b/app/controllers/api/v1/accounts/credentials_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Api::V1::Accounts::CredentialsController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:update]
+  before_action -> { doorkeeper_authorize! :read, :'read:accounts', :'read:me' }, except: [:update]
   before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]
   before_action :require_user!
 
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 428e47391..1e8f9ad50 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -89,6 +89,7 @@ Doorkeeper.configure do
                   :'write:reports',
                   :'write:statuses',
                   :read,
+                  :'read:me',
                   :'read:accounts',
                   :'read:blocks',
                   :'read:bookmarks',
diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml
index 0432a5e3f..98776f219 100644
--- a/config/locales/doorkeeper.en.yml
+++ b/config/locales/doorkeeper.en.yml
@@ -174,6 +174,7 @@ en:
       read:filters: see your filters
       read:follows: see your follows
       read:lists: see your lists
+      read:me: read only your account's basic information
       read:mutes: see your mutes
       read:notifications: see your notifications
       read:reports: see your reports
diff --git a/spec/requests/api/v1/accounts/credentials_spec.rb b/spec/requests/api/v1/accounts/credentials_spec.rb
index 737348c2d..8ae9c78a0 100644
--- a/spec/requests/api/v1/accounts/credentials_spec.rb
+++ b/spec/requests/api/v1/accounts/credentials_spec.rb
@@ -28,6 +28,20 @@ RSpec.describe 'credentials API' do
         locked: true,
       })
     end
+
+    describe 'allows the read:me scope' do
+      let(:scopes) { 'read:me' }
+
+      it 'returns the response successfully' do
+        subject
+
+        expect(response).to have_http_status(200)
+
+        expect(body_as_json).to include({
+          locked: true,
+        })
+      end
+    end
   end
 
   describe 'PATCH /api/v1/accounts/update_credentials' do

From a2399046ca600d492b492b8dae88011de687bece Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 23 Apr 2024 14:54:52 +0200
Subject: [PATCH 210/223] Fix string interpolation for software updates admin
 mailer (#30035)

---
 app/views/admin_mailer/new_critical_software_updates.text.erb | 2 +-
 app/views/admin_mailer/new_software_updates.text.erb          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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 e4886c262..a3f031bda 100644
--- a/app/views/admin_mailer/new_critical_software_updates.text.erb
+++ b/app/views/admin_mailer/new_critical_software_updates.text.erb
@@ -1,7 +1,7 @@
 <%= raw t('admin_mailer.new_critical_software_updates.body') %>
 
 <% @software_updates.each do |update| %>
-- Mastodon #{update.version}: #{update.release_notes}
+- 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 7612b7c59..0eccbbf9e 100644
--- a/app/views/admin_mailer/new_software_updates.text.erb
+++ b/app/views/admin_mailer/new_software_updates.text.erb
@@ -1,7 +1,7 @@
 <%= raw t('admin_mailer.new_software_updates.body') %>
 
 <% @software_updates.each do |update| %>
-- Mastodon #{update.version}: #{update.release_notes}
+- Mastodon <%= update.version %>: <%= update.release_notes %>
 <% end %>
 
 <%= raw t('application_mailer.view')%> <%= admin_software_updates_url %>

From 32ead51e5a8d6abbc0b4bacb00192ddc72a9817a Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 23 Apr 2024 12:43:49 -0400
Subject: [PATCH 211/223] Add material design icons to admin/settings views
 (#27780)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
---
 app/helpers/application_helper.rb                    |  8 ++++++++
 app/javascript/styles/mastodon/admin.scss            |  7 +++++++
 .../account_warnings/_account_warning.html.haml      |  2 +-
 app/views/admin/accounts/_remote_account.html.haml   |  4 ++--
 app/views/admin/accounts/index.html.haml             |  6 +++---
 app/views/admin/accounts/show.html.haml              |  2 +-
 app/views/admin/custom_emojis/index.html.haml        |  8 ++++----
 app/views/admin/dashboard/index.html.haml            |  8 ++++----
 app/views/admin/email_domain_blocks/index.html.haml  |  2 +-
 .../export_domain_blocks/_domain_block.html.haml     |  2 +-
 .../admin/export_domain_blocks/import.html.haml      |  2 +-
 .../admin/follow_recommendations/show.html.haml      |  4 ++--
 app/views/admin/instances/show.html.haml             |  2 +-
 app/views/admin/invites/_invite.html.haml            |  2 +-
 app/views/admin/ip_blocks/index.html.haml            |  2 +-
 app/views/admin/relationships/index.html.haml        |  4 ++--
 app/views/admin/relays/_relay.html.haml              |  4 ++--
 app/views/admin/reports/_header_card.html.haml       |  2 +-
 app/views/admin/reports/_status.html.haml            |  2 +-
 app/views/admin/reports/actions/preview.html.haml    |  2 +-
 app/views/admin/reports/show.html.haml               |  4 ++--
 app/views/admin/roles/_role.html.haml                |  4 ++--
 app/views/admin/settings/shared/_links.html.haml     |  2 +-
 app/views/admin/status_edits/_status_edit.html.haml  |  2 +-
 app/views/admin/statuses/index.html.haml             |  4 ++--
 app/views/admin/tags/show.html.haml                  | 12 ++++++------
 app/views/admin/trends/links/index.html.haml         | 10 +++++-----
 .../links/preview_card_providers/index.html.haml     |  6 +++---
 app/views/admin/trends/statuses/_status.html.haml    |  2 +-
 app/views/admin/trends/statuses/index.html.haml      |  8 ++++----
 app/views/admin/trends/tags/_tag.html.haml           |  2 +-
 app/views/admin/trends/tags/index.html.haml          |  4 ++--
 config/initializers/propshaft.rb                     |  4 ++++
 33 files changed, 79 insertions(+), 60 deletions(-)

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 668afe7fd..4cf959f2d 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -113,6 +113,14 @@ module ApplicationHelper
     content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
   end
 
+  def material_symbol(icon, attributes = {})
+    inline_svg_tag(
+      "400-24px/#{icon}.svg",
+      class: %w(icon).concat(attributes[:class].to_s.split),
+      role: :img
+    )
+  end
+
   def check_icon
     inline_svg_tag 'check.svg'
   end
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index fadd77d13..06a3b5202 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -10,6 +10,13 @@ $content-width: 840px;
   width: 100%;
   min-height: 100vh;
 
+  .icon {
+    width: 16px;
+    height: 16px;
+    vertical-align: middle;
+    margin: 0 2px;
+  }
+
   .sidebar-wrapper {
     min-height: 100vh;
     overflow: hidden;
diff --git a/app/views/admin/account_warnings/_account_warning.html.haml b/app/views/admin/account_warnings/_account_warning.html.haml
index 5702e4f6d..368e69e63 100644
--- a/app/views/admin/account_warnings/_account_warning.html.haml
+++ b/app/views/admin/account_warnings/_account_warning.html.haml
@@ -2,7 +2,7 @@
   .log-entry__header
     .log-entry__avatar
       .indicator-icon{ class: account_warning.overruled? ? 'success' : 'failure' }
-        = fa_icon 'warning'
+        = material_symbol 'warning'
     .log-entry__content
       .log-entry__title
         = t(account_warning.action,
diff --git a/app/views/admin/accounts/_remote_account.html.haml b/app/views/admin/accounts/_remote_account.html.haml
index 99996e1d4..6755af249 100644
--- a/app/views/admin/accounts/_remote_account.html.haml
+++ b/app/views/admin/accounts/_remote_account.html.haml
@@ -2,14 +2,14 @@
   %th= t('admin.accounts.inbox_url')
   %td
     = account.inbox_url
-    = fa_icon DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'times'
+    = material_symbol DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'close'
   %td
     = table_link_to 'search', domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(account.domain)
 %tr
   %th= t('admin.accounts.shared_inbox_url')
   %td
     = account.shared_inbox_url
-    = fa_icon DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'times'
+    = material_symbol DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'close'
   %td
     - if domain_block.nil?
       = table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: account.domain)
diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml
index 0ca457f39..01b072938 100644
--- a/app/views/admin/accounts/index.html.haml
+++ b/app/views/admin/accounts/index.html.haml
@@ -53,19 +53,19 @@
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
         - if @accounts.any?(&:user_pending?)
-          = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]),
+          = f.button safe_join([material_symbol('check'), t('admin.accounts.approve')]),
                      class: 'table-action-link',
                      data: { confirm: t('admin.reports.are_you_sure') },
                      name: :approve,
                      type: :submit
 
-          = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]),
+          = f.button safe_join([material_symbol('close'), t('admin.accounts.reject')]),
                      class: 'table-action-link',
                      data: { confirm: t('admin.reports.are_you_sure') },
                      name: :reject,
                      type: :submit
 
-        = f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]),
+        = f.button safe_join([material_symbol('lock'), t('admin.accounts.perform_full_suspension')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :suspend,
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index d380d807a..41fcafa29 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -20,7 +20,7 @@
               %dd{ title: field.value, class: custom_field_classes(field) }
                 - if field.verified?
                   %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) }
-                    = fa_icon 'check'
+                    = material_symbol 'check'
                 = prerender_custom_emojis(account_field_value_format(field, with_rel_me: false), account.emojis)
 
     - if account.note.present?
diff --git a/app/views/admin/custom_emojis/index.html.haml b/app/views/admin/custom_emojis/index.html.haml
index bea6a7cd2..e87dd4128 100644
--- a/app/views/admin/custom_emojis/index.html.haml
+++ b/app/views/admin/custom_emojis/index.html.haml
@@ -48,19 +48,19 @@
         - if params[:local] == '1'
           = f.button safe_join([fa_icon('save'), t('generic.save_changes')]), name: :update, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
-          = f.button safe_join([fa_icon('eye'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([material_symbol('visibility'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
-          = f.button safe_join([fa_icon('eye-slash'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([material_symbol('visibility_off'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
         = f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.enable')]), name: :enable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
         = f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.disable')]), name: :disable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
         - if can?(:destroy, :custom_emoji)
-          = f.button safe_join([fa_icon('times'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([material_symbol('close'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
         - if can?(:copy, :custom_emoji) && params[:local] != '1'
-          = f.button safe_join([fa_icon('copy'), t('admin.custom_emojis.copy')]), name: :copy, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([material_symbol('content_copy'), t('admin.custom_emojis.copy')]), name: :copy, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
     - if params[:local] == '1'
       .batch-table__form.simple_form
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8a8099278..8430dd3c4 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -57,19 +57,19 @@
   .dashboard__item
     = link_to admin_reports_path, class: 'dashboard__quick-access' do
       %span= t('admin.dashboard.pending_reports_html', count: @pending_reports_count)
-      = fa_icon 'chevron-right fw'
+      = material_symbol 'chevron_right'
 
     = link_to admin_accounts_path(status: 'pending'), class: 'dashboard__quick-access' do
       %span= t('admin.dashboard.pending_users_html', count: @pending_users_count)
-      = fa_icon 'chevron-right fw'
+      = material_symbol 'chevron_right'
 
     = link_to admin_trends_tags_path(status: 'pending_review'), class: 'dashboard__quick-access' do
       %span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count)
-      = fa_icon 'chevron-right fw'
+      = material_symbol 'chevron_right'
 
     = link_to admin_disputes_appeals_path(status: 'pending'), class: 'dashboard__quick-access' do
       %span= t('admin.dashboard.pending_appeals_html', count: @pending_appeals_count)
-      = fa_icon 'chevron-right fw'
+      = material_symbol 'chevron_right'
   .dashboard__item
     = react_admin_component :dimension,
                             dimension: 'sources',
diff --git a/app/views/admin/email_domain_blocks/index.html.haml b/app/views/admin/email_domain_blocks/index.html.haml
index 59036f899..684735c20 100644
--- a/app/views/admin/email_domain_blocks/index.html.haml
+++ b/app/views/admin/email_domain_blocks/index.html.haml
@@ -12,7 +12,7 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('times'), t('admin.email_domain_blocks.delete')]),
+        = f.button safe_join([material_symbol('close'), t('admin.email_domain_blocks.delete')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :delete,
diff --git a/app/views/admin/export_domain_blocks/_domain_block.html.haml b/app/views/admin/export_domain_blocks/_domain_block.html.haml
index cdce4fd28..79cc5595c 100644
--- a/app/views/admin/export_domain_blocks/_domain_block.html.haml
+++ b/app/views/admin/export_domain_blocks/_domain_block.html.haml
@@ -23,5 +23,5 @@
         = f.object.public_comment
       - if existing_relationships
         ·
-        = fa_icon 'warning fw'
+        = material_symbol 'warning'
         = t('admin.export_domain_blocks.import.existing_relationships_warning')
diff --git a/app/views/admin/export_domain_blocks/import.html.haml b/app/views/admin/export_domain_blocks/import.html.haml
index 48016a9ab..52ffc3d46 100644
--- a/app/views/admin/export_domain_blocks/import.html.haml
+++ b/app/views/admin/export_domain_blocks/import.html.haml
@@ -12,7 +12,7 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('copy'), t('admin.domain_blocks.import')]),
+        = f.button safe_join([material_symbol('content_copy'), t('admin.domain_blocks.import')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :save,
diff --git a/app/views/admin/follow_recommendations/show.html.haml b/app/views/admin/follow_recommendations/show.html.haml
index 9d23f9ba5..c8ad653a8 100644
--- a/app/views/admin/follow_recommendations/show.html.haml
+++ b/app/views/admin/follow_recommendations/show.html.haml
@@ -31,13 +31,13 @@
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
         - if params[:status].blank? && can?(:suppress, :follow_recommendation)
-          = f.button safe_join([fa_icon('times'), t('admin.follow_recommendations.suppress')]),
+          = f.button safe_join([material_symbol('close'), t('admin.follow_recommendations.suppress')]),
                      class: 'table-action-link',
                      data: { confirm: t('admin.reports.are_you_sure') },
                      name: :suppress,
                      type: :submit
         - if params[:status] == 'suppressed' && can?(:unsuppress, :follow_recommendation)
-          = f.button safe_join([fa_icon('plus'), t('admin.follow_recommendations.unsuppress')]),
+          = f.button safe_join([material_symbol('add'), t('admin.follow_recommendations.unsuppress')]),
                      class: 'table-action-link',
                      name: :unsuppress,
                      type: :submit
diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml
index 5bf4e899f..d916203d0 100644
--- a/app/views/admin/instances/show.html.haml
+++ b/app/views/admin/instances/show.html.haml
@@ -9,7 +9,7 @@
 
   - if @instance.persisted?
     %p
-      = fa_icon 'info fw'
+      = material_symbol 'info'
       = t('admin.instances.totals_time_period_hint_html')
 
     .dashboard
diff --git a/app/views/admin/invites/_invite.html.haml b/app/views/admin/invites/_invite.html.haml
index e6ad9de34..f9cd6003f 100644
--- a/app/views/admin/invites/_invite.html.haml
+++ b/app/views/admin/invites/_invite.html.haml
@@ -12,7 +12,7 @@
 
   - if invite.valid_for_use?
     %td
-      = fa_icon 'user fw'
+      = material_symbol 'person'
       = invite.uses
       = " / #{invite.max_uses}" unless invite.max_uses.nil?
     %td
diff --git a/app/views/admin/ip_blocks/index.html.haml b/app/views/admin/ip_blocks/index.html.haml
index f1d2b3dc4..9eba6c68f 100644
--- a/app/views/admin/ip_blocks/index.html.haml
+++ b/app/views/admin/ip_blocks/index.html.haml
@@ -14,7 +14,7 @@
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
         - if can?(:destroy, :ip_block)
-          = f.button safe_join([fa_icon('times'), t('admin.ip_blocks.delete')]),
+          = f.button safe_join([material_symbol('close'), t('admin.ip_blocks.delete')]),
                      class: 'table-action-link',
                      data: { confirm: t('admin.reports.are_you_sure') },
                      name: :delete,
diff --git a/app/views/admin/relationships/index.html.haml b/app/views/admin/relationships/index.html.haml
index 8260430d8..c2daefb42 100644
--- a/app/views/admin/relationships/index.html.haml
+++ b/app/views/admin/relationships/index.html.haml
@@ -19,7 +19,7 @@
 
   .back-link
     = link_to admin_account_path(@account.id) do
-      = fa_icon 'chevron-left fw'
+      = material_symbol 'chevron_left'
       = t('admin.statuses.back_to_account')
 
 %hr.spacer/
@@ -30,7 +30,7 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]),
+        = f.button safe_join([material_symbol('lock'), t('admin.accounts.perform_full_suspension')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :suspend,
diff --git a/app/views/admin/relays/_relay.html.haml b/app/views/admin/relays/_relay.html.haml
index f1dd2b2dd..0960124cc 100644
--- a/app/views/admin/relays/_relay.html.haml
+++ b/app/views/admin/relays/_relay.html.haml
@@ -4,7 +4,7 @@
   %td
     - if relay.accepted?
       %span.positive-hint
-        = fa_icon('check')
+        = material_symbol('check')
         &nbsp;
         = t 'admin.relays.enabled'
     - elsif relay.pending?
@@ -13,7 +13,7 @@
       = t 'admin.relays.pending'
     - else
       %span.negative-hint
-        = fa_icon('times')
+        = material_symbol('close')
         &nbsp;
         = t 'admin.relays.disabled'
   %td
diff --git a/app/views/admin/reports/_header_card.html.haml b/app/views/admin/reports/_header_card.html.haml
index e90e3f9c9..52e62b449 100644
--- a/app/views/admin/reports/_header_card.html.haml
+++ b/app/views/admin/reports/_header_card.html.haml
@@ -16,7 +16,7 @@
           %strong.emojify.p-name= display_name(report.target_account, custom_emojify: true)
         %span
           = acct(report.target_account)
-          = fa_icon('lock') if report.target_account.locked?
+          = material_symbol('lock') if report.target_account.locked?
     - if report.target_account.note.present?
       .account-card__bio.emojify
         = prerender_custom_emojis(account_bio_format(report.target_account), report.target_account.emojis)
diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml
index 3775a1101..66820f0a6 100644
--- a/app/views/admin/reports/_status.html.haml
+++ b/app/views/admin/reports/_status.html.haml
@@ -37,5 +37,5 @@
         = t("statuses.visibilities.#{status.visibility}")
       - if status.proper.sensitive?
         ·
-        = fa_icon('eye-slash fw')
+        = material_symbol('visibility_off')
         = t('stream_entries.sensitive_content')
diff --git a/app/views/admin/reports/actions/preview.html.haml b/app/views/admin/reports/actions/preview.html.haml
index 8634bb215..7a737d4f7 100644
--- a/app/views/admin/reports/actions/preview.html.haml
+++ b/app/views/admin/reports/actions/preview.html.haml
@@ -58,7 +58,7 @@
 
                   - status.ordered_media_attachments.each do |media_attachment|
                     %abbr{ title: media_attachment.description }
-                      = fa_icon 'link'
+                      = material_symbol 'link'
                       = media_attachment.file_file_name
                 .strike-card__statuses-list__item__meta
                   = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do
diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml
index e37fa2590..c880021cf 100644
--- a/app/views/admin/reports/show.html.haml
+++ b/app/views/admin/reports/show.html.haml
@@ -41,7 +41,7 @@
 %p
   = t 'admin.reports.statuses_description_html'
   —
-  = link_to safe_join([fa_icon('plus'), t('admin.reports.add_to_report')]),
+  = link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]),
             admin_account_statuses_path(@report.target_account_id, report_id: @report.id),
             class: 'table-action-link'
 
@@ -52,7 +52,7 @@
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
         - if !@statuses.empty? && @report.unresolved?
-          = f.button safe_join([fa_icon('times'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
+          = f.button safe_join([material_symbol('close'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
     .batch-table__body
       - if @statuses.empty?
         = nothing_here 'nothing-here--under-tabs'
diff --git a/app/views/admin/roles/_role.html.haml b/app/views/admin/roles/_role.html.haml
index d6c6b62c8..fd37644c8 100644
--- a/app/views/admin/roles/_role.html.haml
+++ b/app/views/admin/roles/_role.html.haml
@@ -2,7 +2,7 @@
   - if can?(:update, role)
     = link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do
       %span.user-role{ class: "user-role-#{role.id}" }
-        = fa_icon 'users fw'
+        = material_symbol 'group'
 
         - if role.everyone?
           = t('admin.roles.everyone')
@@ -11,7 +11,7 @@
   - else
     %span.announcements-list__item__title
       %span.user-role{ class: "user-role-#{role.id}" }
-        = fa_icon 'users fw'
+        = material_symbol 'group'
 
         - if role.everyone?
           = t('admin.roles.everyone')
diff --git a/app/views/admin/settings/shared/_links.html.haml b/app/views/admin/settings/shared/_links.html.haml
index d8b697592..8b0678d4c 100644
--- a/app/views/admin/settings/shared/_links.html.haml
+++ b/app/views/admin/settings/shared/_links.html.haml
@@ -3,7 +3,7 @@
     :ruby
       primary.item :branding, safe_join([fa_icon('pencil fw'), t('admin.settings.branding.title')]), admin_settings_branding_path
       primary.item :about, safe_join([fa_icon('file-text fw'), t('admin.settings.about.title')]), admin_settings_about_path
-      primary.item :registrations, safe_join([fa_icon('users fw'), t('admin.settings.registrations.title')]), admin_settings_registrations_path
+      primary.item :registrations, safe_join([material_symbol('group'), t('admin.settings.registrations.title')]), admin_settings_registrations_path
       primary.item :discovery, safe_join([fa_icon('search fw'), t('admin.settings.discovery.title')]), admin_settings_discovery_path
       primary.item :content_retention, safe_join([fa_icon('history fw'), t('admin.settings.content_retention.title')]), admin_settings_content_retention_path
       primary.item :appearance, safe_join([fa_icon('desktop fw'), t('admin.settings.appearance.title')]), admin_settings_appearance_path
diff --git a/app/views/admin/status_edits/_status_edit.html.haml b/app/views/admin/status_edits/_status_edit.html.haml
index 725477721..0bec0159e 100644
--- a/app/views/admin/status_edits/_status_edit.html.haml
+++ b/app/views/admin/status_edits/_status_edit.html.haml
@@ -26,5 +26,5 @@
 
         - if status_edit.sensitive?
           ·
-          = fa_icon('eye-slash fw')
+          = material_symbol('visibility_off')
           = t('stream_entries.sensitive_content')
diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml
index 33a41bd36..a41a6332d 100644
--- a/app/views/admin/statuses/index.html.haml
+++ b/app/views/admin/statuses/index.html.haml
@@ -12,11 +12,11 @@
   .back-link
     - if params[:report_id]
       = link_to admin_report_path(params[:report_id].to_i) do
-        = fa_icon 'chevron-left fw'
+        = material_symbol 'chevron_left'
         = t('admin.statuses.back_to_report')
     - else
       = link_to admin_account_path(@account.id) do
-        = fa_icon 'chevron-left fw'
+        = material_symbol 'chevron_left'
         = t('admin.statuses.back_to_account')
 
 %hr.spacer/
diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml
index 2e4424bec..f2d87b54b 100644
--- a/app/views/admin/tags/show.html.haml
+++ b/app/views/admin/tags/show.html.haml
@@ -52,26 +52,26 @@
       = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.usable? ? 'positive' : 'negative'] do
         - if @tag.usable?
           %span= t('admin.trends.tags.usable')
-          = fa_icon 'check fw'
+          = material_symbol 'check'
         - else
           %span= t('admin.trends.tags.not_usable')
-          = fa_icon 'lock fw'
+          = material_symbol 'lock'
 
       = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.trendable? ? 'positive' : 'negative'] do
         - if @tag.trendable?
           %span= t('admin.trends.tags.trendable')
-          = fa_icon 'check fw'
+          = material_symbol 'check'
         - else
           %span= t('admin.trends.tags.not_trendable')
-          = fa_icon 'lock fw'
+          = material_symbol 'lock'
 
       = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
         - if @tag.listable?
           %span= t('admin.trends.tags.listable')
-          = fa_icon 'check fw'
+          = material_symbol 'check'
         - else
           %span= t('admin.trends.tags.not_listable')
-          = fa_icon 'lock fw'
+          = material_symbol 'lock'
 
   %hr.spacer/
 
diff --git a/app/views/admin/trends/links/index.html.haml b/app/views/admin/trends/links/index.html.haml
index 965d2b2e5..c503b2d39 100644
--- a/app/views/admin/trends/links/index.html.haml
+++ b/app/views/admin/trends/links/index.html.haml
@@ -24,7 +24,7 @@
     .back-link
       = link_to admin_trends_links_preview_card_providers_path do
         = t('admin.trends.preview_card_providers.title')
-        = fa_icon 'chevron-right fw'
+        = material_symbol 'chevron_right'
 
 = form_for(@form, url: batch_admin_trends_links_path) do |f|
   = hidden_field_tag :page, params[:page] || 1
@@ -37,22 +37,22 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('check'), t('admin.trends.links.allow')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.links.allow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve,
                    type: :submit
-        = f.button safe_join([fa_icon('check'), t('admin.trends.links.allow_provider')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.links.allow_provider')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve_providers,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.links.disallow')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.links.disallow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.links.disallow_provider')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.links.disallow_provider')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject_providers,
diff --git a/app/views/admin/trends/links/preview_card_providers/index.html.haml b/app/views/admin/trends/links/preview_card_providers/index.html.haml
index c91822fb7..706c60701 100644
--- a/app/views/admin/trends/links/preview_card_providers/index.html.haml
+++ b/app/views/admin/trends/links/preview_card_providers/index.html.haml
@@ -15,7 +15,7 @@
       %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{PreviewCardProvider.pending_review.count})"], ' '), status: 'pending_review'
   .back-link
     = link_to admin_trends_links_path do
-      = fa_icon 'chevron-left fw'
+      = material_symbol 'chevron_left'
       = t('admin.trends.links.title')
 
 %hr.spacer/
@@ -31,12 +31,12 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('check'), t('admin.trends.allow')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.allow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.disallow')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.disallow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject,
diff --git a/app/views/admin/trends/statuses/_status.html.haml b/app/views/admin/trends/statuses/_status.html.haml
index 095f3f218..09547ff03 100644
--- a/app/views/admin/trends/statuses/_status.html.haml
+++ b/app/views/admin/trends/statuses/_status.html.haml
@@ -11,7 +11,7 @@
 
         - status.ordered_media_attachments.each do |media_attachment|
           %abbr{ title: media_attachment.description }
-            = fa_icon 'link'
+            = material_symbol 'link'
             = media_attachment.file_file_name
 
     = t 'admin.trends.statuses.shared_by',
diff --git a/app/views/admin/trends/statuses/index.html.haml b/app/views/admin/trends/statuses/index.html.haml
index 0891d15fc..66151ad31 100644
--- a/app/views/admin/trends/statuses/index.html.haml
+++ b/app/views/admin/trends/statuses/index.html.haml
@@ -31,22 +31,22 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('check'), t('admin.trends.statuses.allow')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.statuses.allow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve,
                    type: :submit
-        = f.button safe_join([fa_icon('check'), t('admin.trends.statuses.allow_account')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.statuses.allow_account')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve_accounts,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.statuses.disallow')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.statuses.disallow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.statuses.disallow_account')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.statuses.disallow_account')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject_accounts,
diff --git a/app/views/admin/trends/tags/_tag.html.haml b/app/views/admin/trends/tags/_tag.html.haml
index 70c7d8dbd..8cc0d713b 100644
--- a/app/views/admin/trends/tags/_tag.html.haml
+++ b/app/views/admin/trends/tags/_tag.html.haml
@@ -5,7 +5,7 @@
   .batch-table__row__content.pending-account
     .pending-account__header
       = link_to admin_tag_path(tag.id) do
-        = fa_icon 'hashtag'
+        = material_symbol 'tag'
         = tag.display_name
 
       %br/
diff --git a/app/views/admin/trends/tags/index.html.haml b/app/views/admin/trends/tags/index.html.haml
index effde7b0e..655955f7f 100644
--- a/app/views/admin/trends/tags/index.html.haml
+++ b/app/views/admin/trends/tags/index.html.haml
@@ -25,12 +25,12 @@
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        = f.button safe_join([fa_icon('check'), t('admin.trends.allow')]),
+        = f.button safe_join([material_symbol('check'), t('admin.trends.allow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :approve,
                    type: :submit
-        = f.button safe_join([fa_icon('times'), t('admin.trends.disallow')]),
+        = f.button safe_join([material_symbol('close'), t('admin.trends.disallow')]),
                    class: 'table-action-link',
                    data: { confirm: t('admin.reports.are_you_sure') },
                    name: :reject,
diff --git a/config/initializers/propshaft.rb b/config/initializers/propshaft.rb
index 6cf368d5b..eff7ec90b 100644
--- a/config/initializers/propshaft.rb
+++ b/config/initializers/propshaft.rb
@@ -1,3 +1,7 @@
 # frozen_string_literal: true
 
+# SVG icons
 Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'images')
+
+# Material Design icons
+Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'material-icons')

From 3f6887557b23d363e7f8f18518db4447739d64bb Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Tue, 23 Apr 2024 12:45:12 -0400
Subject: [PATCH 212/223] Move JS source from `packs` to `entrypoints` (#30037)

---
 app/javascript/{packs => entrypoints}/admin.tsx                 | 0
 app/javascript/{packs => entrypoints}/application.js            | 0
 app/javascript/{packs => entrypoints}/error.js                  | 0
 app/javascript/{packs => entrypoints}/inert.js                  | 0
 app/javascript/{packs => entrypoints}/mailer.js                 | 0
 app/javascript/{packs => entrypoints}/public-path.js            | 0
 app/javascript/{packs => entrypoints}/public.tsx                | 0
 .../{packs => entrypoints}/remote_interaction_helper.ts         | 0
 app/javascript/{packs => entrypoints}/share.jsx                 | 0
 app/javascript/{packs => entrypoints}/sign_up.js                | 0
 .../{packs => entrypoints}/two_factor_authentication.js         | 0
 config/webpacker.yml                                            | 2 +-
 tsconfig.json                                                   | 2 +-
 13 files changed, 2 insertions(+), 2 deletions(-)
 rename app/javascript/{packs => entrypoints}/admin.tsx (100%)
 rename app/javascript/{packs => entrypoints}/application.js (100%)
 rename app/javascript/{packs => entrypoints}/error.js (100%)
 rename app/javascript/{packs => entrypoints}/inert.js (100%)
 rename app/javascript/{packs => entrypoints}/mailer.js (100%)
 rename app/javascript/{packs => entrypoints}/public-path.js (100%)
 rename app/javascript/{packs => entrypoints}/public.tsx (100%)
 rename app/javascript/{packs => entrypoints}/remote_interaction_helper.ts (100%)
 rename app/javascript/{packs => entrypoints}/share.jsx (100%)
 rename app/javascript/{packs => entrypoints}/sign_up.js (100%)
 rename app/javascript/{packs => entrypoints}/two_factor_authentication.js (100%)

diff --git a/app/javascript/packs/admin.tsx b/app/javascript/entrypoints/admin.tsx
similarity index 100%
rename from app/javascript/packs/admin.tsx
rename to app/javascript/entrypoints/admin.tsx
diff --git a/app/javascript/packs/application.js b/app/javascript/entrypoints/application.js
similarity index 100%
rename from app/javascript/packs/application.js
rename to app/javascript/entrypoints/application.js
diff --git a/app/javascript/packs/error.js b/app/javascript/entrypoints/error.js
similarity index 100%
rename from app/javascript/packs/error.js
rename to app/javascript/entrypoints/error.js
diff --git a/app/javascript/packs/inert.js b/app/javascript/entrypoints/inert.js
similarity index 100%
rename from app/javascript/packs/inert.js
rename to app/javascript/entrypoints/inert.js
diff --git a/app/javascript/packs/mailer.js b/app/javascript/entrypoints/mailer.js
similarity index 100%
rename from app/javascript/packs/mailer.js
rename to app/javascript/entrypoints/mailer.js
diff --git a/app/javascript/packs/public-path.js b/app/javascript/entrypoints/public-path.js
similarity index 100%
rename from app/javascript/packs/public-path.js
rename to app/javascript/entrypoints/public-path.js
diff --git a/app/javascript/packs/public.tsx b/app/javascript/entrypoints/public.tsx
similarity index 100%
rename from app/javascript/packs/public.tsx
rename to app/javascript/entrypoints/public.tsx
diff --git a/app/javascript/packs/remote_interaction_helper.ts b/app/javascript/entrypoints/remote_interaction_helper.ts
similarity index 100%
rename from app/javascript/packs/remote_interaction_helper.ts
rename to app/javascript/entrypoints/remote_interaction_helper.ts
diff --git a/app/javascript/packs/share.jsx b/app/javascript/entrypoints/share.jsx
similarity index 100%
rename from app/javascript/packs/share.jsx
rename to app/javascript/entrypoints/share.jsx
diff --git a/app/javascript/packs/sign_up.js b/app/javascript/entrypoints/sign_up.js
similarity index 100%
rename from app/javascript/packs/sign_up.js
rename to app/javascript/entrypoints/sign_up.js
diff --git a/app/javascript/packs/two_factor_authentication.js b/app/javascript/entrypoints/two_factor_authentication.js
similarity index 100%
rename from app/javascript/packs/two_factor_authentication.js
rename to app/javascript/entrypoints/two_factor_authentication.js
diff --git a/config/webpacker.yml b/config/webpacker.yml
index f8462e53a..e07f577c5 100644
--- a/config/webpacker.yml
+++ b/config/webpacker.yml
@@ -2,7 +2,7 @@
 
 default: &default
   source_path: app/javascript
-  source_entry_path: packs
+  source_entry_path: entrypoints
   public_root_path: public
   public_output_path: packs
   cache_path: tmp/cache/webpacker
diff --git a/tsconfig.json b/tsconfig.json
index a193ea35f..7010dda1f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,7 +20,7 @@
   },
   "include": [
     "app/javascript/mastodon",
-    "app/javascript/packs",
+    "app/javascript/entrypoints",
     "app/javascript/types"
   ]
 }

From 0e585b9a52c499f76068cfd1cd85b1a6eedcc02e Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Wed, 24 Apr 2024 10:21:05 +0200
Subject: [PATCH 213/223] Update to Ruby 3.2.4 (#30036)

---
 .ruby-version |  2 +-
 Dockerfile    | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index b347b11ea..351227fca 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.2.3
+3.2.4
diff --git a/Dockerfile b/Dockerfile
index 43bc24295..a95d41a65 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,15 +7,15 @@
 ARG TARGETPLATFORM=${TARGETPLATFORM}
 ARG BUILDPLATFORM=${BUILDPLATFORM}
 
-# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.3"]
-ARG RUBY_VERSION="3.2.3"
+# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.4"]
+ARG RUBY_VERSION="3.2.4"
 # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
 ARG NODE_MAJOR_VERSION="20"
 # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
 ARG DEBIAN_VERSION="bookworm"
 # Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
 FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node
-# Ruby image to use for base image based on combined variables (ex: 3.2.3-slim-bookworm)
+# Ruby image to use for base image based on combined variables (ex: 3.2.4-slim-bookworm)
 FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby
 
 # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
@@ -29,7 +29,7 @@ ARG MASTODON_VERSION_METADATA=""
 # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
 ARG RAILS_SERVE_STATIC_FILES="true"
 # Allow to use YJIT compiler
-# See: https://github.com/ruby/ruby/blob/v3_2_3/doc/yjit/yjit.md
+# See: https://github.com/ruby/ruby/blob/v3_2_4/doc/yjit/yjit.md
 ARG RUBY_YJIT_ENABLE="1"
 # Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
 ARG TZ="Etc/UTC"
@@ -262,4 +262,4 @@ USER mastodon
 # Expose default Puma ports
 EXPOSE 3000
 # Set container tini as default entry point
-ENTRYPOINT ["/usr/bin/tini", "--"]
\ No newline at end of file
+ENTRYPOINT ["/usr/bin/tini", "--"]

From b903e6909e8d534330d19d5ecefcc1296a92ec36 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 24 Apr 2024 04:32:18 -0400
Subject: [PATCH 214/223] Disable `Style/HashAsLastArrayItem` cop (#30041)

---
 .rubocop.yml      |  5 +++++
 .rubocop_todo.yml | 13 -------------
 2 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/.rubocop.yml b/.rubocop.yml
index 1b5ce67ee..542e90b5e 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -182,6 +182,11 @@ Style/FormatStringToken:
   AllowedMethods:
     - redirect_with_vary
 
+# Reason: Prevailing style choice
+# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem
+Style/HashAsLastArrayItem:
+  Enabled: false
+
 # Reason: Enforce modern Ruby style
 # https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
 Style/HashSyntax:
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 3f2e9aee6..c2826d718 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -128,19 +128,6 @@ Style/GuardClause:
     - 'lib/mastodon/cli/media.rb'
     - 'lib/tasks/repo.rake'
 
-# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: braces, no_braces
-Style/HashAsLastArrayItem:
-  Exclude:
-    - 'app/controllers/admin/statuses_controller.rb'
-    - 'app/controllers/api/v1/statuses_controller.rb'
-    - 'app/models/concerns/account/counters.rb'
-    - 'app/models/concerns/status/threading_concern.rb'
-    - 'app/models/status.rb'
-    - 'app/services/batched_remove_status_service.rb'
-    - 'app/services/notify_service.rb'
-
 # This cop supports unsafe autocorrection (--autocorrect-all).
 Style/HashTransformValues:
   Exclude:

From 74012831f61a36b7f52540c5ccafa0f9692a6596 Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
Date: Wed, 24 Apr 2024 10:45:12 +0200
Subject: [PATCH 215/223] Change mute options to be in dropdown on muted users
 list in web UI (#30049)

---
 .../mastodon/components/account.jsx           | 274 +++++++++---------
 .../styles/mastodon/components.scss           |  14 +-
 2 files changed, 151 insertions(+), 137 deletions(-)

diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx
index 4a99dd0bb..3282696d3 100644
--- a/app/javascript/mastodon/components/account.jsx
+++ b/app/javascript/mastodon/components/account.jsx
@@ -1,17 +1,19 @@
 import PropTypes from 'prop-types';
+import { useCallback } from 'react';
 
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
 
 import classNames from 'classnames';
 import { Link } from 'react-router-dom';
 
 import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
 
+import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
 import { EmptyAccount } from 'mastodon/components/empty_account';
 import { ShortNumber } from 'mastodon/components/short_number';
 import { VerifiedBadge } from 'mastodon/components/verified_badge';
 
+import DropdownMenuContainer from '../containers/dropdown_menu_container';
 import { me } from '../initial_state';
 
 import { Avatar } from './avatar';
@@ -30,151 +32,151 @@ const messages = defineMessages({
   unmute_notifications: { id: 'account.unmute_notifications_short', defaultMessage: 'Unmute notifications' },
   mute: { id: 'account.mute_short', defaultMessage: 'Mute' },
   block: { id: 'account.block_short', defaultMessage: 'Block' },
+  more: { id: 'status.more', defaultMessage: 'More' },
 });
 
-class Account extends ImmutablePureComponent {
+const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifications, hidden, minimal, defaultAction, withBio }) => {
+  const intl = useIntl();
 
-  static propTypes = {
-    size: PropTypes.number,
-    account: ImmutablePropTypes.record,
-    onFollow: PropTypes.func,
-    onBlock: PropTypes.func,
-    onMute: PropTypes.func,
-    onMuteNotifications: PropTypes.func,
-    intl: PropTypes.object.isRequired,
-    hidden: PropTypes.bool,
-    minimal: PropTypes.bool,
-    defaultAction: PropTypes.string,
-    withBio: PropTypes.bool,
-  };
+  const handleFollow = useCallback(() => {
+    onFollow(account);
+  }, [onFollow, account]);
 
-  static defaultProps = {
-    size: 46,
-  };
+  const handleBlock = useCallback(() => {
+    onBlock(account);
+  }, [onBlock, account]);
 
-  handleFollow = () => {
-    this.props.onFollow(this.props.account);
-  };
+  const handleMute = useCallback(() => {
+    onMute(account);
+  }, [onMute, account]);
 
-  handleBlock = () => {
-    this.props.onBlock(this.props.account);
-  };
+  const handleMuteNotifications = useCallback(() => {
+    onMuteNotifications(account, true);
+  }, [onMuteNotifications, account]);
 
-  handleMute = () => {
-    this.props.onMute(this.props.account);
-  };
+  const handleUnmuteNotifications = useCallback(() => {
+    onMuteNotifications(account, false);
+  }, [onMuteNotifications, account]);
 
-  handleMuteNotifications = () => {
-    this.props.onMuteNotifications(this.props.account, true);
-  };
-
-  handleUnmuteNotifications = () => {
-    this.props.onMuteNotifications(this.props.account, false);
-  };
-
-  render () {
-    const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props;
-
-    if (!account) {
-      return <EmptyAccount size={size} minimal={minimal} />;
-    }
-
-    if (hidden) {
-      return (
-        <>
-          {account.get('display_name')}
-          {account.get('username')}
-        </>
-      );
-    }
-
-    let buttons;
-
-    if (account.get('id') !== me && account.get('relationship', null) !== null) {
-      const following = account.getIn(['relationship', 'following']);
-      const requested = account.getIn(['relationship', 'requested']);
-      const blocking  = account.getIn(['relationship', 'blocking']);
-      const muting  = account.getIn(['relationship', 'muting']);
-
-      if (requested) {
-        buttons = <Button text={intl.formatMessage(messages.cancel_follow_request)} onClick={this.handleFollow} />;
-      } else if (blocking) {
-        buttons = <Button text={intl.formatMessage(messages.unblock)} onClick={this.handleBlock} />;
-      } else if (muting) {
-        let hidingNotificationsButton;
-
-        if (account.getIn(['relationship', 'muting_notifications'])) {
-          hidingNotificationsButton = <Button text={intl.formatMessage(messages.unmute_notifications)} onClick={this.handleUnmuteNotifications} />;
-        } else {
-          hidingNotificationsButton = <Button text={intl.formatMessage(messages.mute_notifications)} onClick={this.handleMuteNotifications} />;
-        }
-
-        buttons = (
-          <>
-            <Button text={intl.formatMessage(messages.unmute)} onClick={this.handleMute} />
-            {hidingNotificationsButton}
-          </>
-        );
-      } else if (defaultAction === 'mute') {
-        buttons = <Button title={intl.formatMessage(messages.mute)} onClick={this.handleMute} />;
-      } else if (defaultAction === 'block') {
-        buttons = <Button text={intl.formatMessage(messages.block)} onClick={this.handleBlock} />;
-      } else if (!account.get('suspended') && !account.get('moved') || following) {
-        buttons = <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} />;
-      }
-    }
-
-    let muteTimeRemaining;
-
-    if (account.get('mute_expires_at')) {
-      muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
-    }
-
-    let verification;
-
-    const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
-
-    if (firstVerifiedField) {
-      verification = <VerifiedBadge link={firstVerifiedField.get('value')} />;
-    }
+  if (!account) {
+    return <EmptyAccount size={size} minimal={minimal} />;
+  }
 
+  if (hidden) {
     return (
-      <div className={classNames('account', { 'account--minimal': minimal })}>
-        <div className='account__wrapper'>
-          <Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
-            <div className='account__avatar-wrapper'>
-              <Avatar account={account} size={size} />
-            </div>
-
-            <div className='account__contents'>
-              <DisplayName account={account} />
-              {!minimal && (
-                <div className='account__details'>
-                  <ShortNumber value={account.get('followers_count')} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
-                </div>
-              )}
-            </div>
-          </Link>
-
-          {!minimal && (
-            <div className='account__relationship'>
-              {buttons}
-            </div>
-          )}
-        </div>
-
-        {withBio && (account.get('note').length > 0 ? (
-          <div
-            className='account__note translate'
-            dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
-          />
-        ) : (
-          <div className='account__note account__note--missing'><FormattedMessage id='account.no_bio' defaultMessage='No description provided.' /></div>
-        ))}
-      </div>
+      <>
+        {account.get('display_name')}
+        {account.get('username')}
+      </>
     );
   }
 
-}
+  let buttons;
 
-export default injectIntl(Account);
+  if (account.get('id') !== me && account.get('relationship', null) !== null) {
+    const following = account.getIn(['relationship', 'following']);
+    const requested = account.getIn(['relationship', 'requested']);
+    const blocking  = account.getIn(['relationship', 'blocking']);
+    const muting  = account.getIn(['relationship', 'muting']);
+
+    if (requested) {
+      buttons = <Button text={intl.formatMessage(messages.cancel_follow_request)} onClick={handleFollow} />;
+    } else if (blocking) {
+      buttons = <Button text={intl.formatMessage(messages.unblock)} onClick={handleBlock} />;
+    } else if (muting) {
+      let menu;
+
+      if (account.getIn(['relationship', 'muting_notifications'])) {
+        menu = [{ text: intl.formatMessage(messages.unmute_notifications), action: handleUnmuteNotifications }];
+      } else {
+        menu = [{ text: intl.formatMessage(messages.mute_notifications), action: handleMuteNotifications }];
+      }
+
+      buttons = (
+        <>
+          <DropdownMenuContainer
+            items={menu}
+            icon='ellipsis-h'
+            iconComponent={MoreHorizIcon}
+            direction='right'
+            title={intl.formatMessage(messages.more)}
+          />
+
+          <Button text={intl.formatMessage(messages.unmute)} onClick={handleMute} />
+        </>
+      );
+    } else if (defaultAction === 'mute') {
+      buttons = <Button title={intl.formatMessage(messages.mute)} onClick={handleMute} />;
+    } else if (defaultAction === 'block') {
+      buttons = <Button text={intl.formatMessage(messages.block)} onClick={handleBlock} />;
+    } else if (!account.get('suspended') && !account.get('moved') || following) {
+      buttons = <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={handleFollow} />;
+    }
+  }
+
+  let muteTimeRemaining;
+
+  if (account.get('mute_expires_at')) {
+    muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
+  }
+
+  let verification;
+
+  const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
+
+  if (firstVerifiedField) {
+    verification = <VerifiedBadge link={firstVerifiedField.get('value')} />;
+  }
+
+  return (
+    <div className={classNames('account', { 'account--minimal': minimal })}>
+      <div className='account__wrapper'>
+        <Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
+          <div className='account__avatar-wrapper'>
+            <Avatar account={account} size={size} />
+          </div>
+
+          <div className='account__contents'>
+            <DisplayName account={account} />
+            {!minimal && (
+              <div className='account__details'>
+                <ShortNumber value={account.get('followers_count')} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
+              </div>
+            )}
+          </div>
+        </Link>
+
+        {!minimal && (
+          <div className='account__relationship'>
+            {buttons}
+          </div>
+        )}
+      </div>
+
+      {withBio && (account.get('note').length > 0 ? (
+        <div
+          className='account__note translate'
+          dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
+        />
+      ) : (
+        <div className='account__note account__note--missing'><FormattedMessage id='account.no_bio' defaultMessage='No description provided.' /></div>
+      ))}
+    </div>
+  );
+};
+
+Account.propTypes = {
+  size: PropTypes.number,
+  account: ImmutablePropTypes.record,
+  onFollow: PropTypes.func,
+  onBlock: PropTypes.func,
+  onMute: PropTypes.func,
+  onMuteNotifications: PropTypes.func,
+  intl: PropTypes.object.isRequired,
+  hidden: PropTypes.bool,
+  minimal: PropTypes.bool,
+  defaultAction: PropTypes.string,
+  withBio: PropTypes.bool,
+};
+
+export default Account;
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 87e13ee45..b2139169a 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2015,7 +2015,19 @@ a .account__avatar {
   white-space: nowrap;
   display: flex;
   align-items: center;
-  gap: 4px;
+  gap: 8px;
+
+  .icon-button {
+    border: 1px solid var(--background-border-color);
+    border-radius: 4px;
+    box-sizing: content-box;
+    padding: 5px;
+
+    .icon {
+      width: 24px;
+      height: 24px;
+    }
+  }
 }
 
 .account-authorize {

From ebcf9840f4720056ff12055741351b36eb84961a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 24 Apr 2024 10:45:24 +0200
Subject: [PATCH 216/223] New Crowdin Translations (automated) (#30050)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/bg.json    |  1 +
 app/javascript/mastodon/locales/id.json    | 39 ++++++++++++++
 app/javascript/mastodon/locales/zh-HK.json |  1 +
 config/locales/devise.eo.yml               |  3 +-
 config/locales/doorkeeper.bg.yml           |  1 +
 config/locales/doorkeeper.ca.yml           |  1 +
 config/locales/doorkeeper.da.yml           |  1 +
 config/locales/doorkeeper.de.yml           |  1 +
 config/locales/doorkeeper.es-AR.yml        |  1 +
 config/locales/doorkeeper.eu.yml           |  1 +
 config/locales/doorkeeper.fi.yml           |  1 +
 config/locales/doorkeeper.fo.yml           |  1 +
 config/locales/doorkeeper.gl.yml           |  1 +
 config/locales/doorkeeper.he.yml           |  1 +
 config/locales/doorkeeper.hu.yml           |  1 +
 config/locales/doorkeeper.ia.yml           |  1 +
 config/locales/doorkeeper.is.yml           |  1 +
 config/locales/doorkeeper.it.yml           |  1 +
 config/locales/doorkeeper.ko.yml           |  1 +
 config/locales/doorkeeper.nl.yml           |  1 +
 config/locales/doorkeeper.nn.yml           |  1 +
 config/locales/doorkeeper.pl.yml           |  1 +
 config/locales/doorkeeper.sl.yml           |  1 +
 config/locales/doorkeeper.tr.yml           |  1 +
 config/locales/doorkeeper.uk.yml           |  1 +
 config/locales/doorkeeper.vi.yml           |  1 +
 config/locales/doorkeeper.zh-CN.yml        |  1 +
 config/locales/doorkeeper.zh-HK.yml        |  1 +
 config/locales/doorkeeper.zh-TW.yml        |  1 +
 config/locales/eo.yml                      | 63 +++++++++++-----------
 config/locales/ia.yml                      | 52 ++++++++++++++++++
 config/locales/pt-BR.yml                   |  2 +
 config/locales/simple_form.ia.yml          |  2 +
 33 files changed, 157 insertions(+), 31 deletions(-)

diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 910d6cb06..dabefd1f4 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Изберете съществуваща категория или създайте нова",
   "filter_modal.select_filter.title": "Филтриране на публ.",
   "filter_modal.title.status": "Филтриране на публ.",
+  "filtered_notifications_banner.mentions": "{count, plural, one {споменаване} other {споменавания}}",
   "filtered_notifications_banner.pending_requests": "Известията от {count, plural, =0 {никого, когото може да познавате} one {едно лице, което може да познавате} other {# души, които може да познавате}}",
   "filtered_notifications_banner.title": "Филтрирани известия",
   "firehose.all": "Всичко",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 90a48b634..33161f888 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -123,6 +123,7 @@
   "column.directory": "Jelajahi profil",
   "column.domain_blocks": "Domain tersembunyi",
   "column.favourites": "Favorit",
+  "column.firehose": "Feed yang sedang berlangsung",
   "column.follow_requests": "Permintaan mengikuti",
   "column.home": "Beranda",
   "column.lists": "List",
@@ -143,7 +144,9 @@
   "community.column_settings.remote_only": "Hanya jarak jauh",
   "compose.language.change": "Ganti bahasa",
   "compose.language.search": "Telusuri bahasa...",
+  "compose.published.body": "Postingan diterbitkan.",
   "compose.published.open": "Buka",
+  "compose.saved.body": "Postingan tersimpan.",
   "compose_form.direct_message_warning_learn_more": "Pelajari lebih lanjut",
   "compose_form.encryption_warning": "Kiriman di Mastodon tidak dienkripsi secara end-to-end. Jangan bagikan informasi sensitif melalui Mastodon.",
   "compose_form.hashtag_warning": "Kiriman ini tidak akan didaftarkan di bawah tagar apapun selama tidak diatur ke publik. Hanya kiriman publik yang dapat dicari dengan tagar.",
@@ -151,11 +154,19 @@
   "compose_form.lock_disclaimer.lock": "terkunci",
   "compose_form.placeholder": "Apa yang ada di pikiran Anda?",
   "compose_form.poll.duration": "Durasi japat",
+  "compose_form.poll.multiple": "Pilihan ganda",
+  "compose_form.poll.option_placeholder": "Opsi {number}",
+  "compose_form.poll.single": "Pilih Satu",
   "compose_form.poll.switch_to_multiple": "Ubah japat menjadi pilihan ganda",
   "compose_form.poll.switch_to_single": "Ubah japat menjadi pilihan tunggal",
+  "compose_form.poll.type": "Gaya",
+  "compose_form.publish": "Postingan",
   "compose_form.publish_form": "Terbitkan",
+  "compose_form.reply": "Balas",
+  "compose_form.save_changes": "Perbarui",
   "compose_form.spoiler.marked": "Hapus peringatan tentang isi konten",
   "compose_form.spoiler.unmarked": "Tambahkan peringatan tentang isi konten",
+  "compose_form.spoiler_placeholder": "Peringatan konten (opsional)",
   "confirmation_modal.cancel": "Batal",
   "confirmations.block.confirm": "Blokir",
   "confirmations.cancel_follow_request.confirm": "Batalkan permintaan",
@@ -166,12 +177,15 @@
   "confirmations.delete_list.message": "Apakah Anda yakin untuk menghapus daftar ini secara permanen?",
   "confirmations.discard_edit_media.confirm": "Buang",
   "confirmations.discard_edit_media.message": "Anda belum menyimpan perubahan deskripsi atau pratinjau media, buang saja?",
+  "confirmations.domain_block.confirm": "Blokir server",
   "confirmations.domain_block.message": "Apakah Anda benar-benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.",
   "confirmations.edit.confirm": "Ubah",
+  "confirmations.edit.message": "Mengubah akan menimpa pesan yang sedang anda tulis. Apakah anda yakin ingin melanjutkan?",
   "confirmations.logout.confirm": "Keluar",
   "confirmations.logout.message": "Apakah Anda yakin ingin keluar?",
   "confirmations.mute.confirm": "Bisukan",
   "confirmations.redraft.confirm": "Hapus dan susun ulang",
+  "confirmations.redraft.message": "Apakah anda yakin ingin menghapus postingan ini dan menyusun ulang postingan ini? Favorit dan peningkatan akan hilang, dan balasan ke postingan asli tidak akan terhubung ke postingan manapun.",
   "confirmations.reply.confirm": "Balas",
   "confirmations.reply.message": "Membalas sekarang akan menimpa pesan yang sedang Anda buat. Anda yakin ingin melanjutkan?",
   "confirmations.unfollow.confirm": "Berhenti mengikuti",
@@ -180,6 +194,7 @@
   "conversation.mark_as_read": "Tandai sudah dibaca",
   "conversation.open": "Lihat percakapan",
   "conversation.with": "Dengan {names}",
+  "copy_icon_button.copied": "Disalin ke clipboard",
   "copypaste.copied": "Disalin",
   "copypaste.copy_to_clipboard": "Salin ke clipboard",
   "directory.federated": "Dari fediverse yang dikenal",
@@ -191,7 +206,27 @@
   "dismissable_banner.community_timeline": "Ini adalah kiriman publik terkini dari orang yang akunnya berada di {domain}.",
   "dismissable_banner.dismiss": "Abaikan",
   "dismissable_banner.explore_links": "Cerita berita ini sekarang sedang dibicarakan oleh orang di server ini dan lainnya dalam jaringan terdesentralisasi.",
+  "dismissable_banner.explore_statuses": "Ini adalah postingan dari seluruh web sosial yang mendapatkan daya tarik saat ini. Postingan baru dengan lebih banyak peningkatan dan favorit memiliki peringkat lebih tinggi.",
   "dismissable_banner.explore_tags": "Tagar ini sekarang sedang tren di antara orang di server ini dan lainnya dalam jaringan terdesentralisasi.",
+  "dismissable_banner.public_timeline": "Ini adalah postingan publik dari orang-orang di web sosial yang diikuti oleh {domain}.",
+  "domain_block_modal.block": "Blokir server",
+  "domain_block_modal.block_account_instead": "Blokir @{name} saja",
+  "domain_block_modal.they_can_interact_with_old_posts": "Orang-orang dari server ini dapat berinteraksi dengan kiriman lama anda.",
+  "domain_block_modal.they_cant_follow": "Tidak ada seorangpun dari server ini yang dapat mengikuti anda.",
+  "domain_block_modal.they_wont_know": "Mereka tidak akan tahu bahwa mereka diblokir.",
+  "domain_block_modal.title": "Blokir domain?",
+  "domain_block_modal.you_will_lose_followers": "Semua pengikut anda dari server ini akan dihapus.",
+  "domain_block_modal.you_wont_see_posts": "Anda tidak akan melihat postingan atau notifikasi dari pengguna di server ini.",
+  "domain_pill.activitypub_lets_connect": "Ini memungkinkan anda terhubung dan berinteraksi dengan orang-orang tidak hanya di Mastodon, tetapi juga di berbagai aplikasi sosial.",
+  "domain_pill.activitypub_like_language": "ActivityPub seperti bahasa yang digunakan Mastodon dengan jejaring sosial lainnya.",
+  "domain_pill.server": "Server",
+  "domain_pill.their_handle": "Nama penggunanya:",
+  "domain_pill.their_server": "Rumah digital mereka, di mana semua postingan mereka tersedia.",
+  "domain_pill.their_username": "Pengenal unik mereka di server tersebut. Itu memungkinkan dapat mencari pengguna dengan nama yang sama di server lain.",
+  "domain_pill.username": "Nama pengguna",
+  "domain_pill.whats_in_a_handle": "Apa itu nama pengguna?",
+  "domain_pill.who_they_are": "Karena nama pengguna menunjukkan siapa seseorang dan di mana server mereka berada, anda dapat berinteraksi dengan orang-orang di seluruh web sosial  <button>ActivityPub-powered platforms</button>.",
+  "domain_pill.your_handle": "Nama pengguna anda:",
   "embed.instructions": "Sematkan kiriman ini di situs web Anda dengan menyalin kode di bawah ini.",
   "embed.preview": "Tampilan akan seperti ini nantinya:",
   "emoji_button.activity": "Aktivitas",
@@ -260,6 +295,10 @@
   "follow_request.authorize": "Izinkan",
   "follow_request.reject": "Tolak",
   "follow_requests.unlocked_explanation": "Meskipun akun Anda tidak dikunci, staf {domain} menyarankan Anda untuk meninjau permintaan mengikuti dari akun-akun ini secara manual.",
+  "follow_suggestions.curated_suggestion": "Pilihan staf",
+  "follow_suggestions.dismiss": "Jangan tampilkan lagi",
+  "follow_suggestions.hints.featured": "Profil ini telah dipilih sendiri oleh tim {domain}.",
+  "follow_suggestions.hints.friends_of_friends": "Profil ini populer di kalangan orang yang anda ikuti.",
   "followed_tags": "Tagar yang diikuti",
   "footer.about": "Tentang",
   "footer.directory": "Direktori profil",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 0b328c738..3ca9a8d11 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "使用既有類別,或創建一個新類別",
   "filter_modal.select_filter.title": "過濾此帖文",
   "filter_modal.title.status": "過濾一則帖文",
+  "filtered_notifications_banner.mentions": "{count, plural, one {則提及} other {則提及}}",
   "filtered_notifications_banner.pending_requests": "來自 {count, plural, =0 {0 位} other {# 位}}你可能認識的人的通知",
   "filtered_notifications_banner.title": "已過濾之通知",
   "firehose.all": "全部",
diff --git a/config/locales/devise.eo.yml b/config/locales/devise.eo.yml
index af1769aa6..193fecc75 100644
--- a/config/locales/devise.eo.yml
+++ b/config/locales/devise.eo.yml
@@ -12,6 +12,7 @@ eo:
       last_attempt: Vi ankoraŭ povas provi unufoje antaŭ ol via konto estos ŝlosita.
       locked: Via konto estas ŝlosita.
       not_found_in_database: Nevalida %{authentication_keys} aŭ pasvorto.
+      omniauth_user_creation_failure: Eraro okazis kreinte konton por ĉi tiu identeco.
       pending: Via konto ankoraŭ estas kontrolata.
       timeout: Via seanco eksvalidiĝis. Bonvolu ensaluti denove por daŭrigi.
       unauthenticated: Vi devas ensaluti aŭ registriĝi antaŭ ol daŭrigi.
@@ -39,7 +40,7 @@ eo:
         explanation: Retajpu la novan adreson por ŝanĝi vian retpoŝtadreson.
         extra: Se ĉi tiu ŝanĝo ne estis komencita de vi, bonvolu ignori ĉi tiun retmesaĝon. La retadreso por la Mastodon-konto ne ŝanĝiĝos se vi ne aliras la supran ligilon.
         subject: 'Mastodon: Konfirmi retpoŝton por %{instance}'
-        title: Kontrolu retpoŝtadreson
+        title: Kontroli retpoŝtadreson
       reset_password_instructions:
         action: Ŝanĝi pasvorton
         explanation: Vi petis novan pasvorton por via konto.
diff --git a/config/locales/doorkeeper.bg.yml b/config/locales/doorkeeper.bg.yml
index 8e026794e..7633156d7 100644
--- a/config/locales/doorkeeper.bg.yml
+++ b/config/locales/doorkeeper.bg.yml
@@ -174,6 +174,7 @@ bg:
       read:filters: преглед на вашите филтри
       read:follows: преглед на вашите последвания
       read:lists: преглед на вашите списъци
+      read:me: четене само на основните сведения за акаунта ви
       read:mutes: преглед на вашите заглушавания
       read:notifications: преглед на вашите известия
       read:reports: преглед на вашите докладвания
diff --git a/config/locales/doorkeeper.ca.yml b/config/locales/doorkeeper.ca.yml
index 9706f3db7..80827a87d 100644
--- a/config/locales/doorkeeper.ca.yml
+++ b/config/locales/doorkeeper.ca.yml
@@ -174,6 +174,7 @@ ca:
       read:filters: mira els teus filtres
       read:follows: mira els teus seguiments
       read:lists: mira les teves llistes
+      read:me: llegir només la informació bàsica del vostre compte
       read:mutes: mira els teus silenciats
       read:notifications: mira les teves notificacions
       read:reports: mira els teus informes
diff --git a/config/locales/doorkeeper.da.yml b/config/locales/doorkeeper.da.yml
index 2c8b0d13e..ed10e14e2 100644
--- a/config/locales/doorkeeper.da.yml
+++ b/config/locales/doorkeeper.da.yml
@@ -174,6 +174,7 @@ da:
       read:filters: se dine filtre
       read:follows: se dine følger
       read:lists: se dine lister
+      read:me: læs kun kontoens basisoplysninger
       read:mutes: se dine tavsgørelser
       read:notifications: se dine notifikationer
       read:reports: se dine anmeldelser
diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml
index 552dfeba3..80d612255 100644
--- a/config/locales/doorkeeper.de.yml
+++ b/config/locales/doorkeeper.de.yml
@@ -174,6 +174,7 @@ de:
       read:filters: deine Filter einsehen
       read:follows: sehen, wem du folgst
       read:lists: deine Listen sehen
+      read:me: nur deine grundlegenden Kontoinformationen lesen
       read:mutes: deine Stummschaltungen einsehen
       read:notifications: deine Benachrichtigungen sehen
       read:reports: deine Meldungen sehen
diff --git a/config/locales/doorkeeper.es-AR.yml b/config/locales/doorkeeper.es-AR.yml
index 532db1f30..47cfc451a 100644
--- a/config/locales/doorkeeper.es-AR.yml
+++ b/config/locales/doorkeeper.es-AR.yml
@@ -174,6 +174,7 @@ es-AR:
       read:filters: ver tus filtros
       read:follows: ver qué cuentas seguís
       read:lists: ver tus listas
+      read:me: leer solo la información básica de tu cuenta
       read:mutes: ver qué cuentas silenciaste
       read:notifications: ver tus notificaciones
       read:reports: ver tus denuncias
diff --git a/config/locales/doorkeeper.eu.yml b/config/locales/doorkeeper.eu.yml
index e7963672f..88a63f698 100644
--- a/config/locales/doorkeeper.eu.yml
+++ b/config/locales/doorkeeper.eu.yml
@@ -174,6 +174,7 @@ eu:
       read:filters: ikusi zure iragazkiak
       read:follows: ikusi zuk jarraitutakoak
       read:lists: ikusi zure zerrendak
+      read:me: irakurri soilik zure kontuaren oinarrizko informazioa
       read:mutes: ikusi zuk mutututakoak
       read:notifications: ikusi zure jakinarazpenak
       read:reports: ikusi zure salaketak
diff --git a/config/locales/doorkeeper.fi.yml b/config/locales/doorkeeper.fi.yml
index fea01d107..ae8963c76 100644
--- a/config/locales/doorkeeper.fi.yml
+++ b/config/locales/doorkeeper.fi.yml
@@ -174,6 +174,7 @@ fi:
       read:filters: katso suodattimiasi
       read:follows: katso seurattujasi
       read:lists: katso listojasi
+      read:me: lue tilisi perustietoja
       read:mutes: katso mykistyksiäsi
       read:notifications: katso ilmoituksiasi
       read:reports: katso raporttejasi
diff --git a/config/locales/doorkeeper.fo.yml b/config/locales/doorkeeper.fo.yml
index 78f8701ae..4f5cc5a64 100644
--- a/config/locales/doorkeeper.fo.yml
+++ b/config/locales/doorkeeper.fo.yml
@@ -174,6 +174,7 @@ fo:
       read:filters: síggja tíni filtur
       read:follows: síggja hvørji tú fylgir
       read:lists: síggja tínar listar
+      read:me: les bara grundleggjandi upplýsingar av tínari kontu
       read:mutes: síggja tínar doyvingar
       read:notifications: síggja tínar fráboðanir
       read:reports: síggja tínar meldingar
diff --git a/config/locales/doorkeeper.gl.yml b/config/locales/doorkeeper.gl.yml
index aa0eae284..d34c58dec 100644
--- a/config/locales/doorkeeper.gl.yml
+++ b/config/locales/doorkeeper.gl.yml
@@ -174,6 +174,7 @@ gl:
       read:filters: ver os filtros
       read:follows: ver a quen segues
       read:lists: ver as tuas listaxes
+      read:me: ler só a información básica da túa conta
       read:mutes: ver a quen tes acalado
       read:notifications: ver as notificacións
       read:reports: ver as túas denuncias
diff --git a/config/locales/doorkeeper.he.yml b/config/locales/doorkeeper.he.yml
index 9030e45e0..a6376fa4c 100644
--- a/config/locales/doorkeeper.he.yml
+++ b/config/locales/doorkeeper.he.yml
@@ -174,6 +174,7 @@ he:
       read:filters: צפייה במסננים
       read:follows: צפייה בנעקבים
       read:lists: צפיה ברשימותיך
+      read:me: לקריאה בלבד של פרטי חשבונך הבסיסיים
       read:mutes: צפיה במושתקיך
       read:notifications: צפיה בהתראותיך
       read:reports: צפיה בדוחותיך
diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml
index 3822e9c20..28ce283ff 100644
--- a/config/locales/doorkeeper.hu.yml
+++ b/config/locales/doorkeeper.hu.yml
@@ -174,6 +174,7 @@ hu:
       read:filters: szűrök megtekintése
       read:follows: követések megtekintése
       read:lists: listák megtekintése
+      read:me: csak a fiókod alapvető adatainak elolvasása
       read:mutes: némítások megtekintése
       read:notifications: értesítések megtekintése
       read:reports: bejelentések megtekintése
diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml
index b41531a1b..fd7d7a083 100644
--- a/config/locales/doorkeeper.ia.yml
+++ b/config/locales/doorkeeper.ia.yml
@@ -87,6 +87,7 @@ ia:
       read:filters: vider tu filtros
       read:follows: vider tu sequites
       read:lists: vider tu listas
+      read:me: leger solmente le information basic de tu conto
       read:notifications: vider tu notificationes
       read:reports: vider tu reportos
       read:statuses: vider tote le messages
diff --git a/config/locales/doorkeeper.is.yml b/config/locales/doorkeeper.is.yml
index c1e2d4cfc..995d507f5 100644
--- a/config/locales/doorkeeper.is.yml
+++ b/config/locales/doorkeeper.is.yml
@@ -174,6 +174,7 @@ is:
       read:filters: skoða síurnar þínar
       read:follows: sjá hverjum þú fylgist með
       read:lists: skoða listana þína
+      read:me: lesa einungis grunnupplýsingar aðgangsins þíns
       read:mutes: skoða hverja þú þaggar
       read:notifications: sjá tilkynningarnar þínar
       read:reports: skoða skýrslurnar þína
diff --git a/config/locales/doorkeeper.it.yml b/config/locales/doorkeeper.it.yml
index 3fd998fc4..f39f78466 100644
--- a/config/locales/doorkeeper.it.yml
+++ b/config/locales/doorkeeper.it.yml
@@ -174,6 +174,7 @@ it:
       read:filters: visualizzare i tuoi filtri
       read:follows: visualizzare i tuoi seguiti
       read:lists: visualizzare i tuoi elenchi
+      read:me: leggi solo le informazioni di base del tuo account
       read:mutes: visualizzare i tuoi silenziamenti
       read:notifications: visualizzare le tue notifiche
       read:reports: visualizzare le tue segnalazioni
diff --git a/config/locales/doorkeeper.ko.yml b/config/locales/doorkeeper.ko.yml
index 4721e3acd..12674cc12 100644
--- a/config/locales/doorkeeper.ko.yml
+++ b/config/locales/doorkeeper.ko.yml
@@ -174,6 +174,7 @@ ko:
       read:filters: 필터 보기
       read:follows: 팔로우 보기
       read:lists: 리스트 보기
+      read:me: 내 계정의 기본 정보만을 읽습니다
       read:mutes: 뮤트 보기
       read:notifications: 알림 보기
       read:reports: 신고 보기
diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml
index b3e6e79a1..9554c0ee6 100644
--- a/config/locales/doorkeeper.nl.yml
+++ b/config/locales/doorkeeper.nl.yml
@@ -174,6 +174,7 @@ nl:
       read:filters: jouw filters bekijken
       read:follows: de accounts die jij volgt bekijken
       read:lists: jouw lijsten bekijken
+      read:me: alleen de basisgegevens van jouw account lezen
       read:mutes: jouw genegeerde gebruikers bekijken
       read:notifications: jouw meldingen bekijken
       read:reports: jouw gerapporteerde berichten bekijken
diff --git a/config/locales/doorkeeper.nn.yml b/config/locales/doorkeeper.nn.yml
index 0e5d1ca45..ab0380c6f 100644
--- a/config/locales/doorkeeper.nn.yml
+++ b/config/locales/doorkeeper.nn.yml
@@ -174,6 +174,7 @@ nn:
       read:filters: sjå filtera dine
       read:follows: sjå fylgjarane dine
       read:lists: sjå listene dine
+      read:me: les berre kontoen din sin grunnleggjande informasjon
       read:mutes: sjå kven du har målbunde
       read:notifications: sjå varsla dine
       read:reports: sjå rapportane dine
diff --git a/config/locales/doorkeeper.pl.yml b/config/locales/doorkeeper.pl.yml
index 226c0d403..eefca2de6 100644
--- a/config/locales/doorkeeper.pl.yml
+++ b/config/locales/doorkeeper.pl.yml
@@ -174,6 +174,7 @@ pl:
       read:filters: dostęp do filtrów
       read:follows: dostęp do listy obserwowanych
       read:lists: dostęp do Twoich list
+      read:me: odczytaj tylko podstawowe informacje o koncie
       read:mutes: dostęp do listy wyciszonych
       read:notifications: możliwość odczytu powiadomień
       read:reports: dostęp do Twoich zgłoszeń
diff --git a/config/locales/doorkeeper.sl.yml b/config/locales/doorkeeper.sl.yml
index a613308b2..55e00ff96 100644
--- a/config/locales/doorkeeper.sl.yml
+++ b/config/locales/doorkeeper.sl.yml
@@ -174,6 +174,7 @@ sl:
       read:filters: oglejte si svoje filtre
       read:follows: oglejte si svoje sledilce
       read:lists: oglejte si svoje sezname
+      read:me: preberi le osnovne podatke računa
       read:mutes: oglejte si svoje utišane
       read:notifications: oglejte si svoja obvestila
       read:reports: oglejte si svoje prijave
diff --git a/config/locales/doorkeeper.tr.yml b/config/locales/doorkeeper.tr.yml
index 47a15e1b8..f5ebbc5fd 100644
--- a/config/locales/doorkeeper.tr.yml
+++ b/config/locales/doorkeeper.tr.yml
@@ -174,6 +174,7 @@ tr:
       read:filters: süzgeçlerinizi görün
       read:follows: takip ettiklerinizi görün
       read:lists: listelerinizi görün
+      read:me: hesabınızın sadece temel bilgilerini okuma
       read:mutes: sessize aldıklarınızı görün
       read:notifications: bildirimlerinizi görün
       read:reports: raporlarınızı görün
diff --git a/config/locales/doorkeeper.uk.yml b/config/locales/doorkeeper.uk.yml
index 8af404a73..ac7fbbe15 100644
--- a/config/locales/doorkeeper.uk.yml
+++ b/config/locales/doorkeeper.uk.yml
@@ -180,6 +180,7 @@ uk:
       read:filters: бачити Ваші фільтри
       read:follows: бачити Ваші підписки
       read:lists: бачити Ваші списки
+      read:me: читайте лише основну інформацію вашого облікового запису
       read:mutes: бачити ваші нехтування
       read:notifications: бачити Ваші сповіщення
       read:reports: бачити Ваші скарги
diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml
index 837579527..84684d24c 100644
--- a/config/locales/doorkeeper.vi.yml
+++ b/config/locales/doorkeeper.vi.yml
@@ -174,6 +174,7 @@ vi:
       read:filters: xem bộ lọc
       read:follows: xem những người theo dõi
       read:lists: xem danh sách
+      read:me: chỉ đọc thông tin cơ bản tài khoản
       read:mutes: xem những người đã ẩn
       read:notifications: xem thông báo
       read:reports: xem báo cáo của bạn
diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml
index 36c7fb812..73f1f9725 100644
--- a/config/locales/doorkeeper.zh-CN.yml
+++ b/config/locales/doorkeeper.zh-CN.yml
@@ -174,6 +174,7 @@ zh-CN:
       read:filters: 查看你的过滤器
       read:follows: 查看你的关注
       read:lists: 查看你的列表
+      read:me: 只读取你账户的基本信息
       read:mutes: 查看你的隐藏列表
       read:notifications: 查看你的通知
       read:reports: 查看你的举报
diff --git a/config/locales/doorkeeper.zh-HK.yml b/config/locales/doorkeeper.zh-HK.yml
index 79629b12f..76d13a74a 100644
--- a/config/locales/doorkeeper.zh-HK.yml
+++ b/config/locales/doorkeeper.zh-HK.yml
@@ -174,6 +174,7 @@ zh-HK:
       read:filters: 檢視你的過濾條件
       read:follows: 檢視你關注的人
       read:lists: 檢視你的清單
+      read:me: 僅讀取帳號的基本資訊
       read:mutes: 檢視被你靜音的人
       read:notifications: 檢視你的通知
       read:reports: 檢視你的檢舉
diff --git a/config/locales/doorkeeper.zh-TW.yml b/config/locales/doorkeeper.zh-TW.yml
index f2250b79c..86827a712 100644
--- a/config/locales/doorkeeper.zh-TW.yml
+++ b/config/locales/doorkeeper.zh-TW.yml
@@ -174,6 +174,7 @@ zh-TW:
       read:filters: 檢視您的過濾條件
       read:follows: 檢視您跟隨之使用者
       read:lists: 檢視您的列表
+      read:me: 僅讀取您的帳號基本資訊
       read:mutes: 檢視您靜音的人
       read:notifications: 檢視您的通知
       read:reports: 檢視您的檢舉
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index d59eadd52..749f80687 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -74,7 +74,7 @@ eo:
       follows: Sekvatoj
       header: Kapa bildo
       inbox_url: Enira URL
-      invite_request_text: 가입하려는 이유
+      invite_request_text: Kialoj por aliĝi
       invited_by: Invitita de
       ip: IP
       joined: Aliĝis
@@ -104,7 +104,7 @@ eo:
       no_role_assigned: Sen rolo
       not_subscribed: Ne abonita
       pending: Pritraktata recenzo
-      perform_full_suspension: Suspendi
+      perform_full_suspension: Haltigi
       previous_strikes: Antaǔaj admonoj
       previous_strikes_description_html:
         one: Ĉi tiu konto havas <strong>unu</strong> admonon.
@@ -121,7 +121,7 @@ eo:
       remote_suspension_reversible_hint_html: La konto estas suspendita, kaj la datumoj estos komplete forigitaj je %{date}. Ĝis tiam, la konto povas esti malsuspendita sen flankefiko. Se vi deziras tuj forigi ĉiujn datumojn de la konto, vi povas fari tion sube.
       remove_avatar: Forigi la profilbildon
       remove_header: Forigi kapan bildon
-      removed_avatar_msg: La rolfiguro de %{username} estas sukcese forigita
+      removed_avatar_msg: La profilbildo de %{username} estas sukcese forigita
       removed_header_msg: Kapbildo de %{username} suksece forigita
       resend_confirmation:
         already_confirmed: Ĉi tiu uzanto jam estas konfirmita
@@ -184,7 +184,7 @@ eo:
         create_domain_block: Krei Blokadon De Domajno
         create_email_domain_block: Krei Blokadon De Retpoŝta Domajno
         create_ip_block: Krei IP-regulon
-        create_unavailable_domain: Krei nehaveblan domajnon
+        create_unavailable_domain: Krei Nehaveblan Domajnon
         create_user_role: Krei Rolon
         demote_user: Malpromocii Uzanton
         destroy_announcement: Forigi Anoncon
@@ -193,9 +193,9 @@ eo:
         destroy_domain_allow: Forigi Domajnan Permeson
         destroy_domain_block: Forigi blokadon de domajno
         destroy_email_domain_block: Forigi blokadon de retpoŝta domajno
-        destroy_instance: Forigi domajnon
+        destroy_instance: Forigi Domajnon
         destroy_ip_block: Forigi IP-regulon
-        destroy_status: Forigi mesaĝon
+        destroy_status: Forigi Afiŝon
         destroy_unavailable_domain: Forigi Nehaveblan Domajnon
         destroy_user_role: Detrui Rolon
         disable_2fa_user: Malebligi 2FA
@@ -285,7 +285,7 @@ eo:
         update_custom_emoji_html: "%{name} ĝisdatigis la emoĝion %{target}"
         update_domain_block_html: "%{name} ĝisdatigis domajnblokon por %{target}"
         update_ip_block_html: "%{name} ŝanĝis regulon por IP %{target}"
-        update_status_html: "%{name} ĝisdatigis mesaĝon de %{target}"
+        update_status_html: "%{name} ĝisdatigis afiŝon de %{target}"
         update_user_role_html: "%{name} ŝanĝis la rolon %{target}"
       deleted_account: forigita konto
       empty: Neniu ĵurnalo trovita.
@@ -567,7 +567,7 @@ eo:
       disable: Malebligi
       disabled: Malebligita
       enable: Ebligi
-      enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn mesaĝojn de la servilo al ĝi.
+      enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn afiŝojn de la servilo al ĝi.
       enabled: Ebligita
       inbox_url: URL de la ripetilo
       pending: Atendante aprobon de la ripetilo
@@ -587,7 +587,7 @@ eo:
       action_log: Ĵurnalo de revizo
       action_taken_by: Ago farita de
       actions:
-        delete_description_html: Raportitaj mesaĝoj forigotas kaj admono rekorditas.
+        delete_description_html: Raportitaj afiŝoj estos forigita kaj admono estos rekordita por helpi vin indiki estontajn afiŝojn de la sama konto kontraŭ reguloj.
         mark_as_sensitive_description_html: La audovidaĵo en la raportita mesaĝo markotas kiel sentema kaj admono rekorditas.
         other_description_html: Vidu pli da ebloj por regi la sintenon de la konto kaj por personigi la komunikadon kun la raportita konto.
         resolve_description_html: Nenio okazotas al la raportita konto kaj la raporto fermotas.
@@ -634,7 +634,7 @@ eo:
       resolved: Solvitaj
       resolved_msg: Signalo sukcese solvita!
       skip_to_actions: Salti al agoj
-      status: Mesaĝoj
+      status: Afiŝo
       statuses: Raportita enhavo
       statuses_description_html: Sentema enhavo referencitas kun la raportita konto
       summary:
@@ -787,6 +787,7 @@ eo:
       types:
         major: Ĉefa eldono
         minor: Neĉefa eldono
+      version: Versio
     statuses:
       account: Skribanto
       application: Aplikaĵo
@@ -803,12 +804,12 @@ eo:
       media:
         title: Aŭdovidaĵoj
       metadata: Metadatumoj
-      no_status_selected: Neniu mesaĝo estis ŝanĝita ĉar neniu estis elektita
+      no_status_selected: Neniu afiŝo estis ŝanĝita ĉar neniu estis elektita
       open: Malfermi afiŝojn
       original_status: Originala afiŝo
       reblogs: Reblogaĵoj
       status_changed: Afiŝo ŝanĝiĝis
-      title: Mesaĝoj de la konto
+      title: Afiŝoj de la konto
       trending: Popularaĵoj
       visibility: Videbleco
       with_media: Kun aŭdovidaĵoj
@@ -816,7 +817,7 @@ eo:
       actions:
         delete_statuses: "%{name} forigis afiŝojn de %{target}"
         disable: "%{name} frostigis la konton de %{target}"
-        mark_statuses_as_sensitive: "%{name} markis mesaĝojn de %{target} kiel sentemaj"
+        mark_statuses_as_sensitive: "%{name} markis afiŝojn de %{target} kiel tiklan"
         none: "%{name} sendis averton al %{target}"
         sensitive: "%{name} markis konton de %{target} kiel sentema"
         silence: "%{name} limigis la konton de %{target}"
@@ -827,6 +828,8 @@ eo:
     system_checks:
       database_schema_check:
         message_html: Estas pritraktataj datumbazaj migradoj. Bonvolu ekzekuti ilin por certigi, ke la apliko kondutas kiel atendite
+      elasticsearch_preset:
+        action: Legi dokumentaron
       elasticsearch_running_check:
         message_html: Ne eblas konekti Elasticsearch. Bonvolu kontroli ke ĝi funkcias, aǔ malŝaltu plentekstan serĉon
       elasticsearch_version_check:
@@ -940,7 +943,7 @@ eo:
   admin_mailer:
     new_appeal:
       actions:
-        delete_statuses: por forigi iliajn mesaĝojn
+        delete_statuses: por forigi iliajn afiŝojn
         disable: por frostigi ties konton
         mark_statuses_as_sensitive: por marki iliajn mesaĝojn kiel sentemaj
         none: averto
@@ -991,7 +994,7 @@ eo:
     unsubscribe: Malabonu
     view: 'Vidi:'
     view_profile: Vidi profilon
-    view_status: Vidi mesaĝon
+    view_status: Vidi afiŝon
   applications:
     created: Aplikaĵo sukcese kreita
     destroyed: Aplikaĵo sukcese forigita
@@ -1131,7 +1134,7 @@ eo:
       recipient: Senditas por
       reject_appeal: Malakcepti apelacion
       status: 'Afiŝo #%{id}'
-      status_removed: Mesaĝo jam forigitas de sistemo
+      status_removed: Afiŝo jam estas forigita de sistemo
       title: "%{action} de %{date}"
       title_actions:
         delete_statuses: Forigo de afiŝo
@@ -1199,8 +1202,8 @@ eo:
     edit:
       add_keyword: Aldoni ĉefvorton
       keywords: Ĉefvortoj
-      statuses: Individuaj mesaĝoj
-      statuses_hint_html: Ĉi tiu filtrilo kongruas kelkajn mesaĝojn. <a href="%{path}">Kontrolu mesaĝojn de la filtrilo</a>.
+      statuses: Individuaj afiŝoj
+      statuses_hint_html: Ĉi tiu filtrilo kongruas kelkajn afiŝojn. <a href="%{path}">Kontroli afiŝojn de la filtrilo</a>.
       title: Ŝanĝi filtrilojn
     errors:
       deprecated_api_multiple_keywords: Ĉi tiuj parametroj ne povas ŝanĝitis de ĉi tiu programaro. Uzu pli novan programaron.
@@ -1218,8 +1221,8 @@ eo:
         one: "%{count} afiŝo"
         other: "%{count} afiŝoj"
       statuses_long:
-        one: "%{count} mesaĝo kaŝita"
-        other: "%{count} mesaĝoj kaŝita"
+        one: "%{count} afiŝo estas kaŝita"
+        other: "%{count} afiŝoj estas kaŝitaj"
       title: Filtriloj
     new:
       save: Konservi novan filtrilon
@@ -1230,7 +1233,7 @@ eo:
         remove: Forigi de filtrilo
       index:
         hint: Ĉi tiu filtrilo kongruas kelkaj mesaĝoj sendepende de aliaj kriterioj.
-        title: Filtritaj mesaĝoj
+        title: Filtritaj afiŝoj
   generic:
     all: Ĉio
     all_items_on_page_selected_html:
@@ -1644,16 +1647,16 @@ eo:
     interaction_exceptions_explanation: Sciu ke estas neniu garantio ke mesaĝo estos forigita se ĝi iras sub la limo de diskonigoj aŭ stelumoj post atingi ĝin.
     keep_direct: Konservi rektajn mesaĝojn
     keep_direct_hint: Ne forigos viajn rektajn mesagôjn
-    keep_media: Konservi mesaĝojn kun aŭdovidaj aldonaĵoj
+    keep_media: Konservi afiŝojn kun aŭdovidaj aldonaĵoj
     keep_media_hint: Ne forigi mesaĝojn kiuj enhavas aŭdovidajn aldonaĵojn
-    keep_pinned: Konservi alpinglitajn mesaĝojn
+    keep_pinned: Konservi alpinglitajn afiŝojn
     keep_pinned_hint: Ne forigi viajn ajn alpinglitajn mesaĝojn
     keep_polls: Konservi enketojn
     keep_polls_hint: Ne forigi viajn ajn enketojn
-    keep_self_bookmark: Konservi mesaĝojn kiun vi legsignis
+    keep_self_bookmark: Konservi afiŝojn kiun vi legsignis
     keep_self_bookmark_hint: Ne forigi viajn siajn mesaĝojn se vi legsignis ilin
-    keep_self_fav: Konservi mesaĝojn kiujn vi stelumis
-    keep_self_fav_hint: Ne forigi proprajn mesaĝojn se vi stelumis ilin
+    keep_self_fav: Konservi afiŝojn kiujn vi stelumis
+    keep_self_fav_hint: Ne forigi proprajn afiŝojn se vi stelumis ilin
     min_age:
       '1209600': 2 semajnoj
       '15778476': 6 monatoj
@@ -1664,7 +1667,7 @@ eo:
       '63113904': 2 jaroj
       '7889238': 3 monatoj
     min_age_label: Aĝlimo
-    min_favs: Konservi mesaĝojn stelumitajn almenaŭ
+    min_favs: Konservi afiŝojn stelumitajn almenaŭ
     min_favs_hint: Oni ne forigas viajn afiŝojn, kiuj estas diskonigitaj almenaŭ ĉi tiun nombron da fojoj. Lasu malplena por forigi afiŝojn sendepende de iliaj nombroj da diskonigoj
     min_reblogs: Konservi diskonitajn mesaĝojn almenau
     min_reblogs_hint: Oni ne forigas viajn afiŝojn kiuj estas diskonigitaj almenaŭ ĉi tiun nombron da fojoj. Lasu malplena por forigi afiŝojn sendepende de iliaj nombroj da diskonigoj
@@ -1738,11 +1741,11 @@ eo:
         silence: Vi ankorau povas uzi vian konton, sed nur personoj kiuj jam sekvas vin vidos viajn mesaĝojn en tiu ĉi servilo, kaj vi eble estos ekskluzive el diversaj malkovrigaj funkcioj. Tamen, aliaj ankoraŭ povas permane eksekvi vin.
         suspend: Vi ne povas uzi vian konton plu, kaj via profilo kaj aliaj datumoj ne estas disponeblaj plu.
       reason: 'Kialo:'
-      statuses: 'Mesaĝoj ripetitaj:'
+      statuses: 'Afiŝoj citataj:'
       subject:
-        delete_statuses: Viaj mesaĝoj ĉe %{acct} forigitas
+        delete_statuses: Viaj afiŝoj ĉe %{acct} estas forigitaj
         disable: Via konto %{acct} estas frostigita
-        mark_statuses_as_sensitive: Viaj mesaĝoj ĉe %{acct} markitas kiel sentemaj
+        mark_statuses_as_sensitive: Viaj afiŝoj ĉe %{acct} estas markitaj kiel tiklemaj
         none: Averto por %{acct}
         sensitive: Viaj mesaĝoj ĉe %{acct} markitas kiel sentemaj malantau ol nun
         silence: Oni limigis vian konton %{acct}
diff --git a/config/locales/ia.yml b/config/locales/ia.yml
index a167b5d8c..6c9929315 100644
--- a/config/locales/ia.yml
+++ b/config/locales/ia.yml
@@ -15,17 +15,27 @@ 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}
+    nothing_here: Il ha nihil ci!
+    pin_errors:
+      following: Tu debe primo sequer le persona que tu vole indorsar
     posts:
       one: Message
       other: Messages
     posts_tab_heading: Messages
   admin:
+    account_actions:
+      action: Exequer action
+      title: Exequer action de moderation sur %{acct}
     account_moderation_notes:
       create: Lassar un nota
       created_msg: Nota de moderation create con successo!
+      destroyed_msg: Nota de moderation destruite con successo!
     accounts:
       add_email_domain_block: Blocar dominio de e-mail
+      approve: Approbar
+      approved_msg: Demanda de inscription de %{username} approbate con successo
       are_you_sure: Es tu secur?
+      avatar: Avatar
       by_domain: Dominio
       change_email:
         changed_msg: Email cambiate con successo!
@@ -34,6 +44,11 @@ ia:
         new_email: Nove e-mail
         submit: Cambiar e-mail
         title: Cambiar e-mail pro %{username}
+      change_role:
+        changed_msg: Rolo cambiate con successo!
+        label: Cambiar rolo
+        no_role: Necun rolo
+        title: Cambiar rolo pro %{username}
       confirm: Confirmar
       confirmed: Confirmate
       confirming: In confirmation
@@ -42,25 +57,59 @@ ia:
       deleted: Delite
       demote: Degradar
       destroyed_msg: Le datos de %{username} ora es in cauda pro su imminente deletion
+      disable: Gelar
+      disable_sign_in_token_auth: Disactivar le authentication per token in e-mail
       disable_two_factor_authentication: Disactivar 2FA
+      disabled: Gelate
       display_name: Nomine visibile
       domain: Dominio
       edit: Modificar
       email: E-mail
       email_status: Stato de e-mail
+      enable: Disgelar
+      enable_sign_in_token_auth: Activar le authentication per token in e-mail
       enabled: Activate
+      enabled_msg: Conto de %{username} disgelate con successo
       followers: Sequitores
+      follows: Sequites
+      header: Capite
+      inbox_url: URL de cassa de entrata
+      invite_request_text: Motivos pro le inscription
+      invited_by: Invitate per
+      ip: IP
+      joined: Inscription
       location:
         all: Toto
+        local: Local
+        remote: Remote
         title: Location
+      login_status: Stato de session
+      media_attachments: Annexos multimedial
+      memorialize: Render commemorative
+      memorialized: Conto commemorative
+      memorialized_msg: "%{username} ha essite convertite in un conto commemorative"
       moderation:
         active: Active
         all: Toto
         disabled: Disactivate
+        pending: In tractamento
+        silenced: Limitate
+        suspended: Suspendite
+        title: Moderation
       moderation_notes: Notas de moderation
       most_recent_activity: Activitate plus recente
       most_recent_ip: IP plus recente
+      no_account_selected: Necun conto ha essite cambiate perque necun ha essite seligite
+      no_limits_imposed: Necun limite imponite
+      no_role_assigned: Necun rolo assignate
+      not_subscribed: Non subscribite
+      pending: Attende revision
+      perform_full_suspension: Suspender
+      previous_strikes: Previe admonitiones
+      promote: Promover
+      protocol: Protocollo
       public: Public
+      push_subscription_expires: Subscription PuSH expira le
       redownload: Actualisar profilo
       resend_confirmation:
         already_confirmed: Iste usator jam es confirmate
@@ -237,6 +286,9 @@ ia:
       updated_at: Actualisate
       view_profile: Vider profilo
     roles:
+      assigned_users:
+        one: "%{count} usator"
+        other: "%{count} usatores"
       everyone: Permissiones predefinite
       privileges:
         delete_user_data: Deler le datos de usator
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 4c22335ea..8de8e4887 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -1671,6 +1671,7 @@ pt-BR:
       domain_block: Suspensão do servidor (%{target_name})
       user_domain_block: Você bloqueou %{target_name}
     lost_followers: Seguidores perdidos
+    purged: As informações sobre este servidor foram eliminadas pelos administradores do seu servidor.
     type: Evento
   statuses:
     attached:
@@ -1765,6 +1766,7 @@ pt-BR:
     contrast: Mastodon  (Alto contraste)
     default: Mastodon (Noturno)
     mastodon-light: Mastodon (Diurno)
+    system: Automático (usar tema do sistema)
   time:
     formats:
       default: "%H:%M em %d de %b de %Y"
diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml
index 2f04ce982..7012cdb1c 100644
--- a/config/locales/simple_form.ia.yml
+++ b/config/locales/simple_form.ia.yml
@@ -30,6 +30,7 @@ ia:
       defaults:
         autofollow: Invitar a sequer tu conto
         avatar: Pictura de profilo
+        chosen_languages: Filtrar linguas
         confirm_new_password: Confirmar nove contrasigno
         confirm_password: Confirmar contrasigno
         current_password: Contrasigno actual
@@ -39,6 +40,7 @@ ia:
         new_password: Nove contrasigno
         password: Contrasigno
         setting_advanced_layout: Activar le interfacie web avantiate
+        setting_always_send_emails: Sempre inviar notificationes per e-mail
         setting_default_language: Lingua de publication
         setting_display_media_default: Predefinite
         setting_display_media_hide_all: Celar toto

From f4a53f3fb480bb1b9f0fa0d2849b6dc4300f679b Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 24 Apr 2024 04:56:28 -0400
Subject: [PATCH 217/223] Extract constants for column size length validation
 limits (#30045)

---
 app/models/account_moderation_note.rb | 4 +++-
 app/models/account_note.rb            | 4 +++-
 app/models/invite.rb                  | 4 +++-
 app/models/report.rb                  | 4 +++-
 app/models/report_note.rb             | 4 +++-
 app/models/rule.rb                    | 4 +++-
 app/models/user_invite_request.rb     | 4 +++-
 7 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/app/models/account_moderation_note.rb b/app/models/account_moderation_note.rb
index ff399bab0..ad49b2422 100644
--- a/app/models/account_moderation_note.rb
+++ b/app/models/account_moderation_note.rb
@@ -13,10 +13,12 @@
 #
 
 class AccountModerationNote < ApplicationRecord
+  CONTENT_SIZE_LIMIT = 500
+
   belongs_to :account
   belongs_to :target_account, class_name: 'Account'
 
   scope :latest, -> { reorder('created_at DESC') }
 
-  validates :content, presence: true, length: { maximum: 500 }
+  validates :content, presence: true, length: { maximum: CONTENT_SIZE_LIMIT }
 end
diff --git a/app/models/account_note.rb b/app/models/account_note.rb
index 9bc704d98..317e6873f 100644
--- a/app/models/account_note.rb
+++ b/app/models/account_note.rb
@@ -14,9 +14,11 @@
 class AccountNote < ApplicationRecord
   include RelationshipCacheable
 
+  COMMENT_SIZE_LIMIT = 2_000
+
   belongs_to :account
   belongs_to :target_account, class_name: 'Account'
 
   validates :account_id, uniqueness: { scope: :target_account_id }
-  validates :comment, length: { maximum: 2_000 }
+  validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }
 end
diff --git a/app/models/invite.rb b/app/models/invite.rb
index c0cbc5845..2fe9f22fb 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -19,12 +19,14 @@
 class Invite < ApplicationRecord
   include Expireable
 
+  COMMENT_SIZE_LIMIT = 420
+
   belongs_to :user, inverse_of: :invites
   has_many :users, inverse_of: :invite, dependent: nil
 
   scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }
 
-  validates :comment, length: { maximum: 420 }
+  validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }
 
   before_validation :set_code
 
diff --git a/app/models/report.rb b/app/models/report.rb
index df7e3d2ef..3df5a20e1 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -26,6 +26,8 @@ class Report < ApplicationRecord
   include Paginable
   include RateLimitable
 
+  COMMENT_SIZE_LIMIT = 1_000
+
   rate_limit by: :account, family: :reports
 
   belongs_to :account
@@ -46,7 +48,7 @@ class Report < ApplicationRecord
   # A report is considered local if the reporter is local
   delegate :local?, to: :account
 
-  validates :comment, length: { maximum: 1_000 }, if: :local?
+  validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }, if: :local?
   validates :rule_ids, absence: true, if: -> { (category_changed? || rule_ids_changed?) && !violation? }
 
   validate :validate_rule_ids, if: -> { (category_changed? || rule_ids_changed?) && violation? }
diff --git a/app/models/report_note.rb b/app/models/report_note.rb
index 74b46027e..b5c40a18b 100644
--- a/app/models/report_note.rb
+++ b/app/models/report_note.rb
@@ -13,10 +13,12 @@
 #
 
 class ReportNote < ApplicationRecord
+  CONTENT_SIZE_LIMIT = 500
+
   belongs_to :account
   belongs_to :report, inverse_of: :notes, touch: true
 
   scope :latest, -> { reorder(created_at: :desc) }
 
-  validates :content, presence: true, length: { maximum: 500 }
+  validates :content, presence: true, length: { maximum: CONTENT_SIZE_LIMIT }
 end
diff --git a/app/models/rule.rb b/app/models/rule.rb
index f28dc2ffe..99a36397a 100644
--- a/app/models/rule.rb
+++ b/app/models/rule.rb
@@ -15,9 +15,11 @@
 class Rule < ApplicationRecord
   include Discard::Model
 
+  TEXT_SIZE_LIMIT = 300
+
   self.discard_column = :deleted_at
 
-  validates :text, presence: true, length: { maximum: 300 }
+  validates :text, presence: true, length: { maximum: TEXT_SIZE_LIMIT }
 
   scope :ordered, -> { kept.order(priority: :asc, id: :asc) }
 end
diff --git a/app/models/user_invite_request.rb b/app/models/user_invite_request.rb
index 2b76c88b9..9dd677516 100644
--- a/app/models/user_invite_request.rb
+++ b/app/models/user_invite_request.rb
@@ -12,6 +12,8 @@
 #
 
 class UserInviteRequest < ApplicationRecord
+  TEXT_SIZE_LIMIT = 420
+
   belongs_to :user, inverse_of: :invite_request
-  validates :text, presence: true, length: { maximum: 420 }
+  validates :text, presence: true, length: { maximum: TEXT_SIZE_LIMIT }
 end

From b12847462597cf590ec3d9c05635cd736024d335 Mon Sep 17 00:00:00 2001
From: Tim Rogers <rogers.timothy.john@gmail.com>
Date: Wed, 24 Apr 2024 04:09:21 -0500
Subject: [PATCH 218/223] Fixed rendering of excess whitespace in status card
 titles (#30017)

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

diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb
index bb031986d..bec7d3a45 100644
--- a/app/lib/link_details_extractor.rb
+++ b/app/lib/link_details_extractor.rb
@@ -156,7 +156,7 @@ class LinkDetailsExtractor
   end
 
   def title
-    html_entities.decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first)
+    html_entities.decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first).strip
   end
 
   def description

From d9eee9bf9a3a3e99acb1cea12082faf0fe8de0f9 Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Wed, 24 Apr 2024 10:56:54 -0400
Subject: [PATCH 219/223] Remove column defaults for `status_pins` timestamp
 columns (#29261)

---
 ...17171534_remove_defaults_for_status_pins_timestamps.rb | 8 ++++++++
 db/schema.rb                                              | 4 ++--
 2 files changed, 10 insertions(+), 2 deletions(-)
 create mode 100644 db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb

diff --git a/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb b/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb
new file mode 100644
index 000000000..301371a02
--- /dev/null
+++ b/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class RemoveDefaultsForStatusPinsTimestamps < ActiveRecord::Migration[7.1]
+  def change
+    change_column_default :status_pins, :created_at, from: -> { 'CURRENT_TIMESTAMP' }, to: nil
+    change_column_default :status_pins, :updated_at, from: -> { 'CURRENT_TIMESTAMP' }, to: nil
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6a52333a8..a875c6ffc 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1030,8 +1030,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
   create_table "status_pins", force: :cascade do |t|
     t.bigint "account_id", null: false
     t.bigint "status_id", null: false
-    t.datetime "created_at", precision: nil, default: -> { "now()" }, null: false
-    t.datetime "updated_at", precision: nil, default: -> { "now()" }, null: false
+    t.datetime "created_at", precision: nil, null: false
+    t.datetime "updated_at", precision: nil, null: false
     t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true
     t.index ["status_id"], name: "index_status_pins_on_status_id"
   end

From 85fdbd0ad53837c9209acf3fb45811d5bae41cd9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 25 Apr 2024 10:50:54 +0200
Subject: [PATCH 220/223] New Crowdin Translations (automated) (#30062)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/de.json    | 10 +++++-----
 app/javascript/mastodon/locales/ig.json    | 12 ++++++++++++
 app/javascript/mastodon/locales/ja.json    |  2 +-
 app/javascript/mastodon/locales/pt-BR.json |  1 +
 app/javascript/mastodon/locales/sv.json    |  1 +
 config/locales/de.yml                      |  2 +-
 config/locales/devise.de.yml               |  2 +-
 config/locales/doorkeeper.es-MX.yml        |  1 +
 config/locales/doorkeeper.es.yml           |  1 +
 config/locales/doorkeeper.pt-BR.yml        |  1 +
 config/locales/doorkeeper.sv.yml           |  1 +
 config/locales/pt-BR.yml                   |  2 ++
 config/locales/simple_form.pt-BR.yml       |  1 +
 13 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index a1ba25fed..8b52cdb3c 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -536,11 +536,11 @@
   "onboarding.follows.empty": "Bedauerlicherweise können aktuell keine Ergebnisse angezeigt werden. Du kannst die Suche verwenden oder den Reiter „Entdecken“ auswählen, um neue Leute zum Folgen zu finden – oder du versuchst es später erneut.",
   "onboarding.follows.lead": "Deine Startseite ist der primäre Anlaufpunkt, um Mastodon zu erleben. Je mehr Profilen du folgst, umso aktiver und interessanter wird sie. Damit du direkt loslegen kannst, gibt es hier ein paar Vorschläge:",
   "onboarding.follows.title": "Personalisiere deine Startseite",
-  "onboarding.profile.discoverable": "Mein Profil auffindbar machen",
+  "onboarding.profile.discoverable": "Mein Profil darf entdeckt werden",
   "onboarding.profile.discoverable_hint": "Wenn du entdeckt werden möchtest, dann können deine Beiträge in Suchergebnissen und Trends erscheinen. Dein Profil kann ebenfalls anderen mit ähnlichen Interessen vorgeschlagen werden.",
   "onboarding.profile.display_name": "Anzeigename",
   "onboarding.profile.display_name_hint": "Dein richtiger Name oder dein Fantasiename …",
-  "onboarding.profile.lead": "Du kannst das später in den Einstellungen vervollständigen, wo noch mehr Anpassungsmöglichkeiten zur Verfügung stehen.",
+  "onboarding.profile.lead": "Du kannst dein Profil später in den Einstellungen vervollständigen. Dort stehen weitere Anpassungsmöglichkeiten zur Verfügung.",
   "onboarding.profile.note": "Über mich",
   "onboarding.profile.note_hint": "Du kannst andere @Profile erwähnen oder #Hashtags verwenden …",
   "onboarding.profile.save_and_continue": "Speichern und fortfahren",
@@ -556,16 +556,16 @@
   "onboarding.start.title": "Du hast es geschafft!",
   "onboarding.steps.follow_people.body": "Interessanten Profilen zu folgen ist das, was Mastodon ausmacht.",
   "onboarding.steps.follow_people.title": "Personalisiere deine Startseite",
-  "onboarding.steps.publish_status.body": "Begrüße die Welt mit Text, Fotos, Videos oder Umfragen {emoji}",
+  "onboarding.steps.publish_status.body": "Begrüße die Welt mit Text, Fotos, Videos oder Umfragen. {emoji}",
   "onboarding.steps.publish_status.title": "Erstelle deinen ersten Beitrag",
   "onboarding.steps.setup_profile.body": "Mit einem vollständigen Profil interagieren andere eher mit dir.",
   "onboarding.steps.setup_profile.title": "Personalisiere dein Profil",
-  "onboarding.steps.share_profile.body": "Lass deine Freund*innen wissen, wie sie dich auf Mastodon finden können",
+  "onboarding.steps.share_profile.body": "Lass deine Freund*innen wissen, wie sie dich auf Mastodon finden können.",
   "onboarding.steps.share_profile.title": "Teile dein Mastodon-Profil",
   "onboarding.tips.2fa": "<strong>Wusstest du schon?</strong> Du kannst die Sicherheit deines Kontos erhöhen, indem du die Zwei-Faktor-Authentisierung in deinen Kontoeinstellungen aktivierst. Dafür ist keine Telefonnummer notwendig und es funktioniert jede beliebige TOTP-App!",
   "onboarding.tips.accounts_from_other_servers": "<strong>Wusstest du schon?</strong> Da Mastodon dezentralisiert ist, werden einige Profile, denen du begegnest, auf anderen Servern als deinem bereitgestellt. Und trotzdem kannst du uneingeschränkt mit ihnen interagieren! Der Servername befindet sich in der zweiten Hälfte ihres Profilnamens!",
   "onboarding.tips.migration": "<strong>Wusstest du schon?</strong> Wenn du das Gefühl hast, dass {domain} in Zukunft nicht die richtige Serverwahl für dich ist, kannst du auf einen anderen Mastodon-Server umziehen, ohne deine Follower zu verlieren. Du kannst sogar deinen eigenen Server betreiben!",
-  "onboarding.tips.verification": "<strong>Wusstest du schon?</strong> Du kannst dein Konto verifizieren, indem du auf deiner Website auf dein Mastodon-Profil verlinkst und den Link deiner Website zu deinem Profil hinzufügst. Keine Gebühren oder Dokumente erforderlich!",
+  "onboarding.tips.verification": "<strong>Wusstest du schon?</strong> Du kannst dein Konto verifizieren, indem du auf deiner Website auf dein Mastodon-Profil verlinkst und den Link deiner Website zu deinem Profil hinzufügst. Völlig kostenlos und ohne Dokumente einsenden zu müssen!",
   "password_confirmation.exceeds_maxlength": "Passwortbestätigung überschreitet die maximal erlaubte Zeichenanzahl",
   "password_confirmation.mismatching": "Passwortbestätigung stimmt nicht überein",
   "picture_in_picture.restore": "Zurücksetzen",
diff --git a/app/javascript/mastodon/locales/ig.json b/app/javascript/mastodon/locales/ig.json
index a9b300fa4..90253743f 100644
--- a/app/javascript/mastodon/locales/ig.json
+++ b/app/javascript/mastodon/locales/ig.json
@@ -20,6 +20,7 @@
   "column.bookmarks": "Ebenrụtụakā",
   "column.home": "Be",
   "column.lists": "Ndepụta",
+  "column.notifications": "Nziọkwà",
   "column.pins": "Pinned post",
   "column_header.pin": "Gbado na profaịlụ gị",
   "column_subheading.settings": "Mwube",
@@ -42,17 +43,28 @@
   "confirmations.reply.confirm": "Zaa",
   "confirmations.unfollow.confirm": "Kwụsị iso",
   "conversation.delete": "Hichapụ nkata",
+  "disabled_account_banner.account_settings": "Mwube akaụntụ",
   "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.",
   "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.",
+  "domain_pill.username": "Ahaojiaru",
   "embed.instructions": "Embed this status on your website by copying the code below.",
+  "emoji_button.activity": "Mmemme",
+  "emoji_button.label": "Tibanye emoji",
   "emoji_button.search": "Chọọ...",
+  "emoji_button.symbols": "Ọdịmara",
   "empty_column.account_timeline": "No posts found",
   "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}",
   "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
   "errors.unexpected_crash.report_issue": "Kpesa nsogbu",
+  "explore.trending_links": "Akụkọ",
+  "firehose.all": "Ha niine",
+  "follow_request.authorize": "Nye ikike",
   "footer.privacy_policy": "Iwu nzuzu",
   "getting_started.heading": "Mbido",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "home.column_settings.show_replies": "Gosi nzaghachị",
+  "home.hide_announcements": "Zoo ọkwa",
+  "home.show_announcements": "Gosi ọkwa",
   "keyboard_shortcuts.back": "to navigate back",
   "keyboard_shortcuts.blocked": "to open blocked users list",
   "keyboard_shortcuts.boost": "to boost",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 30c9eb77a..f20d93753 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -298,7 +298,7 @@
   "filter_modal.select_filter.title": "この投稿をフィルターする",
   "filter_modal.title.status": "投稿をフィルターする",
   "filtered_notifications_banner.mentions": "{count, plural, one {メンション} other {メンション}}",
-  "filtered_notifications_banner.pending_requests": "{count, plural, =0 {アカウント} other {#アカウント}}からの通知がブロックされています",
+  "filtered_notifications_banner.pending_requests": "{count, plural, =0 {通知がブロックされているアカウントはありません} other {#アカウントからの通知がブロックされています}}",
   "filtered_notifications_banner.title": "ブロック済みの通知",
   "firehose.all": "すべて",
   "firehose.local": "このサーバー",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 1bb73db23..6bda11058 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -297,6 +297,7 @@
   "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.mentions": "{count, plural, one {menção} other {menções}}",
   "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.title": "Notificações filtradas",
   "firehose.all": "Tudo",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 80c203112..2b9f0a51b 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -297,6 +297,7 @@
   "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.mentions": "{count, plural, one {mention} other {mentions}}",
   "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner",
   "filtered_notifications_banner.title": "Filtrerade aviseringar",
   "firehose.all": "Allt",
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 67aad1587..27073ff9e 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -1046,7 +1046,7 @@ de:
     apply_for_account: Konto beantragen
     captcha_confirmation:
       help_html: Falls du Probleme beim Lösen des CAPTCHA hast, dann kannst uns über %{email} kontaktieren und wir werden versuchen, dir zu helfen.
-      hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Weiter“.
+      hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Fortfahren“.
       title: Sicherheitsüberprüfung
     confirmations:
       awaiting_review: Deine E-Mail-Adresse wurde bestätigt und das Team von %{domain} überprüft nun deine Registrierung. Sobald es dein Konto genehmigt, wirst du eine E-Mail erhalten.
diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml
index 73fa1fa60..032132cf5 100644
--- a/config/locales/devise.de.yml
+++ b/config/locales/devise.de.yml
@@ -25,7 +25,7 @@ de:
         explanation_when_pending: Du hast dich für eine Einladung bei %{host} mit dieser E-Mail-Adresse beworben. Sobald du deine E-Mail-Adresse bestätigt hast, werden wir deine Anfrage überprüfen. Du kannst dich in dieser Zeit nicht anmelden. Wenn deine Anfrage abgelehnt wird, werden deine Daten entfernt – von dir ist keine weitere Handlung notwendig. Wenn du das nicht warst, dann kannst du diese E-Mail ignorieren.
         extra_html: Bitte beachte auch die <a href="%{terms_path}">Serverregeln</a> und <a href="%{policy_path}">unsere Datenschutzerklärung</a>.
         subject: 'Mastodon: Anleitung zum Bestätigen deines Kontos auf %{instance}'
-        title: Verifiziere E-Mail-Adresse
+        title: Verifiziere deine 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 Administrator*innen des Servers, wenn du aus deinem Konto ausgesperrt bist.
diff --git a/config/locales/doorkeeper.es-MX.yml b/config/locales/doorkeeper.es-MX.yml
index 082d656bc..e56e0df3b 100644
--- a/config/locales/doorkeeper.es-MX.yml
+++ b/config/locales/doorkeeper.es-MX.yml
@@ -174,6 +174,7 @@ es-MX:
       read:filters: ver tus filtros
       read:follows: ver a quién sigues
       read:lists: ver tus listas
+      read:me: leer solo la información básica de tu cuenta
       read:mutes: ver a quién has silenciado
       read:notifications: ver tus notificaciones
       read:reports: ver tus informes
diff --git a/config/locales/doorkeeper.es.yml b/config/locales/doorkeeper.es.yml
index 002f813b3..44e165a21 100644
--- a/config/locales/doorkeeper.es.yml
+++ b/config/locales/doorkeeper.es.yml
@@ -174,6 +174,7 @@ es:
       read:filters: ver tus filtros
       read:follows: ver a quién sigues
       read:lists: ver tus listas
+      read:me: leer solo la información básica de tu cuenta
       read:mutes: ver a quién has silenciado
       read:notifications: ver tus notificaciones
       read:reports: ver tus informes
diff --git a/config/locales/doorkeeper.pt-BR.yml b/config/locales/doorkeeper.pt-BR.yml
index d7e9353b5..150b4339e 100644
--- a/config/locales/doorkeeper.pt-BR.yml
+++ b/config/locales/doorkeeper.pt-BR.yml
@@ -174,6 +174,7 @@ pt-BR:
       read:filters: ver seus filtros
       read:follows: ver quem você segue
       read:lists: ver suas listas
+      read:me: ler só as informações básicas da sua conta
       read:mutes: ver seus silenciados
       read:notifications: ver suas notificações
       read:reports: ver suas denúncias
diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml
index f2c8bd34b..d336f08c5 100644
--- a/config/locales/doorkeeper.sv.yml
+++ b/config/locales/doorkeeper.sv.yml
@@ -174,6 +174,7 @@ sv:
       read:filters: se dina filter
       read:follows: se vem du följer
       read:lists: se dina listor
+      read:me: läs endast den grundläggande informationen för ditt konto
       read:mutes: se dina tystningar
       read:notifications: se dina notiser
       read:reports: se dina rapporter
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 8de8e4887..9cb9cadee 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -1671,6 +1671,8 @@ pt-BR:
       domain_block: Suspensão do servidor (%{target_name})
       user_domain_block: Você bloqueou %{target_name}
     lost_followers: Seguidores perdidos
+    lost_follows: Seguidores perdidos
+    preamble: Você poderá perder seguidores e seguidores quando bloquear um domínio ou quando os seus moderadores decidirem suspender um servidor remoto. Quando isso acontecer, você poderá baixar listas de relações desfeitas, a serem inspecionadas e possivelmente importadas para outro servidor.
     purged: As informações sobre este servidor foram eliminadas pelos administradores do seu servidor.
     type: Evento
   statuses:
diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml
index 676f5e37a..c3eea9f11 100644
--- a/config/locales/simple_form.pt-BR.yml
+++ b/config/locales/simple_form.pt-BR.yml
@@ -116,6 +116,7 @@ pt-BR:
           sign_up_requires_approval: Novas inscrições exigirão sua aprovação
         severity: Escolha o que acontecerá com as solicitações deste IP
       rule:
+        hint: Opcional. Forneça mais detalhes sobre a regra
         text: Descreva uma regra ou requisito para os usuários neste servidor. Tente mantê-la curta e simples.
       sessions:
         otp: 'Digite o código de dois fatores gerado pelo aplicativo no seu celular ou use um dos códigos de recuperação:'

From 0ec061aa8f7383330b26b3323d2fafd9ec7663e3 Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
Date: Thu, 25 Apr 2024 18:25:33 +0200
Subject: [PATCH 221/223] Change design of people tab on explore in web UI
 (#30059)

---
 .../features/explore/components/card.jsx      | 88 +++++++++++++++++++
 .../mastodon/features/explore/suggestions.jsx |  9 +-
 app/javascript/mastodon/locales/en.json       |  4 +
 .../styles/mastodon/components.scss           | 79 ++++++++++++++++-
 4 files changed, 175 insertions(+), 5 deletions(-)
 create mode 100644 app/javascript/mastodon/features/explore/components/card.jsx

diff --git a/app/javascript/mastodon/features/explore/components/card.jsx b/app/javascript/mastodon/features/explore/components/card.jsx
new file mode 100644
index 000000000..316203060
--- /dev/null
+++ b/app/javascript/mastodon/features/explore/components/card.jsx
@@ -0,0 +1,88 @@
+import PropTypes from 'prop-types';
+import { useCallback } from 'react';
+
+import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
+
+import { Link } from 'react-router-dom';
+
+import { useDispatch, useSelector } from 'react-redux';
+
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import { followAccount, unfollowAccount } from 'mastodon/actions/accounts';
+import { dismissSuggestion } from 'mastodon/actions/suggestions';
+import { Avatar } from 'mastodon/components/avatar';
+import { Button } from 'mastodon/components/button';
+import { DisplayName } from 'mastodon/components/display_name';
+import { IconButton } from 'mastodon/components/icon_button';
+import { domain } from 'mastodon/initial_state';
+
+const messages = defineMessages({
+  follow: { id: 'account.follow', defaultMessage: 'Follow' },
+  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
+  dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" },
+});
+
+export const Card = ({ id, source }) => {
+  const intl = useIntl();
+  const account = useSelector(state => state.getIn(['accounts', id]));
+  const relationship = useSelector(state => state.getIn(['relationships', id]));
+  const dispatch = useDispatch();
+  const following = relationship?.get('following') ?? relationship?.get('requested');
+
+  const handleFollow = useCallback(() => {
+    if (following) {
+      dispatch(unfollowAccount(id));
+    } else {
+      dispatch(followAccount(id));
+    }
+  }, [id, following, dispatch]);
+
+  const handleDismiss = useCallback(() => {
+    dispatch(dismissSuggestion(id));
+  }, [id, dispatch]);
+
+  let label;
+
+  switch (source) {
+  case 'friends_of_friends':
+    label = <FormattedMessage id='follow_suggestions.friends_of_friends_longer' defaultMessage='Popular among people you follow' />;
+    break;
+  case 'similar_to_recently_followed':
+    label = <FormattedMessage id='follow_suggestions.similar_to_recently_followed_longer' defaultMessage='Similar to profiles you recently followed' />;
+    break;
+  case 'featured':
+    label = <FormattedMessage id='follow_suggestions.featured_longer' defaultMessage='Hand-picked by the {domain} team' values={{ domain }} />;
+    break;
+  case 'most_followed':
+    label = <FormattedMessage id='follow_suggestions.popular_suggestion_longer' defaultMessage='Popular on {domain}' values={{ domain }} />;
+    break;
+  case 'most_interactions':
+    label = <FormattedMessage id='follow_suggestions.popular_suggestion_longer' defaultMessage='Popular on {domain}' values={{ domain }} />;
+    break;
+  }
+
+  return (
+    <div className='explore__suggestions__card'>
+      <div className='explore__suggestions__card__source'>
+        {label}
+      </div>
+
+      <div className='explore__suggestions__card__body'>
+        <Link to={`/@${account.get('acct')}`}><Avatar account={account} size={48} /></Link>
+
+        <div className='explore__suggestions__card__body__main'>
+          <div className='explore__suggestions__card__body__main__name-button'>
+            <Link className='explore__suggestions__card__body__main__name-button__name' to={`/@${account.get('acct')}`}><DisplayName account={account} /></Link>
+            <IconButton iconComponent={CloseIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
+            <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} secondary={following} onClick={handleFollow} />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+Card.propTypes = {
+  id: PropTypes.string.isRequired,
+  source: PropTypes.oneOf(['friends_of_friends', 'similar_to_recently_followed', 'featured', 'most_followed', 'most_interactions']),
+};
diff --git a/app/javascript/mastodon/features/explore/suggestions.jsx b/app/javascript/mastodon/features/explore/suggestions.jsx
index ba33c4d08..101ec0d19 100644
--- a/app/javascript/mastodon/features/explore/suggestions.jsx
+++ b/app/javascript/mastodon/features/explore/suggestions.jsx
@@ -10,9 +10,10 @@ import { connect } from 'react-redux';
 
 import { fetchSuggestions } from 'mastodon/actions/suggestions';
 import { LoadingIndicator } from 'mastodon/components/loading_indicator';
-import AccountCard from 'mastodon/features/directory/components/account_card';
 import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 
+import { Card } from './components/card';
+
 const mapStateToProps = state => ({
   suggestions: state.getIn(['suggestions', 'items']),
   isLoading: state.getIn(['suggestions', 'isLoading']),
@@ -54,7 +55,11 @@ class Suggestions extends PureComponent {
     return (
       <div className='explore__suggestions scrollable' data-nosnippet>
         {isLoading ? <LoadingIndicator /> : suggestions.map(suggestion => (
-          <AccountCard key={suggestion.get('account')} id={suggestion.get('account')} />
+          <Card
+            key={suggestion.get('account')}
+            id={suggestion.get('account')}
+            source={suggestion.getIn(['sources', 0])}
+          />
         ))}
       </div>
     );
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index fd44b3952..a1b79881c 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.",
   "follow_suggestions.curated_suggestion": "Staff pick",
   "follow_suggestions.dismiss": "Don't show again",
+  "follow_suggestions.featured_longer": "Hand-picked by the {domain} team",
+  "follow_suggestions.friends_of_friends_longer": "Popular among people you follow",
   "follow_suggestions.hints.featured": "This profile has been hand-picked by the {domain} team.",
   "follow_suggestions.hints.friends_of_friends": "This profile is popular among the people you follow.",
   "follow_suggestions.hints.most_followed": "This profile is one of the most followed on {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "This profile is similar to the profiles you have most recently followed.",
   "follow_suggestions.personalized_suggestion": "Personalized suggestion",
   "follow_suggestions.popular_suggestion": "Popular suggestion",
+  "follow_suggestions.popular_suggestion_longer": "Popular on {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Similar to profiles you recently followed",
   "follow_suggestions.view_all": "View all",
   "follow_suggestions.who_to_follow": "Who to follow",
   "followed_tags": "Followed hashtags",
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index b2139169a..a1864a456 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2016,7 +2016,10 @@ a .account__avatar {
   display: flex;
   align-items: center;
   gap: 8px;
+}
 
+.account__relationship,
+.explore__suggestions__card {
   .icon-button {
     border: 1px solid var(--background-border-color);
     border-radius: 4px;
@@ -2964,6 +2967,75 @@ $ui-header-logo-wordmark-width: 99px;
   display: none;
 }
 
+.explore__suggestions__card {
+  padding: 12px 16px;
+  gap: 8px;
+  display: flex;
+  flex-direction: column;
+  border-bottom: 1px solid var(--background-border-color);
+
+  &:last-child {
+    border-bottom: 0;
+  }
+
+  &__source {
+    padding-inline-start: 60px;
+    font-size: 13px;
+    line-height: 16px;
+    color: $dark-text-color;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+  }
+
+  &__body {
+    display: flex;
+    gap: 12px;
+    align-items: center;
+
+    &__main {
+      flex: 1 1 auto;
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+      min-width: 0;
+
+      &__name-button {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        &__name {
+          display: block;
+          color: inherit;
+          text-decoration: none;
+          flex: 1 1 auto;
+          min-width: 0;
+        }
+
+        .button {
+          min-width: 80px;
+        }
+
+        .display-name {
+          font-size: 15px;
+          line-height: 20px;
+          color: $secondary-text-color;
+
+          strong {
+            font-weight: 700;
+          }
+
+          &__account {
+            color: $darker-text-color;
+            display: block;
+          }
+        }
+      }
+    }
+  }
+}
+
 @media screen and (max-width: $no-gap-breakpoint - 1px) {
   .columns-area__panels__pane--compositional {
     display: none;
@@ -7293,10 +7365,11 @@ a.status-card {
         content: '';
         position: absolute;
         bottom: -1px;
-        left: 0;
-        width: 100%;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 40px;
         height: 3px;
-        border-radius: 4px;
+        border-radius: 4px 4px 0 0;
         background: $highlight-text-color;
       }
     }

From 4ef0b48b951d65920d3a3d9cdfd099967c5e4f6d Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Thu, 25 Apr 2024 19:26:05 +0200
Subject: [PATCH 222/223] Add in-app notifications for moderation
 actions/warnings (#30065)

---
 .../components/moderation_warning.tsx         | 78 +++++++++++++++++++
 .../notifications/components/notification.jsx | 25 ++++++
 app/javascript/mastodon/locales/en.json       |  9 +++
 .../mastodon/reducers/notifications.js        |  1 +
 .../styles/mastodon/components.scss           |  3 +-
 app/models/admin/account_action.rb            |  9 ++-
 app/models/admin/status_batch_action.rb       | 12 ++-
 app/models/notification.rb                    |  6 +-
 .../rest/account_warning_serializer.rb        | 16 ++++
 app/serializers/rest/appeal_serializer.rb     | 15 ++++
 .../rest/notification_serializer.rb           |  5 ++
 app/services/notify_service.rb                |  4 +-
 spec/models/admin/account_action_spec.rb      | 26 +++----
 13 files changed, 188 insertions(+), 21 deletions(-)
 create mode 100644 app/javascript/mastodon/features/notifications/components/moderation_warning.tsx
 create mode 100644 app/serializers/rest/account_warning_serializer.rb
 create mode 100644 app/serializers/rest/appeal_serializer.rb

diff --git a/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx
new file mode 100644
index 000000000..02ae9b371
--- /dev/null
+++ b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx
@@ -0,0 +1,78 @@
+import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
+
+import WarningIcon from '@/material-icons/400-24px/warning-fill.svg?react';
+import { Icon } from 'mastodon/components/icon';
+
+// This needs to be kept in sync with app/models/account_warning.rb
+const messages = defineMessages({
+  none: {
+    id: 'notification.moderation_warning.action_none',
+    defaultMessage: 'Your account has received a moderation warning.',
+  },
+  disable: {
+    id: 'notification.moderation_warning.action_disable',
+    defaultMessage: 'Your account has been disabled.',
+  },
+  mark_statuses_as_sensitive: {
+    id: 'notification.moderation_warning.action_mark_statuses_as_sensitive',
+    defaultMessage: 'Some of your posts have been marked as sensitive.',
+  },
+  delete_statuses: {
+    id: 'notification.moderation_warning.action_delete_statuses',
+    defaultMessage: 'Some of your posts have been removed.',
+  },
+  sensitive: {
+    id: 'notification.moderation_warning.action_sensitive',
+    defaultMessage: 'Your posts will be marked as sensitive from now on.',
+  },
+  silence: {
+    id: 'notification.moderation_warning.action_silence',
+    defaultMessage: 'Your account has been limited.',
+  },
+  suspend: {
+    id: 'notification.moderation_warning.action_suspend',
+    defaultMessage: 'Your account has been suspended.',
+  },
+});
+
+interface Props {
+  action:
+    | 'none'
+    | 'disable'
+    | 'mark_statuses_as_sensitive'
+    | 'delete_statuses'
+    | 'sensitive'
+    | 'silence'
+    | 'suspend';
+  id: string;
+  hidden: boolean;
+}
+
+export const ModerationWarning: React.FC<Props> = ({ action, id, hidden }) => {
+  const intl = useIntl();
+
+  if (hidden) {
+    return null;
+  }
+
+  return (
+    <a
+      href={`/disputes/strikes/${id}`}
+      target='_blank'
+      rel='noopener noreferrer'
+      className='notification__moderation-warning'
+    >
+      <Icon id='warning' icon={WarningIcon} />
+
+      <div className='notification__moderation-warning__content'>
+        <p>{intl.formatMessage(messages[action])}</p>
+        <span className='link-button'>
+          <FormattedMessage
+            id='notification.moderation-warning.learn_more'
+            defaultMessage='Learn more'
+          />
+        </span>
+      </div>
+    </a>
+  );
+};
diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx
index c09155462..caf7f9bdc 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.jsx
+++ b/app/javascript/mastodon/features/notifications/components/notification.jsx
@@ -26,6 +26,7 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 
 import FollowRequestContainer from '../containers/follow_request_container';
 
+import { ModerationWarning } from './moderation_warning';
 import { RelationshipsSeveranceEvent } from './relationships_severance_event';
 import Report from './report';
 
@@ -40,6 +41,7 @@ const messages = defineMessages({
   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}' },
+  moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'Your have received a moderation warning' },
 });
 
 const notificationForScreenReader = (intl, message, timestamp) => {
@@ -383,6 +385,27 @@ class Notification extends ImmutablePureComponent {
     );
   }
 
+  renderModerationWarning (notification) {
+    const { intl, unread, hidden } = this.props;
+    const warning = notification.get('moderation_warning');
+
+    if (!warning) {
+      return null;
+    }
+
+    return (
+      <HotKeys handlers={this.getHandlers()}>
+        <div className={classNames('notification notification-moderation-warning focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.moderationWarning), notification.get('created_at'))}>
+          <ModerationWarning
+            action={warning.get('action')}
+            id={warning.get('id')}
+            hidden={hidden}
+          />
+        </div>
+      </HotKeys>
+    );
+  }
+
   renderAdminSignUp (notification, account, link) {
     const { intl, unread } = this.props;
 
@@ -456,6 +479,8 @@ class Notification extends ImmutablePureComponent {
       return this.renderPoll(notification, account);
     case 'severed_relationships':
       return this.renderRelationshipsSevered(notification);
+    case 'moderation_warning':
+      return this.renderModerationWarning(notification);
     case 'admin.sign_up':
       return this.renderAdminSignUp(notification, account, link);
     case 'admin.report':
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index a1b79881c..9d127b6b0 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -473,6 +473,15 @@
   "notification.follow": "{name} followed you",
   "notification.follow_request": "{name} has requested to follow you",
   "notification.mention": "{name} mentioned you",
+  "notification.moderation-warning.learn_more": "Learn more",
+  "notification.moderation_warning": "Your have received a moderation warning",
+  "notification.moderation_warning.action_delete_statuses": "Some of your posts have been removed.",
+  "notification.moderation_warning.action_disable": "Your account has been disabled.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Some of your posts have been marked as sensitive.",
+  "notification.moderation_warning.action_none": "Your account has received a moderation warning.",
+  "notification.moderation_warning.action_sensitive": "Your posts will be marked as sensitive from now on.",
+  "notification.moderation_warning.action_silence": "Your account has been limited.",
+  "notification.moderation_warning.action_suspend": "Your account has been suspended.",
   "notification.own_poll": "Your poll has ended",
   "notification.poll": "A poll you have voted in has ended",
   "notification.reblog": "{name} boosted your post",
diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js
index 7230fabca..64cddcb66 100644
--- a/app/javascript/mastodon/reducers/notifications.js
+++ b/app/javascript/mastodon/reducers/notifications.js
@@ -56,6 +56,7 @@ export const notificationToMap = notification => ImmutableMap({
   status: notification.status ? notification.status.id : null,
   report: notification.report ? fromJS(notification.report) : null,
   event: notification.event ? fromJS(notification.event) : null,
+  moderation_warning: notification.moderation_warning ? fromJS(notification.moderation_warning) : null,
 });
 
 const normalizeNotification = (state, notification, usePendingItems) => {
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index a1864a456..9cb03bedf 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2180,7 +2180,8 @@ a.account__display-name {
   }
 }
 
-.notification__relationships-severance-event {
+.notification__relationships-severance-event,
+.notification__moderation-warning {
   display: flex;
   gap: 16px;
   color: $secondary-text-color;
diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb
index 2b5560e2e..3700ce4cd 100644
--- a/app/models/admin/account_action.rb
+++ b/app/models/admin/account_action.rb
@@ -52,7 +52,7 @@ class Admin::AccountAction
       process_reports!
     end
 
-    process_email!
+    process_notification!
     process_queue!
   end
 
@@ -158,8 +158,11 @@ class Admin::AccountAction
     queue_suspension_worker! if type == 'suspend'
   end
 
-  def process_email!
-    UserMailer.warning(target_account.user, warning).deliver_later! if warnable?
+  def process_notification!
+    return unless warnable?
+
+    UserMailer.warning(target_account.user, warning).deliver_later!
+    LocalNotificationWorker.perform_async(target_account.id, warning.id, 'AccountWarning', 'moderation_warning')
   end
 
   def warnable?
diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb
index 8a8e2fa37..4a1000193 100644
--- a/app/models/admin/status_batch_action.rb
+++ b/app/models/admin/status_batch_action.rb
@@ -65,7 +65,8 @@ class Admin::StatusBatchAction
       statuses.each { |status| Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true) } unless target_account.local?
     end
 
-    UserMailer.warning(target_account.user, @warning).deliver_later! if warnable?
+    process_notification!
+
     RemovalWorker.push_bulk(status_ids) { |status_id| [status_id, { 'preserve' => target_account.local?, 'immediate' => !target_account.local? }] }
   end
 
@@ -101,7 +102,7 @@ class Admin::StatusBatchAction
       text: text
     )
 
-    UserMailer.warning(target_account.user, @warning).deliver_later! if warnable?
+    process_notification!
   end
 
   def handle_report!
@@ -127,6 +128,13 @@ class Admin::StatusBatchAction
     !report.nil?
   end
 
+  def process_notification!
+    return unless warnable?
+
+    UserMailer.warning(target_account.user, @warning).deliver_later!
+    LocalNotificationWorker.perform_async(target_account.id, @warning.id, 'AccountWarning', 'moderation_warning')
+  end
+
   def warnable?
     send_email_notification && target_account.local?
   end
diff --git a/app/models/notification.rb b/app/models/notification.rb
index b2376c78a..7e0e62683 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -57,6 +57,9 @@ class Notification < ApplicationRecord
     severed_relationships: {
       filterable: false,
     }.freeze,
+    moderation_warning: {
+      filterable: false,
+    }.freeze,
     'admin.sign_up': {
       filterable: false,
     }.freeze,
@@ -90,6 +93,7 @@ class Notification < ApplicationRecord
     belongs_to :poll, inverse_of: false
     belongs_to :report, inverse_of: false
     belongs_to :account_relationship_severance_event, inverse_of: false
+    belongs_to :account_warning, inverse_of: false
   end
 
   validates :type, inclusion: { in: TYPES }
@@ -180,7 +184,7 @@ class Notification < ApplicationRecord
     return unless new_record?
 
     case activity_type
-    when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report'
+    when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report', 'AccountWarning'
       self.from_account_id = activity&.account_id
     when 'Mention'
       self.from_account_id = activity&.status&.account_id
diff --git a/app/serializers/rest/account_warning_serializer.rb b/app/serializers/rest/account_warning_serializer.rb
new file mode 100644
index 000000000..a0ef341d2
--- /dev/null
+++ b/app/serializers/rest/account_warning_serializer.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class REST::AccountWarningSerializer < ActiveModel::Serializer
+  attributes :id, :action, :text, :status_ids, :created_at
+
+  has_one :target_account, serializer: REST::AccountSerializer
+  has_one :appeal, serializer: REST::AppealSerializer
+
+  def id
+    object.id.to_s
+  end
+
+  def status_ids
+    object&.status_ids&.map(&:to_s)
+  end
+end
diff --git a/app/serializers/rest/appeal_serializer.rb b/app/serializers/rest/appeal_serializer.rb
new file mode 100644
index 000000000..a24cabc27
--- /dev/null
+++ b/app/serializers/rest/appeal_serializer.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class REST::AppealSerializer < ActiveModel::Serializer
+  attributes :text, :state
+
+  def state
+    if object.approved?
+      'approved'
+    elsif object.rejected?
+      'rejected'
+    else
+      'pending'
+    end
+  end
+end
diff --git a/app/serializers/rest/notification_serializer.rb b/app/serializers/rest/notification_serializer.rb
index 36a0adfec..417245d19 100644
--- a/app/serializers/rest/notification_serializer.rb
+++ b/app/serializers/rest/notification_serializer.rb
@@ -7,6 +7,7 @@ class REST::NotificationSerializer < ActiveModel::Serializer
   belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer
   belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer
   belongs_to :account_relationship_severance_event, key: :event, if: :relationship_severance_event?, serializer: REST::AccountRelationshipSeveranceEventSerializer
+  belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer
 
   def id
     object.id.to_s
@@ -23,4 +24,8 @@ class REST::NotificationSerializer < ActiveModel::Serializer
   def relationship_severance_event?
     object.type == :severed_relationships
   end
+
+  def moderation_warning_event?
+    object.type == :moderation_warning
+  end
 end
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index c83e4c017..e56562c0a 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -9,6 +9,7 @@ class NotifyService < BaseService
     update
     poll
     status
+    moderation_warning
     # TODO: this probably warrants an email notification
     severed_relationships
   ).freeze
@@ -22,7 +23,7 @@ class NotifyService < BaseService
 
     def dismiss?
       blocked   = @recipient.unavailable?
-      blocked ||= from_self? && @notification.type != :poll && @notification.type != :severed_relationships
+      blocked ||= from_self? && %i(poll severed_relationships moderation_warning).exclude?(@notification.type)
 
       return blocked if message? && from_staff?
 
@@ -75,6 +76,7 @@ class NotifyService < BaseService
       admin.report
       poll
       update
+      account_warning
     ).freeze
 
     def initialize(notification)
diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb
index 9bc9f8061..a9dcf352d 100644
--- a/spec/models/admin/account_action_spec.rb
+++ b/spec/models/admin/account_action_spec.rb
@@ -69,22 +69,22 @@ RSpec.describe Admin::AccountAction do
       end
     end
 
-    it 'creates Admin::ActionLog' do
+    it 'sends notification, log the action, and closes other reports', :aggregate_failures do
+      other_report = Fabricate(:report, target_account: target_account)
+
+      emails = []
       expect do
-        subject
-      end.to change(Admin::ActionLog, :count).by 1
-    end
+        emails = capture_emails { subject }
+      end.to (change(Admin::ActionLog.where(action: type), :count).by 1)
+         .and(change { other_report.reload.action_taken? }.from(false).to(true))
 
-    it 'calls process_email!' do
-      allow(account_action).to receive(:process_email!)
-      subject
-      expect(account_action).to have_received(:process_email!)
-    end
+      expect(emails).to contain_exactly(
+        have_attributes(
+          to: contain_exactly(target_account.user.email)
+        )
+      )
 
-    it 'calls process_reports!' do
-      allow(account_action).to receive(:process_reports!)
-      subject
-      expect(account_action).to have_received(:process_reports!)
+      expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(target_account.id, anything, 'AccountWarning', 'moderation_warning')
     end
   end
 

From 5201882a2389bbd3477440509fe12b2019edb4e7 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 26 Apr 2024 12:05:18 +0200
Subject: [PATCH 223/223] New Crowdin Translations (automated) (#30077)

Co-authored-by: GitHub Actions <noreply@github.com>
---
 app/javascript/mastodon/locales/ca.json    |  4 ++++
 app/javascript/mastodon/locales/da.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/de.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/eu.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/fi.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/fo.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/gd.json    |  4 ++++
 app/javascript/mastodon/locales/gl.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/he.json    |  4 ++++
 app/javascript/mastodon/locales/hu.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/is.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/it.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/nl.json    | 15 ++++++++++++++-
 app/javascript/mastodon/locales/nn.json    |  9 +++++++++
 app/javascript/mastodon/locales/pl.json    | 13 +++++++++++++
 app/javascript/mastodon/locales/pt-PT.json | 13 +++++++++++++
 app/javascript/mastodon/locales/sv.json    |  6 +++++-
 app/javascript/mastodon/locales/zh-CN.json | 13 +++++++++++++
 app/javascript/mastodon/locales/zh-TW.json | 13 +++++++++++++
 config/locales/de.yml                      |  4 ++--
 config/locales/doorkeeper.pt-PT.yml        |  1 +
 21 files changed, 212 insertions(+), 4 deletions(-)

diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 40d9771df..6dfe06a92 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Tot i que el teu compte no està blocat, el personal de {domain} ha pensat que és possible que vulguis revisar manualment les sol·licituds de seguiment d’aquests comptes.",
   "follow_suggestions.curated_suggestion": "Tria de l'equip",
   "follow_suggestions.dismiss": "No ho tornis a mostrar",
+  "follow_suggestions.featured_longer": "Triat personalment per l'equip de {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Popular entre la gent que segueixes",
   "follow_suggestions.hints.featured": "L'equip de {domain} ha seleccionat aquest perfil.",
   "follow_suggestions.hints.friends_of_friends": "Aquest perfil és popular entre la gent que seguiu.",
   "follow_suggestions.hints.most_followed": "Aquest perfil és un dels més seguits a {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Aquest perfil és similar a d'altres que heu seguit recentment.",
   "follow_suggestions.personalized_suggestion": "Suggeriment personalitzat",
   "follow_suggestions.popular_suggestion": "Suggeriment popular",
+  "follow_suggestions.popular_suggestion_longer": "Popular a {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que has seguit fa poc",
   "follow_suggestions.view_all": "Mostra-ho tot",
   "follow_suggestions.who_to_follow": "A qui seguir",
   "followed_tags": "Etiquetes seguides",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index a7c8a049e..a23d53733 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -306,6 +306,8 @@
   "follow_requests.unlocked_explanation": "Selvom din konto ikke er låst, synes {domain}-personalet, du måske bør gennemgå disse anmodninger manuelt.",
   "follow_suggestions.curated_suggestion": "Personaleudvalgt",
   "follow_suggestions.dismiss": "Vis ikke igen",
+  "follow_suggestions.featured_longer": "Håndplukket af {domain}-teamet",
+  "follow_suggestions.friends_of_friends_longer": "Populært blandt personer, som følges",
   "follow_suggestions.hints.featured": "Denne profil er håndplukket af {domain}-teamet.",
   "follow_suggestions.hints.friends_of_friends": "Denne profil er populær blandt de personer, som følges.",
   "follow_suggestions.hints.most_followed": "Denne profil er en af de mest fulgte på {domain}.",
@@ -313,6 +315,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Denne profil svarer til de profiler, som senest er blevet fulgt.",
   "follow_suggestions.personalized_suggestion": "Personligt forslag",
   "follow_suggestions.popular_suggestion": "Populært forslag",
+  "follow_suggestions.popular_suggestion_longer": "Populært på {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Svarende til profiler, som for nylig er fulgt",
   "follow_suggestions.view_all": "Vis alle",
   "follow_suggestions.who_to_follow": "Hvem, som skal følges",
   "followed_tags": "Hashtag, som følges",
@@ -467,6 +471,15 @@
   "notification.follow": "{name} begyndte at følge dig",
   "notification.follow_request": "{name} har anmodet om at følge dig",
   "notification.mention": "{name} nævnte dig",
+  "notification.moderation-warning.learn_more": "Læs mere",
+  "notification.moderation_warning": "Du er tildelt en moderationsadvarsel",
+  "notification.moderation_warning.action_delete_statuses": "Nogle af dine indlæg er blevet fjernet.",
+  "notification.moderation_warning.action_disable": "Din konto er blevet deaktiveret.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nogle af dine indlæg er blevet markeret som sensitive.",
+  "notification.moderation_warning.action_none": "Din konto er tildelt en moderationsadvarsel.",
+  "notification.moderation_warning.action_sensitive": "Dine indlæg markeres fra nu af som sensitive.",
+  "notification.moderation_warning.action_silence": "Din konto er blevet begrænset.",
+  "notification.moderation_warning.action_suspend": "Din konto er suspenderet.",
   "notification.own_poll": "Din afstemning er afsluttet",
   "notification.poll": "En afstemning, hvori du stemte, er slut",
   "notification.reblog": "{name} boostede dit indlæg",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 8b52cdb3c..59d3d0965 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Auch wenn dein Konto öffentlich bzw. nicht geschützt ist, haben die Moderator*innen von {domain} gedacht, dass du diesen Follower lieber manuell bestätigen solltest.",
   "follow_suggestions.curated_suggestion": "Vom Server-Team empfohlen",
   "follow_suggestions.dismiss": "Nicht mehr anzeigen",
+  "follow_suggestions.featured_longer": "Vom {domain}-Team ausgewählt",
+  "follow_suggestions.friends_of_friends_longer": "Beliebt bei Leuten, denen du folgst",
   "follow_suggestions.hints.featured": "Dieses Profil wurde vom {domain}-Team ausgewählt.",
   "follow_suggestions.hints.friends_of_friends": "Dieses Profil ist bei deinen Followern beliebt.",
   "follow_suggestions.hints.most_followed": "Dieses Profil ist eines der am meisten gefolgten auf {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Dieses Profil ähnelt den Profilen, denen du in letzter Zeit gefolgt hast.",
   "follow_suggestions.personalized_suggestion": "Persönliche Empfehlung",
   "follow_suggestions.popular_suggestion": "Beliebte Empfehlung",
+  "follow_suggestions.popular_suggestion_longer": "Beliebt auf {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Ähnlich zu Profilen, denen du seit kurzem folgst",
   "follow_suggestions.view_all": "Alle anzeigen",
   "follow_suggestions.who_to_follow": "Empfohlene Profile",
   "followed_tags": "Gefolgte Hashtags",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} folgt dir",
   "notification.follow_request": "{name} möchte dir folgen",
   "notification.mention": "{name} erwähnte dich",
+  "notification.moderation-warning.learn_more": "Mehr erfahren",
+  "notification.moderation_warning": "Du wurdest von den Moderator*innen verwarnt",
+  "notification.moderation_warning.action_delete_statuses": "Einige deiner Beiträge sind entfernt worden.",
+  "notification.moderation_warning.action_disable": "Dein Konto wurde deaktiviert.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Einige deiner Beiträge wurden mit einer Inhaltswarnung versehen.",
+  "notification.moderation_warning.action_none": "Dein Konto ist von den Moderator*innen verwarnt worden.",
+  "notification.moderation_warning.action_sensitive": "Deine zukünftigen Beiträge werden mit einer Inhaltswarnung versehen.",
+  "notification.moderation_warning.action_silence": "Dein Konto wurde eingeschränkt.",
+  "notification.moderation_warning.action_suspend": "Dein Konto wurde gesperrt.",
   "notification.own_poll": "Deine Umfrage ist beendet",
   "notification.poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
   "notification.reblog": "{name} teilte deinen Beitrag",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 7e2ecf69c..9fae07487 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Zure kontua blokeatuta ez badago ere, {domain} domeinuko arduradunek uste dute kontu hauetako jarraipen eskaerak agian eskuz begiratu nahiko dituzula.",
   "follow_suggestions.curated_suggestion": "Domeinuaren iradokizuna",
   "follow_suggestions.dismiss": "Ez erakutsi berriro",
+  "follow_suggestions.featured_longer": "{domain} domeinuko taldeak hautaturikoak",
+  "follow_suggestions.friends_of_friends_longer": "Jarraitzen duzun jendearen artean ezagunak direnak",
   "follow_suggestions.hints.featured": "Profil hau {domain} domeinuko taldeak eskuz aukeratu du.",
   "follow_suggestions.hints.friends_of_friends": "Profil hau ezaguna da jarraitzen duzun jendearen artean.",
   "follow_suggestions.hints.most_followed": "Profil hau {domain} domeinuan gehien jarraitzen den profiletako bat da.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Profil hau duela gutxi jarraitu dituzun profil askoren antzekoa da.",
   "follow_suggestions.personalized_suggestion": "Iradokizun pertsonalizatua",
   "follow_suggestions.popular_suggestion": "Iradokizun ezaguna",
+  "follow_suggestions.popular_suggestion_longer": "{domain} domeinuan ezagunak direnak",
+  "follow_suggestions.similar_to_recently_followed_longer": "Berriki jarraitu dituzun profilen antzekoa",
   "follow_suggestions.view_all": "Ikusi denak",
   "follow_suggestions.who_to_follow": "Zein jarraitu",
   "followed_tags": "Jarraitutako traolak",
@@ -469,6 +473,15 @@
   "notification.follow": "{name}(e)k jarraitzen dizu",
   "notification.follow_request": "{name}(e)k zu jarraitzeko eskaera egin du",
   "notification.mention": "{name}(e)k aipatu zaitu",
+  "notification.moderation-warning.learn_more": "Informazio gehiago",
+  "notification.moderation_warning": "Moderazio-abisu bat jaso duzu",
+  "notification.moderation_warning.action_delete_statuses": "Argitalpen batzuk kendu dira.",
+  "notification.moderation_warning.action_disable": "Zure kontua desaktibatua izan da.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Argitalpen batzuk hunkigarri gisa ezarri dira.",
+  "notification.moderation_warning.action_none": "Kontuak moderazio-abisu bat jaso du.",
+  "notification.moderation_warning.action_sensitive": "Argitalpenak hunkigarri gisa markatuko dira hemendik aurrera.",
+  "notification.moderation_warning.action_silence": "Kontua murriztu egin da.",
+  "notification.moderation_warning.action_suspend": "Kontua itxi da.",
   "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",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 246bb56fc..5a5031fd1 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, palvelimen {domain} ylläpito on arvioinut, että saatat olla halukas tarkistamaan nämä seuraamispyynnöt erikseen.",
   "follow_suggestions.curated_suggestion": "Ehdotus ylläpidolta",
   "follow_suggestions.dismiss": "Älä näytä uudelleen",
+  "follow_suggestions.featured_longer": "Käsin valinnut palvelimen {domain} tiimi",
+  "follow_suggestions.friends_of_friends_longer": "Suosittu seuraamiesi ihmisten keskuudessa",
   "follow_suggestions.hints.featured": "Tämän profiilin on valinnut palvelimen {domain} tiimi.",
   "follow_suggestions.hints.friends_of_friends": "Seuraamasi käyttäjät suosivat tätä profiilia.",
   "follow_suggestions.hints.most_followed": "Tämä profiili on palvelimen {domain} seuratuimpia.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Tämä profiili on samankaltainen kuin profiilit, joita olet viimeksi seurannut.",
   "follow_suggestions.personalized_suggestion": "Mukautettu ehdotus",
   "follow_suggestions.popular_suggestion": "Suosittu ehdotus",
+  "follow_suggestions.popular_suggestion_longer": "Suosittu palvelimella {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Samankaltainen kuin äskettäin seuraamasi profiilit",
   "follow_suggestions.view_all": "Näytä kaikki",
   "follow_suggestions.who_to_follow": "Ehdotuksia seurattavaksi",
   "followed_tags": "Seuratut aihetunnisteet",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} seurasi sinua",
   "notification.follow_request": "{name} on pyytänyt lupaa saada seurata sinua",
   "notification.mention": "{name} mainitsi sinut",
+  "notification.moderation-warning.learn_more": "Lue lisää",
+  "notification.moderation_warning": "Olet saanut moderointivaroituksen",
+  "notification.moderation_warning.action_delete_statuses": "Jotkin julkaisusi on poistettu.",
+  "notification.moderation_warning.action_disable": "Tilisi on poistettu käytöstä.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Jotkin julkaisusi on merkitty arkaluonteisiksi.",
+  "notification.moderation_warning.action_none": "Tilisi on saanut moderointivaroituksen.",
+  "notification.moderation_warning.action_sensitive": "Tästä lähtien julkaisusi merkitään arkaluonteisiksi.",
+  "notification.moderation_warning.action_silence": "Tiliäsi on rajoitettu.",
+  "notification.moderation_warning.action_suspend": "Tilisi on jäädytetty.",
   "notification.own_poll": "Äänestyksesi on päättynyt",
   "notification.poll": "Kysely, johon osallistuit, on päättynyt",
   "notification.reblog": "{name} tehosti julkaisuasi",
diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json
index 68faf6d81..77257413f 100644
--- a/app/javascript/mastodon/locales/fo.json
+++ b/app/javascript/mastodon/locales/fo.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Sjálvt um konta tín ikki er læst, so hugsa {domain} starvsfólkini, at tú kanska hevur hug at kanna umbønir um at fylgja frá hesum kontum við hond.",
   "follow_suggestions.curated_suggestion": "Val hjá ábyrgdarfólki",
   "follow_suggestions.dismiss": "Lat vera við at vísa",
+  "follow_suggestions.featured_longer": "Vald burturúr av {domain} toyminum",
+  "follow_suggestions.friends_of_friends_longer": "Vælumtókt millum fólk, sum tú fylgir",
   "follow_suggestions.hints.featured": "Hesin vangin er úrvaldur av toyminum handan {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Hesin vangin er vælumtóktur millum tey, tú fylgir.",
   "follow_suggestions.hints.most_followed": "Hesin vangin er ein av teimum, sum er mest fylgdur á {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Hesin vangin líkist teimum, sum tú nýliga hevur fylgt.",
   "follow_suggestions.personalized_suggestion": "Persónligt uppskot",
   "follow_suggestions.popular_suggestion": "Vælumtókt uppskot",
+  "follow_suggestions.popular_suggestion_longer": "Vælumtókt á {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Líkist vangum, sum tú nýliga hevur fylgt",
   "follow_suggestions.view_all": "Vís øll",
   "follow_suggestions.who_to_follow": "Hvørji tú átti at fylgt",
   "followed_tags": "Fylgd frámerki",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} fylgdi tær",
   "notification.follow_request": "{name} biður um at fylgja tær",
   "notification.mention": "{name} nevndi teg",
+  "notification.moderation-warning.learn_more": "Lær meira",
+  "notification.moderation_warning": "Tú hevur móttikið eina umsjónarávarðing",
+  "notification.moderation_warning.action_delete_statuses": "Onkrir av tínum postum eru strikaðir.",
+  "notification.moderation_warning.action_disable": "Konta tín er gjørd óvirkin.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nakrir av postum tínum eru merktir sum viðkvæmir.",
+  "notification.moderation_warning.action_none": "Konta tín hevur móttikið eina umsjónarávarðing.",
+  "notification.moderation_warning.action_sensitive": "Postar tínir verða merktir sum viðkvæmir frá nú av.",
+  "notification.moderation_warning.action_silence": "Konta tín er avmarkað.",
+  "notification.moderation_warning.action_suspend": "Konta tín er ógildað.",
   "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",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index 8ab515e1a..9e79793de 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -297,6 +297,7 @@
   "filter_modal.select_filter.subtitle": "Cleachd roinn-seòrsa a tha ann no cruthaich tè ùr",
   "filter_modal.select_filter.title": "Criathraich am post seo",
   "filter_modal.title.status": "Criathraich post",
+  "filtered_notifications_banner.mentions": "{count, plural, one {iomradh} two {iomradh} few {iomraidhean} other {iomradh}}",
   "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.title": "Brathan criathraichte",
   "firehose.all": "Na h-uile",
@@ -307,6 +308,7 @@
   "follow_requests.unlocked_explanation": "Ged nach eil an cunntas agad glaiste, tha sgioba {domain} dhen bheachd gum b’ fheàirrde thu lèirmheas a dhèanamh air na h-iarrtasan leantainn o na cunntasan seo a làimh.",
   "follow_suggestions.curated_suggestion": "Roghainn an sgioba",
   "follow_suggestions.dismiss": "Na seall seo a-rithist",
+  "follow_suggestions.friends_of_friends_longer": "Fèill mhòr am measg nan daoine a leanas tu",
   "follow_suggestions.hints.featured": "Chaidh a’ phròifil seo a thaghadh le sgioba {domain} a làimh.",
   "follow_suggestions.hints.friends_of_friends": "Tha fèill mhòr air a’ phròifil seo am measg nan daoine a leanas tu.",
   "follow_suggestions.hints.most_followed": "Tha a’ phròifil seo am measg an fheadhainn a leanar as trice air {domain}.",
@@ -314,6 +316,7 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Tha a’ phròifil seo coltach ris na pròifilean air an lean thu o chionn goirid.",
   "follow_suggestions.personalized_suggestion": "Moladh pearsanaichte",
   "follow_suggestions.popular_suggestion": "Moladh air a bheil fèill mhòr",
+  "follow_suggestions.popular_suggestion_longer": "Fèill mhòr air {domain}",
   "follow_suggestions.view_all": "Seall na h-uile",
   "follow_suggestions.who_to_follow": "Molaidhean leantainn",
   "followed_tags": "Tagaichean hais ’gan leantainn",
@@ -468,6 +471,7 @@
   "notification.follow": "Tha {name} ’gad leantainn a-nis",
   "notification.follow_request": "Dh’iarr {name} ’gad leantainn",
   "notification.mention": "Thug {name} iomradh ort",
+  "notification.moderation-warning.learn_more": "Barrachd fiosrachaidh",
   "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",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 901bca749..49802ac48 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Malia que a túa conta non é privada, a administración de {domain} pensou que quizabes terías que revisar de xeito manual as solicitudes de seguiminto.",
   "follow_suggestions.curated_suggestion": "Suxestións do Servidor",
   "follow_suggestions.dismiss": "Non mostrar máis",
+  "follow_suggestions.featured_longer": "Elección persoal do equipo de {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Popular entre as persoas que sigues",
   "follow_suggestions.hints.featured": "Este perfil foi escollido pola administración de {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as persoas que segues.",
   "follow_suggestions.hints.most_followed": "Este perfil é un dos máis seguidos en {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Este perfil ten semellanzas cos perfís que ti seguiches últimamente.",
   "follow_suggestions.personalized_suggestion": "Suxestión personalizada",
   "follow_suggestions.popular_suggestion": "Suxestión popular",
+  "follow_suggestions.popular_suggestion_longer": "Popular en {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Perfís semellantes aos que seguiches recentemente",
   "follow_suggestions.view_all": "Ver todas",
   "follow_suggestions.who_to_follow": "A quen seguir",
   "followed_tags": "Cancelos seguidos",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} comezou a seguirte",
   "notification.follow_request": "{name} solicitou seguirte",
   "notification.mention": "{name} mencionoute",
+  "notification.moderation-warning.learn_more": "Saber máis",
+  "notification.moderation_warning": "Recibiches unha advertencia da moderación",
+  "notification.moderation_warning.action_delete_statuses": "Algunha das túas publicacións foron eliminadas.",
+  "notification.moderation_warning.action_disable": "A túa conta foi desactivada.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algunha das túas publicacións foron marcadas como sensibles.",
+  "notification.moderation_warning.action_none": "A túa conta recibeu unha advertencia da moderación.",
+  "notification.moderation_warning.action_sensitive": "De agora en diante as túas publicacións van ser marcadas como sensibles.",
+  "notification.moderation_warning.action_silence": "A túa conta foi limitada.",
+  "notification.moderation_warning.action_suspend": "A túa conta foi suspendida.",
   "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",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index d696186bf..0b66a27fa 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "למרות שחשבונך אינו נעול, צוות {domain} חושב שאולי כדאי לוודא את בקשות המעקב האלה ידנית.",
   "follow_suggestions.curated_suggestion": "בחירת הצוות",
   "follow_suggestions.dismiss": "לא להציג שוב",
+  "follow_suggestions.featured_longer": "נבחר ידנית על ידי הצוות של {domain}",
+  "follow_suggestions.friends_of_friends_longer": "פופולרי בין הנעקבים שלך",
   "follow_suggestions.hints.featured": "החשבון הזה נבחר אישית על ידי צוות {domain}.",
   "follow_suggestions.hints.friends_of_friends": "חשבון זה פופולרי בין הנעקבים שלך.",
   "follow_suggestions.hints.most_followed": "חשבון זה הוא מבין הנעקבים ביותר בשרת {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "חשבון זה דומה לחשבונות אחרים שאחריהם התחלת לעקוב לאחרונה.",
   "follow_suggestions.personalized_suggestion": "הצעות מותאמות אישית",
   "follow_suggestions.popular_suggestion": "הצעה פופולרית",
+  "follow_suggestions.popular_suggestion_longer": "פופולרי בקהילת {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "דומה למשתמשות.ים שעקבת אחריהן.ם לאחרונה",
   "follow_suggestions.view_all": "צפיה בכל",
   "follow_suggestions.who_to_follow": "אחרי מי לעקוב",
   "followed_tags": "התגיות שהחשבון שלך עוקב אחריהן",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 16dcea642..42ce84258 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni ezen fiókok követési kéréseit.",
   "follow_suggestions.curated_suggestion": "A stáb választása",
   "follow_suggestions.dismiss": "Ne jelenjen meg újra",
+  "follow_suggestions.featured_longer": "A {domain} csapata által kézzel kiválasztott",
+  "follow_suggestions.friends_of_friends_longer": "Népszerű az Ön által követett emberek körében",
   "follow_suggestions.hints.featured": "Ezt a profilt a(z) {domain} csapata választotta ki.",
   "follow_suggestions.hints.friends_of_friends": "Ez a profil népszerű az általad követett emberek körében.",
   "follow_suggestions.hints.most_followed": "Ez a profil a leginkább követett a(z) {domain} oldalon.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Ez a profil hasonló azokhoz a profilokhoz, melyeket nemrég kezdtél el követni.",
   "follow_suggestions.personalized_suggestion": "Személyre szabott javaslat",
   "follow_suggestions.popular_suggestion": "Népszerű javaslat",
+  "follow_suggestions.popular_suggestion_longer": "Népszerű itt: {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Hasonló profilok, melyeket nemrég követett",
   "follow_suggestions.view_all": "Összes megtekintése",
   "follow_suggestions.who_to_follow": "Kit érdemes követni",
   "followed_tags": "Követett hashtagek",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} követ téged",
   "notification.follow_request": "{name} követni szeretne téged",
   "notification.mention": "{name} megemlített",
+  "notification.moderation-warning.learn_more": "További információk",
+  "notification.moderation_warning": "Moderációs figyelmeztetést kaptál",
+  "notification.moderation_warning.action_delete_statuses": "Néhány bejegyzésedet eltávolították.",
+  "notification.moderation_warning.action_disable": "A fiókod le van tiltva.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Néhány bejegyzésedet kényesnek jelölték.",
+  "notification.moderation_warning.action_none": "A fiókod moderációs figyelmeztetést kapott.",
+  "notification.moderation_warning.action_sensitive": "A bejegyzéseid mostantól érzékenynek lesznek jelölve.",
+  "notification.moderation_warning.action_silence": "A fiókod korlátozásra került.",
+  "notification.moderation_warning.action_suspend": "A fiókod felfüggesztésre került.",
   "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",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index 435f98f30..f5bf7c328 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Jafnvel þótt aðgangurinn þinn sé ekki læstur, hafa umsjónarmenn {domain} ímyndað sér að þú gætir viljað yfirfara handvirkt fylgjendabeiðnir frá þessum notendum.",
   "follow_suggestions.curated_suggestion": "Úrval starfsfólks",
   "follow_suggestions.dismiss": "Ekki birta þetta aftur",
+  "follow_suggestions.featured_longer": "Handvalið af {domain}-teyminu",
+  "follow_suggestions.friends_of_friends_longer": "Vinsælt hjá fólki sem þú fylgist með",
   "follow_suggestions.hints.featured": "Þetta notandasnið hefur verið handvalið af {domain}-teyminu.",
   "follow_suggestions.hints.friends_of_friends": "Þetta notandasnið er vinsælt hjá fólki sem þú fylgist með.",
   "follow_suggestions.hints.most_followed": "Þetta notandasnið er eitt af þeim sem mest er fylgst með á {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Þetta notandasnið er líkt þeim sniðum sem þú hefur valið að fylgjast með að undanförnu.",
   "follow_suggestions.personalized_suggestion": "Persónuaðlöguð tillaga",
   "follow_suggestions.popular_suggestion": "Vinsæl tillaga",
+  "follow_suggestions.popular_suggestion_longer": "Vinsælt á {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Svipar til notenda sem þú hefur nýlega farið að fylgjast með",
   "follow_suggestions.view_all": "Skoða allt",
   "follow_suggestions.who_to_follow": "Hverjum á að fylgjast með",
   "followed_tags": "Myllumerki sem fylgst er með",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} fylgist með þér",
   "notification.follow_request": "{name} hefur beðið um að fylgjast með þér",
   "notification.mention": "{name} minntist á þig",
+  "notification.moderation-warning.learn_more": "Kanna nánar",
+  "notification.moderation_warning": "Þú hefur fengið aðvörun frá umsjónarmanni",
+  "notification.moderation_warning.action_delete_statuses": "Sumar færslurnar þínar hafa verið fjarlægðar.",
+  "notification.moderation_warning.action_disable": "Aðgangurinn þinn hefur verið gerður óvirkur.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Sumar færslurnar þínar hafa verið merktar sem viðkvæmt efni.",
+  "notification.moderation_warning.action_none": "Aðgangurinn þinn hefur fengið aðvörun frá umsjónarmanni.",
+  "notification.moderation_warning.action_sensitive": "Færslur þínar á verða héðan í frá merktar sem viðkvæmar.",
+  "notification.moderation_warning.action_silence": "Notandaaðgangurinn þinn hefur verið takmarkaður.",
+  "notification.moderation_warning.action_suspend": "Notandaaðgangurinn þinn hefur verið settur í frysti.",
   "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",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index fcfd09d75..8ab5db1b1 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Anche se il tuo profilo non è privato, lo staff di {domain} ha pensato che potresti voler revisionare manualmente le richieste di seguirti da questi profili.",
   "follow_suggestions.curated_suggestion": "Scelta personale",
   "follow_suggestions.dismiss": "Non visualizzare più",
+  "follow_suggestions.featured_longer": "Selezionato personalmente dal team di {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Popolare tra le persone che segui",
   "follow_suggestions.hints.featured": "Questo profilo è stato selezionato personalmente dal team di {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Questo profilo è popolare tra le persone che segui.",
   "follow_suggestions.hints.most_followed": "Questo profilo è uno dei più seguiti su {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Questo profilo è simile ai profili che hai seguito più recentemente.",
   "follow_suggestions.personalized_suggestion": "Suggerimenti personalizzati",
   "follow_suggestions.popular_suggestion": "Suggerimento frequente",
+  "follow_suggestions.popular_suggestion_longer": "Popolare su {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Simile ai profili che hai seguito di recente",
   "follow_suggestions.view_all": "Vedi tutto",
   "follow_suggestions.who_to_follow": "Chi seguire",
   "followed_tags": "Hashtag seguiti",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} ha iniziato a seguirti",
   "notification.follow_request": "{name} ha richiesto di seguirti",
   "notification.mention": "{name} ti ha menzionato",
+  "notification.moderation-warning.learn_more": "Scopri di più",
+  "notification.moderation_warning": "Hai ricevuto un avviso di moderazione",
+  "notification.moderation_warning.action_delete_statuses": "Alcuni dei tuoi post sono stati rimossi.",
+  "notification.moderation_warning.action_disable": "Il tuo account è stato disattivato.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcuni dei tuoi post sono stati contrassegnati come sensibili.",
+  "notification.moderation_warning.action_none": "Il tuo account ha ricevuto un avviso di moderazione.",
+  "notification.moderation_warning.action_sensitive": "I tuoi post d'ora in poi saranno contrassegnati come sensibili.",
+  "notification.moderation_warning.action_silence": "Il tuo account è stato limitato.",
+  "notification.moderation_warning.action_suspend": "Il tuo account è stato sospeso.",
   "notification.own_poll": "Il tuo sondaggio è terminato",
   "notification.poll": "Un sondaggio in cui hai votato è terminato",
   "notification.reblog": "{name} ha rebloggato il tuo post",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 46d1f9783..1958e4a6a 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -308,13 +308,17 @@
   "follow_requests.unlocked_explanation": "Ook al is jouw account niet besloten, de medewerkers van {domain} denken dat jij misschien de volgende volgverzoeken handmatig wil controleren.",
   "follow_suggestions.curated_suggestion": "Speciaal geselecteerd",
   "follow_suggestions.dismiss": "Niet meer weergeven",
-  "follow_suggestions.hints.featured": "Deze gebruiker is geselecteerd door het team van {domain}.",
+  "follow_suggestions.featured_longer": "Handmatig geselecteerd door het team van {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Populair onder mensen die je volgt",
+  "follow_suggestions.hints.featured": "Deze gebruiker is handmatig geselecteerd door het team van {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Deze gebruiker is populair onder de mensen die jij volgt.",
   "follow_suggestions.hints.most_followed": "Deze gebruiker is een van de meest gevolgde gebruikers op {domain}.",
   "follow_suggestions.hints.most_interactions": "Deze gebruiker is de laatste tijd erg populair op {domain}.",
   "follow_suggestions.hints.similar_to_recently_followed": "Deze gebruiker is vergelijkbaar met gebruikers die je recentelijk hebt gevolgd.",
   "follow_suggestions.personalized_suggestion": "Gepersonaliseerde aanbeveling",
   "follow_suggestions.popular_suggestion": "Populaire aanbeveling",
+  "follow_suggestions.popular_suggestion_longer": "Populair op {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Vergelijkbaar met accounts die je recentelijk bent gaan volgen",
   "follow_suggestions.view_all": "Alles weergeven",
   "follow_suggestions.who_to_follow": "Wie te volgen",
   "followed_tags": "Gevolgde hashtags",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} volgt jou nu",
   "notification.follow_request": "{name} wil jou graag volgen",
   "notification.mention": "{name} vermeldde jou",
+  "notification.moderation-warning.learn_more": "Meer informatie",
+  "notification.moderation_warning": "Je hebt een moderatie-waarschuwing ontvangen",
+  "notification.moderation_warning.action_delete_statuses": "Sommige van je berichten zijn verwijderd.",
+  "notification.moderation_warning.action_disable": "Je account is uitgeschakeld.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Sommige van je berichten zijn gemarkeerd als gevoelig.",
+  "notification.moderation_warning.action_none": "Jouw account heeft een moderatie-waarschuwing ontvangen.",
+  "notification.moderation_warning.action_sensitive": "Je berichten worden vanaf nu als gevoelig gemarkeerd.",
+  "notification.moderation_warning.action_silence": "Jouw account is beperkt.",
+  "notification.moderation_warning.action_suspend": "Jouw account is opgeschort.",
   "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",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index 2cfb0d124..14b355233 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -468,6 +468,15 @@
   "notification.follow": "{name} fylgde deg",
   "notification.follow_request": "{name} har bedt om å fylgja deg",
   "notification.mention": "{name} nemnde deg",
+  "notification.moderation-warning.learn_more": "Lær meir",
+  "notification.moderation_warning": "Du har mottatt ei moderasjonsåtvaring",
+  "notification.moderation_warning.action_delete_statuses": "Nokre av innlegga dine har blitt fjerna.",
+  "notification.moderation_warning.action_disable": "Kontoen din har blitt deaktivert.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nokre av innlegga dine har blitt markert som sensitive.",
+  "notification.moderation_warning.action_none": "Kontoen din har mottatt ei moderasjonsåtvaring.",
+  "notification.moderation_warning.action_sensitive": "Innlegga dine vil bli markerte som sensitive frå no av.",
+  "notification.moderation_warning.action_silence": "Kontoen din har blitt avgrensa.",
+  "notification.moderation_warning.action_suspend": "Kontoen din har blitt suspendert.",
   "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",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 72f1ba58f..b763f740a 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Mimo że Twoje konto nie jest zablokowane, zespół {domain} uznał że możesz chcieć ręcznie przejrzeć prośby o możliwość obserwacji.",
   "follow_suggestions.curated_suggestion": "Wybrane przez personel",
   "follow_suggestions.dismiss": "Nie pokazuj ponownie",
+  "follow_suggestions.featured_longer": "Wybrane przez zespół {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Popularni wśród ludzi których obserwujesz",
   "follow_suggestions.hints.featured": "Ten profil został wybrany przez zespół {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Ten profil jest popularny w gronie użytkowników, których obserwujesz.",
   "follow_suggestions.hints.most_followed": "Ten profil jest jednym z najczęściej obserwowanych na {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Ten profil jest podobny do profili ostatnio przez ciebie zaobserwowanych.",
   "follow_suggestions.personalized_suggestion": "Sugestia spersonalizowana",
   "follow_suggestions.popular_suggestion": "Sugestia popularna",
+  "follow_suggestions.popular_suggestion_longer": "Popularni na {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Podobne do ostatnio zaobserwowanych przez ciebie profilów",
   "follow_suggestions.view_all": "Pokaż wszystkie",
   "follow_suggestions.who_to_follow": "Kogo obserwować",
   "followed_tags": "Obserwowane hasztagi",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} obserwuje Cię",
   "notification.follow_request": "{name} chce cię zaobserwować",
   "notification.mention": "Wspomniało o Tobie przez {name}",
+  "notification.moderation-warning.learn_more": "Dowiedz się więcej",
+  "notification.moderation_warning": "Otrzymałeś/-łaś ostrzeżenie moderacyjne",
+  "notification.moderation_warning.action_delete_statuses": "Niektóre twoje wpisy zostały usunięte.",
+  "notification.moderation_warning.action_disable": "Twoje konto zostało wyłączone.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Niektóre twoje wpisy zostały oznaczone jako wrażliwe.",
+  "notification.moderation_warning.action_none": "Twoje konto otrzymało ostrzeżenie moderacyjne.",
+  "notification.moderation_warning.action_sensitive": "Twoje wpisy będą od teraz oznaczane jako wrażliwe.",
+  "notification.moderation_warning.action_silence": "Twoje konto zostało ograniczone.",
+  "notification.moderation_warning.action_suspend": "Twoje konto zostało zawieszone.",
   "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}",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 7e98cde5f..70903065d 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "Apesar de a sua não ser privada, a administração de {domain} pensa que poderá querer rever manualmente os pedidos de seguimento dessas contas.",
   "follow_suggestions.curated_suggestion": "Escolha da equipe",
   "follow_suggestions.dismiss": "Não mostrar novamente",
+  "follow_suggestions.featured_longer": "Escolhido a dedo pela equipa de {domain}",
+  "follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que segue",
   "follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.",
   "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.",
   "follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos no {domain}.",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu mais recentemente.",
   "follow_suggestions.personalized_suggestion": "Sugestão personalizada",
   "follow_suggestions.popular_suggestion": "Sugestão popular",
+  "follow_suggestions.popular_suggestion_longer": "Popular em {domain}",
+  "follow_suggestions.similar_to_recently_followed_longer": "Semelhantes aos perfis que seguiu recentemente",
   "follow_suggestions.view_all": "Ver tudo",
   "follow_suggestions.who_to_follow": "Quem seguir",
   "followed_tags": "Hashtags seguidas",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} começou a seguir-te",
   "notification.follow_request": "{name} pediu para segui-lo",
   "notification.mention": "{name} mencionou-te",
+  "notification.moderation-warning.learn_more": "Saber mais",
+  "notification.moderation_warning": "Recebeu um aviso de moderação",
+  "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.",
+  "notification.moderation_warning.action_disable": "A sua conta foi desativada.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas das suas publicações foram assinaladas como sensíveis.",
+  "notification.moderation_warning.action_none": "A sua conta recebeu um aviso de moderação.",
+  "notification.moderation_warning.action_sensitive": "As suas publicações serão, a partir de agora, assinaladas como sensíveis.",
+  "notification.moderation_warning.action_silence": "A sua conta foi limitada.",
+  "notification.moderation_warning.action_suspend": "A sua conta foi suspensa.",
   "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",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 2b9f0a51b..c2dd5297d 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -297,7 +297,6 @@
   "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.mentions": "{count, plural, one {mention} other {mentions}}",
   "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner",
   "filtered_notifications_banner.title": "Filtrerade aviseringar",
   "firehose.all": "Allt",
@@ -469,6 +468,11 @@
   "notification.follow": "{name} följer dig",
   "notification.follow_request": "{name} har begärt att följa dig",
   "notification.mention": "{name} nämnde dig",
+  "notification.moderation-warning.learn_more": "Läs mer",
+  "notification.moderation_warning.action_delete_statuses": "Några av dina inlägg har tagits bort.",
+  "notification.moderation_warning.action_disable": "Ditt konto har inaktiverats.",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "Några av dina inlägg har markerats som känsliga.",
+  "notification.moderation_warning.action_silence": "Ditt konto har begränsats.",
   "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",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 83fa72338..ab6fe0bd7 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "尽管你没有锁嘟,但是 {domain} 的工作人员认为你也许会想手动审核审核这些账号的关注请求。",
   "follow_suggestions.curated_suggestion": "站务人员精选",
   "follow_suggestions.dismiss": "不再显示",
+  "follow_suggestions.featured_longer": "由 {domain} 管理团队精选",
+  "follow_suggestions.friends_of_friends_longer": "在你关注的人中很受欢迎",
   "follow_suggestions.hints.featured": "该用户已被 {domain} 管理团队精选。",
   "follow_suggestions.hints.friends_of_friends": "该用户在您关注的人中很受欢迎。",
   "follow_suggestions.hints.most_followed": "该用户是 {domain} 上关注度最高的用户之一。",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "该用户与您最近关注的用户类似。",
   "follow_suggestions.personalized_suggestion": "个性化建议",
   "follow_suggestions.popular_suggestion": "热门建议",
+  "follow_suggestions.popular_suggestion_longer": "在 {domain} 上很受欢迎",
+  "follow_suggestions.similar_to_recently_followed_longer": "与你近期关注的用户相似",
   "follow_suggestions.view_all": "查看全部",
   "follow_suggestions.who_to_follow": "推荐关注",
   "followed_tags": "关注的话题标签",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} 开始关注你",
   "notification.follow_request": "{name} 向你发送了关注请求",
   "notification.mention": "{name} 提及了你",
+  "notification.moderation-warning.learn_more": "了解更多",
+  "notification.moderation_warning": "你收到了一条管理警告",
+  "notification.moderation_warning.action_delete_statuses": "你的一些嘟文已被移除。",
+  "notification.moderation_warning.action_disable": "你的账号已被禁用。",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "你的一些嘟文已被标记为敏感内容。",
+  "notification.moderation_warning.action_none": "你的账号收到了管理警告。",
+  "notification.moderation_warning.action_sensitive": "今后你的嘟文都会被标记为敏感内容。",
+  "notification.moderation_warning.action_silence": "你的账号已被限制。",
+  "notification.moderation_warning.action_suspend": "你的账号已被封禁.",
   "notification.own_poll": "你的投票已经结束",
   "notification.poll": "你参与的一个投票已经结束",
   "notification.reblog": "{name} 转发了你的嘟文",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 33a7070a5..f00d62c07 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -308,6 +308,8 @@
   "follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。",
   "follow_suggestions.curated_suggestion": "精選內容",
   "follow_suggestions.dismiss": "不再顯示",
+  "follow_suggestions.featured_longer": "{domain} 團隊精選",
+  "follow_suggestions.friends_of_friends_longer": "受您跟隨之使用者愛戴的風雲人物",
   "follow_suggestions.hints.featured": "這個個人檔案是 {domain} 管理團隊精心挑選。",
   "follow_suggestions.hints.friends_of_friends": "這個個人檔案於您跟隨的帳號中很受歡迎。",
   "follow_suggestions.hints.most_followed": "這個個人檔案是 {domain} 中最受歡迎的帳號之一。",
@@ -315,6 +317,8 @@
   "follow_suggestions.hints.similar_to_recently_followed": "這個個人檔案與您最近跟隨之帳號類似。",
   "follow_suggestions.personalized_suggestion": "個人化推薦",
   "follow_suggestions.popular_suggestion": "熱門推薦",
+  "follow_suggestions.popular_suggestion_longer": "{domain} 上的人氣王",
+  "follow_suggestions.similar_to_recently_followed_longer": "與您近日跟隨相近之帳號",
   "follow_suggestions.view_all": "檢視全部",
   "follow_suggestions.who_to_follow": "推薦跟隨帳號",
   "followed_tags": "已跟隨主題標籤",
@@ -469,6 +473,15 @@
   "notification.follow": "{name} 已跟隨您",
   "notification.follow_request": "{name} 要求跟隨您",
   "notification.mention": "{name} 已提到您",
+  "notification.moderation-warning.learn_more": "了解更多",
+  "notification.moderation_warning": "您已收到管理員警告",
+  "notification.moderation_warning.action_delete_statuses": "某些您的嘟文已被刪除。",
+  "notification.moderation_warning.action_disable": "您的帳號已被停用。",
+  "notification.moderation_warning.action_mark_statuses_as_sensitive": "某些您的嘟文已被標記為敏感內容。",
+  "notification.moderation_warning.action_none": "您的帳號已收到管理員警告。",
+  "notification.moderation_warning.action_sensitive": "即日起,您的嘟文將會被標記為敏感內容。",
+  "notification.moderation_warning.action_silence": "您的帳號已被限制。",
+  "notification.moderation_warning.action_suspend": "您的帳號已被停權。",
   "notification.own_poll": "您的投票已結束",
   "notification.poll": "您曾投過的投票已經結束",
   "notification.reblog": "{name} 已轉嘟您的嘟文",
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 27073ff9e..923682ea1 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -1449,7 +1449,7 @@ de:
       cooldown: Nach dem Umzug wird es eine Weile dauern, bis du erneut umziehen darfst
       disabled_account: Dein altes Konto ist nur noch eingeschränkt nutzbar. Du kannst jedoch deine Daten exportieren und das Konto wieder reaktivieren.
       followers: Alle Follower werden vom alten zum neuen Konto übertragen
-      only_redirect_html: Alternativ kannst du auch <a href="%{path}">nur eine Weiterleitung zu deinem neuen Profil</a> einrichten, ohne die Follower zu übertragen.
+      only_redirect_html: Alternativ kannst du auch <a href="%{path}">nur eine Weiterleitung zu deinem neuen Konto</a> einrichten, ohne die Follower zu übertragen.
       other_data: Keine anderen Daten werden automatisch zum neuen Konto übertragen
       redirect: Dein altes Konto wird einen Hinweis erhalten, dass du umgezogen bist. Außerdem wird das Profil von Suchanfragen ausgeschlossen
   moderation:
@@ -1845,7 +1845,7 @@ de:
         mark_statuses_as_sensitive: Deine Beiträge von %{acct} wurden mit einer Inhaltswarnung versehen
         none: Warnung für %{acct}
         sensitive: Deine Beiträge von %{acct} werden künftig mit einer Inhaltswarnung versehen
-        silence: Dein Konto %{acct} wurde stummgeschaltet
+        silence: Dein Konto %{acct} wurde eingeschränkt
         suspend: Dein Konto %{acct} wurde gesperrt
       title:
         delete_statuses: Beiträge entfernt
diff --git a/config/locales/doorkeeper.pt-PT.yml b/config/locales/doorkeeper.pt-PT.yml
index 31f6e4627..0457190cd 100644
--- a/config/locales/doorkeeper.pt-PT.yml
+++ b/config/locales/doorkeeper.pt-PT.yml
@@ -174,6 +174,7 @@ pt-PT:
       read:filters: ver os seus filtros
       read:follows: ver quem você segue
       read:lists: ver as suas listas
+      read:me: ler apenas as informações básicas da sua conta
       read:mutes: ver os utilizadores que silenciou
       read:notifications: ver as suas notificações
       read:reports: ver as suas denúncias