refactor(multiboards): remove time filter system end-to-end

Backend retention now keeps only recent posts, making the time filter UI
and newerThan filtering obsolete. Deleted use-time-filter hook, canonical
multiboard routes only, removed footer suggestions, dropped i18n keys.
This commit is contained in:
plebeius
2026-02-22 15:57:42 +08:00
parent f521bdbe33
commit 8e6d81ba59
46 changed files with 84 additions and 811 deletions
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "ترتيب حسب",
"subplebbit_offline_info": "قد يكون هذا المنتدى غير متصل وقد تفشل عملية النشر",
"posts_last_synced_info": "تمت مزامنة المشاركات آخر مرة {{time}}، قد يكون هذا المنتدى غير متصل وقد تفشل عملية النشر.",
"newer_than": "أحدث من",
"no_threads": "لا توجد مواضيع",
"hidden": "مخفي",
"save_options": "حفظ الخيارات",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "يرجى تحديد لوحة قبل النشر.",
"invalid_url_alert": "الرابط المقدم ليس عنوان URL صالحًا.",
"empty_comment_alert": "لا يمكن نشر تعليق فارغ.",
"more_threads_last_week": "{{count}} مواضيع منذ {{currentTimeFilterName}} — [<1>عرض المزيد من المواضيع من الأسبوع الماضي</1>]",
"more_threads_last_month": "{{count}} مواضيع منذ {{currentTimeFilterName}} — [<1>عرض المزيد من المواضيع من الشهر الماضي</1>]",
"newer_threads_available": "مواضيع أحدث متاحة — [<1>تحديث</1>]",
"stored_locally": "مُخزّن محليًا (في بيانات {{location}})، غير مُزامَن بين الأجهزة",
"choose_one": "اختر واحدة:",
@@ -191,7 +188,6 @@
"reset_changes": "إعادة تعيين التغييرات",
"crypto_address_yours": "عنوان العملة الرقمية ينتمي إلى هذا الحساب.",
"delete_wallet": "حذف المحفظة",
"last_bumped": "آخر رفع",
"fit_expanded_images_to_screen": "تغيير حجم الصور الموسعة لتناسب الشاشة",
"fit_expanded_images_to_screen_tip": "حدد الصور الموسعة لكل من عرض وارتفاع المتصفح",
"choose_file": "اختر ملف",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "مساعدة الفلاتر والإبرازات",
"filter_and_highlights": "التصفية والتسليط الضوء",
"boards_you_moderate": "المنتديات التي تقوم بالإشراف عليها",
"more_threads_last_year": "{{count}} مواضيع منذ {{currentTimeFilterName}} — [<1>عرض المزيد من المواضيع من السنة الماضية</1>]",
"moderator_of_this_board": "هذا المستخدم هو مشرف على هذا المنتدى",
"administrator_of_this_board": "هذا المستخدم هو مسؤول عن هذا المنتدى",
"copy_content_id": "نسخ معرف المحتوى",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "দ্বারা বাছাই করুন",
"subplebbit_offline_info": "এই বোর্ডটি অফলাইনে থাকতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে",
"posts_last_synced_info": "পোস্টগুলি শেষবার {{time}} সিঙ্ক করা হয়েছে, এই বোর্ডটি অফলাইনে থাকতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।",
"newer_than": "নতুন পরে",
"no_threads": "কোন থ্রেড নেই",
"hidden": "লুকানো",
"save_options": "অপশন সংরক্ষণ করুন",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "পোস্ট করার আগে একটি বোর্ড নির্বাচন করুন।",
"invalid_url_alert": "দেওয়া লিঙ্কটি একটি বৈধ URL নয়।",
"empty_comment_alert": "খালি মন্তব্য পোস্ট করা যাবে না।",
"more_threads_last_week": "{{count}} থ্রেড {{currentTimeFilterName}} থেকে — [<1>গত সপ্তাহের আরও থ্রেড দেখান</1>]",
"more_threads_last_month": "{{count}} থ্রেড {{currentTimeFilterName}} থেকে — [<1>গত মাসের আরও থ্রেড দেখান</1>]",
"newer_threads_available": "নতুন থ্রেড উপলব্ধ — [<1>রিফ্রেশ করুন</1>]",
"stored_locally": "স্থানীয়ভাবে সংরক্ষিত ({{location}} ডেটাতে), ডিভাইস জুড়ে সিঙ্ক হয় না",
"choose_one": "একটি নির্বাচন করুন:",
@@ -191,7 +188,6 @@
"reset_changes": "পরিবর্তনগুলি রিসেট করুন",
"crypto_address_yours": "ক্রিপ্টো ঠিকানা এই অ্যাকাউন্টের অংশ।",
"delete_wallet": "ওয়ালেট মুছুন",
"last_bumped": "শেষ.bump",
"fit_expanded_images_to_screen": "প্রসারিত ছবিগুলি স্ক্রীনে ফিট করুন",
"fit_expanded_images_to_screen_tip": "প্রসারিত ছবিগুলি ব্রাউজারের প্রস্থ এবং উচ্চতায় সীমাবদ্ধ করুন",
"choose_file": "ফাইল নির্বাচন করুন",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "ফিল্টার এবং হাইলাইট সাহায্য",
"filter_and_highlights": "ফিল্টার এবং হাইলাইট",
"boards_you_moderate": "আপনি যে বোর্ডগুলি পরিচালনা করেন",
"more_threads_last_year": "{{count}} থ্রেড {{currentTimeFilterName}} থেকে — [<1>গত বছরের আরও থ্রেড দেখান</1>]",
"moderator_of_this_board": "এই ব্যবহারকারী এই বোর্ডের একজন মডারেটর",
"administrator_of_this_board": "এই ব্যবহারকারী এই বোর্ডের একজন প্রশাসক",
"copy_content_id": "কনটেন্ট আইডি কপি করুন",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Řadit podle",
"subplebbit_offline_info": "Toto fórum může být offline a publikování může selhat",
"posts_last_synced_info": "Příspěvky naposledy synchronizovány {{time}}, toto fórum může být offline a publikování může selhat.",
"newer_than": "novější než",
"no_threads": "Žádná témata",
"hidden": "skrytý",
"save_options": "Uložit možnosti",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vyberte desku před odesláním.",
"invalid_url_alert": "Poskytnutý odkaz není platná adresa URL.",
"empty_comment_alert": "Nelze publikovat prázdný komentář.",
"more_threads_last_week": "{{count}} vláken od {{currentTimeFilterName}} — [<1>Ukázat více vláken z minulého týdne</1>]",
"more_threads_last_month": "{{count}} příspěvků od {{currentTimeFilterName}} — [<1>Zobrazit více příspěvků z minulého měsíce</1>]",
"newer_threads_available": "Novější vlákna k dispozici — [<1>Obnovit</1>]",
"stored_locally": "Ukládáno lokálně (v datech {{location}}), nesynchronizováno mezi zařízeními",
"choose_one": "Vyberte jednu:",
@@ -191,7 +188,6 @@
"reset_changes": "Obnovit změny",
"crypto_address_yours": "Adresa kryptoměny patří k tomuto účtu.",
"delete_wallet": "Smazat peněženku",
"last_bumped": "Poslední bump",
"fit_expanded_images_to_screen": "Přizpůsobit rozšířené obrázky obrazovce",
"fit_expanded_images_to_screen_tip": "Omezení rozšířených obrázků na šířku a výšku prohlížeče",
"choose_file": "Vyberte soubor",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Pomoc s filtry a zvýrazněním",
"filter_and_highlights": "Filtry a zvýraznění",
"boards_you_moderate": "Fóra, která moderujete",
"more_threads_last_year": "{{count}} příspěvků od {{currentTimeFilterName}} — [<1>Zobrazit více příspěvků z minulého roku</1>]",
"moderator_of_this_board": "Tento uživatel je moderátorem tohoto fóra",
"administrator_of_this_board": "Tento uživatel je administrátorem tohoto fóra",
"copy_content_id": "kopírovat ID obsahu",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sorter efter",
"subplebbit_offline_info": "Dette board kan være offline og publicering kan mislykkes",
"posts_last_synced_info": "Indlæg sidst synkroniseret {{time}}, dette board kan være offline og publicering kan mislykkes.",
"newer_than": "nyere end",
"no_threads": "Ingen tråde",
"hidden": "skjult",
"save_options": "Gem indstillinger",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vælg en tavle, før du poster.",
"invalid_url_alert": "Det angivne link er ikke en gyldig URL.",
"empty_comment_alert": "Kan ikke poste en tom kommentar.",
"more_threads_last_week": "{{count}} tråde siden {{currentTimeFilterName}} — [<1>Vis flere tråde fra sidste uge</1>]",
"more_threads_last_month": "{{count}} tråde siden {{currentTimeFilterName}} — [<1>Vis flere tråde fra sidste måned</1>]",
"newer_threads_available": "Nyere tråde tilgængelige — [<1>Opdater</1>]",
"stored_locally": "Lagres lokalt (i {{location}} data), ikke synkroniseret på tværs af enheder",
"choose_one": "Vælg en:",
@@ -191,7 +188,6 @@
"reset_changes": "Nulstil ændringer",
"crypto_address_yours": "Crypto-adresse tilhører denne konto.",
"delete_wallet": "Slet tegnebog",
"last_bumped": "Sidste bumpet",
"fit_expanded_images_to_screen": "Tilpas udvidede billeder til skærmen",
"fit_expanded_images_to_screen_tip": "Begræns udvidede billeder til både browserens bredde og højde",
"choose_file": "Vælg fil",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filtre og fremhævelser Hjælp",
"filter_and_highlights": "Filtre og fremhævninger",
"boards_you_moderate": "Boards du modererer",
"more_threads_last_year": "{{count}} tråde siden {{currentTimeFilterName}} — [<1>Vis flere tråde fra sidste år</1>]",
"moderator_of_this_board": "Denne bruger er moderator for dette board",
"administrator_of_this_board": "Denne bruger er administrator for dette board",
"copy_content_id": "kopier indhold-ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sortieren nach",
"subplebbit_offline_info": "Dieses Board könnte offline sein und die Veröffentlichung könnte fehlschlagen",
"posts_last_synced_info": "Beiträge zuletzt synchronisiert {{time}}, dieses Board könnte offline sein und die Veröffentlichung könnte fehlschlagen.",
"newer_than": "neuer als",
"no_threads": "Keine Threads",
"hidden": "versteckt",
"save_options": "Optionen speichern",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Bitte wählen Sie ein Board, bevor Sie posten.",
"invalid_url_alert": "Der bereitgestellte Link ist keine gültige URL.",
"empty_comment_alert": "Kann keinen leeren Kommentar posten.",
"more_threads_last_week": "{{count}} Threads seit {{currentTimeFilterName}} — [<1>Mehr Threads aus der letzten Woche anzeigen</1>]",
"more_threads_last_month": "{{count}} Threads seit {{currentTimeFilterName}} — [<1>Mehr Threads vom letzten Monat anzeigen</1>]",
"newer_threads_available": "Neuere Threads verfügbar — [<1>Aktualisieren</1>]",
"stored_locally": "Lokal gespeichert (in {{location}}-Daten), nicht zwischen Geräten synchronisiert",
"choose_one": "Wählen Sie eine:",
@@ -191,7 +188,6 @@
"reset_changes": "Änderungen zurücksetzen",
"crypto_address_yours": "Krypto-Adresse gehört zu diesem Konto.",
"delete_wallet": "Wallet löschen",
"last_bumped": "Zuletzt hochgeladen",
"fit_expanded_images_to_screen": "Erweiterte Bilder an den Bildschirm anpassen",
"fit_expanded_images_to_screen_tip": "Erweiterte Bilder auf die Breite und Höhe des Browsers beschränken",
"choose_file": "Datei auswählen",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filter- und Markierungs-Hilfe",
"filter_and_highlights": "Filter und Hervorhebungen",
"boards_you_moderate": "Boards, die Sie moderieren",
"more_threads_last_year": "{{count}} Threads seit {{currentTimeFilterName}} — [<1>Mehr Threads vom letzten Jahr anzeigen</1>]",
"moderator_of_this_board": "Dieser Benutzer ist Moderator dieses Boards",
"administrator_of_this_board": "Dieser Benutzer ist Administrator dieses Boards",
"copy_content_id": "Inhalts-ID kopieren",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Ταξινόμηση κατά",
"subplebbit_offline_info": "Αυτό το φόρουμ μπορεί να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει",
"posts_last_synced_info": "Οι δημοσιεύσεις συγχρονίστηκαν τελευταία {{time}}, αυτό το φόρουμ μπορεί να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.",
"newer_than": "πιο πρόσφατο από",
"no_threads": "Δεν υπάρχουν θέματα",
"hidden": "κρυφός",
"save_options": "Αποθήκευση επιλογών",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Παρακαλώ επιλέξτε μια κατηγορία πριν δημοσιεύσετε.",
"invalid_url_alert": "Ο παρεχόμενος σύνδεσμος δεν είναι έγκυρη διεύθυνση URL.",
"empty_comment_alert": "Δεν μπορεί να δημοσιευτεί κενό σχόλιο.",
"more_threads_last_week": "{{count}} θέματα από {{currentTimeFilterName}} — [<1>Εμφάνιση περισσότερων θεμάτων από την περασμένη εβδομάδα</1>]",
"more_threads_last_month": "{{count}} νήματα από {{currentTimeFilterName}} — [<1>Προβολή περισσότερων νημάτων από τον τελευταίο μήνα</1>]",
"newer_threads_available": "Διαθέσιμα νεότερα θέματα — [<1>Ανανέωση</1>]",
"stored_locally": "Αποθηκεύεται τοπικά (στα δεδομένα {{location}}), δεν συγχρονίζεται μεταξύ συσκευών",
"choose_one": "Επιλέξτε μία:",
@@ -191,7 +188,6 @@
"reset_changes": "Επαναφορά αλλαγών",
"crypto_address_yours": "Η διεύθυνση κρυπτονομίσματος ανήκει σε αυτόν τον λογαριασμό.",
"delete_wallet": "Διαγραφή πορτοφολιού",
"last_bumped": "Τελευταία ανύψωση",
"fit_expanded_images_to_screen": "Προσαρμόστε τις επεκταμένες εικόνες στην οθόνη",
"fit_expanded_images_to_screen_tip": "Περιορίστε τις επεκταμένες εικόνες τόσο στο πλάτος όσο και στο ύψος του προγράμματος περιήγησης",
"choose_file": "Επιλέξτε αρχείο",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Βοήθεια φίλτρων και επισήμανσης",
"filter_and_highlights": "Φίλτρα και Επισημάνσεις",
"boards_you_moderate": "Boards που διαχειρίζεστε",
"more_threads_last_year": "{{count}} νήματα από {{currentTimeFilterName}} — [<1>Προβολή περισσότερων νημάτων από το περασμένο έτος</1>]",
"moderator_of_this_board": "Αυτός ο χρήστης είναι συντονιστής αυτού του πίνακα",
"administrator_of_this_board": "Αυτός ο χρήστης είναι διαχειριστής αυτού του πίνακα",
"copy_content_id": "αντιγραφή ID περιεχομένου",
-5
View File
@@ -140,7 +140,6 @@
"sort_by": "Sort by",
"subplebbit_offline_info": "This board might be offline and publishing might fail",
"posts_last_synced_info": "Posts last synced {{time}}, this board might be offline and publishing might fail.",
"newer_than": "newer than",
"no_threads": "No threads",
"hidden": "hidden",
"save_options": "Save Options",
@@ -189,8 +188,6 @@
"no_board_selected_warning": "Please select a board before posting.",
"invalid_url_alert": "The provided link is not a valid URL.",
"empty_comment_alert": "Cannot post empty comment.",
"more_threads_last_week": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Week</1>]",
"more_threads_last_month": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Month</1>]",
"newer_threads_available": "Newer threads available — [<1>Refresh</1>]",
"stored_locally": "Stored locally (in {{location}} data), not synced across devices",
"choose_one": "Choose one:",
@@ -199,7 +196,6 @@
"reset_changes": "Reset Changes",
"crypto_address_yours": "Crypto address belongs to this account.",
"delete_wallet": "Delete Wallet",
"last_bumped": "Last Bumped",
"fit_expanded_images_to_screen": "Fit expanded images to screen",
"fit_expanded_images_to_screen_tip": "Limit expanded images to both browser width and height",
"choose_file": "Choose File",
@@ -230,7 +226,6 @@
"filter_and_highlights_help": "Filters & Highlights Help",
"filter_and_highlights": "Filters & Highlights",
"boards_you_moderate": "boards you moderate",
"more_threads_last_year": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Year</1>]",
"moderator_of_this_board": "This user is a moderator of this board",
"administrator_of_this_board": "This user is an administrator of this board",
"copy_content_id": "Copy content ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Ordenar por",
"subplebbit_offline_info": "Este tablero podría estar offline y la publicación podría fallar",
"posts_last_synced_info": "Publicaciones sincronizadas por última vez {{time}}, este tablero podría estar offline y la publicación podría fallar.",
"newer_than": "más reciente que",
"no_threads": "No hay hilos",
"hidden": "oculto",
"save_options": "Guardar opciones",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Por favor, selecciona una tabla antes de publicar.",
"invalid_url_alert": "El enlace proporcionado no es una URL válida.",
"empty_comment_alert": "No se puede publicar un comentario vacío.",
"more_threads_last_week": "{{count}} hilos desde {{currentTimeFilterName}} — [<1>Mostrar más hilos de la semana pasada</1>]",
"more_threads_last_month": "{{count}} hilos desde {{currentTimeFilterName}} — [<1>Ver más hilos del mes pasado</1>]",
"newer_threads_available": "Nuevos hilos disponibles — [<1>Actualizar</1>]",
"stored_locally": "Almacenado localmente (en datos de {{location}}), no sincronizado entre dispositivos",
"choose_one": "Elige uno:",
@@ -191,7 +188,6 @@
"reset_changes": "Restablecer cambios",
"crypto_address_yours": "La dirección de criptomoneda pertenece a esta cuenta.",
"delete_wallet": "Eliminar billetera",
"last_bumped": "Último bump",
"fit_expanded_images_to_screen": "Ajustar imágenes ampliadas a la pantalla",
"fit_expanded_images_to_screen_tip": "Limitar imágenes ampliadas tanto al ancho como a la altura del navegador",
"choose_file": "Elige archivo",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Ayuda de filtros y resaltes",
"filter_and_highlights": "Filtros y resaltados",
"boards_you_moderate": "tableros que moderas",
"more_threads_last_year": "{{count}} hilos desde {{currentTimeFilterName}} — [<1>Ver más hilos del año pasado</1>]",
"moderator_of_this_board": "Este usuario es moderador de este tablero",
"administrator_of_this_board": "Este usuario es administrador de este tablero",
"copy_content_id": "Copiar ID de contenido",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "مرتب‌سازی بر اساس",
"subplebbit_offline_info": "این انجمن ممکن است آفلاین باشد و انتشار ممکن است با شکست مواجه شود",
"posts_last_synced_info": "پست‌ها آخرین بار {{time}} همگام‌سازی شدند، این انجمن ممکن است آفلاین باشد و انتشار ممکن است با شکست مواجه شود.",
"newer_than": "جدیدتر از",
"no_threads": "هیچ موضوعی وجود ندارد",
"hidden": "مخفی",
"save_options": "ذخیره گزینه‌ها",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "لطفاً قبل از ارسال یک تابلو انتخاب کنید.",
"invalid_url_alert": "لینک ارائه شده یک URL معتبر نیست.",
"empty_comment_alert": "نمی‌توان نظر خالی ارسال کرد.",
"more_threads_last_week": "{{count}} موضوع از {{currentTimeFilterName}} — [<1>نمایش موضوعات بیشتر از هفته گذشته</1>]",
"more_threads_last_month": "{{count}} پست از {{currentTimeFilterName}} — [<1>نمایش بیشتر پست‌های ماه گذشته</1>]",
"newer_threads_available": "موضوعات جدیدتر در دسترس است — [<1>بروزرسانی</1>]",
"stored_locally": "ذخیرهٔ محلی (در دادهٔ {{location}})، هم‌گام‌سازی نشده در دستگاه‌ها",
"choose_one": "یکی را انتخاب کنید:",
@@ -191,7 +188,6 @@
"reset_changes": "بازنشانی تغییرات",
"crypto_address_yours": "آدرس رمزارز به این حساب تعلق دارد.",
"delete_wallet": "حذف کیف پول",
"last_bumped": "آخرین افزایش",
"fit_expanded_images_to_screen": "اندازه تصاویر بزرگ شده را به صفحه نمایش بکنید",
"fit_expanded_images_to_screen_tip": "اندازه تصاویر بزرگ شده را به عرض و ارتفاع مرورگر محدود کنید",
"choose_file": "فایل را انتخاب کنید",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "کمک فیلترها و برجسته‌ها",
"filter_and_highlights": "فیلترها و برجسته‌ها",
"boards_you_moderate": "تابلوهایی که مدیریت می‌کنید",
"more_threads_last_year": "{{count}} پست از {{currentTimeFilterName}} — [<1>نمایش بیشتر پست‌های سال گذشته</1>]",
"moderator_of_this_board": "این کاربر مدیر این انجمن است",
"administrator_of_this_board": "این کاربر مدیرکل این انجمن است",
"copy_content_id": "کپی شناسه محتوا",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Järjestä",
"subplebbit_offline_info": "Tämä taulu voi olla offline-tilassa ja julkaisu voi epäonnistua",
"posts_last_synced_info": "Viestit viimeksi synkronoitu {{time}}, tämä taulu voi olla offline-tilassa ja julkaisu voi epäonnistua.",
"newer_than": "uudempi kuin",
"no_threads": "Ei ketjuja",
"hidden": "piilotettu",
"save_options": "Tallenna asetukset",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Valitse taulu ennen julkaisemista.",
"invalid_url_alert": "Annettu linkki ei ole voimassa oleva URL.",
"empty_comment_alert": "Ei voi julkaista tyhjää kommenttia.",
"more_threads_last_week": "{{count}} ketjua sitten {{currentTimeFilterName}} — [<1>Näytä lisää ketjuja viime viikolta</1>]",
"more_threads_last_month": "{{count}} ketjua sitten {{currentTimeFilterName}} — [<1>Näytä lisää viime kuun ketjuja</1>]",
"newer_threads_available": "Uudemmat ketjut saatavilla — [<1>Virkistää</1>]",
"stored_locally": "Tallennettu paikallisesti ({{location}}-datassa), ei synkronoidu laitteiden välillä",
"choose_one": "Valitse yksi:",
@@ -191,7 +188,6 @@
"reset_changes": "Nollaa muutokset",
"crypto_address_yours": "Krypto-osoite kuuluu tähän tiliin.",
"delete_wallet": "Poista lompakko",
"last_bumped": "Viimeisin bump",
"fit_expanded_images_to_screen": "Sovita laajennettuja kuvia näyttöön",
"fit_expanded_images_to_screen_tip": "Rajoita laajennettuja kuvia sekä selaimen leveyteen että korkeuteen",
"choose_file": "Valitse tiedosto",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Suodattimet ja korostukset -apu",
"filter_and_highlights": "Suodattimet ja korostukset",
"boards_you_moderate": "lautakunnat, joita valvot",
"more_threads_last_year": "{{count}} ketjua sitten {{currentTimeFilterName}} — [<1>Näytä lisää viime vuoden ketjuja</1>]",
"moderator_of_this_board": "Tämä käyttäjä on tämän taulun moderaattori",
"administrator_of_this_board": "Tämä käyttäjä on tämän taulun järjestelmänvalvoja",
"copy_content_id": "kopioi sisältö-ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Ayusin ayon sa",
"subplebbit_offline_info": "Maaaring offline ang board na ito at maaaring mabigo ang pag-publish",
"posts_last_synced_info": "Huling na-sync ang mga post {{time}}, maaaring offline ang board na ito at maaaring mabigo ang pag-publish.",
"newer_than": "mas bago kaysa",
"no_threads": "Walang mga thread",
"hidden": "nakatago",
"save_options": "I-save ang mga Opsyon",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Mangyaring pumili ng board bago mag-post.",
"invalid_url_alert": "Ang ibinigay na link ay hindi isang wastong URL.",
"empty_comment_alert": "Hindi makapag-post ng walang laman na komento.",
"more_threads_last_week": "{{count}} mga thread mula sa {{currentTimeFilterName}} — [<1>Ipakita ang higit pang mga thread mula sa nakaraang linggo</1>]",
"more_threads_last_month": "{{count}} mga thread mula {{currentTimeFilterName}} — [<1>Ipakita ang higit pang mga thread mula noong nakaraang buwan</1>]",
"newer_threads_available": "Bagong mga thread na magagamit — [<1>I-refresh</1>]",
"stored_locally": "Naka-imbak nang lokal (sa datos ng {{location}}), hindi naka-sync sa mga device",
"choose_one": "Pumili ng isa:",
@@ -191,7 +188,6 @@
"reset_changes": "I-reset ang mga pagbabago",
"crypto_address_yours": "Ang crypto address ay nauugnay sa account na ito.",
"delete_wallet": "Tanggalin ang Wallet",
"last_bumped": "Huling bump",
"fit_expanded_images_to_screen": "I-adjust ang mga pinalawak na larawan sa screen",
"fit_expanded_images_to_screen_tip": "Limitahan ang mga pinalawak na larawan sa parehong lapad at taas ng browser",
"choose_file": "Pumili ng File",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Tulong sa mga filter at highlight",
"filter_and_highlights": "Mga filter at highlight",
"boards_you_moderate": "mga board na iyong minomoderate",
"more_threads_last_year": "{{count}} mga thread mula {{currentTimeFilterName}} — [<1>Ipakita ang higit pang mga thread mula noong nakaraang taon</1>]",
"moderator_of_this_board": "Ang user na ito ay moderator ng board na ito",
"administrator_of_this_board": "Ang user na ito ay administrator ng board na ito",
"copy_content_id": "kopyahin ang content ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Trier par",
"subplebbit_offline_info": "Ce forum pourrait être hors ligne et la publication pourrait échouer",
"posts_last_synced_info": "Publications synchronisées pour la dernière fois {{time}}, ce forum pourrait être hors ligne et la publication pourrait échouer.",
"newer_than": "plus récent que",
"no_threads": "Pas de fils",
"hidden": "caché",
"save_options": "Enregistrer les options",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Veuillez sélectionner un tableau avant de publier.",
"invalid_url_alert": "Le lien fourni n'est pas une URL valide.",
"empty_comment_alert": "Impossible de publier un commentaire vide.",
"more_threads_last_week": "{{count}} fils depuis {{currentTimeFilterName}} — [<1>Afficher plus de fils de la semaine dernière</1>]",
"more_threads_last_month": "{{count}} fils depuis {{currentTimeFilterName}} — [<1>Afficher plus de fils du mois dernier</1>]",
"newer_threads_available": "Nouveaux fils disponibles — [<1>Rafraîchir</1>]",
"stored_locally": "Stocké localement (dans les données {{location}}), non synchronisé entre les appareils",
"choose_one": "Choisissez-en un :",
@@ -191,7 +188,6 @@
"reset_changes": "Réinitialiser les modifications",
"crypto_address_yours": "L'adresse crypto appartient à ce compte.",
"delete_wallet": "Supprimer le portefeuille",
"last_bumped": "Dernière élévation",
"fit_expanded_images_to_screen": "Ajuster les images agrandies à l'écran",
"fit_expanded_images_to_screen_tip": "Limiter les images agrandies à la fois à la largeur et à la hauteur du navigateur",
"choose_file": "Choisissez un fichier",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Aide sur les filtres et surlignages",
"filter_and_highlights": "Filtres et surlignages",
"boards_you_moderate": "boards que vous modérez",
"more_threads_last_year": "{{count}} fils depuis {{currentTimeFilterName}} — [<1>Afficher plus de fils de l'année dernière</1>]",
"moderator_of_this_board": "Cet utilisateur est modérateur de ce tableau",
"administrator_of_this_board": "Cet utilisateur est administrateur de ce tableau",
"copy_content_id": "Copier l'ID du contenu",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "מיין לפי",
"subplebbit_offline_info": "פורום זה עשוי להיות לא מקוון והפרסום עלול להיכשל",
"posts_last_synced_info": "פוסטים סונכרנו לאחרונה {{time}}, פורום זה עשוי להיות לא מקוון והפרסום עלול להיכשל.",
"newer_than": "חדש יותר מ",
"no_threads": "אין נושאים",
"hidden": "מוסתר",
"save_options": "שמירת האפשרויות",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "אנא בחר לוח לפני פרסום.",
"invalid_url_alert": "הלינק שסופק אינו כתובת URL חוקית.",
"empty_comment_alert": "לא ניתן לפרסם תגובה ריקה.",
"more_threads_last_week": "{{count}} אשכולות מאז {{currentTimeFilterName}} — [<1>הצג עוד אשכולות מהשבוע שעבר</1>]",
"more_threads_last_month": "{{count}} חוטים מאז {{currentTimeFilterName}} — [<1>הצג עוד חוטים מהחודש שעבר</1>]",
"newer_threads_available": "נושאים חדשים זמינים — [<1>רענן</1>]",
"stored_locally": "נשמר מקומית (בנתוני {{location}}), לא מסונכרן בין מכשירים",
"choose_one": "בחר אחת:",
@@ -191,7 +188,6 @@
"reset_changes": "איפוס שינויים",
"crypto_address_yours": "כתובת המטבע הקריפטוגרפי שייכת לחשבון זה.",
"delete_wallet": "מחק ארנק",
"last_bumped": "הבום האחרון",
"fit_expanded_images_to_screen": "התאם את התמונות המורחבות למסך",
"fit_expanded_images_to_screen_tip": "מגביל את התמונות המורחבות גם לרוחב וגם לגובה של הדפדפן",
"choose_file": "בחר קובץ",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "עזרה במסננים והדגשות",
"filter_and_highlights": "מסננים והדגשות",
"boards_you_moderate": "לוחות שאתה מפקח עליהם",
"more_threads_last_year": "{{count}} חוטים מאז {{currentTimeFilterName}} — [<1>הצג עוד חוטים מהשנה שעברה</1>]",
"moderator_of_this_board": "משתמש זה הוא מנהל של הלוח הזה",
"administrator_of_this_board": "משתמש זה הוא מנהל מערכת של הלוח הזה",
"copy_content_id": "העתק מזהה תוכן",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "क्रमबद्ध करें द्वारा",
"subplebbit_offline_info": "यह बोर्ड ऑफ़लाइन हो सकता है और प्रकाशन विफल हो सकता है",
"posts_last_synced_info": "पोस्ट अंतिम बार {{time}} सिंक की गईं, यह बोर्ड ऑफ़लाइन हो सकता है और प्रकाशन विफल हो सकता है।",
"newer_than": "से नई",
"no_threads": "कोई थ्रेड नहीं है",
"hidden": "छिपा हुआ",
"save_options": "विकल्प सहेजें",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "पोस्ट करने से पहले कृपया एक बोर्ड चुनें।",
"invalid_url_alert": "प्रदत्त लिंक एक वैध URL नहीं है।",
"empty_comment_alert": "खाली टिप्पणी पोस्ट नहीं कर सकते।",
"more_threads_last_week": "{{count}} थ्रेड {{currentTimeFilterName}} से — [<1>पिछले सप्ताह के और थ्रेड दिखाएं</1>]",
"more_threads_last_month": "{{count}} थ्रेड्स {{currentTimeFilterName}} से — [<1>अगले महीने के अधिक थ्रेड्स दिखाएं</1>]",
"newer_threads_available": "नए थ्रेड्स उपलब्ध हैं — [<1>रिफ्रेश करें</1>]",
"stored_locally": "स्थानीय रूप से संग्रहीत ({{location}} डेटा में), डिवाइस पर सिंक नहीं",
"choose_one": "एक चुनें:",
@@ -191,7 +188,6 @@
"reset_changes": "परिवर्तन रीसेट करें",
"crypto_address_yours": "क्रिप्टो पता इस खाते से संबंधित है।",
"delete_wallet": "वॉलेट हटाएं",
"last_bumped": "अंतिम बंप",
"fit_expanded_images_to_screen": "विस्तृत चित्रों को स्क्रीन के अनुसार ढालें",
"fit_expanded_images_to_screen_tip": "विस्तृत चित्रों को ब्राउज़र की चौड़ाई और ऊंचाई दोनों तक सीमित करें",
"choose_file": "फाइल चुनें",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "फ़िल्टर और हाइलाइट्स सहायता",
"filter_and_highlights": "फ़िल्टर और हाइलाइट्स",
"boards_you_moderate": "बोर्ड जो आप मॉडरेट करते हैं",
"more_threads_last_year": "{{count}} थ्रेड्स {{currentTimeFilterName}} से — [<1>पिछले साल के अधिक थ्रेड्स दिखाएं</1>]",
"moderator_of_this_board": "यह उपयोगकर्ता इस बोर्ड का मॉडरेटर है",
"administrator_of_this_board": "यह उपयोगकर्ता इस बोर्ड का प्रशासक है",
"copy_content_id": "कंटेंट ID कॉपी करें",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Rendezés",
"subplebbit_offline_info": "Ez a fórum offline lehet és a közzététel sikertelen lehet",
"posts_last_synced_info": "Hozzászólások utoljára szinkronizálva {{time}}, ez a fórum offline lehet és a közzététel sikertelen lehet.",
"newer_than": "újabb, mint",
"no_threads": "Nincsenek témák",
"hidden": "rejtett",
"save_options": "Beállítások mentése",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Kérlek, válassz egy táblát a közzététel előtt.",
"invalid_url_alert": "A megadott hivatkozás nem érvényes URL.",
"empty_comment_alert": "Üres hozzászólást nem lehet közzétenni.",
"more_threads_last_week": "{{count}} szál a {{currentTimeFilterName}} óta — [<1>Mutass több szálat a múlt héten</1>]",
"more_threads_last_month": "{{count}} szál {{currentTimeFilterName}} óta — [<1>Több szál megjelenítése a múlt hónapból</1>]",
"newer_threads_available": "Újabb szálak elérhetők — [<1>Frissíteni</1>]",
"stored_locally": "Helyileg tárolva (a {{location}} adatában), nem szinkronizálva az eszközök között",
"choose_one": "Válasszon egyet:",
@@ -191,7 +188,6 @@
"reset_changes": "Változások visszaállítása",
"crypto_address_yours": "A kripto-cím ehhez a fiókhoz tartozik.",
"delete_wallet": "Tárca törlése",
"last_bumped": "Utolsó bump",
"fit_expanded_images_to_screen": "Illeszkedjen a kibővített képekhez a képernyőhöz",
"fit_expanded_images_to_screen_tip": "A kibővített képeket korlátozza a böngésző szélességére és magasságára",
"choose_file": "Válassza ki a fájlt",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Szűrők és kiemelések súgó",
"filter_and_highlights": "Szűrők és kiemelések",
"boards_you_moderate": "boardok, amelyeket moderálsz",
"more_threads_last_year": "{{count}} szál {{currentTimeFilterName}} óta — [<1>Több szál megjelenítése a múlt évből</1>]",
"moderator_of_this_board": "Ez a felhasználó ennek a táblának a moderátora",
"administrator_of_this_board": "Ez a felhasználó ennek a táblának a rendszergazdája",
"copy_content_id": "tartalom ID másolása",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Urutkan berdasarkan",
"subplebbit_offline_info": "Papan ini mungkin offline dan publikasi mungkin gagal",
"posts_last_synced_info": "Posting terakhir disinkronkan {{time}}, papan ini mungkin offline dan publikasi mungkin gagal.",
"newer_than": "baru daripada",
"no_threads": "Tidak ada thread",
"hidden": "tersembunyi",
"save_options": "Simpan Opsi",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Silakan pilih papan sebelum memposting.",
"invalid_url_alert": "Tautan yang diberikan bukan URL yang valid.",
"empty_comment_alert": "Tidak dapat memposting komentar kosong.",
"more_threads_last_week": "{{count}} thread sejak {{currentTimeFilterName}} — [<1>Show lebih banyak thread dari minggu lalu</1>]",
"more_threads_last_month": "{{count}} thread sejak {{currentTimeFilterName}} — [<1>Tampilkan lebih banyak thread dari bulan lalu</1>]",
"newer_threads_available": "Thread terbaru tersedia — [<1>Segarkan</1>]",
"stored_locally": "Disimpan secara lokal (dalam data {{location}}), tidak disinkronkan antar perangkat",
"choose_one": "Pilih satu:",
@@ -191,7 +188,6 @@
"reset_changes": "Atur Ulang Perubahan",
"crypto_address_yours": "Alamat kripto milik akun ini.",
"delete_wallet": "Hapus Dompet",
"last_bumped": "Terakhir bump",
"fit_expanded_images_to_screen": "Sesuaikan gambar yang diperluas ke layar",
"fit_expanded_images_to_screen_tip": "Batasi gambar yang diperluas baik pada lebar maupun tinggi browser",
"choose_file": "Pilih Berkas",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Bantuan Filter dan Sorotan",
"filter_and_highlights": "Filter dan Sorotan",
"boards_you_moderate": "board yang Anda moderasi",
"more_threads_last_year": "{{count}} thread sejak {{currentTimeFilterName}} — [<1>Tampilkan lebih banyak thread dari tahun lalu</1>]",
"moderator_of_this_board": "Pengguna ini adalah moderator papan ini",
"administrator_of_this_board": "Pengguna ini adalah administrator papan ini",
"copy_content_id": "salin ID konten",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Ordina per",
"subplebbit_offline_info": "Questa bacheca potrebbe essere offline e la pubblicazione potrebbe fallire",
"posts_last_synced_info": "Post sincronizzati l'ultima volta {{time}}, questa bacheca potrebbe essere offline e la pubblicazione potrebbe fallire.",
"newer_than": "più recente di",
"no_threads": "Nessun thread",
"hidden": "nascosto",
"save_options": "Salva opzioni",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Per favore, seleziona una board prima di pubblicare.",
"invalid_url_alert": "Il link fornito non è un URL valido.",
"empty_comment_alert": "Impossibile pubblicare un commento vuoto.",
"more_threads_last_week": "{{count}} thread da {{currentTimeFilterName}} — [<1>Mostra più thread dalla scorsa settimana</1>]",
"more_threads_last_month": "{{count}} thread da {{currentTimeFilterName}} — [<1>Mostra altri thread del mese scorso</1>]",
"newer_threads_available": "Nuovi thread disponibili — [<1>Aggiorna</1>]",
"stored_locally": "Archiviato localmente (nei dati di {{location}}), non sincronizzato tra dispositivi",
"choose_one": "Scegline una:",
@@ -191,7 +188,6 @@
"reset_changes": "Ripristina Modifiche",
"crypto_address_yours": "L'indirizzo cripto appartiene a questo account.",
"delete_wallet": "Elimina Wallet",
"last_bumped": "Ultimo Bump",
"fit_expanded_images_to_screen": "Adatta le immagini espanse allo schermo",
"fit_expanded_images_to_screen_tip": "Limita le immagini espanse sia alla larghezza che all'altezza del browser",
"choose_file": "Scegli File",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Aiuto su Filtri e Evidenziazioni",
"filter_and_highlights": "Filtri e Evidenziazioni",
"boards_you_moderate": "board che moderi",
"more_threads_last_year": "{{count}} thread da {{currentTimeFilterName}} — [<1>Mostra altri thread dell'anno scorso</1>]",
"moderator_of_this_board": "Questo utente è moderatore di questa bacheca",
"administrator_of_this_board": "Questo utente è amministratore di questa bacheca",
"copy_content_id": "Copia ID contenuto",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "並べ替え",
"subplebbit_offline_info": "このボードはオフラインの可能性があり、公開が失敗する可能性があります",
"posts_last_synced_info": "投稿は最後に {{time}} に同期されました。このボードはオフラインの可能性があり、公開が失敗する可能性があります。",
"newer_than": "より新しい",
"no_threads": "スレッドはありません",
"hidden": "隠し",
"save_options": "オプションを保存",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "投稿する前にボードを選択してください。",
"invalid_url_alert": "提供されたリンクは有効なURLではありません。",
"empty_comment_alert": "空のコメントは投稿できません。",
"more_threads_last_week": "{{count}} スレッド {{currentTimeFilterName}} から — [<1>先週のスレッドをさらに表示</1>]",
"more_threads_last_month": "{{count}} スレッド {{currentTimeFilterName}} から — [<1>先月のスレッドをさらに表示</1>]",
"newer_threads_available": "新しいスレッドが利用可能 — [<1>更新</1>]",
"stored_locally": "ローカルに保存({{location}}のデータ内)、デバイス間で同期されません",
"choose_one": "いずれかを選択してください:",
@@ -191,7 +188,6 @@
"reset_changes": "変更をリセット",
"crypto_address_yours": "暗号通貨アドレスはこのアカウントに属しています。",
"delete_wallet": "ウォレットを削除",
"last_bumped": "最後のバンプ",
"fit_expanded_images_to_screen": "拡張された画像を画面に合わせる",
"fit_expanded_images_to_screen_tip": "拡張された画像をブラウザの幅と高さの両方に制限します",
"choose_file": "ファイルを選択",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "フィルターとハイライトのヘルプ",
"filter_and_highlights": "フィルターとハイライト",
"boards_you_moderate": "あなたが管理するボード",
"more_threads_last_year": "{{count}} スレッド {{currentTimeFilterName}} から — [<1>去年のスレッドをさらに表示</1>]",
"moderator_of_this_board": "このユーザーはこのボードのモデレーターです",
"administrator_of_this_board": "このユーザーはこのボードの管理者です",
"copy_content_id": "コンテンツIDをコピー",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "정렬 기준",
"subplebbit_offline_info": "이 게시판이 오프라인일 수 있으며 게시가 실패할 수 있습니다",
"posts_last_synced_info": "게시물이 마지막으로 {{time}}에 동기화되었습니다. 이 게시판이 오프라인일 수 있으며 게시가 실패할 수 있습니다.",
"newer_than": "이전보다 최신",
"no_threads": "스레드가 없습니다",
"hidden": "숨겨진",
"save_options": "옵션 저장",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "게시하기 전에 보드를 선택하십시오.",
"invalid_url_alert": "제공된 링크는 유효한 URL이 아닙니다.",
"empty_comment_alert": "빈 댓글을 게시할 수 없습니다.",
"more_threads_last_week": "{{count}} 스레드 {{currentTimeFilterName}} 이후 — [<1>지난 주의 더 많은 스레드 보기</1>]",
"more_threads_last_month": "{{count}} 스레드 {{currentTimeFilterName}} 이후 — [<1>지난 달의 스레드 더 보기</1>]",
"newer_threads_available": "새로운 스레드 사용 가능 — [<1>새로 고침</1>]",
"stored_locally": "로컬에 저장됨 ({{location}} 데이터 내), 기기 간 동기화되지 않음",
"choose_one": "하나를 선택하세요:",
@@ -191,7 +188,6 @@
"reset_changes": "변경 사항 초기화",
"crypto_address_yours": "암호 주소는이 계정에 속합니다.",
"delete_wallet": "지갑 삭제",
"last_bumped": "마지막 bump",
"fit_expanded_images_to_screen": "확장된 이미지를 화면에 맞추기",
"fit_expanded_images_to_screen_tip": "확장된 이미지를 브라우저의 너비와 높이로 제한합니다",
"choose_file": "파일 선택",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "필터 및 하이라이트 도움말",
"filter_and_highlights": "필터 및 하이라이트",
"boards_you_moderate": "당신이 관리하는 게시판",
"more_threads_last_year": "{{count}} 스레드 {{currentTimeFilterName}} 이후 — [<1>작년의 스레드 더 보기</1>]",
"moderator_of_this_board": "이 사용자는 이 게시판의 관리자입니다",
"administrator_of_this_board": "이 사용자는 이 게시판의 관리자입니다",
"copy_content_id": "콘텐츠 ID 복사",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "क्रमवार करा",
"subplebbit_offline_info": "हे बोर्ड ऑफलाइन असू शकते आणि प्रकाशन अयशस्वी होऊ शकते",
"posts_last_synced_info": "पोस्ट शेवटी {{time}} सिंक केल्या गेल्या, हे बोर्ड ऑफलाइन असू शकते आणि प्रकाशन अयशस्वी होऊ शकते.",
"newer_than": "नवीनतम आहे",
"no_threads": "कोणतेही थ्रेड्स नाहीत",
"hidden": "लपवलेले",
"save_options": "विकल्प साठवा",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "पोस्ट करण्यापूर्वी कृपया एक बोर्ड निवडा.",
"invalid_url_alert": "दिलेला लिंक वैध URL नाही.",
"empty_comment_alert": "रिक्त टिप्पणी पोस्ट करू शकत नाही.",
"more_threads_last_week": "{{count}} थ्रेड {{currentTimeFilterName}} पासून — [<1>गेल्या आठवड्यातील अधिक थ्रेड्स पहा</1>]",
"more_threads_last_month": "{{count}} ध糀ं {{currentTimeFilterName}} पासून — [<1>गेल्या महिन्यातील आणखी थ्रेड्स दाखवा</1>]",
"newer_threads_available": "नवीन थ्रेड्स उपलब्ध आहेत — [<1>रिफ्रेश करा</1>]",
"stored_locally": "स्थानिकरित्या संग्रहित ({{location}} डेटामध्ये), उपकरणांमध्ये समक्रमित नाही",
"choose_one": "एक निवडा:",
@@ -191,7 +188,6 @@
"reset_changes": "बदलांना रीसेट करा",
"crypto_address_yours": "क्रिप्टो पत्ता हा खात्याकडे संबंधित आहे.",
"delete_wallet": "वॉलेट हटवा",
"last_bumped": "अंतिम बंप",
"fit_expanded_images_to_screen": "विस्तृत प्रतिमा स्क्रीनवर फिट करा",
"fit_expanded_images_to_screen_tip": "विस्तृत प्रतिमांना ब्राउझरच्या रुंदी आणि उंचीवर मर्यादित करा",
"choose_file": "फाइल निवडा",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "फिल्टर आणि हायलाइट्स सहाय्य",
"filter_and_highlights": "फिल्टर आणि हायलाइट्स",
"boards_you_moderate": "तुम्ही ज्यांचे नियंत्रण करता अशा बोर्ड्स",
"more_threads_last_year": "{{count}} ध糀ं {{currentTimeFilterName}} पासून — [<1>गेल्या वर्षातील आणखी थ्रेड्स दाखवा</1>]",
"moderator_of_this_board": "हा वापरकर्ता या बोर्डचा मॉडरेटर आहे",
"administrator_of_this_board": "हा वापरकर्ता या बोर्डचा प्रशासक आहे",
"copy_content_id": "कंटेंट ID कॉपी करा",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sorteer op",
"subplebbit_offline_info": "Dit bord kan offline zijn en publiceren kan mislukken",
"posts_last_synced_info": "Berichten voor het laatst gesynchroniseerd {{time}}, dit bord kan offline zijn en publiceren kan mislukken.",
"newer_than": "nieuwer dan",
"no_threads": "Geen threads",
"hidden": "verborgen",
"save_options": "Opties opslaan",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Selecteer een bord voordat je plaatst.",
"invalid_url_alert": "De opgegeven link is geen geldige URL.",
"empty_comment_alert": "Kan geen lege opmerking plaatsen.",
"more_threads_last_week": "{{count}} threads sinds {{currentTimeFilterName}} — [<1>Toon meer threads van vorige week</1>]",
"more_threads_last_month": "{{count}} threads sinds {{currentTimeFilterName}} — [<1>Meer threads van afgelopen maand tonen</1>]",
"newer_threads_available": "Nieuwere threads beschikbaar — [<1>Vernieuwen</1>]",
"stored_locally": "Lokaal opgeslagen (in {{location}} gegevens), niet gesynchroniseerd tussen apparaten",
"choose_one": "Kies er een:",
@@ -191,7 +188,6 @@
"reset_changes": "Wijzigingen resetten",
"crypto_address_yours": "Crypto-adres behoort tot deze account.",
"delete_wallet": "Verwijder portemonnee",
"last_bumped": "Laatste bump",
"fit_expanded_images_to_screen": "Pas uitgebreide afbeeldingen aan het scherm aan",
"fit_expanded_images_to_screen_tip": "Beperk uitgebreide afbeeldingen tot zowel de breedte als de hoogte van de browser",
"choose_file": "Kies een bestand",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filters en Markeringen Help",
"filter_and_highlights": "Filters en markeringen",
"boards_you_moderate": "boards die je beheert",
"more_threads_last_year": "{{count}} threads sinds {{currentTimeFilterName}} — [<1>Meer threads van afgelopen jaar tonen</1>]",
"moderator_of_this_board": "Deze gebruiker is moderator van dit bord",
"administrator_of_this_board": "Deze gebruiker is beheerder van dit bord",
"copy_content_id": "kopieer inhoud-ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sorter etter",
"subplebbit_offline_info": "Dette brettet kan være offline og publisering kan mislykkes",
"posts_last_synced_info": "Innlegg sist synkronisert {{time}}, dette brettet kan være offline og publisering kan mislykkes.",
"newer_than": "nyere enn",
"no_threads": "Ingen tråder",
"hidden": "skjult",
"save_options": "Lagre alternativer",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vennligst velg et brett før du poster.",
"invalid_url_alert": "Den angitte lenken er ikke en gyldig URL.",
"empty_comment_alert": "Kan ikke poste tom kommentar.",
"more_threads_last_week": "{{count}} tråder siden {{currentTimeFilterName}} — [<1>Vis flere tråder fra forrige uke</1>]",
"more_threads_last_month": "{{count}} tråder siden {{currentTimeFilterName}} — [<1>Vis flere tråder fra forrige måned</1>]",
"newer_threads_available": "Nyere tråder tilgjengelig — [<1>Oppdater</1>]",
"stored_locally": "Lagres lokalt (i {{location}} data), ikke synkronisert på tvers av enheter",
"choose_one": "Velg en:",
@@ -191,7 +188,6 @@
"reset_changes": "Tilbakestill endringer",
"crypto_address_yours": "Crypto-adressen tilhører denne kontoen.",
"delete_wallet": "Slett lommebok",
"last_bumped": "Siste bumpet",
"fit_expanded_images_to_screen": "Tilpass utvidede bilder til skjermen",
"fit_expanded_images_to_screen_tip": "Begrens utvidede bilder til både nettleserens bredde og høyde",
"choose_file": "Velg fil",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filtre og fremhevinger Hjelp",
"filter_and_highlights": "Filtre og uthevinger",
"boards_you_moderate": "boards du modererer",
"more_threads_last_year": "{{count}} tråder siden {{currentTimeFilterName}} — [<1>Vis flere tråder fra forrige år</1>]",
"moderator_of_this_board": "Denne brukeren er moderator for dette tavlet",
"administrator_of_this_board": "Denne brukeren er administrator for dette tavlet",
"copy_content_id": "kopier innhold-ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sortuj według",
"subplebbit_offline_info": "To forum może być offline i publikacja może się nie powieść",
"posts_last_synced_info": "Posty ostatnio zsynchronizowane {{time}}, to forum może być offline i publikacja może się nie powieść.",
"newer_than": "nowsze niż",
"no_threads": "Brak wątków",
"hidden": "ukryty",
"save_options": "Zapisz opcje",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Proszę wybrać tablicę przed opublikowaniem.",
"invalid_url_alert": "Podany link nie jest poprawnym adresem URL.",
"empty_comment_alert": "Nie można opublikować pustego komentarza.",
"more_threads_last_week": "{{count}} wątki od {{currentTimeFilterName}} — [<1>Pokaż więcej wątków z zeszłego tygodnia</1>]",
"more_threads_last_month": "{{count}} wątki od {{currentTimeFilterName}} — [<1>Pokaż więcej wątków z zeszłego miesiąca</1>]",
"newer_threads_available": "Nowsze wątki dostępne — [<1>Odśwież</1>]",
"stored_locally": "Przechowywane lokalnie (w danych {{location}}), nie synchronizowane między urządzeniami",
"choose_one": "Wybierz jeden:",
@@ -191,7 +188,6 @@
"reset_changes": "Zresetuj zmiany",
"crypto_address_yours": "Adres kryptowaluty należy do tego konta.",
"delete_wallet": "Usuń portfel",
"last_bumped": "Ostatni bump",
"fit_expanded_images_to_screen": "Dopasuj rozszerzone obrazy do ekranu",
"fit_expanded_images_to_screen_tip": "Ogranicz rozszerzone obrazy do szerokości i wysokości przeglądarki",
"choose_file": "Wybierz plik",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Pomoc dotycząca filtrów i wyróżnień",
"filter_and_highlights": "Filtry i wyróżnienia",
"boards_you_moderate": "boards, które moderujesz",
"more_threads_last_year": "{{count}} wątki od {{currentTimeFilterName}} — [<1>Pokaż więcej wątków z zeszłego roku</1>]",
"moderator_of_this_board": "Ten użytkownik jest moderatorem tego forum",
"administrator_of_this_board": "Ten użytkownik jest administratorem tego forum",
"copy_content_id": "skopiuj ID treści",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Ordenar por",
"subplebbit_offline_info": "Este fórum pode estar offline e a publicação pode falhar",
"posts_last_synced_info": "Publicações sincronizadas pela última vez {{time}}, este fórum pode estar offline e a publicação pode falhar.",
"newer_than": "mais recente que",
"no_threads": "Sem tópicos",
"hidden": "escondido",
"save_options": "Salvar opções",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Por favor, selecione um quadro antes de postar.",
"invalid_url_alert": "O link fornecido não é uma URL válida.",
"empty_comment_alert": "Não é possível postar um comentário vazio.",
"more_threads_last_week": "{{count}} tópicos desde {{currentTimeFilterName}} — [<1>Mostrar mais tópicos da semana passada</1>]",
"more_threads_last_month": "{{count}} tópicos desde {{currentTimeFilterName}} — [<1>Mostrar mais tópicos do mês passado</1>]",
"newer_threads_available": "Novos tópicos disponíveis — [<1>Atualizar</1>]",
"stored_locally": "Armazenado localmente (nos dados de {{location}}), não sincronizado entre dispositivos",
"choose_one": "Escolha um:",
@@ -191,7 +188,6 @@
"reset_changes": "Redefinir Alterações",
"crypto_address_yours": "O endereço de criptomoeda pertence a esta conta.",
"delete_wallet": "Excluir carteira",
"last_bumped": "Último bump",
"fit_expanded_images_to_screen": "Ajustar imagens expandidas à tela",
"fit_expanded_images_to_screen_tip": "Limite imagens expandidas tanto à largura quanto à altura do navegador",
"choose_file": "Escolher arquivo",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Ajuda de Filtros e Realces",
"filter_and_highlights": "Filtros e Destaques",
"boards_you_moderate": "boards que você modera",
"more_threads_last_year": "{{count}} tópicos desde {{currentTimeFilterName}} — [<1>Mostrar mais tópicos do ano passado</1>]",
"moderator_of_this_board": "Este usuário é moderador deste quadro",
"administrator_of_this_board": "Este usuário é administrador deste quadro",
"copy_content_id": "Copiar ID do conteúdo",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sortează după",
"subplebbit_offline_info": "Acest forum poate fi offline și publicarea poate eșua",
"posts_last_synced_info": "Postări sincronizate ultima dată {{time}}, acest forum poate fi offline și publicarea poate eșua.",
"newer_than": "mai nou decât",
"no_threads": "Nu sunt subiecte",
"hidden": "ascuns",
"save_options": "Salvați opțiunile",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vă rugăm să selectați un tablou înainte de a publica.",
"invalid_url_alert": "Linkul furnizat nu este un URL valid.",
"empty_comment_alert": "Nu se poate publica un comentariu gol.",
"more_threads_last_week": "{{count}} fire de discuție de la {{currentTimeFilterName}} — [<1>Arată mai multe fire din săptămâna trecută</1>]",
"more_threads_last_month": "{{count}} subiecte din {{currentTimeFilterName}} — [<1>Afișați mai multe subiecte de luna trecută</1>]",
"newer_threads_available": "Subiecte mai noi disponibile — [<1>Actualizaţi</1>]",
"stored_locally": "Stocat local (în datele {{location}}), nesincronizat între dispozitive",
"choose_one": "Alege una:",
@@ -191,7 +188,6 @@
"reset_changes": "Resetează modificările",
"crypto_address_yours": "Adresa crypto aparține acestui cont.",
"delete_wallet": "Șterge portofelul",
"last_bumped": "Ultima creștere",
"fit_expanded_images_to_screen": "Se potrivesc imaginile extinse pe ecran",
"fit_expanded_images_to_screen_tip": "Limitați imaginile extinse atât la lățimea cât și la înălțimea browserului",
"choose_file": "Alegeți fișierul",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Ajutor pentru filtre și evidențieri",
"filter_and_highlights": "Filtre și evidențieri",
"boards_you_moderate": "boards pe care le moderezi",
"more_threads_last_year": "{{count}} subiecte din {{currentTimeFilterName}} — [<1>Afișați mai multe subiecte de anul trecut</1>]",
"moderator_of_this_board": "Acest utilizator este moderator al acestui forum",
"administrator_of_this_board": "Acest utilizator este administrator al acestui forum",
"copy_content_id": "copiați ID-ul conținutului",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Сортировать по",
"subplebbit_offline_info": "Этот форум может быть офлайн, и публикация может не удаться",
"posts_last_synced_info": "Посты последний раз синхронизированы {{time}}, этот форум может быть офлайн, и публикация может не удаться.",
"newer_than": "новее чем",
"no_threads": "Нет тем",
"hidden": "скрытый",
"save_options": "Сохранить настройки",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Пожалуйста, выберите доску перед публикацией.",
"invalid_url_alert": "Предоставленная ссылка не является действительным URL.",
"empty_comment_alert": "Невозможно опубликовать пустой комментарий.",
"more_threads_last_week": "{{count}} тредов с {{currentTimeFilterName}} — [<1>Показать больше тредов за прошлую неделю</1>]",
"more_threads_last_month": "{{count}} темы с {{currentTimeFilterName}} — [<1>Показать больше тем с прошлого месяца</1>]",
"newer_threads_available": "Доступны новые темы — [<1>Обновить</1>]",
"stored_locally": "Сохранено локально (в данных {{location}}), не синхронизируется между устройствами",
"choose_one": "Выберите один:",
@@ -191,7 +188,6 @@
"reset_changes": "Сбросить изменения",
"crypto_address_yours": "Адрес криптовалюты принадлежит этому аккаунту.",
"delete_wallet": "Удалить кошелек",
"last_bumped": "Последний бамп",
"fit_expanded_images_to_screen": "Подогнать расширенные изображения под экран",
"fit_expanded_images_to_screen_tip": "Ограничить расширенные изображения как по ширине, так и по высоте браузера",
"choose_file": "Выбрать файл",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Помощь с фильтрами и выделениями",
"filter_and_highlights": "Фильтры и выделения",
"boards_you_moderate": "boards, которые вы модерируете",
"more_threads_last_year": "{{count}} темы с {{currentTimeFilterName}} — [<1>Показать больше тем с прошлого года</1>]",
"moderator_of_this_board": "Этот пользователь является модератором этого форума",
"administrator_of_this_board": "Этот пользователь является администратором этого форума",
"copy_content_id": "копировать ID контента",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Rendit sipas",
"subplebbit_offline_info": "Ky forum mund të jetë offline dhe publikimi mund të dështojë",
"posts_last_synced_info": "Postimet u sinkronizuan për herë të fundit {{time}}, ky forum mund të jetë offline dhe publikimi mund të dështojë.",
"newer_than": "më i ri se",
"no_threads": "Nuk ka tema",
"hidden": "i fshehur",
"save_options": "Ruaj Cilësimet",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Ju lutemi zgjidhni një bord para se të postoni.",
"invalid_url_alert": "Lidhja e ofruar nuk është një URL e vlefshme.",
"empty_comment_alert": "Nuk mund të postoni një koment bosh.",
"more_threads_last_week": "{{count}} tema nga {{currentTimeFilterName}} — [<1>Shfaq më shumë tema nga java e kaluar</1>]",
"more_threads_last_month": "{{count}} tema nga {{currentTimeFilterName}} — [<1>Shfaq më shumë tema nga muaji i kaluar</1>]",
"newer_threads_available": "Temat më të reja të disponueshme — [<1>Rifresko</1>]",
"stored_locally": "Ruhet lokalisht (në të dhënat {{location}}), nuk sinkronizohet ndër pajisjet",
"choose_one": "Zgjidhni një:",
@@ -191,7 +188,6 @@
"reset_changes": "Rivendosni ndryshimet",
"crypto_address_yours": "Adresa e kriptovalutës i përket këtij llogarie.",
"delete_wallet": "Fshi portofolin",
"last_bumped": "Bumping i fundit",
"fit_expanded_images_to_screen": "Përshtatni imazhet e zgjeruara në ekran",
"fit_expanded_images_to_screen_tip": "Kufizoni imazhet e zgjeruara si në gjerësi ashtu edhe në lartësi të shfletuesit",
"choose_file": "Zgjidhni skedarin",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Ndihma për Filtro & Thekso",
"filter_and_highlights": "Filtra dhe thekson",
"boards_you_moderate": "boards që i moderoni",
"more_threads_last_year": "{{count}} tema nga {{currentTimeFilterName}} — [<1>Shfaq më shumë tema nga viti i kaluar</1>]",
"moderator_of_this_board": "Ky përdorues është moderator i këtij bordi",
"administrator_of_this_board": "Ky përdorues është administrator i këtij bordi",
"copy_content_id": "kopjo ID e përmbajtjes",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sortera efter",
"subplebbit_offline_info": "Detta forum kan vara offline och publicering kan misslyckas",
"posts_last_synced_info": "Inlägg senast synkroniserade {{time}}, detta forum kan vara offline och publicering kan misslyckas.",
"newer_than": "nyare än",
"no_threads": "Inga trådar",
"hidden": "dold",
"save_options": "Spara alternativ",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vänligen välj en tavla innan du postar.",
"invalid_url_alert": "Den angivna länken är inte en giltig URL.",
"empty_comment_alert": "Kan inte posta tom kommentar.",
"more_threads_last_week": "{{count}} trådar sedan {{currentTimeFilterName}} — [<1>Visa fler trådar från förra veckan</1>]",
"more_threads_last_month": "{{count}} trådar sedan {{currentTimeFilterName}} — [<1>Visa fler trådar från förra månaden</1>]",
"newer_threads_available": "Nyare trådar tillgängliga — [<1>Uppdatera</1>]",
"stored_locally": "Lagrat lokalt (i {{location}} data), inte synkroniserat mellan enheter",
"choose_one": "Välj en:",
@@ -191,7 +188,6 @@
"reset_changes": "Återställ ändringar",
"crypto_address_yours": "Crypto-adressen tillhör denna konto.",
"delete_wallet": "Ta bort plånbok",
"last_bumped": "Senaste bump",
"fit_expanded_images_to_screen": "Anpassa utvidgade bilder till skärmen",
"fit_expanded_images_to_screen_tip": "Begränsa utvidgade bilder till både webbläsarens bredd och höjd",
"choose_file": "Välj fil",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filter och markeringar Hjälp",
"filter_and_highlights": "Filter och markeringar",
"boards_you_moderate": "boards du modererar",
"more_threads_last_year": "{{count}} trådar sedan {{currentTimeFilterName}} — [<1>Visa fler trådar från förra året</1>]",
"moderator_of_this_board": "Denna användare är moderator för detta forum",
"administrator_of_this_board": "Denna användare är administratör för detta forum",
"copy_content_id": "kopiera innehålls-ID",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "గట్టిగా",
"subplebbit_offline_info": "ఈ బోర్డ్ ఆఫ్‌లైన్‌లో ఉండవచ్చు మరియు ప్రచురణ విఫలమవచ్చు",
"posts_last_synced_info": "పోస్ట్‌లు చివరిగా {{time}} సమకాలీకరించబడ్డాయి, ఈ బోర్డ్ ఆఫ్‌లైన్‌లో ఉండవచ్చు మరియు ప్రచురణ విఫలమవచ్చు.",
"newer_than": "కనునుగా",
"no_threads": "ఏ థ్రెడ్‌లు లేవు",
"hidden": "దాగిన",
"save_options": "ఎంచుకోండి సేవ్ చేయండి",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "పోస్ట్ చేయడానికి ముందు దయచేసి ఒక బోర్డు ఎంచుకోండి.",
"invalid_url_alert": "నివేదిక ఇవ్వబడిన లింక్ చెల్లుబాటులో లేని URL.",
"empty_comment_alert": "ఖాళీ వ్యాఖ్యను పోస్ట్ చేయలేరు.",
"more_threads_last_week": "{{count}} థ్రెడ్‌లు {{currentTimeFilterName}} నుండి — [<1>గత వారానికి మరిన్ని థ్రెడ్‌లు చూపించు</1>]",
"more_threads_last_month": "{{count}} థ్రెడ్‌లు {{currentTimeFilterName}} నుండి — [<1>గత నెల నుండి మరిన్ని థ్రెడ్‌లను చూపించండి</1>]",
"newer_threads_available": "కొత్త థ్రెడ్‌లు అందుబాటులో ఉన్నాయి — [<1>రిఫ్రెష్</1>]",
"stored_locally": "స్థానికంగా నిల్వ చేయబడింది ({{location}} డేటాలో), ఉపకరణాల మధ్య సింక్ చేయబడలేదు",
"choose_one": "ఒకటి ఎంపిక చేసుకోండి:",
@@ -191,7 +188,6 @@
"reset_changes": "మార్పులను రీసెట్ చేయండి",
"crypto_address_yours": "క్రిప్టో చిరునామా ఈ ఖాతాకు చేరుకుంది.",
"delete_wallet": "వాలెట్ తొలగించండి",
"last_bumped": "చివరి బంప్",
"fit_expanded_images_to_screen": "విస్తృత చిత్రాలను స్క్రీన్‌కు సరిపోల్చండి",
"fit_expanded_images_to_screen_tip": "విస్తృత చిత్రాలను బ్రౌజర్ వెడల్పు మరియు ఎత్తు రెండింటికీ పరిమితం చేయండి",
"choose_file": "ఫైల్ ఎంపిక చేసుకోండి",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "ఫిల్టర్లు మరియు హైలైట్ సహాయం",
"filter_and_highlights": "ఫిల్టర్లు మరియు హైలైట్స్",
"boards_you_moderate": "మీరు మోడరేట్ చేసే బోర్డులు",
"more_threads_last_year": "{{count}} థ్రెడ్‌లు {{currentTimeFilterName}} నుండి — [<1>గత సంవత్సరం నుండి మరిన్ని థ్రెడ్‌లను చూపించండి</1>]",
"moderator_of_this_board": "ఈ వినియోగదారు ఈ బోర్డ్ యొక్క మోడరేటర్",
"administrator_of_this_board": "ఈ వినియోగదారు ఈ బోర్డ్ యొక్క నిర్వాహకుడు",
"copy_content_id": "కంటెంట్ ID కాపీ చేయండి",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "เรียงลำดับตาม",
"subplebbit_offline_info": "บอร์ดนี้อาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
"posts_last_synced_info": "โพสต์ซิงค์ครั้งล่าสุด {{time}} บอร์ดนี้อาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
"newer_than": "ใหม่กว่า",
"no_threads": "ไม่มีกระทู้",
"hidden": "ซ่อน",
"save_options": "บันทึกตัวเลือก",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "กรุณาเลือกกระดานก่อนที่จะโพสต์.",
"invalid_url_alert": "ลิงก์ที่ให้ไม่ใช่ URL ที่ถูกต้อง",
"empty_comment_alert": "ไม่สามารถโพสต์ความคิดเห็นว่างเปล่าได้",
"more_threads_last_week": "{{count}} กระทู้ตั้งแต่ {{currentTimeFilterName}} — [<1>แสดงกระทู้เพิ่มเติมจากสัปดาห์ที่แล้ว</1>]",
"more_threads_last_month": "{{count}} กระทู้ตั้งแต่ {{currentTimeFilterName}} — [<1>แสดงกระทู้จากเดือนที่แล้วเพิ่มเติม</1>]",
"newer_threads_available": "มีกระทู้ใหม่ที่พร้อมใช้งาน — [<1>รีเฟรช</1>]",
"stored_locally": "เก็บไว้ในเครื่อง (ในข้อมูล {{location}}), ไม่ซิงค์ระหว่างอุปกรณ์",
"choose_one": "เลือกหนึ่ง:",
@@ -191,7 +188,6 @@
"reset_changes": "รีเซ็ตการเปลี่ยนแปลง",
"crypto_address_yours": "ที่อยู่คริปโตเป็นของบัญชีนี้",
"delete_wallet": "ลบกระเป๋าเงิน",
"last_bumped": "เพิ่มล่าสุด",
"fit_expanded_images_to_screen": "ปรับขนาดภาพที่ขยายให้พอดีกับหน้าจอ",
"fit_expanded_images_to_screen_tip": "จำกัดภาพที่ขยายให้พอดีกับทั้งความกว้างและความสูงของเบราว์เซอร์",
"choose_file": "เลือกไฟล์",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "ตัวกรองและการเน้นความช่วยเหลือ",
"filter_and_highlights": "ตัวกรองและไฮไลท์",
"boards_you_moderate": "บอร์ดที่คุณดูแล",
"more_threads_last_year": "{{count}} กระทู้ตั้งแต่ {{currentTimeFilterName}} — [<1>แสดงกระทู้จากปีที่แล้วเพิ่มเติม</1>]",
"moderator_of_this_board": "ผู้ใช้รายนี้เป็นผู้ดูแลของบอร์ดนี้",
"administrator_of_this_board": "ผู้ใช้รายนี้เป็นผู้ดูแลระบบของบอร์ดนี้",
"copy_content_id": "คัดลอก ID เนื้อหา",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sırala",
"subplebbit_offline_info": "Bu forum çevrimdışı olabilir ve yayınlama başarısız olabilir",
"posts_last_synced_info": "Gönderiler son olarak {{time}} senkronize edildi, bu forum çevrimdışı olabilir ve yayınlama başarısız olabilir.",
"newer_than": "daha yeni",
"no_threads": "Hiç gönderi yok",
"hidden": "gizli",
"save_options": "Seçenekleri Kaydet",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Lütfen gönderimden önce bir pano seçin.",
"invalid_url_alert": "Verilen bağlantı geçerli bir URL değildir.",
"empty_comment_alert": "Boş yorum gönderilemez.",
"more_threads_last_week": "{{count}} başlık {{currentTimeFilterName}}den itibaren — [<1>Geçen haftadan daha fazla başlık göster</1>]",
"more_threads_last_month": "{{count}} konu {{currentTimeFilterName}} itibariyle — [<1>Geçen aydan daha fazla konu göster</1>]",
"newer_threads_available": "Yeni gönderiler mevcut — [<1>Yenile</1>]",
"stored_locally": "Yerel olarak depolandı ({{location}} verisinde), cihazlar arasında senkronize değil",
"choose_one": "Birini seç:",
@@ -191,7 +188,6 @@
"reset_changes": "Değişiklikleri Sıfırla",
"crypto_address_yours": "Kripto adres bu hesaba aittir.",
"delete_wallet": "Cüzdanı Sil",
"last_bumped": "Son bump",
"fit_expanded_images_to_screen": "Genişletilmiş resimleri ekrana sığdır",
"fit_expanded_images_to_screen_tip": "Genişletilmiş resimleri hem tarayıcı genişliğine hem de yüksekliğine sınırlayın",
"choose_file": "Dosya Seç",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Filtreler ve Vurgular Yardımı",
"filter_and_highlights": "Filtreler ve Vurgular",
"boards_you_moderate": "modere ettiğiniz panolar",
"more_threads_last_year": "{{count}} konu {{currentTimeFilterName}} itibariyle — [<1>Geçen yıldan daha fazla konu göster</1>]",
"moderator_of_this_board": "Bu kullanıcı bu panonun moderatörüdür",
"administrator_of_this_board": "Bu kullanıcı bu panonun yöneticisidir",
"copy_content_id": "içerik ID'sini kopyala",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Сортувати за",
"subplebbit_offline_info": "Цей форум може бути офлайн, і публікація може не вдатися",
"posts_last_synced_info": "Останній раз пости синхронізовано {{time}}, цей форум може бути офлайн, і публікація може не вдатися.",
"newer_than": "новіше ніж",
"no_threads": "Немає тем",
"hidden": "прихований",
"save_options": "Зберегти налаштування",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Будь ласка, виберіть дошку перед публікацією.",
"invalid_url_alert": "Надане посилання не є дійсною URL-адресою.",
"empty_comment_alert": "Не можна опублікувати порожній коментар.",
"more_threads_last_week": "{{count}} тем з {{currentTimeFilterName}} — [<1>Показати більше тем з минулого тижня</1>]",
"more_threads_last_month": "{{count}} тем з {{currentTimeFilterName}} — [<1>Показати більше тем з минулого місяця</1>]",
"newer_threads_available": "Доступні нові теми — [<1>Оновити</1>]",
"stored_locally": "Збережено локально (у даних {{location}}), не синхронізується між пристроями",
"choose_one": "Виберіть один:",
@@ -191,7 +188,6 @@
"reset_changes": "Скинути зміни",
"crypto_address_yours": "Адреса криптовалюти належить цьому обліковому запису.",
"delete_wallet": "Видалити гаманець",
"last_bumped": "Останній бамп",
"fit_expanded_images_to_screen": "Підлаштувати розширені зображення під екран",
"fit_expanded_images_to_screen_tip": "Обмежити розширені зображення як за шириною, так і за висотою браузера",
"choose_file": "Виберіть файл",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Допомога з фільтрами та підсвічуваннями",
"filter_and_highlights": "Фільтри та виділення",
"boards_you_moderate": "boards, які ви модеруватимете",
"more_threads_last_year": "{{count}} тем з {{currentTimeFilterName}} — [<1>Показати більше тем з минулого року</1>]",
"moderator_of_this_board": "Цей користувач є модератором цього форуму",
"administrator_of_this_board": "Цей користувач є адміністратором цього форуму",
"copy_content_id": "копіювати ID контенту",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "کے ذریعہ سارٹ کریں",
"subplebbit_offline_info": "یہ بورڈ آف لائن ہو سکتا ہے اور اشاعت ناکام ہو سکتی ہے",
"posts_last_synced_info": "پوسٹس آخری بار {{time}} پر مطابقت پذیر ہوئیں، یہ بورڈ آف لائن ہو سکتا ہے اور اشاعت ناکام ہو سکتی ہے۔",
"newer_than": "نئی سے",
"no_threads": "کوئی تھریڈز نہیں ہیں",
"hidden": "چھپا ہوا",
"save_options": "خیارات محفوظ کریں",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "براہ کرم پوسٹ کرنے سے پہلے ایک بورڈ منتخب کریں۔",
"invalid_url_alert": "فراہم کردہ لنک درست URL نہیں ہے۔",
"empty_comment_alert": "خالی تبصرہ پوسٹ نہیں کیا جا سکتا۔",
"more_threads_last_week": "{{count}} تھریڈ {{currentTimeFilterName}} سے — [<1>گزشتہ ہفتے کے مزید تھریڈ دیکھیں</1>]",
"more_threads_last_month": "{{count}} تھریڈز {{currentTimeFilterName}} سے — [<1>پچھلے ماہ کے مزید تھریڈز دکھائیں</1>]",
"newer_threads_available": "نئے تھریڈ دستیاب ہیں — [<1>ریف्रش کریں</1>]",
"stored_locally": "مقامی طور پر محفوظ ({{location}} ڈیٹا میں)، آلات میں مطابقت پذیری نہیں",
"choose_one": "ایک کا انتخاب کریں:",
@@ -191,7 +188,6 @@
"reset_changes": "تبدیلیاں ری سیٹ کریں",
"crypto_address_yours": "کرپٹو پتا اس اکاؤنٹ کا حصہ ہے۔",
"delete_wallet": "والٹ حذف کریں",
"last_bumped": "آخری بمپر",
"fit_expanded_images_to_screen": "پھیلائی ہوئی تصاویر کو اسکرین پر فٹ کریں",
"fit_expanded_images_to_screen_tip": "پھیلائی ہوئی تصاویر کو براؤزر کی چوڑائی اور اونچائی دونوں تک محدود کریں",
"choose_file": "فائل منتخب کریں",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "فلٹرز اور ہائی لائٹس کی مدد",
"filter_and_highlights": "فلٹرز اور ہائلाइटس",
"boards_you_moderate": "وہ بورڈز جن کی آپ نگرانی کرتے ہیں",
"more_threads_last_year": "{{count}} تھریڈز {{currentTimeFilterName}} سے — [<1>گزشتہ سال کے مزید تھریڈز دکھائیں</1>]",
"moderator_of_this_board": "یہ صارف اس بورڈ کا ماڈریٹر ہے",
"administrator_of_this_board": "یہ صارف اس بورڈ کا منتظم ہے",
"copy_content_id": "مواد کی شناخت کاپی کریں",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "Sắp xếp theo",
"subplebbit_offline_info": "Bảng này có thể đang offline và việc xuất bản có thể thất bại",
"posts_last_synced_info": "Bài đăng được đồng bộ lần cuối {{time}}, bảng này có thể đang offline và việc xuất bản có thể thất bại.",
"newer_than": "mới hơn",
"no_threads": "Không có chủ đề",
"hidden": "ẩn",
"save_options": "Lưu tùy chọn",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "Vui lòng chọn một bảng trước khi đăng.",
"invalid_url_alert": "Liên kết được cung cấp không phải là một URL hợp lệ.",
"empty_comment_alert": "Không thể đăng bình luận trống.",
"more_threads_last_week": "{{count}} chủ đề từ {{currentTimeFilterName}} — [<1>Xem thêm chủ đề từ tuần trước</1>]",
"more_threads_last_month": "{{count}} chủ đề từ {{currentTimeFilterName}} — [<1>Hiển thị thêm các chủ đề từ tháng trước</1>]",
"newer_threads_available": "Có các chủ đề mới — [<1>Làm mới</1>]",
"stored_locally": "Lưu cục bộ (trong dữ liệu {{location}}), không đồng bộ giữa thiết bị",
"choose_one": "Chọn một:",
@@ -191,7 +188,6 @@
"reset_changes": "Đặt lại thay đổi",
"crypto_address_yours": "Địa chỉ tiền điện tử thuộc về tài khoản này.",
"delete_wallet": "Xóa ví",
"last_bumped": "Bump gần đây nhất",
"fit_expanded_images_to_screen": "Phù hợp hình ảnh mở rộng với màn hình",
"fit_expanded_images_to_screen_tip": "Hạn chế hình ảnh mở rộng cả chiều rộng và chiều cao của trình duyệt",
"choose_file": "Chọn tệp",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "Trợ giúp bộ lọc và đánh dấu",
"filter_and_highlights": "Bộ lọc và Nổi bật",
"boards_you_moderate": "boards bạn điều hành",
"more_threads_last_year": "{{count}} chủ đề từ {{currentTimeFilterName}} — [<1>Hiển thị thêm các chủ đề từ năm ngoái</1>]",
"moderator_of_this_board": "Người dùng này là người điều hành của bảng này",
"administrator_of_this_board": "Người dùng này là quản trị viên của bảng này",
"copy_content_id": "sao chép ID nội dung",
-5
View File
@@ -135,7 +135,6 @@
"sort_by": "排序方式",
"subplebbit_offline_info": "此看板可能处于离线状态,发布可能会失败",
"posts_last_synced_info": "帖子最后同步于 {{time}},此看板可能处于离线状态,发布可能会失败。",
"newer_than": "新于",
"no_threads": "没有帖子",
"hidden": "隐藏",
"save_options": "保存选项",
@@ -181,8 +180,6 @@
"no_board_selected_warning": "请在发布之前选择一个板块。",
"invalid_url_alert": "提供的链接不是有效的 URL。",
"empty_comment_alert": "无法发布空评论。",
"more_threads_last_week": "{{count}} 主题自 {{currentTimeFilterName}} — [<1>显示更多来自上周的主题</1>]",
"more_threads_last_month": "{{count}} 主题自 {{currentTimeFilterName}} — [<1>显示更多上个月的主题</1>]",
"newer_threads_available": "有新的帖子可用 — [<1>刷新</1>]",
"stored_locally": "本地存储(位于 {{location}} 数据中),不会在设备间同步",
"choose_one": "选择一个:",
@@ -191,7 +188,6 @@
"reset_changes": "重置更改",
"crypto_address_yours": "加密地址属于此帐户。",
"delete_wallet": "删除钱包",
"last_bumped": "最后提升",
"fit_expanded_images_to_screen": "适应扩展图像到屏幕",
"fit_expanded_images_to_screen_tip": "将扩展图像限制为浏览器的宽度和高度",
"choose_file": "选择文件",
@@ -222,7 +218,6 @@
"filter_and_highlights_help": "过滤器和高亮帮助",
"filter_and_highlights": "筛选器与高亮",
"boards_you_moderate": "您管理的板块",
"more_threads_last_year": "{{count}} 主题自 {{currentTimeFilterName}} — [<1>显示更多去年的主题</1>]",
"moderator_of_this_board": "此用户是此版块的版主",
"administrator_of_this_board": "此用户是此版块的管理员",
"copy_content_id": "复制内容ID",
+18 -15
View File
@@ -243,27 +243,30 @@ const App = () => {
<Route path='/faq' element={<FAQ />} />
<Route path='/rules/:boardIdentifier?' element={<Rules />} />
<Route element={<BoardLayout />}>
<Route path='/all/:timeFilterName/:pageNumber' element={boardFeedElement} />
<Route path='/all/:timeFilterName?' element={boardFeedElement} />
<Route path='/all/:timeFilterName?/settings' element={boardFeedElement} />
<Route path='/all/catalog/:timeFilterName?' element={catalogFeedElement} />
<Route path='/all/catalog/:timeFilterName?/settings' element={catalogFeedElement} />
{/* Canonical multiboard routes (no time filter) */}
<Route path='/all' element={boardFeedElement} />
<Route path='/all/settings' element={boardFeedElement} />
<Route path='/all/catalog' element={catalogFeedElement} />
<Route path='/all/catalog/settings' element={catalogFeedElement} />
<Route path='/subs/:timeFilterName/:pageNumber' element={boardFeedElement} />
<Route path='/subs/:timeFilterName?' element={boardFeedElement} />
<Route path='/subs/:timeFilterName?/settings' element={boardFeedElement} />
<Route path='/subs/catalog/:timeFilterName?' element={catalogFeedElement} />
<Route path='/subs/catalog/:timeFilterName?/settings' element={catalogFeedElement} />
<Route path='/subs' element={boardFeedElement} />
<Route path='/subs/settings' element={boardFeedElement} />
<Route path='/subs/catalog' element={catalogFeedElement} />
<Route path='/subs/catalog/settings' element={catalogFeedElement} />
<Route path='/mod/:timeFilterName/:pageNumber' element={boardFeedElement} />
<Route path='/mod/:timeFilterName?' element={boardFeedElement} />
<Route path='/mod/:timeFilterName?/settings' element={boardFeedElement} />
<Route path='/mod/catalog/:timeFilterName?' element={catalogFeedElement} />
<Route path='/mod/catalog/:timeFilterName?/settings' element={catalogFeedElement} />
<Route path='/mod' element={boardFeedElement} />
<Route path='/mod/settings' element={boardFeedElement} />
<Route path='/mod/catalog' element={catalogFeedElement} />
<Route path='/mod/catalog/settings' element={catalogFeedElement} />
<Route path='/mod/modqueue' element={<ModQueueRoute />} />
<Route path='/mod/modqueue/settings' element={<ModQueueRoute />} />
{/* Invalid subpaths: old time-filter URLs (e.g. /all/24h) -> not-found */}
<Route path='/all/*' element={<Navigate to='/not-found' replace />} />
<Route path='/subs/*' element={<Navigate to='/not-found' replace />} />
<Route path='/mod/*' element={<Navigate to='/not-found' replace />} />
<Route path='/:boardIdentifier/:pageNumber' element={boardFeedElement} />
<Route path='/:boardIdentifier' element={boardFeedElement} />
<Route path='/:boardIdentifier/settings' element={boardFeedElement} />
+10 -80
View File
@@ -15,7 +15,6 @@ import useModQueueStore from '../../stores/use-mod-queue-store';
import useFeedViewSettingsStore from '../../stores/use-feed-view-settings-store';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useIsMobile from '../../hooks/use-is-mobile';
import useTimeFilter from '../../hooks/use-time-filter';
import CatalogFilters from '../catalog-filters';
import CatalogSearch from '../catalog-search';
import Tooltip from '../tooltip';
@@ -39,16 +38,9 @@ const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModVie
const directories = useDirectories();
const createCatalogLink = () => {
if (isInAllView) {
if (params?.timeFilterName) return `/all/catalog/${params.timeFilterName}`;
return `/all/catalog`;
} else if (isInSubscriptionsView) {
if (params?.timeFilterName) return `/subs/catalog/${params.timeFilterName}`;
return `/subs/catalog`;
} else if (isInModView) {
if (params?.timeFilterName) return `/mod/catalog/${params.timeFilterName}`;
return `/mod/catalog`;
}
if (isInAllView) return `/all/catalog`;
if (isInSubscriptionsView) return `/subs/catalog`;
if (isInModView) return `/mod/catalog`;
let boardPath = '';
if (address) {
boardPath = getBoardPath(address, directories);
@@ -82,22 +74,16 @@ const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView
const directories = useDirectories();
const createReturnLink = () => {
if (isInAllView) {
if (params?.timeFilterName) return `/all/${params.timeFilterName}`;
return `/all`;
} else if (isInSubscriptionsView) {
if (params?.timeFilterName) return `/subs/${params.timeFilterName}`;
return `/subs`;
} else if (isInModQueueView) {
if (isInAllView) return `/all`;
if (isInSubscriptionsView) return `/subs`;
if (isInModQueueView) {
// If in mod queue view, return to /mod or /:boardIdentifier
if (params?.boardIdentifier) {
return `/${params.boardIdentifier}`;
}
return `/mod`;
} else if (isInModView) {
if (params?.timeFilterName) return `/mod/${params.timeFilterName}`;
return `/mod`;
}
if (isInModView) return `/mod`;
let boardPath = '';
if (address) {
boardPath = getBoardPath(address, directories);
@@ -335,53 +321,6 @@ const ShowOPCommentOption = () => {
);
};
export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView, isInModView, isTopbar = false }: BoardButtonsProps) => {
const { t } = useTranslation();
const navigate = useNavigate();
const { timeFilterName, timeFilterNames } = useTimeFilter();
const changeTimeFilter = (event: React.ChangeEvent<HTMLSelectElement>) => {
const timeFilterName = event.target.value;
const link = isInAllView
? isInCatalogView
? `/all/catalog/${timeFilterName}`
: `/all/${timeFilterName}`
: isInSubscriptionsView
? isInCatalogView
? `/subs/catalog/${timeFilterName}`
: `/subs/${timeFilterName}`
: isInModView
? isInCatalogView
? `/mod/catalog/${timeFilterName}`
: `/mod/${timeFilterName}`
: null;
link && navigate(link);
};
const { sortType } = useSortingStore();
const allTimeFilterNames = timeFilterName ? Array.from(new Set([timeFilterName, ...timeFilterNames])) : timeFilterNames;
return (
<>
{!isTopbar ? (
<>
<span>{isInCatalogView ? (sortType === 'active' ? t('last_bumped') : t('newer_than')) : t('last_bumped')}</span>:&nbsp;
</>
) : (
<> </>
)}
<select onChange={changeTimeFilter} className={[styles.feedName, styles.menuItem, 'capitalize'].join(' ')} value={timeFilterName}>
{allTimeFilterNames.map((name, i) => (
<option key={name + i} value={name}>
{name}
</option>
))}
</select>
</>
);
};
const AllFeedFilter = () => {
const { t } = useTranslation();
const { filter, setFilter } = useAllFeedFilterStore();
@@ -643,9 +582,6 @@ export const DesktopBoardButtons = () => {
</>
)}
{isInAllView && <AllFeedFilter />}
{(isInAllView || isInSubscriptionsView || isInModView) && (
<TimeFilter isInAllView={isInAllView} isInCatalogView={isInCatalogView} isInSubscriptionsView={isInSubscriptionsView} isInModView={isInModView} />
)}
{!(isInAllView || isInSubscriptionsView || isInModView) && (
<>
[
@@ -684,17 +620,11 @@ const SearchOPsBar = () => {
let catalogUrl = '';
if (isInAllView) {
catalogUrl = params?.timeFilterName
? `/all/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
: `/all/catalog?q=${encodeURIComponent(searchQuery)}`;
catalogUrl = `/all/catalog?q=${encodeURIComponent(searchQuery)}`;
} else if (isInSubscriptionsView) {
catalogUrl = params?.timeFilterName
? `/subs/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
: `/subs/catalog?q=${encodeURIComponent(searchQuery)}`;
catalogUrl = `/subs/catalog?q=${encodeURIComponent(searchQuery)}`;
} else if (isInModView) {
catalogUrl = params?.timeFilterName
? `/mod/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
: `/mod/catalog?q=${encodeURIComponent(searchQuery)}`;
catalogUrl = `/mod/catalog?q=${encodeURIComponent(searchQuery)}`;
} else {
catalogUrl = `/${boardPath}/catalog?q=${encodeURIComponent(searchQuery)}`;
}
+1 -1
View File
@@ -1 +1 @@
export { TimeFilter, MobileBoardButtons, DesktopBoardButtons } from './board-buttons';
export { MobileBoardButtons, DesktopBoardButtons } from './board-buttons';
@@ -9,7 +9,6 @@ import styles from './feed-cache-container.module.css';
interface FeedContextFromKey {
viewType: 'all' | 'subs' | 'mod' | 'board';
boardIdentifier?: string;
timeFilterName?: string;
}
const parseFeedKey = (key: string): FeedContextFromKey => {
@@ -17,28 +16,18 @@ const parseFeedKey = (key: string): FeedContextFromKey => {
const filteredSegments = segments.filter((s) => s !== 'catalog');
if (filteredSegments[0] === 'all') {
return {
viewType: 'all',
timeFilterName: filteredSegments[1],
};
return { viewType: 'all' };
}
if (filteredSegments[0] === 'subs') {
return {
viewType: 'subs',
timeFilterName: filteredSegments[1],
};
return { viewType: 'subs' };
}
if (filteredSegments[0] === 'mod') {
return {
viewType: 'mod',
timeFilterName: filteredSegments[1],
};
return { viewType: 'mod' };
}
return {
viewType: 'board',
boardIdentifier: filteredSegments[0],
timeFilterName: filteredSegments[1],
};
};
@@ -53,21 +42,9 @@ const CachedFeedWrapper = ({ feed, isVisible }: CachedFeedWrapperProps) => {
return (
<div className={isVisible ? styles.visible : styles.hidden}>
{feed.type === 'catalog' ? (
<Catalog
feedCacheKey={feed.key}
viewType={context.viewType}
boardIdentifier={context.boardIdentifier}
timeFilterNameFromCache={context.timeFilterName}
isVisible={isVisible}
/>
<Catalog feedCacheKey={feed.key} viewType={context.viewType} boardIdentifier={context.boardIdentifier} isVisible={isVisible} />
) : (
<Board
feedCacheKey={feed.key}
viewType={context.viewType}
boardIdentifier={context.boardIdentifier}
timeFilterNameFromCache={context.timeFilterName}
isVisible={isVisible}
/>
<Board feedCacheKey={feed.key} viewType={context.viewType} boardIdentifier={context.boardIdentifier} isVisible={isVisible} />
)}
</div>
);
-4
View File
@@ -8,7 +8,6 @@ import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/v
import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories';
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils';
import { TimeFilter } from '../board-buttons';
import useCreateBoardModalStore from '../../stores/use-create-board-modal-store';
import useTopbarEditModalStore from '../../stores/use-topbar-edit-modal-store';
import useTopbarVisibilityStore from '../../stores/use-topbar-visibility-store';
@@ -334,9 +333,6 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
<div className={styles.boardSelect}>
<strong>{t('board')}</strong>
{boardSelect}
{(isInAllView || isInSubscriptionsView) && (
<TimeFilter isTopbar={true} isInAllView={isInAllView} isInCatalogView={isInCatalogView} isInSubscriptionsView={isInSubscriptionsView} />
)}
</div>
<div className={styles.pageJump}>
<Link to={useLocation().pathname.replace(/\/$/, '') + '/settings'}>{t('settings')}</Link>
-149
View File
@@ -1,149 +0,0 @@
import assert from 'assert';
import { useParams } from 'react-router-dom';
import { isBoardFeedPageNumber } from '../lib/utils/route-utils';
// the timestamp the last time the user visited
const lastVisitTimestamp = localStorage.getItem('5chanLastVisitTimestamp');
// Singleton pattern to ensure only one interval is ever created
// This prevents memory leaks from multiple intervals being created during HMR or module re-evaluation
// Using window object to persist across hot module reloads
declare global {
interface Window {
_5chanLastVisitTimestampIntervalId?: number;
}
}
if (!window._5chanLastVisitTimestampIntervalId) {
// update the last visited timestamp every n seconds
window._5chanLastVisitTimestampIntervalId = window.setInterval(() => {
localStorage.setItem('5chanLastVisitTimestamp', Date.now().toString());
}, 60 * 1000);
}
const timeFilterNamesToSeconds: Record<string, number | undefined> = {
'1h': 60 * 60,
'12h': 60 * 60 * 12,
'24h': 60 * 60 * 24,
'48h': 60 * 60 * 24 * 2,
'1w': 60 * 60 * 24 * 7,
'1m': 60 * 60 * 24 * 30,
'1y': 60 * 60 * 24 * 365,
all: undefined,
};
// calculate the last visit timeFilterNamesToSeconds
const secondsSinceLastVisit = lastVisitTimestamp ? (Date.now() - parseInt(lastVisitTimestamp, 10)) / 1000 : Infinity;
const day = 24 * 60 * 60;
let lastVisitTimeFilterName: string | undefined;
if (secondsSinceLastVisit > 30 * day) {
lastVisitTimeFilterName = '1m';
timeFilterNamesToSeconds[lastVisitTimeFilterName] = timeFilterNamesToSeconds['1m'];
} else if (secondsSinceLastVisit > 7 * day) {
const weeks = Math.ceil(secondsSinceLastVisit / day / 7);
lastVisitTimeFilterName = `${weeks}w`;
timeFilterNamesToSeconds[lastVisitTimeFilterName] = 60 * 60 * 24 * 7 * weeks;
} else if (secondsSinceLastVisit > day) {
const days = Math.ceil(secondsSinceLastVisit / day);
lastVisitTimeFilterName = `${days}d`;
timeFilterNamesToSeconds[lastVisitTimeFilterName] = 60 * 60 * 24 * days;
} else {
lastVisitTimeFilterName = '24h';
timeFilterNamesToSeconds[lastVisitTimeFilterName] = timeFilterNamesToSeconds['24h'];
}
export const timeFilterNames = [lastVisitTimeFilterName, '1h', '12h', '24h', '48h', '1w', '1m', '1y', 'all'];
export const timeFilterNameToSeconds = (timeFilterName: string | undefined): number | undefined => {
if (!timeFilterName || timeFilterName === 'all') return undefined;
if (timeFilterName in timeFilterNamesToSeconds) {
return timeFilterNamesToSeconds[timeFilterName as keyof typeof timeFilterNamesToSeconds];
}
const match = timeFilterName.match(/^(\d+)([hdwmy])$/);
if (match) {
const [, value, unit] = match;
const numValue = parseInt(value, 10);
switch (unit) {
case 'h':
return numValue * 60 * 60;
case 'd':
return numValue * 24 * 60 * 60;
case 'w':
return numValue * 7 * 24 * 60 * 60;
case 'm':
return numValue * 30 * 24 * 60 * 60;
case 'y':
return numValue * 365 * 24 * 60 * 60;
}
}
return undefined;
};
function convertTimeStringToSeconds(timeString: string): number {
const match = timeString.match(/^(\d+)([hdwmy])$/);
if (!match) {
throw new Error(`Invalid time filter format: ${timeString}`);
}
const [, value, unit] = match;
const numValue = parseInt(value, 10);
switch (unit) {
case 'h':
return numValue * 60 * 60;
case 'd':
return numValue * 24 * 60 * 60;
case 'w':
return numValue * 7 * 24 * 60 * 60;
case 'm':
return numValue * 30 * 24 * 60 * 60;
case 'y':
return numValue * 365 * 24 * 60 * 60;
default:
throw new Error(`Invalid time unit: ${unit}`);
}
}
const useTimeFilter = () => {
const params = useParams();
let timeFilterName = params.timeFilterName;
// Ignore when param is a board feed page number (e.g. /all/3, /biz/2)
if (timeFilterName && isBoardFeedPageNumber(timeFilterName)) {
timeFilterName = undefined;
}
// the default time filter is the last visit time filter
if (!timeFilterName) {
timeFilterName = lastVisitTimeFilterName;
}
let timeFilterSeconds: number | undefined;
if (timeFilterName === 'all') {
timeFilterSeconds = undefined;
} else if (timeFilterName && timeFilterName in timeFilterNamesToSeconds) {
timeFilterSeconds = timeFilterNamesToSeconds[timeFilterName as keyof typeof timeFilterNamesToSeconds];
} else if (timeFilterName) {
try {
timeFilterSeconds = convertTimeStringToSeconds(timeFilterName);
} catch {
console.error(`Invalid time filter format: ${timeFilterName}`);
timeFilterSeconds = undefined;
}
}
// If we still don't have a valid timeFilterSeconds, use the default (24h)
if (timeFilterSeconds === undefined && timeFilterName !== 'all') {
timeFilterSeconds = timeFilterNamesToSeconds['24h'];
}
assert(timeFilterName === 'all' || timeFilterSeconds !== undefined, `useTimeFilter no filter for timeFilterName '${timeFilterName}'`);
return { timeFilterSeconds, timeFilterNames, timeFilterName, lastVisitTimeFilterName };
};
export default useTimeFilter;
+21 -6
View File
@@ -1,15 +1,11 @@
import { describe, it, expect } from 'vitest';
import { normalizeMultiboardFeedPath } from '../route-utils';
import { isFeedRoute, normalizeMultiboardFeedPath } from '../route-utils';
describe('normalizeMultiboardFeedPath', () => {
it('normalizes /all/3 -> /all', () => {
expect(normalizeMultiboardFeedPath('/all/3')).toBe('/all');
});
it('normalizes /all/1w/3 -> /all/1w', () => {
expect(normalizeMultiboardFeedPath('/all/1w/3')).toBe('/all/1w');
});
it('normalizes /subs/2/settings -> /subs/settings', () => {
expect(normalizeMultiboardFeedPath('/subs/2/settings')).toBe('/subs/settings');
});
@@ -21,9 +17,28 @@ describe('normalizeMultiboardFeedPath', () => {
it('leaves non-multiboard paths unchanged', () => {
expect(normalizeMultiboardFeedPath('/biz')).toBe('/biz');
expect(normalizeMultiboardFeedPath('/biz/3')).toBe('/biz/3');
expect(normalizeMultiboardFeedPath('/biz/1w/2')).toBe('/biz/1w/2');
expect(normalizeMultiboardFeedPath('/biz/catalog/4')).toBe('/biz/catalog/4');
expect(normalizeMultiboardFeedPath('/pending/0')).toBe('/pending/0');
expect(normalizeMultiboardFeedPath('/')).toBe('/');
});
});
describe('isFeedRoute', () => {
it('returns true for canonical multiboard paths', () => {
expect(isFeedRoute('/all')).toBe(true);
expect(isFeedRoute('/all/catalog')).toBe(true);
expect(isFeedRoute('/subs')).toBe(true);
expect(isFeedRoute('/subs/catalog')).toBe(true);
expect(isFeedRoute('/mod')).toBe(true);
expect(isFeedRoute('/mod/catalog')).toBe(true);
expect(isFeedRoute('/all/3')).toBe(true);
expect(isFeedRoute('/subs/2')).toBe(true);
expect(isFeedRoute('/mod/catalog/4')).toBe(true);
});
it('returns false for time-filter paths', () => {
expect(isFeedRoute('/all/24h')).toBe(false);
expect(isFeedRoute('/subs/catalog/1w')).toBe(false);
expect(isFeedRoute('/all/1w/3')).toBe(false);
});
});
+4 -11
View File
@@ -109,19 +109,12 @@ export const isFeedRoute = (pathname: string): boolean => {
if (normalizedPath.includes('/modqueue')) return false;
const pathWithoutSettings = normalizedPath.replace(/\/settings$/, '');
if (pathWithoutSettings.startsWith('/all')) return true;
if (pathWithoutSettings.startsWith('/subs')) return true;
if (pathWithoutSettings.startsWith('/mod')) return true;
const segments = pathWithoutSettings.split('/').filter(Boolean);
if (segments.length >= 1) {
if (segments.length === 1) return true;
if (segments.length === 2 && segments[1] === 'catalog') return true;
if (segments.length === 2 && (/^(?:\d+(?:h|d|w|m|y)|all)$/.test(segments[1]) || /^([1-9]|10)$/.test(segments[1]))) return true;
if (segments.length === 3 && segments[1] === 'catalog' && /^(?:\d+(?:h|d|w|m|y)|all)$/.test(segments[2])) return true;
if (segments.length === 3 && /^(?:\d+(?:h|d|w|m|y)|all)$/.test(segments[1]) && /^([1-9]|10)$/.test(segments[2])) return true;
if (segments.length === 2 && segments[0] !== 'all' && segments[0] !== 'subs' && segments[0] !== 'mod' && /^([1-9]|10)$/.test(segments[1])) return true;
if (segments.length === 2 && /^([1-9]|10)$/.test(segments[1])) return true;
if (segments.length === 3 && segments[1] === 'catalog' && /^([1-9]|10)$/.test(segments[2])) return true;
}
return false;
@@ -163,8 +156,8 @@ function isMultiboardFeedPath(pathname: string): boolean {
}
/**
* Normalize multiboard feed paths by removing trailing page-number segments (110),
* while preserving /settings and valid time-filter segments.
* Normalize multiboard feed paths by removing trailing page-number segments (110)
* and preserving /settings.
* Non-multiboard paths are returned unchanged.
*/
export const normalizeMultiboardFeedPath = (pathname: string): string => {
+3 -20
View File
@@ -3,7 +3,6 @@ export type ParamsType = {
boardIdentifier?: string;
commentCid?: string;
subplebbitAddress?: string; // deprecated, kept for backward compatibility
timeFilterName?: string;
};
export const isAllView = (pathname: string): boolean => {
@@ -30,7 +29,7 @@ export const isBoardView = (pathname: string, params: ParamsType): boolean => {
};
export const isCatalogView = (pathname: string, params: ParamsType): boolean => {
const { boardIdentifier, subplebbitAddress, timeFilterName } = params;
const { boardIdentifier, subplebbitAddress } = params;
const identifier = boardIdentifier || subplebbitAddress;
const decodedPathname = decodeURIComponent(pathname);
@@ -38,16 +37,10 @@ export const isCatalogView = (pathname: string, params: ParamsType): boolean =>
(identifier && (decodedPathname === `/${identifier}/catalog` || decodedPathname === `/${identifier}/catalog/settings`)) ||
decodedPathname === `/all/catalog` ||
decodedPathname === `/all/catalog/settings` ||
decodedPathname === `/all/catalog/${timeFilterName}` ||
decodedPathname === `/all/catalog/${timeFilterName}/settings` ||
decodedPathname === `/subs/catalog` ||
decodedPathname === `/subs/catalog/settings` ||
decodedPathname === `/subs/catalog/${timeFilterName}` ||
decodedPathname === `/subs/catalog/${timeFilterName}/settings` ||
decodedPathname === `/mod/catalog` ||
decodedPathname === `/mod/catalog/settings` ||
decodedPathname === `/mod/catalog/${timeFilterName}` ||
decodedPathname === `/mod/catalog/${timeFilterName}/settings`
decodedPathname === `/mod/catalog/settings`
);
};
@@ -83,17 +76,7 @@ export const isSettingsView = (pathname: string, params: ParamsType): boolean =>
};
export const isSubscriptionsView = (pathname: string, params: ParamsType): boolean => {
const { timeFilterName } = params;
return (
pathname === '/subs' ||
pathname === '/subs/settings' ||
pathname === `/subs/${timeFilterName}` ||
pathname === `/subs/${timeFilterName}/settings` ||
pathname === '/subs/catalog' ||
pathname === '/subs/catalog/settings' ||
pathname === `/subs/catalog/${timeFilterName}` ||
pathname === `/subs/catalog/${timeFilterName}/settings`
);
return pathname === '/subs' || pathname === '/subs/settings' || pathname === '/subs/catalog' || pathname === '/subs/catalog/settings';
};
export const isNotFoundView = (pathname: string, params: ParamsType): boolean => {
+9 -143
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { Link, useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom';
import { useEffect, useMemo, useRef } from 'react';
import { useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom';
import { Comment, useAccount, useAccountComments, useAccountSubplebbits, useFeed, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
@@ -8,9 +8,8 @@ import styles from './board.module.css';
import { shouldShowSnow } from '../../lib/snow';
import { useDirectoryAddresses, useDirectories, useDirectoryByAddress } from '../../hooks/use-directories';
import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
import useFeedResetStore from '../../stores/use-feed-reset-store';
import useSortingStore from '../../stores/use-sorting-store';
import useFeedViewSettingsStore from '../../stores/use-feed-view-settings-store';
@@ -33,13 +32,6 @@ interface BoardFooterProps {
isInAllView: boolean;
isInSubscriptionsView: boolean;
isInModView: boolean;
showMorePostsSuggestion: boolean;
feedLength: number;
weeklyFeedLength: number;
monthlyFeedLength: number;
yearlyFeedLength: number;
boardPath: string | undefined;
currentTimeFilterName: string | undefined;
subplebbitState: string | undefined;
subscriptionsLength: number;
accountSubplebbitAddressesLength: number;
@@ -59,13 +51,6 @@ const BoardFooter = ({
isInAllView,
isInSubscriptionsView,
isInModView,
showMorePostsSuggestion,
feedLength,
weeklyFeedLength,
monthlyFeedLength,
yearlyFeedLength,
boardPath,
currentTimeFilterName,
subplebbitState,
subscriptionsLength,
accountSubplebbitAddressesLength,
@@ -73,11 +58,7 @@ const BoardFooter = ({
}: BoardFooterProps) => {
const { t } = useTranslation();
const loadingStateString =
useFeedStateString(subplebbitAddresses) ||
(feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength)
? t('loading_feed')
: t('looking_for_more_posts'));
const loadingStateString = useFeedStateString(subplebbitAddresses) || (combinedFeedLength === 0 ? t('loading_feed') : t('looking_for_more_posts'));
let footerContent;
if (combinedFeedLength === 0) {
@@ -86,7 +67,7 @@ const BoardFooter = ({
if (hasMore || (subplebbitAddresses && subplebbitAddresses.length === 0)) {
footerContent = (
<>
{subplebbitAddressesWithNewerPosts.length > 0 ? (
{subplebbitAddressesWithNewerPosts.length > 0 && (
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='newer_threads_available'
@@ -95,44 +76,6 @@ const BoardFooter = ({
}}
/>
</div>
) : (
(isInAllView || isInSubscriptionsView || isInModView) &&
showMorePostsSuggestion &&
(monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength) &&
(() => {
const basePath = isInAllView ? '/all' : isInSubscriptionsView ? '/subs' : isInModView ? '/mod' : boardPath ? `/${boardPath}` : '';
return weeklyFeedLength > feedLength ? (
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='more_threads_last_week'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: <Link to={`${basePath}/1w`} />,
}}
/>
</div>
) : monthlyFeedLength > feedLength ? (
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='more_threads_last_month'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: <Link to={`${basePath}/1m`} />,
}}
/>
</div>
) : (
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='more_threads_last_year'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: <Link to={`${basePath}/1y`} />,
}}
/>
</div>
);
})()
)}
</>
);
@@ -159,11 +102,10 @@ export interface BoardProps {
feedCacheKey?: string;
viewType?: 'all' | 'subs' | 'mod' | 'board';
boardIdentifier?: string;
timeFilterNameFromCache?: string;
isVisible?: boolean;
}
const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, timeFilterNameFromCache, isVisible = true }: BoardProps) => {
const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, isVisible = true }: BoardProps) => {
const { t } = useTranslation();
const location = useLocation();
const params = useParams();
@@ -180,7 +122,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
return resolvedAddressFromUrl;
}, [boardIdentifierProp, directories, resolvedAddressFromUrl]);
const boardPath = useBoardPath(subplebbitAddress);
const directoryAddresses = useDirectoryAddresses();
const filteredDirectoryAddresses = useFilteredDirectoryAddresses();
@@ -204,9 +145,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
}, [isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, directoryAddresses, filteredDirectoryAddresses, subscriptions, accountSubplebbitAddresses]);
const { sortType } = useSortingStore();
const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
const timeFilterName = timeFilterNameFromCache || timeFilterNameFromHook;
const timeFilterSeconds = timeFilterNameFromCache ? timeFilterNameToSeconds(timeFilterNameFromCache) : timeFilterSecondsFromHook;
const enableInfiniteScroll = useFeedViewSettingsStore((state) => state.enableInfiniteScroll);
const isForcedInfiniteScroll = isInAllView || isInSubscriptionsView || isInModView;
@@ -219,25 +157,14 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
subplebbitAddresses,
sortType,
postsPerPage: effectiveInfiniteScroll ? infiniteFeedPostsPerPage : paginationFeedPostsPerPage,
...(isInAllView || isInSubscriptionsView || isInModView ? { newerThan: timeFilterSeconds } : {}),
}),
[
subplebbitAddresses,
sortType,
effectiveInfiniteScroll,
infiniteFeedPostsPerPage,
paginationFeedPostsPerPage,
isInAllView,
isInSubscriptionsView,
isInModView,
timeFilterSeconds,
],
[subplebbitAddresses, sortType, effectiveInfiniteScroll, infiniteFeedPostsPerPage, paginationFeedPostsPerPage],
);
const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed(feedOptions);
const { accountComments } = useAccountComments();
const feedContextKey = `${isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : isInModView ? 'mod' : (subplebbitAddress ?? 'board')}-${sortType}-${timeFilterSeconds}-${viewType ?? 'board'}-${effectiveInfiniteScroll}`;
const feedContextKey = `${isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : isInModView ? 'mod' : (subplebbitAddress ?? 'board')}-${sortType}-${viewType ?? 'board'}-${effectiveInfiniteScroll}`;
const pathWithoutSettings = location.pathname.replace(/\/settings$/, '');
const currentPage = getPageFromFeedPath(pathWithoutSettings);
const paginationBasePath = stripPageFromFeedPath(pathWithoutSettings);
@@ -338,39 +265,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
}, 300);
};
// suggest the user to change time filter if there aren't enough posts
const { feed: weeklyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 7,
});
const { feed: monthlyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 30,
});
const { feed: yearlyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 365,
});
const feedLength = feed.length;
const weeklyFeedLength = weeklyFeed.length;
const monthlyFeedLength = monthlyFeed.length;
const yearlyFeedLength = yearlyFeed.length;
const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setShowMorePostsSuggestion(true);
}, 5000);
return () => clearTimeout(timer);
}, []);
const currentTimeFilterName = timeFilterName || params?.timeFilterName;
// Memoize footer component to preserve identity across renders (Virtuoso optimization)
// Note: useFeedStateString is called inside BoardFooter to isolate re-renders from backend state changes
const footerComponents = useMemo(
@@ -385,13 +279,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
feedLength={feedLength}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
subplebbitState={subplebbitState}
subscriptionsLength={subscriptions?.length || 0}
accountSubplebbitAddressesLength={accountSubplebbitAddresses?.length || 0}
@@ -408,13 +295,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
isInAllView,
isInSubscriptionsView,
isInModView,
showMorePostsSuggestion,
feedLength,
weeklyFeedLength,
monthlyFeedLength,
yearlyFeedLength,
boardPath,
currentTimeFilterName,
subplebbitState,
subscriptions?.length,
accountSubplebbitAddresses?.length,
@@ -424,7 +304,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
);
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
const virtuosoStateKey = feedCacheKey ? `${feedCacheKey}-${sortType}-${timeFilterSeconds}` : `${location.pathname}-${sortType}-${timeFilterSeconds}`;
const virtuosoStateKey = feedCacheKey ? `${feedCacheKey}-${sortType}` : `${location.pathname}-${sortType}`;
const navigationType = useNavigationType();
const hasBeenVisibleRef = useRef(false);
@@ -514,13 +394,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
feedLength={feedLength}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
subplebbitState={subplebbitState}
subscriptionsLength={subscriptions?.length || 0}
accountSubplebbitAddressesLength={accountSubplebbitAddresses?.length || 0}
@@ -544,13 +417,6 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
feedLength={feedLength}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
subplebbitState={subplebbitState}
subscriptionsLength={subscriptions?.length || 0}
accountSubplebbitAddressesLength={accountSubplebbitAddresses?.length || 0}
+13 -179
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { Link, useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom';
import { useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { Comment, useAccount, useFeed, useSubplebbit, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
@@ -7,9 +7,8 @@ import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
import { useDirectories, useDirectoryByAddress } from '../../hooks/use-directories';
import { useBoardFeedPageSize } from '../../hooks/use-board-feed-page-size';
import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
import useWindowWidth from '../../hooks/use-window-width';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
import useFeedResetStore from '../../stores/use-feed-reset-store';
@@ -28,19 +27,12 @@ const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
interface CatalogFooterProps {
subplebbitAddresses: string[];
hasMore: boolean;
feedLength: number;
combinedFeedLength: number;
subplebbitAddressesWithNewerPosts: string[];
onNewerPostsClick: () => void;
isInAllView: boolean;
isInSubscriptionsView: boolean;
isInModView: boolean;
showMorePostsSuggestion: boolean;
weeklyFeedLength: number;
monthlyFeedLength: number;
yearlyFeedLength: number;
boardPath: string | undefined;
currentTimeFilterName: string | undefined;
/** When false, suppress the loading ellipsis (e.g. non-infinite mode) */
showLoadingEllipsis?: boolean;
}
@@ -51,39 +43,26 @@ interface CatalogFooterProps {
const CatalogFooter = ({
subplebbitAddresses,
hasMore,
feedLength,
combinedFeedLength,
subplebbitAddressesWithNewerPosts,
onNewerPostsClick,
isInAllView,
isInSubscriptionsView,
isInModView,
showMorePostsSuggestion,
weeklyFeedLength,
monthlyFeedLength,
yearlyFeedLength,
boardPath,
currentTimeFilterName,
showLoadingEllipsis = true,
}: CatalogFooterProps) => {
const { t } = useTranslation();
const loadingStateString =
useFeedStateString(subplebbitAddresses) ||
(feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
? t('loading_feed')
: t('looking_for_more_posts');
const loadingStateString = useFeedStateString(subplebbitAddresses) || (combinedFeedLength === 0 ? t('loading_feed') : t('looking_for_more_posts'));
let footerContent;
if (feedLength === 0) {
if (combinedFeedLength === 0) {
footerContent = t('no_threads');
}
if (combinedFeedLength === 0) {
footerContent = t('no_threads');
}
if (hasMore || (subplebbitAddresses && subplebbitAddresses.length === 0)) {
footerContent = (
<>
{subplebbitAddressesWithNewerPosts.length > 0 ? (
{subplebbitAddressesWithNewerPosts.length > 0 && (
<div className={styles.stateString}>
<Trans
i18nKey='newer_threads_available'
@@ -92,53 +71,6 @@ const CatalogFooter = ({
}}
/>
</div>
) : (
(isInAllView || isInSubscriptionsView || isInModView) &&
showMorePostsSuggestion &&
(monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength) &&
(weeklyFeedLength > feedLength ? (
<div className={styles.stateString}>
<Trans
i18nKey='more_threads_last_week'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: (
<Link
to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : isInModView ? '/mod/catalog' : `/${boardPath}/catalog`) + '/1w'}
/>
),
}}
/>
</div>
) : monthlyFeedLength > feedLength ? (
<div className={styles.stateString}>
<Trans
i18nKey='more_threads_last_month'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: (
<Link
to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : isInModView ? '/mod/catalog' : `/${boardPath}/catalog`) + '/1m'}
/>
),
}}
/>
</div>
) : (
<div className={styles.stateString}>
<Trans
i18nKey='more_threads_last_year'
values={{ currentTimeFilterName, count: feedLength }}
components={{
1: (
<Link
to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : isInModView ? '/mod/catalog' : `/${boardPath}/catalog`) + '/1y'}
/>
),
}}
/>
</div>
))
)}
{showLoadingEllipsis && (
<div className={styles.stateString}>
@@ -156,35 +88,17 @@ const CatalogFooter = ({
interface CatalogLoadingProps {
subplebbitAddresses: string[];
hasMore: boolean;
feedLength: number;
weeklyFeedLength: number;
monthlyFeedLength: number;
yearlyFeedLength: number;
combinedFeedLength: number;
state: string | undefined;
subscriptionsLength: number;
combinedFeedLength: number;
error: Error | undefined;
}
const CatalogLoading = ({
subplebbitAddresses,
hasMore,
feedLength,
weeklyFeedLength,
monthlyFeedLength,
yearlyFeedLength,
state,
subscriptionsLength,
combinedFeedLength,
error,
}: CatalogLoadingProps) => {
const CatalogLoading = ({ subplebbitAddresses, hasMore, combinedFeedLength, state, subscriptionsLength, error }: CatalogLoadingProps) => {
const { t } = useTranslation();
const rawFeedStateString = useFeedStateString(subplebbitAddresses);
const loadingStateString =
rawFeedStateString || (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
? t('loading_feed')
: t('looking_for_more_posts');
const loadingStateString = rawFeedStateString || (combinedFeedLength === 0 ? t('loading_feed') : t('looking_for_more_posts'));
return (
<div className={styles.stateString}>
@@ -289,11 +203,10 @@ export interface CatalogProps {
feedCacheKey?: string;
viewType?: 'all' | 'subs' | 'mod' | 'board';
boardIdentifier?: string;
timeFilterNameFromCache?: string;
isVisible?: boolean;
}
const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, timeFilterNameFromCache, isVisible = true }: CatalogProps) => {
const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, isVisible = true }: CatalogProps) => {
const { t } = useTranslation();
const location = useLocation();
const navigate = useNavigate();
@@ -316,7 +229,6 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
return resolvedAddressFromUrl;
}, [boardIdentifierProp, directories, resolvedAddressFromUrl]);
const boardPath = useBoardPath(subplebbitAddress);
const { filterItems, searchText, clearMatchedFilters } = useCatalogFiltersStore();
const account = useAccount();
@@ -352,10 +264,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
}
}, [isInAllView, isInSubscriptionsView, isInModView, location.pathname, navigate]);
const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
const { sortType } = useSortingStore();
const timeFilterName = timeFilterNameFromCache || timeFilterNameFromHook;
const timeFilterSeconds = timeFilterNameFromCache ? timeFilterNameToSeconds(timeFilterNameFromCache) : timeFilterSecondsFromHook;
// Create a stable callback for filter matching
const handleFilterMatch = useCallback((filterIndex: number, cid: string, subplebbitAddress: string) => {
@@ -380,18 +289,12 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
? infiniteFeedPostsPerPage
: paginationFeedPostsPerPage;
const options: any = {
return {
subplebbitAddresses,
sortType,
postsPerPage: catalogPostsPerPage,
filter: createCombinedFilter(filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
};
if (isInAllView || isInSubscriptionsView || isInModView) {
options.newerThan = timeFilterSeconds;
}
return options;
}, [
subplebbitAddresses,
sortType,
@@ -401,7 +304,6 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
effectiveInfiniteScroll,
infiniteFeedPostsPerPage,
paginationFeedPostsPerPage,
timeFilterSeconds,
filterItems,
searchText,
subplebbitAddress,
@@ -474,36 +376,6 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
};
// suggest the user to change time filter if there aren't enough posts
const { feed: weeklyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 7,
filter: createCombinedFilter(filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
});
const { feed: monthlyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 30,
filter: createCombinedFilter(filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
});
const { feed: yearlyFeed } = useFeed({
subplebbitAddresses,
sortType,
newerThan: 60 * 60 * 24 * 365,
filter: createCombinedFilter(filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
});
const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setShowMorePostsSuggestion(true);
}, 5000);
return () => clearTimeout(timer);
}, []);
const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
useEffect(() => {
if (isVisible) {
@@ -513,12 +385,6 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
const subplebbit = useSubplebbit({ subplebbitAddress });
const { error, shortAddress, state, title } = subplebbit || {};
const feedLength = feed.length;
const weeklyFeedLength = weeklyFeed.length;
const monthlyFeedLength = monthlyFeed.length;
const yearlyFeedLength = yearlyFeed.length;
const currentTimeFilterName = timeFilterName || params?.timeFilterName;
// Memoize footer component to preserve identity across renders (Virtuoso optimization)
// Note: useFeedStateString is called inside CatalogFooter to isolate re-renders from backend state changes
@@ -528,19 +394,12 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
<CatalogFooter
subplebbitAddresses={subplebbitAddresses}
hasMore={hasMore}
feedLength={feedLength}
combinedFeedLength={cappedFeed.length}
subplebbitAddressesWithNewerPosts={subplebbitAddressesWithNewerPosts}
onNewerPostsClick={handleNewerPostsButtonClick}
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
showLoadingEllipsis={effectiveInfiniteScroll}
/>
),
@@ -548,19 +407,12 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
[
subplebbitAddresses,
hasMore,
feedLength,
cappedFeed.length,
subplebbitAddressesWithNewerPosts,
handleNewerPostsButtonClick,
isInAllView,
isInSubscriptionsView,
isInModView,
showMorePostsSuggestion,
weeklyFeedLength,
monthlyFeedLength,
yearlyFeedLength,
boardPath,
currentTimeFilterName,
effectiveInfiniteScroll,
],
);
@@ -603,7 +455,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
const rows = useCatalogFeedRows(columnCount, processedFeed, isFeedLoaded, subplebbit);
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
const virtuosoStateKey = feedCacheKey ? `${feedCacheKey}-${sortType}-${timeFilterSeconds}` : `${location.pathname}-${sortType}-${timeFilterSeconds}-catalog`;
const virtuosoStateKey = feedCacheKey ? `${feedCacheKey}-${sortType}` : `${location.pathname}-${sortType}-catalog`;
const navigationType = useNavigationType();
const hasBeenVisibleRef = useRef(false);
@@ -709,19 +561,12 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
<CatalogFooter
subplebbitAddresses={subplebbitAddresses}
hasMore={hasMore}
feedLength={feedLength}
combinedFeedLength={cappedFeed.length}
subplebbitAddressesWithNewerPosts={subplebbitAddressesWithNewerPosts}
onNewerPostsClick={handleNewerPostsButtonClick}
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
showLoadingEllipsis={true}
/>
</>
@@ -734,19 +579,12 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
<CatalogFooter
subplebbitAddresses={subplebbitAddresses}
hasMore={hasMore}
feedLength={feedLength}
combinedFeedLength={cappedFeed.length}
subplebbitAddressesWithNewerPosts={subplebbitAddressesWithNewerPosts}
onNewerPostsClick={handleNewerPostsButtonClick}
isInAllView={isInAllView}
isInSubscriptionsView={isInSubscriptionsView}
isInModView={isInModView}
showMorePostsSuggestion={showMorePostsSuggestion}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
boardPath={boardPath}
currentTimeFilterName={currentTimeFilterName}
showLoadingEllipsis={false}
/>
</>
@@ -757,13 +595,9 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
<CatalogLoading
subplebbitAddresses={subplebbitAddresses}
hasMore={hasMore}
feedLength={feedLength}
weeklyFeedLength={weeklyFeedLength}
monthlyFeedLength={monthlyFeedLength}
yearlyFeedLength={yearlyFeedLength}
combinedFeedLength={cappedFeed.length}
state={state}
subscriptionsLength={isInSubscriptionsView ? subscriptions?.length || 0 : 1}
combinedFeedLength={cappedFeed.length}
error={error}
/>
</div>