From 7b9ad2c416e549c475bb56a18e85648cd5e58ab7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:28:53 +0200 Subject: [PATCH 01/48] fix(deps): update dependency sass to v1.86.2 (#34358) 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 2437c9a22d..7a8269ed37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15738,8 +15738,8 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.86.1 - resolution: "sass@npm:1.86.1" + version: 1.86.2 + resolution: "sass@npm:1.86.2" dependencies: "@parcel/watcher": "npm:^2.4.1" chokidar: "npm:^4.0.0" @@ -15750,7 +15750,7 @@ __metadata: optional: true bin: sass: sass.js - checksum: 10c0/16733c7cd7ebb180d12c7aa8fdf4647de857901ab55c369f810b3654aa1c4cd61bb0274981d7792f0ccdfb29755aab17afc13c9daad69d8ffc4d761a8314c93a + checksum: 10c0/fe40b63a19e867f460369d495bcdc979598c0b105c9d52164a7e9cc4e12ab91c27337702a1b58575f7da8fd08256b85fd2f34cc8275eb7c57699bfc5029f54a3 languageName: node linkType: hard From e1d67484229d9cc54a26d6cc90fdbc69ccf3166b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:42:19 +0200 Subject: [PATCH 02/48] New Crowdin Translations (automated) (#34360) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/cs.json | 1 + app/javascript/mastodon/locales/cy.json | 1 + app/javascript/mastodon/locales/da.json | 1 + app/javascript/mastodon/locales/de.json | 1 + app/javascript/mastodon/locales/es-AR.json | 1 + app/javascript/mastodon/locales/es-MX.json | 1 + app/javascript/mastodon/locales/es.json | 1 + app/javascript/mastodon/locales/fi.json | 1 + app/javascript/mastodon/locales/fo.json | 1 + app/javascript/mastodon/locales/gl.json | 1 + app/javascript/mastodon/locales/he.json | 13 ++++-- app/javascript/mastodon/locales/hu.json | 1 + app/javascript/mastodon/locales/is.json | 1 + app/javascript/mastodon/locales/kab.json | 1 + app/javascript/mastodon/locales/nl.json | 1 + app/javascript/mastodon/locales/pt-PT.json | 1 + app/javascript/mastodon/locales/sq.json | 1 + app/javascript/mastodon/locales/uk.json | 1 + app/javascript/mastodon/locales/vi.json | 1 + app/javascript/mastodon/locales/zh-TW.json | 1 + config/locales/he.yml | 38 ++++++++++++++++-- config/locales/lv.yml | 46 ++++++++++++++++++++++ 23 files changed, 110 insertions(+), 7 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index cdf79c8edc..a282796a50 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicació} other {{counter} publicacions}}", "account.unblock": "Desbloca @{name}", "account.unblock_domain": "Desbloca el domini {domain}", + "account.unblock_domain_short": "Desbloca", "account.unblock_short": "Desbloca", "account.unendorse": "No recomanis en el perfil", "account.unfollow": "Deixa de seguir", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index deced039c2..625ea7ce96 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} příspěvek} few {{counter} příspěvky} many {{counter} příspěvků} other {{counter} příspěvků}}", "account.unblock": "Odblokovat @{name}", "account.unblock_domain": "Odblokovat doménu {domain}", + "account.unblock_domain_short": "Odblokovat", "account.unblock_short": "Odblokovat", "account.unendorse": "Nezvýrazňovat na profilu", "account.unfollow": "Přestat sledovat", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index c107cbebe3..27ecc6e8eb 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postiad} two {{counter} bostiad} few {{counter} phostiad} many {{counter} postiad} other {{counter} postiad}}", "account.unblock": "Dadrwystro @{name}", "account.unblock_domain": "Dadrwystro parth {domain}", + "account.unblock_domain_short": "Dadrwystro", "account.unblock_short": "Dadrwystro", "account.unendorse": "Peidio a'i ddangos ar fy mhroffil", "account.unfollow": "Dad-ddilyn", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index c5d7fc66f5..d8695c194c 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} indlæg} other {{counter} indlæg}}", "account.unblock": "Fjern blokering af @{name}", "account.unblock_domain": "Fjern blokering af domænet {domain}", + "account.unblock_domain_short": "Afblokér", "account.unblock_short": "Fjern blokering", "account.unendorse": "Fjern visning på din profil", "account.unfollow": "Følg ikke længere", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index debb2db480..6a14858d11 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}", "account.unblock": "{name} nicht mehr blockieren", "account.unblock_domain": "Blockierung von {domain} aufheben", + "account.unblock_domain_short": "Entsperren", "account.unblock_short": "Blockierung aufheben", "account.unendorse": "Im Profil nicht mehr empfehlen", "account.unfollow": "Entfolgen", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 724fd5d274..2eb96dd5bd 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} mensaje} other {{counter} mensajes}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No destacar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 0fe0f1cad3..dbaf1955e4 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Mostrar a {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No mostrar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 8d6bb4cdbe..be6a0f95ee 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No mostrar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 3e5a327301..4be3211045 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} julkaisu} other {{counter} julkaisua}}", "account.unblock": "Kumoa käyttäjän @{name} esto", "account.unblock_domain": "Kumoa verkkotunnuksen {domain} esto", + "account.unblock_domain_short": "Kumoa esto", "account.unblock_short": "Kumoa esto", "account.unendorse": "Kumoa suosittelu profiilissasi", "account.unfollow": "Älä seuraa", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 06ab07023e..636d32729c 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postur} other {{counter} postar}}", "account.unblock": "Banna ikki @{name}", "account.unblock_domain": "Banna ikki økisnavnið {domain}", + "account.unblock_domain_short": "Banna ikki", "account.unblock_short": "Banna ikki", "account.unendorse": "Vís ikki á vanga", "account.unfollow": "Fylg ikki", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 8106c86714..6eb5457043 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicacións}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Amosar {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "Non amosar no perfil", "account.unfollow": "Deixar de seguir", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index f31b862a03..f5c6e66f9b 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -64,8 +64,9 @@ "account.show_reblogs": "הצג הדהודים מאת @{name}", "account.statuses_counter": "{count, plural, one {הודעה אחת} two {הודעותיים} many {{counter} הודעות} other {{counter} הודעות}}", "account.unblock": "להסיר חסימה ל- @{name}", - "account.unblock_domain": "הסירי את החסימה של קהילת {domain}", - "account.unblock_short": "הסר חסימה", + "account.unblock_domain": "הסרת החסימה של קהילת {domain}", + "account.unblock_domain_short": "הסרת חסימה", + "account.unblock_short": "הסרת חסימה", "account.unendorse": "אל תקדם בפרופיל", "account.unfollow": "הפסקת מעקב", "account.unmute": "הפסקת השתקת @{name}", @@ -905,6 +906,12 @@ "video.expand": "להרחיב וידאו", "video.fullscreen": "מסך מלא", "video.hide": "להסתיר וידאו", + "video.mute": "השתקה", "video.pause": "השהיה", - "video.play": "ניגון" + "video.play": "ניגון", + "video.skip_backward": "דילוג אחורה", + "video.skip_forward": "דילוג קדימה", + "video.unmute": "ביטול השתקה", + "video.volume_down": "הנמכת עוצמת השמע", + "video.volume_up": "הגברת עוצמת שמע" } diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 942c96ffec..2caba889e3 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} bejegyzés} other {{counter} bejegyzés}}", "account.unblock": "@{name} letiltásának feloldása", "account.unblock_domain": "{domain} domain tiltásának feloldása", + "account.unblock_domain_short": "Tiltás feloldása", "account.unblock_short": "Tiltás feloldása", "account.unendorse": "Ne jelenjen meg a profilodon", "account.unfollow": "Követés megszüntetése", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 47cd31fd6b..db257927fc 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}", "account.unblock": "Aflétta útilokun af @{name}", "account.unblock_domain": "Aflétta útilokun lénsins {domain}", + "account.unblock_domain_short": "Aflétta útilokun", "account.unblock_short": "Hætta að loka á", "account.unendorse": "Ekki birta á notandasniði", "account.unfollow": "Hætta að fylgja", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index f62d32226f..912b7b273a 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -61,6 +61,7 @@ "account.statuses_counter": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}}", "account.unblock": "Serreḥ i @{name}", "account.unblock_domain": "Ssken-d {domain}", + "account.unblock_domain_short": "Serreḥ", "account.unblock_short": "Serreḥ", "account.unendorse": "Ur ttwellih ara fell-as deg umaɣnu-inek", "account.unfollow": "Ur ṭṭafaṛ ara", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index c1aef7ff7d..a4af036527 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} bericht} other {{counter} berichten}}", "account.unblock": "@{name} deblokkeren", "account.unblock_domain": "{domain} niet langer blokkeren", + "account.unblock_domain_short": "Deblokkeren", "account.unblock_short": "Deblokkeren", "account.unendorse": "Niet op profiel weergeven", "account.unfollow": "Ontvolgen", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index d5df6e59cf..32af518415 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicação} other {{counter} publicações}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear o domínio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "Não destacar no perfil", "account.unfollow": "Deixar de seguir", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 116b3906a2..a80b3df80d 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postim} other {{counter} postime}}", "account.unblock": "Zhbllokoje @{name}", "account.unblock_domain": "Zhblloko përkatësinë {domain}", + "account.unblock_domain_short": "Zhbllokoje", "account.unblock_short": "Zhbllokoje", "account.unendorse": "Mos e përfshi në profil", "account.unfollow": "Resht së ndjekuri", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 85b0125c07..eb7931f02c 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} допис} few {{counter} дописи} many {{counter} дописів} other {{counter} допис}}", "account.unblock": "Розблокувати @{name}", "account.unblock_domain": "Розблокувати {domain}", + "account.unblock_domain_short": "Розблокувати", "account.unblock_short": "Розблокувати", "account.unendorse": "Не публікувати у профілі", "account.unfollow": "Відписатися", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index b179f50fa9..21a7e5da47 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{counter} Tút}}", "account.unblock": "Bỏ chặn @{name}", "account.unblock_domain": "Bỏ ẩn {domain}", + "account.unblock_domain_short": "Bỏ chặn", "account.unblock_short": "Bỏ chặn", "account.unendorse": "Ngưng tôn vinh người này", "account.unfollow": "Bỏ theo dõi", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 710814f12d..f2b8665e49 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{count} 則嘟文}}", "account.unblock": "解除封鎖 @{name}", "account.unblock_domain": "解除封鎖網域 {domain}", + "account.unblock_domain_short": "解除封鎖", "account.unblock_short": "解除封鎖", "account.unendorse": "取消於個人檔案推薦對方", "account.unfollow": "取消跟隨", diff --git a/config/locales/he.yml b/config/locales/he.yml index f9b2970fd0..6d575bc564 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -232,7 +232,7 @@ he: silence_account: הגבלת חשבון suspend_account: השעיית חשבון unassigned_report: ביטול הקצאת דו"ח - unblock_email_account: ביטול חסימת כתובת דוא"ל + unblock_email_account: הסרת חסימת כתובת דוא"ל unsensitive_account: ביטול Force-Sensitive לחשבון unsilence_account: ביטול השתקת חשבון unsuspend_account: ביטול השעיית חשבון @@ -263,11 +263,11 @@ he: create_user_role_html: "%{name} יצר את התפקיד של %{target}" demote_user_html: "%{name} הוריד/ה בדרגה את המשתמש %{target}" destroy_announcement_html: "%{name} מחק/ה את ההכרזה %{target}" - destroy_canonical_email_block_html: "%{name} הסיר/ה חסימה מדואל %{target}" + destroy_canonical_email_block_html: "%{name} הסירו חסימה מדואל %{target}" destroy_custom_emoji_html: "%{name} מחק אמוג'י של %{target}" destroy_domain_allow_html: "%{name} לא התיר/ה פדרציה עם הדומיין %{target}" - destroy_domain_block_html: "%{name} הסיר/ה חסימה מהדומיין %{target}" - destroy_email_domain_block_html: '%{name} הסיר/ה חסימה מדומיין הדוא"ל %{target}' + destroy_domain_block_html: החסימה על מתחם %{target} הוסרה ע"י %{name} + destroy_email_domain_block_html: הוסרה חסימת מתחם דוא"ל %{target} בידי %{name} destroy_instance_html: "%{name} טיהר/ה את הדומיין %{target}" destroy_ip_block_html: "%{name} מחק/ה את הכלל עבור IP %{target}" destroy_relay_html: "%{name} מחקו את הממסר %{target}" @@ -495,6 +495,36 @@ he: new: title: יבוא רשימת שרתים חסומים no_file: לא נבחר קובץ + fasp: + debug: + callbacks: + created_at: תאריך יצירה + delete: מחיקה + ip: כתובת IP + request_body: גוף הבקשה + title: ניפוי תקלות בקריאות חוזרות + providers: + active: פעילים + base_url: קישור בסיס + callback: קריאה חוזרת + delete: מחיקה + edit: עריכת ספק + finish_registration: סיום הרשמה + name: שם + providers: ספקים + public_key_fingerprint: טביעת האצבע של המפתח הציבורי + registration_requested: נדרשת הרשמה + registrations: + confirm: אישור + description: קיבלת הרשמה דרך FASP. יש לדחות אותה אם לא ביקשת את ההרשמה הזו מיוזמתך. אם זו בקשה מיוזמתך, יש להשוות בהקפדה אם השם וטביעת האצבע של המפתח הציבורי תואמים לפני אישור הרישום. + reject: דחיה + title: אישור הרשמת FASP + save: שמירה + select_capabilities: בחירת יכולות + sign_in: כניסה + status: מצב + title: ספקי משנה לפדיוורס + title: פרוטוקול FASP follow_recommendations: description_html: "עקבו אחר ההמלצות על מנת לעזור למשתמשים חדשים למצוא תוכן מעניין. במידה ומשתמש לא תקשר מספיק עם משתמשים אחרים כדי ליצור המלצות מעקב, חשבונות אלה יומלצו במקום. הם מחושבים מחדש על בסיסי יומיומי מתערובת של החשבונות הפעילים ביותר עם החשבונות הנעקבים ביותר עבור שפה נתונה." language: עבור שפה diff --git a/config/locales/lv.yml b/config/locales/lv.yml index af65e9e02b..e9bbe35e47 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -304,6 +304,7 @@ lv: title: Audita žurnāls unavailable_instance: "(domēna vārds nav pieejams)" announcements: + back: Atgriezties pie paziņojumiem destroyed_msg: Paziņojums sekmīgi izdzēsts. edit: title: Labot paziņojumu @@ -312,6 +313,9 @@ lv: new: create: Izveidot paziņojumu title: Jauns paziņojums + preview: + explanation_html: 'E-pasta ziņojums tiks nosūtīts %{display_count} lietotājiem. Šis teksts tiks iekļauts e-pasta ziņojumā:' + title: Priekšskatīt paziņojumu publish: Publicēt published_msg: Paziņojums sekmīgi publicēts. scheduled_for: Plānots uz %{time} @@ -1422,6 +1426,48 @@ lv: merge_long: Saglabāt esošos ierakstus un pievienot jaunus overwrite: Pārrakstīt overwrite_long: Nomainīt pašreizējos ierakstus ar jauniem + overwrite_preambles: + blocking_html: + one: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontam no %{filename}. + other: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontiem no %{filename}. + bookmarks_html: + one: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstam no %{filename}. + other: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstiem no %{filename}. + zero: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstiem no %{filename}. + domain_blocking_html: + one: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēnam no %{filename}. + other: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēniem no %{filename}. + zero: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēniem no %{filename}. + following_html: + one: Tu gatavojies sekot līdz %{count} kontam no %{filename} un pārtrauksi sekot citiem. + other: Tu gatavojies sekot līdz %{count} kontiem no %{filename} un pārtrauksi sekot citiem. + zero: Tu gatavojies sekot līdz %{count} kontiem no %{filename} un pārtrauksi sekot citiem. + lists_html: + one: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontam tiks pievienoti jaunajos sarakstos. + other: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontiem tiks pievienoti jaunajos sarakstos. + zero: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontiem tiks pievienoti jaunajos sarakstos. + muting_html: + one: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontam no %{filename}. + other: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontiem no %{filename}. + preambles: + blocking_html: + one: Tu gatavojies liegt līdz %{count} kontam no %{filename}. + other: Tu gatavojies liegt līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies liegt līdz %{count} kontiem no %{filename}. + bookmarks_html: + one: Tu gatavojies pievienot līdz %{count} ierakstam no %{filename} savām grāmatzīmēm. + other: Tu gatavojies pievienot līdz %{count} ierakstiem no %{filename} savām grāmatzīmēm. + zero: Tu gatavojies pievienot līdz %{count} ierakstiem no %{filename} savām grāmatzīmēm. + domain_blocking_html: + one: Tu gatavojies liegt līdz %{count} domēnam no %{filename}. + other: Tu gatavojies liegt līdz %{count} domēniem no %{filename}. + zero: Tu gatavojies liegt līdz %{count} domēniem no %{filename}. + following_html: + one: Tu gatavojies sekot līdz %{count} kontam no %{filename}. + other: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. preface: Tu vari ievietot datus, kurus esi izguvis no cita servera, kā, piemēram, cilvēku sarakstu, kuriem Tu seko vai kurus bloķē. recent_imports: Nesen importēts states: From d65c3e95ad83d24a52aa8b4c62d93b3770067c74 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:49:10 +0200 Subject: [PATCH 03/48] chore(deps): update dependency irb to v1.15.2 (#34363) 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 80049a7dc2..6aeee348be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -328,7 +328,7 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.8.0) - irb (1.15.1) + irb (1.15.2) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) From 5859abf2ff6a5d9dd4d8c772add97ad006254793 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:49:14 +0200 Subject: [PATCH 04/48] chore(deps): update dependency rubocop to v1.75.2 (#34364) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6aeee348be..3e9b5458b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -740,7 +740,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 9) rspec-support (3.13.2) - rubocop (1.75.1) + rubocop (1.75.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -748,10 +748,10 @@ GEM parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.43.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.43.0) + rubocop-ast (1.44.0) parser (>= 3.3.7.2) prism (~> 1.4) rubocop-capybara (2.22.1) From 58e3e43e06aeb3e968aa1063f13229d3453a9dd8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:24:27 +0200 Subject: [PATCH 05/48] New Crowdin Translations (automated) (#34366) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/cs.json | 8 ++--- app/javascript/mastodon/locales/kab.json | 2 ++ app/javascript/mastodon/locales/tr.json | 1 + app/javascript/mastodon/locales/ug.json | 37 ++++++++++++++++-------- config/locales/lv.yml | 9 ++++++ config/locales/simple_form.de.yml | 2 +- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 625ea7ce96..4ffef4f392 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -80,7 +80,7 @@ "admin.dashboard.retention.cohort_size": "Noví uživatelé", "admin.impact_report.instance_accounts": "Profily účtů, které by byli odstaněny", "admin.impact_report.instance_followers": "Sledující, o které by naši uživatelé přišli", - "admin.impact_report.instance_follows": "Sledující, o které by naši uživatelé přišli", + "admin.impact_report.instance_follows": "Sledující, o které by jejich uživatelé přišli", "admin.impact_report.title": "Shrnutí dopadu", "alert.rate_limited.message": "Zkuste to prosím znovu po {retry_time, time, medium}.", "alert.rate_limited.title": "Spojení omezena", @@ -102,7 +102,7 @@ "annual_report.summary.archetype.replier": "Sociální motýlek", "annual_report.summary.followers.followers": "sledujících", "annual_report.summary.followers.total": "{count} celkem", - "annual_report.summary.here_it_is": "Zde je tvůj {year} v přehledu:", + "annual_report.summary.here_it_is": "Zde je tvůj rok {year} v přehledu:", "annual_report.summary.highlighted_post.by_favourites": "nejvíce oblíbený příspěvek", "annual_report.summary.highlighted_post.by_reblogs": "nejvíce boostovaný příspěvek", "annual_report.summary.highlighted_post.by_replies": "příspěvek s nejvíce odpověďmi", @@ -268,7 +268,7 @@ "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": "Jejich digitální domov, kde žijí jejich všechny příspěvky.", + "domain_pill.their_server": "Jejich digitální domov, kde žijí všechny jejich příspěvky.", "domain_pill.their_username": "Jejich jedinečný identifikátor na jejich serveru. Je možné, že na jiných serverech jsou uživatelé se stejným uživatelským jménem.", "domain_pill.username": "Uživatelské jméno", "domain_pill.whats_in_a_handle": "Co obsahuje handle?", @@ -573,7 +573,7 @@ "notification.label.private_reply": "Privátní odpověď", "notification.label.reply": "Odpověď", "notification.mention": "Zmínka", - "notification.mentioned_you": "{name} vás zmínil", + "notification.mentioned_you": "{name} vás zmínil*a", "notification.moderation-warning.learn_more": "Zjistit více", "notification.moderation_warning": "Obdrželi jste varování od moderátorů", "notification.moderation_warning.action_delete_statuses": "Některé z vašich příspěvků byly odstraněny.", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 912b7b273a..c4d9d75c0e 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -248,6 +248,7 @@ "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", + "filtered_notifications_banner.title": "Ilɣa yettwasizdgen", "firehose.all": "Akk", "firehose.local": "Deg uqeddac-ayi", "firehose.remote": "Iqeddacen nniḍen", @@ -426,6 +427,7 @@ "notification_requests.edit_selection": "Ẓreg", "notification_requests.exit_selection": "Immed", "notification_requests.notifications_from": "Alɣuten sɣur {name}", + "notification_requests.title": "Ilɣa yettwasizdgen", "notifications.clear": "Sfeḍ alɣuten", "notifications.clear_confirmation": "Tebɣiḍ s tidet ad tekkseḍ akk alɣuten-inek·em i lebda?", "notifications.column_settings.admin.report": "Ineqqisen imaynuten:", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index e95efc642a..a33317ac9c 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} gönderi} other {{counter} gönderi}}", "account.unblock": "@{name} adlı kişinin engelini kaldır", "account.unblock_domain": "{domain} alan adının engelini kaldır", + "account.unblock_domain_short": "Engeli kaldır", "account.unblock_short": "Engeli kaldır", "account.unendorse": "Profilimde öne çıkarma", "account.unfollow": "Takibi bırak", diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json index 378f688ba8..e550d7e678 100644 --- a/app/javascript/mastodon/locales/ug.json +++ b/app/javascript/mastodon/locales/ug.json @@ -1,21 +1,34 @@ { - "about.blocks": "ئوتتۇراھال مۇلازىمېتىر", - "about.contact": "ئالاقىلاشقۇچى:", - "account.badges.bot": "Bot", - "account.cancel_follow_request": "Withdraw follow request", - "account.posts": "Toots", - "account.posts_with_replies": "Toots and replies", + "about.blocks": "باشقۇرۇلىدىغان مۇلازىمېتىر", + "about.contact": "ئالاقە:", + "about.disclaimer": "Mastodon ھەقسىز، ئوچۇق كودلۇق يۇمشاق دېتال تاۋار ماركىسى Mastodon gGmbH غا تەۋە.", + "about.domain_blocks.no_reason_available": "سەۋەبىنى ئىشلەتكىلى بولمايدۇ", + "account.badges.bot": "ماشىنا ئادەم", + "account.cancel_follow_request": "ئەگىشىش ئىلتىماسىدىن ۋاز كەچ", + "account.posts": "يازما", + "account.posts_with_replies": "يازما ۋە ئىنكاس", + "account.report": "@{name} نى پاش قىل", "account.requested": "Awaiting approval", - "account_note.placeholder": "Click to add a note", - "column.pins": "Pinned toot", - "community.column_settings.media_only": "Media only", + "account_note.placeholder": "چېكىلسە ئىزاھات قوشىدۇ", + "column.pins": "چوققىلانغان يازما", + "community.column_settings.media_only": "ۋاسىتەلا", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.placeholder": "What is on your mind?", - "compose_form.publish_form": "Publish", - "compose_form.spoiler.marked": "Text is hidden behind warning", + "compose_form.publish_form": "يېڭى يازما", + "compose_form.reply": "جاۋاب", + "compose_form.save_changes": "يېڭىلا", + "compose_form.spoiler.marked": "مەزمۇن ئاگاھلاندۇرۇشىنى چىقىرىۋەت", "compose_form.spoiler.unmarked": "Text is not hidden", - "confirmations.delete.message": "Are you sure you want to delete this status?", + "compose_form.spoiler_placeholder": "مەزمۇن ئاگاھلاندۇرۇشى (تاللاشچان)", + "confirmation_modal.cancel": "ۋاز كەچ", + "confirmations.block.confirm": "توس", + "confirmations.delete.message": "بۇ يازمىنى راستىنلا ئۆچۈرەمسىز؟", + "confirmations.delete.title": "يازما ئۆچۈرەمدۇ؟", + "confirmations.delete_list.confirm": "ئۆچۈر", + "confirmations.delete_list.message": "بۇ تىزىمنى راستتىنلا مەڭگۈلۈك ئۆچۈرەمسىز؟", + "confirmations.delete_list.title": "تىزىمنى ئۆچۈرەمدۇ؟", + "confirmations.discard_edit_media.confirm": "تاشلىۋەت", "embed.instructions": "Embed this status on your website by copying the code below.", "empty_column.account_timeline": "No toots here!", "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.", diff --git a/config/locales/lv.yml b/config/locales/lv.yml index e9bbe35e47..07fc9c9780 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -459,7 +459,9 @@ lv: create: Pievienot domēnu resolve: Atrisināt domēnu title: Liegt jaunu e-pasta domēnu + no_email_domain_block_selected: Neviens e-pasta domēna bloks netika mainīts, jo neviens netika atlasīts not_permitted: Nav atļauta + resolved_dns_records_hint_html: Domēna vārds saistās ar zemāk norādītajiem MX domēniem, kuri beigās ir atbildīgi par e-pasta pieņemšana. MX domēna liegšana liegs reģistrēšanos no jebkuras e-pasta adreses, kas izmanto to pašu MX domēnu, pat ja redzamais domēna vārds ir atšķirīgs. Jāuzmanās, lai neliegtu galvenos e-pasta pakalpojuma sniedzējus. resolved_through_html: Atrisināts, izmantojot %{domain} title: Bloķētie e-pasta domēni export_domain_allows: @@ -477,6 +479,13 @@ lv: new: title: Importēt bloķētos domēnus no_file: Nav atlasīts neviens fails + fasp: + debug: + callbacks: + created_at: Izveidots + delete: Izdzēst + ip: IP adrese + request_body: Pieprasījuma saturs follow_recommendations: description_html: "Sekošanas ieteikumi palīdz jauniem lietotājiem ātri arast saistošu saturu. Kad lietotājs nav pietiekami mijiedarbojies ar citiem, lai veidotos pielāgoti sekošanas iteikumi, tiek ieteikti šie konti. Tie tiek pārskaitļoti ik dienas, izmantojot kontu, kuriem ir augstākās nesenās iesaistīšanās un lielākais vietējo sekotāju skaits norādītajā valodā." language: Valodai diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 016ed4b25a..342a1dbe1c 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -84,7 +84,7 @@ de: backups_retention_period: Nutzer*innen haben die Möglichkeit, Archive ihrer Beiträge zu erstellen, die sie später herunterladen können. Wenn ein positiver Wert gesetzt ist, werden diese Archive nach der festgelegten Anzahl von Tagen automatisch aus deinem Speicher gelöscht. bootstrap_timeline_accounts: Diese Konten werden bei den Follower-Empfehlungen für neu registrierte Nutzer*innen oben angeheftet. closed_registrations_message: Wird angezeigt, wenn Registrierungen deaktiviert sind - content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Das Verwenden dieser Option richtet sich ausschließlich an Server für spezielle Zwecke und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. + content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Diese Option richtet sich ausschließlich an Server mit speziellen Zwecken und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. custom_css: Du kannst benutzerdefinierte Stile auf die Web-Version von Mastodon anwenden. favicon: WEBP, PNG, GIF oder JPG. Überschreibt das Standard-Mastodon-Favicon mit einem eigenen Symbol. mascot: Überschreibt die Abbildung in der erweiterten Weboberfläche. From 4d3758308a5c65ecdc8d34631abbbc2c50f9f82e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 4 Apr 2025 03:24:32 -0400 Subject: [PATCH 06/48] Use bundler version 2.6.7 (#34362) --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3e9b5458b4..1491251676 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,7 +94,7 @@ GEM ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.3.2) - aws-partitions (1.1066.0) + aws-partitions (1.1080.0) aws-sdk-core (3.215.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) @@ -194,7 +194,7 @@ GEM devise_pam_authenticatable2 (9.2.0) devise (>= 4.0.0) rpam2 (~> 4.0) - diff-lcs (1.6.0) + diff-lcs (1.6.1) discard (1.4.0) activerecord (>= 4.2, < 9.0) docile (1.4.1) @@ -266,10 +266,10 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) - google-protobuf (4.30.1) + google-protobuf (4.30.2) bigdecimal rake (>= 13) - googleapis-common-protos-types (1.18.0) + googleapis-common-protos-types (1.19.0) google-protobuf (>= 3.18, < 5.a) haml (6.3.0) temple (>= 0.8.2) @@ -426,7 +426,7 @@ GEM mime-types (3.6.2) logger mime-types-data (~> 3.2015) - mime-types-data (3.2025.0318) + mime-types-data (3.2025.0402) mini_mime (1.1.5) mini_portile2 (2.8.8) minitest (5.25.5) @@ -688,7 +688,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.7.0) rdf (~> 3.3) - rdoc (6.12.0) + rdoc (6.13.1) psych (>= 4.0.0) redcarpet (3.6.1) redis (4.8.1) @@ -851,7 +851,7 @@ GEM temple (0.10.3) terminal-table (4.0.0) unicode-display_width (>= 1.1.1, < 4) - terrapin (1.0.1) + terrapin (1.1.0) climate_control test-prof (1.4.4) thor (1.3.2) @@ -1085,4 +1085,4 @@ RUBY VERSION ruby 3.4.1p0 BUNDLED WITH - 2.6.6 + 2.6.7 From 9b596dbc78534b3e5c183b498960b94b6fb931cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:24:51 +0200 Subject: [PATCH 07/48] fix(deps): update dependency sass to v1.86.3 (#34368) 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 7a8269ed37..e9694d35fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15738,8 +15738,8 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.86.2 - resolution: "sass@npm:1.86.2" + version: 1.86.3 + resolution: "sass@npm:1.86.3" dependencies: "@parcel/watcher": "npm:^2.4.1" chokidar: "npm:^4.0.0" @@ -15750,7 +15750,7 @@ __metadata: optional: true bin: sass: sass.js - checksum: 10c0/fe40b63a19e867f460369d495bcdc979598c0b105c9d52164a7e9cc4e12ab91c27337702a1b58575f7da8fd08256b85fd2f34cc8275eb7c57699bfc5029f54a3 + checksum: 10c0/ba819a0828f732adf7a94cd8ca017bce92bc299ffb878836ed1da80a30612bfbbf56a5e42d6dff3ad80d919c2025afb42948fc7b54a7bc61a9a2d58e1e0c558a languageName: node linkType: hard From 4ed9778c85583b42f87a7d431af08b39547b7099 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:36:53 +0200 Subject: [PATCH 08/48] chore(deps): update dependency brakeman to v7.0.1 (#34367) 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 1491251676..a6edb1379b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -126,7 +126,7 @@ GEM blurhash (0.1.8) bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (7.0.0) + brakeman (7.0.1) racc browser (6.2.0) brpoplpush-redis_script (0.1.3) From 5f87ae101c5e0e940e148d493eaac1ce31fe24c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:17:29 +0200 Subject: [PATCH 09/48] chore(deps): update dependency strong_migrations to v2.3.0 (#34369) 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 a6edb1379b..b949c7ec54 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -840,7 +840,7 @@ GEM stoplight (4.1.1) redlock (~> 1.0) stringio (3.1.6) - strong_migrations (2.2.1) + strong_migrations (2.3.0) activerecord (>= 7) swd (2.0.3) activesupport (>= 3) From b4317faee2c9d19886843476e9f24f37544da095 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 08:30:53 +0200 Subject: [PATCH 10/48] chore(deps): update dependency linzer to v0.6.4 (#34377) 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 b949c7ec54..d4c727c3c4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -395,7 +395,7 @@ GEM rexml link_header (0.0.8) lint_roller (1.1.0) - linzer (0.6.3) + linzer (0.6.4) openssl (~> 3.0, >= 3.0.0) rack (>= 2.2, < 4.0) starry (~> 0.2) From 107a94cf6b2381a1b05426f686e082d3086adfe8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 08:31:06 +0200 Subject: [PATCH 11/48] chore(deps): update dependency brakeman to v7.0.2 (#34376) 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 d4c727c3c4..2877b2c743 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -126,7 +126,7 @@ GEM blurhash (0.1.8) bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (7.0.1) + brakeman (7.0.2) racc browser (6.2.0) brpoplpush-redis_script (0.1.3) From 8451b36a726c98b57f510e25e780360a3ab865cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 06:40:32 +0000 Subject: [PATCH 12/48] chore(deps): update dependency doorkeeper to v5.8.2 (#34372) 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 2877b2c743..09d5410ca0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -199,7 +199,7 @@ GEM activerecord (>= 4.2, < 9.0) docile (1.4.1) domain_name (0.6.20240107) - doorkeeper (5.8.1) + doorkeeper (5.8.2) railties (>= 5) dotenv (3.1.7) drb (2.2.1) @@ -697,7 +697,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.10.0) - reline (0.6.0) + reline (0.6.1) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) From 0b900339b006144b7de507d2a12a64f1d29508ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 06:42:52 +0000 Subject: [PATCH 13/48] chore(deps): update dependency selenium-webdriver to v4.31.0 (#34379) 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 09d5410ca0..4d4d0d1792 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -797,7 +797,7 @@ GEM activerecord (>= 4.0.0) railties (>= 4.0.0) securerandom (0.4.1) - selenium-webdriver (4.30.1) + selenium-webdriver (4.31.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) From 9a056883269226648103ce437deb2f0d79b902d7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 06:45:26 +0000 Subject: [PATCH 14/48] New Crowdin Translations (automated) (#34374) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 1 + app/javascript/mastodon/locales/cs.json | 4 +- app/javascript/mastodon/locales/eo.json | 5 +- app/javascript/mastodon/locales/es-MX.json | 6 +-- app/javascript/mastodon/locales/ga.json | 9 +++- app/javascript/mastodon/locales/it.json | 1 + app/javascript/mastodon/locales/kab.json | 38 ++++++++------- app/javascript/mastodon/locales/nan.json | 54 +++++++++++++++++++++- app/javascript/mastodon/locales/ru.json | 1 + app/javascript/mastodon/locales/sk.json | 6 ++- app/javascript/mastodon/locales/sv.json | 1 + app/javascript/mastodon/locales/th.json | 6 ++- app/javascript/mastodon/locales/zh-HK.json | 7 +++ config/locales/activerecord.es-MX.yml | 2 +- config/locales/activerecord.ga.yml | 2 + config/locales/cy.yml | 30 ++++++++++++ config/locales/doorkeeper.kab.yml | 10 ++-- config/locales/el.yml | 31 +++++++++++++ config/locales/es-MX.yml | 2 +- config/locales/ga.yml | 30 ++++++++++++ config/locales/kab.yml | 4 +- config/locales/lv.yml | 11 +++++ config/locales/ru.yml | 3 ++ config/locales/simple_form.es-MX.yml | 16 +++---- config/locales/simple_form.ga.yml | 8 ++++ config/locales/simple_form.kab.yml | 6 +-- config/locales/simple_form.th.yml | 3 ++ config/locales/th.yml | 8 +++- config/locales/zh-HK.yml | 10 +++- 29 files changed, 265 insertions(+), 50 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index bd2d37c681..eb7a22a04b 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} публикация} other {{counter} публикации}}", "account.unblock": "Отблокиране на @{name}", "account.unblock_domain": "Отблокиране на домейн {domain}", + "account.unblock_domain_short": "Отблокиране", "account.unblock_short": "Отблокиране", "account.unendorse": "Не включвайте в профила", "account.unfollow": "Стоп на следването", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 4ffef4f392..503dc7714d 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -560,7 +560,7 @@ "notification.admin.sign_up.name_and_others": "{name} a {count, plural, one {# další} few {# další} many {# dalších} other {# dalších}} se zaregistrovali", "notification.annual_report.message": "Váš #Wrapstodon {year} na Vás čeká! Podívejte se, jak vypadal tento Váš rok na Mastodonu!", "notification.annual_report.view": "Zobrazit #Wrapstodon", - "notification.favourite": "{name} si oblíbil*a váš příspěvek", + "notification.favourite": "{name} si oblíbil váš příspěvek", "notification.favourite.name_and_others_with_link": "{name} a {count, plural, one {# další si oblíbil} few {# další si oblíbili} other {# dalších si oblíbilo}} Váš příspěvek", "notification.favourite_pm": "{name} si oblíbil vaši soukromou zmínku", "notification.favourite_pm.name_and_others_with_link": "{name} a {count, plural, one {# další si oblíbil} few {# další si oblíbili} other {# dalších si oblíbilo}} Vaši soukromou zmínku", @@ -573,7 +573,7 @@ "notification.label.private_reply": "Privátní odpověď", "notification.label.reply": "Odpověď", "notification.mention": "Zmínka", - "notification.mentioned_you": "{name} vás zmínil*a", + "notification.mentioned_you": "{name} vás zmínil", "notification.moderation-warning.learn_more": "Zjistit více", "notification.moderation_warning": "Obdrželi jste varování od moderátorů", "notification.moderation_warning.action_delete_statuses": "Některé z vašich příspěvků byly odstraněny.", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index accc2b8052..207fa5b955 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}}", "account.unblock": "Malbloki @{name}", "account.unblock_domain": "Malbloki la domajnon {domain}", + "account.unblock_domain_short": "Malbloki", "account.unblock_short": "Malbloki", "account.unendorse": "Ne plu rekomendi ĉe la profilo", "account.unfollow": "Ĉesi sekvi", @@ -905,6 +906,8 @@ "video.expand": "Pligrandigi la videon", "video.fullscreen": "Igi plenekrana", "video.hide": "Kaŝu la filmeton", + "video.mute": "Silentigi", "video.pause": "Paŭzigi", - "video.play": "Ekigi" + "video.play": "Ekigi", + "video.unmute": "Ne plu silentigi" } diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index dbaf1955e4..929f962e6a 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -910,8 +910,8 @@ "video.pause": "Pausar", "video.play": "Reproducir", "video.skip_backward": "Saltar atrás", - "video.skip_forward": "Adelantar", + "video.skip_forward": "Saltar adelante", "video.unmute": "Dejar de silenciar", - "video.volume_down": "Bajar volumen", - "video.volume_up": "Subir volumen" + "video.volume_down": "Bajar el volumen", + "video.volume_up": "Subir el volumen" } diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index d3af400c64..cd0d58da4a 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} poist}}", "account.unblock": "Bain bac de @{name}", "account.unblock_domain": "Bain bac den ainm fearainn {domain}", + "account.unblock_domain_short": "Díbhlocáil", "account.unblock_short": "Díbhlocáil", "account.unendorse": "Ná chuir ar an phróifíl mar ghné", "account.unfollow": "Ná lean a thuilleadh", @@ -905,6 +906,12 @@ "video.expand": "Leath físeán", "video.fullscreen": "Lánscáileán", "video.hide": "Cuir físeán i bhfolach", + "video.mute": "Balbhaigh", "video.pause": "Cuir ar sos", - "video.play": "Cuir ar siúl" + "video.play": "Cuir ar siúl", + "video.skip_backward": "Scipeáil siar", + "video.skip_forward": "Scipeáil ar aghaidh", + "video.unmute": "Díbhalbhú", + "video.volume_down": "Toirt síos", + "video.volume_up": "Toirt suas" } diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 9fa5c725b6..99cb78716f 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} post}}", "account.unblock": "Sblocca @{name}", "account.unblock_domain": "Sblocca il dominio {domain}", + "account.unblock_domain_short": "Sblocca", "account.unblock_short": "Sblocca", "account.unendorse": "Non mostrare sul profilo", "account.unfollow": "Smetti di seguire", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index c4d9d75c0e..a29bd33468 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -20,10 +20,10 @@ "account.cancel_follow_request": "Sefsex taḍfart", "account.copy": "Nɣel assaɣ ɣer umaɣnu", "account.direct": "Bder-d @{name} weḥd-s", - "account.disable_notifications": "Ḥbes ur iyi-d-ttazen ara alɣuten mi ara d-isuffeɣ @{name}", + "account.disable_notifications": "Ḥbes ur iyi-d-ttazen ara ilɣa mi ara d-isuffeɣ @{name}", "account.domain_blocked": "Taɣult yeffren", "account.edit_profile": "Ẓreg amaɣnu", - "account.enable_notifications": "Azen-iyi-d alɣuten mi ara d-isuffeɣ @{name}", + "account.enable_notifications": "Azen-iyi-d ilɣa mi ara d-isuffeɣ @{name}", "account.endorse": "Welleh fell-as deg umaɣnu-inek", "account.featured_tags.last_status_at": "Tasuffeɣt taneggarut ass n {date}", "account.featured_tags.last_status_never": "Ulac tisuffaɣ", @@ -45,7 +45,7 @@ "account.mention": "Bder-d @{name}", "account.moved_to": "{name} yenna-d dakken amiḍan-is amaynut yuɣal :", "account.mute": "Sgugem @{name}", - "account.mute_notifications_short": "Susem alɣuten", + "account.mute_notifications_short": "Susem ilɣa", "account.mute_short": "Sgugem", "account.muted": "Yettwasgugem", "account.mutual": "Temṭafarem", @@ -75,6 +75,8 @@ "alert.unexpected.message": "Yeḍra-d unezri ur netturaǧu ara.", "alert.unexpected.title": "Ayhuh!", "alt_text_badge.title": "Aḍris asegzan", + "alt_text_modal.add_alt_text": "Rnu aḍris amlellay", + "alt_text_modal.add_text_from_image": "Rnu aḍris amlellay seg tugna", "alt_text_modal.cancel": "Semmet", "alt_text_modal.done": "Immed", "announcement.announcement": "Ulɣu", @@ -116,7 +118,7 @@ "column.home": "Agejdan", "column.lists": "Tibdarin", "column.mutes": "Imiḍanen yettwasgugmen", - "column.notifications": "Alɣuten", + "column.notifications": "Ilɣa", "column.pins": "Tisuffaɣ yettwasenṭḍen", "column.public": "Tasuddemt tamatut", "column_back_button.label": "Tuɣalin", @@ -168,6 +170,7 @@ "confirmations.logout.confirm": "Ffeɣ", "confirmations.logout.message": "D tidet tebɣiḍ ad teffɣeḍ?", "confirmations.logout.title": "Tebɣiḍ ad teffɣeḍ ssya?", + "confirmations.missing_alt_text.confirm": "Rnu aḍris amlellay", "confirmations.missing_alt_text.secondary": "Suffeɣ akken yebɣu yili", "confirmations.mute.confirm": "Sgugem", "confirmations.redraft.confirm": "Kkes sakin ɛiwed tira", @@ -229,7 +232,7 @@ "empty_column.home": "Tasuddemt tagejdant n yisallen d tilemt! Ẓer {public} neɣ nadi ad tafeḍ imseqdacen-nniḍen ad ten-ḍefṛeḍ.", "empty_column.list": "Ar tura ur yelli kra deg umuɣ-a. Ad d-yettwasken da ticki iɛeggalen n wumuɣ-a suffɣen-d kra.", "empty_column.mutes": "Ulac ɣur-k·m imseqdacen i yettwasgugmen.", - "empty_column.notifications": "Ulac ɣur-k·m alɣuten. Sedmer akked yemdanen-nniḍen akken ad tebduḍ adiwenni.", + "empty_column.notifications": "Ulac ɣur-k·m ilɣa. Sedmer akked yemdanen-nniḍen akken ad tebduḍ adiwenni.", "empty_column.public": "Ulac kra da! Aru kra, neɣ ḍfeṛ imdanen i yellan deg yiqeddacen-nniḍen akken ad d-teččar tsuddemt tazayezt", "error.unexpected_crash.next_steps": "Smiren asebter-a, ma ur yekkis ara wugur, ẓer d akken tzemreḍ ad tesqedceḍ Maṣṭudun deg yiminig-nniḍen neɣ deg usnas anaṣli.", "errors.unexpected_crash.copy_stacktrace": "Nɣel stacktrace ɣef wafus", @@ -328,7 +331,7 @@ "keyboard_shortcuts.mention": "akken ad d-bedreḍ ameskar", "keyboard_shortcuts.muted": "akken ad teldiḍ tabdart n yimseqdacen yettwasgugmen", "keyboard_shortcuts.my_profile": "akken ad d-teldiḍ amaɣnu-ik", - "keyboard_shortcuts.notifications": "akken ad d-teldiḍ ajgu n walɣuten", + "keyboard_shortcuts.notifications": "Ad d-yeldi ajgu n yilɣa", "keyboard_shortcuts.open_media": "i tiɣwalin yeldin", "keyboard_shortcuts.pinned": "akken ad teldiḍ tabdart n tjewwiqin yettwasentḍen", "keyboard_shortcuts.profile": "akken ad d-teldiḍ amaɣnu n umeskar", @@ -410,6 +413,7 @@ "notification.admin.sign_up": "Ijerred {name}", "notification.favourite": "{name} yesmenyaf addad-ik·im", "notification.follow": "iṭṭafar-ik·em-id {name}", + "notification.follow.name_and_others": "{name} akked {count, plural, one {# nniḍen} other {# nniḍen}} iḍfeṛ-k·m-id", "notification.follow_request": "{name} yessuter-d ad k·m-yeḍfeṛ", "notification.label.mention": "Abdar", "notification.label.private_mention": "Abdar uslig", @@ -426,12 +430,12 @@ "notification_requests.dismiss": "Agi", "notification_requests.edit_selection": "Ẓreg", "notification_requests.exit_selection": "Immed", - "notification_requests.notifications_from": "Alɣuten sɣur {name}", + "notification_requests.notifications_from": "Ilɣa sɣur {name}", "notification_requests.title": "Ilɣa yettwasizdgen", - "notifications.clear": "Sfeḍ alɣuten", - "notifications.clear_confirmation": "Tebɣiḍ s tidet ad tekkseḍ akk alɣuten-inek·em i lebda?", + "notifications.clear": "Sfeḍ ilɣa", + "notifications.clear_confirmation": "Tebɣiḍ s tidet ad tekkseḍ akk ilɣa-inek·em i lebda?", "notifications.column_settings.admin.report": "Ineqqisen imaynuten:", - "notifications.column_settings.alert": "Alɣuten n tnarit", + "notifications.column_settings.alert": "Ilɣ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", @@ -440,12 +444,12 @@ "notifications.column_settings.group": "Agraw", "notifications.column_settings.mention": "Abdar:", "notifications.column_settings.poll": "Igemmaḍ n usenqed:", - "notifications.column_settings.push": "Alɣuten yettudemmren", + "notifications.column_settings.push": "Ilɣa yettudemmren", "notifications.column_settings.reblog": "Seǧhed:", "notifications.column_settings.show": "Ssken-d tilɣa deg ujgu", "notifications.column_settings.sound": "Rmed imesli", "notifications.column_settings.status": "Tisuffaɣ timaynutin :", - "notifications.column_settings.unread_notifications.category": "Alɣuten ur nettwaɣra", + "notifications.column_settings.unread_notifications.category": "Ilɣa ur nettwaɣra", "notifications.column_settings.update": "Iẓreg:", "notifications.filter.all": "Akk", "notifications.filter.boosts": "Seǧhed", @@ -455,9 +459,9 @@ "notifications.filter.polls": "Igemmaḍ n usenqed", "notifications.filter.statuses": "Ileqman n yimdanen i teṭṭafareḍ", "notifications.grant_permission": "Mudd tasiregt.", - "notifications.group": "{count} n walɣuten", - "notifications.mark_as_read": "Creḍ meṛṛa alɣuten am wakken ttwaɣran", - "notifications.permission_denied": "D awezɣi ad yili wermad n walɣuten n tnarit axateṛ turagt tettwagdel", + "notifications.group": "{count} n yilɣa", + "notifications.mark_as_read": "Creḍ akk ilɣa am wakken ttwaɣran", + "notifications.permission_denied": "D awezɣi ad yili wermad n yilɣa n tnarit axateṛ turagt tettwagdel", "notifications.policy.drop": "Anef-as", "notifications.policy.filter": "Sizdeg", "notifications.policy.filter_new_accounts.hint": "Imiḍanen imaynuten i d-yennulfan deg {days, plural, one {yiwen n wass} other {# n wussan}} yezrin", @@ -467,7 +471,7 @@ "notifications.policy.filter_not_following_hint": "Alamma tqebleḍ-ten s ufus", "notifications.policy.filter_not_following_title": "Wid akked tid ur tettḍafareḍ ara", "notifications.policy.filter_private_mentions_title": "Abdar uslig ur yettwasferken ara", - "notifications_permission_banner.enable": "Rmed alɣuten n tnarit", + "notifications_permission_banner.enable": "Rmed ilɣa n tnarit", "notifications_permission_banner.title": "Ur zeggel acemma", "onboarding.follows.back": "Uɣal", "onboarding.follows.done": "Immed", @@ -635,7 +639,7 @@ "status.unpin": "Kkes asenteḍ seg umaɣnu", "subscribed_languages.save": "Sekles ibeddilen", "tabs_bar.home": "Agejdan", - "tabs_bar.notifications": "Alɣuten", + "tabs_bar.notifications": "Ilɣa", "terms_of_service.title": "Tiwtilin n useqdec", "time_remaining.days": "Mazal {number, plural, one {# wass} other {# wussan}}", "time_remaining.hours": "Mazal {number, plural, one {# usarag} other {# yisragen}}", diff --git a/app/javascript/mastodon/locales/nan.json b/app/javascript/mastodon/locales/nan.json index 57eef0a874..268dbfa2b7 100644 --- a/app/javascript/mastodon/locales/nan.json +++ b/app/javascript/mastodon/locales/nan.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{count} ê PO文}}", "account.unblock": "取消封鎖 @{name}", "account.unblock_domain": "Kā域名 {domain} 取消封鎖", + "account.unblock_domain_short": "取消封鎖", "account.unblock_short": "取消封鎖", "account.unendorse": "Mài tī個人資料推薦伊", "account.unfollow": "取消跟tuè", @@ -387,8 +388,8 @@ "hashtag.column_settings.tag_mode.none": "Lóng mài", "hashtag.column_settings.tag_toggle": "Kā追加ê標籤加添kàu tsit ê欄", "hashtag.counter_by_accounts": "{count, plural, one {{counter} ê} other {{counter} ê}}參與ê", - "hashtag.counter_by_uses": "{count, plural, one {{counter} ê} other {{counter} ê}} PO文", - "hashtag.counter_by_uses_today": "Kin-á日有 {count, plural, one {{counter} ê} other {{counter} ê}} PO文", + "hashtag.counter_by_uses": "{count, plural, one {{counter} 篇} other {{counter} 篇}} PO文", + "hashtag.counter_by_uses_today": "Kin-á日有 {count, plural, one {{counter} 篇} other {{counter} 篇}} PO文", "hashtag.follow": "跟tuè hashtag", "hashtag.unfollow": "取消跟tuè hashtag", "hashtags.and_other": "……kap 其他 {count, plural, other {# ê}}", @@ -468,6 +469,55 @@ "keyboard_shortcuts.spoilers": "顯示/隱藏內容警告", "keyboard_shortcuts.start": "Phah開「開始用」欄", "keyboard_shortcuts.toggle_hidden": "顯示/隱藏內容警告後壁ê PO文", + "keyboard_shortcuts.toggle_sensitivity": "顯示/tshàng媒體", + "keyboard_shortcuts.toot": "PO新PO文", + "keyboard_shortcuts.translate": "kā PO文翻譯", + "keyboard_shortcuts.unfocus": "離開輸入框仔/tshiau-tshuē格仔", + "keyboard_shortcuts.up": "佇列單內kā suá khah面頂", + "lightbox.close": "關", + "lightbox.next": "下tsi̍t ê", + "lightbox.previous": "頂tsi̍t ê", + "lightbox.zoom_in": "Tshūn-kiu kàu實際ê sài-suh", + "lightbox.zoom_out": "Tshūn-kiu kàu適當ê sài-suh", + "limited_account_hint.action": "一直顯示個人資料", + "limited_account_hint.title": "Tsit ê 個人資料予 {domain} ê管理員tshàng起來ah。", + "link_preview.author": "Tuì {name}", + "link_preview.more_from_author": "看 {name} ê其他內容", + "link_preview.shares": "{count, plural, one {{counter} 篇} other {{counter} 篇}} PO文", + "lists.add_member": "加", + "lists.add_to_list": "加添kàu列單", + "lists.add_to_lists": "Kā {name} 加添kàu列單", + "lists.create": "建立", + "lists.create_a_list_to_organize": "開新ê列單,組織lí tshù ê時間線", + "lists.create_list": "建立列單", + "lists.delete": "Thâi掉列單", + "lists.done": "做好ah", + "lists.edit": "編輯列單", + "lists.exclusive": "佇tshù ê時間線kā成員tshàng起來。", + "lists.exclusive_hint": "Nā bóo-mi̍h口座佇tsit ê列單,ē tuì lí tshù ê時間線kā tsit ê口座tshàng起來,避免koh看見in ê PO文。", + "lists.find_users_to_add": "Tshuē beh加添ê用者", + "lists.list_members": "列單ê成員", + "lists.list_members_count": "{count, plural, other {# 位成員}}", + "lists.list_name": "列單ê名", + "lists.new_list_name": "新ê列單ê名", + "lists.no_lists_yet": "Iáu無列單。", + "lists.no_members_yet": "Iáu無成員。", + "lists.no_results_found": "Tshuē無結果。", + "lists.remove_member": "Suá掉", + "lists.replies_policy.followed": "所跟tuè ê任何用者", + "lists.replies_policy.list": "列單ê成員", + "lists.replies_policy.none": "無半位", + "lists.save": "儲存", + "lists.search": "Tshiau-tshuē", + "lists.show_replies_to": "列單成員回應ê顯示範圍", + "load_pending": "{count, plural, other {# ê 項目}}", + "loading_indicator.label": "Leh載入……", + "media_gallery.hide": "Khàm掉", + "moved_to_account_banner.text": "Lí ê口座 {disabledAccount} 已經停止使用ah,因為suá kàu {movedToAccount}。", + "mute_modal.hide_from_notifications": "Tuì通知內底khàm掉", + "mute_modal.hide_options": "Khàm掉選項", + "mute_modal.indefinite": "直到我取消消音", + "mute_modal.show_options": "顯示選項", "notification.favourite_pm": "{name} kah意lí ê私人提起", "notification.favourite_pm.name_and_others_with_link": "{name} kap{count, plural, other {另外 # ê lâng}}kah意lí ê私人提起", "search_popout.language_code": "ISO語言代碼", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index bc19a93c60..15ae4b9e0a 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} пост} few {{counter} поста} other {{counter} постов}}", "account.unblock": "Разблокировать @{name}", "account.unblock_domain": "Разблокировать {domain}", + "account.unblock_domain_short": "Разблокировать", "account.unblock_short": "Разблокировать", "account.unendorse": "Не рекомендовать в профиле", "account.unfollow": "Отписаться", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index a55455f658..d6aff6b56c 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} príspevok} other {{counter} príspevkov}}", "account.unblock": "Odblokovať @{name}", "account.unblock_domain": "Odblokovať doménu {domain}", + "account.unblock_domain_short": "Odblokovať", "account.unblock_short": "Odblokovať", "account.unendorse": "Nezobrazovať na vlastnom profile", "account.unfollow": "Zrušiť sledovanie", @@ -826,6 +827,9 @@ "video.expand": "Zväčšiť video", "video.fullscreen": "Zobraziť na celú obrazovku", "video.hide": "Skryť video", + "video.mute": "Stíšiť", "video.pause": "Pozastaviť", - "video.play": "Prehrať" + "video.play": "Prehrať", + "video.volume_down": "Hlasitosť nadol", + "video.volume_up": "Hlasitosť nahor" } diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 8dc6161a94..1e2e9c585b 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} inlägg} other {{counter} inlägg}}", "account.unblock": "Avblockera @{name}", "account.unblock_domain": "Avblockera {domain}", + "account.unblock_domain_short": "Avblockera", "account.unblock_short": "Avblockera", "account.unendorse": "Visa inte på profil", "account.unfollow": "Sluta följ", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 859413b899..d9e607f856 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{counter} โพสต์}}", "account.unblock": "เลิกปิดกั้น @{name}", "account.unblock_domain": "เลิกปิดกั้นโดเมน {domain}", + "account.unblock_domain_short": "เลิกปิดกั้น", "account.unblock_short": "เลิกปิดกั้น", "account.unendorse": "ไม่แสดงในโปรไฟล์", "account.unfollow": "เลิกติดตาม", @@ -688,6 +689,7 @@ "poll_button.remove_poll": "เอาการสำรวจความคิดเห็นออก", "privacy.change": "เปลี่ยนความเป็นส่วนตัวของโพสต์", "privacy.direct.long": "ทุกคนที่กล่าวถึงในโพสต์", + "privacy.direct.short": "การกล่าวถึงแบบส่วนตัว", "privacy.private.long": "เฉพาะผู้ติดตามของคุณเท่านั้น", "privacy.private.short": "ผู้ติดตาม", "privacy.public.long": "ใครก็ตามที่อยู่ในและนอก Mastodon", @@ -892,6 +894,8 @@ "video.expand": "ขยายวิดีโอ", "video.fullscreen": "เต็มหน้าจอ", "video.hide": "ซ่อนวิดีโอ", + "video.mute": "ปิดเสียง", "video.pause": "หยุดชั่วคราว", - "video.play": "เล่น" + "video.play": "เล่น", + "video.unmute": "เลิกปิดเสียง" } diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index fb920a6b09..d6ffb2b6bf 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -84,6 +84,8 @@ "alert.unexpected.message": "發生意外錯誤。", "alert.unexpected.title": "失敗!", "alt_text_badge.title": "替代文字", + "alt_text_modal.cancel": "取消", + "alt_text_modal.done": "完成", "announcement.announcement": "公告", "attachments_list.unprocessed": "(未處理)", "audio.hide": "隱藏音訊", @@ -135,6 +137,7 @@ "column_header.pin": "置頂", "column_header.show_settings": "顯示設定", "column_header.unpin": "取消置頂", + "column_search.cancel": "取消", "column_subheading.settings": "設定", "community.column_settings.local_only": "只顯示本站", "community.column_settings.media_only": "只顯示多媒體", @@ -344,6 +347,7 @@ "home.pending_critical_update.title": "有重要的安全更新!", "home.show_announcements": "顯示公告", "ignore_notifications_modal.ignore": "忽略推播通知", + "info_button.label": "幫助", "interaction_modal.on_another_server": "於不同伺服器", "interaction_modal.on_this_server": "於此伺服器", "interaction_modal.title.favourite": "把 {name} 的帖文加入最愛", @@ -394,6 +398,7 @@ "limited_account_hint.title": "此個人檔案已被 {domain} 的管理員隱藏。", "link_preview.author": "由 {name} 提供", "lists.delete": "刪除列表", + "lists.done": "完成", "lists.edit": "編輯列表", "lists.replies_policy.followed": "任何已關注的用戶", "lists.replies_policy.list": "列表中的用戶", @@ -461,6 +466,7 @@ "notification.update": "{name} 編輯了帖文", "notification_requests.accept": "接受", "notification_requests.dismiss": "忽略", + "notification_requests.exit_selection": "完成", "notification_requests.notifications_from": "來自 {name} 的通知", "notification_requests.title": "已過濾之通知", "notifications.clear": "清空通知紀錄", @@ -507,6 +513,7 @@ "notifications_permission_banner.enable": "啟用桌面通知", "notifications_permission_banner.how_to_control": "只要啟用桌面通知,便可在 Mastodon 網站沒有打開時收到通知。在已經啟用桌面通知的時候,你可以透過上面的 {icon} 按鈕準確控制哪些類型的互動會產生桌面通知。", "notifications_permission_banner.title": "不放過任何事情", + "onboarding.follows.done": "完成", "onboarding.follows.empty": "很遺憾,現在無法顯示任何結果。你可以嘗試搜尋或瀏覽探索頁面來找使用者來追蹤,或者稍後再試。", "onboarding.profile.discoverable": "將個人檔案設為可被搜尋", "onboarding.profile.discoverable_hint": "當你在 Mastodon 上選擇可被搜尋時,你的帖文可能會出現在搜尋結果和熱門,你的個人檔案也可能被推薦給與你興趣相似的人。", diff --git a/config/locales/activerecord.es-MX.yml b/config/locales/activerecord.es-MX.yml index c3b0562c32..02384f1c71 100644 --- a/config/locales/activerecord.es-MX.yml +++ b/config/locales/activerecord.es-MX.yml @@ -56,7 +56,7 @@ es-MX: user: attributes: date_of_birth: - below_limit: está por debajo de la edad mínima + below_limit: está por debajo del límite de edad email: blocked: utiliza un proveedor de correo no autorizado unreachable: no parece existir diff --git a/config/locales/activerecord.ga.yml b/config/locales/activerecord.ga.yml index e5b07470ae..853c705663 100644 --- a/config/locales/activerecord.ga.yml +++ b/config/locales/activerecord.ga.yml @@ -55,6 +55,8 @@ ga: too_soon: róluath, caithfidh sé bheith níos déanaí ná %{date} user: attributes: + date_of_birth: + below_limit: faoi ​​bhun na teorann aoise email: blocked: úsáideann soláthraí ríomhphoist dícheadaithe unreachable: ní cosúil go bhfuil sé ann diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 9349176842..edd89fedc6 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -511,6 +511,36 @@ cy: new: title: Mewnforio blociau parth no_file: Heb ddewis ffeil + fasp: + debug: + callbacks: + created_at: Crëwyd am + delete: Dileu + ip: Cyfeiriad IP + request_body: Gofyn am y corff + title: Adalwasau Dadfygio + providers: + active: Gweithredol + base_url: URL sylfaen + callback: Adalwad + delete: Dileu + edit: Golygu Darparwr + finish_registration: Gorffen cofrestru + name: Enw + providers: Darparwyr + public_key_fingerprint: Ôl bys allwedd cyhoeddus + registration_requested: Cais am gofrestru + registrations: + confirm: Cadarnhau + description: Rydych wedi derbyn cofrestriad gan FASP. Gwrthodwch hyn os nad chi ofynnodd amdano. Os taw chi gychwynnodd hyn, cymharwch yr enw ac allwedd yr ôl bys yn ofalus cyn cadarnhau'r cofrestriad. + reject: Gwrthod + title: Cadarnhau Cofrestriad FASP + save: Cadw + select_capabilities: Dewis Galluoedd + sign_in: Mewngofnodi + status: Statws + title: Fediverse Auxiliary Service Providers + title: FASP follow_recommendations: description_html: "Mae dilyn yr argymhellion yn helpu i ddefnyddwyr newydd ddod o hyd i gynnwys diddorol yn gyflym. Pan nad yw defnyddiwr wedi rhyngweithio digon ag eraill i ffurfio argymhellion dilyn personol, argymhellir y cyfrifon hyn yn lle hynny. Cânt eu hailgyfrifo'n ddyddiol o gymysgedd o gyfrifon gyda'r ymgysylltiadau diweddar uchaf a'r cyfrif dilynwyr lleol uchaf ar gyfer iaith benodol." language: Ar gyfer iaith diff --git a/config/locales/doorkeeper.kab.yml b/config/locales/doorkeeper.kab.yml index fa9e1c540a..c65bada409 100644 --- a/config/locales/doorkeeper.kab.yml +++ b/config/locales/doorkeeper.kab.yml @@ -111,9 +111,9 @@ kab: lists: Tibdarin media: Imeddayen n umidya mutes: Yeggugem - notifications: Alɣuten + notifications: Ilɣa profile: Amaɣnu-k Mastodon - push: Alɣuten yettudemmren + push: Ilɣa yettudemmren reports: Ineqqisen search: Nadi statuses: Tisuffaɣ @@ -127,7 +127,7 @@ kab: admin:read: ad iɣeṛ akk isefka ɣef uqeddac admin:write: ad iẓreg akk isefka ɣef uqeddac follow: ad ibeddel assaɣen n umiḍan - push: ad iṭṭef-d alɣuten-ik·im yettwademren + push: ad iṭṭef-d ilɣa-k·m yettwademren read: ad iɣeṛ akk isefka n umiḍan-ik·im read:accounts: ẓer isallen n yimiḍanen read:blocks: ẓer imiḍanen i tesḥebseḍ @@ -136,7 +136,7 @@ kab: read:follows: ẓer imeḍfaṛen-ik read:lists: ẓer tibdarin-ik·im read:mutes: ẓer wid i tesgugmeḍ - read:notifications: ad iẓer alɣuten-inek·inem + read:notifications: ad iẓer ilɣa-inek·inem read:reports: ẓer ineqqisen-ik·im read:search: anadi deg umkan-ik·im read:statuses: ad iẓer meṛṛa tisuffaɣ @@ -148,4 +148,4 @@ kab: write:follows: ḍfeṛ imdanen write:lists: ad yesnulfu tibdarin write:media: ad yessali ifuyla n umidya - write:notifications: sfeḍ alɣuten-ik·im + write:notifications: sfeḍ ilɣa-k·m diff --git a/config/locales/el.yml b/config/locales/el.yml index 2c6d91298e..d2f4fbba01 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -318,6 +318,9 @@ el: new: create: Δημιουργία ανακοίνωσης title: Νέα ανακοίνωση + preview: + explanation_html: 'Το email θα αποσταλεί σε %{display_count} χρήστες. Το ακόλουθο κείμενο θα συμπεριληφθεί στο e-mail:' + title: Προεπισκόπηση ειδοποίησης ανακοίνωσης publish: Δημοσίευση published_msg: Επιτυχής δημοσίευση ανακοίνωσης! scheduled_for: Προγραμματισμένη για %{time} @@ -476,6 +479,34 @@ el: new: title: Εισαγωγή αποκλεισμένων τομέων no_file: Δεν επιλέχθηκε αρχείο + fasp: + debug: + callbacks: + created_at: Δημιουργήθηκε στις + delete: Διαγραφή + ip: Διεύθυνση IP + request_body: Σώμα αιτήματος + title: Κλήσεις Αποσφαλμάτωσης + providers: + active: Ενεργό + base_url: URL βάσης + callback: Επανάκληση + delete: Διαγραφή + edit: Επεξεργασία Παρόχου + finish_registration: Ολοκλήρωση εγγραφής + name: Όνομα + providers: Πάροχοι + public_key_fingerprint: Αποτύπωμα δημόσιου κλειδιού + registration_requested: Η εγγραφή ζητήθηκε + registrations: + confirm: Επιβεβαίωση + description: Έλαβες μια εγγραφή από ένα FASP. Απέρριψέ την αν δεν την άρχισες εσύ. Αν το άρχισες εσύ, σύγκρινε προσεκτικά το όνομα και το κλειδί αποτύπωμα πριν από την επιβεβαίωση της εγγραφής. + reject: Απόρριψη + title: Επιβεβαίωση Εγγραφής FASP + save: Αποθήκευση + select_capabilities: Επέλεξε Δυνατότητες + sign_in: Σύνδεση + status: Κατάσταση follow_recommendations: description_html: "Ακολουθώντας συστάσεις βοηθάει τους νέους χρήστες να βρουν γρήγορα ενδιαφέρον περιεχόμενο. Όταν ένας χρήστης δεν έχει αλληλεπιδράσει με άλλους αρκετά για να διαμορφώσει εξατομικευμένες συστάσεις, συνιστώνται αυτοί οι λογαριασμοί. Υπολογίζονται εκ νέου σε καθημερινή βάση από ένα σύνολο λογαριασμών με τις υψηλότερες πρόσφατες αλληλεπιδράσεις και μεγαλύτερο αριθμό τοπικών ακόλουθων για μια δεδομένη γλώσσα." language: Για τη γλώσσα diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 5f92f2c85d..a9192740fe 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -500,7 +500,7 @@ es-MX: registration_requested: Se solicitó el registro registrations: confirm: Confirmar - description: Has recibido un registro de un FASP. Recházalo si no lo iniciaste tú. Si lo iniciaste tú, compara cuidadosamente el nombre y la huella de la clave antes de confirmar el registro. + description: Has recibido un registro de un FASP. Recházalo si no lo iniciaste tú. Si lo comenzaste tú, compara cuidadosamente el nombre y la huella de la clave antes de confirmar el registro. reject: Rechazar title: Confirmar registro FASP save: Guardar diff --git a/config/locales/ga.yml b/config/locales/ga.yml index d552c72de7..58d02fc6a9 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -503,6 +503,36 @@ ga: new: title: Iompórtáil bloic fearainn no_file: Níor roghnaíodh aon chomhad + fasp: + debug: + callbacks: + created_at: Cruthaithe ag + delete: Scrios + ip: Seoladh IP + request_body: Comhlacht iarratais + title: Glaonna Dífhabhtaithe + providers: + active: Gníomhach + base_url: Bun-URL + callback: Glao ar ais + delete: Scrios + edit: Cuir Soláthraí in Eagar + finish_registration: Críochnaigh clárú + name: Ainm + providers: Soláthraithe + public_key_fingerprint: Méarloirg eochair phoiblí + registration_requested: Clárú iarrtha + registrations: + confirm: Deimhnigh + description: Fuair ​​tú clárú ó FASP. Diúltaigh é murar chuir tú tús leis seo. Má thionscain tú é seo, déan comparáid chúramach idir an t-ainm agus an eochair-mhéarlorg sula ndearbhaítear an clárúchán. + reject: Diúltaigh + title: Deimhnigh Clárú FASP + save: Sábháil + select_capabilities: Roghnaigh Cumais + sign_in: Sínigh Isteach + status: Stádas + title: Soláthraithe Seirbhíse Cúnta Fediverse + title: FASP follow_recommendations: description_html: "Lean na moltaí cabhraíonn sé le húsáideoirí nua ábhar suimiúil a aimsiú go tapa. Nuair nach mbíonn go leor idirghníomhaithe ag úsáideoir le daoine eile chun moltaí pearsantaithe a leanúint, moltar na cuntais seo ina ionad sin. Déantar iad a athríomh ar bhonn laethúil ó mheascán de chuntais a bhfuil na rannpháirtíochtaí is airde acu le déanaí agus na háirimh áitiúla is airde leanúna do theanga ar leith." language: Don teanga diff --git a/config/locales/kab.yml b/config/locales/kab.yml index 1f6fc8f698..85a88be7bb 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -615,7 +615,7 @@ kab: filters: contexts: account: Imeɣna - notifications: Alɣuten + notifications: Ilɣa thread: Idiwenniyen edit: add_keyword: Rnu awal tasarut @@ -810,7 +810,7 @@ kab: import: Kter import_and_export: Taktert d usifeḍ migrate: Tunigin n umiḍan - notifications: Alɣuten s imayl + notifications: Ilɣa s imayl preferences: Imenyafen profile: Ameɣnu relationships: Imeḍfaṛen akked wid i teṭṭafaṛeḍ diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 07fc9c9780..6a21ad8cee 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -486,6 +486,17 @@ lv: delete: Izdzēst ip: IP adrese request_body: Pieprasījuma saturs + providers: + base_url: Pamata URL + delete: Izdzēst + edit: Labot nodrošinātāju + finish_registration: Pabeigt reģistrēšanos + name: Nosaukums + providers: Nodrošinātāji + public_key_fingerprint: Publiskās atslēgas pirkstu nospiedums + registration_requested: Pieprasīta reģistrēšanās + registrations: + confirm: Apstiprināt follow_recommendations: description_html: "Sekošanas ieteikumi palīdz jauniem lietotājiem ātri arast saistošu saturu. Kad lietotājs nav pietiekami mijiedarbojies ar citiem, lai veidotos pielāgoti sekošanas iteikumi, tiek ieteikti šie konti. Tie tiek pārskaitļoti ik dienas, izmantojot kontu, kuriem ir augstākās nesenās iesaistīšanās un lielākais vietējo sekotāju skaits norādītajā valodā." language: Valodai diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 0501e8cb54..8c06332695 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -495,6 +495,9 @@ ru: new: title: Импорт доменных блокировок no_file: Файл не выбран + fasp: + providers: + sign_in: follow_recommendations: description_html: "Следуйте рекомендациям, чтобы помочь новым пользователям быстро находить интересный контент. Если пользователь не взаимодействовал с другими в достаточной степени, чтобы сформировать персонализированные рекомендации, вместо этого рекомендуется использовать эти учетные записи. Они пересчитываются на ежедневной основе на основе комбинации аккаунтов с наибольшим количеством недавних взаимодействий и наибольшим количеством местных подписчиков для данного языка." language: Для языка diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml index b768c6551f..b2f7daf500 100644 --- a/config/locales/simple_form.es-MX.yml +++ b/config/locales/simple_form.es-MX.yml @@ -51,7 +51,7 @@ es-MX: inbox_url: Copia la URL de la página principal del relé que deseas usar irreversible: Las publicaciones filtradas desaparecerán irreversiblemente, incluso si este filtro es eliminado más adelante locale: El idioma de la interfaz de usuario, correos y notificaciones push - password: Utiliza al menos 8 caracteres + password: Usa al menos 8 caracteres phrase: Se aplicará sin importar las mayúsculas o los avisos de contenido de una publicación scopes: Qué APIs de la aplicación tendrán acceso. Si seleccionas el alcance de nivel mas alto, no necesitas seleccionar las individuales. setting_aggregate_reblogs: No mostrar nuevos impulsos para las publicaciones que han sido recientemente impulsadas (sólo afecta a las publicaciones recibidas recientemente) @@ -68,10 +68,10 @@ es-MX: domain_allow: domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados email_domain_block: - domain: Este puede ser el nombre de dominio que se muestra en al dirección de correo o el registro MX que utiliza. Se comprobarán al registrarse. + domain: Este puede ser el nombre de dominio que se muestra en la dirección de correo o el registro MX que utiliza. Se comprobarán al registrarse. with_dns_records: Se hará un intento de resolver los registros DNS del dominio dado y los resultados serán también puestos en lista negra featured_tag: - name: 'Aquí están algunas de las etiquetas que más has utilizado recientemente:' + name: 'Aquí están algunas de las etiquetas que más has usado recientemente:' filters: action: Elegir qué acción realizar cuando una publicación coincide con el filtro actions: @@ -90,14 +90,14 @@ es-MX: mascot: Reemplaza la ilustración en la interfaz web avanzada. media_cache_retention_period: Los archivos multimedia de las publicaciones realizadas por usuarios remotos se almacenan en caché en su servidor. Si se establece en un valor positivo, los archivos multimedia se eliminarán tras el número de días especificado. Si los datos multimedia se solicitan después de haber sido eliminados, se volverán a descargar, si el contenido de origen sigue estando disponible. Debido a las restricciones sobre la frecuencia con la que las tarjetas de previsualización de enlaces sondean sitios de terceros, se recomienda establecer este valor en al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese tiempo. min_age: Se pedirá a los usuarios que confirmen su fecha de nacimiento al registrarse - peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el fediverso. Aquí no se incluye ningún dato sobre si usted federa con un servidor determinado, sólo que su servidor lo sabe. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. + peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el fediverso. Aquí no se incluye ningún dato sobre si usted federa con un servidor determinado, solamente que su servidor lo sabe. Esto es usado por los servicios que recopilan estadísticas sobre la federación en un sentido general. profile_directory: El directorio de perfiles lista a todos los usuarios que han optado por que su cuenta pueda ser descubierta. require_invite_text: Cuando los registros requieren aprobación manual, hace obligatoria la entrada de texto "¿Por qué quieres unirte?" en lugar de opcional site_contact_email: Cómo la gente puede ponerse en contacto contigo para consultas legales o de ayuda. site_contact_username: Cómo puede contactarte la gente en Mastodon. site_extended_description: Cualquier información adicional que pueda ser útil para los visitantes y sus usuarios. Se puede estructurar con formato Markdown. site_short_description: Una breve descripción para ayudar a identificar su servidor de forma única. ¿Quién lo administra, a quién va dirigido? - site_terms: Utiliza tu propia política de privacidad o déjala en blanco para usar la predeterminada Puede estructurarse con formato Markdown. + site_terms: Usa tu propia política de privacidad o déjala en blanco para usar la predeterminada Puede estructurarse con formato Markdown. site_title: Cómo puede referirse la gente a tu servidor además de por el nombre de dominio. status_page_url: URL de una página donde las personas pueden ver el estado de este servidor durante una interrupción theme: El tema que los visitantes no registrados y los nuevos usuarios ven. @@ -138,11 +138,11 @@ es-MX: text: Puede estructurarse con la sintaxis Markdown. terms_of_service_generator: admin_email: Las notificaciones legales incluyen contraavisos, órdenes judiciales, solicitudes de retirada y solicitudes de aplicación de la ley. - arbitration_address: Puede ser la misma que la dirección física anterior, o "N/A" si utiliza correo electrónico. - arbitration_website: Puede ser un formulario web, o “N/A” si utiliza correo electrónico. + arbitration_address: Puede ser la misma que la dirección física anterior, o "N/A" si usa correo electrónico. + arbitration_website: Puede ser un formulario web, o “N/A” si usa correo electrónico. choice_of_law: Ciudad, región, territorio o estado de las leyes de sustancia interna de las que se regirán todas y cada una de las reclamaciones. dmca_address: Para los operadores de EE. UU., utilice la dirección registrada en el Directorio de Agentes Designados de la DMCA. Un listado de apartados de correos está disponible bajo petición directa, utilice la Solicitud de Renuncia de Apartado de Correos de Agente Designado de la DMCA para enviar un correo electrónico a la Oficina de Derechos de Autor y describa que usted es un moderador de contenidos desde su casa que teme venganza o represalias por sus acciones y necesita utilizar un apartado de correos para eliminar su dirección particular de la vista del público. - dmca_email: Puede ser el mismo correo electrónico utilizado para "Dirección de correo electrónico para avisos legales" de arriba. + dmca_email: Puede ser el mismo correo electrónico usado para “Dirección de correo electrónico para avisos legales” de arriba. domain: Identificación única del servicio en línea que presta. jurisdiction: Indique el país de residencia de quien paga las facturas. Si se trata de una empresa u otra entidad, indique el país en el que está constituida y la ciudad, región, territorio o estado, según proceda. min_age: No debe ser menor de la edad mínima exigida por las leyes de su jurisdicción. diff --git a/config/locales/simple_form.ga.yml b/config/locales/simple_form.ga.yml index af75401d3f..bd8dac2a36 100644 --- a/config/locales/simple_form.ga.yml +++ b/config/locales/simple_form.ga.yml @@ -75,6 +75,7 @@ ga: filters: action: Roghnaigh an gníomh ba cheart a dhéanamh nuair a mheaitseálann postáil an scagaire actions: + blur: Folaigh na meáin taobh thiar de rabhadh, gan an téacs féin a cheilt hide: Cuir an t-ábhar scagtha i bhfolach go hiomlán, ag iompar amhail is nach raibh sé ann warn: Folaigh an t-ábhar scagtha taobh thiar de rabhadh a luann teideal an scagaire form_admin_settings: @@ -88,6 +89,7 @@ ga: favicon: WEBP, PNG, GIF nó JPG. Sáraíonn sé an favicon Mastodon réamhshocraithe le deilbhín saincheaptha. mascot: Sáraíonn sé an léaráid san ardchomhéadan gréasáin. media_cache_retention_period: Déantar comhaid meán ó phoist a dhéanann cianúsáideoirí a thaisceadh ar do fhreastalaí. Nuair a bheidh luach dearfach socraithe, scriosfar na meáin tar éis an líon sonraithe laethanta. Má iarrtar na sonraí meán tar éis é a scriosadh, déanfar é a ath-íoslódáil, má tá an t-ábhar foinse fós ar fáil. Mar gheall ar shrianta ar cé chomh minic is atá cártaí réamhamhairc ag vótaíocht do shuíomhanna tríú páirtí, moltar an luach seo a shocrú go 14 lá ar a laghad, nó ní dhéanfar cártaí réamhamhairc naisc a nuashonrú ar éileamh roimh an am sin. + min_age: Iarrfar ar úsáideoirí a ndáta breithe a dhearbhú le linn clárúcháin peers_api_enabled: Liosta de na hainmneacha fearainn ar tháinig an freastalaí seo orthu sa choinbhleacht. Níl aon sonraí san áireamh anseo faoi cé acu an ndéanann tú cónascadh le freastalaí ar leith, díreach go bhfuil a fhios ag do fhreastalaí faoi. Úsáideann seirbhísí a bhailíonn staitisticí ar chónaidhm go ginearálta é seo. profile_directory: Liostaíonn an t-eolaire próifíle na húsáideoirí go léir a roghnaigh isteach le bheith in-aimsithe. require_invite_text: Nuair a bhíonn faomhadh láimhe ag teastáil le haghaidh clárúcháin, déan an "Cén fáth ar mhaith leat a bheith páirteach?" ionchur téacs éigeantach seachas roghnach @@ -146,6 +148,7 @@ ga: min_age: Níor chóir go mbeidís faoi bhun na haoise íosta a éilíonn dlíthe do dhlínse. user: chosen_languages: Nuair a dhéantar iad a sheiceáil, ní thaispeánfar ach postálacha i dteangacha roghnaithe in amlínte poiblí + date_of_birth: Ní mór dúinn a chinntiú go bhfuil tú ar a laghad %{age} chun Mastodon a úsáid. Ní stórálfaimid é seo. role: Rialaíonn an ról na ceadanna atá ag an úsáideoir. user_role: color: Dath le húsáid don ról ar fud an Chomhéadain, mar RGB i bhformáid heicsidheachúlach @@ -258,6 +261,7 @@ ga: name: Haischlib filters: actions: + blur: Folaigh na meáin le rabhadh hide: Cuir i bhfolach go hiomlán warn: Cuir i bhfolach le rabhadh form_admin_settings: @@ -271,6 +275,7 @@ ga: favicon: Favicon mascot: Mascóg saincheaptha (oidhreacht) media_cache_retention_period: Tréimhse choinneála taisce meán + min_age: Riachtanas aoise íosta peers_api_enabled: Foilsigh liosta de na freastalaithe aimsithe san API profile_directory: Cumasaigh eolaire próifíle registrations_mode: Cé atá in ann clárú @@ -349,6 +354,9 @@ ga: jurisdiction: Dlínse dhlíthiúil min_age: Aois íosta user: + date_of_birth_1i: Lá + date_of_birth_2i: Mí + date_of_birth_3i: Bliain role: Ról time_zone: Crios ama user_role: diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml index c14f6376a0..c0ff7e598e 100644 --- a/config/locales/simple_form.kab.yml +++ b/config/locales/simple_form.kab.yml @@ -18,7 +18,7 @@ kab: bot: Smekti-d wiyaḍ dakken amiḍan-a ixeddem s wudem amezwer tigawin tiwurmanin yernu ur yezmir ara ad yettwaɛass email: Ad n-teṭṭfeḍ imayl i usentem irreversible: Tisuffaɣ i tessazedgeḍ ad ttwakksent i lebda, ula ma tekkseḍ imsizdeg-nni ar zdat - locale: Tutlayt n ugrudem, imaylen d walɣuten yettudemren + locale: Tutlayt n ugrudem, imaylen d yilɣa yettudemren password: Seqdec ma drus 8 n yisekkilen setting_always_send_emails: S umata, ilɣa s yimayl ur d-ttwaceyyεen ara mi ara tesseqdaceḍ Mastodon s wudem urmid setting_display_media_default: Ffer imidyaten yettwacreḍ d infariyen @@ -115,8 +115,8 @@ kab: theme: Asentel amezwer thumbnail: Tanfult n uqeddac interactions: - must_be_follower: Ssewḥel alɣuten sɣur wid akked tid ur yellin ara d imeḍfaren-ik·im - must_be_following: Ssewḥel alɣuten sɣur wid akked tid ur tettḍafareḍ ara + must_be_follower: Ssewḥel ilɣa sɣur wid akk d tid ur yellin ara d imeḍfaren-ik·im + must_be_following: Ssewḥel ilɣa sɣur wid akked tid ur tettḍafareḍ ara must_be_following_dm: Sewḥel iznan usriden sɣur wid akked tid ur tettḍafareḍ ara invite: comment: Awennit diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index dfaa61e0cc..530bd60ad1 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -324,6 +324,9 @@ th: terms_of_service_generator: domain: โดเมน user: + date_of_birth_1i: วัน + date_of_birth_2i: เดือน + date_of_birth_3i: ปี role: บทบาท time_zone: โซนเวลา user_role: diff --git a/config/locales/th.yml b/config/locales/th.yml index 9b7ae7897d..19f9e4da1f 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -466,6 +466,12 @@ th: new: title: นำเข้าการปิดกั้นโดเมน no_file: ไม่ได้เลือกไฟล์ + fasp: + debug: + callbacks: + created_at: สร้างเมื่อ + delete: ลบ + ip: ที่อยู่ IP follow_recommendations: description_html: "คำแนะนำการติดตามช่วยให้ผู้ใช้ใหม่ค้นหาเนื้อหาที่น่าสนใจได้อย่างรวดเร็ว เมื่อผู้ใช้ไม่ได้โต้ตอบกับผู้อื่นมากพอที่จะสร้างคำแนะนำการติดตามเฉพาะบุคคล จะแนะนำบัญชีเหล่านี้แทน จะคำนวณคำแนะนำใหม่เป็นประจำทุกวันจากบัญชีต่าง ๆ ที่มีการมีส่วนร่วมล่าสุดสูงสุดและจำนวนผู้ติดตามในเซิร์ฟเวอร์สูงสุดสำหรับภาษาที่กำหนด" language: สำหรับภาษา @@ -1636,7 +1642,7 @@ th: last_active: ใช้งานล่าสุด most_recent: ล่าสุด moved: ย้ายแล้ว - mutual: ร่วมกัน + mutual: คนที่มีร่วมกัน primary: หลัก relationship: ความสัมพันธ์ remove_selected_domains: เอาผู้ติดตามทั้งหมดออกจากโดเมนที่เลือก diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 7278058dce..43f4f3ecba 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -38,7 +38,7 @@ zh-HK: current_email: 現時電郵 label: 更改電郵 new_email: 新的電郵 - submit: 改變電郵 + submit: 更改電郵 title: 改變 %{username} 的電郵 change_role: changed_msg: 成功更改身份! @@ -182,6 +182,7 @@ zh-HK: destroy_domain_block: 刪除已封鎖的域名 destroy_instance: 清除網域 destroy_ip_block: 刪除 IP 規則 + destroy_relay: 刪除中繼 destroy_status: 刪除文章 destroy_unavailable_domain: 刪除無效域名 destroy_user_role: 刪除身份 @@ -425,6 +426,12 @@ zh-HK: new: title: 匯入封鎖的網域 no_file: 未選擇檔案 + fasp: + debug: + callbacks: + delete: 刪除 + providers: + delete: 刪除 follow_recommendations: description_html: "跟隨建議幫助新使用者快速找到有趣內容。 當使用者尚未和其他帳號足夠多的互動以產生個人化建議時,以下帳號將被推荐。這些是一句指定語言的近期參與度和本地粉絲數最高之帳戶組合每日重新計算。" language: 按語言 @@ -1549,6 +1556,7 @@ zh-HK: import: 匯入 import_and_export: 匯入及匯出 migrate: 帳戶遷移 + notifications: 電郵通知 preferences: 偏好設定 profile: 個人資料 relationships: 關注及追隨者 From 264ecdcc13d39ab929230e62e454b67532fbebc5 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 7 Apr 2025 11:31:00 +0200 Subject: [PATCH 15/48] Bump version to v4.3.7 (#34385) --- CHANGELOG.md | 23 +++++++++++++++++++++++ docker-compose.yml | 6 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b0f64146..4dd4783597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file. +## [4.3.7] - 2025-04-02 + +### Add + +- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire) +- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire) + +### Changed + +- Change account suspensions to be federated to recently-followed accounts as well (#34294 by @ClearlyClaire) +- Change `AccountReachFinder` to consider statuses based on suspension date (#32805 and #34291 by @ClearlyClaire and @mjankowski) +- Change user archive signed URL TTL from 10 seconds to 1 hour (#34254 by @ClearlyClaire) + +### Fixed + +- Fix static version of animated PNG emojis not being properly extracted (#34337 by @ClearlyClaire) +- Fix filters not applying in detailed view, favourites and bookmarks (#34259 and #34260 by @ClearlyClaire) +- Fix handling of malformed/unusual HTML (#34201 by @ClearlyClaire) +- Fix `CacheBuster` being queued for missing media attachments (#34253 by @ClearlyClaire) +- Fix incorrect URL being used when cache busting (#34189 by @ClearlyClaire) +- Fix streaming server refusing unix socket path in `DATABASE_URL` (#34091 by @ClearlyClaire) +- Fix “x” hotkey not working on boosted filtered posts (#33758 by @ClearlyClaire) + ## [4.3.6] - 2025-03-13 ### Security diff --git a/docker-compose.yml b/docker-compose.yml index 95375d17d0..ba34d858a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,7 +59,7 @@ services: web: # You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes # build: . - image: ghcr.io/mastodon/mastodon:v4.3.6 + image: ghcr.io/mastodon/mastodon:v4.3.7 restart: always env_file: .env.production command: bundle exec puma -C config/puma.rb @@ -83,7 +83,7 @@ services: # build: # dockerfile: ./streaming/Dockerfile # context: . - image: ghcr.io/mastodon/mastodon-streaming:v4.3.6 + image: ghcr.io/mastodon/mastodon-streaming:v4.3.7 restart: always env_file: .env.production command: node ./streaming/index.js @@ -102,7 +102,7 @@ services: sidekiq: # You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes # build: . - image: ghcr.io/mastodon/mastodon:v4.3.6 + image: ghcr.io/mastodon/mastodon:v4.3.7 restart: always env_file: .env.production command: bundle exec sidekiq From 54aefa90145960de5c80b4ee4f6b60accd8d9a6c Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 7 Apr 2025 12:55:04 +0200 Subject: [PATCH 16/48] Fix visual glitches with filtering posts (#34387) --- app/javascript/styles/mastodon/components.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 66513750e6..d2a1c2b7b8 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5271,6 +5271,9 @@ a.status-card { &__results { &__item { + display: flex; + align-items: center; + gap: 0.5em; cursor: pointer; color: $primary-text-color; font-size: 14px; @@ -6275,7 +6278,7 @@ a.status-card { a { text-decoration: none; - color: $inverted-text-color; + color: $highlight-text-color; font-weight: 500; &:hover { From ff7230df065461ad3fafefdb974f723641059388 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 7 Apr 2025 12:56:30 +0200 Subject: [PATCH 17/48] Forces radio buttons to be correctly centred (#34389) --- app/javascript/styles/mastodon/components.scss | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d2a1c2b7b8..a399553f29 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -7572,14 +7572,11 @@ a.status-card { } .radio-button__input.checked::before { - position: absolute; - left: 2px; - top: 2px; content: ''; display: block; border-radius: 50%; - width: 12px; - height: 12px; + width: calc(100% - 4px); + height: calc(100% - 4px); background: $ui-highlight-color; } From 94ae96b9bc1753d5ccbea1c9ab2dae15d284b4ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 08:29:21 +0200 Subject: [PATCH 18/48] chore(deps): update dependency haml_lint to v0.62.0 (#34394) 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 4d4d0d1792..865686a5bd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -280,7 +280,7 @@ GEM activesupport (>= 5.1) haml (>= 4.0.6) railties (>= 5.1) - haml_lint (0.61.1) + haml_lint (0.62.0) haml (>= 5.0) parallel (~> 1.10) rainbow From f31b5334353a594b17770495a925484aceb51186 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 08:46:46 +0200 Subject: [PATCH 19/48] New Crowdin Translations (automated) (#34395) Co-authored-by: GitHub Actions --- config/locales/lv.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 6a21ad8cee..9ed84286d8 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -262,6 +262,7 @@ lv: destroy_custom_emoji_html: "%{name} izdzēsa emocijzīmi %{target}" destroy_domain_allow_html: "%{name} neatļāva federāciju ar domēnu %{target}" destroy_domain_block_html: "%{name} atbloķēja domēnu %{target}" + destroy_email_domain_block_html: "%{name} atcēla e-pasta domēna %{target} liegumu" destroy_instance_html: "%{name} attīrija domēnu %{target}" destroy_ip_block_html: "%{name} izdzēsa nosacījumu priekš IP %{target}" destroy_status_html: "%{name} noņēma ziņu %{target}" @@ -486,8 +487,10 @@ lv: delete: Izdzēst ip: IP adrese request_body: Pieprasījuma saturs + title: Atkļūdošanas atpakaļsaukumi providers: base_url: Pamata URL + callback: Atpakaļsaukums delete: Izdzēst edit: Labot nodrošinātāju finish_registration: Pabeigt reģistrēšanos @@ -497,6 +500,15 @@ lv: registration_requested: Pieprasīta reģistrēšanās registrations: confirm: Apstiprināt + description: Tu saņēmi reģistrēšanos no FĀPS. Tā ir jānoraida, ja to neveici. Ja veici, rūpīgi jāsalīdzina nosaukums un atslēgas pirkstu nospiedums, pirms reģistrēšanās apstiprināšanas. + reject: Noraidīt + title: Apstiprināt FĀPS reģistrēšanos + save: Saglabāt + select_capabilities: Atlasīt spējas + sign_in: Pieteikties + status: Stāvoklis + title: Fediverse ārējie pakalpojumu sniedzēji + title: FĀPS follow_recommendations: description_html: "Sekošanas ieteikumi palīdz jauniem lietotājiem ātri arast saistošu saturu. Kad lietotājs nav pietiekami mijiedarbojies ar citiem, lai veidotos pielāgoti sekošanas iteikumi, tiek ieteikti šie konti. Tie tiek pārskaitļoti ik dienas, izmantojot kontu, kuriem ir augstākās nesenās iesaistīšanās un lielākais vietējo sekotāju skaits norādītajā valodā." language: Valodai @@ -643,6 +655,9 @@ lv: actions_description_remote_html: Izlem, kādas darbības jāveic, lai atrisinātu šo ziņojumu. Tas ietekmēs tikai to, kā tavs serveris sazinās ar šo attālo kontu un apstrādā tā saturu. actions_no_posts: Šim ziņojumam nav saistītu ierakstu, kurus izdzēst add_to_report: Pievienot varāk paziņošanai + already_suspended_badges: + local: Jau ir apturēts šajā serverī + remote: Jau ir apturēts viņu serverī are_you_sure: Vai esi pārliecināts? assign_to_self: Piešķirt man assigned: Piešķirtais satura pārraudzītājs @@ -702,6 +717,7 @@ lv: delete_data_html: Dzēsiet lietotāja @%{acct} profilu un saturu pēc 30 dienām, ja vien to darbība pa šo laiku netiks atcelta preview_preamble_html: "@%{acct} saņems brīdinājumu ar šādu saturu:" record_strike_html: Ierakstiet brīdinājumu pret @%{acct}, lai palīdzētu jums izvērst turpmākus pārkāpumus no šī konta + send_email_html: Nosūtīt @%{acct} brīdinājuma e-pasta ziņojumu warning_placeholder: Izvēles papildu pamatojums satura pārraudzības darbībai. target_origin: Ziņotā konta izcelsme title: Ziņojumi @@ -743,6 +759,7 @@ lv: manage_appeals: Pārvaldīt Pārsūdzības manage_appeals_description: Ļauj lietotājiem pārskatīt iebildumus pret satura pārraudzības darbībām manage_blocks: Pārvaldīt Bloķus + manage_blocks_description: Ļauj lietotājiem liegt e-pasta pakalpojumu sniedzējus un IP adreses manage_custom_emojis: Pārvaldīt Pielāgotās Emocijzīmes manage_custom_emojis_description: Ļauj lietotājiem pārvaldīt pielāgotās emocijzīmes serverī manage_federation: Pārvaldīt Federāciju @@ -760,6 +777,7 @@ lv: manage_taxonomies: Pārvaldīt Taksonomijas manage_taxonomies_description: Ļauj lietotājiem pārskatīt aktuālāko saturu un atjaunināt tēmturu iestatījumus manage_user_access: Pārvaldīt Lietotāju Piekļuves + manage_user_access_description: Ļauj lietotājiem atspējot citu lietotāju divupakāpju autentificēšanos, mainīt savu e-pasta adresi un atiestatīt savu paroli manage_users: Pārvaldīt Lietotājus manage_users_description: Ļauj lietotājiem skatīt citu lietotāju informāciju un veikt pret viņiem satura pārraudzības darbības manage_webhooks: Pārvaldīt Tīmekļa Aizķeres @@ -834,6 +852,7 @@ lv: destroyed_msg: Vietnes augšupielāde sekmīgi izdzēsta. software_updates: critical_update: Kritiski - lūdzu, ātri atjaunini + description: Ir ieteicams uzturēt savu Mastodon serveri atjauninātu, lai gūtu labumu no jaunākajiem labojumiem un iespējām. Vēl jo vairāk, dažreiz ir ļoti svarīgi savlaicīgi atjaunināt Mastodon, lai izvairītos no drošības nepilnībām. Šo iemeslu dēļ Mastodon pārbauda atjauninājumus ik pēc 30 minūtēm, un paziņos atbilstoši e-pasta paziņojumu iestatījumiem. documentation_link: Uzzināt vairāk release_notes: Laidiena piezīmes title: Pieejamie atjauninājumi From ebfd48b0f2566733268705888c3836aa7d2a4da8 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 8 Apr 2025 09:18:52 +0200 Subject: [PATCH 20/48] Remove 4.1 support from SECURITY.md (#34386) --- SECURITY.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 43ab4454c4..26c06e67f8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,9 +13,8 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through ## Supported Versions -| Version | Supported | -| ------- | ---------------- | -| 4.3.x | Yes | -| 4.2.x | Yes | -| 4.1.x | Until 2025-04-08 | -| < 4.1 | No | +| Version | Supported | +| ------- | --------- | +| 4.3.x | Yes | +| 4.2.x | Yes | +| < 4.2 | No | From d81983f181c5051804438c99a27be5939e293cff Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 8 Apr 2025 12:35:54 +0200 Subject: [PATCH 21/48] Fix the delete suggestion button not working and using a deprecated endpoint (#34396) --- app/javascript/mastodon/api/suggestions.ts | 2 +- app/javascript/mastodon/features/explore/components/card.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/api/suggestions.ts b/app/javascript/mastodon/api/suggestions.ts index d4817698cc..976986c0ab 100644 --- a/app/javascript/mastodon/api/suggestions.ts +++ b/app/javascript/mastodon/api/suggestions.ts @@ -5,4 +5,4 @@ export const apiGetSuggestions = (limit: number) => apiRequestGet('v2/suggestions', { limit }); export const apiDeleteSuggestion = (accountId: string) => - apiRequestDelete(`v1/suggestions/${accountId}`); + apiRequestDelete(`v2/suggestions/${accountId}`); diff --git a/app/javascript/mastodon/features/explore/components/card.jsx b/app/javascript/mastodon/features/explore/components/card.jsx index 15470ec24c..9617781b53 100644 --- a/app/javascript/mastodon/features/explore/components/card.jsx +++ b/app/javascript/mastodon/features/explore/components/card.jsx @@ -25,7 +25,7 @@ export const Card = ({ id, source }) => { const dispatch = useDispatch(); const handleDismiss = useCallback(() => { - dispatch(dismissSuggestion(id)); + dispatch(dismissSuggestion({ accountId: id })); }, [id, dispatch]); let label; From 36afb4557a460b911585305892f20f16668cf1d9 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 8 Apr 2025 16:32:17 +0200 Subject: [PATCH 22/48] Fix incorrect deprecation warning for `DELETE /api/v1/suggestions/:id` (#34397) --- app/controllers/api/v1/suggestions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/suggestions_controller.rb b/app/controllers/api/v1/suggestions_controller.rb index 918ec45beb..df9346832f 100644 --- a/app/controllers/api/v1/suggestions_controller.rb +++ b/app/controllers/api/v1/suggestions_controller.rb @@ -4,7 +4,7 @@ class Api::V1::SuggestionsController < Api::BaseController include Authorization include DeprecationConcern - deprecate_api '2021-05-16' + deprecate_api '2021-05-16', only: [:index] before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, except: :index From f66d092b322628bfe0e83882cd54e58895886c5a Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 8 Apr 2025 16:49:49 +0200 Subject: [PATCH 23/48] Fix usage of incorrect API endpoint for suggestion deletion (#34398) --- app/javascript/mastodon/api/suggestions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/api/suggestions.ts b/app/javascript/mastodon/api/suggestions.ts index 976986c0ab..d4817698cc 100644 --- a/app/javascript/mastodon/api/suggestions.ts +++ b/app/javascript/mastodon/api/suggestions.ts @@ -5,4 +5,4 @@ export const apiGetSuggestions = (limit: number) => apiRequestGet('v2/suggestions', { limit }); export const apiDeleteSuggestion = (accountId: string) => - apiRequestDelete(`v2/suggestions/${accountId}`); + apiRequestDelete(`v1/suggestions/${accountId}`); From 887336f2c66b6ac5049d10bf5f27fa69a15e0745 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 16:58:42 +0200 Subject: [PATCH 24/48] fix(deps): update dependency tesseract.js to v6.0.1 (#34388) 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 e9694d35fd..1568040692 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17265,8 +17265,8 @@ __metadata: linkType: hard "tesseract.js@npm:^6.0.0": - version: 6.0.0 - resolution: "tesseract.js@npm:6.0.0" + version: 6.0.1 + resolution: "tesseract.js@npm:6.0.1" dependencies: bmp-js: "npm:^0.1.0" idb-keyval: "npm:^6.2.0" @@ -17277,7 +17277,7 @@ __metadata: tesseract.js-core: "npm:^6.0.0" wasm-feature-detect: "npm:^1.2.11" zlibjs: "npm:^0.3.1" - checksum: 10c0/f65b816eabc16266bfa74ea61db73afa2d21ce0f57041b87b96abdff8954e042ee16637edea20aaf752227bc075052ca12021f4f68d5d25d52f062ebc4c644e1 + checksum: 10c0/1d73bb1fbc00c8629756d9594989d8bbfabda657a8cad84922ad68eb0f073148c82845bf71a882e5d2427a46edb5a470356864e60562c7a8442bddd70251435a languageName: node linkType: hard From bdf9baa2e82a3e363b73990e24697c3a321feeae Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Apr 2025 18:06:23 +0200 Subject: [PATCH 25/48] Refactor `` into TypeScript (#34355) --- app/javascript/mastodon/actions/tags.js | 81 --------- app/javascript/mastodon/api/tags.ts | 14 +- .../mastodon/components/hashtag.tsx | 4 + .../mastodon/features/followed_tags/index.jsx | 95 ----------- .../mastodon/features/followed_tags/index.tsx | 161 ++++++++++++++++++ .../mastodon/reducers/followed_tags.js | 43 ----- app/javascript/mastodon/reducers/index.ts | 2 - .../styles/mastodon/components.scss | 10 +- 8 files changed, 181 insertions(+), 229 deletions(-) delete mode 100644 app/javascript/mastodon/actions/tags.js delete mode 100644 app/javascript/mastodon/features/followed_tags/index.jsx create mode 100644 app/javascript/mastodon/features/followed_tags/index.tsx delete mode 100644 app/javascript/mastodon/reducers/followed_tags.js diff --git a/app/javascript/mastodon/actions/tags.js b/app/javascript/mastodon/actions/tags.js deleted file mode 100644 index 6e0c95288a..0000000000 --- a/app/javascript/mastodon/actions/tags.js +++ /dev/null @@ -1,81 +0,0 @@ -import api, { getLinks } from '../api'; - -export const FOLLOWED_HASHTAGS_FETCH_REQUEST = 'FOLLOWED_HASHTAGS_FETCH_REQUEST'; -export const FOLLOWED_HASHTAGS_FETCH_SUCCESS = 'FOLLOWED_HASHTAGS_FETCH_SUCCESS'; -export const FOLLOWED_HASHTAGS_FETCH_FAIL = 'FOLLOWED_HASHTAGS_FETCH_FAIL'; - -export const FOLLOWED_HASHTAGS_EXPAND_REQUEST = 'FOLLOWED_HASHTAGS_EXPAND_REQUEST'; -export const FOLLOWED_HASHTAGS_EXPAND_SUCCESS = 'FOLLOWED_HASHTAGS_EXPAND_SUCCESS'; -export const FOLLOWED_HASHTAGS_EXPAND_FAIL = 'FOLLOWED_HASHTAGS_EXPAND_FAIL'; - -export const fetchFollowedHashtags = () => (dispatch) => { - dispatch(fetchFollowedHashtagsRequest()); - - api().get('/api/v1/followed_tags').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(fetchFollowedHashtagsSuccess(response.data, next ? next.uri : null)); - }).catch(err => { - dispatch(fetchFollowedHashtagsFail(err)); - }); -}; - -export function fetchFollowedHashtagsRequest() { - return { - type: FOLLOWED_HASHTAGS_FETCH_REQUEST, - }; -} - -export function fetchFollowedHashtagsSuccess(followed_tags, next) { - return { - type: FOLLOWED_HASHTAGS_FETCH_SUCCESS, - followed_tags, - next, - }; -} - -export function fetchFollowedHashtagsFail(error) { - return { - type: FOLLOWED_HASHTAGS_FETCH_FAIL, - error, - }; -} - -export function expandFollowedHashtags() { - return (dispatch, getState) => { - const url = getState().getIn(['followed_tags', 'next']); - - if (url === null) { - return; - } - - dispatch(expandFollowedHashtagsRequest()); - - api().get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(expandFollowedHashtagsSuccess(response.data, next ? next.uri : null)); - }).catch(error => { - dispatch(expandFollowedHashtagsFail(error)); - }); - }; -} - -export function expandFollowedHashtagsRequest() { - return { - type: FOLLOWED_HASHTAGS_EXPAND_REQUEST, - }; -} - -export function expandFollowedHashtagsSuccess(followed_tags, next) { - return { - type: FOLLOWED_HASHTAGS_EXPAND_SUCCESS, - followed_tags, - next, - }; -} - -export function expandFollowedHashtagsFail(error) { - return { - type: FOLLOWED_HASHTAGS_EXPAND_FAIL, - error, - }; -} diff --git a/app/javascript/mastodon/api/tags.ts b/app/javascript/mastodon/api/tags.ts index 2cb802800c..4b111def81 100644 --- a/app/javascript/mastodon/api/tags.ts +++ b/app/javascript/mastodon/api/tags.ts @@ -1,4 +1,4 @@ -import { apiRequestPost, apiRequestGet } from 'mastodon/api'; +import api, { getLinks, apiRequestPost, apiRequestGet } from 'mastodon/api'; import type { ApiHashtagJSON } from 'mastodon/api_types/tags'; export const apiGetTag = (tagId: string) => @@ -9,3 +9,15 @@ export const apiFollowTag = (tagId: string) => export const apiUnfollowTag = (tagId: string) => apiRequestPost(`v1/tags/${tagId}/unfollow`); + +export const apiGetFollowedTags = async (url?: string) => { + const response = await api().request({ + method: 'GET', + url: url ?? '/api/v1/followed_tags', + }); + + return { + tags: response.data, + links: getLinks(response), + }; +}; diff --git a/app/javascript/mastodon/components/hashtag.tsx b/app/javascript/mastodon/components/hashtag.tsx index 30c20e0abd..1fe41e1e8b 100644 --- a/app/javascript/mastodon/components/hashtag.tsx +++ b/app/javascript/mastodon/components/hashtag.tsx @@ -106,6 +106,7 @@ export interface HashtagProps { to: string; uses?: number; withGraph?: boolean; + children?: React.ReactNode; } export const Hashtag: React.FC = ({ @@ -117,6 +118,7 @@ export const Hashtag: React.FC = ({ className, description, withGraph = true, + children, }) => (
@@ -158,5 +160,7 @@ export const Hashtag: React.FC = ({
)} + + {children &&
{children}
}
); diff --git a/app/javascript/mastodon/features/followed_tags/index.jsx b/app/javascript/mastodon/features/followed_tags/index.jsx deleted file mode 100644 index 21248e6de9..0000000000 --- a/app/javascript/mastodon/features/followed_tags/index.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import PropTypes from 'prop-types'; - -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -import { Helmet } from 'react-helmet'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { debounce } from 'lodash'; - -import TagIcon from '@/material-icons/400-24px/tag.svg?react'; -import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags'; -import ColumnHeader from 'mastodon/components/column_header'; -import { Hashtag } from 'mastodon/components/hashtag'; -import ScrollableList from 'mastodon/components/scrollable_list'; -import Column from 'mastodon/features/ui/components/column'; - -const messages = defineMessages({ - heading: { id: 'followed_tags', defaultMessage: 'Followed hashtags' }, -}); - -const mapStateToProps = state => ({ - hashtags: state.getIn(['followed_tags', 'items']), - isLoading: state.getIn(['followed_tags', 'isLoading'], true), - hasMore: !!state.getIn(['followed_tags', 'next']), -}); - -class FollowedTags extends ImmutablePureComponent { - - static propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - hashtags: ImmutablePropTypes.list, - isLoading: PropTypes.bool, - hasMore: PropTypes.bool, - multiColumn: PropTypes.bool, - }; - - componentDidMount() { - this.props.dispatch(fetchFollowedHashtags()); - } - - handleLoadMore = debounce(() => { - this.props.dispatch(expandFollowedHashtags()); - }, 300, { leading: true }); - - render () { - const { intl, hashtags, isLoading, hasMore, multiColumn } = this.props; - - const emptyMessage = ; - - return ( - - - - - {hashtags.map((hashtag) => ( - day.get('uses')).toArray()} - /> - ))} - - - - - - - ); - } - -} - -export default connect(mapStateToProps)(injectIntl(FollowedTags)); diff --git a/app/javascript/mastodon/features/followed_tags/index.tsx b/app/javascript/mastodon/features/followed_tags/index.tsx new file mode 100644 index 0000000000..21d63a6fec --- /dev/null +++ b/app/javascript/mastodon/features/followed_tags/index.tsx @@ -0,0 +1,161 @@ +import { useEffect, useState, useCallback, useRef } from 'react'; + +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import { isFulfilled } from '@reduxjs/toolkit'; + +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; +import { unfollowHashtag } from 'mastodon/actions/tags_typed'; +import { apiGetFollowedTags } from 'mastodon/api/tags'; +import type { ApiHashtagJSON } from 'mastodon/api_types/tags'; +import { Button } from 'mastodon/components/button'; +import { Column } from 'mastodon/components/column'; +import type { ColumnRef } from 'mastodon/components/column'; +import { ColumnHeader } from 'mastodon/components/column_header'; +import { Hashtag } from 'mastodon/components/hashtag'; +import ScrollableList from 'mastodon/components/scrollable_list'; +import { useAppDispatch } from 'mastodon/store'; + +const messages = defineMessages({ + heading: { id: 'followed_tags', defaultMessage: 'Followed hashtags' }, +}); + +const FollowedTag: React.FC<{ + tag: ApiHashtagJSON; + onUnfollow: (arg0: string) => void; +}> = ({ tag, onUnfollow }) => { + const dispatch = useAppDispatch(); + const tagId = tag.name; + + const handleClick = useCallback(() => { + void dispatch(unfollowHashtag({ tagId })).then((result) => { + if (isFulfilled(result)) { + onUnfollow(tagId); + } + + return ''; + }); + }, [dispatch, onUnfollow, tagId]); + + const people = + parseInt(tag.history[0].accounts) + + parseInt(tag.history[1]?.accounts ?? ''); + + return ( + + + + ); +}; + +const FollowedTags: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => { + const intl = useIntl(); + const [tags, setTags] = useState([]); + const [loading, setLoading] = useState(false); + const [next, setNext] = useState(); + const hasMore = !!next; + const columnRef = useRef(null); + + useEffect(() => { + setLoading(true); + + void apiGetFollowedTags() + .then(({ tags, links }) => { + const next = links.refs.find((link) => link.rel === 'next'); + + setTags(tags); + setLoading(false); + setNext(next?.uri); + + return ''; + }) + .catch(() => { + setLoading(false); + }); + }, [setTags, setLoading, setNext]); + + const handleLoadMore = useCallback(() => { + setLoading(true); + + void apiGetFollowedTags(next) + .then(({ tags, links }) => { + const next = links.refs.find((link) => link.rel === 'next'); + + setLoading(false); + setTags((previousTags) => [...previousTags, ...tags]); + setNext(next?.uri); + + return ''; + }) + .catch(() => { + setLoading(false); + }); + }, [setTags, setLoading, setNext, next]); + + const handleUnfollow = useCallback( + (tagId: string) => { + setTags((tags) => tags.filter((tag) => tag.name !== tagId)); + }, + [setTags], + ); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const emptyMessage = ( + + ); + + return ( + + + + + {tags.map((tag) => ( + + ))} + + + + {intl.formatMessage(messages.heading)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default FollowedTags; diff --git a/app/javascript/mastodon/reducers/followed_tags.js b/app/javascript/mastodon/reducers/followed_tags.js deleted file mode 100644 index afea8e3b35..0000000000 --- a/app/javascript/mastodon/reducers/followed_tags.js +++ /dev/null @@ -1,43 +0,0 @@ -import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; - -import { - FOLLOWED_HASHTAGS_FETCH_REQUEST, - FOLLOWED_HASHTAGS_FETCH_SUCCESS, - FOLLOWED_HASHTAGS_FETCH_FAIL, - FOLLOWED_HASHTAGS_EXPAND_REQUEST, - FOLLOWED_HASHTAGS_EXPAND_SUCCESS, - FOLLOWED_HASHTAGS_EXPAND_FAIL, -} from 'mastodon/actions/tags'; - -const initialState = ImmutableMap({ - items: ImmutableList(), - isLoading: false, - next: null, -}); - -export default function followed_tags(state = initialState, action) { - switch(action.type) { - case FOLLOWED_HASHTAGS_FETCH_REQUEST: - return state.set('isLoading', true); - case FOLLOWED_HASHTAGS_FETCH_SUCCESS: - return state.withMutations(map => { - map.set('items', fromJS(action.followed_tags)); - map.set('isLoading', false); - map.set('next', action.next); - }); - case FOLLOWED_HASHTAGS_FETCH_FAIL: - return state.set('isLoading', false); - case FOLLOWED_HASHTAGS_EXPAND_REQUEST: - return state.set('isLoading', true); - case FOLLOWED_HASHTAGS_EXPAND_SUCCESS: - return state.withMutations(map => { - map.update('items', set => set.concat(fromJS(action.followed_tags))); - map.set('isLoading', false); - map.set('next', action.next); - }); - case FOLLOWED_HASHTAGS_EXPAND_FAIL: - return state.set('isLoading', false); - default: - return state; - } -} diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts index cd5f55a868..e98d835f47 100644 --- a/app/javascript/mastodon/reducers/index.ts +++ b/app/javascript/mastodon/reducers/index.ts @@ -13,7 +13,6 @@ import conversations from './conversations'; import custom_emojis from './custom_emojis'; import { dropdownMenuReducer } from './dropdown_menu'; import filters from './filters'; -import followed_tags from './followed_tags'; import height_cache from './height_cache'; import history from './history'; import { listsReducer } from './lists'; @@ -73,7 +72,6 @@ const reducers = { markers: markersReducer, picture_in_picture: pictureInPictureReducer, history, - followed_tags, notificationPolicy: notificationPolicyReducer, notificationRequests: notificationRequestsReducer, }; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a399553f29..5d011d8f32 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -8110,13 +8110,9 @@ noscript { &__item { display: flex; align-items: center; - padding: 15px; + padding: 16px; border-bottom: 1px solid var(--background-border-color); - gap: 15px; - - &:last-child { - border-bottom: 0; - } + gap: 8px; &__name { flex: 1 1 auto; @@ -8223,7 +8219,7 @@ noscript { } &--compact &__item { - padding: 10px; + padding: 12px; } } From 6a39f00745ab2da7917f9584f94ef1eb456001c4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Apr 2025 18:06:31 +0200 Subject: [PATCH 26/48] Refactor `` and `` into TypeScript (#34356) --- .../features/bookmarked_statuses/index.jsx | 115 ----------------- .../features/bookmarked_statuses/index.tsx | 116 ++++++++++++++++++ .../features/favourited_statuses/index.jsx | 115 ----------------- .../features/favourited_statuses/index.tsx | 116 ++++++++++++++++++ .../mastodon/reducers/status_lists.js | 1 + app/javascript/mastodon/selectors/index.js | 5 +- app/javascript/mastodon/selectors/statuses.ts | 15 +++ 7 files changed, 249 insertions(+), 234 deletions(-) delete mode 100644 app/javascript/mastodon/features/bookmarked_statuses/index.jsx create mode 100644 app/javascript/mastodon/features/bookmarked_statuses/index.tsx delete mode 100644 app/javascript/mastodon/features/favourited_statuses/index.jsx create mode 100644 app/javascript/mastodon/features/favourited_statuses/index.tsx create mode 100644 app/javascript/mastodon/selectors/statuses.ts diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx deleted file mode 100644 index 122baafd6c..0000000000 --- a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import PropTypes from 'prop-types'; - -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -import { Helmet } from 'react-helmet'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { debounce } from 'lodash'; - -import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; -import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks'; -import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; -import ColumnHeader from 'mastodon/components/column_header'; -import StatusList from 'mastodon/components/status_list'; -import Column from 'mastodon/features/ui/components/column'; -import { getStatusList } from 'mastodon/selectors'; - -const messages = defineMessages({ - heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, -}); - -const mapStateToProps = state => ({ - statusIds: getStatusList(state, 'bookmarks'), - isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true), - hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']), -}); - -class Bookmarks extends ImmutablePureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - intl: PropTypes.object.isRequired, - columnId: PropTypes.string, - multiColumn: PropTypes.bool, - hasMore: PropTypes.bool, - isLoading: PropTypes.bool, - }; - - UNSAFE_componentWillMount () { - this.props.dispatch(fetchBookmarkedStatuses()); - } - - handlePin = () => { - const { columnId, dispatch } = this.props; - - if (columnId) { - dispatch(removeColumn(columnId)); - } else { - dispatch(addColumn('BOOKMARKS', {})); - } - }; - - handleMove = (dir) => { - const { columnId, dispatch } = this.props; - dispatch(moveColumn(columnId, dir)); - }; - - handleHeaderClick = () => { - this.column.scrollTop(); - }; - - setRef = c => { - this.column = c; - }; - - handleLoadMore = debounce(() => { - this.props.dispatch(expandBookmarkedStatuses()); - }, 300, { leading: true }); - - render () { - const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; - const pinned = !!columnId; - - const emptyMessage = ; - - return ( - - - - - - - {intl.formatMessage(messages.heading)} - - - - ); - } - -} - -export default connect(mapStateToProps)(injectIntl(Bookmarks)); diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.tsx b/app/javascript/mastodon/features/bookmarked_statuses/index.tsx new file mode 100644 index 0000000000..5d4574b05b --- /dev/null +++ b/app/javascript/mastodon/features/bookmarked_statuses/index.tsx @@ -0,0 +1,116 @@ +import { useEffect, useRef, useCallback } from 'react'; + +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; +import { + fetchBookmarkedStatuses, + expandBookmarkedStatuses, +} from 'mastodon/actions/bookmarks'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { Column } from 'mastodon/components/column'; +import type { ColumnRef } from 'mastodon/components/column'; +import { ColumnHeader } from 'mastodon/components/column_header'; +import StatusList from 'mastodon/components/status_list'; +import { getStatusList } from 'mastodon/selectors'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +const messages = defineMessages({ + heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, +}); + +const Bookmarks: React.FC<{ + columnId: string; + multiColumn: boolean; +}> = ({ columnId, multiColumn }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const columnRef = useRef(null); + const statusIds = useAppSelector((state) => + getStatusList(state, 'bookmarks'), + ); + const isLoading = useAppSelector( + (state) => + state.status_lists.getIn(['bookmarks', 'isLoading'], true) as boolean, + ); + const hasMore = useAppSelector( + (state) => !!state.status_lists.getIn(['bookmarks', 'next']), + ); + + useEffect(() => { + dispatch(fetchBookmarkedStatuses()); + }, [dispatch]); + + const handlePin = useCallback(() => { + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('BOOKMARKS', {})); + } + }, [dispatch, columnId]); + + const handleMove = useCallback( + (dir: number) => { + dispatch(moveColumn(columnId, dir)); + }, + [dispatch, columnId], + ); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const handleLoadMore = useCallback(() => { + dispatch(expandBookmarkedStatuses()); + }, [dispatch]); + + const pinned = !!columnId; + + const emptyMessage = ( + + ); + + return ( + + + + + + + {intl.formatMessage(messages.heading)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default Bookmarks; diff --git a/app/javascript/mastodon/features/favourited_statuses/index.jsx b/app/javascript/mastodon/features/favourited_statuses/index.jsx deleted file mode 100644 index 9e0b982239..0000000000 --- a/app/javascript/mastodon/features/favourited_statuses/index.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import PropTypes from 'prop-types'; - -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -import { Helmet } from 'react-helmet'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { debounce } from 'lodash'; - -import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; -import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; -import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'mastodon/actions/favourites'; -import ColumnHeader from 'mastodon/components/column_header'; -import StatusList from 'mastodon/components/status_list'; -import Column from 'mastodon/features/ui/components/column'; -import { getStatusList } from 'mastodon/selectors'; - -const messages = defineMessages({ - heading: { id: 'column.favourites', defaultMessage: 'Favorites' }, -}); - -const mapStateToProps = state => ({ - statusIds: getStatusList(state, 'favourites'), - isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true), - hasMore: !!state.getIn(['status_lists', 'favourites', 'next']), -}); - -class Favourites extends ImmutablePureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - intl: PropTypes.object.isRequired, - columnId: PropTypes.string, - multiColumn: PropTypes.bool, - hasMore: PropTypes.bool, - isLoading: PropTypes.bool, - }; - - UNSAFE_componentWillMount () { - this.props.dispatch(fetchFavouritedStatuses()); - } - - handlePin = () => { - const { columnId, dispatch } = this.props; - - if (columnId) { - dispatch(removeColumn(columnId)); - } else { - dispatch(addColumn('FAVOURITES', {})); - } - }; - - handleMove = (dir) => { - const { columnId, dispatch } = this.props; - dispatch(moveColumn(columnId, dir)); - }; - - handleHeaderClick = () => { - this.column.scrollTop(); - }; - - setRef = c => { - this.column = c; - }; - - handleLoadMore = debounce(() => { - this.props.dispatch(expandFavouritedStatuses()); - }, 300, { leading: true }); - - render () { - const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; - const pinned = !!columnId; - - const emptyMessage = ; - - return ( - - - - - - - {intl.formatMessage(messages.heading)} - - - - ); - } - -} - -export default connect(mapStateToProps)(injectIntl(Favourites)); diff --git a/app/javascript/mastodon/features/favourited_statuses/index.tsx b/app/javascript/mastodon/features/favourited_statuses/index.tsx new file mode 100644 index 0000000000..908a8ae4a1 --- /dev/null +++ b/app/javascript/mastodon/features/favourited_statuses/index.tsx @@ -0,0 +1,116 @@ +import { useEffect, useRef, useCallback } from 'react'; + +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { + fetchFavouritedStatuses, + expandFavouritedStatuses, +} from 'mastodon/actions/favourites'; +import { Column } from 'mastodon/components/column'; +import type { ColumnRef } from 'mastodon/components/column'; +import { ColumnHeader } from 'mastodon/components/column_header'; +import StatusList from 'mastodon/components/status_list'; +import { getStatusList } from 'mastodon/selectors'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +const messages = defineMessages({ + heading: { id: 'column.favourites', defaultMessage: 'Favorites' }, +}); + +const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({ + columnId, + multiColumn, +}) => { + const dispatch = useAppDispatch(); + const intl = useIntl(); + const columnRef = useRef(null); + const statusIds = useAppSelector((state) => + getStatusList(state, 'favourites'), + ); + const isLoading = useAppSelector( + (state) => + state.status_lists.getIn(['favourites', 'isLoading'], true) as boolean, + ); + const hasMore = useAppSelector( + (state) => !!state.status_lists.getIn(['favourites', 'next']), + ); + + useEffect(() => { + dispatch(fetchFavouritedStatuses()); + }, [dispatch]); + + const handlePin = useCallback(() => { + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('FAVOURITES', {})); + } + }, [dispatch, columnId]); + + const handleMove = useCallback( + (dir: number) => { + dispatch(moveColumn(columnId, dir)); + }, + [dispatch, columnId], + ); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const handleLoadMore = useCallback(() => { + dispatch(expandFavouritedStatuses()); + }, [dispatch]); + + const pinned = !!columnId; + + const emptyMessage = ( + + ); + + return ( + + + + + + + {intl.formatMessage(messages.heading)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default Favourites; diff --git a/app/javascript/mastodon/reducers/status_lists.js b/app/javascript/mastodon/reducers/status_lists.js index 6cb6a937bb..c9d39130ee 100644 --- a/app/javascript/mastodon/reducers/status_lists.js +++ b/app/javascript/mastodon/reducers/status_lists.js @@ -96,6 +96,7 @@ const removeOneFromList = (state, listType, status) => { return state.updateIn([listType, 'items'], (list) => list.delete(status.get('id'))); }; +/** @type {import('@reduxjs/toolkit').Reducer} */ export default function statusLists(state = initialState, action) { switch(action.type) { case FAVOURITED_STATUSES_FETCH_REQUEST: diff --git a/app/javascript/mastodon/selectors/index.js b/app/javascript/mastodon/selectors/index.js index 5ccaba23fd..3119b285b2 100644 --- a/app/javascript/mastodon/selectors/index.js +++ b/app/javascript/mastodon/selectors/index.js @@ -6,6 +6,7 @@ import { me } from '../initial_state'; import { getFilters } from './filters'; export { makeGetAccount } from "./accounts"; +export { getStatusList } from "./statuses"; export const makeGetStatus = () => { return createSelector( @@ -77,7 +78,3 @@ export const makeGetReport = () => createSelector([ (_, base) => base, (state, _, targetAccountId) => state.getIn(['accounts', targetAccountId]), ], (base, targetAccount) => base.set('target_account', targetAccount)); - -export const getStatusList = createSelector([ - (state, type) => state.getIn(['status_lists', type, 'items']), -], (items) => items.toList()); diff --git a/app/javascript/mastodon/selectors/statuses.ts b/app/javascript/mastodon/selectors/statuses.ts new file mode 100644 index 0000000000..4d045e924a --- /dev/null +++ b/app/javascript/mastodon/selectors/statuses.ts @@ -0,0 +1,15 @@ +import { createSelector } from '@reduxjs/toolkit'; +import type { OrderedSet as ImmutableOrderedSet } from 'immutable'; + +import type { RootState } from 'mastodon/store'; + +export const getStatusList = createSelector( + [ + ( + state: RootState, + type: 'favourites' | 'bookmarks' | 'pins' | 'trending', + ) => + state.status_lists.getIn([type, 'items']) as ImmutableOrderedSet, + ], + (items) => items.toList(), +); From 0e5be63fb327403902076df602ec2dd410ada789 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Apr 2025 18:28:14 +0200 Subject: [PATCH 27/48] Change unfollow button label from "Mutual" to "Unfollow" in web UI (#34392) --- .../mastodon/components/follow_button.tsx | 7 +- .../components/account_header.tsx | 99 +++---------------- 2 files changed, 15 insertions(+), 91 deletions(-) diff --git a/app/javascript/mastodon/components/follow_button.tsx b/app/javascript/mastodon/components/follow_button.tsx index f49abfd2b3..4a22bb1c3f 100644 --- a/app/javascript/mastodon/components/follow_button.tsx +++ b/app/javascript/mastodon/components/follow_button.tsx @@ -16,8 +16,7 @@ const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, followBack: { id: 'account.follow_back', defaultMessage: 'Follow back' }, - mutual: { id: 'account.mutual', defaultMessage: 'Mutual' }, - edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, + editProfile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, }); export const FollowButton: React.FC<{ @@ -73,11 +72,9 @@ export const FollowButton: React.FC<{ if (!signedIn) { label = intl.formatMessage(messages.follow); } else if (accountId === me) { - label = intl.formatMessage(messages.edit_profile); + label = intl.formatMessage(messages.editProfile); } else if (!relationship) { label = ; - } else if (relationship.following && relationship.followed_by) { - label = intl.formatMessage(messages.mutual); } else if (relationship.following || relationship.requested) { label = intl.formatMessage(messages.unfollow); } else if (relationship.followed_by) { diff --git a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx index 9505d48010..ae1724a728 100644 --- a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx @@ -37,10 +37,10 @@ import { FollowingCounter, StatusesCounter, } from 'mastodon/components/counters'; +import { FollowButton } from 'mastodon/components/follow_button'; import { FormattedDateWrapper } from 'mastodon/components/formatted_date'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; -import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { ShortNumber } from 'mastodon/components/short_number'; import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; import { DomainPill } from 'mastodon/features/account/components/domain_pill'; @@ -51,7 +51,6 @@ import { useIdentity } from 'mastodon/identity_context'; import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state'; import type { Account } from 'mastodon/models/account'; import type { DropdownMenu } from 'mastodon/models/dropdown_menu'; -import type { Relationship } from 'mastodon/models/relationship'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION, @@ -179,20 +178,6 @@ const titleFromAccount = (account: Account) => { return `${prefix} (@${acct})`; }; -const messageForFollowButton = (relationship?: Relationship) => { - if (!relationship) return messages.follow; - - if (relationship.get('following') && relationship.get('followed_by')) { - return messages.mutual; - } else if (relationship.get('following') || relationship.get('requested')) { - return messages.unfollow; - } else if (relationship.get('followed_by')) { - return messages.followBack; - } else { - return messages.follow; - } -}; - const dateFormatOptions: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', @@ -215,20 +200,6 @@ export const AccountHeader: React.FC<{ const hidden = useAppSelector((state) => getAccountHidden(state, accountId)); const handleLinkClick = useLinks(); - const handleFollow = useCallback(() => { - if (!account) { - return; - } - - if (relationship?.following || relationship?.requested) { - dispatch( - openModal({ modalType: 'CONFIRM_UNFOLLOW', modalProps: { account } }), - ); - } else { - dispatch(followAccount(account.id)); - } - }, [dispatch, account, relationship]); - const handleBlock = useCallback(() => { if (!account) { return; @@ -365,23 +336,6 @@ export const AccountHeader: React.FC<{ ); }, [dispatch, account]); - const handleInteractionModal = useCallback(() => { - if (!account) { - return; - } - - dispatch( - openModal({ - modalType: 'INTERACTION', - modalProps: { - type: 'follow', - accountId: account.id, - url: account.uri, - }, - }), - ); - }, [dispatch, account]); - const handleOpenAvatar = useCallback( (e: React.MouseEvent) => { if (e.button !== 0 || e.ctrlKey || e.metaKey) { @@ -417,10 +371,6 @@ export const AccountHeader: React.FC<{ }); }, [account]); - const handleEditProfile = useCallback(() => { - window.open('/settings/profile', '_blank'); - }, []); - const handleMouseEnter = useCallback( ({ currentTarget }: React.MouseEvent) => { if (autoPlayGif) { @@ -680,9 +630,12 @@ export const AccountHeader: React.FC<{ return null; } - let actionBtn, bellBtn, lockedIcon, shareBtn; + let actionBtn: React.ReactNode, + bellBtn: React.ReactNode, + lockedIcon: React.ReactNode, + shareBtn: React.ReactNode; - const info = []; + const info: React.ReactNode[] = []; if (me !== account.id && relationship?.blocking) { info.push( @@ -750,43 +703,17 @@ export const AccountHeader: React.FC<{ ); } - if (me !== account.id) { - if (signedIn && !relationship) { - // Wait until the relationship is loaded - actionBtn = ( - - ); - } else if (!relationship?.blocking) { - actionBtn = ( - + ); + } else if (isExternalLinkItem(option)) { + element = ( + + {text} + + ); + } else { + element = ( + + {text} + + ); + } + + return ( +
  • + {element} +
  • + ); + }; + + const renderItemMethod = renderItem ?? nativeRenderItem; + + return ( +
    + {(loading || !items) && } + + {!loading && renderHeader && items && ( +
    + {renderHeader(items)} +
    + )} + + {!loading && items && ( +
      + {items.map((option, i) => + renderItemMethod(option, i, { + onClick: handleClick, + onKeyUp: handleItemKeyUp, + }), + )} +
    + )} +
    + ); +}; + +interface DropdownProps { + children?: React.ReactElement; + icon?: string; + iconComponent?: IconProp; + items?: Item[]; + loading?: boolean; + title?: string; + disabled?: boolean; + scrollable?: boolean; + scrollKey?: string; + status?: ImmutableMap; + renderItem?: RenderItemFn; + renderHeader?: RenderHeaderFn; + onOpen?: () => void; + onItemClick?: (arg0: Item, arg1: number) => void; +} + +const offset = [5, 5] as OffsetValue; +const popperConfig = { strategy: 'fixed' } as UsePopperOptions; + +export const Dropdown = ({ + children, + icon, + iconComponent, + items, + loading, + title = 'Menu', + disabled, + scrollable, + status, + renderItem, + renderHeader, + onOpen, + onItemClick, + scrollKey, +}: DropdownProps) => { + const dispatch = useAppDispatch(); + const openDropdownId = useAppSelector((state) => state.dropdownMenu.openId); + const openedViaKeyboard = useAppSelector( + (state) => state.dropdownMenu.keyboard, + ); + const [currentId] = useState(id++); + const open = currentId === openDropdownId; + const activeElement = useRef(null); + const targetRef = useRef(null); + + const handleClose = useCallback(() => { + if (activeElement.current) { + activeElement.current.focus({ preventScroll: true }); + activeElement.current = null; + } + + dispatch( + closeModal({ + modalType: 'ACTIONS', + ignoreFocus: false, + }), + ); + + dispatch(closeDropdownMenu({ id: currentId })); + }, [dispatch, currentId]); + + const handleClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const { type } = e; + + if (open) { + handleClose(); + } else { + onOpen?.(); + + if (status) { + dispatch(fetchRelationships([status.getIn(['account', 'id'])])); + } + + if (isUserTouching()) { + dispatch( + openModal({ + modalType: 'ACTIONS', + modalProps: { + status, + actions: items, + onClick: onItemClick, + }, + }), + ); + } else { + dispatch( + openDropdownMenu({ + id: currentId, + keyboard: type !== 'click', + scrollKey, + }), + ); + } + } + }, + [ + dispatch, + currentId, + scrollKey, + onOpen, + onItemClick, + open, + status, + items, + handleClose, + ], + ); + + const handleMouseDown = useCallback(() => { + if (!open && document.activeElement instanceof HTMLElement) { + activeElement.current = document.activeElement; + } + }, [open]); + + const handleButtonKeyDown = useCallback( + (e: React.KeyboardEvent) => { + switch (e.key) { + case ' ': + case 'Enter': + handleMouseDown(); + break; + } + }, + [handleMouseDown], + ); + + const handleKeyPress = useCallback( + (e: React.KeyboardEvent) => { + switch (e.key) { + case ' ': + case 'Enter': + handleClick(e); + e.stopPropagation(); + e.preventDefault(); + break; + } + }, + [handleClick], + ); + + const handleItemClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const i = Number(e.currentTarget.getAttribute('data-index')); + const item = items?.[i]; + + handleClose(); + + if (!item) { + return; + } + + if (typeof onItemClick === 'function') { + e.preventDefault(); + onItemClick(item, i); + } else if (isActionItem(item)) { + e.preventDefault(); + item.action(); + } + }, + [handleClose, onItemClick, items], + ); + + useEffect(() => { + return () => { + if (currentId === openDropdownId) { + handleClose(); + } + }; + }, [currentId, openDropdownId, handleClose]); + + let button: React.ReactElement; + + if (children) { + button = cloneElement(Children.only(children), { + onClick: handleClick, + onMouseDown: handleMouseDown, + onKeyDown: handleButtonKeyDown, + onKeyPress: handleKeyPress, + ref: targetRef, + }); + } else if (icon && iconComponent) { + button = ( + + ); + } else { + return null; + } + + return ( + <> + {button} + + + {({ props, arrowProps, placement }) => ( +
    +
    +
    + + +
    +
    + )} + + + ); +}; diff --git a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js b/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js deleted file mode 100644 index 726fee9076..0000000000 --- a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js +++ /dev/null @@ -1,32 +0,0 @@ -import { connect } from 'react-redux'; - -import { openDropdownMenu, closeDropdownMenu } from 'mastodon/actions/dropdown_menu'; -import { fetchHistory } from 'mastodon/actions/history'; -import DropdownMenu from 'mastodon/components/dropdown_menu'; - -/** - * - * @param {import('mastodon/store').RootState} state - * @param {*} props - */ -const mapStateToProps = (state, { statusId }) => ({ - openDropdownId: state.dropdownMenu.openId, - openedViaKeyboard: state.dropdownMenu.keyboard, - items: state.getIn(['history', statusId, 'items']), - loading: state.getIn(['history', statusId, 'loading']), -}); - -const mapDispatchToProps = (dispatch, { statusId }) => ({ - - onOpen (id, onItemClick, keyboard) { - dispatch(fetchHistory(statusId)); - dispatch(openDropdownMenu({ id, keyboard })); - }, - - onClose (id) { - dispatch(closeDropdownMenu({ id })); - }, - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(DropdownMenu); diff --git a/app/javascript/mastodon/components/edited_timestamp/index.jsx b/app/javascript/mastodon/components/edited_timestamp/index.jsx deleted file mode 100644 index f8fa043259..0000000000 --- a/app/javascript/mastodon/components/edited_timestamp/index.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { FormattedMessage, injectIntl } from 'react-intl'; - -import { connect } from 'react-redux'; - -import { openModal } from 'mastodon/actions/modal'; -import { FormattedDateWrapper } from 'mastodon/components/formatted_date'; -import InlineAccount from 'mastodon/components/inline_account'; -import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; - -import DropdownMenu from './containers/dropdown_menu_container'; - -const mapDispatchToProps = (dispatch, { statusId }) => ({ - - onItemClick (index) { - dispatch(openModal({ - modalType: 'COMPARE_HISTORY', - modalProps: { index, statusId }, - })); - }, - -}); - -class EditedTimestamp extends PureComponent { - - static propTypes = { - statusId: PropTypes.string.isRequired, - timestamp: PropTypes.string.isRequired, - intl: PropTypes.object.isRequired, - onItemClick: PropTypes.func.isRequired, - }; - - handleItemClick = (item, i) => { - const { onItemClick } = this.props; - onItemClick(i); - }; - - renderHeader = items => { - return ( - - ); - }; - - renderItem = (item, index, { onClick, onKeyPress }) => { - const formattedDate = ; - const formattedName = ; - - const label = item.get('original') ? ( - - ) : ( - - ); - - return ( -
  • - -
  • - ); - }; - - render () { - const { timestamp, statusId } = this.props; - - return ( - - - - ); - } - -} - -export default connect(null, mapDispatchToProps)(injectIntl(EditedTimestamp)); diff --git a/app/javascript/mastodon/components/edited_timestamp/index.tsx b/app/javascript/mastodon/components/edited_timestamp/index.tsx new file mode 100644 index 0000000000..770cf33f8c --- /dev/null +++ b/app/javascript/mastodon/components/edited_timestamp/index.tsx @@ -0,0 +1,140 @@ +import { useCallback } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import type { Map as ImmutableMap, List as ImmutableList } from 'immutable'; + +import { fetchHistory } from 'mastodon/actions/history'; +import { openModal } from 'mastodon/actions/modal'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; +import { FormattedDateWrapper } from 'mastodon/components/formatted_date'; +import InlineAccount from 'mastodon/components/inline_account'; +import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +type HistoryItem = ImmutableMap; + +export const EditedTimestamp: React.FC<{ + statusId: string; + timestamp: string; +}> = ({ statusId, timestamp }) => { + const dispatch = useAppDispatch(); + const items = useAppSelector( + (state) => + ( + state.history.getIn([statusId, 'items']) as + | ImmutableList + | undefined + )?.toArray() as HistoryItem[], + ); + const loading = useAppSelector( + (state) => state.history.getIn([statusId, 'loading']) as boolean, + ); + + const handleOpen = useCallback(() => { + dispatch(fetchHistory(statusId)); + }, [dispatch, statusId]); + + const handleItemClick = useCallback( + (_item: HistoryItem, i: number) => { + dispatch( + openModal({ + modalType: 'COMPARE_HISTORY', + modalProps: { index: i, statusId }, + }), + ); + }, + [dispatch, statusId], + ); + + const renderHeader = useCallback((items: HistoryItem[]) => { + return ( + + ); + }, []); + + const renderItem = useCallback( + ( + item: HistoryItem, + index: number, + { + onClick, + onKeyUp, + }: { + onClick: React.MouseEventHandler; + onKeyUp: React.KeyboardEventHandler; + }, + ) => { + const formattedDate = ( + + ); + const formattedName = ( + + ); + + const label = (item.get('original') as boolean) ? ( + + ) : ( + + ); + + return ( +
  • + +
  • + ); + }, + [], + ); + + return ( + + items={items} + loading={loading} + renderItem={renderItem} + scrollable + renderHeader={renderHeader} + onOpen={handleOpen} + onItemClick={handleItemClick} + > + + + ); +}; diff --git a/app/javascript/mastodon/components/icon_button.tsx b/app/javascript/mastodon/components/icon_button.tsx index 179df83627..8ec665bbd8 100644 --- a/app/javascript/mastodon/components/icon_button.tsx +++ b/app/javascript/mastodon/components/icon_button.tsx @@ -1,4 +1,4 @@ -import { PureComponent, createRef } from 'react'; +import { useState, useEffect, useCallback, forwardRef } from 'react'; import classNames from 'classnames'; @@ -15,99 +15,108 @@ interface Props { onMouseDown?: React.MouseEventHandler; onKeyDown?: React.KeyboardEventHandler; onKeyPress?: React.KeyboardEventHandler; - active: boolean; + active?: boolean; expanded?: boolean; style?: React.CSSProperties; activeStyle?: React.CSSProperties; - disabled: boolean; + disabled?: boolean; inverted?: boolean; - animate: boolean; - overlay: boolean; - tabIndex: number; + animate?: boolean; + overlay?: boolean; + tabIndex?: number; counter?: number; href?: string; - ariaHidden: boolean; + ariaHidden?: boolean; } -interface States { - activate: boolean; - deactivate: boolean; -} -export class IconButton extends PureComponent { - buttonRef = createRef(); - static defaultProps = { - active: false, - disabled: false, - animate: false, - overlay: false, - tabIndex: 0, - ariaHidden: false, - }; - - state = { - activate: false, - deactivate: false, - }; - - UNSAFE_componentWillReceiveProps(nextProps: Props) { - if (!nextProps.animate) return; - - if (this.props.active && !nextProps.active) { - this.setState({ activate: false, deactivate: true }); - } else if (!this.props.active && nextProps.active) { - this.setState({ activate: true, deactivate: false }); - } - } - - handleClick: React.MouseEventHandler = (e) => { - e.preventDefault(); - - if (!this.props.disabled && this.props.onClick != null) { - this.props.onClick(e); - } - }; - - handleKeyPress: React.KeyboardEventHandler = (e) => { - if (this.props.onKeyPress && !this.props.disabled) { - this.props.onKeyPress(e); - } - }; - - handleMouseDown: React.MouseEventHandler = (e) => { - if (!this.props.disabled && this.props.onMouseDown) { - this.props.onMouseDown(e); - } - }; - - handleKeyDown: React.KeyboardEventHandler = (e) => { - if (!this.props.disabled && this.props.onKeyDown) { - this.props.onKeyDown(e); - } - }; - - render() { - const style = { - ...this.props.style, - ...(this.props.active ? this.props.activeStyle : {}), - }; - - const { - active, +export const IconButton = forwardRef( + ( + { className, - disabled, expanded, icon, iconComponent, inverted, - overlay, - tabIndex, title, counter, href, - ariaHidden, - } = this.props; + style, + activeStyle, + onClick, + onKeyDown, + onKeyPress, + onMouseDown, + active = false, + disabled = false, + animate = false, + overlay = false, + tabIndex = 0, + ariaHidden = false, + }, + buttonRef, + ) => { + const [activate, setActivate] = useState(false); + const [deactivate, setDeactivate] = useState(false); - const { activate, deactivate } = this.state; + useEffect(() => { + if (!animate) { + return; + } + + if (activate && !active) { + setActivate(false); + setDeactivate(true); + } else if (!activate && active) { + setActivate(true); + setDeactivate(false); + } + }, [setActivate, setDeactivate, animate, active, activate]); + + const handleClick: React.MouseEventHandler = useCallback( + (e) => { + e.preventDefault(); + + if (!disabled) { + onClick?.(e); + } + }, + [disabled, onClick], + ); + + const handleKeyPress: React.KeyboardEventHandler = + useCallback( + (e) => { + if (!disabled) { + onKeyPress?.(e); + } + }, + [disabled, onKeyPress], + ); + + const handleMouseDown: React.MouseEventHandler = + useCallback( + (e) => { + if (!disabled) { + onMouseDown?.(e); + } + }, + [disabled, onMouseDown], + ); + + const handleKeyDown: React.KeyboardEventHandler = + useCallback( + (e) => { + if (!disabled) { + onKeyDown?.(e); + } + }, + [disabled, onKeyDown], + ); + + const buttonStyle = { + ...style, + ...(active ? activeStyle : {}), + }; const classes = classNames(className, 'icon-button', { active, @@ -146,18 +155,19 @@ export class IconButton extends PureComponent { aria-hidden={ariaHidden} title={title} className={classes} - onClick={this.handleClick} - onMouseDown={this.handleMouseDown} - onKeyDown={this.handleKeyDown} - // eslint-disable-next-line @typescript-eslint/no-deprecated - onKeyPress={this.handleKeyPress} - style={style} + onClick={handleClick} + onMouseDown={handleMouseDown} + onKeyDown={handleKeyDown} + onKeyPress={handleKeyPress} // eslint-disable-line @typescript-eslint/no-deprecated + style={buttonStyle} tabIndex={tabIndex} disabled={disabled} - ref={this.buttonRef} + ref={buttonRef} > {contents} ); - } -} + }, +); + +IconButton.displayName = 'IconButton'; diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 9cd2d8d20c..344524f8be 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -25,7 +25,7 @@ import { identityContextPropShape, withIdentity } from 'mastodon/identity_contex import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; -import DropdownMenuContainer from '../containers/dropdown_menu_container'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { me } from '../initial_state'; import { IconButton } from './icon_button'; @@ -390,7 +390,7 @@ class StatusActionBar extends ImmutablePureComponent {
    - ({ - openDropdownId: state.dropdownMenu.openId, - openedViaKeyboard: state.dropdownMenu.keyboard, -}); - -/** - * @param {any} dispatch - * @param {Object} root0 - * @param {any} [root0.status] - * @param {any} root0.items - * @param {any} [root0.scrollKey] - */ -const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ - onOpen(id, onItemClick, keyboard) { - if (status) { - dispatch(fetchRelationships([status.getIn(['account', 'id'])])); - } - - dispatch(isUserTouching() ? openModal({ - modalType: 'ACTIONS', - modalProps: { - status, - actions: items, - onClick: onItemClick, - }, - }) : openDropdownMenu({ id, keyboard, scrollKey })); - }, - - onClose(id) { - dispatch(closeModal({ - modalType: 'ACTIONS', - ignoreFocus: false, - })); - dispatch(closeDropdownMenu({ id })); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(DropdownMenu); diff --git a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx index ae1724a728..ca12834528 100644 --- a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx @@ -37,12 +37,12 @@ import { FollowingCounter, StatusesCounter, } from 'mastodon/components/counters'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { FollowButton } from 'mastodon/components/follow_button'; import { FormattedDateWrapper } from 'mastodon/components/formatted_date'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; import { ShortNumber } from 'mastodon/components/short_number'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; import { DomainPill } from 'mastodon/features/account/components/domain_pill'; import AccountNoteContainer from 'mastodon/features/account/containers/account_note_container'; import FollowRequestNoteContainer from 'mastodon/features/account/containers/follow_request_note_container'; @@ -50,7 +50,7 @@ import { useLinks } from 'mastodon/hooks/useLinks'; import { useIdentity } from 'mastodon/identity_context'; import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state'; import type { Account } from 'mastodon/models/account'; -import type { DropdownMenu } from 'mastodon/models/dropdown_menu'; +import type { MenuItem } from 'mastodon/models/dropdown_menu'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION, @@ -406,7 +406,7 @@ export const AccountHeader: React.FC<{ const remoteDomain = isRemote ? account?.acct.split('@')[1] : null; const menu = useMemo(() => { - const arr: DropdownMenu = []; + const arr: MenuItem[] = []; if (!account) { return arr; @@ -806,13 +806,11 @@ export const AccountHeader: React.FC<{
    {!hidden && bellBtn} {!hidden && shareBtn} - {!hidden && actionBtn}
    diff --git a/app/javascript/mastodon/features/compose/components/action_bar.jsx b/app/javascript/mastodon/features/compose/components/action_bar.tsx similarity index 55% rename from app/javascript/mastodon/features/compose/components/action_bar.jsx rename to app/javascript/mastodon/features/compose/components/action_bar.tsx index f7339141ad..af24c565f6 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.jsx +++ b/app/javascript/mastodon/features/compose/components/action_bar.tsx @@ -2,64 +2,82 @@ import { useMemo } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useDispatch } from 'react-redux'; - import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import { openModal } from 'mastodon/actions/modal'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; +import { useAppDispatch } from 'mastodon/store'; const messages = defineMessages({ edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, - preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, - follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, + preferences: { + id: 'navigation_bar.preferences', + defaultMessage: 'Preferences', + }, + follow_requests: { + id: 'navigation_bar.follow_requests', + defaultMessage: 'Follow requests', + }, favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, - followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' }, + followed_tags: { + id: 'navigation_bar.followed_tags', + defaultMessage: 'Followed hashtags', + }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, - domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' }, + domain_blocks: { + id: 'navigation_bar.domain_blocks', + defaultMessage: 'Blocked domains', + }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' }, logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, }); -export const ActionBar = () => { - const dispatch = useDispatch(); +export const ActionBar: React.FC = () => { + const dispatch = useAppDispatch(); const intl = useIntl(); const menu = useMemo(() => { const handleLogoutClick = () => { - dispatch(openModal({ modalType: 'CONFIRM_LOG_OUT' })); + dispatch(openModal({ modalType: 'CONFIRM_LOG_OUT', modalProps: {} })); }; - return ([ - { text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' }, - { text: intl.formatMessage(messages.preferences), href: '/settings/preferences' }, + return [ + { + text: intl.formatMessage(messages.edit_profile), + href: '/settings/profile', + }, + { + text: intl.formatMessage(messages.preferences), + href: '/settings/preferences', + }, { text: intl.formatMessage(messages.pins), to: '/pinned' }, null, - { text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' }, + { + text: intl.formatMessage(messages.follow_requests), + to: '/follow_requests', + }, { text: intl.formatMessage(messages.favourites), to: '/favourites' }, { text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' }, { text: intl.formatMessage(messages.lists), to: '/lists' }, - { text: intl.formatMessage(messages.followed_tags), to: '/followed_tags' }, + { + text: intl.formatMessage(messages.followed_tags), + to: '/followed_tags', + }, null, { text: intl.formatMessage(messages.mutes), to: '/mutes' }, { text: intl.formatMessage(messages.blocks), to: '/blocks' }, - { text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' }, + { + text: intl.formatMessage(messages.domain_blocks), + to: '/domain_blocks', + }, { text: intl.formatMessage(messages.filters), href: '/filters' }, null, { text: intl.formatMessage(messages.logout), action: handleLogoutClick }, - ]); + ]; }, [intl, dispatch]); - return ( - - ); + return ; }; diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx index 0d154db1e1..c27cd3727f 100644 --- a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx +++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx @@ -24,7 +24,7 @@ import AvatarComposite from 'mastodon/components/avatar_composite'; import { IconButton } from 'mastodon/components/icon_button'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import StatusContent from 'mastodon/components/status_content'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { autoPlayGif } from 'mastodon/initial_state'; import { makeGetStatus } from 'mastodon/selectors'; @@ -205,7 +205,7 @@ export const Conversation = ({ conversation, scrollKey, onMoveUp, onMoveDown })
    - {menu.length > 0 && ( - )} diff --git a/app/javascript/mastodon/features/lists/index.tsx b/app/javascript/mastodon/features/lists/index.tsx index 25a537336e..a455597127 100644 --- a/app/javascript/mastodon/features/lists/index.tsx +++ b/app/javascript/mastodon/features/lists/index.tsx @@ -13,9 +13,9 @@ import { fetchLists } from 'mastodon/actions/lists'; import { openModal } from 'mastodon/actions/modal'; import { Column } from 'mastodon/components/column'; import { ColumnHeader } from 'mastodon/components/column_header'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { Icon } from 'mastodon/components/icon'; import ScrollableList from 'mastodon/components/scrollable_list'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; import { getOrderedLists } from 'mastodon/selectors/lists'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; @@ -60,12 +60,11 @@ const ListItem: React.FC<{ {title} -
    diff --git a/app/javascript/mastodon/features/notifications/components/notification_request.jsx b/app/javascript/mastodon/features/notifications/components/notification_request.jsx index 626929ae50..9c9365d088 100644 --- a/app/javascript/mastodon/features/notifications/components/notification_request.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification_request.jsx @@ -17,7 +17,7 @@ import { initReport } from 'mastodon/actions/reports'; import { Avatar } from 'mastodon/components/avatar'; import { CheckBox } from 'mastodon/components/check_box'; import { IconButton } from 'mastodon/components/icon_button'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { makeGetAccount } from 'mastodon/selectors'; import { toCappedNumber } from 'mastodon/utils/numbers'; diff --git a/app/javascript/mastodon/features/notifications/requests.jsx b/app/javascript/mastodon/features/notifications/requests.jsx index ccaed312b4..b2bdd0ec77 100644 --- a/app/javascript/mastodon/features/notifications/requests.jsx +++ b/app/javascript/mastodon/features/notifications/requests.jsx @@ -23,7 +23,7 @@ import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; import { Icon } from 'mastodon/components/icon'; import ScrollableList from 'mastodon/components/scrollable_list'; -import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; +import { Dropdown } from 'mastodon/components/dropdown_menu'; import { NotificationRequest } from './components/notification_request'; import { PolicyControls } from './components/policy_controls'; @@ -126,7 +126,7 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
    0 && !selectAllChecked} onChange={handleSelectAll} />
    - - +
    ); diff --git a/app/javascript/mastodon/features/status/components/detailed_status.tsx b/app/javascript/mastodon/features/status/components/detailed_status.tsx index 0e6ee8c1ea..2fa43ac132 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.tsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.tsx @@ -14,7 +14,7 @@ import { Link } from 'react-router-dom'; import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; import { AnimatedNumber } from 'mastodon/components/animated_number'; import { ContentWarning } from 'mastodon/components/content_warning'; -import EditedTimestamp from 'mastodon/components/edited_timestamp'; +import { EditedTimestamp } from 'mastodon/components/edited_timestamp'; import { FilterWarning } from 'mastodon/components/filter_warning'; import { FormattedDateWrapper } from 'mastodon/components/formatted_date'; import type { StatusLike } from 'mastodon/components/hashtag_bar'; diff --git a/app/javascript/mastodon/models/dropdown_menu.ts b/app/javascript/mastodon/models/dropdown_menu.ts index 35a29ab62a..ceea9ad4dd 100644 --- a/app/javascript/mastodon/models/dropdown_menu.ts +++ b/app/javascript/mastodon/models/dropdown_menu.ts @@ -3,16 +3,18 @@ interface BaseMenuItem { dangerous?: boolean; } -interface ActionMenuItem extends BaseMenuItem { +export interface ActionMenuItem extends BaseMenuItem { action: () => void; } -interface LinkMenuItem extends BaseMenuItem { +export interface LinkMenuItem extends BaseMenuItem { to: string; } -interface ExternalLinkMenuItem extends BaseMenuItem { +export interface ExternalLinkMenuItem extends BaseMenuItem { href: string; + target?: string; + method?: 'post' | 'put' | 'delete'; } export type MenuItem = @@ -20,5 +22,3 @@ export type MenuItem = | LinkMenuItem | ExternalLinkMenuItem | null; - -export type DropdownMenu = MenuItem[]; diff --git a/app/javascript/mastodon/reducers/dropdown_menu.ts b/app/javascript/mastodon/reducers/dropdown_menu.ts index 59e19bb16d..0e46f0ee80 100644 --- a/app/javascript/mastodon/reducers/dropdown_menu.ts +++ b/app/javascript/mastodon/reducers/dropdown_menu.ts @@ -3,15 +3,15 @@ import { createReducer } from '@reduxjs/toolkit'; import { closeDropdownMenu, openDropdownMenu } from '../actions/dropdown_menu'; interface DropdownMenuState { - openId: string | null; + openId: number | null; keyboard: boolean; - scrollKey: string | null; + scrollKey: string | undefined; } const initialState: DropdownMenuState = { openId: null, keyboard: false, - scrollKey: null, + scrollKey: undefined, }; export const dropdownMenuReducer = createReducer(initialState, (builder) => { @@ -27,7 +27,7 @@ export const dropdownMenuReducer = createReducer(initialState, (builder) => { .addCase(closeDropdownMenu, (state, { payload: { id } }) => { if (state.openId === id) { state.openId = null; - state.scrollKey = null; + state.scrollKey = undefined; } }); }); From 498372fd06bfb0235b75888629ca5de0336ccd71 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 09:57:18 +0200 Subject: [PATCH 30/48] New Crowdin Translations (automated) (#34403) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 2 +- app/javascript/mastodon/locales/fi.json | 2 +- app/javascript/mastodon/locales/lad.json | 13 ++++++++++- config/locales/fi.yml | 2 +- config/locales/lad.yml | 12 ++++++++++ config/locales/lv.yml | 29 ++++++++++++++++++++++++ config/locales/simple_form.lad.yml | 3 +++ 7 files changed, 59 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index eb7a22a04b..bf5a5b1016 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -675,7 +675,7 @@ "onboarding.follows.title": "Последвайте хора, за да започнете", "onboarding.profile.discoverable": "Правене на моя профил откриваем", "onboarding.profile.discoverable_hint": "Включвайки откриваемостта в Mastodon, вашите публикации може да се появят при резултатите от търсене и изгряващи неща, и вашия профил може да бъде предложен на хора с подобни интереси като вашите.", - "onboarding.profile.display_name": "Името на показ", + "onboarding.profile.display_name": "Показвано име", "onboarding.profile.display_name_hint": "Вашето пълно име или псевдоним…", "onboarding.profile.note": "Биография", "onboarding.profile.note_hint": "Може да @споменавате други хора или #хаштагове…", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 4be3211045..53df277b70 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -240,7 +240,7 @@ "conversation.mark_as_read": "Merkitse luetuksi", "conversation.open": "Näytä keskustelu", "conversation.with": "{names} kanssa", - "copy_icon_button.copied": "Sisältö kopioitiin leikepöydälle", + "copy_icon_button.copied": "Kopioitu leikepöydälle", "copypaste.copied": "Kopioitu", "copypaste.copy_to_clipboard": "Kopioi leikepöydälle", "directory.federated": "Tunnetusta fediversumista", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index ab410dc2a8..d9d941f8e8 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}", "account.unblock": "Dezbloka a @{name}", "account.unblock_domain": "Dezbloka domeno {domain}", + "account.unblock_domain_short": "Dezbloka", "account.unblock_short": "Dezbloka", "account.unendorse": "No avalia en profil", "account.unfollow": "Desige", @@ -86,6 +87,7 @@ "alert.unexpected.message": "Afito un yerro no asperado.", "alert.unexpected.title": "Atyo!", "alt_text_badge.title": "Teksto alternativo", + "alt_text_modal.add_alt_text": "Adjusta teksto alternativo", "alt_text_modal.cancel": "Anula", "alt_text_modal.change_thumbnail": "Troka minyatura", "alt_text_modal.done": "Fecho", @@ -195,9 +197,12 @@ "confirmations.discard_edit_media.message": "Tienes trokamientos no guadrados en la deskripsion o vista previa. Keres efasarlos entanto?", "confirmations.edit.confirm": "Edita", "confirmations.edit.message": "Si edites agora, kitaras el mesaj kualo estas eskriviendo aktualmente. Estas siguro ke keres fazerlo?", + "confirmations.follow_to_list.title": "Segir utilizador?", "confirmations.logout.confirm": "Sal", "confirmations.logout.message": "Estas siguro ke keres salir de tu kuento?", "confirmations.logout.title": "Salir?", + "confirmations.missing_alt_text.confirm": "Adjusta teksto alternativo", + "confirmations.missing_alt_text.title": "Adjustar teksto alternativo?", "confirmations.mute.confirm": "Silensia", "confirmations.redraft.confirm": "Efasa i reeskrive", "confirmations.redraft.message": "Estas siguro ke keres efasar esta publikasyon i reeskrivirla? Pedreras todos los favoritos i repartajasyones asosiados kon esta publikasyon i repuestas a eya seran guerfanadas.", @@ -372,6 +377,7 @@ "ignore_notifications_modal.not_followers_title": "Inyorar avizos de personas a las kualas no te sigen?", "ignore_notifications_modal.not_following_title": "Inyorar avizos de personas a las kualas no siges?", "ignore_notifications_modal.private_mentions_title": "Ignorar avizos de mensyones privadas no solisitadas?", + "info_button.label": "Ayuda", "interaction_modal.on_another_server": "En otro sirvidor", "interaction_modal.on_this_server": "En este sirvidor", "interaction_modal.title.favourite": "Endika ke te plaze publikasyon de {name}", @@ -426,6 +432,7 @@ "link_preview.shares": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}", "lists.add_member": "Adjusta", "lists.add_to_list": "Adjusta a lista", + "lists.create": "Kriya", "lists.create_list": "Kriya lista", "lists.delete": "Efasa lista", "lists.done": "Fecho", @@ -588,6 +595,7 @@ "poll_button.remove_poll": "Kita anketa", "privacy.change": "Troka privasita de publikasyon", "privacy.direct.long": "Todos enmentados en la publikasyon", + "privacy.direct.short": "Enmentadura privada", "privacy.private.long": "Solo para tus suivantes", "privacy.private.short": "Suivantes", "privacy.public.long": "Todos en i afuera de Mastodon", @@ -682,6 +690,7 @@ "search_results.accounts": "Profiles", "search_results.all": "Todos", "search_results.hashtags": "Etiketas", + "search_results.no_results": "No ay rezultados.", "search_results.see_all": "Ve todo", "search_results.statuses": "Publikasyones", "search_results.title": "Bushka por \"{q}\"", @@ -775,6 +784,8 @@ "video.expand": "Espande video", "video.fullscreen": "Ekran kompleto", "video.hide": "Eskonde video", + "video.mute": "Silensia", "video.pause": "Pauza", - "video.play": "Reproduze" + "video.play": "Reproduze", + "video.unmute": "Desilensia" } diff --git a/config/locales/fi.yml b/config/locales/fi.yml index e999748ad9..fcb180518f 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -457,7 +457,7 @@ fi: domain: Verkkotunnus new: create: Lisää verkkotunnus - resolve: Selvitä verkkotunnus + resolve: Resolvoi verkkotunnus title: Estä uusi sähköpostiverkkotunnus no_email_domain_block_selected: Sähköpostiverkkotunnusten estoja ei muutettu, koska yhtäkään ei ollut valittuna not_permitted: Ei sallittu diff --git a/config/locales/lad.yml b/config/locales/lad.yml index 86dbc668c0..c1364fbb01 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -462,6 +462,18 @@ lad: new: title: Importa blokos de domeno no_file: Dinguna dosya tiene sido eskojida + fasp: + debug: + callbacks: + delete: Efasa + providers: + name: Nombre + registrations: + confirm: Konfirma + reject: Refuza + save: Guadra + sign_in: Konektate + status: Estado follow_recommendations: description_html: "Las rekomendasyones de kuentos ayudan a los muevos utilizadores a topar presto kontenido enteresante. Kuando un utilizador no tiene enteraktuado kon otros lo sufisiente komo para djenerar rekomendasyones personalizadas de kuentos a las ke segir, en sus lugar se le rekomiendan estes kuentos. Se rekalkulan diariamente a partir de una mikstura de kuentos kon el mayor numero de enteraksyones rezientes i kon el mayor numero de suivantes lokales kon una lingua determinada." language: Para la lingua diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 9ed84286d8..151cc6cf6c 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -1507,6 +1507,14 @@ lv: one: Tu gatavojies sekot līdz %{count} kontam no %{filename}. other: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. zero: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. + lists_html: + one: Tu gatavojies pievienot līdz pat %{count} kontam no %{filename} saviem sarakstiem. Tiks izveidoti jauni saraksti, ja nav saraksta, kurā pievienot. + other: Tu gatavojies pievienot līdz pat %{count} kontiem no %{filename} saviem sarakstiem. Tiks izveidoti jauni saraksti, ja nav saraksta, kurā pievienot. + zero: Tu gatavojies pievienot līdz pat %{count} kontiem no %{filename} saviem sarakstiem. Tiks izveidoti jauni saraksti, ja nav saraksta, kurā pievienot. + muting_html: + one: Tu gatavojies apklusināt līdz pat %{count} kontam no %{filename}. + other: Tu gatavojies apklusināt līdz pat %{count} kontiem no %{filename}. + zero: Tu gatavojies apklusināt līdz pat %{count} kontiem no %{filename}. preface: Tu vari ievietot datus, kurus esi izguvis no cita servera, kā, piemēram, cilvēku sarakstu, kuriem Tu seko vai kurus bloķē. recent_imports: Nesen importēts states: @@ -1578,6 +1586,7 @@ lv: unsubscribe: action: Jā, atcelt abonēšanu complete: Anulēts + confirmation_html: Vai tiešām atteikties no %{type} saņemšanas savā e-pasta adresē %{email} par %{domain} esošo Mastodon? Vienmēr var abonēt no jauna savos e-pasta paziņojumu iestatījumos. emails: notification_emails: favourite: izlases paziņojumu e-pasta ziņojumi @@ -1585,10 +1594,13 @@ lv: follow_request: sekošanas pieprasījumu e-pasta ziņojumi mention: pieminēšanas paziņojumu e-pasta ziņojumi reblog: pastiprinājumu paziņojumu e-pasta ziņojumi + resubscribe_html: Ja abonements tika atcelts kļūdas dēļ, abonēt no jauna var savos e-pasta paziņojumu iestatījumos. + success_html: Tu vairs savā e-pasta adresē %{email} nesaņemsi %{type} par %{domain} esošo Mastodon. title: Atcelt abonēšanu media_attachments: validations: images_and_video: Nevar pievienot videoklipu tādai ziņai, kura jau satur attēlus + not_found: Informācijas nesējs %{ids} nav atrasts vai jau pievienots citam ierakstam not_ready: Nevar pievienot failus, kuru apstrāde nav pabeigta. Pēc brīža mēģini vēlreiz! too_many: Nevar pievienot vairāk kā 4 failus migrations: @@ -1666,6 +1678,7 @@ lv: subject: "%{name} laboja ierakstu" notifications: administration_emails: Pārvaldītāju e-pasta paziņojumi + email_events: E-pasta paziņojumu notikumi email_events_hint: 'Atlasi notikumus, par kuriem vēlies saņemt paziņojumus:' number: human: @@ -1722,6 +1735,9 @@ lv: errors: limit_reached: Sasniegts dažādu reakciju limits unrecognized_emoji: nav atpazīta emocijzīme + redirects: + prompt: Ja uzticies šai saitei, jāklikšķina uz tās, lai turpinātu. + title: Tu atstāj %{instance}. relationships: activity: Konta aktivitāte confirm_follow_selected_followers: Vai tiešām vēlies sekot atlasītajiem sekotājiem? @@ -1833,10 +1849,13 @@ lv: severed_relationships: download: Lejupielādēt (%{count}) event_type: + account_suspension: Konta apturēšana (%{target_name}) + domain_block: Servera apturēšana (%{target_name}) user_domain_block: Jūs bloķējāt %{target_name} lost_followers: Zaudētie sekotāji lost_follows: Zaudētie sekojumi preamble: Tu vari zaudēt sekojamos un sekotājus, kad liedz domēnu vai kad satura pārraudzītāji izlemj apturēt attālu serveri. Kad t as notiek, būs iespējams lejupielādēt sarakstus ar pārtrauktajām saiknēm, kurus tad var izpētīt un, iespējams, ievietot citā serverī. + purged: Informāciju par šo serveri notīrīja Tava servera pārvaldītāji. type: Notikums statuses: attached: @@ -1926,6 +1945,7 @@ lv: contrast: Mastodon (Augsts kontrasts) default: Mastodon (Tumšs) mastodon-light: Mastodon (Gaišs) + system: Automātisks (ievēro sistēmas izskatu) time: formats: default: "%b %d, %Y, %H:%M" @@ -1952,6 +1972,10 @@ lv: recovery_instructions_html: Ja kādreiz zaudēsi piekļuvi savam tālrunim, vari izmantot kādu no zemāk norādītajiem atkopes kodiem, lai atgūtu piekļuvi savam kontam. Atkpes kodi jātur drošībā. Piemēram, tos var izdrukāt un glabāt kopā ar citiem svarīgiem dokumentiem. webauthn: Drošības atslēgas user_mailer: + announcement_published: + description: "%{domain} pārvaldītāji veic paziņojumu:" + subject: Pakalpojuma paziņojums + title: "%{domain} pakalpojuma paziņojums" appeal_approved: action: Konta iestatījumi explanation: Apelācija par brīdinājumu jūsu kontam %{strike_date}, ko iesniedzāt %{appeal_date}, ir apstiprināta. Jūsu konts atkal ir labā stāvoklī. @@ -1962,8 +1986,13 @@ lv: subject: Jūsu %{date} apelācija ir noraidīta title: Apelācija noraidīta backup_ready: + explanation: Tu pieprasīji pilnu sava Mastodon konta rezerves kopiju. + extra: Tā tagad ir gatava lejupielādei. subject: Tavs arhīvs ir gatavs lejupielādei title: Arhīva līdzņemšana + failed_2fa: + details: 'Šeit ir informācija par pieteikšanās mēģinājumu:' + explanation: Kāds mēģināja pieteikties Tavā kontā, bet norādīja nederīgu otro autentificēšanās soli. suspicious_sign_in: change_password: mainīt paroli details: 'Šeit ir pieteikšanās izvērsums:' diff --git a/config/locales/simple_form.lad.yml b/config/locales/simple_form.lad.yml index 6fef9f7422..a3f70bd361 100644 --- a/config/locales/simple_form.lad.yml +++ b/config/locales/simple_form.lad.yml @@ -311,6 +311,9 @@ lad: terms_of_service_generator: domain: Domeno user: + date_of_birth_1i: Diya + date_of_birth_2i: Mez + date_of_birth_3i: Anyo role: Rolo time_zone: Zona de tiempo user_role: From 6deadd596d44a036ce2376d713092a805a81c593 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 9 Apr 2025 09:42:57 -0400 Subject: [PATCH 31/48] Remove deprecated single-argument variation of `UnfilterNotificationsWorker` (#33353) --- app/workers/unfilter_notifications_worker.rb | 21 +++------------- .../unfilter_notifications_worker_spec.rb | 24 +++++++++---------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/app/workers/unfilter_notifications_worker.rb b/app/workers/unfilter_notifications_worker.rb index 53a35ce12c..cb8a46b8f4 100644 --- a/app/workers/unfilter_notifications_worker.rb +++ b/app/workers/unfilter_notifications_worker.rb @@ -4,25 +4,14 @@ class UnfilterNotificationsWorker include Sidekiq::Worker include Redisable - # Earlier versions of the feature passed a `notification_request` ID - # If `to_account_id` is passed, the first argument is an account ID - # TODO for after 4.3.0: drop the single-argument case - def perform(notification_request_or_account_id, from_account_id = nil) - if from_account_id.present? - @notification_request = nil - @from_account = Account.find_by(id: from_account_id) - @recipient = Account.find_by(id: notification_request_or_account_id) - else - @notification_request = NotificationRequest.find_by(id: notification_request_or_account_id) - @from_account = @notification_request&.from_account - @recipient = @notification_request&.account - end + def perform(account_id, from_account_id) + @from_account = Account.find_by(id: from_account_id) + @recipient = Account.find_by(id: account_id) return if @from_account.nil? || @recipient.nil? push_to_conversations! unfilter_notifications! - remove_request! decrement_worker_count! end @@ -36,10 +25,6 @@ class UnfilterNotificationsWorker filtered_notifications.in_batches.update_all(filtered: false) end - def remove_request! - @notification_request&.destroy! - end - def filtered_notifications Notification.where(account: @recipient, from_account: @from_account, filtered: true) end diff --git a/spec/workers/unfilter_notifications_worker_spec.rb b/spec/workers/unfilter_notifications_worker_spec.rb index 464a4520ff..2fd130301f 100644 --- a/spec/workers/unfilter_notifications_worker_spec.rb +++ b/spec/workers/unfilter_notifications_worker_spec.rb @@ -5,6 +5,7 @@ require 'rails_helper' RSpec.describe UnfilterNotificationsWorker do let(:recipient) { Fabricate(:account) } let(:sender) { Fabricate(:account) } + let(:worker) { described_class.new } before do # Populate multiple kinds of filtered notifications @@ -67,23 +68,22 @@ RSpec.describe UnfilterNotificationsWorker do end describe '#perform' do - context 'with single argument (prerelease behavior)' do - subject { described_class.new.perform(notification_request.id) } - - let(:notification_request) { Fabricate(:notification_request, from_account: sender, account: recipient) } + context 'with recipient and sender' do + subject { worker.perform(recipient.id, sender.id) } it_behaves_like 'shared behavior' - - it 'destroys the notification request' do - expect { subject } - .to change { NotificationRequest.exists?(notification_request.id) }.to(false) - end end - context 'with two arguments' do - subject { described_class.new.perform(recipient.id, sender.id) } + context 'with missing records' do + it 'runs without error for missing sender' do + expect { worker.perform(recipient.id, nil) } + .to_not raise_error + end - it_behaves_like 'shared behavior' + it 'runs without error for missing recipient' do + expect { worker.perform(nil, sender.id) } + .to_not raise_error + end end end end From a89ddcfd2d8f8dc5159e874dd33edc3f6c57fe7a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 09:01:39 +0200 Subject: [PATCH 32/48] New Crowdin Translations (automated) (#34407) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/fa.json | 1 + app/javascript/mastodon/locales/pt-BR.json | 1 + config/locales/fa.yml | 16 ++++++++++++++ config/locales/lv.yml | 25 ++++++++++++++-------- config/locales/pt-BR.yml | 16 ++++++++++++++ config/locales/simple_form.fa.yml | 3 +++ 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index f4758e5afb..27f0bf4e9a 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}}", "account.unblock": "رفع مسدودیت ‎@{name}", "account.unblock_domain": "رفع مسدودیت دامنهٔ {domain}", + "account.unblock_domain_short": "آنبلاک", "account.unblock_short": "رفع مسدودیت", "account.unendorse": "معرّفی نکردن در نمایه", "account.unfollow": "پی‌نگرفتن", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 3ac1946503..5279159d79 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicação} other {{counter} publicações}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear domínio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "Remover", "account.unfollow": "Deixar de seguir", diff --git a/config/locales/fa.yml b/config/locales/fa.yml index b5dce6dabf..f1c74829c9 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -479,6 +479,22 @@ fa: new: title: درون‌ریزی انسدادهای دامنه no_file: هیچ پرونده‌ای گزیده نشده + fasp: + debug: + callbacks: + delete: حذف + providers: + active: فعال + delete: حذف + finish_registration: تکمیل ثبت‌نام + name: نام + providers: ارائه دهندگان + registrations: + confirm: تایید + reject: رد کردن + save: ذخیره + sign_in: ورود + status: وضعیت follow_recommendations: description_html: "پیشنهادات پیگیری به کاربران جدید کک می‌کند تا سریع‌تر محتوای جالب را پیدا کنند. زمانی که کاربری هنوز به اندازه کافی با دیگران تعامل نداشته است تا پیشنهادات پیگیری شخصی‌سازی‌شده دریافت کند، این حساب‌ها را به جای آن فهرست مشاهده خواهد کرد. این حساب‌ها به صورت روزانه و در ترکیب با بیشتری تعاملات و بالاترین دنبال‌کنندگان محلی برای یک زبان مشخص بازمحاسبه می‌شوند." language: برای زبان diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 151cc6cf6c..fad8a2609e 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -259,6 +259,7 @@ lv: create_user_role_html: "%{name} nomainīja %{target} lomu" demote_user_html: "%{name} pazemināja lietotāju %{target}" destroy_announcement_html: "%{name} izdzēsa paziņojumu %{target}" + destroy_canonical_email_block_html: "%{name} atcēla e-pasta adreses liegumu ar jaucējvērtību %{target}" destroy_custom_emoji_html: "%{name} izdzēsa emocijzīmi %{target}" destroy_domain_allow_html: "%{name} neatļāva federāciju ar domēnu %{target}" destroy_domain_block_html: "%{name} atbloķēja domēnu %{target}" @@ -409,7 +410,7 @@ lv: permanent_action: Apturēšanas atsaukšana neatjaunos nekādus datus vai attiecības. preamble_html: Tu gatavojies apturēt domēna %{domain} un tā apakšdomēnu darbību. remove_all_data: Tādējādi no tava servera tiks noņemts viss šī domēna kontu saturs, multivide un profila dati. - stop_communication: Jūsu serveris pārtrauks sazināties ar šiem serveriem. + stop_communication: Tavs serveris pārtrauks sazināties ar šiem serveriem. title: Apstiprināt domēna %{domain} bloķēšanu undo_relationships: Tādējādi tiks atsauktas jebkuras sekošanas attiecības starp šo un tavu serveru kontiem. created_msg: Domēna bloķēšana tagad tiek apstrādāta @@ -949,11 +950,13 @@ lv: message_html: "Tava objektu krātuve ir nepareizi konfigurēta. Tavu lietotāju privātums ir apdraudēts." tags: moderation: + not_trendable: Nav izplatīts not_usable: Nav izmantojams pending_review: Gaida pārskatīšanu review_requested: Pieprasīta pārskatīšana reviewed: Pārskatīts title: Stāvoklis + trendable: Izplatīts unreviewed: Nepārskatīts usable: Izmantojams name: Nosaukums @@ -1312,7 +1315,7 @@ lv: appeal_approved: Šis brīdinājums tika sekmīgi pārsūdzēts un vairs nav spēkā appeal_rejected: Apelācija ir noraidīta appeal_submitted_at: Apelācija iesniegta - appealed_msg: Jūsu apelācija ir iesniegta. Ja tā tiks apstiprināta, jums tiks paziņots. + appealed_msg: Tava pārsūdzība ir iesniegta. Ja tā tiks apstiprināta, Tev tiks paziņots. appeals: submit: Iesniegt apelāciju approve_appeal: Apstiprināt apelāciju @@ -1332,9 +1335,9 @@ lv: sensitive: Konta atzīmēšana kā jūtīgu silence: Konta ierobežošana suspend: Konta apturēšana - your_appeal_approved: Jūsu apelācija ir apstiprināta + your_appeal_approved: Tava pārsūdzība tika apstiprināta your_appeal_pending: Jūs esat iesniedzis apelāciju - your_appeal_rejected: Jūsu apelācija ir noraidīta + your_appeal_rejected: Tava pārsūdzība tika noraidīta edit_profile: basic_information: Pamata informācija hint_html: "Pielāgo, ko cilvēki redz Tavā publiskajā profilā un blakus Taviem ierakstiem. Ir lielāka iespējamība, ka citi clivēki sekos Tev un mijiedarbosies ar Tevi, ja Tev ir aizpildīts profils un profila attēls." @@ -1929,7 +1932,7 @@ lv: '7889238': 3 mēneši min_age_label: Vecuma slieksnis min_favs: Saglabāt ziņas izlsasē vismaz - min_favs_hint: Nedzēš nevienu jūsu ziņu, kas ir saņēmusi vismaz tik daudz izcēlumu. Atstājiet tukšu, lai dzēstu ziņas neatkarīgi no to izcēlumu skaita + min_favs_hint: Neizdzēš nevienu no Taviem ierakstiem, kas ir pievienoti šādā daudzumā izlašu. Atstāt tukšu, lai izdzēstu ierakstus neatkarīgi no tā, cik izlasēs tie ir pievienoti min_reblogs: Saglabāt ziņas izceltas vismaz min_reblogs_hint: Neizdzēš nevienu no tavām ziņām, kas ir izceltas vismaz tik reižu. Atstāj tukšu, lai dzēstu ziņas neatkarīgi no to izcēlumu skaita stream_entries: @@ -1978,12 +1981,13 @@ lv: title: "%{domain} pakalpojuma paziņojums" appeal_approved: action: Konta iestatījumi - explanation: Apelācija par brīdinājumu jūsu kontam %{strike_date}, ko iesniedzāt %{appeal_date}, ir apstiprināta. Jūsu konts atkal ir labā stāvoklī. - subject: Jūsu %{date} apelācija ir apstiprināta + explanation: Pārsūdzība par brīdinājumu Tavam kontam %{strike_date}, ko iesniedzi %{appeal_date}, ir apstiprināta. Tavs konts atkal ir labā stāvoklī. + subject: Tava %{date} iesniegtā pārsūdzība tika apstiprināta title: Apelācija apstiprināta appeal_rejected: - explanation: Apelācija par brīdinājumu jūsu kontam %{strike_date}, ko iesniedzāt %{appeal_date}, ir noraidīta. - subject: Jūsu %{date} apelācija ir noraidīta + explanation: Pārsūdzība par brīdinājumu Tavam kontam %{strike_date}, ko iesniedzi %{appeal_date}, tika noraidīta. + subject: Tava %{date} iesniegta pārsūdzība tika noraidīta + subtitle: Tava pārsūdzība tika noraidīta. title: Apelācija noraidīta backup_ready: explanation: Tu pieprasīji pilnu sava Mastodon konta rezerves kopiju. @@ -1993,6 +1997,9 @@ lv: failed_2fa: details: 'Šeit ir informācija par pieteikšanās mēģinājumu:' explanation: Kāds mēģināja pieteikties Tavā kontā, bet norādīja nederīgu otro autentificēšanās soli. + further_actions_html: Ja tas nebiji Tu, mēs iesakām nekavējoties %{action}, jo var būt noticis drošības pārkāpums. + subject: Otrās pakāpes autentificēšanās atteice + title: Neizdevās otrās pakāpes autentificēšanās suspicious_sign_in: change_password: mainīt paroli details: 'Šeit ir pieteikšanās izvērsums:' diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 6a8fdda024..a2e142ab55 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -320,6 +320,7 @@ pt-BR: title: Novo anúncio preview: explanation_html: 'Esse e-mail será enviado a %{display_count} usuários. O texto a seguir será incluído ao e-mail:' + title: Visualizar anúncio publish: Publicar published_msg: Anúncio publicado! scheduled_for: Agendado para %{time} @@ -484,19 +485,30 @@ pt-BR: created_at: Criado em delete: Apagar ip: Endereço de IP + request_body: Corpo da solicitação + title: Depurar Callbacks providers: + active: Ativo base_url: URL Base + callback: Callback delete: Apagar + edit: Editar provedor finish_registration: Finalizar o cadastro name: Nome + providers: Provedores public_key_fingerprint: Impressão digital de chave pública registration_requested: Cadastro solicitado registrations: confirm: Confirmar + description: Você recebeu um registro de um FASP. Rejeite se você não tiver iniciado isso. Se você iniciou isso, compare cuidadosamente o nome e a impressão digital da chave antes de confirmar o registro. reject: Rejeitar + title: Confirmar o registro FASP save: Salvar + select_capabilities: Selecionar recursos sign_in: Entrar status: Estado + title: Provedores de serviços auxiliares do Fediverso + title: FASP follow_recommendations: description_html: "A recomendação de contas ajuda os novos usuários a encontrar rapidamente conteúdo interessante. Quando um usuário ainda não tiver interagido o suficiente para gerar recomendações de contas, essas contas serão recomendadas. Essas recomendações são recalculadas diariamente a partir de uma lista de contas com alto engajamento e maior número de seguidores locais em uma dada língua." language: Na língua @@ -1927,6 +1939,10 @@ pt-BR: recovery_instructions_html: Se você perder acesso ao seu celular, você pode usar um dos códigos de recuperação abaixo para acessar a sua conta. Mantenha os códigos de recuperação em um local seguro. Por exemplo, você pode imprimi-los e guardá-los junto a outros documentos importantes. webauthn: Chaves de segurança user_mailer: + announcement_published: + description: 'Os administradores do %{domain} estão fazendo um anúncio:' + subject: Anúncio de serviço + title: Anúncio de serviço de %{domain} appeal_approved: action: Configurações da conta explanation: A revisão da punição na sua conta em %{strike_date} que você enviou em %{appeal_date} foi aprovada. Sua conta está novamente em situação regular. diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index 520b684847..9f46cdec7d 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -349,6 +349,9 @@ fa: jurisdiction: صلاحیت قانونی min_age: کمینهٔ زمان user: + date_of_birth_1i: روز + date_of_birth_2i: ماه + date_of_birth_3i: سال role: نقش time_zone: منطقهٔ زمانی user_role: From e74d682b218096578d59f9a310a85e315dac1b6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 09:02:44 +0200 Subject: [PATCH 33/48] chore(deps): update dependency linzer to v0.6.5 (#34409) 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 865686a5bd..86cfaa3132 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -395,7 +395,7 @@ GEM rexml link_header (0.0.8) lint_roller (1.1.0) - linzer (0.6.4) + linzer (0.6.5) openssl (~> 3.0, >= 3.0.0) rack (>= 2.2, < 4.0) starry (~> 0.2) From 4c2f64907bb7220db5c6323dd18fb8d37443741c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 10 Apr 2025 08:49:24 -0400 Subject: [PATCH 34/48] Remove deprecated `Import` model (#34371) --- .../dimension/space_usage_dimension.rb | 1 - app/models/import.rb | 46 ---- app/services/import_service.rb | 144 ----------- app/workers/import/relationship_worker.rb | 57 ----- app/workers/import_worker.rb | 17 -- config/initializers/paperclip.rb | 2 +- db/migrate/20250410144908_drop_imports.rb | 11 + db/schema.rb | 16 +- lib/mastodon/cli/media.rb | 2 - spec/fabricators/import_fabricator.rb | 7 - spec/models/import_spec.rb | 10 - spec/services/import_service_spec.rb | 242 ------------------ spec/workers/import_worker_spec.rb | 23 -- 13 files changed, 13 insertions(+), 565 deletions(-) delete mode 100644 app/models/import.rb delete mode 100644 app/services/import_service.rb delete mode 100644 app/workers/import/relationship_worker.rb delete mode 100644 app/workers/import_worker.rb create mode 100644 db/migrate/20250410144908_drop_imports.rb delete mode 100644 spec/fabricators/import_fabricator.rb delete mode 100644 spec/models/import_spec.rb delete mode 100644 spec/services/import_service_spec.rb delete mode 100644 spec/workers/import_worker_spec.rb diff --git a/app/lib/admin/metrics/dimension/space_usage_dimension.rb b/app/lib/admin/metrics/dimension/space_usage_dimension.rb index f1b6dba040..0d3fd8db33 100644 --- a/app/lib/admin/metrics/dimension/space_usage_dimension.rb +++ b/app/lib/admin/metrics/dimension/space_usage_dimension.rb @@ -45,7 +45,6 @@ class Admin::Metrics::Dimension::SpaceUsageDimension < Admin::Metrics::Dimension PreviewCard.sum(:image_file_size), Account.sum(Arel.sql('COALESCE(avatar_file_size, 0) + COALESCE(header_file_size, 0)')), Backup.sum(:dump_file_size), - Import.sum(:data_file_size), SiteUpload.sum(:file_file_size), ].sum diff --git a/app/models/import.rb b/app/models/import.rb deleted file mode 100644 index 4bdb392014..0000000000 --- a/app/models/import.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: imports -# -# id :bigint(8) not null, primary key -# type :integer not null -# approved :boolean default(FALSE), not null -# created_at :datetime not null -# updated_at :datetime not null -# data_file_name :string -# data_content_type :string -# data_file_size :integer -# data_updated_at :datetime -# account_id :bigint(8) not null -# overwrite :boolean default(FALSE), not null -# - -# NOTE: This is a deprecated model, only kept to not break ongoing imports -# on upgrade. See `BulkImport` and `Form::Import` for its replacements. - -class Import < ApplicationRecord - FILE_TYPES = %w(text/plain text/csv application/csv).freeze - MODES = %i(merge overwrite).freeze - - self.inheritance_column = false - - belongs_to :account - - enum :type, { following: 0, blocking: 1, muting: 2, domain_blocking: 3, bookmarks: 4 } - - validates :type, presence: true - - has_attached_file :data - validates_attachment_content_type :data, content_type: FILE_TYPES - validates_attachment_presence :data - - def mode - overwrite? ? :overwrite : :merge - end - - def mode=(str) - self.overwrite = str.to_sym == :overwrite - end -end diff --git a/app/services/import_service.rb b/app/services/import_service.rb deleted file mode 100644 index a695df2fc9..0000000000 --- a/app/services/import_service.rb +++ /dev/null @@ -1,144 +0,0 @@ -# frozen_string_literal: true - -require 'csv' - -# NOTE: This is a deprecated service, only kept to not break ongoing imports -# on upgrade. See `BulkImportService` for its replacement. - -class ImportService < BaseService - ROWS_PROCESSING_LIMIT = 20_000 - - def call(import) - @import = import - @account = @import.account - - case @import.type - when 'following' - import_follows! - when 'blocking' - import_blocks! - when 'muting' - import_mutes! - when 'domain_blocking' - import_domain_blocks! - when 'bookmarks' - import_bookmarks! - end - end - - private - - def import_follows! - parse_import_data!(['Account address']) - import_relationships!('follow', 'unfollow', @account.following, ROWS_PROCESSING_LIMIT, reblogs: { header: 'Show boosts', default: true }, notify: { header: 'Notify on new posts', default: false }, languages: { header: 'Languages', default: nil }) - end - - def import_blocks! - parse_import_data!(['Account address']) - import_relationships!('block', 'unblock', @account.blocking, ROWS_PROCESSING_LIMIT) - end - - def import_mutes! - parse_import_data!(['Account address']) - import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT, notifications: { header: 'Hide notifications', default: true }) - end - - def import_domain_blocks! - parse_import_data!(['#domain']) - items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip } - - if @import.overwrite? - presence_hash = items.index_with(true) - - @account.domain_blocks.find_each do |domain_block| - if presence_hash[domain_block.domain] - items.delete(domain_block.domain) - else - @account.unblock_domain!(domain_block.domain) - end - end - end - - items.each do |domain| - @account.block_domain!(domain) - end - - AfterAccountDomainBlockWorker.push_bulk(items) do |domain| - [@account.id, domain] - end - end - - def import_relationships!(action, undo_action, overwrite_scope, limit, extra_fields = {}) - local_domain_suffix = "@#{Rails.configuration.x.local_domain}" - items = @data.take(limit).map { |row| [row['Account address']&.strip&.delete_suffix(local_domain_suffix), extra_fields.to_h { |key, field_settings| [key, row[field_settings[:header]]&.strip || field_settings[:default]] }] }.reject { |(id, _)| id.blank? } - - if @import.overwrite? - presence_hash = items.each_with_object({}) { |(id, extra), mapping| mapping[id] = [true, extra] } - - overwrite_scope.reorder(nil).find_each do |target_account| - if presence_hash[target_account.acct] - items.delete(target_account.acct) - extra = presence_hash[target_account.acct][1] - Import::RelationshipWorker.perform_async(@account.id, target_account.acct, action, extra.stringify_keys) - else - Import::RelationshipWorker.perform_async(@account.id, target_account.acct, undo_action) - end - end - end - - head_items = items.uniq { |acct, _| acct.split('@')[1] } - tail_items = items - head_items - - Import::RelationshipWorker.push_bulk(head_items + tail_items) do |acct, extra| - [@account.id, acct, action, extra.stringify_keys] - end - end - - def import_bookmarks! - parse_import_data!(['#uri']) - items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#uri'].strip } - - if @import.overwrite? - presence_hash = items.index_with(true) - - @account.bookmarks.find_each do |bookmark| - if presence_hash[bookmark.status.uri] - items.delete(bookmark.status.uri) - else - bookmark.destroy! - end - end - end - - statuses = items.filter_map do |uri| - status = ActivityPub::TagManager.instance.uri_to_resource(uri, Status) - next if status.nil? && ActivityPub::TagManager.instance.local_uri?(uri) - - status || ActivityPub::FetchRemoteStatusService.new.call(uri) - rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::UnexpectedResponseError - nil - rescue => e - Rails.logger.warn "Unexpected error when importing bookmark: #{e}" - nil - end - - account_ids = statuses.map(&:account_id) - preloaded_relations = @account.relations_map(account_ids, skip_blocking_and_muting: true) - - statuses.keep_if { |status| StatusPolicy.new(@account, status, preloaded_relations).show? } - - statuses.each do |status| - @account.bookmarks.find_or_create_by!(account: @account, status: status) - end - end - - def parse_import_data!(default_headers) - data = CSV.parse(import_data, headers: true) - data = CSV.parse(import_data, headers: default_headers) unless data.headers&.first&.strip&.include?(' ') - @data = data.compact_blank - end - - def import_data - Paperclip.io_adapters.for(@import.data).read.force_encoding(Encoding::UTF_8) - end -end diff --git a/app/workers/import/relationship_worker.rb b/app/workers/import/relationship_worker.rb deleted file mode 100644 index 2298b095a7..0000000000 --- a/app/workers/import/relationship_worker.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This is a deprecated worker, only kept to not break ongoing imports -# on upgrade. See `Import::RowWorker` for its replacement. - -class Import::RelationshipWorker - include Sidekiq::Worker - - sidekiq_options queue: 'pull', retry: 8, dead: false - - def perform(account_id, target_account_uri, relationship, options) - from_account = Account.find(account_id) - target_domain = domain(target_account_uri) - 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? - - case relationship - when 'follow' - begin - FollowService.new.call(from_account, target_account, **options) - rescue ActiveRecord::RecordInvalid - raise if FollowLimitValidator.limit_for_account(from_account) < from_account.following_count - end - when 'unfollow' - UnfollowService.new.call(from_account, target_account) - when 'block' - BlockService.new.call(from_account, target_account) - when 'unblock' - UnblockService.new.call(from_account, target_account) - when 'mute' - MuteService.new.call(from_account, target_account, **options) - when 'unmute' - UnmuteService.new.call(from_account, target_account) - end - rescue ActiveRecord::RecordNotFound - true - end - - def domain(uri) - domain = uri.is_a?(Account) ? uri.domain : uri.split('@')[1] - TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain) - end - - def stoplight_wrapper(domain) - if domain.present? - 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) } - else - Stoplight('domain-blank') - end - end -end diff --git a/app/workers/import_worker.rb b/app/workers/import_worker.rb deleted file mode 100644 index b6afb972a9..0000000000 --- a/app/workers/import_worker.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This is a deprecated worker, only kept to not break ongoing imports -# on upgrade. See `ImportWorker` for its replacement. - -class ImportWorker - include Sidekiq::Worker - - sidekiq_options queue: 'pull', retry: false - - def perform(import_id) - import = Import.find(import_id) - ImportService.new.call(import) - ensure - import&.destroy - end -end diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index ed16d50a76..6d908fa477 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -169,7 +169,7 @@ else end Rails.application.reloader.to_prepare do - Paperclip.options[:content_type_mappings] = { csv: Import::FILE_TYPES } + Paperclip.options[:content_type_mappings] = { csv: %w(text/plain text/csv application/csv) } end # In some places in the code, we rescue this exception, but we don't always diff --git a/db/migrate/20250410144908_drop_imports.rb b/db/migrate/20250410144908_drop_imports.rb new file mode 100644 index 0000000000..7be9daf750 --- /dev/null +++ b/db/migrate/20250410144908_drop_imports.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class DropImports < ActiveRecord::Migration[7.1] + def up + drop_table :imports + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/schema.rb b/db/schema.rb index 26db259464..b09360ff43 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_03_13_123400) do +ActiveRecord::Schema[8.0].define(version: 2025_04_10_144908) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -555,19 +555,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_13_123400) do t.index ["user_id"], name: "index_identities_on_user_id" end - create_table "imports", force: :cascade do |t| - t.integer "type", null: false - t.boolean "approved", default: false, null: false - t.datetime "created_at", precision: nil, null: false - t.datetime "updated_at", precision: nil, null: false - t.string "data_file_name" - t.string "data_content_type" - t.integer "data_file_size" - t.datetime "data_updated_at", precision: nil - t.bigint "account_id", null: false - t.boolean "overwrite", default: false, null: false - end - create_table "invites", force: :cascade do |t| t.bigint "user_id", null: false t.string "code", default: "", null: false @@ -1329,7 +1316,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_13_123400) do add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade add_foreign_key "generated_annual_reports", "accounts" add_foreign_key "identities", "users", name: "fk_bea040f377", on_delete: :cascade - add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade add_foreign_key "invites", "users", on_delete: :cascade add_foreign_key "list_accounts", "accounts", on_delete: :cascade add_foreign_key "list_accounts", "follow_requests", on_delete: :cascade diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index 84ec13eaab..1059eb6066 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -293,7 +293,6 @@ module Mastodon::CLI Account Backup CustomEmoji - Import MediaAttachment PreviewCard SiteUpload @@ -309,7 +308,6 @@ module Mastodon::CLI [:headers, Account.sum(:header_file_size), Account.local.sum(:header_file_size)], [:preview_cards, PreviewCard.sum(:image_file_size), nil], [:backups, Backup.sum(:dump_file_size), nil], - [:imports, Import.sum(:data_file_size), nil], [:settings, SiteUpload.sum(:file_file_size), nil], ].map { |label, total, local| [label.to_s.titleize, number_to_human_size(total), local.present? ? number_to_human_size(local) : nil] } end diff --git a/spec/fabricators/import_fabricator.rb b/spec/fabricators/import_fabricator.rb deleted file mode 100644 index 4951bb9a4d..0000000000 --- a/spec/fabricators/import_fabricator.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -Fabricator(:import) do - account - type :following - data { attachment_fixture('imports.txt') } -end diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb deleted file mode 100644 index 587e0a9d26..0000000000 --- a/spec/models/import_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Import do - describe 'Validations' do - it { is_expected.to validate_presence_of(:type) } - it { is_expected.to validate_presence_of(:data) } - end -end diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb deleted file mode 100644 index 2e1358c635..0000000000 --- a/spec/services/import_service_spec.rb +++ /dev/null @@ -1,242 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ImportService, :inline_jobs do - include RoutingHelper - - let!(:account) { Fabricate(:account, locked: false) } - let!(:bob) { Fabricate(:account, username: 'bob', locked: false) } - let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false, protocol: :activitypub, inbox_url: 'https://example.com/inbox') } - - before do - stub_request(:post, 'https://example.com/inbox').to_return(status: 200) - end - - context 'when importing old-style list of muted users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('mute-imports.txt') } - - describe 'when no accounts are muted' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, including notifications' do - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - - describe 'when some accounts are muted and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, including notifications' do - account.mute!(bob, notifications: false) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - - describe 'when some accounts are muted and overwrite is set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) } - - it 'mutes the listed accounts, including notifications' do - account.mute!(bob, notifications: false) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - end - - context 'when importing new-style list of muted users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('new-mute-imports.txt') } - - describe 'when no accounts are muted' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - - describe 'when some accounts are muted and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - account.mute!(bob, notifications: true) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - - describe 'when some accounts are muted and overwrite is set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) } - - it 'mutes the listed accounts, respecting notifications' do - account.mute!(bob, notifications: true) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - end - - context 'when importing old-style list of followed users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('mute-imports.txt') } - - describe 'when no accounts are followed' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, including boosts' do - subject.call(import) - - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - - describe 'when some accounts are already followed and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, including notifications' do - account.follow!(bob, reblogs: false) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - - describe 'when some accounts are already followed and overwrite is set' do - let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) } - - it 'mutes the listed accounts, including notifications' do - account.follow!(bob, reblogs: false) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - end - - context 'when importing new-style list of followed users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('new-following-imports.txt') } - - describe 'when no accounts are followed' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, respecting boosts' do - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - - describe 'when some accounts are already followed and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - account.follow!(bob, reblogs: true) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - - describe 'when some accounts are already followed and overwrite is set' do - let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) } - - it 'mutes the listed accounts, respecting notifications' do - account.follow!(bob, reblogs: true) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - end - - # Based on the bug report 20571 where UTF-8 encoded domains were rejecting import of their users - # - # https://github.com/mastodon/mastodon/issues/20571 - context 'with a utf-8 encoded domains' do - subject { described_class.new } - - let!(:nare) { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') } - let(:csv) { attachment_fixture('utf8-followers.txt') } - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - # Make sure to not actually go to the remote server - before do - stub_request(:post, nare.inbox_url).to_return(status: 200) - end - - it 'follows the listed account' do - expect(account.follow_requests.count).to eq 0 - subject.call(import) - expect(account.follow_requests.count).to eq 1 - end - end - - context 'when importing bookmarks' do - subject { described_class.new } - - let(:csv) { attachment_fixture('bookmark-imports.txt') } - let(:local_account) { Fabricate(:account, username: 'foo', domain: nil) } - let!(:remote_status) { Fabricate(:status, uri: 'https://example.com/statuses/1312') } - let!(:direct_status) { Fabricate(:status, uri: 'https://example.com/statuses/direct', visibility: :direct) } - - around do |example| - local_before = Rails.configuration.x.local_domain - web_before = Rails.configuration.x.web_domain - Rails.configuration.x.local_domain = 'local.com' - Rails.configuration.x.web_domain = 'local.com' - example.run - Rails.configuration.x.web_domain = web_before - Rails.configuration.x.local_domain = local_before - end - - before do - service = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('https://unknown-remote.com/users/bar/statuses/1') do - Fabricate(:status, uri: 'https://unknown-remote.com/users/bar/statuses/1') - end - end - - describe 'when no bookmarks are set' do - let(:import) { Import.create(account: account, type: 'bookmarks', data: csv) } - - it 'adds the toots the user has access to to bookmarks' do - local_status = Fabricate(:status, account: local_account, uri: 'https://local.com/users/foo/statuses/42', id: 42, local: true) - subject.call(import) - expect(account.bookmarks.map { |bookmark| bookmark.status.id }).to include(local_status.id) - expect(account.bookmarks.map { |bookmark| bookmark.status.id }).to include(remote_status.id) - expect(account.bookmarks.map { |bookmark| bookmark.status.id }).to_not include(direct_status.id) - expect(account.bookmarks.count).to eq 3 - end - end - end -end diff --git a/spec/workers/import_worker_spec.rb b/spec/workers/import_worker_spec.rb deleted file mode 100644 index 1d34aafe86..0000000000 --- a/spec/workers/import_worker_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ImportWorker do - let(:worker) { described_class.new } - let(:service) { instance_double(ImportService, call: true) } - - describe '#perform' do - before do - allow(ImportService).to receive(:new).and_return(service) - end - - let(:import) { Fabricate(:import) } - - it 'sends the import to the service' do - worker.perform(import.id) - - expect(service).to have_received(:call).with(import) - expect { import.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end -end From de19af36500365ecb5993a456b56188da1c7c03e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 10 Apr 2025 09:51:17 -0400 Subject: [PATCH 35/48] Extract `frontend_translations` helper to support module (#34400) --- spec/support/system_helpers.rb | 6 ++++++ spec/system/account_notes_spec.rb | 2 +- spec/system/log_out_spec.rb | 12 ++++++++---- spec/system/new_statuses_spec.rb | 15 +-------------- spec/system/share_entrypoint_spec.rb | 16 +++------------- 5 files changed, 19 insertions(+), 32 deletions(-) diff --git a/spec/support/system_helpers.rb b/spec/support/system_helpers.rb index ffbba177b3..44bbc64a59 100644 --- a/spec/support/system_helpers.rb +++ b/spec/support/system_helpers.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module SystemHelpers + FRONTEND_TRANSLATIONS = JSON.parse Rails.root.join('app', 'javascript', 'mastodon', 'locales', 'en.json').read + def submit_button I18n.t('generic.save_changes') end @@ -16,4 +18,8 @@ module SystemHelpers def css_id(record) "##{dom_id(record)}" end + + def frontend_translations(key) + FRONTEND_TRANSLATIONS[key] + end end diff --git a/spec/system/account_notes_spec.rb b/spec/system/account_notes_spec.rb index c4054f204e..1d125e1984 100644 --- a/spec/system/account_notes_spec.rb +++ b/spec/system/account_notes_spec.rb @@ -18,7 +18,7 @@ RSpec.describe 'Account notes', :inline_jobs, :js, :streaming do visit_profile(other_account) note_text = 'This is a personal note' - fill_in 'Click to add note', with: note_text + fill_in frontend_translations('account_note.placeholder'), with: note_text # This is a bit awkward since there is no button to save the change # The easiest way is to send ctrl+enter ourselves diff --git a/spec/system/log_out_spec.rb b/spec/system/log_out_spec.rb index 2e52254ca0..ebbf5a5772 100644 --- a/spec/system/log_out_spec.rb +++ b/spec/system/log_out_spec.rb @@ -17,8 +17,9 @@ RSpec.describe 'Log out' do click_on 'Logout' end - expect(page).to have_title(I18n.t('auth.login')) - expect(page).to have_current_path('/auth/sign_in') + expect(page) + .to have_title(I18n.t('auth.login')) + .and have_current_path('/auth/sign_in') end end @@ -28,6 +29,8 @@ RSpec.describe 'Log out' do ignore_js_error(/Failed to load resource: the server responded with a status of 422/) visit root_path + expect(page) + .to have_css('body', class: 'app-body') within '.navigation-bar' do click_on 'Menu' @@ -39,8 +42,9 @@ RSpec.describe 'Log out' do click_on 'Log out' - expect(page).to have_title(I18n.t('auth.login')) - expect(page).to have_current_path('/auth/sign_in') + expect(page) + .to have_title(I18n.t('auth.login')) + .and have_current_path('/auth/sign_in') end end end diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb index 480c77cf87..d14bcc0058 100644 --- a/spec/system/new_statuses_spec.rb +++ b/spec/system/new_statuses_spec.rb @@ -17,20 +17,7 @@ RSpec.describe 'NewStatuses', :inline_jobs, :js, :streaming do status_text = 'This is a new status!' within('.compose-form') do - fill_in "What's on your mind?", with: status_text - click_on 'Post' - end - - expect(page) - .to have_css('.status__content__text', text: status_text) - end - - it 'can be posted again' do - visit_homepage - status_text = 'This is a second status!' - - within('.compose-form') do - fill_in "What's on your mind?", with: status_text + fill_in frontend_translations('compose_form.placeholder'), with: status_text click_on 'Post' end diff --git a/spec/system/share_entrypoint_spec.rb b/spec/system/share_entrypoint_spec.rb index 7ccfee599a..b55ea31657 100644 --- a/spec/system/share_entrypoint_spec.rb +++ b/spec/system/share_entrypoint_spec.rb @@ -23,24 +23,14 @@ RSpec.describe 'Share page', :js, :streaming do fill_in_form expect(page) - .to have_css('.notification-bar-message', text: translations['compose.published.body']) + .to have_css('.notification-bar-message', text: frontend_translations('compose.published.body')) end def fill_in_form within('.compose-form') do - fill_in translations['compose_form.placeholder'], + fill_in frontend_translations('compose_form.placeholder'), with: 'This is a new status!' - click_on translations['compose_form.publish'] + click_on frontend_translations('compose_form.publish') end end - - def translations - # TODO: Extract to system spec helper for re-use? - JSON.parse( - Rails - .root - .join('app', 'javascript', 'mastodon', 'locales', 'en.json') - .read - ) - end end From 5d817a758d0d16924364489092f661b82451e1c9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 10 Apr 2025 16:02:52 +0200 Subject: [PATCH 36/48] Add dropdown to lists of accounts in web UI (#34391) --- .../mastodon/components/account.tsx | 176 +++++++++++------- 1 file changed, 107 insertions(+), 69 deletions(-) diff --git a/app/javascript/mastodon/components/account.tsx b/app/javascript/mastodon/components/account.tsx index 55f1e6fb91..f6241504f6 100644 --- a/app/javascript/mastodon/components/account.tsx +++ b/app/javascript/mastodon/components/account.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; @@ -12,6 +12,7 @@ import { muteAccount, unmuteAccount, } from 'mastodon/actions/accounts'; +import { openModal } from 'mastodon/actions/modal'; import { initMuteModal } from 'mastodon/actions/mutes'; import { Avatar } from 'mastodon/components/avatar'; import { Button } from 'mastodon/components/button'; @@ -23,7 +24,7 @@ import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import { ShortNumber } from 'mastodon/components/short_number'; import { Skeleton } from 'mastodon/components/skeleton'; import { VerifiedBadge } from 'mastodon/components/verified_badge'; -import { me } from 'mastodon/initial_state'; +import type { MenuItem } from 'mastodon/models/dropdown_menu'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; const messages = defineMessages({ @@ -46,6 +47,14 @@ const messages = defineMessages({ mute: { id: 'account.mute_short', defaultMessage: 'Mute' }, block: { id: 'account.block_short', defaultMessage: 'Block' }, more: { id: 'status.more', defaultMessage: 'More' }, + addToLists: { + id: 'account.add_or_remove_from_list', + defaultMessage: 'Add or Remove from lists', + }, + openOriginalPage: { + id: 'account.open_original_page', + defaultMessage: 'Open original page', + }, }); export const Account: React.FC<{ @@ -60,6 +69,7 @@ export const Account: React.FC<{ const account = useAppSelector((state) => state.accounts.get(id)); const relationship = useAppSelector((state) => state.relationships.get(id)); const dispatch = useAppDispatch(); + const accountUrl = account?.url; const handleBlock = useCallback(() => { if (relationship?.blocking) { @@ -77,13 +87,62 @@ export const Account: React.FC<{ } }, [dispatch, id, account, relationship]); - const handleMuteNotifications = useCallback(() => { - dispatch(muteAccount(id, true)); - }, [dispatch, id]); + const menu = useMemo(() => { + let arr: MenuItem[] = []; - const handleUnmuteNotifications = useCallback(() => { - dispatch(muteAccount(id, false)); - }, [dispatch, id]); + if (defaultAction === 'mute') { + const handleMuteNotifications = () => { + dispatch(muteAccount(id, true)); + }; + + const handleUnmuteNotifications = () => { + dispatch(muteAccount(id, false)); + }; + + arr = [ + { + text: intl.formatMessage( + relationship?.muting_notifications + ? messages.unmute_notifications + : messages.mute_notifications, + ), + action: relationship?.muting_notifications + ? handleUnmuteNotifications + : handleMuteNotifications, + }, + ]; + } else if (defaultAction !== 'block') { + const handleAddToLists = () => { + dispatch( + openModal({ + modalType: 'LIST_ADDER', + modalProps: { + accountId: id, + }, + }), + ); + }; + + arr = [ + { + text: intl.formatMessage(messages.addToLists), + action: handleAddToLists, + }, + ]; + + if (accountUrl) { + arr.unshift( + { + text: intl.formatMessage(messages.openOriginalPage), + href: accountUrl, + }, + null, + ); + } + } + + return arr; + }, [dispatch, intl, id, accountUrl, relationship, defaultAction]); if (hidden) { return ( @@ -94,68 +153,42 @@ export const Account: React.FC<{ ); } - let buttons; + let button: React.ReactNode, dropdown: React.ReactNode; - if (account && account.id !== me && relationship) { - const { requested, blocking, muting } = relationship; - - if (requested) { - buttons = ; - } else if (blocking) { - buttons = ( -
    - {!minimal &&
    {buttons}
    } + {!minimal && ( +
    + {dropdown} + {button} +
    + )} {account && From 678c8dfeec2c221cf609b924161dc03cebfa41e1 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 10 Apr 2025 16:34:27 +0200 Subject: [PATCH 37/48] Refactor `StatusCacheHydrator` (#34414) --- app/lib/status_cache_hydrator.rb | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/lib/status_cache_hydrator.rb b/app/lib/status_cache_hydrator.rb index 34f6199ec0..676e9e62a0 100644 --- a/app/lib/status_cache_hydrator.rb +++ b/app/lib/status_cache_hydrator.rb @@ -26,12 +26,7 @@ class StatusCacheHydrator def hydrate_non_reblog_payload(empty_payload, account_id) empty_payload.tap do |payload| - payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.id) - payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.id) - payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.conversation_id) - payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.id) - payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.id) if @status.account_id == account_id - payload[:filtered] = mapped_applied_custom_filter(account_id, @status) + fill_status_payload(payload, @status, account_id) if payload[:poll] payload[:poll][:voted] = @status.account_id == account_id @@ -45,18 +40,12 @@ class StatusCacheHydrator payload[:muted] = false payload[:bookmarked] = false payload[:pinned] = false if @status.account_id == account_id - payload[:filtered] = mapped_applied_custom_filter(account_id, @status.reblog) # If the reblogged status is being delivered to the author who disabled the display of the application # used to create the status, we need to hydrate it here too payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id - payload[:reblog][:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.reblog_of_id) - payload[:reblog][:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.reblog_of_id) - payload[:reblog][:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.reblog.conversation_id) - payload[:reblog][:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.reblog_of_id) - payload[:reblog][:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.reblog_of_id) if @status.reblog.account_id == account_id - payload[:reblog][:filtered] = payload[:filtered] + fill_status_payload(payload[:reblog], @status.reblog, account_id) if payload[:reblog][:poll] if @status.reblog.account_id == account_id @@ -69,11 +58,21 @@ class StatusCacheHydrator end end + payload[:filtered] = payload[:reblog][:filtered] payload[:favourited] = payload[:reblog][:favourited] payload[:reblogged] = payload[:reblog][:reblogged] end end + def fill_status_payload(payload, status, account_id) + payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: status.id) + payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: status.id) + payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: status.conversation_id) + payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: status.id) + payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: status.id) if status.account_id == account_id + payload[:filtered] = mapped_applied_custom_filter(account_id, status) + end + def mapped_applied_custom_filter(account_id, status) CustomFilter .apply_cached_filters(CustomFilter.cached_filters_for(account_id), status) From d43bfa95aab836a12de5df4f302c820417610bac Mon Sep 17 00:00:00 2001 From: Echo Date: Thu, 10 Apr 2025 17:40:30 +0200 Subject: [PATCH 38/48] Adds featured tab to web (#34405) --- .../mastodon/components/hashtag.tsx | 2 +- .../mastodon/components/navigation_portal.tsx | 21 +-- .../mastodon/components/remote_hint.tsx | 43 +++++ .../account/components/featured_tags.jsx | 51 ------ .../containers/featured_tags_container.js | 17 -- .../mastodon/features/account/navigation.jsx | 52 ------ .../components/empty_message.tsx | 50 ++++++ .../components/featured_tag.tsx | 51 ++++++ .../features/account_featured/index.tsx | 156 ++++++++++++++++++ .../features/account_gallery/index.tsx | 81 +-------- .../components/account_header.tsx | 3 + .../features/account_timeline/index.jsx | 34 +--- app/javascript/mastodon/features/ui/index.jsx | 2 + .../features/ui/util/async-components.js | 4 + app/javascript/mastodon/hooks/useAccountId.ts | 37 +++++ .../mastodon/hooks/useAccountVisibility.ts | 20 +++ app/javascript/mastodon/locales/en.json | 5 +- config/routes.rb | 1 + 18 files changed, 385 insertions(+), 245 deletions(-) create mode 100644 app/javascript/mastodon/components/remote_hint.tsx delete mode 100644 app/javascript/mastodon/features/account/components/featured_tags.jsx delete mode 100644 app/javascript/mastodon/features/account/containers/featured_tags_container.js delete mode 100644 app/javascript/mastodon/features/account/navigation.jsx create mode 100644 app/javascript/mastodon/features/account_featured/components/empty_message.tsx create mode 100644 app/javascript/mastodon/features/account_featured/components/featured_tag.tsx create mode 100644 app/javascript/mastodon/features/account_featured/index.tsx create mode 100644 app/javascript/mastodon/hooks/useAccountId.ts create mode 100644 app/javascript/mastodon/hooks/useAccountVisibility.ts diff --git a/app/javascript/mastodon/components/hashtag.tsx b/app/javascript/mastodon/components/hashtag.tsx index 1fe41e1e8b..346c95183f 100644 --- a/app/javascript/mastodon/components/hashtag.tsx +++ b/app/javascript/mastodon/components/hashtag.tsx @@ -102,7 +102,7 @@ export interface HashtagProps { description?: React.ReactNode; history?: number[]; name: string; - people: number; + people?: number; to: string; uses?: number; withGraph?: boolean; diff --git a/app/javascript/mastodon/components/navigation_portal.tsx b/app/javascript/mastodon/components/navigation_portal.tsx index 08f91ce18a..d3ac8baa6e 100644 --- a/app/javascript/mastodon/components/navigation_portal.tsx +++ b/app/javascript/mastodon/components/navigation_portal.tsx @@ -1,25 +1,6 @@ -import { Switch, Route } from 'react-router-dom'; - -import AccountNavigation from 'mastodon/features/account/navigation'; import Trends from 'mastodon/features/getting_started/containers/trends_container'; import { showTrends } from 'mastodon/initial_state'; -const DefaultNavigation: React.FC = () => (showTrends ? : null); - export const NavigationPortal: React.FC = () => ( -
    - - - - - - - - - -
    +
    {showTrends && }
    ); diff --git a/app/javascript/mastodon/components/remote_hint.tsx b/app/javascript/mastodon/components/remote_hint.tsx new file mode 100644 index 0000000000..772aa805db --- /dev/null +++ b/app/javascript/mastodon/components/remote_hint.tsx @@ -0,0 +1,43 @@ +import { FormattedMessage } from 'react-intl'; + +import { useAppSelector } from 'mastodon/store'; + +import { TimelineHint } from './timeline_hint'; + +interface RemoteHintProps { + accountId?: string; +} + +export const RemoteHint: React.FC = ({ accountId }) => { + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); + const domain = account?.acct ? account.acct.split('@')[1] : undefined; + if ( + !account || + !account.url || + account.acct !== account.username || + !domain + ) { + return null; + } + + return ( + + } + label={ + {domain} }} + /> + } + /> + ); +}; diff --git a/app/javascript/mastodon/features/account/components/featured_tags.jsx b/app/javascript/mastodon/features/account/components/featured_tags.jsx deleted file mode 100644 index 56a9efac02..0000000000 --- a/app/javascript/mastodon/features/account/components/featured_tags.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import PropTypes from 'prop-types'; - -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; - -import { Hashtag } from 'mastodon/components/hashtag'; - -const messages = defineMessages({ - lastStatusAt: { id: 'account.featured_tags.last_status_at', defaultMessage: 'Last post on {date}' }, - empty: { id: 'account.featured_tags.last_status_never', defaultMessage: 'No posts' }, -}); - -class FeaturedTags extends ImmutablePureComponent { - - static propTypes = { - account: ImmutablePropTypes.record, - featuredTags: ImmutablePropTypes.list, - tagged: PropTypes.string, - intl: PropTypes.object.isRequired, - }; - - render () { - const { account, featuredTags, intl } = this.props; - - if (!account || account.get('suspended') || featuredTags.isEmpty()) { - return null; - } - - return ( -
    -

    }} />

    - - {featuredTags.take(3).map(featuredTag => ( - 0) ? intl.formatMessage(messages.lastStatusAt, { date: intl.formatDate(featuredTag.get('last_status_at'), { month: 'short', day: '2-digit' }) }) : intl.formatMessage(messages.empty)} - /> - ))} -
    - ); - } - -} - -export default injectIntl(FeaturedTags); diff --git a/app/javascript/mastodon/features/account/containers/featured_tags_container.js b/app/javascript/mastodon/features/account/containers/featured_tags_container.js deleted file mode 100644 index 726c805f78..0000000000 --- a/app/javascript/mastodon/features/account/containers/featured_tags_container.js +++ /dev/null @@ -1,17 +0,0 @@ -import { List as ImmutableList } from 'immutable'; -import { connect } from 'react-redux'; - -import { makeGetAccount } from 'mastodon/selectors'; - -import FeaturedTags from '../components/featured_tags'; - -const mapStateToProps = () => { - const getAccount = makeGetAccount(); - - return (state, { accountId }) => ({ - account: getAccount(state, accountId), - featuredTags: state.getIn(['user_lists', 'featured_tags', accountId, 'items'], ImmutableList()), - }); -}; - -export default connect(mapStateToProps)(FeaturedTags); diff --git a/app/javascript/mastodon/features/account/navigation.jsx b/app/javascript/mastodon/features/account/navigation.jsx deleted file mode 100644 index aa78135de2..0000000000 --- a/app/javascript/mastodon/features/account/navigation.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { connect } from 'react-redux'; - -import FeaturedTags from 'mastodon/features/account/containers/featured_tags_container'; -import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; - -const mapStateToProps = (state, { match: { params: { acct } } }) => { - const accountId = state.getIn(['accounts_map', normalizeForLookup(acct)]); - - if (!accountId) { - return { - isLoading: true, - }; - } - - return { - accountId, - isLoading: false, - }; -}; - -class AccountNavigation extends PureComponent { - - static propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - acct: PropTypes.string, - tagged: PropTypes.string, - }).isRequired, - }).isRequired, - - accountId: PropTypes.string, - isLoading: PropTypes.bool, - }; - - render () { - const { accountId, isLoading, match: { params: { tagged } } } = this.props; - - if (isLoading) { - return null; - } - - return ( - - ); - } - -} - -export default connect(mapStateToProps)(AccountNavigation); diff --git a/app/javascript/mastodon/features/account_featured/components/empty_message.tsx b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx new file mode 100644 index 0000000000..9dd8ffdfe0 --- /dev/null +++ b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx @@ -0,0 +1,50 @@ +import { FormattedMessage } from 'react-intl'; + +import { LimitedAccountHint } from 'mastodon/features/account_timeline/components/limited_account_hint'; + +interface EmptyMessageProps { + suspended: boolean; + hidden: boolean; + blockedBy: boolean; + accountId?: string; +} + +export const EmptyMessage: React.FC = ({ + accountId, + suspended, + hidden, + blockedBy, +}) => { + if (!accountId) { + return null; + } + + let message: React.ReactNode = null; + + if (suspended) { + message = ( + + ); + } else if (hidden) { + message = ; + } else if (blockedBy) { + message = ( + + ); + } else { + message = ( + + ); + } + + return
    {message}
    ; +}; diff --git a/app/javascript/mastodon/features/account_featured/components/featured_tag.tsx b/app/javascript/mastodon/features/account_featured/components/featured_tag.tsx new file mode 100644 index 0000000000..7b476ba01d --- /dev/null +++ b/app/javascript/mastodon/features/account_featured/components/featured_tag.tsx @@ -0,0 +1,51 @@ +import { defineMessages, useIntl } from 'react-intl'; + +import type { Map as ImmutableMap } from 'immutable'; + +import { Hashtag } from 'mastodon/components/hashtag'; + +export type TagMap = ImmutableMap< + 'id' | 'name' | 'url' | 'statuses_count' | 'last_status_at' | 'accountId', + string | null +>; + +interface FeaturedTagProps { + tag: TagMap; + account: string; +} + +const messages = defineMessages({ + lastStatusAt: { + id: 'account.featured_tags.last_status_at', + defaultMessage: 'Last post on {date}', + }, + empty: { + id: 'account.featured_tags.last_status_never', + defaultMessage: 'No posts', + }, +}); + +export const FeaturedTag: React.FC = ({ tag, account }) => { + const intl = useIntl(); + const name = tag.get('name') ?? ''; + const count = Number.parseInt(tag.get('statuses_count') ?? ''); + return ( + 0 + ? intl.formatMessage(messages.lastStatusAt, { + date: intl.formatDate(tag.get('last_status_at') ?? '', { + month: 'short', + day: '2-digit', + }), + }) + : intl.formatMessage(messages.empty) + } + /> + ); +}; diff --git a/app/javascript/mastodon/features/account_featured/index.tsx b/app/javascript/mastodon/features/account_featured/index.tsx new file mode 100644 index 0000000000..70e411f61a --- /dev/null +++ b/app/javascript/mastodon/features/account_featured/index.tsx @@ -0,0 +1,156 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { useParams } from 'react-router'; + +import type { Map as ImmutableMap } from 'immutable'; +import { List as ImmutableList } from 'immutable'; + +import { fetchFeaturedTags } from 'mastodon/actions/featured_tags'; +import { expandAccountFeaturedTimeline } from 'mastodon/actions/timelines'; +import { ColumnBackButton } from 'mastodon/components/column_back_button'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; +import { RemoteHint } from 'mastodon/components/remote_hint'; +import StatusContainer from 'mastodon/containers/status_container'; +import { useAccountId } from 'mastodon/hooks/useAccountId'; +import { useAccountVisibility } from 'mastodon/hooks/useAccountVisibility'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +import { AccountHeader } from '../account_timeline/components/account_header'; +import Column from '../ui/components/column'; + +import { EmptyMessage } from './components/empty_message'; +import { FeaturedTag } from './components/featured_tag'; +import type { TagMap } from './components/featured_tag'; + +interface Params { + acct?: string; + id?: string; +} + +const AccountFeatured = () => { + const accountId = useAccountId(); + const { suspended, blockedBy, hidden } = useAccountVisibility(accountId); + const forceEmptyState = suspended || blockedBy || hidden; + const { acct = '' } = useParams(); + + const dispatch = useAppDispatch(); + + useEffect(() => { + if (accountId) { + void dispatch(expandAccountFeaturedTimeline(accountId)); + dispatch(fetchFeaturedTags(accountId)); + } + }, [accountId, dispatch]); + + const isLoading = useAppSelector( + (state) => + !accountId || + !!(state.timelines as ImmutableMap).getIn([ + `account:${accountId}:pinned`, + 'isLoading', + ]) || + !!state.user_lists.getIn(['featured_tags', accountId, 'isLoading']), + ); + const featuredTags = useAppSelector( + (state) => + state.user_lists.getIn( + ['featured_tags', accountId, 'items'], + ImmutableList(), + ) as ImmutableList, + ); + const featuredStatusIds = useAppSelector( + (state) => + (state.timelines as ImmutableMap).getIn( + [`account:${accountId}:pinned`, 'items'], + ImmutableList(), + ) as ImmutableList, + ); + + if (isLoading) { + return ( + +
    + +
    +
    + ); + } + + if (featuredStatusIds.isEmpty() && featuredTags.isEmpty()) { + return ( + + + ); + } + + return ( + + + +
    + {accountId && ( + + )} + {!featuredTags.isEmpty() && ( + <> +

    + +

    + {featuredTags.map((tag) => ( + + ))} + + )} + {!featuredStatusIds.isEmpty() && ( + <> +

    + +

    + {featuredStatusIds.map((statusId) => ( + + ))} + + )} + +
    +
    + ); +}; + +const AccountFeaturedWrapper = ({ + children, + accountId, +}: React.PropsWithChildren<{ accountId?: string }>) => { + return ( + + +
    + {accountId && } + {children} +
    +
    + ); +}; + +// eslint-disable-next-line import/no-default-export +export default AccountFeatured; diff --git a/app/javascript/mastodon/features/account_gallery/index.tsx b/app/javascript/mastodon/features/account_gallery/index.tsx index 60afdadc81..0027329c93 100644 --- a/app/javascript/mastodon/features/account_gallery/index.tsx +++ b/app/javascript/mastodon/features/account_gallery/index.tsx @@ -2,25 +2,22 @@ import { useEffect, useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import { useParams } from 'react-router-dom'; - import { createSelector } from '@reduxjs/toolkit'; import type { Map as ImmutableMap } from 'immutable'; import { List as ImmutableList } from 'immutable'; -import { lookupAccount, fetchAccount } from 'mastodon/actions/accounts'; import { openModal } from 'mastodon/actions/modal'; import { expandAccountMediaTimeline } from 'mastodon/actions/timelines'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; +import { RemoteHint } from 'mastodon/components/remote_hint'; import ScrollableList from 'mastodon/components/scrollable_list'; -import { TimelineHint } from 'mastodon/components/timeline_hint'; import { AccountHeader } from 'mastodon/features/account_timeline/components/account_header'; import { LimitedAccountHint } from 'mastodon/features/account_timeline/components/limited_account_hint'; import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; import Column from 'mastodon/features/ui/components/column'; +import { useAccountId } from 'mastodon/hooks/useAccountId'; +import { useAccountVisibility } from 'mastodon/hooks/useAccountVisibility'; import type { MediaAttachment } from 'mastodon/models/media_attachment'; -import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; -import { getAccountHidden } from 'mastodon/selectors/accounts'; import type { RootState } from 'mastodon/store'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; @@ -56,53 +53,11 @@ const getAccountGallery = createSelector( }, ); -interface Params { - acct?: string; - id?: string; -} - -const RemoteHint: React.FC<{ - accountId: string; -}> = ({ accountId }) => { - const account = useAppSelector((state) => state.accounts.get(accountId)); - const acct = account?.acct; - const url = account?.url; - const domain = acct ? acct.split('@')[1] : undefined; - - if (!url) { - return null; - } - - return ( - - } - label={ - {domain} }} - /> - } - /> - ); -}; - export const AccountGallery: React.FC<{ multiColumn: boolean; }> = ({ multiColumn }) => { - const { acct, id } = useParams(); const dispatch = useAppDispatch(); - const accountId = useAppSelector( - (state) => - id ?? - (state.accounts_map.get(normalizeForLookup(acct)) as string | undefined), - ); + const accountId = useAccountId(); const attachments = useAppSelector((state) => accountId ? getAccountGallery(state, accountId) @@ -123,33 +78,15 @@ export const AccountGallery: React.FC<{ const account = useAppSelector((state) => accountId ? state.accounts.get(accountId) : undefined, ); - const blockedBy = useAppSelector( - (state) => - state.relationships.getIn([accountId, 'blocked_by'], false) as boolean, - ); - const suspended = useAppSelector( - (state) => state.accounts.getIn([accountId, 'suspended'], false) as boolean, - ); const isAccount = !!account; - const remote = account?.acct !== account?.username; - const hidden = useAppSelector((state) => - accountId ? getAccountHidden(state, accountId) : false, - ); + + const { suspended, blockedBy, hidden } = useAccountVisibility(accountId); + const maxId = attachments.last()?.getIn(['status', 'id']) as | string | undefined; useEffect(() => { - if (!accountId) { - dispatch(lookupAccount(acct)); - } - }, [dispatch, accountId, acct]); - - useEffect(() => { - if (accountId && !isAccount) { - dispatch(fetchAccount(accountId)); - } - if (accountId && isAccount) { void dispatch(expandAccountMediaTimeline(accountId)); } @@ -233,7 +170,7 @@ export const AccountGallery: React.FC<{ defaultMessage='Profile unavailable' /> ); - } else if (remote && attachments.isEmpty()) { + } else if (attachments.isEmpty()) { emptyMessage = ; } else { emptyMessage = ( @@ -259,7 +196,7 @@ export const AccountGallery: React.FC<{ ) } alwaysPrepend - append={remote && accountId && } + append={accountId && } scrollKey='account_gallery' isLoading={isLoading} hasMore={!forceEmptyState && hasMore} diff --git a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx index ca12834528..c8fb3d2ae7 100644 --- a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx @@ -956,6 +956,9 @@ export const AccountHeader: React.FC<{ {!(hideTabs || hidden) && (
    + + + diff --git a/app/javascript/mastodon/features/account_timeline/index.jsx b/app/javascript/mastodon/features/account_timeline/index.jsx index 886191e668..a5223275b3 100644 --- a/app/javascript/mastodon/features/account_timeline/index.jsx +++ b/app/javascript/mastodon/features/account_timeline/index.jsx @@ -7,12 +7,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { TimelineHint } from 'mastodon/components/timeline_hint'; import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; import { me } from 'mastodon/initial_state'; import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; import { getAccountHidden } from 'mastodon/selectors/accounts'; -import { useAppSelector } from 'mastodon/store'; import { lookupAccount, fetchAccount } from '../../actions/accounts'; import { fetchFeaturedTags } from '../../actions/featured_tags'; @@ -21,6 +19,7 @@ import { ColumnBackButton } from '../../components/column_back_button'; import { LoadingIndicator } from '../../components/loading_indicator'; import StatusList from '../../components/status_list'; import Column from '../ui/components/column'; +import { RemoteHint } from 'mastodon/components/remote_hint'; import { AccountHeader } from './components/account_header'; import { LimitedAccountHint } from './components/limited_account_hint'; @@ -47,11 +46,8 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa return { accountId, - remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])), - remoteUrl: state.getIn(['accounts', accountId, 'url']), isAccount: !!state.getIn(['accounts', accountId]), statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList), - featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'], emptyList), isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']), hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']), suspended: state.getIn(['accounts', accountId, 'suspended'], false), @@ -60,24 +56,6 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa }; }; -const RemoteHint = ({ accountId, url }) => { - const acct = useAppSelector(state => state.accounts.get(accountId)?.acct); - const domain = acct ? acct.split('@')[1] : undefined; - - return ( - } - label={{domain} }} />} - /> - ); -}; - -RemoteHint.propTypes = { - url: PropTypes.string.isRequired, - accountId: PropTypes.string.isRequired, -}; - class AccountTimeline extends ImmutablePureComponent { static propTypes = { @@ -89,7 +67,6 @@ class AccountTimeline extends ImmutablePureComponent { accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, statusIds: ImmutablePropTypes.list, - featuredStatusIds: ImmutablePropTypes.list, isLoading: PropTypes.bool, hasMore: PropTypes.bool, withReplies: PropTypes.bool, @@ -97,8 +74,6 @@ class AccountTimeline extends ImmutablePureComponent { isAccount: PropTypes.bool, suspended: PropTypes.bool, hidden: PropTypes.bool, - remote: PropTypes.bool, - remoteUrl: PropTypes.string, multiColumn: PropTypes.bool, }; @@ -161,7 +136,7 @@ class AccountTimeline extends ImmutablePureComponent { }; render () { - const { accountId, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props; + const { accountId, statusIds, isLoading, hasMore, blockedBy, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props; if (isLoading && statusIds.isEmpty()) { return ( @@ -191,8 +166,6 @@ class AccountTimeline extends ImmutablePureComponent { emptyMessage = ; } - const remoteMessage = remote ? : null; - return ( @@ -200,10 +173,9 @@ class AccountTimeline extends ImmutablePureComponent { } alwaysPrepend - append={remoteMessage} + append={} scrollKey='account_timeline' statusIds={forceEmptyState ? emptyList : statusIds} - featuredStatusIds={featuredStatusIds} isLoading={isLoading} hasMore={!forceEmptyState && hasMore} onLoadMore={this.handleLoadMore} diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index a1cb8212d2..bb9720c17f 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -73,6 +73,7 @@ import { About, PrivacyPolicy, TermsOfService, + AccountFeatured, } from './util/async-components'; import { ColumnsContextProvider } from './util/columns_context'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; @@ -236,6 +237,7 @@ class SwitchingColumnsArea extends PureComponent { + diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 8c3b342778..ec493ae283 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -66,6 +66,10 @@ export function AccountGallery () { return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery'); } +export function AccountFeatured() { + return import(/* webpackChunkName: "features/account_featured" */'../../account_featured'); +} + export function Followers () { return import(/* webpackChunkName: "features/followers" */'../../followers'); } diff --git a/app/javascript/mastodon/hooks/useAccountId.ts b/app/javascript/mastodon/hooks/useAccountId.ts new file mode 100644 index 0000000000..1cc819ca59 --- /dev/null +++ b/app/javascript/mastodon/hooks/useAccountId.ts @@ -0,0 +1,37 @@ +import { useEffect } from 'react'; + +import { useParams } from 'react-router'; + +import { fetchAccount, lookupAccount } from 'mastodon/actions/accounts'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +interface Params { + acct?: string; + id?: string; +} + +export function useAccountId() { + const { acct, id } = useParams(); + const accountId = useAppSelector( + (state) => + id ?? + (state.accounts_map.get(normalizeForLookup(acct)) as string | undefined), + ); + + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); + const isAccount = !!account; + + const dispatch = useAppDispatch(); + useEffect(() => { + if (!accountId) { + dispatch(lookupAccount(acct)); + } else if (!isAccount) { + dispatch(fetchAccount(accountId)); + } + }, [dispatch, accountId, acct, isAccount]); + + return accountId; +} diff --git a/app/javascript/mastodon/hooks/useAccountVisibility.ts b/app/javascript/mastodon/hooks/useAccountVisibility.ts new file mode 100644 index 0000000000..55651af5a0 --- /dev/null +++ b/app/javascript/mastodon/hooks/useAccountVisibility.ts @@ -0,0 +1,20 @@ +import { getAccountHidden } from 'mastodon/selectors/accounts'; +import { useAppSelector } from 'mastodon/store'; + +export function useAccountVisibility(accountId?: string) { + const blockedBy = useAppSelector( + (state) => !!state.relationships.getIn([accountId, 'blocked_by'], false), + ); + const suspended = useAppSelector( + (state) => !!state.accounts.getIn([accountId, 'suspended'], false), + ); + const hidden = useAppSelector((state) => + accountId ? Boolean(getAccountHidden(state, accountId)) : false, + ); + + return { + blockedBy, + suspended, + hidden, + }; +} diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index ebd5412cf2..0a0f043b4d 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -27,9 +27,11 @@ "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured": "Featured", + "account.featured.hashtags": "Hashtags", + "account.featured.posts": "Posts", "account.featured_tags.last_status_at": "Last post on {date}", "account.featured_tags.last_status_never": "No posts", - "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.follow_back": "Follow back", "account.followers": "Followers", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_featured": "This list is empty", "empty_column.account_hides_collections": "This user has chosen to not make this information available", "empty_column.account_suspended": "Account suspended", "empty_column.account_timeline": "No posts here!", diff --git a/config/routes.rb b/config/routes.rb index 5b130c517b..2fff44851e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -129,6 +129,7 @@ Rails.application.routes.draw do constraints(username: %r{[^@/.]+}) do with_options to: 'accounts#show' do get '/@:username', as: :short_account + get '/@:username/featured' get '/@:username/with_replies', as: :short_account_with_replies get '/@:username/media', as: :short_account_media get '/@:username/tagged/:tag', as: :short_account_tag From 1d7b45093d4eec197ca8cdb81bda0eeeb70bf95e Mon Sep 17 00:00:00 2001 From: Essem Date: Thu, 10 Apr 2025 23:27:12 -0500 Subject: [PATCH 39/48] Fix notification request screen breaking due to dropdown (#34423) --- .../notifications/components/notification_request.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/notifications/components/notification_request.jsx b/app/javascript/mastodon/features/notifications/components/notification_request.jsx index 9c9365d088..381bb1153f 100644 --- a/app/javascript/mastodon/features/notifications/components/notification_request.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification_request.jsx @@ -105,11 +105,10 @@ export const NotificationRequest = ({ id, accountId, notificationsCount, checked
    -
    From e7537769301d9f5467da2f749d7db460da8b621c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 11 Apr 2025 04:09:40 -0400 Subject: [PATCH 40/48] Fix `Style/HashTransformValues` cop (#34416) --- .rubocop_todo.yml | 8 +------- app/serializers/rest/web_push_subscription_serializer.rb | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f63a3ebf39..c3c41f3c5d 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-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.75.1. +# using RuboCop version 1.75.2. # 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 @@ -58,12 +58,6 @@ Style/FormatStringToken: Style/GuardClause: Enabled: false -# This cop supports unsafe autocorrection (--autocorrect-all). -Style/HashTransformValues: - Exclude: - - 'app/serializers/rest/web_push_subscription_serializer.rb' - - 'app/services/import_service.rb' - # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: diff --git a/app/serializers/rest/web_push_subscription_serializer.rb b/app/serializers/rest/web_push_subscription_serializer.rb index 4cb980bb93..01825a3bb0 100644 --- a/app/serializers/rest/web_push_subscription_serializer.rb +++ b/app/serializers/rest/web_push_subscription_serializer.rb @@ -6,7 +6,7 @@ class REST::WebPushSubscriptionSerializer < ActiveModel::Serializer delegate :standard, to: :object def alerts - (object.data&.dig('alerts') || {}).each_with_object({}) { |(k, v), h| h[k] = ActiveModel::Type::Boolean.new.cast(v) } + (object.data&.dig('alerts') || {}).transform_values { |v| ActiveModel::Type::Boolean.new.cast(v) } end def server_key From 7d50942b362c0758fc5d0cdf86e9c8b7c65dfddf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 08:16:00 +0000 Subject: [PATCH 41/48] New Crowdin Translations (automated) (#34424) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/an.json | 1 - app/javascript/mastodon/locales/ar.json | 1 - app/javascript/mastodon/locales/ast.json | 1 - app/javascript/mastodon/locales/az.json | 1 - app/javascript/mastodon/locales/be.json | 1 - app/javascript/mastodon/locales/bg.json | 1 - app/javascript/mastodon/locales/bn.json | 1 - app/javascript/mastodon/locales/br.json | 1 - app/javascript/mastodon/locales/ca.json | 1 - app/javascript/mastodon/locales/ckb.json | 1 - app/javascript/mastodon/locales/cs.json | 1 - app/javascript/mastodon/locales/cy.json | 5 ++- app/javascript/mastodon/locales/da.json | 5 ++- app/javascript/mastodon/locales/de.json | 5 ++- app/javascript/mastodon/locales/el.json | 1 - app/javascript/mastodon/locales/en-GB.json | 1 - app/javascript/mastodon/locales/eo.json | 4 ++- app/javascript/mastodon/locales/es-AR.json | 5 ++- app/javascript/mastodon/locales/es-MX.json | 5 ++- app/javascript/mastodon/locales/es.json | 5 ++- app/javascript/mastodon/locales/et.json | 1 - app/javascript/mastodon/locales/eu.json | 1 - app/javascript/mastodon/locales/fa.json | 1 - app/javascript/mastodon/locales/fi.json | 4 ++- app/javascript/mastodon/locales/fil.json | 1 - app/javascript/mastodon/locales/fo.json | 5 ++- app/javascript/mastodon/locales/fr-CA.json | 1 - app/javascript/mastodon/locales/fr.json | 1 - app/javascript/mastodon/locales/fy.json | 1 - app/javascript/mastodon/locales/ga.json | 1 - app/javascript/mastodon/locales/gd.json | 1 - app/javascript/mastodon/locales/gl.json | 5 ++- app/javascript/mastodon/locales/he.json | 1 - app/javascript/mastodon/locales/hi.json | 1 - app/javascript/mastodon/locales/hr.json | 1 - app/javascript/mastodon/locales/hu.json | 5 ++- app/javascript/mastodon/locales/ia.json | 1 - app/javascript/mastodon/locales/id.json | 1 - app/javascript/mastodon/locales/ie.json | 1 - app/javascript/mastodon/locales/io.json | 1 - app/javascript/mastodon/locales/is.json | 5 ++- app/javascript/mastodon/locales/it.json | 5 ++- app/javascript/mastodon/locales/ja.json | 1 - app/javascript/mastodon/locales/kk.json | 1 - app/javascript/mastodon/locales/ko.json | 1 - app/javascript/mastodon/locales/ku.json | 1 - app/javascript/mastodon/locales/la.json | 1 - app/javascript/mastodon/locales/lad.json | 1 - app/javascript/mastodon/locales/lt.json | 1 - app/javascript/mastodon/locales/lv.json | 11 +++--- app/javascript/mastodon/locales/mr.json | 1 - app/javascript/mastodon/locales/ms.json | 1 - app/javascript/mastodon/locales/my.json | 1 - app/javascript/mastodon/locales/nan.json | 1 - app/javascript/mastodon/locales/ne.json | 1 - app/javascript/mastodon/locales/nl.json | 5 ++- app/javascript/mastodon/locales/nn.json | 5 ++- app/javascript/mastodon/locales/no.json | 1 - app/javascript/mastodon/locales/oc.json | 1 - app/javascript/mastodon/locales/pl.json | 1 - app/javascript/mastodon/locales/pt-BR.json | 1 - app/javascript/mastodon/locales/pt-PT.json | 1 - app/javascript/mastodon/locales/ro.json | 1 - app/javascript/mastodon/locales/ru.json | 2 +- app/javascript/mastodon/locales/ry.json | 1 - app/javascript/mastodon/locales/sa.json | 1 - app/javascript/mastodon/locales/sc.json | 1 - app/javascript/mastodon/locales/sco.json | 1 - app/javascript/mastodon/locales/sk.json | 1 - app/javascript/mastodon/locales/sl.json | 1 - app/javascript/mastodon/locales/sq.json | 5 ++- app/javascript/mastodon/locales/sr-Latn.json | 1 - app/javascript/mastodon/locales/sr.json | 1 - app/javascript/mastodon/locales/sv.json | 1 - app/javascript/mastodon/locales/th.json | 1 - app/javascript/mastodon/locales/tok.json | 1 - app/javascript/mastodon/locales/tr.json | 5 ++- app/javascript/mastodon/locales/tt.json | 1 - app/javascript/mastodon/locales/uk.json | 5 ++- app/javascript/mastodon/locales/ur.json | 1 - app/javascript/mastodon/locales/uz.json | 1 - app/javascript/mastodon/locales/vi.json | 5 ++- app/javascript/mastodon/locales/zh-CN.json | 1 - app/javascript/mastodon/locales/zh-HK.json | 1 - app/javascript/mastodon/locales/zh-TW.json | 5 ++- config/locales/lv.yml | 38 ++++++++++---------- config/locales/ru.yml | 1 + config/locales/simple_form.lv.yml | 10 +++--- 88 files changed, 110 insertions(+), 113 deletions(-) diff --git a/app/javascript/mastodon/locales/an.json b/app/javascript/mastodon/locales/an.json index 605c86f73e..49b6f41eac 100644 --- a/app/javascript/mastodon/locales/an.json +++ b/app/javascript/mastodon/locales/an.json @@ -25,7 +25,6 @@ "account.endorse": "Amostrar en perfil", "account.featured_tags.last_status_at": "Zaguera publicación lo {date}", "account.featured_tags.last_status_never": "Sin publicacions", - "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Encara no sigue dengún a este usuario.", diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index fc8e559dfc..326dd8fbc5 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -29,7 +29,6 @@ "account.endorse": "أوصِ به على صفحتك الشخصية", "account.featured_tags.last_status_at": "آخر منشور في {date}", "account.featured_tags.last_status_never": "لا توجد رسائل", - "account.featured_tags.title": "وسوم {name} المميَّزة", "account.follow": "متابعة", "account.follow_back": "تابعه بالمثل", "account.followers": "مُتابِعون", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index d43a0276dc..5edce9a4d8 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -27,7 +27,6 @@ "account.enable_notifications": "Avisame cuando @{name} espublice artículos", "account.endorse": "Destacar nel perfil", "account.featured_tags.last_status_never": "Nun hai nenguna publicación", - "account.featured_tags.title": "Etiquetes destacaes de: {name}", "account.follow": "Siguir", "account.follow_back": "Siguir tamién", "account.followers": "Siguidores", diff --git a/app/javascript/mastodon/locales/az.json b/app/javascript/mastodon/locales/az.json index 6a52c706b4..550312f31d 100644 --- a/app/javascript/mastodon/locales/az.json +++ b/app/javascript/mastodon/locales/az.json @@ -29,7 +29,6 @@ "account.endorse": "Profildə seçilmişlərə əlavə et", "account.featured_tags.last_status_at": "Son paylaşım {date} tarixində olub", "account.featured_tags.last_status_never": "Paylaşım yoxdur", - "account.featured_tags.title": "{name} istifadəçisinin seçilmiş heşteqləri", "account.follow": "İzlə", "account.follow_back": "Sən də izlə", "account.followers": "İzləyicilər", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 6c6e10270f..9011fdfd63 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -29,7 +29,6 @@ "account.endorse": "Паказваць у профілі", "account.featured_tags.last_status_at": "Апошні допіс ад {date}", "account.featured_tags.last_status_never": "Няма допісаў", - "account.featured_tags.title": "Тэгі, выбраныя {name}", "account.follow": "Падпісацца", "account.follow_back": "Падпісацца ў адказ", "account.followers": "Падпісчыкі", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index bf5a5b1016..5c032755ff 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -29,7 +29,6 @@ "account.endorse": "Представи в профила", "account.featured_tags.last_status_at": "Последна публикация на {date}", "account.featured_tags.last_status_never": "Няма публикации", - "account.featured_tags.title": "Главни хаштагове на {name}", "account.follow": "Последване", "account.follow_back": "Последване взаимно", "account.followers": "Последователи", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index ed2b06289f..ec0f4eb447 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -29,7 +29,6 @@ "account.endorse": "প্রোফাইলে ফিচার করুন", "account.featured_tags.last_status_at": "{date} এ সর্বশেষ পোস্ট", "account.featured_tags.last_status_never": "কোনো পোস্ট নেই", - "account.featured_tags.title": "{name} এর ফিচার করা Hashtag সমূহ", "account.follow": "অনুসরণ", "account.follow_back": "তাকে অনুসরণ করো", "account.followers": "অনুসরণকারী", diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json index fad38721b0..51e3723d19 100644 --- a/app/javascript/mastodon/locales/br.json +++ b/app/javascript/mastodon/locales/br.json @@ -28,7 +28,6 @@ "account.endorse": "Lakaat war-wel war ar profil", "account.featured_tags.last_status_at": "Toud diwezhañ : {date}", "account.featured_tags.last_status_never": "Embannadur ebet", - "account.featured_tags.title": "Hashtagoù pennañ {name}", "account.follow": "Heuliañ", "account.follow_back": "Heuliañ d'ho tro", "account.followers": "Tud koumanantet", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index a282796a50..d6ebbbc1d8 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -29,7 +29,6 @@ "account.endorse": "Recomana en el perfil", "account.featured_tags.last_status_at": "Darrer tut el {date}", "account.featured_tags.last_status_never": "No hi ha tuts", - "account.featured_tags.title": "etiquetes destacades de {name}", "account.follow": "Segueix", "account.follow_back": "Segueix tu també", "account.followers": "Seguidors", diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json index 765eacd080..31f2dbbc11 100644 --- a/app/javascript/mastodon/locales/ckb.json +++ b/app/javascript/mastodon/locales/ckb.json @@ -28,7 +28,6 @@ "account.endorse": "ناساندن لە پرۆفایل", "account.featured_tags.last_status_at": "دوایین پۆست لە {date}", "account.featured_tags.last_status_never": "هیچ پۆستێک نییە", - "account.featured_tags.title": "هاشتاگە تایبەتەکانی {name}", "account.follow": "بەدواداچوون", "account.follow_back": "فۆڵۆو بکەنەوە", "account.followers": "شوێنکەوتووان", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 503dc7714d..25657f9cbf 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -29,7 +29,6 @@ "account.endorse": "Zvýraznit na profilu", "account.featured_tags.last_status_at": "Poslední příspěvek {date}", "account.featured_tags.last_status_never": "Žádné příspěvky", - "account.featured_tags.title": "Hlavní hashtagy uživatele {name}", "account.follow": "Sledovat", "account.follow_back": "Také sledovat", "account.followers": "Sledující", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 27ecc6e8eb..3bf10be7fb 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -27,9 +27,11 @@ "account.edit_profile": "Golygu proffil", "account.enable_notifications": "Rhowch wybod i fi pan fydd @{name} yn postio", "account.endorse": "Dangos ar fy mhroffil", + "account.featured": "Dethol", + "account.featured.hashtags": "Hashnodau", + "account.featured.posts": "Postiadau", "account.featured_tags.last_status_at": "Y postiad olaf ar {date}", "account.featured_tags.last_status_never": "Dim postiadau", - "account.featured_tags.title": "Prif hashnodau {name}", "account.follow": "Dilyn", "account.follow_back": "Dilyn nôl", "account.followers": "Dilynwyr", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Canlyniadau chwilio", "emoji_button.symbols": "Symbolau", "emoji_button.travel": "Teithio a Llefydd", + "empty_column.account_featured": "Mae'r rhestr hon yn wag", "empty_column.account_hides_collections": "Mae'r defnyddiwr wedi dewis i beidio rhannu'r wybodaeth yma", "empty_column.account_suspended": "Cyfrif wedi'i atal", "empty_column.account_timeline": "Dim postiadau yma!", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index d8695c194c..b72e40eaf7 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -27,9 +27,11 @@ "account.edit_profile": "Redigér profil", "account.enable_notifications": "Advisér mig, når @{name} poster", "account.endorse": "Fremhæv på profil", + "account.featured": "Fremhævet", + "account.featured.hashtags": "Hashtags", + "account.featured.posts": "Indlæg", "account.featured_tags.last_status_at": "Seneste indlæg {date}", "account.featured_tags.last_status_never": "Ingen indlæg", - "account.featured_tags.title": "{name}s fremhævede etiketter", "account.follow": "Følg", "account.follow_back": "Følg tilbage", "account.followers": "Følgere", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Søgeresultater", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Rejser og steder", + "empty_column.account_featured": "Denne liste er tom", "empty_column.account_hides_collections": "Brugeren har valgt ikke at gøre denne information tilgængelig", "empty_column.account_suspended": "Konto suspenderet", "empty_column.account_timeline": "Ingen indlæg her!", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 6a14858d11..943c5ae8b2 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -27,9 +27,11 @@ "account.edit_profile": "Profil bearbeiten", "account.enable_notifications": "Benachrichtige mich wenn @{name} etwas postet", "account.endorse": "Im Profil empfehlen", + "account.featured": "Empfohlen", + "account.featured.hashtags": "Hashtags", + "account.featured.posts": "Beiträge", "account.featured_tags.last_status_at": "Letzter Beitrag am {date}", "account.featured_tags.last_status_never": "Keine Beiträge", - "account.featured_tags.title": "Von {name} vorgestellte Hashtags", "account.follow": "Folgen", "account.follow_back": "Ebenfalls folgen", "account.followers": "Follower", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Suchergebnisse", "emoji_button.symbols": "Symbole", "emoji_button.travel": "Reisen & Orte", + "empty_column.account_featured": "Diese Liste ist leer", "empty_column.account_hides_collections": "Das Konto hat sich dazu entschieden, diese Information nicht zu veröffentlichen", "empty_column.account_suspended": "Konto gesperrt", "empty_column.account_timeline": "Keine Beiträge vorhanden!", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 1918c4371e..0b9e42cbe9 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -29,7 +29,6 @@ "account.endorse": "Προβολή στο προφίλ", "account.featured_tags.last_status_at": "Τελευταία ανάρτηση στις {date}", "account.featured_tags.last_status_never": "Καμία ανάρτηση", - "account.featured_tags.title": "προβεβλημένες ετικέτες του/της {name}", "account.follow": "Ακολούθησε", "account.follow_back": "Ακολούθησε και εσύ", "account.followers": "Ακόλουθοι", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 2f461cd19d..b46d02baa9 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -29,7 +29,6 @@ "account.endorse": "Feature on profile", "account.featured_tags.last_status_at": "Last post on {date}", "account.featured_tags.last_status_never": "No posts", - "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.follow_back": "Follow back", "account.followers": "Followers", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 207fa5b955..1d360e59d7 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -27,9 +27,10 @@ "account.edit_profile": "Redakti la profilon", "account.enable_notifications": "Sciigu min kiam @{name} afiŝos", "account.endorse": "Prezenti ĉe via profilo", + "account.featured.hashtags": "Kradvortoj", + "account.featured.posts": "Afiŝoj", "account.featured_tags.last_status_at": "Lasta afîŝo je {date}", "account.featured_tags.last_status_never": "Neniu afiŝo", - "account.featured_tags.title": "Rekomendataj kradvortoj de {name}", "account.follow": "Sekvi", "account.follow_back": "Sekvu reen", "account.followers": "Sekvantoj", @@ -294,6 +295,7 @@ "emoji_button.search_results": "Serĉaj rezultoj", "emoji_button.symbols": "Simboloj", "emoji_button.travel": "Vojaĝoj kaj lokoj", + "empty_column.account_featured": "Ĉi tiu listo estas malplena", "empty_column.account_hides_collections": "Ĉi tiu uzanto elektis ne disponebligi ĉi tiu informon", "empty_column.account_suspended": "Konto suspendita", "empty_column.account_timeline": "Neniuj afiŝoj ĉi tie!", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 2eb96dd5bd..cc694ebfe7 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -27,9 +27,11 @@ "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} envíe mensajes", "account.endorse": "Destacar en el perfil", + "account.featured": "Destacados", + "account.featured.hashtags": "Etiquetas", + "account.featured.posts": "Mensajes", "account.featured_tags.last_status_at": "Último mensaje: {date}", "account.featured_tags.last_status_never": "Sin mensajes", - "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.follow_back": "Seguir", "account.followers": "Seguidores", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_featured": "Esta lista está vacía", "empty_column.account_hides_collections": "Este usuario eligió no publicar esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay mensajes acá!", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 929f962e6a..45b002ce0f 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -27,9 +27,11 @@ "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} publique algo", "account.endorse": "Destacar en mi perfil", + "account.featured": "Destacado", + "account.featured.hashtags": "Etiquetas", + "account.featured.posts": "Publicaciones", "account.featured_tags.last_status_at": "Última publicación el {date}", "account.featured_tags.last_status_never": "Sin publicaciones", - "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.follow_back": "Seguir también", "account.followers": "Seguidores", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_featured": "Esta lista está vacía", "empty_column.account_hides_collections": "Este usuario ha elegido no hacer disponible esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay publicaciones aquí!", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index be6a0f95ee..2575d901f5 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -27,9 +27,11 @@ "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} publique algo", "account.endorse": "Destacar en el perfil", + "account.featured": "Destacado", + "account.featured.hashtags": "Etiquetas", + "account.featured.posts": "Publicaciones", "account.featured_tags.last_status_at": "Última publicación el {date}", "account.featured_tags.last_status_never": "Sin publicaciones", - "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.follow_back": "Seguir también", "account.followers": "Seguidores", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_featured": "Esta lista está vacía", "empty_column.account_hides_collections": "Este usuario ha decidido no mostrar esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay publicaciones aquí!", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index d2fb81bee6..3e0610126e 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -29,7 +29,6 @@ "account.endorse": "Too profiilil esile", "account.featured_tags.last_status_at": "Viimane postitus {date}", "account.featured_tags.last_status_never": "Postitusi pole", - "account.featured_tags.title": "{name} esiletõstetud sildid", "account.follow": "Jälgi", "account.follow_back": "Jälgi vastu", "account.followers": "Jälgijad", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 5507e7f343..0c73c9f540 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -29,7 +29,6 @@ "account.endorse": "Nabarmendu profilean", "account.featured_tags.last_status_at": "Azken bidalketa {date} datan", "account.featured_tags.last_status_never": "Bidalketarik ez", - "account.featured_tags.title": "{name} erabiltzailearen nabarmendutako traolak", "account.follow": "Jarraitu", "account.follow_back": "Jarraitu bueltan", "account.followers": "Jarraitzaileak", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 27f0bf4e9a..3e31eb8a15 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -29,7 +29,6 @@ "account.endorse": "معرّفی در نمایه", "account.featured_tags.last_status_at": "آخرین فرسته در {date}", "account.featured_tags.last_status_never": "بدون فرسته", - "account.featured_tags.title": "برچسب‌های برگزیدهٔ {name}", "account.follow": "پی‌گرفتن", "account.follow_back": "دنبال کردن متقابل", "account.followers": "پی‌گیرندگان", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 53df277b70..b33e9f6163 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -27,9 +27,10 @@ "account.edit_profile": "Muokkaa profiilia", "account.enable_notifications": "Ilmoita minulle, kun @{name} julkaisee", "account.endorse": "Suosittele profiilissasi", + "account.featured.hashtags": "Aihetunnisteet", + "account.featured.posts": "Julkaisut", "account.featured_tags.last_status_at": "Viimeisin julkaisu {date}", "account.featured_tags.last_status_never": "Ei julkaisuja", - "account.featured_tags.title": "Käyttäjän {name} suosittelemat aihetunnisteet", "account.follow": "Seuraa", "account.follow_back": "Seuraa takaisin", "account.followers": "Seuraajat", @@ -294,6 +295,7 @@ "emoji_button.search_results": "Hakutulokset", "emoji_button.symbols": "Symbolit", "emoji_button.travel": "Matkailu ja paikat", + "empty_column.account_featured": "Tämä lista on tyhjä", "empty_column.account_hides_collections": "Käyttäjä on päättänyt pitää nämä tiedot yksityisinä", "empty_column.account_suspended": "Tili jäädytetty", "empty_column.account_timeline": "Ei viestejä täällä.", diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json index 4c33ac01a1..c13d0a8afe 100644 --- a/app/javascript/mastodon/locales/fil.json +++ b/app/javascript/mastodon/locales/fil.json @@ -29,7 +29,6 @@ "account.endorse": "I-tampok sa profile", "account.featured_tags.last_status_at": "Huling post noong {date}", "account.featured_tags.last_status_never": "Walang mga post", - "account.featured_tags.title": "Nakatampok na hashtag ni {name}", "account.follow": "Sundan", "account.follow_back": "Sundan pabalik", "account.followers": "Mga tagasunod", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 636d32729c..82939adcce 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -27,9 +27,11 @@ "account.edit_profile": "Broyt vanga", "account.enable_notifications": "Boða mær frá, tá @{name} skrivar", "account.endorse": "Víst á vangamyndini", + "account.featured": "Tikin fram", + "account.featured.hashtags": "Frámerki", + "account.featured.posts": "Postar", "account.featured_tags.last_status_at": "Seinasta strongur skrivaður {date}", "account.featured_tags.last_status_never": "Einki uppslag", - "account.featured_tags.title": "Tvíkrossar hjá {name}", "account.follow": "Fylg", "account.follow_back": "Fylg aftur", "account.followers": "Fylgjarar", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Leitiúrslit", "emoji_button.symbols": "Ímyndir", "emoji_button.travel": "Ferðing og støð", + "empty_column.account_featured": "Hesin listin er tómur", "empty_column.account_hides_collections": "Hesin brúkarin hevur valt, at hesar upplýsingarnar ikki skulu vera tøkar", "empty_column.account_suspended": "Kontan gjørd óvirkin", "empty_column.account_timeline": "Einki uppslag her!", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index dd497adbbb..ad71d98ff8 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -29,7 +29,6 @@ "account.endorse": "Inclure sur profil", "account.featured_tags.last_status_at": "Dernière publication {date}", "account.featured_tags.last_status_never": "Aucune publication", - "account.featured_tags.title": "Hashtags inclus de {name}", "account.follow": "Suivre", "account.follow_back": "Suivre en retour", "account.followers": "abonné·e·s", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 5b76cbfde6..de653eec8f 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -29,7 +29,6 @@ "account.endorse": "Recommander sur votre profil", "account.featured_tags.last_status_at": "Dernier message le {date}", "account.featured_tags.last_status_never": "Aucun message", - "account.featured_tags.title": "Les hashtags en vedette de {name}", "account.follow": "Suivre", "account.follow_back": "Suivre en retour", "account.followers": "Abonné·e·s", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 46da3ea09d..e3c3222868 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -29,7 +29,6 @@ "account.endorse": "Op profyl werjaan", "account.featured_tags.last_status_at": "Lêste berjocht op {date}", "account.featured_tags.last_status_never": "Gjin berjochten", - "account.featured_tags.title": "Utljochte hashtags fan {name}", "account.follow": "Folgje", "account.follow_back": "Weromfolgje", "account.followers": "Folgers", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index cd0d58da4a..5935b39e2d 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -29,7 +29,6 @@ "account.endorse": "Cuir ar an phróifíl mar ghné", "account.featured_tags.last_status_at": "Postáil is déanaí ar {date}", "account.featured_tags.last_status_never": "Gan aon phoist", - "account.featured_tags.title": "Haischlib faoi thrácht {name}", "account.follow": "Lean", "account.follow_back": "Leanúint ar ais", "account.followers": "Leantóirí", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index 69aa5f69ef..f295db0b43 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -29,7 +29,6 @@ "account.endorse": "Brosnaich air a’ phròifil", "account.featured_tags.last_status_at": "Am post mu dheireadh {date}", "account.featured_tags.last_status_never": "Gun phost", - "account.featured_tags.title": "Na tagaichean hais brosnaichte aig {name}", "account.follow": "Lean", "account.follow_back": "Lean air ais", "account.followers": "Luchd-leantainn", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 6eb5457043..57e7b5ee5a 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -27,9 +27,11 @@ "account.edit_profile": "Editar perfil", "account.enable_notifications": "Noficarme cando @{name} publique", "account.endorse": "Amosar no perfil", + "account.featured": "Destacado", + "account.featured.hashtags": "Cancelos", + "account.featured.posts": "Publicacións", "account.featured_tags.last_status_at": "Última publicación o {date}", "account.featured_tags.last_status_never": "Sen publicacións", - "account.featured_tags.title": "Cancelos destacados de {name}", "account.follow": "Seguir", "account.follow_back": "Seguir tamén", "account.followers": "Seguidoras", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Resultados da procura", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viaxes e Lugares", + "empty_column.account_featured": "A lista está baleira", "empty_column.account_hides_collections": "A usuaria decideu non facer pública esta información", "empty_column.account_suspended": "Conta suspendida", "empty_column.account_timeline": "Non hai publicacións aquí!", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index f5c6e66f9b..89d36dc962 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -29,7 +29,6 @@ "account.endorse": "קדם את החשבון בפרופיל", "account.featured_tags.last_status_at": "חצרוץ אחרון בתאריך {date}", "account.featured_tags.last_status_never": "אין חצרוצים", - "account.featured_tags.title": "התגיות המועדפות של {name}", "account.follow": "לעקוב", "account.follow_back": "לעקוב בחזרה", "account.followers": "עוקבים", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 10c5356719..a3eec9544c 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -28,7 +28,6 @@ "account.endorse": "प्रोफ़ाइल पर दिखाए", "account.featured_tags.last_status_at": "{date} का अंतिम पोस्ट", "account.featured_tags.last_status_never": "कोई पोस्ट नहीं है", - "account.featured_tags.title": "{name} के चुनिंदा हैशटैग", "account.follow": "फॉलो करें", "account.follow_back": "फॉलो करें", "account.followers": "फॉलोवर", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 092647bd31..38807b28b2 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -28,7 +28,6 @@ "account.endorse": "Istakni na profilu", "account.featured_tags.last_status_at": "Zadnji post {date}", "account.featured_tags.last_status_never": "Nema postova", - "account.featured_tags.title": "Istaknuti hashtagovi {name}", "account.follow": "Prati", "account.follow_back": "Slijedi natrag", "account.followers": "Pratitelji", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 2caba889e3..826dca6137 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -27,9 +27,11 @@ "account.edit_profile": "Profil szerkesztése", "account.enable_notifications": "Figyelmeztessen, ha @{name} bejegyzést tesz közzé", "account.endorse": "Kiemelés a profilodon", + "account.featured": "Kiemelt", + "account.featured.hashtags": "Hashtagek", + "account.featured.posts": "Bejegyzések", "account.featured_tags.last_status_at": "Legutolsó bejegyzés ideje: {date}", "account.featured_tags.last_status_never": "Nincs bejegyzés", - "account.featured_tags.title": "{name} kiemelt hashtagjei", "account.follow": "Követés", "account.follow_back": "Viszontkövetés", "account.followers": "Követő", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Keresési találatok", "emoji_button.symbols": "Szimbólumok", "emoji_button.travel": "Utazás és helyek", + "empty_column.account_featured": "Ez a lista üres", "empty_column.account_hides_collections": "Ez a felhasználó úgy döntött, hogy nem teszi elérhetővé ezt az információt.", "empty_column.account_suspended": "Fiók felfüggesztve", "empty_column.account_timeline": "Itt nincs bejegyzés!", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index d4706dbf8c..7f4f66796e 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -29,7 +29,6 @@ "account.endorse": "Evidentiar sur le profilo", "account.featured_tags.last_status_at": "Ultime message publicate le {date}", "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", "account.followers": "Sequitores", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index f4724b6f4f..102e547d40 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -29,7 +29,6 @@ "account.endorse": "Tampilkan di profil", "account.featured_tags.last_status_at": "Kiriman terakhir pada {date}", "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", diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json index ba5ad494ce..7cd463727f 100644 --- a/app/javascript/mastodon/locales/ie.json +++ b/app/javascript/mastodon/locales/ie.json @@ -28,7 +28,6 @@ "account.endorse": "Recomandar sur profil", "account.featured_tags.last_status_at": "Ultim posta ye {date}", "account.featured_tags.last_status_never": "Null postas", - "account.featured_tags.title": "Recomandat hashtags de {name}", "account.follow": "Sequer", "account.follow_back": "Sequer reciprocmen", "account.followers": "Sequitores", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 21723e10b8..596ca4c3fe 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -29,7 +29,6 @@ "account.endorse": "Traito di profilo", "account.featured_tags.last_status_at": "Antea posto ye {date}", "account.featured_tags.last_status_never": "Nula posti", - "account.featured_tags.title": "Ekstaca gretvorti di {name}", "account.follow": "Sequar", "account.follow_back": "Anke sequez", "account.followers": "Sequanti", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index db257927fc..5f956c71f6 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -27,9 +27,11 @@ "account.edit_profile": "Breyta notandasniði", "account.enable_notifications": "Láta mig vita þegar @{name} sendir inn", "account.endorse": "Birta á notandasniði", + "account.featured": "Með aukið vægi", + "account.featured.hashtags": "Myllumerki", + "account.featured.posts": "Færslur", "account.featured_tags.last_status_at": "Síðasta færsla þann {date}", "account.featured_tags.last_status_never": "Engar færslur", - "account.featured_tags.title": "Myllumerki hjá {name} með aukið vægi", "account.follow": "Fylgjast með", "account.follow_back": "Fylgjast með til baka", "account.followers": "Fylgjendur", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Leitarniðurstöður", "emoji_button.symbols": "Tákn", "emoji_button.travel": "Ferðalög og staðir", + "empty_column.account_featured": "Þessi listi er tómur", "empty_column.account_hides_collections": "Notandinn hefur valið að gera ekki tiltækar þessar upplýsingar", "empty_column.account_suspended": "Notandaaðgangur í frysti", "empty_column.account_timeline": "Engar færslur hér!", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 99cb78716f..36770c675f 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -27,9 +27,11 @@ "account.edit_profile": "Modifica profilo", "account.enable_notifications": "Avvisami quando @{name} pubblica un post", "account.endorse": "In evidenza sul profilo", + "account.featured": "In primo piano", + "account.featured.hashtags": "Hashtag", + "account.featured.posts": "Post", "account.featured_tags.last_status_at": "Ultimo post il {date}", "account.featured_tags.last_status_never": "Nessun post", - "account.featured_tags.title": "Hashtag in evidenza di {name}", "account.follow": "Segui", "account.follow_back": "Segui a tua volta", "account.followers": "Follower", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Risultati della ricerca", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Viaggi & Luoghi", + "empty_column.account_featured": "Questa lista è vuota", "empty_column.account_hides_collections": "Questo utente ha scelto di non rendere disponibili queste informazioni", "empty_column.account_suspended": "Profilo sospeso", "empty_column.account_timeline": "Nessun post qui!", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index ab9a5ce64c..847c479b23 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -29,7 +29,6 @@ "account.endorse": "プロフィールで紹介する", "account.featured_tags.last_status_at": "最終投稿 {date}", "account.featured_tags.last_status_never": "投稿がありません", - "account.featured_tags.title": "{name}の注目ハッシュタグ", "account.follow": "フォロー", "account.follow_back": "フォローバック", "account.followers": "フォロワー", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index 120e2415b5..adc3cdc230 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -25,7 +25,6 @@ "account.enable_notifications": "@{name} постары туралы ескерту", "account.endorse": "Профильде ұсыну", "account.featured_tags.last_status_never": "Пост жоқ", - "account.featured_tags.title": "{name} таңдаулы хэштегтері", "account.follow": "Жазылу", "account.followers": "Жазылушы", "account.followers.empty": "Бұл қолданушыға әлі ешкім жазылмаған.", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 76f94fb43f..be6e4be7e1 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -29,7 +29,6 @@ "account.endorse": "프로필에 추천하기", "account.featured_tags.last_status_at": "{date}에 마지막으로 게시", "account.featured_tags.last_status_never": "게시물 없음", - "account.featured_tags.title": "{name} 님의 추천 해시태그", "account.follow": "팔로우", "account.follow_back": "맞팔로우", "account.followers": "팔로워", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index f867908f37..23ee9fc932 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -29,7 +29,6 @@ "account.endorse": "Taybetiyên li ser profîl", "account.featured_tags.last_status_at": "Şandiya dawî di {date} de", "account.featured_tags.last_status_never": "Şandî tune ne", - "account.featured_tags.title": "{name}'s hashtagên taybet", "account.follow": "Bişopîne", "account.follow_back": "Bişopîne", "account.followers": "Şopîner", diff --git a/app/javascript/mastodon/locales/la.json b/app/javascript/mastodon/locales/la.json index f422230cb8..c6e5d85c07 100644 --- a/app/javascript/mastodon/locales/la.json +++ b/app/javascript/mastodon/locales/la.json @@ -23,7 +23,6 @@ "account.domain_blocked": "Dominium impeditum", "account.edit_profile": "Recolere notionem", "account.featured_tags.last_status_never": "Nulla contributa", - "account.featured_tags.title": "Hashtag notātī {name}", "account.followers_counter": "{count, plural, one {{counter} sectator} other {{counter} sectatores}}", "account.following_counter": "{count, plural, one {{counter} sectans} other {{counter} sectans}}", "account.moved_to": "{name} significavit eum suam rationem novam nunc esse:", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index d9d941f8e8..f67ef676ad 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -29,7 +29,6 @@ "account.endorse": "Avalia en profil", "account.featured_tags.last_status_at": "Ultima publikasyon de {date}", "account.featured_tags.last_status_never": "No ay publikasyones", - "account.featured_tags.title": "Etiketas avaliadas de {name}", "account.follow": "Sige", "account.follow_back": "Sige tamyen", "account.followers": "Suivantes", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index f112bc73d9..7110e809c1 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -29,7 +29,6 @@ "account.endorse": "Rodyti profilyje", "account.featured_tags.last_status_at": "Paskutinis įrašas {date}", "account.featured_tags.last_status_never": "Nėra įrašų", - "account.featured_tags.title": "{name} rodomi saitažodžiai", "account.follow": "Sekti", "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 203b321574..27760c59ff 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -29,7 +29,6 @@ "account.endorse": "Izcelts profilā", "account.featured_tags.last_status_at": "Beidzamā ziņa {date}", "account.featured_tags.last_status_never": "Ierakstu nav", - "account.featured_tags.title": "{name} izceltie tēmturi", "account.follow": "Sekot", "account.follow_back": "Sekot atpakaļ", "account.followers": "Sekotāji", @@ -54,7 +53,7 @@ "account.muted": "Apklusināts", "account.mutual": "Abpusēji", "account.no_bio": "Apraksts nav sniegts.", - "account.open_original_page": "Atvērt oriģinālo lapu", + "account.open_original_page": "Atvērt pirmavota lapu", "account.posts": "Ieraksti", "account.posts_with_replies": "Ieraksti un atbildes", "account.report": "Sūdzēties par @{name}", @@ -214,7 +213,7 @@ "confirmations.missing_alt_text.secondary": "Vienalga iesūtīt", "confirmations.mute.confirm": "Apklusināt", "confirmations.redraft.confirm": "Dzēst un pārrakstīt", - "confirmations.redraft.message": "Vai tiešām vēlies dzēst šo ziņu un no jauna noformēt to? Izlase un pastiprinājumi tiks zaudēti, un atbildes uz sākotnējo ziņu tiks atstātas bez autoratlīdzības.", + "confirmations.redraft.message": "Vai tiešām vēlies izdzēst šo ierakstu un veidot jaunu tā uzmetumu? Pievienošana izlasēs un pastiprinājumi tiks zaudēti, un sākotnējā ieraksta atbildes paliks bez saiknes ar to.", "confirmations.redraft.title": "Dzēst un rakstīt vēlreiz?", "confirmations.reply.confirm": "Atbildēt", "confirmations.reply.message": "Tūlītēja atbildēšana pārrakstīs pašlaik sastādīto ziņu. Vai tiešām turpināt?", @@ -597,7 +596,7 @@ "report.close": "Darīts", "report.comment.title": "Vai, tavuprāt, mums vēl būtu kas jāzina?", "report.forward": "Pārsūtīt {target}", - "report.forward_hint": "Konts ir no cita servera. Vai nosūtīt anonimizētu sūdzības kopiju arī tam?", + "report.forward_hint": "Konts ir no cita servera. Vai nosūtīt anonimizētu ziņojuma kopiju arī tur?", "report.mute": "Apklusināt", "report.mute_explanation": "Tu neredzēsi viņu ierakstus. Viņi joprojām var Tev sekot un redzēt Tavus ierakstus un nezinās, ka viņi ir apklusināti.", "report.next": "Tālāk", @@ -692,7 +691,7 @@ "status.pinned": "Piesprausts ieraksts", "status.read_more": "Lasīt vairāk", "status.reblog": "Pastiprināt", - "status.reblog_private": "Pastiprināt, nemainot redzamību", + "status.reblog_private": "Pastiprināt ar sākotnējo redzamību", "status.reblogged_by": "{name} pastiprināja", "status.reblogs": "{count, plural, zero {pastiprinājumu} one {pastiprinājums} other {pastiprinājumi}}", "status.reblogs.empty": "Neviens šo ierakstu vēl nav pastiprinājis. Kad būs, tie parādīsies šeit.", @@ -706,7 +705,7 @@ "status.share": "Kopīgot", "status.show_less_all": "Rādīt mazāk visiem", "status.show_more_all": "Rādīt vairāk visiem", - "status.show_original": "Rādīt oriģinālu", + "status.show_original": "Rādīt pirmavotu", "status.title.with_attachments": "{user} publicējis {attachmentCount, plural, one {pielikumu} other {{attachmentCount} pielikumus}}", "status.translate": "Tulkot", "status.translated_from_with": "Tulkots no {lang} izmantojot {provider}", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index 94f9aef261..919a34532f 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -28,7 +28,6 @@ "account.endorse": "प्रोफाइलवरील वैशिष्ट्य", "account.featured_tags.last_status_at": "शेवटचे पोस्ट {date} रोजी", "account.featured_tags.last_status_never": "पोस्ट नाहीत", - "account.featured_tags.title": "{name} चे वैशिष्ट्यीकृत हॅशटॅग", "account.follow": "अनुयायी व्हा", "account.follow_back": "आपणही अनुसरण करा", "account.followers": "अनुयायी", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index af80cc20cf..f6a34116e8 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -29,7 +29,6 @@ "account.endorse": "Tampilkan di profil", "account.featured_tags.last_status_at": "Hantaran terakhir pada {date}", "account.featured_tags.last_status_never": "Tiada hantaran", - "account.featured_tags.title": "Tanda pagar pilihan {name}", "account.follow": "Ikuti", "account.follow_back": "Ikut balik", "account.followers": "Pengikut", diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json index 51cba22153..362537edeb 100644 --- a/app/javascript/mastodon/locales/my.json +++ b/app/javascript/mastodon/locales/my.json @@ -28,7 +28,6 @@ "account.endorse": "အကောင့်ပရိုဖိုင်တွင်ဖော်ပြပါ", "account.featured_tags.last_status_at": "နောက်ဆုံးပို့စ်ကို {date} တွင် တင်ခဲ့သည်။", "account.featured_tags.last_status_never": "ပို့စ်တင်ထားခြင်းမရှိပါ", - "account.featured_tags.title": "ဖော်ပြထားသောဟက်ရှ်တက်ခ်များ", "account.follow": "စောင့်ကြည့်", "account.followers": "စောင့်ကြည့်သူများ", "account.followers.empty": "ဤသူကို စောင့်ကြည့်သူ မရှိသေးပါ။", diff --git a/app/javascript/mastodon/locales/nan.json b/app/javascript/mastodon/locales/nan.json index 268dbfa2b7..1ae348871f 100644 --- a/app/javascript/mastodon/locales/nan.json +++ b/app/javascript/mastodon/locales/nan.json @@ -29,7 +29,6 @@ "account.endorse": "用個人資料推薦對方", "account.featured_tags.last_status_at": "頂kái tī {date} Po文", "account.featured_tags.last_status_never": "無PO文", - "account.featured_tags.title": "{name} ê推薦hashtag", "account.follow": "跟tuè", "account.follow_back": "Tuè tńg去", "account.followers": "跟tuè lí ê", diff --git a/app/javascript/mastodon/locales/ne.json b/app/javascript/mastodon/locales/ne.json index 696f9fbed8..af2c922cbd 100644 --- a/app/javascript/mastodon/locales/ne.json +++ b/app/javascript/mastodon/locales/ne.json @@ -25,7 +25,6 @@ "account.enable_notifications": "@{name} ले पोस्ट गर्दा मलाई सूचित गर्नुहोस्", "account.endorse": "प्रोफाइलमा फिचर गर्नुहोस्", "account.featured_tags.last_status_never": "कुनै पोस्ट छैन", - "account.featured_tags.title": "{name}का विशेष ह्यासट्यागहरू", "account.follow": "फलो गर्नुहोस", "account.follow_back": "फलो ब्याक गर्नुहोस्", "account.followers": "फलोअरहरु", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index a4af036527..e22b7b3774 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -27,9 +27,11 @@ "account.edit_profile": "Profiel bewerken", "account.enable_notifications": "Geef een melding wanneer @{name} een bericht plaatst", "account.endorse": "Op profiel weergeven", + "account.featured": "Uitgelicht", + "account.featured.hashtags": "Hashtags", + "account.featured.posts": "Berichten", "account.featured_tags.last_status_at": "Laatste bericht op {date}", "account.featured_tags.last_status_never": "Geen berichten", - "account.featured_tags.title": "Uitgelichte hashtags van {name}", "account.follow": "Volgen", "account.follow_back": "Terugvolgen", "account.followers": "Volgers", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Zoekresultaten", "emoji_button.symbols": "Symbolen", "emoji_button.travel": "Reizen en locaties", + "empty_column.account_featured": "Deze lijst is leeg", "empty_column.account_hides_collections": "Deze gebruiker heeft ervoor gekozen deze informatie niet beschikbaar te maken", "empty_column.account_suspended": "Account opgeschort", "empty_column.account_timeline": "Hier zijn geen berichten!", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 4e0e96d974..ab867017a9 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -27,9 +27,11 @@ "account.edit_profile": "Rediger profil", "account.enable_notifications": "Varsle meg når @{name} skriv innlegg", "account.endorse": "Vis på profilen", + "account.featured": "Utvald", + "account.featured.hashtags": "Emneknaggar", + "account.featured.posts": "Innlegg", "account.featured_tags.last_status_at": "Sist nytta {date}", "account.featured_tags.last_status_never": "Ingen innlegg", - "account.featured_tags.title": "{name} sine framheva emneknaggar", "account.follow": "Fylg", "account.follow_back": "Fylg tilbake", "account.followers": "Fylgjarar", @@ -293,6 +295,7 @@ "emoji_button.search_results": "Søkeresultat", "emoji_button.symbols": "Symbol", "emoji_button.travel": "Reise & stader", + "empty_column.account_featured": "Denne lista er tom", "empty_column.account_hides_collections": "Denne brukaren har valt å ikkje gjere denne informasjonen tilgjengeleg", "empty_column.account_suspended": "Kontoen er utestengd", "empty_column.account_timeline": "Ingen tut her!", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 584132ffe6..a18ccdc0dc 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -29,7 +29,6 @@ "account.endorse": "Vis frem på profilen", "account.featured_tags.last_status_at": "Siste innlegg {date}", "account.featured_tags.last_status_never": "Ingen Innlegg", - "account.featured_tags.title": "{name} sine fremhevede emneknagger", "account.follow": "Følg", "account.follow_back": "Følg tilbake", "account.followers": "Følgere", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 616f8a64af..74ae8fad4d 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -26,7 +26,6 @@ "account.endorse": "Mostrar pel perfil", "account.featured_tags.last_status_at": "Darrièra publicacion lo {date}", "account.featured_tags.last_status_never": "Cap de publicacion", - "account.featured_tags.title": "Etiquetas en avant de {name}", "account.follow": "Sègre", "account.follow_back": "Sègre en retorn", "account.followers": "Seguidors", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index c6b2a5d412..ed827bcf29 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -29,7 +29,6 @@ "account.endorse": "Wyróżnij na profilu", "account.featured_tags.last_status_at": "Ostatni post {date}", "account.featured_tags.last_status_never": "Brak postów", - "account.featured_tags.title": "Polecane hasztagi {name}", "account.follow": "Obserwuj", "account.follow_back": "Również obserwuj", "account.followers": "Obserwujący", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 5279159d79..55cfeea582 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -29,7 +29,6 @@ "account.endorse": "Recomendar", "account.featured_tags.last_status_at": "Última publicação em {date}", "account.featured_tags.last_status_never": "Sem publicações", - "account.featured_tags.title": "Hashtags em destaque de {name}", "account.follow": "Seguir", "account.follow_back": "Seguir de volta", "account.followers": "Seguidores", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 32af518415..87c9e5846a 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -29,7 +29,6 @@ "account.endorse": "Destacar no perfil", "account.featured_tags.last_status_at": "Última publicação em {date}", "account.featured_tags.last_status_never": "Sem publicações", - "account.featured_tags.title": "Etiquetas destacadas por {name}", "account.follow": "Seguir", "account.follow_back": "Seguir também", "account.followers": "Seguidores", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index 56d577f3f0..8fec42bbd0 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -29,7 +29,6 @@ "account.endorse": "Promovează pe profil", "account.featured_tags.last_status_at": "Ultima postare pe {date}", "account.featured_tags.last_status_never": "Fără postări", - "account.featured_tags.title": "Haștagurile recomandate de {name}", "account.follow": "Urmărește", "account.follow_back": "Urmăreşte înapoi", "account.followers": "Urmăritori", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 15ae4b9e0a..6763a354f3 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -27,9 +27,9 @@ "account.edit_profile": "Редактировать", "account.enable_notifications": "Уведомлять о постах от @{name}", "account.endorse": "Рекомендовать в профиле", + "account.featured": "Избранное", "account.featured_tags.last_status_at": "Последний пост {date}", "account.featured_tags.last_status_never": "Нет постов", - "account.featured_tags.title": "Избранные хэштеги {name}", "account.follow": "Подписаться", "account.follow_back": "Подписаться в ответ", "account.followers": "Подписчики", diff --git a/app/javascript/mastodon/locales/ry.json b/app/javascript/mastodon/locales/ry.json index 8fd083efc3..ed9751634e 100644 --- a/app/javascript/mastodon/locales/ry.json +++ b/app/javascript/mastodon/locales/ry.json @@ -28,7 +28,6 @@ "account.endorse": "Указовати на профілови", "account.featured_tags.last_status_at": "Датум послідньої публикації {date}", "account.featured_tags.last_status_never": "Ниє публикацій", - "account.featured_tags.title": "Ублюблені гештеґы {name}", "account.follow": "Пудписати ся", "account.follow_back": "Пудписати ся тоже", "account.followers": "Пудписникы", diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json index 1ecc057023..ce88bda740 100644 --- a/app/javascript/mastodon/locales/sa.json +++ b/app/javascript/mastodon/locales/sa.json @@ -26,7 +26,6 @@ "account.endorse": "व्यक्तिगतविवरणे वैशिष्ट्यम्", "account.featured_tags.last_status_at": "{date} दिने गतस्थापनम्", "account.featured_tags.last_status_never": "न पत्रम्", - "account.featured_tags.title": "{name} इत्यस्य विशेषहैस्टैगः", "account.follow": "अनुस्रियताम्", "account.followers": "अनुसर्तारः", "account.followers.empty": "नाऽनुसर्तारो वर्तन्ते", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index c885078a73..79ef6f6ef5 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -29,7 +29,6 @@ "account.endorse": "Cussìgia in su profilu tuo", "account.featured_tags.last_status_at": "Ùrtima publicatzione in su {date}", "account.featured_tags.last_status_never": "Peruna publicatzione", - "account.featured_tags.title": "Etichetas de {name} in evidèntzia", "account.follow": "Sighi", "account.follow_back": "Sighi tue puru", "account.followers": "Sighiduras", diff --git a/app/javascript/mastodon/locales/sco.json b/app/javascript/mastodon/locales/sco.json index 5960fb7760..872a61a8a2 100644 --- a/app/javascript/mastodon/locales/sco.json +++ b/app/javascript/mastodon/locales/sco.json @@ -25,7 +25,6 @@ "account.endorse": "Shaw oan profile", "account.featured_tags.last_status_at": "Last post oan {date}", "account.featured_tags.last_status_never": "Nae posts", - "account.featured_tags.title": "{name}'s hielichtit hashtags", "account.follow": "Follae", "account.followers": "Follaers", "account.followers.empty": "Naebody follaes this uiser yit.", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index d6aff6b56c..57fc3be484 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -29,7 +29,6 @@ "account.endorse": "Zobraziť na vlastnom profile", "account.featured_tags.last_status_at": "Posledný príspevok dňa {date}", "account.featured_tags.last_status_never": "Žiadne príspevky", - "account.featured_tags.title": "Odporúčané hashtagy účtu {name}", "account.follow": "Sledovať", "account.follow_back": "Sledovať späť", "account.followers": "Sledovatelia", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index e6c0b67427..eef20456de 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -29,7 +29,6 @@ "account.endorse": "Izpostavi v profilu", "account.featured_tags.last_status_at": "Zadnja objava {date}", "account.featured_tags.last_status_never": "Ni objav", - "account.featured_tags.title": "Izpostavljeni ključniki osebe {name}", "account.follow": "Sledi", "account.follow_back": "Sledi nazaj", "account.followers": "Sledilci", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index a80b3df80d..bb1668b2ef 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -27,9 +27,11 @@ "account.edit_profile": "Përpunoni profilin", "account.enable_notifications": "Njoftomë, kur poston @{name}", "account.endorse": "Pasqyrojeni në profil", + "account.featured": "Të zgjedhur", + "account.featured.hashtags": "Hashtag-ë", + "account.featured.posts": "Postime", "account.featured_tags.last_status_at": "Postimi i fundit më {date}", "account.featured_tags.last_status_never": "Pa postime", - "account.featured_tags.title": "Hashtagë të zgjedhur të {name}", "account.follow": "Ndiqeni", "account.follow_back": "Ndiqe gjithashtu", "account.followers": "Ndjekës", @@ -289,6 +291,7 @@ "emoji_button.search_results": "Përfundime kërkimi", "emoji_button.symbols": "Simbole", "emoji_button.travel": "Udhëtime & Vende", + "empty_column.account_featured": "Kjo listë është e zbrazët", "empty_column.account_hides_collections": "Ky përdorues ka zgjedhur të mos e japë këtë informacion", "empty_column.account_suspended": "Llogaria u pezullua", "empty_column.account_timeline": "S’ka mesazhe këtu!", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 3d077cbe22..2d00533e0e 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -28,7 +28,6 @@ "account.endorse": "Istakni na profilu", "account.featured_tags.last_status_at": "Poslednja objava {date}", "account.featured_tags.last_status_never": "Nema objava", - "account.featured_tags.title": "Istaknute heš oznake korisnika {name}", "account.follow": "Prati", "account.follow_back": "Uzvrati praćenje", "account.followers": "Pratioci", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 43c57b3e25..af323bed27 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -28,7 +28,6 @@ "account.endorse": "Истакни на профилу", "account.featured_tags.last_status_at": "Последња објава {date}", "account.featured_tags.last_status_never": "Нема објава", - "account.featured_tags.title": "Истакнуте хеш ознаке корисника {name}", "account.follow": "Прати", "account.follow_back": "Узврати праћење", "account.followers": "Пратиоци", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 1e2e9c585b..c23a645135 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -29,7 +29,6 @@ "account.endorse": "Visa på profil", "account.featured_tags.last_status_at": "Senaste inlägg den {date}", "account.featured_tags.last_status_never": "Inga inlägg", - "account.featured_tags.title": "{name}s utvalda hashtaggar", "account.follow": "Följ", "account.follow_back": "Följ tillbaka", "account.followers": "Följare", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index d9e607f856..429d0db428 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -29,7 +29,6 @@ "account.endorse": "แสดงในโปรไฟล์", "account.featured_tags.last_status_at": "โพสต์ล่าสุดเมื่อ {date}", "account.featured_tags.last_status_never": "ไม่มีโพสต์", - "account.featured_tags.title": "แฮชแท็กที่น่าสนใจของ {name}", "account.follow": "ติดตาม", "account.follow_back": "ติดตามกลับ", "account.followers": "ผู้ติดตาม", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 59dd34eb5c..08ce6fd324 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -29,7 +29,6 @@ "account.endorse": "lipu jan la o suli e ni", "account.featured_tags.last_status_at": "sitelen pini pi jan ni li lon tenpo {date}", "account.featured_tags.last_status_never": "toki ala li lon", - "account.featured_tags.title": "{name} la kulupu ni pi toki suli li pona", "account.follow": "o kute", "account.follow_back": "jan ni li kute e sina. o kute", "account.followers": "jan kute", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index a33317ac9c..fa5a84dd68 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -27,9 +27,11 @@ "account.edit_profile": "Profili düzenle", "account.enable_notifications": "@{name} kişisinin gönderi bildirimlerini aç", "account.endorse": "Profilimde öne çıkar", + "account.featured": "Öne çıkan", + "account.featured.hashtags": "Etiketler", + "account.featured.posts": "Gönderiler", "account.featured_tags.last_status_at": "Son gönderinin tarihi {date}", "account.featured_tags.last_status_never": "Gönderi yok", - "account.featured_tags.title": "{name} kişisinin öne çıkan etiketleri", "account.follow": "Takip et", "account.follow_back": "Geri takip et", "account.followers": "Takipçi", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Arama sonuçları", "emoji_button.symbols": "Semboller", "emoji_button.travel": "Seyahat ve Yerler", + "empty_column.account_featured": "Bu liste boş", "empty_column.account_hides_collections": "Bu kullanıcı bu bilgiyi sağlamayı tercih etmemiştir", "empty_column.account_suspended": "Hesap askıya alındı", "empty_column.account_timeline": "Burada hiç gönderi yok!", diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json index 602d676361..ee50180ced 100644 --- a/app/javascript/mastodon/locales/tt.json +++ b/app/javascript/mastodon/locales/tt.json @@ -27,7 +27,6 @@ "account.endorse": "Профильдә тәкъдим итү", "account.featured_tags.last_status_at": "Соңгы хәбәр {date}", "account.featured_tags.last_status_never": "Хәбәрләр юк", - "account.featured_tags.title": "{name} тәкъдим ителгән хэштеглар", "account.follow": "Язылу", "account.followers": "Язылучы", "account.followers.empty": "Әле беркем дә язылмаган.", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index eb7931f02c..b995713c52 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -27,9 +27,11 @@ "account.edit_profile": "Редагувати профіль", "account.enable_notifications": "Повідомляти мене про дописи @{name}", "account.endorse": "Рекомендувати у моєму профілі", + "account.featured": "Рекомендоване", + "account.featured.hashtags": "Хештеги", + "account.featured.posts": "Дописи", "account.featured_tags.last_status_at": "Останній допис {date}", "account.featured_tags.last_status_never": "Немає дописів", - "account.featured_tags.title": "{name} виділяє хештеґи", "account.follow": "Підписатися", "account.follow_back": "Стежити також", "account.followers": "Підписники", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Результати пошуку", "emoji_button.symbols": "Символи", "emoji_button.travel": "Подорожі та місця", + "empty_column.account_featured": "Список порожній", "empty_column.account_hides_collections": "Цей користувач вирішив не робити цю інформацію доступною", "empty_column.account_suspended": "Обліковий запис заблоковано", "empty_column.account_timeline": "Тут немає дописів!", diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index cd50b512b4..e28ad93828 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -22,7 +22,6 @@ "account.endorse": "مشکص پر نمایاں کریں", "account.featured_tags.last_status_at": "آخری پوسٹ {date} کو", "account.featured_tags.last_status_never": "کوئی مراسلہ نہیں", - "account.featured_tags.title": "{name} کے نمایاں ہیش ٹیگز", "account.follow": "پیروی کریں", "account.follow_back": "اکاؤنٹ کو فالو بیک ", "account.followers": "پیروکار", diff --git a/app/javascript/mastodon/locales/uz.json b/app/javascript/mastodon/locales/uz.json index e58ab35444..6dd350651d 100644 --- a/app/javascript/mastodon/locales/uz.json +++ b/app/javascript/mastodon/locales/uz.json @@ -25,7 +25,6 @@ "account.endorse": "Profildagi xususiyat", "account.featured_tags.last_status_at": "Oxirgi post: {date}", "account.featured_tags.last_status_never": "Habarlar yo'q", - "account.featured_tags.title": "{name} ning taniqli hashtaglari", "account.follow": "Obuna bo‘lish", "account.followers": "Obunachilar", "account.followers.empty": "Bu foydalanuvchini hali hech kim kuzatmaydi.", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 21a7e5da47..a608b3ed85 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -27,9 +27,11 @@ "account.edit_profile": "Sửa hồ sơ", "account.enable_notifications": "Nhận thông báo khi @{name} đăng tút", "account.endorse": "Tôn vinh người này", + "account.featured": "Nổi bật", + "account.featured.hashtags": "Hashtag", + "account.featured.posts": "Tút", "account.featured_tags.last_status_at": "Tút gần nhất {date}", "account.featured_tags.last_status_never": "Chưa có tút", - "account.featured_tags.title": "Hashtag của {name}", "account.follow": "Theo dõi", "account.follow_back": "Theo dõi lại", "account.followers": "Người theo dõi", @@ -294,6 +296,7 @@ "emoji_button.search_results": "Kết quả tìm kiếm", "emoji_button.symbols": "Biểu tượng", "emoji_button.travel": "Du lịch", + "empty_column.account_featured": "Danh sách trống", "empty_column.account_hides_collections": "Người này đã chọn ẩn thông tin", "empty_column.account_suspended": "Tài khoản vô hiệu hóa", "empty_column.account_timeline": "Chưa có tút nào!", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 050e1308b6..48f12d241a 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -29,7 +29,6 @@ "account.endorse": "在个人资料中推荐此用户", "account.featured_tags.last_status_at": "上次发言于 {date}", "account.featured_tags.last_status_never": "暂无嘟文", - "account.featured_tags.title": "{name} 的精选标签", "account.follow": "关注", "account.follow_back": "回关", "account.followers": "关注者", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index d6ffb2b6bf..493d06b672 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -29,7 +29,6 @@ "account.endorse": "在個人檔案中推薦對方", "account.featured_tags.last_status_at": "上次帖文於 {date}", "account.featured_tags.last_status_never": "暫無文章", - "account.featured_tags.title": "{name} 的精選標籤", "account.follow": "關注", "account.follow_back": "追蹤對方", "account.followers": "追蹤者", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index f2b8665e49..3bb8ed4cbc 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -27,9 +27,11 @@ "account.edit_profile": "編輯個人檔案", "account.enable_notifications": "當 @{name} 嘟文時通知我", "account.endorse": "於個人檔案推薦對方", + "account.featured": "精選內容", + "account.featured.hashtags": "主題標籤", + "account.featured.posts": "嘟文", "account.featured_tags.last_status_at": "上次嘟文於 {date}", "account.featured_tags.last_status_never": "沒有嘟文", - "account.featured_tags.title": "{name} 的推薦主題標籤", "account.follow": "跟隨", "account.follow_back": "跟隨回去", "account.followers": "跟隨者", @@ -294,6 +296,7 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", + "empty_column.account_featured": "此列表為空", "empty_column.account_hides_collections": "這位使用者選擇不提供此資訊", "empty_column.account_suspended": "帳號已被停權", "empty_column.account_timeline": "這裡還沒有嘟文!", diff --git a/config/locales/lv.yml b/config/locales/lv.yml index fad8a2609e..2bb5abf2de 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -19,10 +19,10 @@ lv: pin_errors: following: Tev ir jāseko personai, kuru vēlies atbalstīt posts: - one: Ziņa - other: Ziņas - zero: Ziņu - posts_tab_heading: Ziņas + one: Ieraksts + other: Ieraksti + zero: Ierakstu + posts_tab_heading: Ieraksti self_follow_error: Nav ļauts sekot savam kontam admin: account_actions: @@ -120,7 +120,7 @@ lv: public: Publisks push_subscription_expires: PuSH abonements beidzas redownload: Atsvaidzināt profilu - redownloaded_msg: "%{username} profils sekmīgi atsvaidzināts no izcelsmes" + redownloaded_msg: "%{username} profils sekmīgi atsvaidzināts no pirmavota" reject: Noraidīt rejected_msg: "%{username} reģistrēšanās pieteikums sekmīgi noraidīts" remote_suspension_irreversible: Šī konta dati ir neatgriezeniski dzēsti. @@ -152,7 +152,7 @@ lv: targeted_reports: Ziņojuši citi silence: Ierobežot silenced: Ierobežots - statuses: Ziņas + statuses: Ieraksti strikes: Iepriekšējie streiki subscribe: Abonēt suspend: Apturēt @@ -176,7 +176,7 @@ lv: whitelisted: Atļauts federācijai action_logs: action_types: - approve_appeal: Apstiprināt Apelāciju + approve_appeal: Apstiprināt pārsūdzību approve_user: Apstiprināt lietotāju assigned_to_self_report: Piešķirt Pārskatu change_email_user: Mainīt lietotāja e-pasta adresi @@ -218,11 +218,11 @@ lv: memorialize_account: Saglabāt Kontu Piemiņai promote_user: Izceltt Lietotāju publish_terms_of_service: Publicēt pakalpojuma izmantošanas noteikumus - reject_appeal: Noraidīt Apelāciju + reject_appeal: Noraidīt pārsūdzību reject_user: Noraidīt lietotāju remove_avatar_user: Noņemt profila attēlu reopen_report: Atkārtoti Atvērt Ziņojumu - resend_user: Atkārtoti nosūtīt Apstiprinājuma Pastu + resend_user: Atkārtoti nosūtīt apstiprinājuma e-pasta ziņojumu reset_password_user: Atiestatīt Paroli resolve_report: Atrisināt Ziņojumu sensitive_account: Uzspiesti atzimēt kontu kā jūtīgu @@ -241,7 +241,7 @@ lv: update_status: Atjaunināt ziņu update_user_role: Atjaunināt lomu actions: - approve_appeal_html: "%{name} apstiprināja satura pārraudzības lēmuma iebildumu no %{target}" + approve_appeal_html: "%{name} apstiprināja satura pārraudzības lēmuma pārsūdzību no %{target}" approve_user_html: "%{name} apstiprināja reģistrēšanos no %{target}" assigned_to_self_report_html: "%{name} piešķīra pārskatu %{target} sev" change_email_user_html: "%{name} nomainīja lietotāja %{target} e-pasta adresi" @@ -277,7 +277,7 @@ lv: memorialize_account_html: "%{name} pārvērta %{target} kontu par atmiņas lapu" promote_user_html: "%{name} paaugstināja lietotāju %{target}" publish_terms_of_service_html: "%{name} padarīja pieejamus pakalpojuma izmantošanas noteikumu atjauninājumus" - reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma iebildumu no %{target}" + reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma pārsūdzību no %{target}" reject_user_html: "%{name} noraidīja reģistrēšanos no %{target}" remove_avatar_user_html: "%{name} noņēma %{target} profila attēlu" reopen_report_html: "%{name} atkārtoti atvēra ziņojumu %{target}" @@ -560,7 +560,7 @@ lv: instance_languages_dimension: Populārākās valodas instance_media_attachments_measure: saglabātie multivides pielikumi instance_reports_measure: ziņojumi par viņiem - instance_statuses_measure: saglabātās ziņas + instance_statuses_measure: saglabātie ieraksti delivery: all: Visas clear: Notīrīt piegādes kļūdas @@ -625,7 +625,7 @@ lv: disable: Atspējot disabled: Atspējots enable: Iespējot - enable_hint: Kad tas būs iespējots, tavs serveris abonēs visas publiskās ziņas no šī releja un sāks tam sūtīt šī servera publiskās ziņas. + enable_hint: Tiklīdz iespējots, serveris abonēs visus šī releja publiskos ierakstus un sāks tam sūtīt šī iservera publiskos ierakstus. enabled: Iespējots inbox_url: Releja URL pending: Gaida apstiprinājumu no releja @@ -709,7 +709,7 @@ lv: silence_html: 'Jūs gatavojaties ierobežot @%{acct} kontu. Tas:' suspend_html: 'Jūs gatavojaties apturēt @%{acct} kontu. Tas:' actions: - delete_html: Noņemt aizskarošās ziņas + delete_html: Noņemt aizskarošos ierakstus mark_as_sensitive_html: Atzīmēt aizskarošo ierakstu informācijas nesējus kā jūtīgus silence_html: Ievērojami ierobežo @%{acct} sasniedzamību, padarot viņa profilu un saturu redzamu tikai cilvēkiem, kas jau seko tam vai pašrocīgi uzmeklē profilu suspend_html: Apturēt @%{acct}, padarot viņu profilu un saturu nepieejamu un neiespējamu mijiedarbību ar @@ -720,7 +720,7 @@ lv: record_strike_html: Ierakstiet brīdinājumu pret @%{acct}, lai palīdzētu jums izvērst turpmākus pārkāpumus no šī konta send_email_html: Nosūtīt @%{acct} brīdinājuma e-pasta ziņojumu warning_placeholder: Izvēles papildu pamatojums satura pārraudzības darbībai. - target_origin: Ziņotā konta izcelsme + target_origin: Konta, par kuru ziņots, izcelsme title: Ziņojumi unassign: Atsaukt unknown_action_msg: 'Nezināms konts: %{action}' @@ -882,12 +882,12 @@ lv: title: Multivide metadata: Metadati no_history: Šis ieraksts nav bijis labots - no_status_selected: Neviena ziņa netika mainīta, jo neviena netika atlasīta + no_status_selected: Neviens ieraksts netika mainīts, jo nekas netika atlasīts open: Atvērt ziņu - original_status: Oriģinālā ziņa + original_status: Sākotnējais ieraksts reblogs: Reblogi replied_to_html: Atbildēja %{acct_link} - status_changed: Ziņa mainīta + status_changed: Ieraksts izmainīts status_title: Publicēja @%{name} title: Konta ieraksti - @%{name} trending: Aktuāli @@ -1983,6 +1983,7 @@ lv: action: Konta iestatījumi explanation: Pārsūdzība par brīdinājumu Tavam kontam %{strike_date}, ko iesniedzi %{appeal_date}, ir apstiprināta. Tavs konts atkal ir labā stāvoklī. subject: Tava %{date} iesniegtā pārsūdzība tika apstiprināta + subtitle: Tavs konts atkal ir labā stāvoklī. title: Apelācija apstiprināta appeal_rejected: explanation: Pārsūdzība par brīdinājumu Tavam kontam %{strike_date}, ko iesniedzi %{appeal_date}, tika noraidīta. @@ -2010,6 +2011,7 @@ lv: terms_of_service_changed: agreement: Ar %{domain} izmantošanas tuprināšanu tiek piekrists šiem noteikumiem. Ja ir iebildumi pret atjauninātajiem noteikumiem, savu piekrišanu var atcelt jebkurā laikā ar sava konta izdzēšanu. changelog: 'Šeit īsumā ir aprakstīts, ko šis atjauninājums nozīmē:' + description: 'Šis e-pasta ziņojums tika saņemts, jo mēs veicam dažas izmaiņas savos pakalpojuma izmantošanas noteikumos %{domain}. Šie atjauninājumi stāsies spēkā %{date}. Mēs aicinām pārskatīt pilnus atjauninātos noteikumus šeit:' sign_off: "%{domain} komanda" subject: Mūsu pakalpojuma izmantošanas noteikumu atjauninājumi subtitle: Mainās %{domain} pakalpojuma izmantošanas noteikumi diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 8c06332695..1f01f622f5 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -498,6 +498,7 @@ ru: fasp: providers: sign_in: + status: Пост follow_recommendations: description_html: "Следуйте рекомендациям, чтобы помочь новым пользователям быстро находить интересный контент. Если пользователь не взаимодействовал с другими в достаточной степени, чтобы сформировать персонализированные рекомендации, вместо этого рекомендуется использовать эти учетные записи. Они пересчитываются на ежедневной основе на основе комбинации аккаунтов с наибольшим количеством недавних взаимодействий и наибольшим количеством местных подписчиков для данного языка." language: Для языка diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 0c362b0a30..287ce36a5d 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -25,7 +25,7 @@ lv: type_html: Izvēlies, ko darīt ar %{acct} types: disable: Neļauj lietotājam izmantot savu kontu, bet neizdzēs vai neslēp tā saturu. - none: Izmanto šo, lai nosūtītu lietotājam brīdinājumu, neradot nekādas citas darbības. + none: Šis ir izmantojams, lai nosūtītu lietotājam brīdinājumu bez jebkādu citu darbību izraisīšanas. sensitive: Visus šī lietotāja informācijas nesēju pielikumus uzspiesti atzīmēt kā jūtīgus. silence: Neļaut lietotājam veikt ierakstus ar publisku redzamību, paslēpt viņa ierakstus un paziņojumus no cilvēkiem, kas tam neseko. Tiek aizvērti visi ziņojumi par šo kontu. suspend: Novērs jebkādu mijiedarbību no šī konta vai uz to un dzēs tā saturu. Atgriežams 30 dienu laikā. Tiek aizvērti visi šī konta pārskati. @@ -45,8 +45,8 @@ lv: context: Viens vai vairāki konteksti, kur jāpiemēro filtrs current_password: Drošības nolūkos, lūdzu, ievadi pašreizējā konta paroli current_username: Lai apstiprinātu, lūdzu, ievadi pašreizējā konta paroli - digest: Tiek nosūtīts tikai pēc ilgstošas bezdarbības un tikai tad, ja savas prombūtnes laikā esi saņēmis jebkādas personīgas ziņas - email: Tev tiks nosūtīts apstiprinājuma e-pasts + digest: Tiek nosūtīts tikai pēc ilgstošas bezdarbības un tikai tad, ja savas prombūtnes laikā saņēmi jebkādas personīgas ziņas + email: Tev tiks nosūtīts apstiprinājuma e-pasta ziņojums header: WEBP, PNG, GIF vai JPG. Ne vairāk kā %{size}. Tiks samazināts līdz %{dimensions}px inbox_url: Nokopē URL no tā releja sākumlapas, kuru vēlies izmantot irreversible: Filtrētās ziņas neatgriezeniski pazudīs, pat ja filtrs vēlāk tiks noņemts @@ -125,7 +125,7 @@ lv: hint: Izvēles. Sniedz vairāk informācijas par noteikumu text: Jāapraksta nosacījums vai prasība šī servera lietotājiem. Jāmēģina to veidot īsu un vienkāršu sessions: - otp: 'Jāievada tālruņa lietotnes izveidots divpakāpju kods vai jāizmanto viens no saviem atkopes kodie:' + otp: 'Jāievada tālruņa lietotnes izveidots divpakāpju kods vai jāizmanto viens no saviem atkopes kodiem:' webauthn: Ja tā ir USB atslēga, noteikti ievieto to un, ja nepieciešams, pieskaries tai. settings: indexable: Tava profila lapa var tikt parādīta Google, Bing un citu meklēšanas dzinēju rezultātos. @@ -213,7 +213,7 @@ lv: max_uses: Maksimālais lietojumu skaits new_password: Jauna parole note: Par sevi - otp_attempt: Divfaktoru kods + otp_attempt: Divpakāpju kods password: Parole phrase: Atslēgvārds vai frāze setting_advanced_layout: Iespējot paplašināto tīmekļa saskarni From 23edac59ec33c9a4e6d48c4ebd9f7412cbaef42f Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 11 Apr 2025 11:28:25 +0200 Subject: [PATCH 42/48] Fix dropdown menus not working on mobile (#34428) --- .../mastodon/components/dropdown_menu.tsx | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/javascript/mastodon/components/dropdown_menu.tsx b/app/javascript/mastodon/components/dropdown_menu.tsx index a5d2deaae1..fc3e9e1321 100644 --- a/app/javascript/mastodon/components/dropdown_menu.tsx +++ b/app/javascript/mastodon/components/dropdown_menu.tsx @@ -354,6 +354,28 @@ export const Dropdown = ({ dispatch(closeDropdownMenu({ id: currentId })); }, [dispatch, currentId]); + const handleItemClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const i = Number(e.currentTarget.getAttribute('data-index')); + const item = items?.[i]; + + handleClose(); + + if (!item) { + return; + } + + if (typeof onItemClick === 'function') { + e.preventDefault(); + onItemClick(item, i); + } else if (isActionItem(item)) { + e.preventDefault(); + item.action(); + } + }, + [handleClose, onItemClick, items], + ); + const handleClick = useCallback( (e: React.MouseEvent | React.KeyboardEvent) => { const { type } = e; @@ -374,7 +396,7 @@ export const Dropdown = ({ modalProps: { status, actions: items, - onClick: onItemClick, + onClick: handleItemClick, }, }), ); @@ -394,7 +416,7 @@ export const Dropdown = ({ currentId, scrollKey, onOpen, - onItemClick, + handleItemClick, open, status, items, @@ -434,28 +456,6 @@ export const Dropdown = ({ [handleClick], ); - const handleItemClick = useCallback( - (e: React.MouseEvent | React.KeyboardEvent) => { - const i = Number(e.currentTarget.getAttribute('data-index')); - const item = items?.[i]; - - handleClose(); - - if (!item) { - return; - } - - if (typeof onItemClick === 'function') { - e.preventDefault(); - onItemClick(item, i); - } else if (isActionItem(item)) { - e.preventDefault(); - item.action(); - } - }, - [handleClose, onItemClick, items], - ); - useEffect(() => { return () => { if (currentId === openDropdownId) { From 720889cc97e05944abe1b0f83c52722b98a71222 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 11:28:44 +0200 Subject: [PATCH 43/48] fix(deps): update dependency dotenv to v16.5.0 (#34425) 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 1568040692..5ad52872a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7678,9 +7678,9 @@ __metadata: linkType: hard "dotenv@npm:^16.0.3": - version: 16.4.7 - resolution: "dotenv@npm:16.4.7" - checksum: 10c0/be9f597e36a8daf834452daa1f4cc30e5375a5968f98f46d89b16b983c567398a330580c88395069a77473943c06b877d1ca25b4afafcdd6d4adb549e8293462 + version: 16.5.0 + resolution: "dotenv@npm:16.5.0" + checksum: 10c0/5bc94c919fbd955bf0ba44d33922a1e93d1078e64a1db5c30faeded1d996e7a83c55332cb8ea4fae5a9ca4d0be44cbceb95c5811e70f9f095298df09d1997dd9 languageName: node linkType: hard From 5bf6b826253758778bbda886d3e327698b26809f Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 11 Apr 2025 11:35:36 +0200 Subject: [PATCH 44/48] Fix editing and redrafting polls (#34430) --- app/javascript/mastodon/reducers/compose.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 73468c04fe..330dcd93d0 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -491,9 +491,9 @@ export const composeReducer = (state = initialState, action) => { if (action.status.get('poll')) { map.set('poll', ImmutableMap({ - options: action.status.getIn(['poll', 'options']).map(x => x.get('title')), - multiple: action.status.getIn(['poll', 'multiple']), - expires_in: expiresInFromExpiresAt(action.status.getIn(['poll', 'expires_at'])), + options: ImmutableList(action.status.get('poll').options.map(x => x.title)), + multiple: action.status.get('poll').multiple, + expires_in: expiresInFromExpiresAt(action.status.get('poll').expires_at), })); } }); @@ -520,9 +520,9 @@ export const composeReducer = (state = initialState, action) => { if (action.status.get('poll')) { map.set('poll', ImmutableMap({ - options: action.status.getIn(['poll', 'options']).map(x => x.get('title')), - multiple: action.status.getIn(['poll', 'multiple']), - expires_in: expiresInFromExpiresAt(action.status.getIn(['poll', 'expires_at'])), + options: ImmutableList(action.status.get('poll').options.map(x => x.title)), + multiple: action.status.get('poll').multiple, + expires_in: expiresInFromExpiresAt(action.status.get('poll').expires_at), })); } }); From eb695e6b1770d467efed10cc73d5284b46ea9475 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 11:43:58 +0200 Subject: [PATCH 45/48] chore(deps): update dependency dotenv to v3.1.8 (#34417) 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 86cfaa3132..1ed4b71318 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -201,7 +201,7 @@ GEM domain_name (0.6.20240107) doorkeeper (5.8.2) railties (>= 5) - dotenv (3.1.7) + dotenv (3.1.8) drb (2.2.1) elasticsearch (7.17.11) elasticsearch-api (= 7.17.11) From 00cd218741775af5bb068d4bf61da8ae8853c209 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 11 Apr 2025 11:52:23 +0200 Subject: [PATCH 46/48] Add paragraph to tell admins that email announcements cannot be opted out (#34411) --- app/views/admin/announcements/previews/show.html.haml | 2 ++ config/locales/en.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/app/views/admin/announcements/previews/show.html.haml b/app/views/admin/announcements/previews/show.html.haml index fdfbf598b5..54d5d45ed6 100644 --- a/app/views/admin/announcements/previews/show.html.haml +++ b/app/views/admin/announcements/previews/show.html.haml @@ -7,6 +7,8 @@ = material_symbol 'chevron_left' = t('admin.announcements.back') +.flash-message.info= t('admin.announcements.preview.disclaimer') + %p.lead = t('admin.announcements.preview.explanation_html', count: @user_count, display_count: number_with_delimiter(@user_count)) diff --git a/config/locales/en.yml b/config/locales/en.yml index 4c5e1466f7..f0e1f86c4e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -319,6 +319,7 @@ en: create: Create announcement title: New announcement preview: + disclaimer: As users cannot opt out of them, email notifications should be limited to important announcements such as personal data breach or server closure notifications. explanation_html: 'The email will be sent to %{display_count} users. The following text will be included in the e-mail:' title: Preview announcement notification publish: Publish From a296facdea884cc828999c9f9be0f4bc83afe68d Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 11 Apr 2025 12:47:05 +0200 Subject: [PATCH 47/48] Fix empty menu section in status dropdown (#34431) --- app/javascript/mastodon/components/status_action_bar.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 344524f8be..25116d19b0 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -274,10 +274,9 @@ class StatusActionBar extends ImmutablePureComponent { if (writtenByMe && pinnableStatus) { menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); + menu.push(null); } - menu.push(null); - if (writtenByMe || withDismiss) { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); From a9cfaa6eed31c3d73094f585f9ab7fac9f3a28a8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 11 Apr 2025 12:50:46 +0200 Subject: [PATCH 48/48] Add dropdown menu to hashtag links in web UI (#34393) --- .../mastodon/components/dropdown_menu.tsx | 51 ++++-- .../components/edited_timestamp/index.tsx | 4 +- .../mastodon/components/hashtag_bar.tsx | 17 +- .../mastodon/components/status_content.jsx | 1 + .../ui/components/hashtag_menu_controller.tsx | 157 ++++++++++++++++++ app/javascript/mastodon/features/ui/index.jsx | 2 + app/javascript/mastodon/locales/en.json | 3 + 7 files changed, 213 insertions(+), 22 deletions(-) create mode 100644 app/javascript/mastodon/features/ui/components/hashtag_menu_controller.tsx diff --git a/app/javascript/mastodon/components/dropdown_menu.tsx b/app/javascript/mastodon/components/dropdown_menu.tsx index fc3e9e1321..886d517fa9 100644 --- a/app/javascript/mastodon/components/dropdown_menu.tsx +++ b/app/javascript/mastodon/components/dropdown_menu.tsx @@ -71,6 +71,8 @@ type RenderItemFn = ( }, ) => React.ReactNode; +type ItemClickFn = (item: Item, index: number) => void; + type RenderHeaderFn = (items: Item[]) => React.ReactNode; interface DropdownMenuProps { @@ -81,10 +83,10 @@ interface DropdownMenuProps { openedViaKeyboard: boolean; renderItem?: RenderItemFn; renderHeader?: RenderHeaderFn; - onItemClick: (e: React.MouseEvent | React.KeyboardEvent) => void; + onItemClick?: ItemClickFn; } -const DropdownMenu = ({ +export const DropdownMenu = ({ items, loading, scrollable, @@ -176,20 +178,35 @@ const DropdownMenu = ({ [], ); + const handleItemClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const i = Number(e.currentTarget.getAttribute('data-index')); + const item = items?.[i]; + + onClose(); + + if (!item) { + return; + } + + if (typeof onItemClick === 'function') { + e.preventDefault(); + onItemClick(item, i); + } else if (isActionItem(item)) { + e.preventDefault(); + item.action(); + } + }, + [onClose, onItemClick, items], + ); + const handleItemKeyUp = useCallback( (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { - onItemClick(e); + handleItemClick(e); } }, - [onItemClick], - ); - - const handleClick = useCallback( - (e: React.MouseEvent | React.KeyboardEvent) => { - onItemClick(e); - }, - [onItemClick], + [handleItemClick], ); const nativeRenderItem = (option: Item, i: number) => { @@ -209,7 +226,7 @@ const DropdownMenu = ({ element = (
    diff --git a/app/javascript/mastodon/components/edited_timestamp/index.tsx b/app/javascript/mastodon/components/edited_timestamp/index.tsx index 770cf33f8c..4a33210199 100644 --- a/app/javascript/mastodon/components/edited_timestamp/index.tsx +++ b/app/javascript/mastodon/components/edited_timestamp/index.tsx @@ -36,11 +36,11 @@ export const EditedTimestamp: React.FC<{ }, [dispatch, statusId]); const handleItemClick = useCallback( - (_item: HistoryItem, i: number) => { + (_item: HistoryItem, index: number) => { dispatch( openModal({ modalType: 'COMPARE_HISTORY', - modalProps: { index: i, statusId }, + modalProps: { index, statusId }, }), ); }, diff --git a/app/javascript/mastodon/components/hashtag_bar.tsx b/app/javascript/mastodon/components/hashtag_bar.tsx index 1642ba6504..4f88385bef 100644 --- a/app/javascript/mastodon/components/hashtag_bar.tsx +++ b/app/javascript/mastodon/components/hashtag_bar.tsx @@ -20,6 +20,7 @@ export type StatusLike = Record<{ contentHTML: string; media_attachments: List; spoiler_text?: string; + account: Record<{ id: string }>; }>; function normalizeHashtag(hashtag: string) { @@ -195,13 +196,19 @@ export function getHashtagBarForStatus(status: StatusLike) { return { statusContentProps, - hashtagBar: , + hashtagBar: ( + + ), }; } const HashtagBar: React.FC<{ hashtags: string[]; -}> = ({ hashtags }) => { + accountId: string; +}> = ({ hashtags, accountId }) => { const [expanded, setExpanded] = useState(false); const handleClick = useCallback(() => { setExpanded(true); @@ -218,7 +225,11 @@ const HashtagBar: React.FC<{ return (
    {revealedHashtags.map((hashtag) => ( - + #{hashtag} ))} diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index cc20888799..275fea5f0e 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -115,6 +115,7 @@ class StatusContent extends PureComponent { } else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) { link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false); link.setAttribute('href', `/tags/${link.text.replace(/^#/, '')}`); + link.setAttribute('data-menu-hashtag', this.props.status.getIn(['account', 'id'])); } else { link.setAttribute('title', link.href); link.classList.add('unhandled-link'); diff --git a/app/javascript/mastodon/features/ui/components/hashtag_menu_controller.tsx b/app/javascript/mastodon/features/ui/components/hashtag_menu_controller.tsx new file mode 100644 index 0000000000..6707b24672 --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/hashtag_menu_controller.tsx @@ -0,0 +1,157 @@ +import { useEffect, useRef, useState, useCallback, useMemo } from 'react'; + +import { useIntl, defineMessages } from 'react-intl'; + +import { useLocation } from 'react-router-dom'; + +import Overlay from 'react-overlays/Overlay'; +import type { + OffsetValue, + UsePopperOptions, +} from 'react-overlays/esm/usePopper'; + +import { DropdownMenu } from 'mastodon/components/dropdown_menu'; +import { useAppSelector } from 'mastodon/store'; + +const messages = defineMessages({ + browseHashtag: { + id: 'hashtag.browse', + defaultMessage: 'Browse posts in #{hashtag}', + }, + browseHashtagFromAccount: { + id: 'hashtag.browse_from_account', + defaultMessage: 'Browse posts from @{name} in #{hashtag}', + }, + muteHashtag: { id: 'hashtag.mute', defaultMessage: 'Mute #{hashtag}' }, +}); + +const offset = [5, 5] as OffsetValue; +const popperConfig = { strategy: 'fixed' } as UsePopperOptions; + +const isHashtagLink = ( + element: HTMLAnchorElement | null, +): element is HTMLAnchorElement => { + if (!element) { + return false; + } + + return element.matches('[data-menu-hashtag]'); +}; + +interface TargetParams { + hashtag?: string; + accountId?: string; +} + +export const HashtagMenuController: React.FC = () => { + const intl = useIntl(); + const [open, setOpen] = useState(false); + const [{ accountId, hashtag }, setTargetParams] = useState({}); + const targetRef = useRef(null); + const location = useLocation(); + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); + + useEffect(() => { + setOpen(false); + targetRef.current = null; + }, [setOpen, location]); + + useEffect(() => { + const handleClick = (e: MouseEvent) => { + const target = (e.target as HTMLElement).closest('a'); + + if (e.button !== 0 || e.ctrlKey || e.metaKey) { + return; + } + + if (!isHashtagLink(target)) { + return; + } + + const hashtag = target.text.replace(/^#/, ''); + const accountId = target.getAttribute('data-menu-hashtag'); + + if (!hashtag || !accountId) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + targetRef.current = target; + setOpen(true); + setTargetParams({ hashtag, accountId }); + }; + + document.addEventListener('click', handleClick, { capture: true }); + + return () => { + document.removeEventListener('click', handleClick); + }; + }, [setTargetParams, setOpen]); + + const handleClose = useCallback(() => { + setOpen(false); + targetRef.current = null; + }, [setOpen]); + + const menu = useMemo( + () => [ + { + text: intl.formatMessage(messages.browseHashtag, { + hashtag, + }), + to: `/tags/${hashtag}`, + }, + { + text: intl.formatMessage(messages.browseHashtagFromAccount, { + hashtag, + name: account?.username, + }), + to: `/@${account?.acct}/tagged/${hashtag}`, + }, + null, + { + text: intl.formatMessage(messages.muteHashtag, { + hashtag, + }), + href: '/filters', + dangerous: true, + }, + ], + [intl, hashtag, account], + ); + + if (!open) { + return null; + } + + return ( + + {({ props, arrowProps, placement }) => ( +
    +
    +
    + + +
    +
    + )} + + ); +}; diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index bb9720c17f..7c4f45721d 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -31,6 +31,7 @@ import initialState, { me, owner, singleUserMode, trendsEnabled, trendsAsLanding import BundleColumnError from './components/bundle_column_error'; import Header from './components/header'; import { UploadArea } from './components/upload_area'; +import { HashtagMenuController } from './components/hashtag_menu_controller'; import ColumnsAreaContainer from './containers/columns_area_container'; import LoadingBarContainer from './containers/loading_bar_container'; import ModalContainer from './containers/modal_container'; @@ -611,6 +612,7 @@ class UI extends PureComponent { {layout !== 'mobile' && } {!disableHoverCards && } + diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 0a0f043b4d..65a82feac6 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -381,6 +381,8 @@ "generic.saved": "Saved", "getting_started.heading": "Getting started", "hashtag.admin_moderation": "Open moderation interface for #{name}", + "hashtag.browse": "Browse posts in #{hashtag}", + "hashtag.browse_from_account": "Browse posts from @{name} in #{hashtag}", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -394,6 +396,7 @@ "hashtag.counter_by_uses": "{count, plural, one {{counter} post} other {{counter} posts}}", "hashtag.counter_by_uses_today": "{count, plural, one {{counter} post} other {{counter} posts}} today", "hashtag.follow": "Follow hashtag", + "hashtag.mute": "Mute #{hashtag}", "hashtag.unfollow": "Unfollow hashtag", "hashtags.and_other": "…and {count, plural, other {# more}}", "hints.profiles.followers_may_be_missing": "Followers for this profile may be missing.",