diff --git a/CHANGELOG.md b/CHANGELOG.md index d3953313c7..db0d025621 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +#### v2.8.2 (2023-01-13) + +##### Chores + +* incrementing version number - v2.8.1 (727f879e) +* update changelog for v2.8.1 (d17d4ec0) + +##### Bug Fixes + +* move call to `filter:middleware.buildHeader` out of parallel so that req can be overridden by plugins prior to loading config (25ae58e8) + +#### v2.8.1 (2022-12-30) + +##### Chores + +* fallbacks for new language string (8a69e740) +* remove extraneous lines from changelog (bbaf26ce) +* incrementing version number - v2.8.0 (8e77673d) +* update changelog for v2.8.0 (a5c2edb9) + +##### Bug Fixes + +* vulnerability in socket.io nested namespaces (#11117) (586eed14) +* lock post/reply similar to user.create (1ea9481a) + #### v2.8.0 (2022-12-21) ##### Chores diff --git a/install/data/defaults.json b/install/data/defaults.json index 9ba908e913..bd2d4d5296 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -4,6 +4,7 @@ "defaultLang": "en-GB", "loginDays": 14, "loginSeconds": 0, + "sessionDuration": 0, "loginAttempts": 5, "lockoutDuration": 60, "adminReloginDuration": 60, diff --git a/install/package.json b/install/package.json index 27884a90d2..f50818816a 100644 --- a/install/package.json +++ b/install/package.json @@ -46,7 +46,7 @@ "cli-graph": "3.2.2", "clipboard": "2.0.11", "colors": "1.4.0", - "commander": "9.4.1", + "commander": "9.5.0", "compare-versions": "5.0.3", "compression": "1.7.4", "connect-flash": "0.1.1", @@ -55,12 +55,12 @@ "connect-pg-simple": "8.0.0", "connect-redis": "6.1.3", "cookie-parser": "1.4.6", - "cron": "2.1.0", + "cron": "2.2.0", "cropperjs": "1.5.13", "csurf": "1.11.0", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.16.10", + "esbuild": "0.16.16", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", @@ -112,7 +112,7 @@ "passport-local": "1.0.0", "pg": "8.8.0", "pg-cursor": "2.7.4", - "postcss": "8.4.20", + "postcss": "8.4.21", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", @@ -152,16 +152,16 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.0.3", - "@commitlint/cli": "17.3.0", - "@commitlint/config-angular": "17.3.0", + "@commitlint/cli": "17.4.1", + "@commitlint/config-angular": "17.4.0", "coveralls": "3.1.1", - "eslint": "8.30.0", + "eslint": "8.31.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.26.0", "grunt": "1.5.3", "grunt-contrib-watch": "1.1.0", - "husky": "8.0.2", - "jsdom": "20.0.3", + "husky": "8.0.3", + "jsdom": "21.0.0", "lint-staged": "13.1.0", "mocha": "10.2.0", "mocha-lcov-reporter": "1.3.0", diff --git a/public/language/ar/admin/advanced/events.json b/public/language/ar/admin/advanced/events.json index 218d088830..263dd0e062 100644 --- a/public/language/ar/admin/advanced/events.json +++ b/public/language/ar/admin/advanced/events.json @@ -3,7 +3,7 @@ "no-events": "لا توجد أحداث", "control-panel": "لوحة تحكم الأحداث", "delete-events": "حذف الاحداث", - "confirm-delete-all-events": "Are you sure you want to delete all logged events?", + "confirm-delete-all-events": "هل أنت متاكد أنك تريد حذف كل سجل اﻻحداث؟", "filters": "تصفية", "filters-apply": "تطبيق التصفية", "filter-type": "نوع الحدث", diff --git a/public/language/ar/admin/manage/registration.json b/public/language/ar/admin/manage/registration.json index f51b4d56e6..0dc019b066 100644 --- a/public/language/ar/admin/manage/registration.json +++ b/public/language/ar/admin/manage/registration.json @@ -1,20 +1,20 @@ { - "queue": "Queue", + "queue": "الطابور", "description": "There are no users in the registration queue.
To enable this feature, go to Settings → User → User Registration and set Registration Type to \"Admin Approval\".", - "list.name": "Name", - "list.email": "Email", + "list.name": "اﻹسم", + "list.email": "البريد الإلكتروني", "list.ip": "IP", - "list.time": "Time", + "list.time": "التوقيت", "list.username-spam": "Frequency: %1 Appears: %2 Confidence: %3", "list.email-spam": "Frequency: %1 Appears: %2", "list.ip-spam": "Frequency: %1 Appears: %2", - "invitations": "Invitations", + "invitations": "الدعوات", "invitations.description": "Below is a complete list of invitations sent. Use ctrl-f to search through the list by email or username.

The username will be displayed to the right of the emails for users who have redeemed their invitations.", - "invitations.inviter-username": "Inviter Username", - "invitations.invitee-email": "Invitee Email", - "invitations.invitee-username": "Invitee Username (if registered)", + "invitations.inviter-username": "أسم المستخدم الداعي", + "invitations.invitee-email": "البريد اﻻلكتروني للمدعو", + "invitations.invitee-username": "اسم المستخم للمدعو (اذا كان مسجل)", - "invitations.confirm-delete": "Are you sure you wish to delete this invitation?" + "invitations.confirm-delete": "هل أنت متأكد من أنك تريد حذف هذه الدعوة؟" } \ No newline at end of file diff --git a/public/language/ar/admin/settings/user.json b/public/language/ar/admin/settings/user.json index 56f835492a..6fa1337000 100644 --- a/public/language/ar/admin/settings/user.json +++ b/public/language/ar/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "تسجيل المستخدم", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 9cf3543922..ed2cb779b5 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "يسمح لك بالنشر مرة كل %1 ثانية - يرجى الإنتظار قبل النشر مجدداً", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/ar/user.json b/public/language/ar/user.json index 6edb9b3752..5a72edac6e 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -1,6 +1,6 @@ { "banned": "محظور", - "muted": "Muted", + "muted": "كتم ", "offline": "غير متصل", "deleted": "محذوف", "username": "إسم المستخدم", @@ -9,7 +9,7 @@ "email": "البريد الإلكتروني", "confirm_email": "تأكيد عنوان البريد الإلكتروني", "account_info": "معلومات الحساب", - "admin_actions_label": "Administrative Actions", + "admin_actions_label": "الإجراءات الإدارية", "ban_account": "حظر الحساب", "ban_account_confirm": "هل تريد حقاً حظر هاذا العضو؟", "unban_account": "إزالة حظر الحساب", @@ -24,7 +24,7 @@ "delete_account_content_confirm": "Are you sure you want to delete this account's content (posts/topics/uploads)?
This action is irreversible and you will not be able to recover any data

", "delete_all_confirm": "Are you sure you want to delete this account and all of its content (posts/topics/uploads)?
This action is irreversible and you will not be able to recover any data

", "account-deleted": "تم حذف الحساب", - "account-content-deleted": "Account content deleted", + "account-content-deleted": "تم حذف محتوى حساب", "fullname": "الاسم الكامل", "website": "الموقع الإلكتروني", "location": "الموقع", @@ -34,25 +34,25 @@ "profile": "الملف الشخصي", "profile_views": "عدد المشاهدات", "reputation": "السمعة", - "bookmarks": "Bookmarks", - "watched_categories": "Watched categories", - "change_all": "Change All", + "bookmarks": "المفضلات", + "watched_categories": "الأقسام المُتابعة", + "change_all": "غير الكل", "watched": "متابع", "ignored": "تم تجاهله", - "default-category-watch-state": "Default category watch state", + "default-category-watch-state": "حالة مشاهدة اﻻقسام الافتراضية", "followers": "المتابعون", "following": "يتابع", - "blocks": "Blocks", - "block_toggle": "Toggle Block", - "block_user": "Block User", - "unblock_user": "Unblock User", + "blocks": "الكتل", + "block_toggle": "تبديل الكتلة", + "block_user": "أحظر المستخدم", + "unblock_user": "ألغ حظر المستخدم", "aboutme": "معلومة عنك او السيرة الذاتية", "signature": "توقيع", "birthday": "عيد ميلاد", "chat": "محادثة", "chat_with": "متابعة الدردشة مع %1", "new_chat_with": "بدء دردشة جديدة مع %1", - "flag-profile": "Flag Profile", + "flag-profile": "ضع علامة على الملف الشخصي", "follow": "تابع", "unfollow": "إلغاء المتابعة", "more": "المزيد", @@ -87,7 +87,7 @@ "remove_cover_picture_confirm": "هل تريد بالتأكيد إزالة صورة الغلاف؟", "crop_picture": "إقتصاص الصورة", "upload_cropped_picture": "إقتصاص ورفع", - "avatar-background-colour": "Avatar background colour", + "avatar-background-colour": "لون الخلفية للصورة الرمزية", "settings": "خيارات", "show_email": "أظهر بريدي الإلكتروني", "show_fullname": "أظهر اسمي الكامل", @@ -108,16 +108,16 @@ "has_no_ignored_topics": "هذا المستخدم لم يقم بتجاهل اية مواضيع حتى الآن.", "has_no_upvoted_posts": "هذا المستخدم لم يقم بالتصويت للأعلى لأي مشاركة حتى الآن.", "has_no_downvoted_posts": "هذا المستخدم لم يقم بالتصويت للأسفل لأي مشاركة حتى الآن.", - "has_no_controversial_posts": "This user does not have any downvoted posts yet.", - "has_no_blocks": "You have blocked no users.", + "has_no_controversial_posts": "هذا المستخدم ﻻيمتلك تصويت للأسفل لأي مشاركة حتى الآن.", + "has_no_blocks": "أنت لم تحظر اي مستخدم", "email_hidden": "البريد الإلكتروني مخفي", "hidden": "مخفي", "paginate_description": "عرض المواضيع والردود موزعة على صفحات عوضاً عن التمرير اللانهائي.", "topics_per_page": "المواضيع في كل صفحة", "posts_per_page": "الردود في كل صفحة", "max_items_per_page": "أقصى %1", - "acp_language": "Admin Page Language", - "notifications": "Notifications", + "acp_language": "لغة صفحة اﻻدارة", + "notifications": "التنبيهات", "upvote-notif-freq": "معدل تكرار تنبيهات التصويت للأعلى", "upvote-notif-freq.all": "كل التصويتات للأعلى", "upvote-notif-freq.first": "First Per Post", diff --git a/public/language/bg/admin/settings/user.json b/public/language/bg/admin/settings/user.json index 618e3c7361..9c868b99bb 100644 --- a/public/language/bg/admin/settings/user.json +++ b/public/language/bg/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Дни", "session-time-seconds": "Секунди", "session-time-help": "Тези стойности се използват за определяне на дължината на периода, през който потребителите ще останат вписани в системата, ако поставят отметка в полето „Запомнете ме“ при вписването. Имайте предвид, че ще се използва само една от тези стойности. Ако няма стойност за секунди, ще се използва стойността за дни. Ако няма и стойност за дни, то ще се използва стандартната стойност от 14 дни.", + "session-duration": "Продължителност на сесията, ако „Запомнете ме“ не е отбелязано (в секунди)", + "session-duration-help": "По подразбиране (или ако стойността е 0) потребителят ще остане вписан докато не изтече сесията му (обикновено докато браузърът или разделът не бъде затворен). Използвайте тази настройка, ако искате да определите точно време (в секунди), след което сесията на потребителя да бъде прекратена.", "online-cutoff": "Брой минути, след които потребителят ще бъде смятан за неактивен", "online-cutoff-help": "Ако потребителят не извършва никакви действия през този период, ще бъде смятан за неактивен и няма да получава известия в реално време.", "registration": "Регистриране на потребителите", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 2abf4a891b..dd91902e96 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Не е избрана категория.", "too-many-posts": "Можете да публикувате веднъж на %1 секунда/и – моля, изчакайте малко, преди да опитате да публикувате отново", "too-many-posts-newbie": "Като нов потребител, Вие можете да публикувате веднъж на %1 секунда/и, докато не натрупате %2 репутация – моля, изчакайте малко, преди да опитате да публикувате отново", + "already-posting": "В момента публикувате", "tag-too-short": "Моля, въведете по-дълъг етикет. Етикетите трябва да съдържат поне %1 символ(а)", "tag-too-long": "Моля, въведете по-кратък етикет. Етикетите трябва да съдържат не повече от %1 символ(а)", "not-enough-tags": "Недостатъчно етикети. Темите трябва да имат поне %1 етикет(а)", diff --git a/public/language/bn/admin/settings/user.json b/public/language/bn/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/bn/admin/settings/user.json +++ b/public/language/bn/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index a4aab7b399..ff59e31fbe 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/cs/admin/settings/user.json b/public/language/cs/admin/settings/user.json index da3647a63f..cfda7dfdd0 100644 --- a/public/language/cs/admin/settings/user.json +++ b/public/language/cs/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dny", "session-time-seconds": "Sekundy", "session-time-help": "Tyto hodnoty jsou využity v rozhodujícím procesu, jak dlouho zůstane uživatel přihlášen při zaškrtnutí „Zapamatovat si mě”. Nezapomeňte, že bude použita jen jedna hodnota. Jestli není nastavena hodnota v sekundách, budou brány v potaz dny. Nebudou-li nastaveny dny, hodnota bude standardně 14 dní.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Počet minut, kdy je uživatel považován za neaktivního", "online-cutoff-help": "Nebude-li uživatel vykonávat žádnou akci v tomto časovém rozpětí, bude považován za neaktivního a nebude docházet k automatickým aktualizacím.", "registration": "Registrace uživatele", diff --git a/public/language/cs/category.json b/public/language/cs/category.json index bb53e67664..4952cd6b1f 100644 --- a/public/language/cs/category.json +++ b/public/language/cs/category.json @@ -19,5 +19,5 @@ "notwatching.message": "Nyní nesledujete aktualizace z této kategorie a všech podkategorií", "ignoring.message": "Nyní ignorujete aktualizace této kategorie a všech jejich kategorii", "watched-categories": "Sledované kategorie", - "x-more-categories": "%1 more categories" + "x-more-categories": "%1 dalších kategorií" } \ No newline at end of file diff --git a/public/language/cs/email.json b/public/language/cs/email.json index 470ba7eca8..fada8d0597 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -6,9 +6,9 @@ "greeting_no_name": "Dobrý den", "greeting_with_name": "Dobrý den %1", "email.verify-your-email.subject": "Ověřte prosím vaší e-mailovou adresu", - "email.verify.text1": "You've requested that we change or confirm your email address", - "email.verify.text2": "For security purposes, we only change or confirm the email address on file once its ownership has been confirmed via email. If you did not request this, no action is required on your part.", - "email.verify.text3": "Once you confirm this email address, we will replace your current email address with this one (%1).", + "email.verify.text1": "Požádali jste o změnu nebo potvrzení Vaší emailové adresy", + "email.verify.text2": "Z bezpečnostních důvodů potvrzujeme emailové adresy až ve chvíli, kdy potvrdíte jejich vlastnictví. Pokud jste toto nevyžádali, není třeba na Vaší straně žádné další akce.", + "email.verify.text3": "Jakmile adresu potvrdíte, nahradíme vaši současnou emailovou adresu touto (%1).", "welcome.text1": "Děkujeme vám za registraci na %1!", "welcome.text2": "Pro úplnou aktivaci vašeho účtu potřebujeme ověřit vaši e-mailovou adresu.", "welcome.text3": "Administrátor právě potvrdil vaší registraci. Nyní se můžete přihlásit jménem a heslem.", @@ -23,8 +23,8 @@ "reset.notify.text1": "Informujeme Vás, že na %1 vaše heslo bylo úspěšně změněno.", "reset.notify.text2": "Pokud jste to neschválil, prosíme neprodleně kontaktujte správce.", "digest.latest_topics": "Nejnovější témata od %1", - "digest.top-topics": "Top topics from %1", - "digest.popular-topics": "Popular topics from %1", + "digest.top-topics": "Nejlepší témata od %1", + "digest.popular-topics": "Oblíbená témata od %1", "digest.cta": "Kliknutím zde navštívíte %1", "digest.unsub.info": "Tento výtah vám byl odeslán, protože jste si to nastavili ve vašich odběrech.", "digest.day": "den", @@ -48,8 +48,8 @@ "unsub.cta": "Chcete-li změnit tyto nastavení, klikněte zde.", "unsubscribe": "odhlásit", "unsub.success": "Již nebudete nadále dostávat e-maily z %1", - "unsub.failure.title": "Unable to unsubscribe", - "unsub.failure.message": "Unfortunately, we were not able to unsubscribe you from the mailing list, as there was an issue with the link. However, you can alter your email preferences by going to your user settings.

(error: %1)", + "unsub.failure.title": "Zrušení odběru selhalo", + "unsub.failure.message": "Bohužel jsme nebyli schopni Vás odebrat z emailové korespondence, jelikož nastal problém s odkazem. Nicméně je možné upravit emailové předvolby ve Vašich uživatelských nastaveních.

(chyba: %1)", "banned.subject": "Byl jste zablokován od %1", "banned.text1": "Uživatel %1 byl zablokován od %2", "banned.text2": "Blokace bude trvat do %1", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 0ea7d387b9..d2c66306cf 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Nebyla vybrána kategorie.", "too-many-posts": "Můžete přispívat jednou za %1 sekund - vyčkejte tedy, než vytvoříte další příspěvek", "too-many-posts-newbie": "Jako nový uživatel, můžete přispívat jednou za %1 sekund, dokud nezískáte pověst %2 - vyčkejte tedy, než vytvoříte další příspěvek", + "already-posting": "You are already posting", "tag-too-short": "Zadejte delší značku. Značky by měli mít alespoň %1 znaků", "tag-too-long": "Zadejte kratší značku. Značky nesmí být delší než %1 znaků", "not-enough-tags": "Málo značek. Téma musí obsahovat alespoň %1 značek", diff --git a/public/language/cs/flags.json b/public/language/cs/flags.json index d20bbdf652..b70ca55245 100644 --- a/public/language/cs/flags.json +++ b/public/language/cs/flags.json @@ -26,10 +26,10 @@ "filter-quick-mine": "Přiřazeno mě", "filter-cid-all": "Všechny kategorie", "apply-filters": "Použít filtry", - "more-filters": "More Filters", - "fewer-filters": "Fewer Filters", + "more-filters": "Další filtry", + "fewer-filters": "Méně filtrů", - "quick-actions": "Quick Actions", + "quick-actions": "Rychlé akce", "flagged-user": "Označený uživatel", "view-profile": "Zobrazit profil", "start-new-chat": "Začít novou konverzaci", @@ -62,7 +62,7 @@ "state-rejected": "Zamítnuto", "no-assignee": "Nepřiřazeno", - "sort": "Sort by", + "sort": "Seřadit dle", "sort-newest": "Newest first", "sort-oldest": "Oldest first", "sort-reports": "Most reports", diff --git a/public/language/cs/global.json b/public/language/cs/global.json index 73dfef6204..ab9b47c270 100644 --- a/public/language/cs/global.json +++ b/public/language/cs/global.json @@ -23,14 +23,14 @@ "close": "Zrušit", "pagination": "Stránkování", "pagination.out_of": "%1 z %2", - "pagination.enter_index": "Go to post index", + "pagination.enter_index": "Přejít na n-tý příspěvek", "header.admin": "Administrace", "header.categories": "Kategorie", "header.recent": "Nejnovější", "header.unread": "Nepřečtené", "header.tags": "Značky", "header.popular": "Populární", - "header.top": "Top", + "header.top": "Nejlepší", "header.users": "Uživatelé", "header.groups": "Skupiny", "header.chats": "Chaty", @@ -54,24 +54,24 @@ "users": "Uživatelé", "topics": "Témata", "posts": "Příspěvky", - "x-posts": "%1 posts", + "x-posts": "% příspěvků", "best": "Nejlepší", - "controversial": "Controversial", + "controversial": "Kontroverzní", "votes": "Počet hlasů", - "x-votes": "%1 votes", - "voters": "Voters", + "x-votes": "%1 hlasů", + "voters": "Hlasující", "upvoters": "Souhlasník", "upvoted": "Souhlasů", "downvoters": "Nesouhlasník", "downvoted": "Nesouhlasů", "views": "Zobrazení", - "posters": "Posters", + "posters": "Přispěvatelé", "reputation": "Reputace", "lastpost": "Poslední příspěvek", "firstpost": "První příspěvek", "read_more": "čtěte více", "more": "Více", - "none": "None", + "none": "Žádné", "posted_ago_by_guest": "přispěl %1 host", "posted_ago_by": "přispěl %1 od %2", "posted_ago": "přispěl %1", @@ -97,8 +97,8 @@ "guest": "Host", "guests": "Hosté", "former_user": "Bývalý uživatel", - "system-user": "System", - "unknown-user": "Unknown user", + "system-user": "Systém", + "unknown-user": "Neznámý uživatel", "updated.title": "Fórum bylo zaktualizováno", "updated.message": "Toto fórum bylo právě aktualizováno na poslední verzi. Klikněte zde a obnovte tuto stránku.", "privacy": "Soukromí", diff --git a/public/language/cs/language.json b/public/language/cs/language.json index d2a404b6f7..4ebf3b1471 100644 --- a/public/language/cs/language.json +++ b/public/language/cs/language.json @@ -1,5 +1,5 @@ { - "name": "Czech", + "name": "Čeština (Česká Republika)", "code": "cs", "dir": "ltr" } \ No newline at end of file diff --git a/public/language/cs/login.json b/public/language/cs/login.json index 49463eae9d..dabe2b9412 100644 --- a/public/language/cs/login.json +++ b/public/language/cs/login.json @@ -8,5 +8,5 @@ "login_successful": "Přihlášení proběhlo úspěšně!", "dont_have_account": "Nemáte účet?", "logged-out-due-to-inactivity": "Z důvodu nečinnosti jste byl odhlášen z ovládacího panelu administrátora", - "caps-lock-enabled": "Caps Lock is enabled" + "caps-lock-enabled": "Máte zapnutý Caps Lock" } \ No newline at end of file diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json index 11af95b03f..085659c2e9 100644 --- a/public/language/cs/notifications.json +++ b/public/language/cs/notifications.json @@ -1,8 +1,8 @@ { "title": "Upozornění", "no_notifs": "Nemáte žádná nová upozornění.", - "see_all": "All notifications", - "mark_all_read": "Mark all read", + "see_all": "Všechna upozornění", + "mark_all_read": "Označit vše jako přečtené", "back_to_home": "Zpět na %1", "outgoing_link": "Odkaz mimo fórum", "outgoing_link_message": "Opouštíte %1", @@ -14,7 +14,7 @@ "topics": "Témata", "replies": "Odpovědi", "chat": "Konverzace", - "group-chat": "Group Chats", + "group-chat": "Skupinová konverzace", "follows": "Sledování", "upvote": "Souhlasy", "new-flags": "Nové označení", @@ -36,7 +36,7 @@ "user_posted_to_dual": "%1%2 odpověděli na: %3", "user_posted_to_multiple": "%1 a %2 další/ch odpověděli na %3", "user_posted_topic": "%1 založil nové téma: %2", - "user_edited_post": "%1 has edited a post in %2", + "user_edited_post": "Příspěvek %2 byl upraven uživatelem %1 ", "user_started_following_you": "%1 vás začal sledovat.", "user_started_following_you_dual": "%1 a %2 vás začali sledovat.", "user_started_following_you_multiple": "%1 a %2 další/ch vás začali sledovat.", @@ -44,12 +44,12 @@ "new_register_multiple": "Je zde %1 registračních požadavků čeká na vyřízení.", "flag_assigned_to_you": "Označení %1 vám bylo přiřazeno", "post_awaiting_review": "Příspěvek na schválení", - "profile-exported": "%1 profile exported, click to download", - "posts-exported": "%1 posts exported, click to download", - "uploads-exported": "%1 uploads exported, click to download", - "users-csv-exported": "Users csv exported, click to download", - "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.", - "post-queue-rejected": "Your queued post has been rejected.", + "profile-exported": "%1 profil byl exportován, klikněte pro jeho stažení", + "posts-exported": "%1 příspěvků bylo exportováno, klikněte pro jejich stažení", + "uploads-exported": "%1 nahraných souborů bylo exportováno, klikněte pro jejich stažení", + "users-csv-exported": "Seznam uživatelů v csv byl exportován, klikněte pro stažení", + "post-queue-accepted": "Váš příspěvek byl akceptován. Klikněte zde pro jeho zobrazení.", + "post-queue-rejected": "Váš příspěvek byl odmítnut.", "post-queue-notify": "Queued post received a notification:
\"%1\"", "email-confirmed": "E-mail potvrzen", "email-confirmed-message": "Děkujeme za ověření vaší e-mailové adresy. Váš účet je nyní aktivní.", @@ -59,17 +59,17 @@ "notification_only": "Jen oznámení", "email_only": "Jen e-mail", "notification_and_email": "Oznámení a e-mail", - "notificationType_upvote": "Vyjádří-li někdo souhlas s vaším příspěvkem", - "notificationType_new-topic": "Začne-li někdo sledovat příspěvky a téma", - "notificationType_new-reply": "Bude-li přidán nový příspěvek v tématu, které sledujete", - "notificationType_post-edit": "When a post is edited in a topic you are watching", - "notificationType_follow": "Začne-li vás někdo sledovat", + "notificationType_upvote": "Jakmile někdo vyjádří souhlas s vaším příspěvkem", + "notificationType_new-topic": "Jakmile někdo koho sledujete vytvoří nové téma", + "notificationType_new-reply": "Jakmile je přidán nový příspěvek v tématu, které sledujete", + "notificationType_post-edit": "Jakmile je upraven příspěvek v tématu, které sledujete", + "notificationType_follow": "Jakmile vás někdo začne sledovat", "notificationType_new-chat": "Obdržíte-li novou konverzační zprávu", - "notificationType_new-group-chat": "When you receive a group chat message", + "notificationType_new-group-chat": "Když obdržíte zprávu ve skupinové konverzaci", "notificationType_group-invite": "Obdržíte-li pozvání ke skupině", - "notificationType_group-leave": "When a user leaves your group", - "notificationType_group-request-membership": "Pokud někdo požaduje připojení se do vaší skupiny", - "notificationType_new-register": "Bude-li někdo přidán do registrační fronty", + "notificationType_group-leave": "Když uživatel opustí Vaši skupinu", + "notificationType_group-request-membership": "Jakmile někdo pošle žádost o připojení se do vaší skupiny", + "notificationType_new-register": "Jakmile je někdo přidán do registrační fronty", "notificationType_post-queue": "Bude-li přidán nový příspěvek do fronty", "notificationType_new-post-flag": "Bude-li příspěvek označen", "notificationType_new-user-flag": "Bude-li uživatel označen" diff --git a/public/language/cs/user.json b/public/language/cs/user.json index 8eac8be334..5344d796bf 100644 --- a/public/language/cs/user.json +++ b/public/language/cs/user.json @@ -1,6 +1,6 @@ { "banned": "Zablokován", - "muted": "Muted", + "muted": "Ztlumen", "offline": "Nepřipojen", "deleted": "Odstraněno", "username": "Uživatelské jméno", @@ -13,8 +13,8 @@ "ban_account": "Zablokovat účet", "ban_account_confirm": "Opravdu chcete zablokovat tohoto uživatele?", "unban_account": "Odblokovat účet", - "mute_account": "Mute Account", - "unmute_account": "Unmute Account", + "mute_account": "Ztlumit účet", + "unmute_account": "Zrušit ztlumení účtu", "delete_account": "Odstranit účet", "delete_account_as_admin": "Delete Account", "delete_content": "Delete Account Content", @@ -97,7 +97,7 @@ "digest_off": "Vypnuto", "digest_daily": "Denně", "digest_weekly": "Týdně", - "digest_biweekly": "Bi-Weekly", + "digest_biweekly": "Každý druhý týden", "digest_monthly": "Měsíčně", "has_no_follower": "Tohoto uživatele nikdo nesleduje :(", "follows_no_one": "Tento uživatel nikoho nesleduje :(", @@ -117,7 +117,7 @@ "posts_per_page": "Příspěvků na stránce", "max_items_per_page": "Maximum %1", "acp_language": "Jazyk stránky správce", - "notifications": "Notifications", + "notifications": "Oznámení", "upvote-notif-freq": "Frekvence upozornění na souhlasy", "upvote-notif-freq.all": "Všechny souhlasy", "upvote-notif-freq.first": "První podle příspěvku", @@ -191,9 +191,9 @@ "consent.export-uploads-success": "Exporting uploads, you will get a notification when it is complete.", "consent.export_posts": "Exportovat příspěvky (*.csv)", "consent.export-posts-success": "Exporting posts, you will get a notification when it is complete.", - "emailUpdate.intro": "Please enter your email address below. This forum uses your email address for scheduled digest and notifications, as well as for account recovery in the event of a lost password.", + "emailUpdate.intro": "Prosíme vložte svou emailovou adresu. Toto fórum používá Vaši emailovou adresu pro zasílání pravidelných přehledů a oznámení. Emailová adresa je také použita pro obnovení přístupu v případě ztráty hesla.", "emailUpdate.optional": "This field is optional. You are not obligated to provide your email address, but without a validated email you will not be able to recover your account or login with your email.", "emailUpdate.required": "This field is required.", - "emailUpdate.change-instructions": "A confirmation email will be sent to the entered email address with a unique link. Accessing that link will confirm your ownership of the email address and it will become active on your account. At any time, you are able to update your email on file from within your account page.", + "emailUpdate.change-instructions": "Potvrzovací email s unikátním odkazem bude odeslán na poskytnutou emailovou adresu. Rozkliknutím tohoto odkazu potvrdíte vlastnictví emailové adresy a ta se stane aktivní na Vašem účtě. Kdykoliv můžete emailovou adresu změnit z vašeho profilu.", "emailUpdate.password-challenge": "Please enter your password in order to verify account ownership." } \ No newline at end of file diff --git a/public/language/da/admin/settings/user.json b/public/language/da/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/da/admin/settings/user.json +++ b/public/language/da/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/da/error.json b/public/language/da/error.json index a8af5ad84d..d7612af9e1 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Du kan højest skrive et indlæg hver %1 sekund(er) - venligst vent et øjeblik før næste indlæg", "too-many-posts-newbie": "Som ny bruger kan du kun skrive et indlæg engang hvert %1. sekund() indtil du har optjent %2 omdømme point - venligst vent et øjeblik før næste indlæg.", + "already-posting": "You are already posting", "tag-too-short": "Indtast et længere tag. Tags skal indeholde mindst %1 karakter(er).", "tag-too-long": "Indtast et længere tag. Tags kan ikke være længere end %1 karakter(er).", "not-enough-tags": "Ikke nok tags. Tråde skal have mindst %1 tag(s)", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index 2af71b2cc6..b032894126 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Tage", "session-time-seconds": "Sekunden", "session-time-help": "Diese Werte legen fest, wie lange ein Benutzer angemeldet bleibt, wenn er die Option "Eingeloggt bleiben" beim Login aktiviert. Beachte, dass nur einer dieser Werte verwendet wird. Wenn Sekunden nicht festgelegt wurden, greifen wir auf Tage zurück. Wenn Tage nicht festlegt wurden, werden standardmäßig 14 Tage verwendet.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minuten nachdem der Benutzer als inaktiv betrachtet wird", "online-cutoff-help": "Wenn der Benutzer für diese Dauer keine Aktionen ausführt, wird er als inaktiv betrachtet und erhält keine Echtzeit-Updates.", "registration": "Benutzer Registrierung", diff --git a/public/language/de/error.json b/public/language/de/error.json index bd3dd4083d..76ba50487e 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategorie nicht ausgewählt", "too-many-posts": "Du kannst nur einen Beitrag innerhalb von %1 Sekunden erstellen - Bitte warte bevor Du erneut einen Beitrag erstellst.", "too-many-posts-newbie": "Als neuer Benutzer kannst du nur einmal alle %1 Sekunde(n) posten, bis du %2 Reputation erworben hast - bitte warte, bevor du erneut postest", + "already-posting": "You are already posting", "tag-too-short": "Bitte gebe ein längeres Schlagwort ein. Schlagworte sollten mindestens %1 Zeichen enthalten.", "tag-too-long": "Bitte gebe ein kürzeres Schlagwort ein. Schlagworte können nicht länger als %1 Zeichen sein.", "not-enough-tags": "Nicht genügend Schlagworte. Themen müssen mindestens %1 Schlagwort(e) enthalten", diff --git a/public/language/el/admin/settings/user.json b/public/language/el/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/el/admin/settings/user.json +++ b/public/language/el/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/el/error.json b/public/language/el/error.json index 295e09f069..38d4c42c33 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/en-GB/admin/settings/user.json +++ b/public/language/en-GB/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index b25f6a688c..14d080b2af 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -101,6 +101,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/en-US/admin/settings/user.json b/public/language/en-US/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/en-US/admin/settings/user.json +++ b/public/language/en-US/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json index 5c9c3c1078..4191fad94f 100644 --- a/public/language/en-US/error.json +++ b/public/language/en-US/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/en-x-pirate/admin/settings/user.json b/public/language/en-x-pirate/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/en-x-pirate/admin/settings/user.json +++ b/public/language/en-x-pirate/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json index 5c9c3c1078..4191fad94f 100644 --- a/public/language/en-x-pirate/error.json +++ b/public/language/en-x-pirate/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/es/admin/settings/user.json b/public/language/es/admin/settings/user.json index 60eebe04bf..e57c6e6e07 100644 --- a/public/language/es/admin/settings/user.json +++ b/public/language/es/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Días", "session-time-seconds": "Segundos", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutos después de que el usuario se considere inactivo", "online-cutoff-help": "Si el usuario no realiza acciones durante este tiempo, se considerarán inactivos y no recibirán actualizaciones en tiempo real.", "registration": "Registro de Usuario", diff --git a/public/language/es/error.json b/public/language/es/error.json index c6e8e97a1c..89111f9ce7 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categoría no seleccionada.", "too-many-posts": "Solo puedes publicar una vez cada %1 segundo(s) - por favor espere antes de volver a publicar", "too-many-posts-newbie": "Como nuevo usuario, solo puedes publicar una vez cada %1 segundo(s) hasta hayas ganado una reputación de %2 - por favor espera antes de volver a publicar", + "already-posting": "You are already posting", "tag-too-short": "Por favor introduce una etiqueta más larga. Las etiquetas deben contener por lo menos %1 caractere(s)", "tag-too-long": "Por favor introduce una etiqueta más corta. Las etiquetas no pueden exceder los %1 caractere(s)", "not-enough-tags": "Etiquetas insuficientes. El tema debe tener al menos %1 etiqueta(s).", diff --git a/public/language/et/admin/settings/user.json b/public/language/et/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/et/admin/settings/user.json +++ b/public/language/et/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/et/error.json b/public/language/et/error.json index 99402c0356..46b6967ef2 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Te saate postitada %1 sekundi tagant - palun oodake enne uue postituse tegemist.", "too-many-posts-newbie": "Uue kasutajana saadte postitada vaid iga %1 sekundi tagant, seniks kuni olete teeninud vähemalt %2 reputatsiooni - palun oodake enne uue postituse tegemist.", + "already-posting": "You are already posting", "tag-too-short": "Palun sisestage pikem märksõna. Märksõna pikkus peab olema vähemalt %1 tähemärk(i).", "tag-too-long": "Palun sisestage lühem märksõna. Märksõna pikkus peab olema vähem kui %1 tähemärk(i).", "not-enough-tags": "Liiga vähe märksõnu. Teemadel peab olemalt vähemalt %1 märksõna", diff --git a/public/language/fa-IR/admin/settings/user.json b/public/language/fa-IR/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/fa-IR/admin/settings/user.json +++ b/public/language/fa-IR/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json index 61b0066ce5..12123473d5 100644 --- a/public/language/fa-IR/error.json +++ b/public/language/fa-IR/error.json @@ -88,6 +88,7 @@ "category-not-selected": "هیچ دسته‌بندی انتخاب نشده.", "too-many-posts": "شما می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ارسال پست جدید صبر کنید", "too-many-posts-newbie": "به عنوان یک کاربر جدید ، تا زمانی که شما %2 اعتبار کسب کنید می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ایجاد پست جدید صبر کنید .", + "already-posting": "You are already posting", "tag-too-short": "لطفا برچسب بلندتری وارد کنید. برچسبها باید حداقل %1 کاراکتر داشته باشند.", "tag-too-long": "لطفا برچسب کوتاه تری وارد کنید . برچسب ها نباید بیشتر از %1 کاراکتر داشته باشند", "not-enough-tags": "تعداد برچسب ها کافی نیست. موضوع ها یابد حداقل %1 برچسب داشته باشند", diff --git a/public/language/fi/admin/settings/user.json b/public/language/fi/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/fi/admin/settings/user.json +++ b/public/language/fi/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index a722959895..b9b0f83ab9 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/fr/admin/settings/user.json b/public/language/fr/admin/settings/user.json index a6e6c9f25f..680552fff8 100644 --- a/public/language/fr/admin/settings/user.json +++ b/public/language/fr/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Jours", "session-time-seconds": "Secondes", "session-time-help": "Ces valeurs permettent de définir la durée pendant laquelle un utilisateur reste connecté lorsqu'il consulte le lien \"Se souvenir de moi\". Notez que seulement une de ces valeurs sera utilisée. S'il n'y a pas de valeur en secondes, la valeur sera en jours. S'il n'y a pas de valeur en jours, la valeur sera par défaut est 14 jours.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes après que l'utilisateur soit considéré comme inactif", "online-cutoff-help": "Si l'utilisateur n'effectue aucune action pendant cette durée, il est considéré comme inactif et ne reçoit pas de mises à jour en temps réel.", "registration": "Inscription des utilisateurs", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index ba75c58a9e..f0769114f6 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Aucune catégorie sélectionnée", "too-many-posts": "Vous ne pouvez poster que toutes les %1 seconde(s) - merci de patienter avant de publier à nouveau.", "too-many-posts-newbie": "En tant que nouvel utilisateur, vous ne pouvez poster que toutes les %1 seconde(s) jusqu'à ce que vous obteniez une réputation de %2 - patientez avant de publier de nouveau.", + "already-posting": "Vous pouvez poster", "tag-too-short": "Veuillez entrer un mot-clé plus long. Les mots-clés doivent contenir au moins %1 caractère(s).", "tag-too-long": "Veuillez entrer un mot-clé plus court. Les mot-clés ne peuvent excéder %1 caractère(s).", "not-enough-tags": "Pas assez de mots-clés. Les sujets doivent avoir au moins %1 mots-clé(s).", diff --git a/public/language/gl/admin/settings/user.json b/public/language/gl/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/gl/admin/settings/user.json +++ b/public/language/gl/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index 6f94164ab5..c3984cf2cc 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categoría non seleccionada", "too-many-posts": "Só podes postear unha vez cada %1 segundo(s) - por favor agarda antes de publicar de novo.", "too-many-posts-newbie": "Como novo usuario, só podes publicar unha vez cada %1 segundo(s) ata que acades %2 de reputación -por favor, agarda para publicar de novo.", + "already-posting": "You are already posting", "tag-too-short": "Por favor, introduce unha etiqueta máis longa. As etiquetas deben conter %1 carácter(es) como mínimo.", "tag-too-long": "Por favor, introduce unha etiqueta máis curta. As etiquetas non poden conter máis de %1 carácter(es).", "not-enough-tags": "Non hai etiquetas dabondas. Os temas deben ter %1 etiqueta(s) como mínimo.", diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index 6601d20392..3e9e19bb8b 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "ימים", "session-time-seconds": "שניות", "session-time-help": "ערכים אלו משמשים כדי להגדיר כמה זמן משתמשים יישארו מחוברים כאשר הם סימנו "זכור אותי" בהתחברות. שים לב שייעשה שימוש רק באחד מהערכים האלו. אם אין ערך שניות נשתמש בערך ימים. אם אין ערך ימים הערך יחזור לברירת מחדל 14 יום.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "אחרי כמה דקות דקות המשתמש ייחשב ללא פעיל", "online-cutoff-help": "אם משתמש אינו מבצע פעולות במשך זמן זה, הוא נחשב כלא פעיל ואינו מקבל עדכונים בזמן אמת.", "registration": "רישום משתמש", diff --git a/public/language/he/error.json b/public/language/he/error.json index b161d73ed7..78d7dd20ec 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -88,6 +88,7 @@ "category-not-selected": "לא נבחרה קטגוריה", "too-many-posts": "ניתן לפרסם פוסט רק פעם ב-%1 שניות - אנא המתינו לפני פרסום נוסף", "too-many-posts-newbie": "כמשתמשים חדשים, אתם יכולים לפרסם פוסט רק פעם ב-%1 שניות עד שיהיו לכם %2 נקודות מוניטין - אנא המתינו לפני פרסום נוסף", + "already-posting": "You are already posting", "tag-too-short": "הכניסו תגית ארוכה יותר. תגיות חייבות להכיל לפחות %1 תווים", "tag-too-long": "הכניסו תגית קצרה יותר. תגיות יכולות להיות רק עד %1 תווים", "not-enough-tags": "אין מספיק תגיות. נושא חייב להכיל לפחות %1 תגיות", diff --git a/public/language/hr/admin/settings/user.json b/public/language/hr/admin/settings/user.json index e1aa153b52..19fe266984 100644 --- a/public/language/hr/admin/settings/user.json +++ b/public/language/hr/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Korisnička registracija", diff --git a/public/language/hr/error.json b/public/language/hr/error.json index 321c26e789..48a227155b 100644 --- a/public/language/hr/error.json +++ b/public/language/hr/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategorija nije odabrana.", "too-many-posts": "Možete objavljivati svakih %1 skeundi, pričekajte prije ponovne objave", "too-many-posts-newbie": "Kao novi korisnik, možete objavljivati svakih %1 sekundi dok ne steknete reputaciju %2 - molimo pričekajte prije ponovne objave", + "already-posting": "You are already posting", "tag-too-short": "Unesite dužu oznaku. Oznake moraju sadržavati najmanje %1 znak(ova)", "tag-too-long": "Unesite kraću oznaku. Oznake me mogu imati više od %1 znak(ova)", "not-enough-tags": "Nema dovoljno oznaka. Teme moraju imate bar %1 oznaku", diff --git a/public/language/hu/admin/settings/user.json b/public/language/hu/admin/settings/user.json index f679e5b510..382a89b69d 100644 --- a/public/language/hu/admin/settings/user.json +++ b/public/language/hu/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Nap", "session-time-seconds": "Másodperc", "session-time-help": "Ezek az értékek határozzák meg, hogy mennyi ideig maradjanak bejelentkezve, ha bekapcsolják az \"Emlékezzen rám\" lehetőséget bejelentkezésnél. Ha nincs másodperc érték megadva, akkor a nap értékét vesszük figyelembe. Ha nincs nap érték megadva, akkor az alapértelmezett 14 nap kerül beállításra.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Hány perc elteltével számítson egy felhasználó inaktívnak", "online-cutoff-help": "Ha egy felhasználó nem csinál semmit az oldalon, akkor inaktívnak nyilvánítjuk és nem kapnak valós idejű frissítéseket.", "registration": "Felhasználó regisztráció", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index bc9f9b1d6e..b59878f00e 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -88,6 +88,7 @@ "category-not-selected": "A kategória nincs kiválasztva.", "too-many-posts": "Csak %1 másodpercenként hozhatsz létre új bejegyzést - kérlek várj egy kicsit mielőtt új bejegyzést tennél közzé", "too-many-posts-newbie": "Új felhasználóként csak egyszer készíthetsz bejegyzést %1 másodpercen belül, amíg el nem éred a %2 szintet - kérlek várj egy kicsit mielőtt új bejegyzést tennél közzé", + "already-posting": "You are already posting", "tag-too-short": "Kérlek hosszabb címkét adj meg. A címke legalább %1 karaktert kell, hogy tartalmazzon", "tag-too-long": "Kérlek rövidebb címkét adj meg. A címkék nem lehetnek hosszabbak %1 karakternél", "not-enough-tags": "Nincs elég címke. A bejegyzésnek legalább %1 címkét kell tartalmaznia", diff --git a/public/language/hy/admin/settings/user.json b/public/language/hy/admin/settings/user.json index 81d4337eec..b7526cc3ac 100644 --- a/public/language/hy/admin/settings/user.json +++ b/public/language/hy/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Օրեր", "session-time-seconds": "Վայրկյաններ ", "session-time-help": "Այս արժեքներն օգտագործվում են որոշելու համար, թե որքան ժամանակ է օգտվողը մնում մուտք գործած, երբ նա ստուգում է «Հիշիր ինձ» մուտքի վրա: Նշենք, որ այս արժեքներից միայն մեկը կօգտագործվի: Եթե վայրկյանների արժեք չկա, մենք վերադառնում ենք օրերի: Եթե օրերի արժեք չկա, մենք լռելյայն սահմանում ենք 14 օր:", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Րոպեներ անց Օգտագործողը համարվում է ոչ ակտիվ, ", "online-cutoff-help": "Եթե օգտատերը այս տևողության համար որևէ գործողություններ չի կատարում, նա համարվում է ոչ ակտիվ և իրական ժամանակում թարմացումներ չի ստանում:", "registration": "Օգտատերի գրանցում ", diff --git a/public/language/hy/error.json b/public/language/hy/error.json index e5edebff0b..9c7fb41cf3 100644 --- a/public/language/hy/error.json +++ b/public/language/hy/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Կատեգորիան ընտրված չէ:", "too-many-posts": "Դուք կարող եք գրառում անել միայն յուրաքանչյուր %1 վայրկյան(եր) մեկ անգամ. խնդրում ենք սպասել նորից գրառում անելուց առաջ", "too-many-posts-newbie": "Որպես նոր օգտատեր, դուք կարող եք հրապարակել միայն յուրաքանչյուր %1 վայրկյան(եր) մեկ անգամ, քանի դեռ չեք վաստակել %2 վարկանիշ, խնդրում ենք սպասել՝ նորից գրառում կատարելուց առաջ:", + "already-posting": "You are already posting", "tag-too-short": "Խնդրում ենք մուտքագրել ավելի երկար թեգ: Թեգերը պետք է պարունակեն առնվազն %1 նիշ(ներ)", "tag-too-long": "Խնդրում ենք մուտքագրել ավելի կարճ թեգ: Թեգերը չեն կարող ավելի երկար լինել, քան %1 նիշ(ներ)", "not-enough-tags": "Ոչ բավարար թեգեր: Թեմաները պետք է ունենան առնվազն %1 թեգ(ներ)", diff --git a/public/language/id/admin/settings/user.json b/public/language/id/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/id/admin/settings/user.json +++ b/public/language/id/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/id/error.json b/public/language/id/error.json index 0ed7fbbe05..d82708bf4a 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Anda hanya dapat memposting sekali setiap %1 detik() - harap tunggu sebelum memposting lagi", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/it/admin/settings/user.json b/public/language/it/admin/settings/user.json index b418763c86..b6c27f03cc 100644 --- a/public/language/it/admin/settings/user.json +++ b/public/language/it/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Giorni", "session-time-seconds": "Secondi", "session-time-help": "Questi valori vengono utilizzati per definire per quanto tempo un utente rimane loggato quando spuntano "Remember Me" al login. Nota che solo uno di questi valori verrà utilizzato. Se non ci sono valori per secondi si passerà ai giorni. Se non ci sono valori per igiorni si passerà al valore di dafault di 14 giorni.", + "session-duration": "Durata della sessione se \"Ricordami\" non è selezionato (secondi)", + "session-duration-help": "Per impostazione predefinita — o se impostato su 0 — l'utente rimarrà connesso per tutta la durata della sessione (ad es. per tutto il tempo in cui la finestra/tab del browser rimane aperta). Imposta questo valore per invalidare esplicitamente la sessione dopo il numero di secondi specificato.", "online-cutoff": "Minuti dopo per cui l'utente è considerato inattivo", "online-cutoff-help": "Se l'utente non esegue alcuna azione per questa durata di tempo, vengono considerati inattivi e non ricevono aggiornamenti in tempo reale.", "registration": "Registrazione Utente", diff --git a/public/language/it/error.json b/public/language/it/error.json index ed6895dc00..4afe20a0ce 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categoria non selezionata.", "too-many-posts": "È possibile inserire un Post ogni %1 secondi - si prega di attendere prima di postare di nuovo", "too-many-posts-newbie": "Come nuovo utente puoi postare solamente una volta ogni %1 secondi finché non hai raggiunto un livello di reputazione %2 - per favore attendi prima di scrivere ancora", + "already-posting": "Stai già postando", "tag-too-short": "Inserisci un tag più lungo. I tag devono contenere almeno %1 caratteri.", "tag-too-long": "Per favore inserisci un tag più corto. I tags non dovrebbero essere più lunghi di %1 caratteri", "not-enough-tags": "Tag non sufficienti. Le discussioni devono avere almeno %1 Tag", diff --git a/public/language/ja/admin/settings/user.json b/public/language/ja/admin/settings/user.json index dcd8a4edaf..6d15cf9b20 100644 --- a/public/language/ja/admin/settings/user.json +++ b/public/language/ja/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "日", "session-time-seconds": "秒", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "ユーザーが非アクティブと見なされてからの分数", "online-cutoff-help": "この期間中にユーザーが何も操作を行わなかった場合、非アクティブと見なされ、リアルタイムの更新を受け取れません", "registration": "ユーザー登録", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index 86f0f7866f..c60b3dccc9 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -88,6 +88,7 @@ "category-not-selected": "カテゴリが選択されていません。", "too-many-posts": "あなたは%1秒間に一つの投稿しか許されます-少し待ってまた投稿してください", "too-many-posts-newbie": "あなたは%2評判を得ているまで、新しいユーザーとしては、一度だけごとに%1秒を投稿することができます - 再び投稿する前にお待ちください", + "already-posting": "You are already posting", "tag-too-short": "%1文字(s)以上でタグを入力してください。", "tag-too-long": "%1文字(s)以内でタグを入力してください。", "not-enough-tags": "タグが足りません。スレッドはせめて%1のタグ(s)が必要です。", diff --git a/public/language/ko/admin/settings/user.json b/public/language/ko/admin/settings/user.json index ac9db811b2..30faa2b48d 100644 --- a/public/language/ko/admin/settings/user.json +++ b/public/language/ko/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "일", "session-time-seconds": "초", "session-time-help": "사용자가 "로그인 유지" 항목을 활성화할 경우 해당 수치만큼 사용자의 로그인 상태를 유지합니다. 다음 값들 중 한 가지를 사용합니다. 에 해당되는 값이 없을 경우 에 해당되는 값을 적용하고, 에 해당되는 값도 없을 경우 기본값인 14일을 적용합니다.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "사용자를 비접속 상태로 간주할 시간 (분)", "online-cutoff-help": "해당 시간동안 사용자의 행동이 없을 경우 비접속 상태로 간주하고 실시간 업데이트를 적용하지 않습니다.", "registration": "회원가입", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index a993734ce1..dc5e0540b8 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -88,6 +88,7 @@ "category-not-selected": "선택된 카테고리가 없습니다.", "too-many-posts": "새 게시물 작성은 %1초마다 가능합니다. 조금 천천히 작성해주세요.", "too-many-posts-newbie": "신규 사용자는 %2만큼의 인지도를 얻기 전까지 %1초마다 게시물을 작성할 수 있습니다. 조금 천천히 작성해주세요.", + "already-posting": "You are already posting", "tag-too-short": "태그가 너무 짧습니다. 태그는 최소 %1자 이상이어야 합니다.", "tag-too-long": "태그가 너무 깁니다. 태그는 최대 %1자 이내로 사용 가능합니다.", "not-enough-tags": "태그가 없거나 부족합니다. 게시물은 %1개 이상의 태그를 사용해야 합니다.", diff --git a/public/language/lt/admin/menu.json b/public/language/lt/admin/menu.json index 379e0b2687..9c156d6ec7 100644 --- a/public/language/lt/admin/menu.json +++ b/public/language/lt/admin/menu.json @@ -8,7 +8,7 @@ "section-general": "General", "section-manage": "Manage", - "manage/categories": "Categories", + "manage/categories": "Kategorijos", "manage/privileges": "Privileges", "manage/tags": "Tags", "manage/users": "Users", @@ -27,7 +27,7 @@ "settings/reputation": "Reputation & Flags", "settings/email": "Email", "settings/user": "Users", - "settings/group": "Groups", + "settings/group": "Grupės", "settings/guest": "Guests", "settings/uploads": "Uploads", "settings/languages": "Languages", diff --git a/public/language/lt/admin/settings/guest.json b/public/language/lt/admin/settings/guest.json index 75d44f37e4..f29ece3218 100644 --- a/public/language/lt/admin/settings/guest.json +++ b/public/language/lt/admin/settings/guest.json @@ -1,5 +1,5 @@ { - "settings": "Settings", + "settings": "Nustatymai", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/lt/admin/settings/user.json b/public/language/lt/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/lt/admin/settings/user.json +++ b/public/language/lt/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/lt/email.json b/public/language/lt/email.json index 0a19bac268..6b505399b7 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -5,7 +5,7 @@ "invite": "Pakvietimas nuo %1", "greeting_no_name": "Sveiki", "greeting_with_name": "Sveiki %1", - "email.verify-your-email.subject": "Please verify your email", + "email.verify-your-email.subject": "Patvirtinkite el. pašto adresą", "email.verify.text1": "You've requested that we change or confirm your email address", "email.verify.text2": "For security purposes, we only change or confirm the email address on file once its ownership has been confirmed via email. If you did not request this, no action is required on your part.", "email.verify.text3": "Once you confirm this email address, we will replace your current email address with this one (%1).", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 75e9510ec5..44a93c7315 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Nepasirinkta kategorija.", "too-many-posts": "Jus galite rašyti kas %1 sekunde(s) - prašome palaukti prieš rašant dar kartą", "too-many-posts-newbie": "Kadangi esate naujas narys, jūs galite tik rašyti kas %1 sekunde(s) kol jūs pasieksite %2 reputacija - prašome palaukti prieš rašant dar kartą", + "already-posting": "You are already posting", "tag-too-short": "Prašome įvesti ilgesnę žymą. Žyma turi sudaryti mažiausiai %1 simboli(us)", "tag-too-long": "Prašome įvesti trumpesnę žymą. Žyma turi būti ne ilgesni negu %1 simboli(us)", "not-enough-tags": "Neužteka žymių. Temos turi turėti mažiausiai %1 žyme(s)", diff --git a/public/language/lv/admin/settings/user.json b/public/language/lv/admin/settings/user.json index 9a3d3d0c7d..fbcb918546 100644 --- a/public/language/lv/admin/settings/user.json +++ b/public/language/lv/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dienas", "session-time-seconds": "Sekundes", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minūtes, pēc kura lietotājs tiek uzskatīts par neaktīvu", "online-cutoff-help": "Ja lietotājs šajā laikā neveic nekādas darbības, tas tiek uzskatīts par neaktīvu un nesaņem reāllaika atjauninājumus.", "registration": "Reģistrācija", diff --git a/public/language/lv/error.json b/public/language/lv/error.json index 181d294341..392ca6ea12 100644 --- a/public/language/lv/error.json +++ b/public/language/lv/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategorija nav atlasīta.", "too-many-posts": "Var publicēt tikai vienu rakstu katras %1 sekundes - lūdzu, uzgaidi, pirms publicē vēlreiz", "too-many-posts-newbie": "Jauni lietotāji var ievietot tikai vienu rakstu katras %1 sekundes, līdz ir nopelnīti %2 ranga punkti - lūdzu, uzgaidi, pirms publicē vēlreiz", + "already-posting": "You are already posting", "tag-too-short": "Lūdzu, ievadi garāku birku. Birkā jāsatur vismaz %1 rakstzīmes.", "tag-too-long": "Lūdzu, ievadi īsāku birku. Birkā nevar būt vairāk kā %1 rakstzīmes.", "not-enough-tags": "Nav pietiekami daudz birku. Tematiem jābūt vismaz %1 birkām", diff --git a/public/language/ms/admin/settings/user.json b/public/language/ms/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/ms/admin/settings/user.json +++ b/public/language/ms/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 500af2859f..dabfbe3476 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Anda hanya boleh mengirim sekali setiap %1 saat() - sila tunggu sebelum kiriman seterusnya", "too-many-posts-newbie": "Sebagai pengguna baru, anda hanya boleh mengirim sekali setiap %1 saat() sehinnga anda mendapat %2 reputasi - sila tunggu sebelum kiriman seterusnya", + "already-posting": "You are already posting", "tag-too-short": "Sila masukkan tag yang lebih panjang. Tag mesti mengandungi sekurang-kurangnya %1 aksara()", "tag-too-long": "Sila masukkan tag yang lebih pendek. Tag mesti mengandungi tidak lebih %1 aksara()", "not-enough-tags": "Tag tidak mencukupi. Topik memerlukan sekurang-kurangnya %1 tag()", diff --git a/public/language/nb/admin/admin.json b/public/language/nb/admin/admin.json index 65bbbc4f99..a05d6876cb 100644 --- a/public/language/nb/admin/admin.json +++ b/public/language/nb/admin/admin.json @@ -1,6 +1,6 @@ { "alert.confirm-rebuild-and-restart": "Er du sikker på at du vil gjenoppbygge og restarte NodeBB?", - "alert.confirm-restart": "Er du sikker på at du ønsker å restarte NoddeBB?", + "alert.confirm-restart": "Er du sikker på at du ønsker å restarte NodeBB?", "acp-title": "%1 | NodeBB Admin Kontrollpanel", "settings-header-contents": "Innhold", diff --git a/public/language/nb/admin/menu.json b/public/language/nb/admin/menu.json index 379e0b2687..88eedddb5d 100644 --- a/public/language/nb/admin/menu.json +++ b/public/language/nb/admin/menu.json @@ -5,17 +5,17 @@ "dashboard/users": "Users", "dashboard/topics": "Topics", "dashboard/searches": "Searches", - "section-general": "General", + "section-general": "Generelt", "section-manage": "Manage", "manage/categories": "Categories", "manage/privileges": "Privileges", "manage/tags": "Tags", - "manage/users": "Users", + "manage/users": "Brukere", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", "manage/post-queue": "Post Queue", - "manage/groups": "Groups", + "manage/groups": "Grupper", "manage/ip-blacklist": "IP Blacklist", "manage/uploads": "Uploads", "manage/digest": "Digests", @@ -25,17 +25,17 @@ "settings/homepage": "Home Page", "settings/navigation": "Navigation", "settings/reputation": "Reputation & Flags", - "settings/email": "Email", - "settings/user": "Users", + "settings/email": "E-post", + "settings/user": "Brukere", "settings/group": "Groups", "settings/guest": "Guests", "settings/uploads": "Uploads", "settings/languages": "Languages", - "settings/post": "Posts", + "settings/post": "Innlegg", "settings/chat": "Chats", "settings/pagination": "Pagination", - "settings/tags": "Tags", - "settings/notifications": "Notifications", + "settings/tags": "Tagger", + "settings/notifications": "Varsler", "settings/api": "API Access", "settings/sounds": "Sounds", "settings/social": "Social", @@ -47,12 +47,12 @@ "settings.page-title": "%1 Settings", "section-appearance": "Appearance", - "appearance/themes": "Themes", - "appearance/skins": "Skins", + "appearance/themes": "Tema", + "appearance/skins": "Drakter", "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", - "extend/plugins": "Plugins", + "extend/plugins": "Tillegg", "extend/widgets": "Widgets", "extend/rewards": "Rewards", @@ -61,23 +61,23 @@ "section-plugins": "Plugins", "extend/plugins.install": "Install Plugins", - "section-advanced": "Advanced", + "section-advanced": "Avansert", "advanced/database": "Database", "advanced/events": "Events", "advanced/hooks": "Hooks", - "advanced/logs": "Logs", + "advanced/logs": "Logger", "advanced/errors": "Errors", "advanced/cache": "Cache", "development/logger": "Logger", "development/info": "Info", "rebuild-and-restart-forum": "Rebuild & Restart Forum", - "restart-forum": "Restart Forum", - "logout": "Log out", - "view-forum": "View Forum", + "restart-forum": "Restart forum", + "logout": "Logg ut", + "view-forum": "Vis forum", - "search.placeholder": "Search settings", - "search.no-results": "No results...", + "search.placeholder": "Søkeinnstillinger", + "search.no-results": "Ingen resultater", "search.search-forum": "Search the forum for ", "search.keep-typing": "Type more to see results...", "search.start-typing": "Start typing to see results...", diff --git a/public/language/nb/admin/settings/user.json b/public/language/nb/admin/settings/user.json index 7998884043..c6199c5698 100644 --- a/public/language/nb/admin/settings/user.json +++ b/public/language/nb/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dager", "session-time-seconds": "Sekunder", "session-time-help": "Disse verdiene brukes for å følge med på hvor lenge en bruker er logget inn når de sjekker "Remember Me" ved pålogging. Merk at kun en av disse verdiene brukes. Hvis det ikke er sekundverdi bruker vi dager. Hvis det ikke er noen verdier for dager faller verdien tilbake til 14 dager.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutter etter at bruker er ansett som inaktiv ", "online-cutoff-help": "Hvis brukeren ikke utfører noen handlinger for den bestemte varigheten, anses de som inaktive, og de mottar ikke sanntidsoppdateringer.", "registration": "Brukerregistrering", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index 5a56fc2e75..64130de51f 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategori ikke valgt", "too-many-posts": "Du kan bare poste en gang per %1 sekund(er) – vennligst vent før du poster igjen", "too-many-posts-newbie": "Som ny bruker kan du bare poste en gang per %1. sekund(er), før du har opparbeidet %2 i omdømme – vennligst vent før du poster igjen", + "already-posting": "You are already posting", "tag-too-short": "Vennligst skriv et lengre emneord. Disse må være på minst %1 tegn", "tag-too-long": "Vennligst skriv et kortere emneord. Disse kan ikke være lengre enn %1 tegn", "not-enough-tags": "Ikke nok emneord. Emner må ha minst %1.", diff --git a/public/language/nb/groups.json b/public/language/nb/groups.json index f1526365be..29a9ecc9c5 100644 --- a/public/language/nb/groups.json +++ b/public/language/nb/groups.json @@ -59,6 +59,6 @@ "new-group.group_name": "Gruppenavn:", "upload-group-cover": "Last opp et deksel for gruppen ", "bulk-invite-instructions": "Skriv inn en liste over kommaseparerte brukernavn for å invitere til denne gruppen", - "bulk-invite": "Bulk Invite", + "bulk-invite": "Inviter i bulk", "remove_group_cover_confirm": "Er du sikker på at du vil fjerne omslagsbildet? " } \ No newline at end of file diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index a7d97ba9c9..35ebb177d1 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -6,10 +6,10 @@ "chat.no_active": "Du har ingen aktive chatter.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har sendt deg en melding", - "chat.see_all": "All chats", - "chat.mark_all_read": "Mark all read", + "chat.see_all": "Alle chatter", + "chat.mark_all_read": "Marker alle som lest", "chat.no-messages": "Vennligst velg en mottaker for å vise chatte-melding historikk", - "chat.no-users-in-room": "No users in this room", + "chat.no-users-in-room": "Ingen brukere i dette rommet", "chat.recent-chats": "Nylige chatter", "chat.contacts": "Kontakter", "chat.message-history": "Meldingshistorikk", @@ -47,17 +47,17 @@ "composer.discard": "Er du sikker på at du vil forkaste dette innlegget?", "composer.submit_and_lock": "Send og lås", "composer.toggle_dropdown": "Veksle nedtrekksfelt", - "composer.uploading": "Uploading %1", - "composer.formatting.bold": "Bold", - "composer.formatting.italic": "Italic", - "composer.formatting.list": "List", - "composer.formatting.strikethrough": "Strikethrough", + "composer.uploading": "Laster opp %1", + "composer.formatting.bold": "Uthevet", + "composer.formatting.italic": "Kursiv", + "composer.formatting.list": "Liste", + "composer.formatting.strikethrough": "Gjennomstreking", "composer.formatting.code": "Code", - "composer.formatting.link": "Link", - "composer.formatting.picture": "Image Link", - "composer.upload-picture": "Upload Image", - "composer.upload-file": "Upload File", - "composer.zen_mode": "Zen Mode", + "composer.formatting.link": "Lenke", + "composer.formatting.picture": "Bildelenke", + "composer.upload-picture": "Last opp bilde", + "composer.upload-file": "Last opp fil ", + "composer.zen_mode": "Zenmodus", "composer.select_category": "Velg en kategori", "composer.textarea.placeholder": "Enter your post content here, drag and drop images", "composer.schedule-for": "Schedule topic for", @@ -70,7 +70,7 @@ "bootbox.confirm": "Bekreft", "bootbox.submit": "Submit", "bootbox.send": "Send", - "cover.dragging_title": "Cover Photo Positioning", + "cover.dragging_title": "Posisjoner bilde", "cover.dragging_message": "Drag the cover photo to the desired position and click \"Save\"", "cover.saved": "Cover photo image and position saved", "thumbs.modal.title": "Manage topic thumbnails", diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index 9ae49a8f93..9282fa280d 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -1,8 +1,8 @@ { "title": "Varsler", "no_notifs": "Du har ingen nye varsler", - "see_all": "All notifications", - "mark_all_read": "Mark all read", + "see_all": "Alle varslinger", + "mark_all_read": "Marker alle som lest", "back_to_home": "Tilbake til %1", "outgoing_link": "Utgående link", "outgoing_link_message": "Du forlater nå %1", diff --git a/public/language/nb/user.json b/public/language/nb/user.json index 4a2782610f..ee6f732278 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -1,6 +1,6 @@ { "banned": "Utestengt", - "muted": "Muted", + "muted": "Dempet", "offline": "Frakoblet", "deleted": "Slettet", "username": "Brukernavn", @@ -43,7 +43,7 @@ "followers": "Følgere", "following": "Følger", "blocks": "Blokkeringer", - "block_toggle": "Toggle Block", + "block_toggle": "Endre blokkering", "block_user": "Blokker bruker", "unblock_user": "Opphev blokkering av bruker", "aboutme": "Om meg", @@ -157,10 +157,10 @@ "info.banned-permanently": "Utestengt permanent", "info.banned-reason-label": "Årsak", "info.banned-no-reason": "ingen årsak oppgitt", - "info.mute-history": "Recent Mute History", - "info.no-mute-history": "This user has never been muted", - "info.muted-until": "Muted until %1", - "info.muted-expiry": "Expiry", + "info.mute-history": "Nylig dempet", + "info.no-mute-history": "Denne brukeren har ikke vært dempet", + "info.muted-until": "Dempet inntil %1", + "info.muted-expiry": "Utløper", "info.muted-no-reason": "Ingen grunn oppgitt.", "info.username-history": "Brukernavnhistorikk", "info.email-history": "E-post-historikk", @@ -195,5 +195,5 @@ "emailUpdate.optional": "Dette feltet er valgfritt. Du er ikke forpliktet til å oppgi e-postadressen din, men uten en validert e-postadresse vil du ikke kunne gjenopprette kontoen din eller logge på med e-postadressen din.", "emailUpdate.required": "Dette feltet er obligatorisk", "emailUpdate.change-instructions": "En bekreftelses-e-post med en unik lenke vil bli sendt til den angitte e-postadressen. Ved å klikke på lenken, vil du bekrefte at du eier e-postadressen, og den blir aktiv på kontoen din. Du kan når som helst oppdatere e-postadressen på brukerprofilen din.", - "emailUpdate.password-challenge": "Please enter your password in order to verify account ownership." + "emailUpdate.password-challenge": "Skriv inn passordet ditt for å verifisere eierskap." } \ No newline at end of file diff --git a/public/language/nl/admin/settings/user.json b/public/language/nl/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/nl/admin/settings/user.json +++ b/public/language/nl/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index ab9d7f2234..b0f354ed81 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categorie niet geselecteerd ", "too-many-posts": "Het is slechts toegestaan iedere %1 seconde(n) een bericht te plaatsen - wacht even voordat opnieuw een bericht verzonden wordt", "too-many-posts-newbie": "Nieuwe gebruikersaccounts zoals deze zijn begrensd en mogen slechts iedere %1 seconde(n) berichten plaatsen, tot het moment dat %2 reputatie verdiend is - wacht daarom even met opnieuw een bericht te plaatsten", + "already-posting": "You are already posting", "tag-too-short": "Geef een tag op die uit meer tekens bestaat. Tags dienen uit minimaal %1 teken(s) te bestaan.", "tag-too-long": "Geef een kortere tag op. Tags mogen niet langer dan %1 teken(s) zijn", "not-enough-tags": "Niet genoeg labels. Onderwerp moeten tenminste %1 label(s) hebben", diff --git a/public/language/pl/admin/settings/user.json b/public/language/pl/admin/settings/user.json index 0389a4abaa..a8284f57a0 100644 --- a/public/language/pl/admin/settings/user.json +++ b/public/language/pl/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dni", "session-time-seconds": "Sekund", "session-time-help": "Te wartości określają czas, przez jaki użytkownik pozostaje zalogowany, gdy zaznaczy opcję "Zapamiętaj mnie" przy logowaniu. Użyta zostanie tylko jedna z tych wartości. Jeśli nie ma wartości sekundach, dostępne będą dni. W razie braku wartości w dniach domyślną wartością będzie 14 dni.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Po tylu minutach użytkownik zostaje uznany za nieaktywnego.", "online-cutoff-help": "Jeśli użytkownik nie wykona żadnych działań w określonym czasie, zostaje on uznany za nieaktywnego i nie otrzyma aktualizacji w czasie rzeczywistym.", "registration": "Rejestracja użytkownika", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 1790700f13..ba0618f597 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Nie wybrano kategorii.", "too-many-posts": "Możesz publikować posty raz na %1 sekund – poczekaj, zanim dodasz kolejny post", "too-many-posts-newbie": "Jako nowy użytkownik możesz publikować posty raz na %1 sekund, dopóki nie zdobędziesz reputacji na poziomie %2 – poczekaj, zanim dodasz kolejny post", + "already-posting": "You are already posting", "tag-too-short": "Wprowadź dłuższy tag. Tagi muszą mieć przynajmniej %1 znak(-ów)", "tag-too-long": "Wprowadź krótszy tag. Tagi nie mogą mieć więcej niż %1 znak(-ów)", "not-enough-tags": "Zbyt mało tagów. Tematy muszą posiadać przynajmniej %1 tag(ów)", diff --git a/public/language/pt-BR/admin/settings/user.json b/public/language/pt-BR/admin/settings/user.json index 069cfb422f..27b217ccff 100644 --- a/public/language/pt-BR/admin/settings/user.json +++ b/public/language/pt-BR/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dias", "session-time-seconds": "Segundos", "session-time-help": "Estes valores são usados para determinar por quanto tempo um usuário fica logado quando eles habilitarem a opção "Lembrar-me" durante o login. Observe que apenas um destes valores será usado. Se não houver um valor para segundos, usamos o valor de dias. Se não houver um valor para dias, usamos o valor padrão, que é 14 dias.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutos para que o usuário seja considerado inativo", "online-cutoff-help": "Se o usuário não realizar nenhuma ação durante esse período, ele será considerado inativo e não receberá atualizações em tempo real.", "registration": "Registro de Usuário", diff --git a/public/language/pt-BR/error.json b/public/language/pt-BR/error.json index 94f0fac0c3..960e95cc55 100644 --- a/public/language/pt-BR/error.json +++ b/public/language/pt-BR/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categoria não escolhida.", "too-many-posts": "Você pode postar uma vez a cada %1 segundo(s) - por favor aguarde antes de postar novamente", "too-many-posts-newbie": "Como novo usuário, você só pode postar uma vez a cada %1 segundo(s) até que você tenha, pelo menos, %2 de reputação. Por favor, aguarde antes de postar novamente.", + "already-posting": "You are already posting", "tag-too-short": "Por favor digite uma tag maior. Tags devem conter pelo menos %1 caractere(s)", "tag-too-long": "Por favor digite uma tag menor. Tags não podem conter mais que %1 caractere(s)", "not-enough-tags": "Sem tags suficientes. Tópicos devem ter no mínimo %1 tag(s)", diff --git a/public/language/pt-PT/admin/settings/user.json b/public/language/pt-PT/admin/settings/user.json index 29a086a557..a8c4d6e62d 100644 --- a/public/language/pt-PT/admin/settings/user.json +++ b/public/language/pt-PT/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dias", "session-time-seconds": "Segundos", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutos após o utilizador ser considerado inativo", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Registo de Utilizadores", diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index 4099256361..65e772d521 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Categoria não selecionada.", "too-many-posts": "Só podes publicar a cada %1 segundo(s) - por favor espera até poderes publicar outra vez", "too-many-posts-newbie": "Como novo utilizador, só podes publicar a cada %1 segundo(s) até teres conquistado %2 de reputação - por favor espera até poderes publicar outra vez", + "already-posting": "You are already posting", "tag-too-short": "Por favor introduz um marcador maior. Os marcadores devem ter pelo menos %1 caracter(s)", "tag-too-long": "Por favor introduz um marcador mais curto. Os marcadores devem ter no máximo %1 caracter(es)", "not-enough-tags": "Não existem marcadores suficientes. Os tópicos devem ter pelo menos %1 marcador(es)", diff --git a/public/language/ro/admin/settings/user.json b/public/language/ro/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/ro/admin/settings/user.json +++ b/public/language/ro/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index e08f7396de..ed49f99971 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/ru/admin/settings/user.json b/public/language/ru/admin/settings/user.json index cfd9c08a47..04acfa8bfb 100644 --- a/public/language/ru/admin/settings/user.json +++ b/public/language/ru/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Дни", "session-time-seconds": "Секунды", "session-time-help": "Эти значения используются для определения того, как долго участник остается в системе, когда он включает "Запомнить меня" при входе. Обратите внимание на то, что будет использовано только одно из этих значений. Если значение секунды отсутствует, мы возвращаемся к значению дни. Если значение дни отсутствует, по умолчанию используется значение 14 дней.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Через сколько минут пользователь будет считаться неактивным", "online-cutoff-help": "Если участник не выполняет никаких действий в течение этого времени, он считается неактивным и не получает обновлений в реальном времени.", "registration": "Регистрация пользователей", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 2cbdb2bc51..8367b758b0 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Категория не выбрана", "too-many-posts": "Для того, чтобы разместить новое сообщение, нужно подождать %1 сек.", "too-many-posts-newbie": "Для того, чтобы разместить новое сообщение, нужно подождать %1 сек. Это время уменьшится, как только ваша репутация вырастет до %2.", + "already-posting": "You are already posting", "tag-too-short": "Слишком короткая метка. Минимум %1 символов.", "tag-too-long": "Слишком длинная метка. Максимум %1 символов.", "not-enough-tags": "Пожалуйста, добавьте метки в ваше сообщение. У темы должно быть минимум %1 меток.", diff --git a/public/language/ru/flags.json b/public/language/ru/flags.json index e0eef3de53..aa63b4d002 100644 --- a/public/language/ru/flags.json +++ b/public/language/ru/flags.json @@ -27,7 +27,7 @@ "filter-cid-all": "Все категории", "apply-filters": "Применить фильтры", "more-filters": "Больше фильтров", - "fewer-filters": "Fewer Filters", + "fewer-filters": "Меньше фильтров", "quick-actions": "Быстрые действия", "flagged-user": "Отмеченный пользователь", @@ -38,7 +38,7 @@ "delete-post": "Удалить сообщение", "purge-post": "Стереть удалённое сообщение", "restore-post": "Восстановить сообщение", - "delete": "Delete Flag", + "delete": "Удалить жалобу", "user-view": "Открыть профиль", "user-edit": "Изменить профиль", @@ -47,10 +47,10 @@ "add-note": "Добавить примечание", "no-notes": "Нет примечаний.", "delete-note-confirm": "Вы уверены, что хотите удалить это примечание к жалобе?", - "delete-flag-confirm": "Are you sure you want to delete this flag?", + "delete-flag-confirm": "Вы уверены, что хотите удалить эту жалобу?", "note-added": "Примечание добавлено", "note-deleted": "Примечание удалено", - "flag-deleted": "Flag Deleted", + "flag-deleted": "Жалоба удалена", "history": "История жалоб участника", "no-history": "Нет истории жалобы.", @@ -85,5 +85,5 @@ "bulk-resolve": "Решить жалобы", "bulk-success": "Жалоба %1 обновлена", "flagged-timeago-readable": "Получена жалоба (%2)", - "auto-flagged": "[Auto Flagged] Received %1 downvotes." + "auto-flagged": "[Автожалоба] Получено %1 голосов против." } \ No newline at end of file diff --git a/public/language/ru/top.json b/public/language/ru/top.json index b8a05bfa5f..6df3292255 100644 --- a/public/language/ru/top.json +++ b/public/language/ru/top.json @@ -1,4 +1,4 @@ { - "title": "Top", - "no_top_topics": "No top topics" + "title": "Топ", + "no_top_topics": "Нет топовых тем" } \ No newline at end of file diff --git a/public/language/ru/users.json b/public/language/ru/users.json index 85d3dd0382..a4a6c85ea3 100644 --- a/public/language/ru/users.json +++ b/public/language/ru/users.json @@ -5,7 +5,7 @@ "most_flags": "Больше всего жалоб", "search": "Поиск", "enter_username": "Введите имя пользователя для поиска", - "search-user-for-chat": "Search a user to start chat", + "search-user-for-chat": "Найдите пользователя, чтобы начать чат", "load_more": "Загрузить еще", "users-found-search-took": "Найдено пользователей: %1! Поиск занял %2 с.", "filter-by": "Сортировать по", diff --git a/public/language/rw/admin/settings/user.json b/public/language/rw/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/rw/admin/settings/user.json +++ b/public/language/rw/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index 738b57aa25..2153353025 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Wemerewe kugira icyo ushyiraho rimwe mu masegonda (isegonda) %1. Ba utegerejeho gato kugirango wongere", "too-many-posts-newbie": "Nk'umuntu mushya, wemerewe gushyiraho ikintu rimwe mu masegonda (isegonda) %1 kugeza igihe ugize amanota agera kuri %2. Ba utegerejeho gato kugirango wongere", + "already-posting": "You are already posting", "tag-too-short": "Gerageza ukoreshe akamenyetso kagizwe n'inyuguti (cyangwa ibimenyetso) nibura zigera kuri %1", "tag-too-long": "Gerageza ukoreshe akamenyetso kagizwe n'inyuguti (cyangwa ibimenyetso) zitarenze %1", "not-enough-tags": "Nta tumenyetso turiho duhagije. Ibiganiro bigomba kugira utumenyetso (akamenyetso) nibura %1", diff --git a/public/language/sc/admin/settings/user.json b/public/language/sc/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/sc/admin/settings/user.json +++ b/public/language/sc/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index 5c9c3c1078..4191fad94f 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", + "already-posting": "You are already posting", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", "not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)", diff --git a/public/language/sk/admin/settings/user.json b/public/language/sk/admin/settings/user.json index 18b8367c0b..5022bc3b40 100644 --- a/public/language/sk/admin/settings/user.json +++ b/public/language/sk/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Registrácia používateľa", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 68e637b8dc..191c951b3c 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategória nebola vybratá.", "too-many-posts": "Môžete uverejniť príspevok každých %1 sekúnd(y) - prosím počkajte pred opätovným zverejnením", "too-many-posts-newbie": "Ako nový užívateľ, môžete uverejniť príspevok raz za %1 sekúnd(y) pokiaľ nezískate %2 reputáciu - prosím, počkajte pred ďalším uverejnením", + "already-posting": "You are already posting", "tag-too-short": "Prosím, zadajte dlhšiu značku. Značky by mali obsahovať najmenej %1 znak(ov)", "tag-too-long": "Prosím, zadajte kratšiu značku. Značky nemôžu obsahovať viac ako %1 znak(ov)", "not-enough-tags": "Príliš malo značiek. Témy musia mať minimálne %1 značku(y)", diff --git a/public/language/sl/admin/settings/user.json b/public/language/sl/admin/settings/user.json index 31a7f090c0..0b68919c76 100644 --- a/public/language/sl/admin/settings/user.json +++ b/public/language/sl/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Dni", "session-time-seconds": "Sekund", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minut po tem, ko je uporabnik neaktiven", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Registracija uporabnika", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index 89ba3cc0c9..20f0be3469 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Category not selected.", "too-many-posts": "Objavljate lahko na %1 s - prosimo, počakajte pred novo objavo.", "too-many-posts-newbie": "Kot nov uporabnik lahko objavljate le na %1 s, dokler ne dosežete ugled vsaj %2 - prosimo, počakajte pred novo objavo.", + "already-posting": "You are already posting", "tag-too-short": "Prosimo, vnesite daljšo oznako. Obvezno število znakov: vsaj %1.", "tag-too-long": "Prosimo, vnesite krajšo oznako. Največje število znakov: %1.", "not-enough-tags": "Ni dovolj oznak. Obvezno število oznak: %1. ", diff --git a/public/language/sq-AL/admin/settings/user.json b/public/language/sq-AL/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/sq-AL/admin/settings/user.json +++ b/public/language/sq-AL/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/sq-AL/error.json b/public/language/sq-AL/error.json index 5b476ba971..8c2c0b7d5e 100644 --- a/public/language/sq-AL/error.json +++ b/public/language/sq-AL/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategoria nuk është zgjedhur.", "too-many-posts": "Mund të postoni vetëm një herë në %1 sekond(a) - ju lutemi prisni përpara se të postoni përsëri", "too-many-posts-newbie": "Si përdorues i ri, ju mund të postoni vetëm një herë në %1 sekond(a) derisa të keni fituar %2 reputacion - ju lutemi prisni përpara se të postoni përsëri", + "already-posting": "You are already posting", "tag-too-short": "Ju lutemi vendosni një tag më të gjatë. Tag-et duhet të përmbajnë të paktën %1 karakter(e)", "tag-too-long": "Ju lutemi vendosni një tag më të shkurtër. Tag-et nuk mund të jenë më të gjata se %1 karakter(e)", "not-enough-tags": "Numër jo i mjaftueshëm i tag-eve. Temat duhet të kenë të paktën %1 tag(-e)", diff --git a/public/language/sr/admin/settings/user.json b/public/language/sr/admin/settings/user.json index 041e750fcc..331b89acce 100644 --- a/public/language/sr/admin/settings/user.json +++ b/public/language/sr/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Registracija korisnika", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index ad5e181e66..2816cd21b3 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Није одабрана категорија", "too-many-posts": "Можете објављивати поруке само једном у %1 секунди - сачекајте пре него што покушате поново", "too-many-posts-newbie": "Као нови корисник, можете објављивати поруке само једном у %1 секунди док не достигнете %2 углед - сачекајте пре него што покушате поново", + "already-posting": "You are already posting", "tag-too-short": "Унесите дужу ознаку. Ознаке морају садржати најмање %1 знак(ов)а.", "tag-too-long": "Унесите краћу ознаку. Ознаке не смеју бити дуже од %1 знак(ов)а.", "not-enough-tags": "Нема довољно ознака. Теме морају имати најмање %1 ознаке/а.", diff --git a/public/language/sv/admin/settings/user.json b/public/language/sv/admin/settings/user.json index 1d5d460472..c8c418a206 100644 --- a/public/language/sv/admin/settings/user.json +++ b/public/language/sv/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index 1913ad41df..5951c4e022 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategori Ej vald.", "too-many-posts": "Du måste vänta minst %1 sekund(er) mellan varje inlägg", "too-many-posts-newbie": "Som ny användare måste du vänta %1 sekund(er) mellan varje inlägg tills dess du har %2 förtroende", + "already-posting": "You are already posting", "tag-too-short": "Fyll i en längre tagg. Taggar måste vara minst %1 tecken långa", "tag-too-long": "Fyll i en kortare tagg. Taggar kan ej vara längre än %1 tecken långa", "not-enough-tags": "Otillräckligt antal taggar. Ämnen måste ha minst %1 taggar", diff --git a/public/language/th/admin/settings/user.json b/public/language/th/admin/settings/user.json index 2ed52e4742..dd21ee6631 100644 --- a/public/language/th/admin/settings/user.json +++ b/public/language/th/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "User Registration", diff --git a/public/language/th/error.json b/public/language/th/error.json index 5664227505..a92289d675 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -88,6 +88,7 @@ "category-not-selected": "ไม่มีการเลือกหมวดหมู่", "too-many-posts": "คุณสามารถโพสต์ได้เพียงครั้งเดียวเท่านั้นในทุกๆ %1 วินาที(s) - โปรดรอสักครู่ก่อนการโพสต์อีกครั้ง", "too-many-posts-newbie": "เนื่องด้วยการเป็นผู้ใช้งานใหม่ คุณสามารถโพสต์ได้เพียงครั้งเดียวเท่านั้นในทุกๆ %1 วินาที(s) จนกว่าคุณจะได้รับ %2 ชื่อเสียง - โปรดรอสักครู่ก่อนการโพสต์อีกครั้ง", + "already-posting": "You are already posting", "tag-too-short": "กรุณากรอกแท็กให้ยาวขึ้น แท็กควรมีข้อความอย่างน้อย %1 ตัวอักษร(s)", "tag-too-long": "กรุณากรอกแท็กให้สั้นลง แท็กไม่สามารถยาวกว่า %1 ตัวอักษร(s)", "not-enough-tags": "จำนวนแท็กไม่พอ กระทู้ต้องมีอย่างน้อย %1 แท็ก(s)", diff --git a/public/language/tr/admin/settings/advanced.json b/public/language/tr/admin/settings/advanced.json index 84fc2f5ad5..ee33386298 100644 --- a/public/language/tr/admin/settings/advanced.json +++ b/public/language/tr/admin/settings/advanced.json @@ -3,7 +3,7 @@ "maintenance-mode.help": "Forum bakım modundayken, tüm istekler statik bir bekletme sayfasına yönlendirilir. Yöneticiler bu yönlendirmeden muaftır ve siteye normal olarak erişebilirler.", "maintenance-mode.status": "Bakım Modu Durum Kodu", "maintenance-mode.message": "Bakım Mesajı", - "maintenance-mode.groups-exempt-from-maintenance-mode": "Select groups that should be exempt from maintenance mode", + "maintenance-mode.groups-exempt-from-maintenance-mode": "Bakım Modundan muaf tutulacak grupları seçiniz", "headers": "Başlıklar", "headers.allow-from": "NodeBB'yi bir iFrame'e yerleştirmek için ALLOW-FROM'u ayarla", "headers.csp-frame-ancestors": "NodeBB'yi bir iFrame'e yerleştirmek için Content-Security-Policy frame-ancestors başlığını ayarla", @@ -18,9 +18,9 @@ "headers.acah": "Erişim-Kontrolü-Başlık-İzni", "headers.coep": "Cross-Origin-Embed Politikası", "headers.coep-help": "Etkinleştirildiğinde (varsayılan), başlığı require-corp olarak ayarlayacaktır.", - "headers.coop": "Cross-Origin-Opener-Policy", + "headers.coop": "Cross-Origin-Opener Politikası", "headers.corp": "Cross-Origin Kaynak Politikası", - "headers.permissions-policy": "Permissions-Policy", + "headers.permissions-policy": "İzin Politikası", "headers.permissions-policy-help": "Allows setting permissions policy header, for example \"geolocation=*, camera=()\", see this for more info.", "hsts": "STS", "hsts.enabled": "HSTS'yi etkinleştir (önerilir)", diff --git a/public/language/tr/admin/settings/email.json b/public/language/tr/admin/settings/email.json index bdebff56d6..1a6538c933 100644 --- a/public/language/tr/admin/settings/email.json +++ b/public/language/tr/admin/settings/email.json @@ -5,8 +5,8 @@ "from": "From Name", "from-help": "The from name to display in the email.", - "confirmation-settings": "Confirmation", - "confirmation.expiry": "Hours to keep email confirmation link valid", + "confirmation-settings": "Onay", + "confirmation.expiry": "Onay linki kaç saat geçerli olacak", "smtp-transport": "SMTP Transport", "smtp-transport.enabled": "SMTP Aktarımını Etkinleştir", diff --git a/public/language/tr/admin/settings/user.json b/public/language/tr/admin/settings/user.json index 4b9c6a1952..2ed3e783dc 100644 --- a/public/language/tr/admin/settings/user.json +++ b/public/language/tr/admin/settings/user.json @@ -1,7 +1,7 @@ { "authentication": "Kimlik Doğrulama", "email-confirm-interval": "Kullanıcı onay e-postasını tekrar gönderemez", - "email-confirm-interval2": "minutes have elapsed", + "email-confirm-interval2": "dakika geçti", "allow-login-with": "Girişe izin ver:", "allow-login-with.username-email": "Kullanıcı Adı veya E-posta", "allow-login-with.username": "Sadece kullanıcı adı", @@ -29,6 +29,8 @@ "session-time-days": "Gün", "session-time-seconds": "Saniye", "session-time-help": "Bu değerler, kullanıcının \"Beni Hatırla\" seçeneğini işaretlediğinde ne kadar süreyle oturumda kaldığını kontrol etmek için kullanılır. girişte. Bu değerlerden sadece birinin kullanılacağını unutmayın. Saniye değeri yoksa, gün dikkate alınır. Gün değeri yoksa, varsayılan değer 14 gün olur.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Kullanıcının atıl olarak değerlendirileceği dakika cinsinden geçen süre", "online-cutoff-help": "Eğer kullanıcı bu süre içinde herhangi bir işlem yapmazsa, etkin olmayan olarak kabul edilir ve gerçek zamanlı güncellemeler almaz.", "registration": "Kullanıcı Kaydı", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index 3d2d608cde..cd79fca037 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Kategori bulunamadı. Lütfen bir kategori seçiniz. ", "too-many-posts": "%1 saniye içinde yalnızca bir ileti gönderebilirsiniz - lütfen tekrar ileti göndermeden önce bekleyiniz.", "too-many-posts-newbie": "Yeni bir kullanıcı olarak, %2 saygınlık puanı kazanana kadar %1 saniye içinde bir ileti gönderebilirsiniz - lütfen tekrar ileti göndermeden önce bekleyiniz.", + "already-posting": "Halihazırda ileti gönderiyorsunuz...", "tag-too-short": "Lütfen daha uzun bir etiket girin. Etiketler en az %1 karakter içermelidir.", "tag-too-long": "Lütfen daha kısa bir etiket girin. Etiketler %1 karakterden uzun olamaz.", "not-enough-tags": "Yeterince etiket yok. Başlılar en az %1 etikete sahip olmalıdır", diff --git a/public/language/uk/admin/settings/user.json b/public/language/uk/admin/settings/user.json index cb43123c90..49e9d9fae7 100644 --- a/public/language/uk/admin/settings/user.json +++ b/public/language/uk/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Days", "session-time-seconds": "Seconds", "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Minutes after user is considered inactive", "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", "registration": "Реєстрація користувачів", diff --git a/public/language/uk/error.json b/public/language/uk/error.json index b20d7955ae..9418ca4bf6 100644 --- a/public/language/uk/error.json +++ b/public/language/uk/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Категорію не вибрано.", "too-many-posts": "Ви не можете постити частіше %1 секунд(и) — зачекайте, будь ласка, перед повторною спробою", "too-many-posts-newbie": "Як новий користувач, ви не можете публікувати частіше %1 секунд(и) доки не заробите %2 репутації — зачекайте, будь ласка, перед повторною спробою", + "already-posting": "You are already posting", "tag-too-short": "Введіть, будь ласка, довший тег. Мінімальна довжина тегу %1 символ(ів)", "tag-too-long": "Введіть, будь ласка, коротший тег. Максимальна довжина тегу %1 символ(ів)", "not-enough-tags": "Замало тегів. Тема повинна мати щонайменше %1 тег(и)", diff --git a/public/language/vi/admin/settings/user.json b/public/language/vi/admin/settings/user.json index 0fd9f6f18e..2ed9abdd02 100644 --- a/public/language/vi/admin/settings/user.json +++ b/public/language/vi/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "Ngày", "session-time-seconds": "Giây", "session-time-help": "Giá trị này dùng để điều chỉnh thời gian người dùng đăng nhập khi họ chọn "Nhớ Tôi" lúc đăng nhập. Lưu ý chỉ một trong những giá trị này sẽ được dùng. Nếu không có giá trị giây chúng tôi sẽ dùng ngày. Nếu không có ngày mặc định là 14 ngày.", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "Số phút sau khi người dùng được coi là không hoạt động", "online-cutoff-help": "Nếu người dùng không thao tác trong khoảng thời gian này, được coi là không hoạt động và không nhận được cập nhật theo thời gian thực.", "registration": "Đăng Ký Người Dùng", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 861368eb9d..0c41fe1498 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -88,6 +88,7 @@ "category-not-selected": "Chưa chọn category", "too-many-posts": "Bạn chỉ có đăng bài mới mỗi %1 giây - vui lòng đợi để tiếp tục đăng bài.", "too-many-posts-newbie": "Là người dùng mới, bạn chỉ có thể đăng %1 giây một lần cho đến khi bạn đạt được %2 danh tiếng - vui lòng đợi trước khi đăng lại", + "already-posting": "You are already posting", "tag-too-short": "Vui lòng nhập tag dài hơn. Tag phải có tối thiểu %1 ký tự.", "tag-too-long": "Vui lòng nhập tag ngắn hơn. Tag chỉ có thể có tối đa %1 ký tự.", "not-enough-tags": "Không đủ thẻ. Chủ đề phải có ít nhất %1 thẻ.", diff --git a/public/language/zh-CN/admin/settings/user.json b/public/language/zh-CN/admin/settings/user.json index f78cc552c4..1e88ee08c0 100644 --- a/public/language/zh-CN/admin/settings/user.json +++ b/public/language/zh-CN/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "天", "session-time-seconds": "秒", "session-time-help": "这些值将用于控制用户在登录时选中"记住我"后能够保持登录的时长。注意以下数值中只有一个将被使用。若值为空我们将回退使用。若值为空我们将使用默认值14天。", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "分钟后认为用户已离线", "online-cutoff-help": "若用户在此时间后未作出任何动作,他们将被视为不活跃状态且不会收到实时更新。", "registration": "用户注册", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index 1aacee0eff..4517693259 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -88,6 +88,7 @@ "category-not-selected": "未选择版块。", "too-many-posts": "发帖需要间隔 %1 秒以上 - 请稍候再发帖", "too-many-posts-newbie": "因为您是新用户,所以限制每隔 %1 秒才能发帖一次,直到您有 %2 点声望为止 —— 请稍候再发帖", + "already-posting": "You are already posting", "tag-too-short": "标签太短,不能少于 %1 个字符", "tag-too-long": "标签太长,不能超过 %1 个字符", "not-enough-tags": "没有足够的标签。主题必须至少有 %1 个标签。", diff --git a/public/language/zh-TW/admin/settings/user.json b/public/language/zh-TW/admin/settings/user.json index 6848e90747..2e725725ea 100644 --- a/public/language/zh-TW/admin/settings/user.json +++ b/public/language/zh-TW/admin/settings/user.json @@ -29,6 +29,8 @@ "session-time-days": "天", "session-time-seconds": "秒", "session-time-help": "這些值將用於控制使用者在登入時選中"記住我"後能夠保持登入的持續時間。注意以下數字中只有一個將被使用。若值為空我們將改為使用。若值為空我們將使用預設值14天。", + "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", + "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", "online-cutoff": "分鐘後認定使用者已離線", "online-cutoff-help": "若使用者在此時間後未作出任何動作,他們將被視為不活躍狀態且不會收到即時更新。", "registration": "使用者註冊", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index 33d156bcc7..57bb0fa200 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -88,6 +88,7 @@ "category-not-selected": "未選擇版面。", "too-many-posts": "貼文需要間隔 %1 秒以上 - 請稍候再發文", "too-many-posts-newbie": "因為您是新使用者,所以限制每隔 %1 秒才能發文一次,直到您有 %2 點聲望為止 —— 請稍候再發文", + "already-posting": "You are already posting", "tag-too-short": "標籤太短,不能少於 %1 個字元", "tag-too-long": "標籤太長,不能超過 %1 個字元", "not-enough-tags": "沒有足夠的主題標籤。主題必須至少有 %1 個標籤", diff --git a/src/categories/index.js b/src/categories/index.js index 5789c25e37..a95d862e77 100644 --- a/src/categories/index.js +++ b/src/categories/index.js @@ -99,6 +99,10 @@ Categories.getModerators = async function (cid) { }; Categories.getModeratorUids = async function (cids) { + // Only check active categories + const disabled = (await Categories.getCategoriesFields(cids, ['disabled'])).map(obj => obj.disabled); + // cids = cids.filter((_, idx) => !disabled[idx]); + const groupNames = cids.reduce((memo, cid) => { memo.push(`cid:${cid}:privileges:moderate`); memo.push(`cid:${cid}:privileges:groups:moderate`); @@ -120,9 +124,14 @@ Categories.getModeratorUids = async function (cids) { const uniqGroups = _.uniq(_.flatten(sets.groupNames)); const groupUids = await groups.getMembersOfGroups(uniqGroups); const map = _.zipObject(uniqGroups, groupUids); - const moderatorUids = cids.map( - (cid, index) => _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g])))) - ); + const moderatorUids = cids.map((cid, index) => { + if (disabled[index]) { + return []; + } + + return _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g])))); + }); + console.log('what', moderatorUids); return moderatorUids; }; diff --git a/src/categories/update.js b/src/categories/update.js index d4be83edb8..ec1c2edb1e 100644 --- a/src/categories/update.js +++ b/src/categories/update.js @@ -11,6 +11,7 @@ const cache = require('../cache'); module.exports = function (Categories) { Categories.update = async function (modified) { const cids = Object.keys(modified); + console.log('updating', cids); await Promise.all(cids.map(cid => updateCategory(cid, modified[cid]))); return cids; }; diff --git a/src/cli/index.js b/src/cli/index.js index 02796cc61a..b05868f3f1 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -32,6 +32,12 @@ try { if (!semver.satisfies(version, defaultPackage.dependencies[packageName])) { const e = new TypeError(`Incorrect dependency version: ${packageName}`); e.code = 'DEP_WRONG_VERSION'; + // delete the module from require cache so it doesn't break rest of the upgrade + // https://github.com/NodeBB/NodeBB/issues/11173 + const resolvedModule = require.resolve(packageName); + if (require.cache[resolvedModule]) { + delete require.cache[resolvedModule]; + } throw e; } }; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 885088dd26..ebc91b2235 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -289,8 +289,9 @@ function continueLogin(strategy, req, res, next) { req.session.cookie.maxAge = duration; req.session.cookie.expires = new Date(Date.now() + duration); } else { - req.session.cookie.maxAge = false; - req.session.cookie.expires = false; + const duration = meta.config.sessionDuration * 1000; + req.session.cookie.maxAge = duration || false; + req.session.cookie.expires = duration ? new Date(Date.now() + duration) : false; } plugins.hooks.fire('action:login.continue', { req, strategy, userData, error: null }); diff --git a/src/controllers/write/topics.js b/src/controllers/write/topics.js index d0f860680f..bac1e42924 100644 --- a/src/controllers/write/topics.js +++ b/src/controllers/write/topics.js @@ -2,6 +2,7 @@ const validator = require('validator'); +const db = require('../../database'); const api = require('../../api'); const topics = require('../../topics'); const privileges = require('../../privileges'); @@ -17,19 +18,39 @@ Topics.get = async (req, res) => { }; Topics.create = async (req, res) => { - const payload = await api.topics.create(req, req.body); - if (payload.queued) { - helpers.formatApiResponse(202, res, payload); - } else { - helpers.formatApiResponse(200, res, payload); + const id = await lockPosting(req, '[[error:already-posting]]'); + try { + const payload = await api.topics.create(req, req.body); + if (payload.queued) { + helpers.formatApiResponse(202, res, payload); + } else { + helpers.formatApiResponse(200, res, payload); + } + } finally { + await db.deleteObjectField('locks', id); } }; Topics.reply = async (req, res) => { - const payload = await api.topics.reply(req, { ...req.body, tid: req.params.tid }); - helpers.formatApiResponse(200, res, payload); + const id = await lockPosting(req, '[[error:already-posting]]'); + try { + const payload = await api.topics.reply(req, { ...req.body, tid: req.params.tid }); + helpers.formatApiResponse(200, res, payload); + } finally { + await db.deleteObjectField('locks', id); + } }; +async function lockPosting(req, error) { + const id = req.uid > 0 ? req.uid : req.sessionID; + const value = `posting${id}`; + const count = await db.incrObjectField('locks', value); + if (count > 1) { + throw new Error(error); + } + return value; +} + Topics.delete = async (req, res) => { await api.topics.delete(req, { tids: [req.params.tid] }); helpers.formatApiResponse(200, res); diff --git a/src/middleware/header.js b/src/middleware/header.js index a6ce35b156..e1db4535e3 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -19,7 +19,7 @@ middleware.buildHeader = helpers.try(async (req, res, next) => { await require('./index').applyCSRFasync(req, res); } - ({ req, locals: res.locals } = await plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals })); + await plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals }); const [config, canLoginIfBanned] = await Promise.all([ controllers.api.loadConfig(req), user.bans.canLoginIfBanned(req.uid), diff --git a/src/socket.io/index.js b/src/socket.io/index.js index b77edbb57d..60c7a8cd27 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -123,7 +123,7 @@ async function onMessage(socket, payload) { const parts = eventName.toString().split('.'); const namespace = parts[0]; const methodToCall = parts.reduce((prev, cur) => { - if (prev !== null && prev[cur]) { + if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) { return prev[cur]; } return null; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index d82785b042..443e73678f 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -51,7 +51,7 @@ SocketUser.reset.send = async function (socket, email) { } catch (err) { await logEvent(err.message); await sleep(2500 + ((Math.random() * 500) - 250)); - const internalErrors = ['[[error:invalid-email]]', '[[error:reset-rate-limited]]']; + const internalErrors = ['[[error:invalid-email]]']; if (!internalErrors.includes(err.message)) { throw err; } diff --git a/src/topics/unread.js b/src/topics/unread.js index ff07c3c5a8..f7943143f3 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -67,7 +67,7 @@ module.exports = function (Topics) { } const data = await getTids(params); - if (uid <= 0 || !data.tids || !data.tids.length) { + if (uid <= 0) { return data; } diff --git a/src/user/reset.js b/src/user/reset.js index b8a77a4d08..557a83285c 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -17,6 +17,8 @@ const UserReset = module.exports; const twoHours = 7200000; +UserReset.minSecondsBetweenEmails = 60; + UserReset.validate = async function (code) { const uid = await db.getObjectField('reset:uid', code); if (!uid) { @@ -39,31 +41,45 @@ UserReset.generate = async function (uid) { return code; }; -async function canGenerate(uid) { - const score = await db.sortedSetScore('reset:issueDate:uid', uid); - if (score > Date.now() - (1000 * 60)) { - throw new Error('[[error:reset-rate-limited]]'); - } -} - UserReset.send = async function (email) { const uid = await user.getUidByEmail(email); if (!uid) { throw new Error('[[error:invalid-email]]'); } - await canGenerate(uid); - await db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid); - const code = await UserReset.generate(uid); - await emailer.send('reset', uid, { - reset_link: `${nconf.get('url')}/reset/${code}`, - subject: '[[email:password-reset-requested]]', - template: 'reset', - uid: uid, - }).catch(err => winston.error(`[emailer.send] ${err.stack}`)); + await lockReset(uid, '[[error:reset-rate-limited]]'); + try { + await canGenerate(uid); + await db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid); + const code = await UserReset.generate(uid); + await emailer.send('reset', uid, { + reset_link: `${nconf.get('url')}/reset/${code}`, + subject: '[[email:password-reset-requested]]', + template: 'reset', + uid: uid, + }).catch(err => winston.error(`[emailer.send] ${err.stack}`)); - return code; + return code; + } finally { + db.deleteObjectField('locks', `reset${uid}`); + } }; +async function lockReset(uid, error) { + const value = `reset${uid}`; + const count = await db.incrObjectField('locks', value); + if (count > 1) { + throw new Error(error); + } + return value; +} + +async function canGenerate(uid) { + const score = await db.sortedSetScore('reset:issueDate:uid', uid); + if (score > Date.now() - (UserReset.minSecondsBetweenEmails * 1000)) { + throw new Error('[[error:reset-rate-limited]]'); + } +} + UserReset.commit = async function (code, password) { user.isPasswordValid(password); const validated = await UserReset.validate(code); @@ -122,16 +138,13 @@ UserReset.updateExpiry = async function (uid) { }; UserReset.clean = async function () { - const [tokens, uids] = await Promise.all([ - db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours), - db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours), - ]); - if (!tokens.length && !uids.length) { + const tokens = await db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours); + if (!tokens.length) { return; } winston.verbose(`[UserReset.clean] Removing ${tokens.length} reset tokens from database`); - await cleanTokensAndUids(tokens, uids); + await cleanTokens(tokens); }; UserReset.cleanByUid = async function (uid) { @@ -153,13 +166,15 @@ UserReset.cleanByUid = async function (uid) { } winston.verbose(`[UserReset.cleanByUid] Found ${tokensToClean.length} token(s), removing...`); - await cleanTokensAndUids(tokensToClean, uid); + await Promise.all([ + cleanTokens(tokensToClean), + db.deleteObjectField('locks', `reset${uid}`), + ]); }; -async function cleanTokensAndUids(tokens, uids) { +async function cleanTokens(tokens) { await Promise.all([ db.deleteObjectFields('reset:uid', tokens), db.sortedSetRemove('reset:issueDate', tokens), - db.sortedSetRemove('reset:issueDate:uid', uids), ]); } diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index 4a34a27277..5e3bd0af36 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -106,23 +106,34 @@
- - +
+ + +
- - -
-
-
-

- [[admin/settings/user:session-time-help]] -

+
+ +
-
- +
+
+

+ [[admin/settings/user:session-time-help]] +

+
+
+ +
+ + +

[[admin/settings/user:session-duration-help]]

+
+ +
+

[[admin/settings/user:online-cutoff-help]]

diff --git a/test/authentication.js b/test/authentication.js index b8889d95eb..0dd702698f 100644 --- a/test/authentication.js +++ b/test/authentication.js @@ -6,6 +6,7 @@ const url = require('url'); const async = require('async'); const nconf = require('nconf'); const request = require('request'); +const requestAsync = require('request-promise-native'); const util = require('util'); const db = require('./mocks/databasemock'); @@ -157,29 +158,6 @@ describe('authentication', () => { }); }); - it('should login a user', (done) => { - helpers.loginUser('regular', 'regularpwd', (err, data) => { - assert.ifError(err); - assert(data.body); - request({ - url: `${nconf.get('url')}/api/self`, - json: true, - jar: data.jar, - }, (err, response, body) => { - assert.ifError(err); - assert(body); - assert.equal(body.username, 'regular'); - assert.equal(body.email, 'regular@nodebb.org'); - db.getObject(`uid:${regularUid}:sessionUUID:sessionId`, (err, sessions) => { - assert.ifError(err); - assert(sessions); - assert(Object.keys(sessions).length > 0); - done(); - }); - }); - }); - }); - it('should regenerate the session identifier on successful login', async () => { const matchRegexp = /express\.sid=s%3A(.+?);/; const { hostname, path } = url.parse(nconf.get('url')); @@ -208,6 +186,114 @@ describe('authentication', () => { }); }); + describe('login', () => { + let username; + let password; + let uid; + + function getCookieExpiry(res) { + assert(res.headers['set-cookie']); + assert.strictEqual(res.headers['set-cookie'][0].includes('Expires'), true); + + const values = res.headers['set-cookie'][0].split(';'); + return values.reduce((memo, cur) => { + if (!memo) { + const [name, value] = cur.split('='); + if (name === ' Expires') { + memo = new Date(value); + } + } + + return memo; + }, undefined); + } + + beforeEach(async () => { + ([username, password] = [utils.generateUUID().slice(0, 10), utils.generateUUID()]); + uid = await user.create({ username, password }); + }); + + it('should login a user', async () => { + const { jar, body: loginBody } = await helpers.loginUser(username, password); + assert(loginBody); + const body = await requestAsync({ + url: `${nconf.get('url')}/api/self`, + json: true, + jar, + }); + assert(body); + assert.equal(body.username, username); + const sessions = await db.getObject(`uid:${uid}:sessionUUID:sessionId`); + assert(sessions); + assert(Object.keys(sessions).length > 0); + }); + + it('should set a cookie that only lasts for the life of the browser session', async () => { + const { res } = await helpers.loginUser(username, password); + + assert(res.headers); + assert(res.headers['set-cookie']); + assert.strictEqual(res.headers['set-cookie'][0].includes('Expires'), false); + }); + + it('should set a different expiry if sessionDuration is set', async () => { + const _sessionDuration = meta.config.sessionDuration; + const days = 1; + meta.config.sessionDuration = days * 24 * 60 * 60; + + const { res } = await helpers.loginUser(username, password); + + const expiry = getCookieExpiry(res); + const expected = new Date(); + expected.setUTCDate(expected.getUTCDate() + days); + + assert.strictEqual(expiry.getUTCDate(), expected.getUTCDate()); + + meta.config.sessionDuration = _sessionDuration; + }); + + it('should set a cookie that lasts for x days where x is loginDays setting, if asked to remember', async () => { + const { res } = await helpers.loginUser(username, password, { remember: 'on' }); + + const expiry = getCookieExpiry(res); + const expected = new Date(); + expected.setUTCDate(expected.getUTCDate() + meta.config.loginDays); + + assert.strictEqual(expiry.getUTCDate(), expected.getUTCDate()); + }); + + it('should set the cookie expiry properly if loginDays setting is changed', async () => { + const _loginDays = meta.config.loginDays; + meta.config.loginDays = 5; + + const { res } = await helpers.loginUser(username, password, { remember: 'on' }); + + const expiry = getCookieExpiry(res); + const expected = new Date(); + expected.setUTCDate(expected.getUTCDate() + meta.config.loginDays); + + assert.strictEqual(expiry.getUTCDate(), expected.getUTCDate()); + + meta.config.loginDays = _loginDays; + }); + + it('should ignore loginDays if loginSeconds is truthy', async () => { + const _loginSeconds = meta.config.loginSeconds; + meta.config.loginSeconds = 60; + + const { res } = await helpers.loginUser(username, password, { remember: 'on' }); + + const expiry = getCookieExpiry(res); + const expected = new Date(); + expected.setUTCSeconds(expected.getUTCSeconds() + meta.config.loginSeconds); + + assert.strictEqual(expiry.getUTCDate(), expected.getUTCDate()); + assert.strictEqual(expiry.getUTCMinutes(), expected.getUTCMinutes()); + + meta.config.loginSeconds = _loginSeconds; + }); + }); + it('should fail to login if ip address is invalid', (done) => { const jar = request.jar(); request({ @@ -238,77 +324,53 @@ describe('authentication', () => { }); }); - it('should fail to login if user does not exist', (done) => { - helpers.loginUser('doesnotexist', 'nopassword', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:invalid-login-credentials]]'); - done(); - }); + it('should fail to login if user does not exist', async () => { + const { res, body } = await helpers.loginUser('doesnotexist', 'nopassword'); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:invalid-login-credentials]]'); }); - it('should fail to login if username is empty', (done) => { - helpers.loginUser('', 'some password', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:invalid-username-or-password]]'); - done(); - }); + it('should fail to login if username is empty', async () => { + const { res, body } = await helpers.loginUser('', 'some password'); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:invalid-username-or-password]]'); }); - it('should fail to login if password is empty', (done) => { - helpers.loginUser('someuser', '', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:invalid-username-or-password]]'); - done(); - }); + it('should fail to login if password is empty', async () => { + const { res, body } = await helpers.loginUser('someuser', ''); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:invalid-username-or-password]]'); }); - it('should fail to login if username and password are empty', (done) => { - helpers.loginUser('', '', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:invalid-username-or-password]]'); - done(); - }); + it('should fail to login if username and password are empty', async () => { + const { res, body } = await helpers.loginUser('', ''); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:invalid-username-or-password]]'); }); - it('should fail to login if user does not have password field in db', (done) => { - user.create({ username: 'hasnopassword', email: 'no@pass.org' }, (err, uid) => { - assert.ifError(err); - helpers.loginUser('hasnopassword', 'doesntmatter', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:invalid-login-credentials]]'); - done(); - }); - }); + it('should fail to login if user does not have password field in db', async () => { + await user.create({ username: 'hasnopassword', email: 'no@pass.org' }); + const { res, body } = await helpers.loginUser('hasnopassword', 'doesntmatter'); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:invalid-login-credentials]]'); }); - it('should fail to login if password is longer than 4096', (done) => { + it('should fail to login if password is longer than 4096', async () => { let longPassword; for (let i = 0; i < 5000; i++) { longPassword += 'a'; } - helpers.loginUser('someuser', longPassword, (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:password-too-long]]'); - done(); - }); + const { res, body } = await helpers.loginUser('someuser', longPassword); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:password-too-long]]'); }); - it('should fail to login if local login is disabled', (done) => { - privileges.global.rescind(['groups:local:login'], 'registered-users', (err) => { - assert.ifError(err); - helpers.loginUser('regular', 'regularpwd', (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert.equal(data.body, '[[error:local-login-disabled]]'); - privileges.global.give(['groups:local:login'], 'registered-users', done); - }); - }); + it('should fail to login if local login is disabled', async () => { + await privileges.global.rescind(['groups:local:login'], 'registered-users'); + const { res, body } = await helpers.loginUser('regular', 'regularpwd'); + assert.equal(res.statusCode, 403); + assert.equal(body, '[[error:local-login-disabled]]'); + await privileges.global.give(['groups:local:login'], 'registered-users'); }); it('should fail to register if registraton is disabled', (done) => { @@ -396,15 +458,12 @@ describe('authentication', () => { assert.equal(res.statusCode, 200); }); - it('should fail to login if login type is username and an email is sent', (done) => { + it('should fail to login if login type is username and an email is sent', async () => { meta.config.allowLoginWith = 'username'; - helpers.loginUser('ginger@nodebb.org', '123456', (err, data) => { - meta.config.allowLoginWith = 'username-email'; - assert.ifError(err); - assert.equal(data.res.statusCode, 400); - assert.equal(data.body, '[[error:wrong-login-type-username]]'); - done(); - }); + const { res, body } = await helpers.loginUser('ginger@nodebb.org', '123456'); + meta.config.allowLoginWith = 'username-email'; + assert.equal(res.statusCode, 400); + assert.equal(body, '[[error:wrong-login-type-username]]'); }); it('should send 200 if not logged in', (done) => { @@ -443,37 +502,26 @@ describe('authentication', () => { bannedUser.uid = await user.create({ username: 'banme', password: '123456', email: 'ban@me.com' }); }); - it('should prevent banned user from logging in', (done) => { - user.bans.ban(bannedUser.uid, 0, 'spammer', (err) => { - assert.ifError(err); - helpers.loginUser(bannedUser.username, bannedUser.pw, (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - delete data.body.timestamp; - assert.deepStrictEqual(data.body, { - banned_until: 0, - banned_until_readable: '', - expiry: 0, - expiry_readable: '', - reason: 'spammer', - uid: bannedUser.uid, - }); - user.bans.unban(bannedUser.uid, (err) => { - assert.ifError(err); - const expiry = Date.now() + 10000; - user.bans.ban(bannedUser.uid, expiry, '', (err) => { - assert.ifError(err); - helpers.loginUser(bannedUser.username, bannedUser.pw, (err, data) => { - assert.ifError(err); - assert.equal(data.res.statusCode, 403); - assert(data.body.banned_until); - assert(data.body.reason, '[[user:info.banned-no-reason]]'); - done(); - }); - }); - }); - }); + it('should prevent banned user from logging in', async () => { + await user.bans.ban(bannedUser.uid, 0, 'spammer'); + const { res: res1, body: body1 } = await helpers.loginUser(bannedUser.username, bannedUser.pw); + assert.equal(res1.statusCode, 403); + delete body1.timestamp; + assert.deepStrictEqual(body1, { + banned_until: 0, + banned_until_readable: '', + expiry: 0, + expiry_readable: '', + reason: 'spammer', + uid: bannedUser.uid, }); + await user.bans.unban(bannedUser.uid); + const expiry = Date.now() + 10000; + await user.bans.ban(bannedUser.uid, expiry, ''); + const { res: res2, body: body2 } = await helpers.loginUser(bannedUser.username, bannedUser.pw); + assert.equal(res2.statusCode, 403); + assert(body2.banned_until); + assert(body2.reason, '[[user:info.banned-no-reason]]'); }); it('should allow banned user to log in if the "banned-users" group has "local-login" privilege', async () => { @@ -497,24 +545,18 @@ describe('authentication', () => { function (next) { user.create({ username: 'lockme', password: '123456' }, next); }, - function (_uid, next) { + async (_uid) => { uid = _uid; - helpers.loginUser('lockme', 'abcdef', next); + return helpers.loginUser('lockme', 'abcdef'); }, - function (data, next) { - helpers.loginUser('lockme', 'abcdef', next); - }, - function (data, next) { - helpers.loginUser('lockme', 'abcdef', next); - }, - function (data, next) { - helpers.loginUser('lockme', 'abcdef', next); - }, - function (data, next) { + async data => helpers.loginUser('lockme', 'abcdef'), + async data => helpers.loginUser('lockme', 'abcdef'), + async data => helpers.loginUser('lockme', 'abcdef'), + async (data) => { meta.config.loginAttempts = 5; assert.equal(data.res.statusCode, 403); assert.equal(data.body, '[[error:account-locked]]'); - helpers.loginUser('lockme', 'abcdef', next); + return helpers.loginUser('lockme', 'abcdef'); }, function (data, next) { assert.equal(data.res.statusCode, 403); diff --git a/test/categories.js b/test/categories.js index cd28ee33ef..284d0a0696 100644 --- a/test/categories.js +++ b/test/categories.js @@ -826,17 +826,18 @@ describe('Categories', () => { }); }); - describe('Categories.getModeratorUids', () => { - before((done) => { - async.series([ - async.apply(groups.create, { name: 'testGroup' }), - async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup'), - async.apply(groups.join, 'testGroup', 1), - ], done); + describe.only('Categories.getModeratorUids', () => { + let cid; + + before(async () => { + ({ cid } = await Categories.create({ name: 'foobar' })); + await groups.create({ name: 'testGroup' }); + await groups.join(`cid:${cid}:privileges:groups:moderate`, 'testGroup'); + await groups.join('testGroup', 1); }); it('should retrieve all users with moderator bit in category privilege', (done) => { - Categories.getModeratorUids([1, 2], (err, uids) => { + Categories.getModeratorUids([cid, 2], (err, uids) => { assert.ifError(err); assert.strictEqual(uids.length, 2); assert(uids[0].includes('1')); @@ -851,7 +852,7 @@ describe('Categories', () => { async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup2'), async.apply(groups.join, 'testGroup2', 1), function (next) { - Categories.getModeratorUids([1, 2], (err, uids) => { + Categories.getModeratorUids([cid, 2], (err, uids) => { assert.ifError(err); assert(uids[0].includes('1')); next(); @@ -860,10 +861,18 @@ describe('Categories', () => { ], done); }); + it('should not return moderators of disabled categories', async () => { + const payload = {}; + payload[cid] = { disabled: 1 }; + await Categories.update(payload); + const uids = await Categories.getModeratorUids([1, 2]); + assert(!uids[0].includes('1')); + }); + after((done) => { async.series([ - async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup'), - async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup2'), + async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup'), + async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup2'), async.apply(groups.destroy, 'testGroup'), async.apply(groups.destroy, 'testGroup2'), ], done); diff --git a/test/controllers-admin.js b/test/controllers-admin.js index c53f3ce3e3..73fc73089b 100644 --- a/test/controllers-admin.js +++ b/test/controllers-admin.js @@ -4,6 +4,7 @@ const async = require('async'); const assert = require('assert'); const nconf = require('nconf'); const request = require('request'); +const requestAsync = require('request-promise-native'); const db = require('./mocks/databasemock'); const categories = require('../src/categories'); @@ -65,17 +66,16 @@ describe('Admin Controllers', () => { }); }); - it('should 403 if user is not admin', (done) => { - helpers.loginUser('admin', 'barbar', (err, data) => { - assert.ifError(err); - jar = data.jar; - request(`${nconf.get('url')}/admin`, { jar: jar }, (err, res, body) => { - assert.ifError(err); - assert.equal(res.statusCode, 403); - assert(body); - done(); - }); + it('should 403 if user is not admin', async () => { + ({ jar } = await helpers.loginUser('admin', 'barbar')); + const { statusCode, body } = await requestAsync(`${nconf.get('url')}/admin`, { + jar: jar, + simple: false, + resolveWithFullResponse: true, }); + + assert.equal(statusCode, 403); + assert(body); }); it('should load admin dashboard', (done) => { diff --git a/test/controllers.js b/test/controllers.js index d5cfd5e7dd..83b9c52d74 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -1704,23 +1704,13 @@ describe('Controllers', () => { }); }); - it('should return false if user can not edit user', (done) => { - user.create({ username: 'regularJoe', password: 'barbar' }, (err) => { - assert.ifError(err); - helpers.loginUser('regularJoe', 'barbar', (err, data) => { - assert.ifError(err); - const { jar } = data; - request(`${nconf.get('url')}/api/user/foo/info`, { jar: jar, json: true }, (err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 403); - request(`${nconf.get('url')}/api/user/foo/edit`, { jar: jar, json: true }, (err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 403); - done(); - }); - }); - }); - }); + it('should return false if user can not edit user', async () => { + await user.create({ username: 'regularJoe', password: 'barbar' }); + const { jar } = await helpers.loginUser('regularJoe', 'barbar'); + let { statusCode } = await requestAsync(`${nconf.get('url')}/api/user/foo/info`, { jar: jar, json: true, simple: false, resolveWithFullResponse: true }); + assert.equal(statusCode, 403); + ({ statusCode } = await requestAsync(`${nconf.get('url')}/api/user/foo/edit`, { jar: jar, json: true, simple: false, resolveWithFullResponse: true })); + assert.equal(statusCode, 403); }); it('should load correct user', (done) => { @@ -1776,22 +1766,18 @@ describe('Controllers', () => { }); }); - it('should increase profile view', (done) => { - helpers.loginUser('regularJoe', 'barbar', (err, data) => { - assert.ifError(err); - const { jar } = data; - request(`${nconf.get('url')}/api/user/foo`, { jar: jar }, (err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - setTimeout(() => { - user.getUserField(fooUid, 'profileviews', (err, viewcount) => { - assert.ifError(err); - assert(viewcount > 0); - done(); - }); - }, 500); - }); + it('should increase profile view', async () => { + const { jar } = await helpers.loginUser('regularJoe', 'barbar'); + const { statusCode } = await requestAsync(`${nconf.get('url')}/api/user/foo`, { + jar: jar, + simple: false, + resolveWithFullResponse: true, }); + assert.equal(statusCode, 200); + + await sleep(500); + const viewcount = await user.getUserField(fooUid, 'profileviews'); + assert(viewcount > 0); }); it('should parse about me', (done) => { diff --git a/test/helpers/index.js b/test/helpers/index.js index 6ca11e9252..90323c856d 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -40,37 +40,38 @@ helpers.request = async function (method, uri, options) { }); }; -helpers.loginUser = function (username, password, callback) { +helpers.loginUser = async (username, password, payload = {}) => { const jar = request.jar(); + const form = { username, password, ...payload }; - request({ + const { statusCode, body: configBody } = await requestAsync({ url: `${nconf.get('url')}/api/config`, json: true, jar: jar, - }, (err, res, body) => { - if (err || res.statusCode !== 200) { - return callback(err || new Error('[[error:invalid-response]]')); - } - const { csrf_token } = body; - request.post(`${nconf.get('url')}/login`, { - form: { - username: username, - password: password, - }, - json: true, - jar: jar, - headers: { - 'x-csrf-token': csrf_token, - }, - }, (err, res, body) => { - if (err) { - return callback(err || new Error('[[error:invalid-response]]')); - } - callback(null, { jar, res, body, csrf_token: csrf_token }); - }); + followRedirect: false, + simple: false, + resolveWithFullResponse: true, }); -}; + if (statusCode !== 200) { + throw new Error('[[error:invalid-response]]'); + } + + const { csrf_token } = configBody; + const res = await requestAsync.post(`${nconf.get('url')}/login`, { + form, + json: true, + jar: jar, + followRedirect: false, + simple: false, + resolveWithFullResponse: true, + headers: { + 'x-csrf-token': csrf_token, + }, + }); + + return { jar, res, body: res.body, csrf_token: csrf_token }; +}; helpers.logoutUser = function (jar, callback) { request({ diff --git a/test/messaging.js b/test/messaging.js index 6c201a3fa9..1095fb8568 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -67,10 +67,10 @@ describe('Messaging Library', () => { await Groups.join('administrators', mocks.users.foo.uid); await User.setSetting(mocks.users.baz.uid, 'restrictChat', '1'); - ({ jar: mocks.users.foo.jar, csrf_token: mocks.users.foo.csrf } = await util.promisify(helpers.loginUser)('foo', 'barbar')); - ({ jar: mocks.users.bar.jar, csrf_token: mocks.users.bar.csrf } = await util.promisify(helpers.loginUser)('bar', 'bazbaz')); - ({ jar: mocks.users.baz.jar, csrf_token: mocks.users.baz.csrf } = await util.promisify(helpers.loginUser)('baz', 'quuxquux')); - ({ jar: mocks.users.herp.jar, csrf_token: mocks.users.herp.csrf } = await util.promisify(helpers.loginUser)('herp', 'derpderp')); + ({ jar: mocks.users.foo.jar, csrf_token: mocks.users.foo.csrf } = await helpers.loginUser('foo', 'barbar')); + ({ jar: mocks.users.bar.jar, csrf_token: mocks.users.bar.csrf } = await helpers.loginUser('bar', 'bazbaz')); + ({ jar: mocks.users.baz.jar, csrf_token: mocks.users.baz.csrf } = await helpers.loginUser('baz', 'quuxquux')); + ({ jar: mocks.users.herp.jar, csrf_token: mocks.users.herp.csrf } = await helpers.loginUser('herp', 'derpderp')); chatMessageDelay = meta.config.chatMessageDelay; meta.config.chatMessageDelay = 0; @@ -277,7 +277,7 @@ describe('Messaging Library', () => { it('should change owner if owner is deleted', async () => { const sender = await User.create({ username: 'deleted_chat_user', password: 'barbar' }); - const { jar: senderJar, csrf_token: senderCsrf } = await util.promisify(helpers.loginUser)('deleted_chat_user', 'barbar'); + const { jar: senderJar, csrf_token: senderCsrf } = await helpers.loginUser('deleted_chat_user', 'barbar'); const receiver = await User.create({ username: 'receiver' }); const { response } = await request(`${nconf.get('url')}/api/v3/chats`, { @@ -851,7 +851,7 @@ describe('Messaging Library', () => { }); it('should return 404 if user is not in room', async () => { - const data = await util.promisify(helpers.loginUser)('baz', 'quuxquux'); + const data = await helpers.loginUser('baz', 'quuxquux'); const response = await request(`${nconf.get('url')}/api/user/baz/chats/${roomId}`, { resolveWithFullResponse: true, simple: false, diff --git a/test/posts.js b/test/posts.js index f40af0c0d8..344ad9990c 100644 --- a/test/posts.js +++ b/test/posts.js @@ -3,7 +3,7 @@ const assert = require('assert'); const async = require('async'); -const request = require('request'); +const request = require('request-promise-native'); const nconf = require('nconf'); const path = require('path'); const util = require('util'); @@ -77,13 +77,7 @@ describe('Post\'s', () => { }); it('should update category teaser properly', async () => { - const util = require('util'); - const getCategoriesAsync = util.promisify(async (callback) => { - request(`${nconf.get('url')}/api/categories`, { json: true }, (err, res, body) => { - callback(err, body); - }); - }); - + const getCategoriesAsync = async () => await request(`${nconf.get('url')}/api/categories`, { json: true }); const postResult = await topics.post({ uid: globalModUid, cid: cid, title: 'topic title', content: '123456789' }); let data = await getCategoriesAsync(); @@ -378,15 +372,11 @@ describe('Post\'s', () => { function (next) { privileges.categories.rescind(['groups:posts:view_deleted'], cid, 'Global Moderators', next); }, - function (next) { - helpers.loginUser('global mod', '123456', (err, data) => { - assert.ifError(err); - request(`${nconf.get('url')}/api/topic/${tid}`, { jar: data.jar, json: true }, (err, res, body) => { - assert.ifError(err); - assert.equal(body.posts[1].content, '[[topic:post_is_deleted]]'); - privileges.categories.give(['groups:posts:view_deleted'], cid, 'Global Moderators', next); - }); - }); + async () => { + const { jar } = await helpers.loginUser('global mod', '123456'); + const { posts } = await request(`${nconf.get('url')}/api/topic/${tid}`, { jar, json: true }); + assert.equal(posts[1].content, '[[topic:post_is_deleted]]'); + await privileges.categories.give(['groups:posts:view_deleted'], cid, 'Global Moderators'); }, ], done); }); @@ -996,19 +986,13 @@ describe('Post\'s', () => { queueId = result.id; }); - it('should load queued posts', (done) => { - helpers.loginUser('globalmod', 'globalmodpwd', (err, data) => { - jar = data.jar; - assert.ifError(err); - request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }, (err, res, body) => { - assert.ifError(err); - assert.equal(body.posts[0].type, 'topic'); - assert.equal(body.posts[0].data.content, 'queued topic content'); - assert.equal(body.posts[1].type, 'reply'); - assert.equal(body.posts[1].data.content, 'this is a queued reply'); - done(); - }); - }); + it('should load queued posts', async () => { + ({ jar } = await helpers.loginUser('globalmod', 'globalmodpwd')); + const { posts } = await request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }); + assert.equal(posts[0].type, 'topic'); + assert.equal(posts[0].data.content, 'queued topic content'); + assert.equal(posts[1].type, 'reply'); + assert.equal(posts[1].data.content, 'this is a queued reply'); }); it('should error if data is invalid', (done) => { @@ -1018,43 +1002,26 @@ describe('Post\'s', () => { }); }); - it('should edit post in queue', (done) => { - socketPosts.editQueuedContent({ uid: globalModUid }, { id: queueId, content: 'newContent' }, (err) => { - assert.ifError(err); - request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }, (err, res, body) => { - assert.ifError(err); - assert.equal(body.posts[1].type, 'reply'); - assert.equal(body.posts[1].data.content, 'newContent'); - done(); - }); - }); + it('should edit post in queue', async () => { + await socketPosts.editQueuedContent({ uid: globalModUid }, { id: queueId, content: 'newContent' }); + const { posts } = await request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }); + assert.equal(posts[1].type, 'reply'); + assert.equal(posts[1].data.content, 'newContent'); }); - it('should edit topic title in queue', (done) => { - socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, title: 'new topic title' }, (err) => { - assert.ifError(err); - request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }, (err, res, body) => { - assert.ifError(err); - assert.equal(body.posts[0].type, 'topic'); - assert.equal(body.posts[0].data.title, 'new topic title'); - done(); - }); - }); + it('should edit topic title in queue', async () => { + await socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, title: 'new topic title' }); + const { posts } = await request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }); + assert.equal(posts[0].type, 'topic'); + assert.equal(posts[0].data.title, 'new topic title'); }); - it('should edit topic category in queue', (done) => { - socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, cid: 2 }, (err) => { - assert.ifError(err); - request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }, (err, res, body) => { - assert.ifError(err); - assert.equal(body.posts[0].type, 'topic'); - assert.equal(body.posts[0].data.cid, 2); - socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, cid: cid }, (err) => { - assert.ifError(err); - done(); - }); - }); - }); + it('should edit topic category in queue', async () => { + await socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, cid: 2 }); + const { posts } = await request(`${nconf.get('url')}/api/post-queue`, { jar: jar, json: true }); + assert.equal(posts[0].type, 'topic'); + assert.equal(posts[0].data.cid, 2); + await socketPosts.editQueuedContent({ uid: globalModUid }, { id: topicQueueId, cid: cid }); }); it('should prevent regular users from approving posts', (done) => { diff --git a/test/socket.io.js b/test/socket.io.js index 83e5635cd3..fae66f82bc 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -91,6 +91,22 @@ describe('socket.io', () => { }); }); + it('should return error for unknown event', (done) => { + io.emit('user.gdpr.__proto__.constructor.toString', (err) => { + assert(err); + assert.equal(err.message, '[[error:invalid-event, user.gdpr.__proto__.constructor.toString]]'); + done(); + }); + }); + + it('should return error for unknown event', (done) => { + io.emit('constructor.toString', (err) => { + assert(err); + assert.equal(err.message, '[[error:invalid-event, constructor.toString]]'); + done(); + }); + }); + it('should get installed themes', (done) => { const themes = ['nodebb-theme-persona']; io.emit('admin.themes.getInstalled', (err, data) => { @@ -717,7 +733,7 @@ describe('socket.io', () => { it('should not generate code if rate limited', (done) => { socketUser.reset.send({ uid: 0 }, 'regular@test.com', (err) => { - assert.ifError(err); + assert(err); async.parallel({ count: async.apply(db.sortedSetCount.bind(db), 'reset:issueDate', 0, Date.now()), diff --git a/test/user.js b/test/user.js index ddde49c3a8..718249536f 100644 --- a/test/user.js +++ b/test/user.js @@ -15,7 +15,6 @@ const User = require('../src/user'); const Topics = require('../src/topics'); const Categories = require('../src/categories'); const Posts = require('../src/posts'); -const Password = require('../src/password'); const groups = require('../src/groups'); const messaging = require('../src/messaging'); const helpers = require('./helpers'); @@ -349,6 +348,28 @@ describe('User', () => { }); }); }); + + it('should only post 1 topic out of 10', async () => { + await User.create({ username: 'flooder', password: '123456' }); + const { jar } = await helpers.loginUser('flooder', '123456'); + const titles = new Array(10).fill('topic title'); + const res = await Promise.allSettled(titles.map(async (title) => { + const { body } = await helpers.request('post', '/api/v3/topics', { + form: { + cid: testCid, + title: title, + content: 'the content', + }, + jar: jar, + json: true, + }); + return body.status; + })); + const failed = res.filter(res => res.value.code === 'bad-request'); + const success = res.filter(res => res.value.code === 'ok'); + assert.strictEqual(failed.length, 9); + assert.strictEqual(success.length, 1); + }); }); describe('.search()', () => { @@ -565,106 +586,6 @@ describe('User', () => { }); }); - describe('passwordReset', () => { - let uid; - let code; - before(async () => { - uid = await User.create({ username: 'resetuser', password: '123456' }); - await User.setUserField(uid, 'email', 'reset@me.com'); - await User.email.confirmByUid(uid); - }); - - it('.generate() should generate a new reset code', (done) => { - User.reset.generate(uid, (err, _code) => { - assert.ifError(err); - assert(_code); - - code = _code; - done(); - }); - }); - - it('.generate() should invalidate a previous generated reset code', async () => { - const _code = await User.reset.generate(uid); - const valid = await User.reset.validate(code); - assert.strictEqual(valid, false); - - code = _code; - }); - - it('.validate() should ensure that this new code is valid', (done) => { - User.reset.validate(code, (err, valid) => { - assert.ifError(err); - assert.strictEqual(valid, true); - done(); - }); - }); - - it('.validate() should correctly identify an invalid code', (done) => { - User.reset.validate(`${code}abcdef`, (err, valid) => { - assert.ifError(err); - assert.strictEqual(valid, false); - done(); - }); - }); - - it('.send() should create a new reset code and reset password', async () => { - code = await User.reset.send('reset@me.com'); - }); - - it('.commit() should update the user\'s password and confirm their email', (done) => { - User.reset.commit(code, 'newpassword', (err) => { - assert.ifError(err); - - async.parallel({ - userData: function (next) { - User.getUserData(uid, next); - }, - password: function (next) { - db.getObjectField(`user:${uid}`, 'password', next); - }, - }, (err, results) => { - assert.ifError(err); - Password.compare('newpassword', results.password, true, (err, match) => { - assert.ifError(err); - assert(match); - assert.strictEqual(results.userData['email:confirmed'], 1); - done(); - }); - }); - }); - }); - - it('.should error if same password is used for reset', async () => { - const uid = await User.create({ username: 'badmemory', email: 'bad@memory.com', password: '123456' }); - const code = await User.reset.generate(uid); - let err; - try { - await User.reset.commit(code, '123456'); - } catch (_err) { - err = _err; - } - assert.strictEqual(err.message, '[[error:reset-same-password]]'); - }); - - it('should not validate email if password reset is due to expiry', async () => { - const uid = await User.create({ username: 'resetexpiry', email: 'reset@expiry.com', password: '123456' }); - let confirmed = await User.getUserField(uid, 'email:confirmed'); - let [verified, unverified] = await groups.isMemberOfGroups(uid, ['verified-users', 'unverified-users']); - assert.strictEqual(confirmed, 0); - assert.strictEqual(verified, false); - assert.strictEqual(unverified, true); - await User.setUserField(uid, 'passwordExpiry', Date.now()); - const code = await User.reset.generate(uid); - await User.reset.commit(code, '654321'); - confirmed = await User.getUserField(uid, 'email:confirmed'); - [verified, unverified] = await groups.isMemberOfGroups(uid, ['verified-users', 'unverified-users']); - assert.strictEqual(confirmed, 0); - assert.strictEqual(verified, false); - assert.strictEqual(unverified, true); - }); - }); - describe('hash methods', () => { it('should return uid from email', (done) => { User.getUidByEmail('john@example.com', (err, uid) => { @@ -1928,7 +1849,7 @@ describe('User', () => { it('should get unread count for user', async () => { const count = await socketUser.getUnreadCount({ uid: testUid }); - assert.strictEqual(count, 3); + assert.strictEqual(count, 4); }); it('should get unread chat count 0 for guest', async () => { @@ -1951,15 +1872,15 @@ describe('User', () => { assert.deepStrictEqual(counts, { unreadChatCount: 0, unreadCounts: { - '': 3, - new: 3, - unreplied: 3, + '': 4, + new: 4, + unreplied: 4, watched: 0, }, - unreadNewTopicCount: 3, + unreadNewTopicCount: 4, unreadNotificationCount: 0, - unreadTopicCount: 3, - unreadUnrepliedTopicCount: 3, + unreadTopicCount: 4, + unreadUnrepliedTopicCount: 4, unreadWatchedTopicCount: 0, }); }); @@ -2006,25 +1927,18 @@ describe('User', () => { done(); }); - it('should add user to approval queue', (done) => { - helpers.registerUser({ + it('should add user to approval queue', async () => { + await helpers.registerUser({ username: 'rejectme', password: '123456', 'password-confirm': '123456', email: '