diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a227c5e0..26444d0188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,91 @@ +#### 1.11.0 (2018-12-14) + +##### Chores + +* incrementing version number - v1.11.1 (2104877c) +* **deps:** + * update dependency husky to v1.2.1 (63f4b569) + * update node:8.14.0 docker digest to dd2381f (7449ae3e) + * update node.js to v8.14.0 (8a5a031d) + +##### New Features + +* Allow getting logfile path from config (#7044) (f3e8e065) +* remove uid::ignored:cids (#7099) (263c9180) +* cache category tag whitelist (78fa7340) +* make user cards look less derpy (31bb2ae9) +* added new middleware authenticateOrGuest (4fba1492) +* closes #7070 (7ca62b83) +* added README.md in languages folder (648964fa) +* up composer (7eee8e1d) +* allow array results (54c127d1) +* #7023 (f581c052) +* close #7002, console message if mismatched origins (89c025d1) +* added changelog file to root of repo (e89b4fca) +* **email:** don't escape html in notification bodies. (#7042) (d7c55bc3) + +##### Bug Fixes + +* #7108 (81697390) +* dont save data for non-positive uids (62f01a83) +* #7103 (f103390a) +* dont update cid::tids:votes if topic is pinned (2f57a4b9) +* #7102 (d117df77) +* #7102 (85a07e99) +* don't explode if there is no css el (74d0e88d) +* db info page (26ccd8f6) +* logAttempt conditional (a6c8e0ab) +* #7087, server-side protection against guest blocks (33d4956b) +* don't crash in flags.validate if user blocked target (81aa3a0b) +* dont send empty strings (555c092f) +* #7085 (fe0f95a2) +* #7086 (e55fb437) +* wrong variable #7085 (71163421) +* admins&mods when there are mutliple lines of users (de437e36) +* refreshing settings page on save if language changed (ed46c5e2) +* not calling authenticate middleware on resource direct access routes (eeaee8cc) +* #7038, autoLocale logic not playing nicely with no-refresh auths (#7059) (5f3d1c76) +* #7074 (2604cf63) +* #7071 buildSkinAsset won't rebuild continuously (a07d9898) +* #7063, logout code should do hard page nav to / or data.next (6df5668e) +* #7061 (eab297bd) +* skin not changing after login or logout, #7038 (28a1fa78) +* #7040 (a63ddbe2) +* #7041 (ec0c50d4) +* #7043 (8d7c3897) +* add missing render function (cb7c2d8c) +* #7033 (8808a033) +* #7037 (b86f1556) +* #6991, add timeout for version Github request (43c3bb02) +* #7030 (58d4376f) +* **deps:** + * update dependency nodebb-plugin-composer-default to v6.1.17 (3bcfd7fc) + * update dependency nodebb-theme-persona to v9.1.4 (b6ad5fd4) + * update dependency nodebb-plugin-markdown to v8.8.6 (#7079) (46fb365d) + * update dependency nodebb-theme-persona to v9.1.3 (#7075) (d2aea57a) + * update dependency nodebb-theme-persona to v9.1.2 (42e792ab) + * update dependency nodebb-theme-persona to v9.1.1 (#7069) (bdb33056) + * update dependency postcss to v7.0.6 (6b5428c5) + * update dependency nodebb-plugin-composer-default to v6.1.14 (#7058) (e48ed6e0) + * update dependency nodebb-plugin-composer-default to v6.1.13 (#7057) (ada1d6d0) + * update dependency nodebb-plugin-composer-default to v6.1.12 (#7056) (9f9f72da) + * update dependency nodebb-plugin-composer-default to v6.1.11 (#7055) (89acb896) + * update dependency nodebb-theme-slick to v1.2.18 (#7049) (b6cb77c1) + * update dependency nodebb-theme-slick to v1.2.17 (#7048) (7334c45b) + * update dependency nodebb-theme-slick to v1.2.16 (#7047) (1cb1af0c) + * update dependency connect-mongo to v2.0.3 (#7046) (d0d0c7f0) + * update dependency nodebb-plugin-dbsearch to v3.0.3 (#7035) (adb1b5f3) + * update dependency lru-cache to v4.1.5 (#7031) (887582eb) + * update dependency socket.io to v2.2.0 (b9d49867) + * update dependency socket.io-client to v2.2.0 (824bd541) + * update dependency nodebb-plugin-dbsearch to v3.0.2 (#7028) (11f1b409) + * update dependency nodebb-plugin-dbsearch to v3.0.1 (#7027) (e71f443c) +* **i18n:** pushed notifications source to tx, pulled fallbacks (8dd8370b) + +##### Code Style Changes + +* **eslint:** match operator-linebreak preferences (ba619c7e) + ### 1.11.0 (2018-11-28) ##### Chores diff --git a/Dockerfile b/Dockerfile index dcfa024379..94f93699a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # The base image is the latest 8.x node (LTS) -FROM node:8.14.0@sha256:dd2381fe1f68df03a058094097886cd96b24a47724ff5a588b90921f13e875b7 +FROM node:8.15.0@sha256:cb66110c9c7d84bae9a6db8675f49d5c9e34d528023ef185b186e29ae5461051 RUN mkdir -p /usr/src/app WORKDIR /usr/src/app diff --git a/install/data/defaults.json b/install/data/defaults.json index c1c01f4a5e..717d4eae52 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -116,5 +116,6 @@ "eventLoopLagThreshold": 100, "eventLoopInterval": 500, "onlineCutoff": 30, - "timeagoCutoff": 30 + "timeagoCutoff": 30, + "categoryWatchState": "watching" } \ No newline at end of file diff --git a/install/package.json b/install/package.json index 787acc437d..51a445da83 100644 --- a/install/package.json +++ b/install/package.json @@ -32,11 +32,11 @@ "ace-builds": "^1.2.9", "archiver": "^3.0.0", "async": "2.6.1", - "autoprefixer": "^9.0.0", + "autoprefixer": "^9.4.6", "bcryptjs": "2.4.3", "benchpressjs": "^1.2.5", "body-parser": "^1.18.2", - "bootstrap": "^3.3.7", + "bootstrap": "^3.4.0", "bootswatch": "^3", "chart.js": "^2.7.1", "cli-graph": "^3.2.2", @@ -56,7 +56,7 @@ "cropperjs": "^1.2.2", "csurf": "^1.9.0", "daemon": "^1.1.0", - "diff": "^3.4.0", + "diff": "^4.0.1", "express": "^4.16.2", "express-session": "^1.15.6", "express-useragent": "^1.0.12", @@ -66,50 +66,51 @@ "ipaddr.js": "^1.5.4", "jquery": "^3.2.1", "jsesc": "2.5.2", - "json-2-csv": "^2.1.2", + "json-2-csv": "^3.0.0", + "jsonwebtoken": "^8.4.0", "less": "^2.7.3", "lodash": "^4.17.10", "logrotate-stream": "^0.2.5", - "lru-cache": "4.1.5", + "lru-cache": "5.1.1", "material-design-lite": "^1.3.0", "mime": "^2.2.0", "mkdirp": "^0.5.1", - "mongodb": "3.1.10", + "mongodb": "3.1.13", "morgan": "^1.9.0", "mousetrap": "^1.6.1", "mubsub-nbb": "^1.5.0", "nconf": "^0.10.0", - "nodebb-plugin-composer-default": "6.1.17", - "nodebb-plugin-dbsearch": "3.0.3", + "nodebb-plugin-composer-default": "6.1.21", + "nodebb-plugin-dbsearch": "3.0.4", "nodebb-plugin-emoji": "^2.2.5", "nodebb-plugin-emoji-android": "2.0.0", - "nodebb-plugin-markdown": "8.8.6", - "nodebb-plugin-mentions": "2.3.0", + "nodebb-plugin-markdown": "8.8.7", + "nodebb-plugin-mentions": "2.5.2", "nodebb-plugin-soundpack-default": "1.0.0", "nodebb-plugin-spam-be-gone": "0.5.5", "nodebb-rewards-essentials": "0.0.13", "nodebb-theme-lavender": "5.0.8", - "nodebb-theme-persona": "9.1.4", - "nodebb-theme-slick": "1.2.18", - "nodebb-theme-vanilla": "10.1.12", - "nodebb-widget-essentials": "4.0.11", - "nodemailer": "^4.6.5", + "nodebb-theme-persona": "9.1.13", + "nodebb-theme-slick": "1.2.19", + "nodebb-theme-vanilla": "10.1.18", + "nodebb-widget-essentials": "4.0.13", + "nodemailer": "^5.0.0", "passport": "^0.4.0", "passport-local": "1.0.0", "pg": "^7.4.0", - "pg-cursor": "^1.3.0", - "postcss": "7.0.6", + "pg-cursor": "^2.0.0", + "postcss": "7.0.14", "postcss-clean": "1.1.0", "promise-polyfill": "^8.0.0", "prompt": "^1.0.0", "redis": "2.8.0", "request": "2.88.0", - "rimraf": "2.6.2", + "rimraf": "2.6.3", "rss": "^1.2.2", "sanitize-html": "^1.16.3", "semver": "^5.4.1", "serve-favicon": "^2.4.5", - "sharp": "0.21.0", + "sharp": "0.21.3", "sitemap": "^2.0.0", "socket.io": "2.2.0", "socket.io-adapter-cluster": "^1.0.1", @@ -119,31 +120,31 @@ "socket.io-redis": "5.2.0", "socketio-wildcard": "2.0.0", "spdx-license-list": "^5.0.0", - "spider-detector": "1.0.18", + "spider-detector": "1.0.19", "toobusy-js": "^0.5.1", "uglify-es": "^3.3.9", - "validator": "10.9.0", + "validator": "10.11.0", "winston": "3.1.0", "xml": "^1.0.1", "xregexp": "^4.1.1", "zxcvbn": "^4.4.2" }, "devDependencies": { - "@commitlint/cli": "7.2.1", - "@commitlint/config-angular": "7.1.2", + "@commitlint/cli": "7.3.2", + "@commitlint/config-angular": "7.3.1", "coveralls": "3.0.2", - "eslint": "5.9.0", + "eslint": "5.12.1", "eslint-config-airbnb-base": "13.1.0", - "eslint-plugin-import": "2.14.0", + "eslint-plugin-import": "2.15.0", "grunt": "1.0.3", "grunt-contrib-watch": "1.1.0", - "husky": "1.2.1", - "jsdom": "13.0.0", + "husky": "1.3.1", + "jsdom": "13.1.0", "lint-staged": "8.1.0", "mocha": "5.2.0", "mocha-lcov-reporter": "1.3.0", "nyc": "13.1.0", - "smtp-server": "3.4.7" + "smtp-server": "3.5.0" }, "bugs": { "url": "https://github.com/NodeBB/NodeBB/issues" @@ -168,4 +169,4 @@ "url": "https://github.com/barisusakli" } ] -} \ No newline at end of file +} diff --git a/nodebb.bat b/nodebb.bat index ba0e75d249..f7f45890d9 100644 --- a/nodebb.bat +++ b/nodebb.bat @@ -1 +1 @@ -@echo off && cd %~dp0 && node ./src/cli %* +@echo off && cd %~dp0 && node ./nodebb %* diff --git a/public/language/ar/admin/settings/user.json b/public/language/ar/admin/settings/user.json index 026a58e309..4dede3c264 100644 --- a/public/language/ar/admin/settings/user.json +++ b/public/language/ar/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ar/category.json b/public/language/ar/category.json index 6c86d47b03..0e1eb394c1 100644 --- a/public/language/ar/category.json +++ b/public/language/ar/category.json @@ -7,14 +7,16 @@ "browsing": "تصفح", "no_replies": "لم يرد أحد", "no_new_posts": "لا توجد مشاركات جديدة.", - "share_this_category": "شارك هذا القسم", "watch": "تابع", "ignore": "تجاهل", "watching": "متابع", + "not-watching": "Not Watching", "ignoring": "متجاهل", - "watching.description": "أظهر المواضيع في غير مقروء", - "ignoring.description": "لا تظهر المواضيع في غير مقروء", - "watch.message": "أنت الآن تتابع التحديثات من هذا القسم وجميع الأقسام الفرعية", - "ignore.message": "أنت الآن تتجاهل التحديثات من هذا القسم وجميع الأقسام الفرعية", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "الأقسام المُتابعة" } \ No newline at end of file diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json index aa100c29d0..17faabfd36 100644 --- a/public/language/ar/notifications.json +++ b/public/language/ar/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/ar/user.json b/public/language/ar/user.json index 020355aaf8..34df2c23ec 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "متابع", "ignored": "تم تجاهله", + "default-category-watch-state": "Default category watch state", "followers": "المتابعون", "following": "يتابع", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "تغيير الصورة", "change_username": "تغيير اسم المستخدم", "change_email": "تغيير البريد اﻹلكتروني", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "تعديل", "edit-profile": "تعديل الملف الشخصي", "default_picture": "أيقونة افتراضية", diff --git a/public/language/bg/admin/settings/user.json b/public/language/bg/admin/settings/user.json index 5c1129bd05..cb45427735 100644 --- a/public/language/bg/admin/settings/user.json +++ b/public/language/bg/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Изпращане на е-писмо, когато се появи отговор в темите, за които съм абониран(а).", "follow-created-topics": "Следване на темите, които създавате", "follow-replied-topics": "Следване на темите, на които отговаряте", - "default-notification-settings": "Настройки по подразбиране за известията" + "default-notification-settings": "Настройки по подразбиране за известията", + "categoryWatchState": "Състояние по подразбиране за следенето на категории", + "categoryWatchState.watching": "Да се следят", + "categoryWatchState.notwatching": "Да не се следят", + "categoryWatchState.ignoring": "Да се пренебрегват" } \ No newline at end of file diff --git a/public/language/bg/category.json b/public/language/bg/category.json index f8d66ac219..b18ac6fd53 100644 --- a/public/language/bg/category.json +++ b/public/language/bg/category.json @@ -7,14 +7,16 @@ "browsing": "разглежда", "no_replies": "Няма отговори", "no_new_posts": "Няма нови публикации.", - "share_this_category": "Споделяне на тази категория", "watch": "Следене", "ignore": "Пренебрегване", "watching": "Следите", + "not-watching": "Не следите", "ignoring": "Пренебрегвате", - "watching.description": "Темите да се показват в непрочетените", - "ignoring.description": "Темите да не се показват в непрочетените", - "watch.message": "Вече следите новите неща в категорията и подкатегориите ѝ", - "ignore.message": "Вече не следите новите неща в тази категория и всички нейни подкатегории", + "watching.description": "Темите да се показват в непрочетените и скорошните", + "not-watching.description": "Темите да не се показват в непрочетените, а само в скорошните", + "ignoring.description": "Темите да не се показват нито в непрочетените, нито в скорошните", + "watching.message": "Вече следите новите неща в категорията и подкатегориите ѝ", + "notwatching.message": "Вече не следите новите неща в категорията и подкатегориите ѝ", + "ignoring.message": "Вече пренебрегвате новите неща в тази категория и всички нейни подкатегории", "watched-categories": "Следени категории" } \ No newline at end of file diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json index 4105dcdbdf..5bde63d158 100644 --- a/public/language/bg/notifications.json +++ b/public/language/bg/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Когато някой започне да Ви следва", "notificationType_new-chat": "Когато получите съобщение в разговор", "notificationType_group-invite": "Когато получите покана за група", + "notificationType_group-request-membership": "Когато някой поиска да се включи в група, на която Вие сте собственик", "notificationType_new-register": "Когато някой бъде добавен в опашката за регистрация", "notificationType_post-queue": "Когато бъде добавена нова публикация в опашката", "notificationType_new-post-flag": "Когато публикация бъде докладвана", diff --git a/public/language/bg/user.json b/public/language/bg/user.json index b764dff7c7..71f0b755be 100644 --- a/public/language/bg/user.json +++ b/public/language/bg/user.json @@ -28,6 +28,7 @@ "watched_categories": "Следени категории", "watched": "Следени", "ignored": "Пренебрегвани", + "default-category-watch-state": "Състояние по подразбиране за следенето на категории", "followers": "Последователи", "following": "Следва", "blocks": "Блокира", @@ -48,6 +49,7 @@ "change_picture": "Промяна на снимката", "change_username": "Промяна на потребителското име", "change_email": "Промяна на е-пощата", + "email_same_as_password": "Моля, въведете текущата си парола, за да продължите – Вие въведохте новата си е-поща отново", "edit": "Редактиране", "edit-profile": "Редактиране на профила", "default_picture": "Иконка по подразбиране", diff --git a/public/language/bn/admin/settings/user.json b/public/language/bn/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/bn/admin/settings/user.json +++ b/public/language/bn/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/bn/category.json b/public/language/bn/category.json index 93309521f8..c7c2da799a 100644 --- a/public/language/bn/category.json +++ b/public/language/bn/category.json @@ -7,14 +7,16 @@ "browsing": "ব্রাউজিং", "no_replies": "কোন রিপ্লাই নেই", "no_new_posts": "নতুন কোন পোস্ট নাই", - "share_this_category": "এই বিভাগটি অন্যের সাথে ভাগাভাগি করুন", "watch": "নজর রাখুন", "ignore": "উপেক্ষা করুন", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "প্রেক্ষিত বিভাগসমূহ" } \ No newline at end of file diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json index 747f8039b2..2aaf5b055a 100644 --- a/public/language/bn/notifications.json +++ b/public/language/bn/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/bn/user.json b/public/language/bn/user.json index 8f636c8899..ca9c3b5069 100644 --- a/public/language/bn/user.json +++ b/public/language/bn/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "দেখা হয়েছে", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "যাদের অনুসরণ করছেন", "following": "যারা আপনাকে অনুসরণ করছে", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "ছবি পরিবর্তন", "change_username": "ইউজারনেম পরিবর্তন করুন", "change_email": "ইমেইল পরিবর্তন করুন", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "সম্পাদনা", "edit-profile": "Edit Profile", "default_picture": "ডিফল্ট আইকন", diff --git a/public/language/cs/admin/advanced/database.json b/public/language/cs/admin/advanced/database.json index dca29c8437..95089916ea 100644 --- a/public/language/cs/admin/advanced/database.json +++ b/public/language/cs/admin/advanced/database.json @@ -18,16 +18,16 @@ "mongo.resident-memory": "Residentní paměť", "mongo.virtual-memory": "Virtuální paměť", "mongo.mapped-memory": "Namapovaná paměť", - "mongo.bytes-in": "Bytes In", - "mongo.bytes-out": "Bytes Out", - "mongo.num-requests": "Number of Requests", + "mongo.bytes-in": "Bajtů ->", + "mongo.bytes-out": "Bajtů <-", + "mongo.num-requests": "Počet požadavků", "mongo.raw-info": "Raw informace MongoDB", "redis": "Redis", "redis.version": "Verze Redis", - "redis.keys": "Keys", - "redis.expires": "Expires", - "redis.avg-ttl": "Average TTL", + "redis.keys": "Klíče", + "redis.expires": "Platnost", + "redis.avg-ttl": "Průměrné TTL", "redis.connected-clients": "Připojených klientů", "redis.connected-slaves": "Druhotná připojení", "redis.blocked-clients": "Blokovaných klientů", @@ -36,10 +36,10 @@ "redis.total-connections-recieved": "Souhrné množství připojení", "redis.total-commands-processed": "Souhrnně zpracováno příkazů", "redis.iops": "Okamžité zpracování za sekundu", - "redis.iinput": "Instantaneous Input Per Second", - "redis.ioutput": "Instantaneous Output Per Second", - "redis.total-input": "Total Input", - "redis.total-output": "Total Ouput", + "redis.iinput": "Okamžité vstupy/s", + "redis.ioutput": "Okamžité výstupy/s", + "redis.total-input": "Celkové vstupy", + "redis.total-output": "Celkové výstupy", "redis.keyspace-hits": "Zpracováno klíčů", "redis.keyspace-misses": "Chyby klíče", diff --git a/public/language/cs/admin/general/dashboard.json b/public/language/cs/admin/general/dashboard.json index c36183a70f..310e868799 100644 --- a/public/language/cs/admin/general/dashboard.json +++ b/public/language/cs/admin/general/dashboard.json @@ -65,9 +65,9 @@ "high-presence-topics": "Témata s vysokou účastí", "graphs.page-views": "Zobrazení stránky", - "graphs.page-views-registered": "Page Views Registered", - "graphs.page-views-guest": "Page Views Guest", - "graphs.page-views-bot": "Page Views Bot", + "graphs.page-views-registered": "Zobrazených stránek/registrovaní", + "graphs.page-views-guest": "Zobrazených stránek/hosté", + "graphs.page-views-bot": "Zobrazených stránek/bot", "graphs.unique-visitors": "Jedineční návštěvníci", "graphs.registered-users": "Registrovaní uživatelé", "graphs.anonymous-users": "Anonymní uživatelé", diff --git a/public/language/cs/admin/general/navigation.json b/public/language/cs/admin/general/navigation.json index ee47e72da1..b4810248ec 100644 --- a/public/language/cs/admin/general/navigation.json +++ b/public/language/cs/admin/general/navigation.json @@ -8,7 +8,7 @@ "id": "ID: doporučené", "properties": "Vlastnosti:", - "groups": "Groups:", + "groups": "Skupiny:", "open-new-window": "Otevřít v novém okně", "btn.delete": "Odstranit", diff --git a/public/language/cs/admin/manage/categories.json b/public/language/cs/admin/manage/categories.json index e356a2f88c..bdf2d81292 100644 --- a/public/language/cs/admin/manage/categories.json +++ b/public/language/cs/admin/manage/categories.json @@ -29,8 +29,8 @@ "select-category": "Vyberte kategorii", "set-parent-category": "Nastavit nadřazenou kategorii", - "privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. Select the domain of effect from the dropdown below.", - "privileges.category-selector": "Configuring privileges for ", + "privileges.description": "Můžete upravit oprávnění přístupu pro kategorii ve v této části. Oprávnění může být uděleno na uživatele nebo na celou skupinu. Vyberte si z vysouvacího seznamu.", + "privileges.category-selector": "Konfigurace oprávnění pro", "privileges.warning": "Poznámka: nastavení oprávnění má okamžitý vliv. Není tedy nutné uložit kategorii pro upravení těchto nastavení", "privileges.section-viewing": "Oprávnění prohlížení", "privileges.section-posting": "Oprávnění příspěvků", @@ -70,5 +70,5 @@ "alert.group-search": "Hledat skupinu…", "collapse-all": "Sbalit vše", "expand-all": "Rozbalit vše", - "disable-on-create": "Disable on create" + "disable-on-create": "Zakázat při vytvoření" } \ No newline at end of file diff --git a/public/language/cs/admin/manage/privileges.json b/public/language/cs/admin/manage/privileges.json index 31e8b34d68..138e845d4f 100644 --- a/public/language/cs/admin/manage/privileges.json +++ b/public/language/cs/admin/manage/privileges.json @@ -10,7 +10,7 @@ "search-content": "Hledat obsah", "search-users": "Hledat uživatele", "search-tags": "Hledat označení", - "allow-local-login": "Local Login", + "allow-local-login": "Místní přihlášení", "find-category": "Hledat kategorii", "access-category": "Přístup ke kategorii", diff --git a/public/language/cs/admin/manage/uploads.json b/public/language/cs/admin/manage/uploads.json index 21bc8201fc..9cd0fbf24b 100644 --- a/public/language/cs/admin/manage/uploads.json +++ b/public/language/cs/admin/manage/uploads.json @@ -1,9 +1,9 @@ { - "upload-file": "Upload File", - "filename": "Filename", - "usage": "Post Usage", - "orphaned": "Orphaned", - "size/filecount": "Size / Filecount", - "confirm-delete": "Do you really want to delete this file?", - "filecount": "%1 files" + "upload-file": "Nahrát soubor", + "filename": "Název souboru", + "usage": "Použito v příspěvku", + "orphaned": "Nevyužito", + "size/filecount": "Velikost / Počet souborů", + "confirm-delete": "Opravdu chcete odstranit tento soubor?", + "filecount": "%1 souborů" } \ No newline at end of file diff --git a/public/language/cs/admin/manage/users.json b/public/language/cs/admin/manage/users.json index a500e93cad..9be8453d99 100644 --- a/public/language/cs/admin/manage/users.json +++ b/public/language/cs/admin/manage/users.json @@ -93,7 +93,7 @@ "alerts.error-x": "Chyba

%1

", "alerts.create-success": "Uživatel byl vytvořen.", - "alerts.prompt-email": "Emails: ", + "alerts.prompt-email": "E-maily:", "alerts.email-sent-to": "E-mail s pozvánkou byl odeslán na %1", "alerts.x-users-found": "Počet nalezených uživatelů: %1 (hledání trvalo %2 ms)" } \ No newline at end of file diff --git a/public/language/cs/admin/menu.json b/public/language/cs/admin/menu.json index 16b72f5cbb..e246f3bf24 100644 --- a/public/language/cs/admin/menu.json +++ b/public/language/cs/admin/menu.json @@ -57,7 +57,7 @@ "section-advanced": "Pokročilé", "advanced/database": "Databáze", "advanced/events": "Události", - "advanced/hooks": "Hooks", + "advanced/hooks": "Háky", "advanced/logs": "Protokoly", "advanced/errors": "Chyby", "advanced/cache": "Mezipamě", diff --git a/public/language/cs/admin/settings/uploads.json b/public/language/cs/admin/settings/uploads.json index 922ee8776e..b4adf08bdd 100644 --- a/public/language/cs/admin/settings/uploads.json +++ b/public/language/cs/admin/settings/uploads.json @@ -4,18 +4,18 @@ "private": "Nahrané soubory jsou soukromé", "private-extensions": "Přípona souborů je soukromá", "private-uploads-extensions-help": "Pro nastavení soukromí, zde zadejte seznam souborů oddělený čárkou (tj. pdf, xls,doc). prázdný seznam znamená, že všechny soubory jsou soukromé.", - "resize-image-width-threshold": "Resize images if they are wider than specified width", - "resize-image-width-threshold-help": "(in pixels, default: 1520 pixels, set to 0 to disable)", - "resize-image-width": "Resize images down to specified width", - "resize-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)", + "resize-image-width-threshold": "Změnit velikost obrázků, jsou-li širší než určená šířka", + "resize-image-width-threshold-help": "(v pixelech, výchozí: 1520 pixelů, pro zakázání - nastavte 0)", + "resize-image-width": "Změnit velikost obrázků na určenou šířku", + "resize-image-width-help": "(v pixelech, výchozí: 760 pixelů, pro zakázání - nastavte 0)", "resize-image-quality": "Kvalita při změně velikosti obrázků", "resize-image-quality-help": "Pro snížení velikosti zmenšených obrázků použijte nižší nastavení kvality.", "max-file-size": "Maximální velikost souboru (v KiB)", "max-file-size-help": "(v kilobajtech, výchozí 2048 KiB)", - "reject-image-width": "Maximum Image Width (in pixels)", - "reject-image-width-help": "Images wider than this value will be rejected.", - "reject-image-height": "Maximum Image Height (in pixels)", - "reject-image-height-help": "Images taller than this value will be rejected.", + "reject-image-width": "Maximální šířka obrázku (v pixelech)", + "reject-image-width-help": "Širší obrázek než tato hodnota bude zamítnut.", + "reject-image-height": "Maximální výška obrázku (v pixelech)", + "reject-image-height-help": "Vyšší obrázek než tato hodnota bude zamítnut.", "allow-topic-thumbnails": "Povolit uživatelům nahrát miniatury témat", "topic-thumb-size": "Velikost miniatury tématu", "allowed-file-extensions": "Povolené přípony souborů", diff --git a/public/language/cs/admin/settings/user.json b/public/language/cs/admin/settings/user.json index e45cbc87aa..f14b96ffbc 100644 --- a/public/language/cs/admin/settings/user.json +++ b/public/language/cs/admin/settings/user.json @@ -8,8 +8,8 @@ "allow-login-with.username": "Pouze uživatelské jméno", "allow-login-with.email": "Pouze e-mail", "account-settings": "Nastavení účtu", - "gdpr_enabled": "Enable GDPR consent collection", - "gdpr_enabled_help": "When enabled, all new registrants will be required to explicitly give consent for data collection and usage under the General Data Protection Regulation (GDPR). Note: Enabling GDPR does not force pre-existing users to provide consent. To do so, you will need to install the GDPR plugin.", + "gdpr_enabled": "Povolit souhlas s GDPR", + "gdpr_enabled_help": "Je-li povoleno, všichni nový uživatelé budou muset souhlasit se sběrem dat dle General Data Protection Regulation (GDPR).Nezapomeňte, že: povolení GDPR nepřinutí již existující uživatele dát souhlas. Abyste tak učinili, bude muset nainstalovat zásuvný modul GDPR.", "disable-username-changes": "Zakázat změnu uživatelského jména", "disable-email-changes": "Zakázat změnu e-mailu", "disable-password-changes": "Zakázat změnu hesla", @@ -27,12 +27,12 @@ "lockout-duration": "Délka blokování účtu (v minutách)", "login-days": "Počet dní na zapamatování relace přihlášení uživatele", "password-expiry-days": "Vynutit reset hesla po určitém počtu dní", - "session-time": "Session Time", - "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.", - "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.", + "session-time": "Čas relace", + "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í.", + "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", "registration-type": "Typ registrace", "registration-type.normal": "Normální", @@ -70,5 +70,9 @@ "email-post-notif": "Zaslat e-mail, objeví-li se odpovědi v tématu, který sleduji", "follow-created-topics": "Sledovat mnou vytvořená témata", "follow-replied-topics": "Sledovat témata, na které jste odpověděl", - "default-notification-settings": "Nastavení výchozího oznámení" + "default-notification-settings": "Nastavení výchozího oznámení", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/cs/category.json b/public/language/cs/category.json index 8118e85006..a5f2134d3e 100644 --- a/public/language/cs/category.json +++ b/public/language/cs/category.json @@ -7,14 +7,16 @@ "browsing": "prohlíží", "no_replies": "Nikdo ještě neodpověděl", "no_new_posts": "Žádné nové příspěvky", - "share_this_category": "Sdílet tuto kategorii", "watch": "Sledovat", "ignore": "Ignorovat", "watching": "Sledováno", + "not-watching": "Not Watching", "ignoring": "Ignorováno", - "watching.description": "Zobrazit témata jako nepřečtená", - "ignoring.description": "Nezobrazovat témata v nepřečtených", - "watch.message": "Nyní sledujete všechny aktualizace z této kategorie a všech podkategorií", - "ignore.message": "Nyní ignorujete aktualizace z této kategorie a všech podkategoriích", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Sledované kategorie" } \ No newline at end of file diff --git a/public/language/cs/email.json b/public/language/cs/email.json index 137b828384..ffa404387e 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -1,6 +1,6 @@ { - "test-email.subject": "Test Email", - "password-reset-requested": "Password Reset Requested!", + "test-email.subject": "Test e-mailu", + "password-reset-requested": "Vyžádáno resetování hesla!", "welcome-to": "Vítejte v %1", "invite": "Pozvánka od %1", "greeting_no_name": "Dobrý den", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 90e8889566..532f79b982 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -88,7 +88,7 @@ "invalid-image-type": "Neplatný typ obrázku. Povolené typy jsou: %1", "invalid-image-extension": "Neplatná přípona obrázku", "invalid-file-type": "Neplatný typ souboru. Povolené typy jsou: %1", - "invalid-image-dimensions": "Image dimensions are too big", + "invalid-image-dimensions": "Rozlišení obrázku je moc velké.", "group-name-too-short": "Název skupiny je moc krátký", "group-name-too-long": "Název skupiny je moc dlouhý", "group-already-exists": "Skupina už existuje", @@ -120,7 +120,7 @@ "chat-edit-duration-expired": "Je vám umožněno upravit konverzační zprávy pod dobu %1 sekund/y po jejich odeslání", "chat-delete-duration-expired": "Je vám umožněno odstranit konverzační zprávy pod dobu %1 sekund/y po jejich odeslání", "chat-deleted-already": "Tato konverzační zpráva již byla odstraněna.", - "chat-restored-already": "This chat message has already been restored.", + "chat-restored-already": "Tato konverzační zpráva již byla obnovena.", "already-voting-for-this-post": "Již jste v tomto příspěvku hlasoval.", "reputation-system-disabled": "Systém reputací je zakázán.", "downvoting-disabled": "Systém nesouhlasu je zakázán", @@ -153,8 +153,8 @@ "cant-move-to-same-topic": "Není možné přesunout příspěvek do stejného tématu!", "cannot-block-self": "Nemůžete zablokovat sebe sama!", "cannot-block-privileged": "Nemůžete zablokovat správce nebo hlavní moderátory", - "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", + "cannot-block-guest": "Hosté nemohou blokovat ostatní uživatele.", + "already-blocked": "Tento uživatel již byl zablokován.", + "already-unblocked": "Tento uživatel již byl odblokován", "no-connection": "Zdá se, že nastal problém s připojením k internetu" } \ No newline at end of file diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index c1f76280a4..64a7050077 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -47,7 +47,7 @@ "composer.formatting.italic": "Kurzíva", "composer.formatting.list": "Seznam", "composer.formatting.strikethrough": "Přeškrtnutí", - "composer.formatting.code": "Code", + "composer.formatting.code": "Kód", "composer.formatting.link": "Odkaz", "composer.formatting.picture": "Obrázek", "composer.upload-picture": "Nahrát obrázek", diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json index e1568104df..65c2f46a73 100644 --- a/public/language/cs/notifications.json +++ b/public/language/cs/notifications.json @@ -8,7 +8,7 @@ "outgoing_link_message": "Opouštíte %1", "continue_to": "Pokračovat na %1", "return_to": "Vrátit se na %1", - "new_notification": "You have a new notification", + "new_notification": "Máte nové upozornění", "you_have_unread_notifications": "Máte nepřečtená upozornění.", "all": "Vše", "topics": "Témata", @@ -56,6 +56,7 @@ "notificationType_follow": "Začne-li vás někdo sledovat", "notificationType_new-chat": "Obdržíte-li novou konverzační zprávu", "notificationType_group-invite": "Obdržíte-li pozvání ke skupině", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Bude-li 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", diff --git a/public/language/cs/pages.json b/public/language/cs/pages.json index fa8f4dfdcd..31ed5b8f74 100644 --- a/public/language/cs/pages.json +++ b/public/language/cs/pages.json @@ -45,7 +45,7 @@ "account/posts": "Příspěvky od %1", "account/topics": "Příspěvky vytvořeny uživatelem %1", "account/groups": "%1's skupiny", - "account/watched_categories": "%1's Watched Categories", + "account/watched_categories": "%1's sledovaných kategorii", "account/bookmarks": "%1's zazáložkované příspěvky", "account/settings": "Uživatelské nastavení", "account/watched": "Témata sledovaná uživatelem %1", @@ -55,7 +55,7 @@ "account/best": "Nejlepší příspěvky od %1", "account/blocks": "Zablokovaní uživatelé z %1", "account/uploads": "Nahráno od %1", - "account/sessions": "Login Sessions", + "account/sessions": "Relace s přihlášením", "confirm": "E-mail potvrzen", "maintenance.text": "%1 momentálně prochází údržbou. Vraťte se později.", "maintenance.messageIntro": "Správce zanechal tuto zprávu:", diff --git a/public/language/cs/search.json b/public/language/cs/search.json index e6d267550e..de1c762624 100644 --- a/public/language/cs/search.json +++ b/public/language/cs/search.json @@ -17,7 +17,7 @@ "at-most": "Nejvíce", "relevance": "Relevantnost", "post-time": "Čas příspěvku", - "votes": "Votes", + "votes": "Hlasů", "newer-than": "Novější než", "older-than": "Starší než", "any-date": "Jakékoliv datum", @@ -31,7 +31,7 @@ "sort-by": "Řadit dle", "last-reply-time": "Čas poslední odpovědi", "topic-title": "Název tématu", - "topic-votes": "Topic votes", + "topic-votes": "Hlasy tématu", "number-of-replies": "Počet odpovědí", "number-of-views": "Počet zobrazení", "topic-start-date": "Počáteční datum tématu", diff --git a/public/language/cs/user.json b/public/language/cs/user.json index 8a8a23f4d1..0450890466 100644 --- a/public/language/cs/user.json +++ b/public/language/cs/user.json @@ -25,9 +25,10 @@ "profile_views": "Zobrazení profilu", "reputation": "Reputace", "bookmarks": "Záložky", - "watched_categories": "Watched categories", + "watched_categories": "Sledované kategorie", "watched": "Sledován", "ignored": "Ignorován", + "default-category-watch-state": "Default category watch state", "followers": "Sledují ho", "following": "Sleduje", "blocks": "Zablokováni", @@ -48,6 +49,7 @@ "change_picture": "Změnit obrázek", "change_username": "Změnit uživatelské jméno", "change_email": "Změnit e-mail", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Upravit", "edit-profile": "Upravit profil", "default_picture": "Výchozí ikonka", @@ -148,7 +150,7 @@ "info.moderation-note": "Poznámka moderace", "info.moderation-note.success": "Poznámka moderace byla uložena", "info.moderation-note.add": "Přidat poznámku", - "sessions.description": "This page allows you to view any active sessions on this forum and revoke them if necessary. You can revoke your own session by logging out of your account.", + "sessions.description": "Tato stránka vám zobrazuje aktivní relace na tomto fóru a umožňuje vám je zrušit. Můžete tak i zrušit vlastní relaci svým odhlášením. ", "consent.title": "Váš právní souhlas", "consent.lead": "Toto komunitní fórum sbírá zpracovává vaše osobní údaje.", "consent.intro": "Tyto informace používáme pouze pro peronizaci vašich zkušeností v této komunitě, stejně tak k rozpoznání příspěvků, které jste pod uživatelským účtem vytvořil. Během jednotlivých registračních kroků budete požádán/a o zadání Vašeho uživatelského jména a e-mailové adresy. Můžete také dobrovolně poskytnout některé dodatečné informace do vašeho profilu na webové stránce.Tyto informace uchováváme po dobu životnosti vašeho uživatelského účtu a Vy můžete kdykoliv zrušit tento svůj souhlas smazáním vašeho účtu. Kdykoli můžete požadovat kopii svých příspěvků na této webové stránce pomocí stránky „Práva a souhlas”

Máte-li nějaké otázky nebo obavy, obraťte se na tým správců fóra.", diff --git a/public/language/cs/users.json b/public/language/cs/users.json index 06a57ceb3b..8ad78761dc 100644 --- a/public/language/cs/users.json +++ b/public/language/cs/users.json @@ -10,7 +10,7 @@ "filter-by": "Filtrovat dle", "online-only": "Pouze připojené", "invite": "Pozvat", - "prompt-email": "Emails:", + "prompt-email": "E-maily:", "invitation-email-sent": "E-mailová pozvánka byla odeslána na adresu %1", "user_list": "Seznam uživatelů", "recent_topics": "Poslední témata", diff --git a/public/language/da/admin/settings/user.json b/public/language/da/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/da/admin/settings/user.json +++ b/public/language/da/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/da/category.json b/public/language/da/category.json index e40ba1bc55..d78a91909e 100644 --- a/public/language/da/category.json +++ b/public/language/da/category.json @@ -7,14 +7,16 @@ "browsing": "browse", "no_replies": "Ingen har svaret", "no_new_posts": "Ingen nye indlæg", - "share_this_category": "Del denne kategori", "watch": "Overvåg", "ignore": "Ignorer", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Fulgte kategorier" } \ No newline at end of file diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json index edf3ea6ff2..7544d7b047 100644 --- a/public/language/da/notifications.json +++ b/public/language/da/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/da/user.json b/public/language/da/user.json index e4fec860bf..06077c6fe9 100644 --- a/public/language/da/user.json +++ b/public/language/da/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Set", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Followers", "following": "Følger", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Skift billede", "change_username": "Ændre brugernavn", "change_email": "Ændre email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Rediger", "edit-profile": "Rediger Profil", "default_picture": "Standard ikon", diff --git a/public/language/de/admin/advanced/database.json b/public/language/de/admin/advanced/database.json index 2f25cc17af..834fc7deb4 100644 --- a/public/language/de/admin/advanced/database.json +++ b/public/language/de/admin/advanced/database.json @@ -18,16 +18,16 @@ "mongo.resident-memory": "Permanenter Speicher", "mongo.virtual-memory": "Virtueller Speicher", "mongo.mapped-memory": "Zugeordneter Speicher", - "mongo.bytes-in": "Bytes In", - "mongo.bytes-out": "Bytes Out", - "mongo.num-requests": "Number of Requests", + "mongo.bytes-in": "Bytes eingehend", + "mongo.bytes-out": "Bytes ausgehend", + "mongo.num-requests": "Anzahl an Anfragen", "mongo.raw-info": "MongoDB Rohinfo", "redis": "Redis", "redis.version": "Redis Version", - "redis.keys": "Keys", - "redis.expires": "Expires", - "redis.avg-ttl": "Average TTL", + "redis.keys": "Schlüssel", + "redis.expires": "Ablauf", + "redis.avg-ttl": "Durchschnittliche TTL", "redis.connected-clients": "Verbundene Clients", "redis.connected-slaves": "Verbundene Slaves", "redis.blocked-clients": "Blockierte Clients", @@ -36,10 +36,10 @@ "redis.total-connections-recieved": "Gesamte empfangen Verbindungen", "redis.total-commands-processed": "Insgesamt Kommandos ausgeführt", "redis.iops": "Durchschnittliche Anzahl von Ein-/Ausgaben pro Sekunde", - "redis.iinput": "Instantaneous Input Per Second", - "redis.ioutput": "Instantaneous Output Per Second", - "redis.total-input": "Total Input", - "redis.total-output": "Total Ouput", + "redis.iinput": "Sofortige Eingabe pro Sekunde", + "redis.ioutput": "Sofortige Ausgabe pro Sekunde", + "redis.total-input": "Gesamt Eingabe", + "redis.total-output": "Gesamt Ausgabe", "redis.keyspace-hits": "Schlüsselraum Treffer", "redis.keyspace-misses": "Schlüsselraum Verfehlungen", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index f17d070899..41ca3880c4 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Sende eine E-Mail wenn auf Themen die ich abonniert habe geantwortet wird", "follow-created-topics": "Themen folgen, die du erstellst", "follow-replied-topics": "Themen folgen, auf die du antwortest", - "default-notification-settings": "Standardbenachrichtigungseinstellungen" + "default-notification-settings": "Standardbenachrichtigungseinstellungen", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/de/category.json b/public/language/de/category.json index 3e6998d184..878081bd57 100644 --- a/public/language/de/category.json +++ b/public/language/de/category.json @@ -7,14 +7,16 @@ "browsing": "Aktiv", "no_replies": "Niemand hat geantwortet", "no_new_posts": "Keine neuen Beiträge.", - "share_this_category": "Teile diese Kategorie", "watch": "Beobachten", "ignore": "Ignorieren", "watching": "Beobachte", + "not-watching": "Nicht beobachtet", "ignoring": "Ignoriere", - "watching.description": "Zeige Themen in Ungelesen", - "ignoring.description": "Zeige keine Themen in Ungelesen", - "watch.message": "Du beobachtest jetzt Änderungen in dieser Kategorie und allen Subkategorien", - "ignore.message": "Du ignorierst jetzt Änderungen in dieser Kategorie und allen Subkategorien", + "watching.description": "Zeige Themen in Ungelesen und Aktuell", + "not-watching.description": "Zeige keine Themen in Ungelesen, zeige sie in Aktuell", + "ignoring.description": "Zeige keine Themen in Ungelesen und Aktuell", + "watching.message": "Du beobachtest jetzt Aktualisierungen aus dieser Kategorie und allen Unterkategorien", + "notwatching.message": "Du beobachtest jetzt keine Aktualisierungen aus dieser Kategorie und allen Unterkategorien", + "ignoring.message": "Du ignorierst jetzt Aktualisierungen aus dieser Kategorie und allen Unterkategorien", "watched-categories": "Beobachtete Kategorien" } \ No newline at end of file diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index b83521cb49..8bfa0370d2 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Wenn dir jemand neues folgt", "notificationType_new-chat": "Wenn du eine Chat Nachricht erhältst", "notificationType_group-invite": "Wenn du eine Gruppeneinladung erhältst", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Wenn jemand der Registrierungswarteschlange hinzugefügt wird", "notificationType_post-queue": "Wenn ein neuer Beitrag eingereiht wird", "notificationType_new-post-flag": "Wenn ein Beitrag gemeldet wird", diff --git a/public/language/de/register.json b/public/language/de/register.json index ac2ef5fef4..6e11f0b7a4 100644 --- a/public/language/de/register.json +++ b/public/language/de/register.json @@ -21,6 +21,6 @@ "interstitial.intro": "Wir benötigen ein wenig mehr Informationen bevor wir dein Konto erstellen können.", "interstitial.errors-found": "Wir konnten deinen Registrierungsvorgang nicht abschließen:", "gdpr_agree_data": "Ich stimme der Sammlung und Verarbeitung meiner Persönlichen Daten auf dieser Website zu.", - "gdpr_agree_email": "Ich bin damit einverstanden, dass ich Informations und Benachrichtigungs-EMails von dieser Website erhalte.", + "gdpr_agree_email": "Ich bin damit einverstanden, dass ich Informations und Benachrichtigungs-E-Mails von dieser Website erhalte.", "gdpr_consent_denied": "Du musst zustimmen, dass diese Seite deine Daten sammeln und verarbeiten darf, und dir Emails senden darf." } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index 26a93620f9..2e317b490a 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -28,6 +28,7 @@ "watched_categories": "Beobachtete Kategorien", "watched": "Beobachtet", "ignored": "Ignoriert", + "default-category-watch-state": "Default category watch state", "followers": "Follower", "following": "Folge ich", "blocks": "Blockiert", @@ -48,6 +49,7 @@ "change_picture": "Profilbild ändern", "change_username": "Benutzernamen ändern", "change_email": "E-Mail ändern", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Ändern", "edit-profile": "Profil ändern", "default_picture": "Standardsymbol", @@ -151,8 +153,8 @@ "sessions.description": "Auf dieser Seite kannst du alle aktiven Sitzungen in diesem Forum einsehen und bei Bedarf widerrufen. Du kannst deine eigene Sitzung widerrufen, indem du dich von deinem Konto abmeldest.", "consent.title": "Deine Rechte & Zustimmungen", "consent.lead": "Dieses Community-Forum sammelt und verarbeitet deine persönlichen Daten.", - "consent.intro": "Wir nutzen diese Daten ausschließlich um dein Erlebnis in dieser Community persönlicher zu gestalten, sowie um deine Beiträge mit deinem Konto zu verknüpfen. Während der Registration wurdest du nach einem Benutzernamen und einer E-Mail-Adresse gefragt. Optional kannst du weitere Informationen bereitstellen um dein Profil auf dieser Website zu vervollständigen.

Wir behalten diese Informationen für die Lebensdauer deines Kontos, womit du jederzeit in der Lage bist deine Zustimmung durch löschen deines Kontos zu widerrufen. Du kannst jederzeit eine Kopie deiner Daten über deine Rechte & Zustimmungen-Seite anfordern.

Solltest du Fragen oder Bedenken haben, melde dich gerne bei den Administratoren dieses Forums.", - "consent.email_intro": "Gelegentlich werden wir E-Mails zu deiner registrierten E-Mail Adresse senden um dich über Generelles oder dich direkt betreffendes auf dem Laufenden zu halten. Auf deiner Benutzer-Einstellungen-Seite kannst du die Häufigkeit dieser Benachrichtigungen Einstellen (sogar komplett deaktivieren), sowie auswählen, welche Art von Benachrichtigungen du erhalten möchtest.", + "consent.intro": "Wir verwenden diese Informationen ausschließlich, um Deine Erfahrungen in dieser Community zu personalisieren und Deine Beiträge dem Benutzerkonto zuzuordnen.

Wir bewahren diese Informationen für die Dauer Deines Benutzerkontos auf. Du kannst die Einwilligung jederzeit widerrufen, indem Du Dein Konto löschst.

Wenn Du Fragen oder Bedenken hast, empfehlen wir, dich an das Adminteam dieses Forums zu wenden.", + "consent.email_intro": "Gelegentlich senden wir E-Mails an Deine E-Mail-Adresse um Updates bereitzustellen und/oder Dich über neue Aktivitäten zu informieren.", "consent.digest_frequency": "Sofern nicht explizit in Ihren Benutzereinstellungen geändert, werden alle %1 Zusammenfassungen per E-Mail versandt.", "consent.digest_off": "Sofern in Ihren Benutzereinstellungen nicht explizit geändert, werden keine Zusammenfassungen per E-Mail versandt.", "consent.received": "Du hast zugestimmt, dass diese Website deine Persönlichen Daten sammeln und verarbeiten darf. Es ist keine weitere Aktion erforderlich.", diff --git a/public/language/el/admin/settings/user.json b/public/language/el/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/el/admin/settings/user.json +++ b/public/language/el/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/el/category.json b/public/language/el/category.json index d194f5f37e..5ffaaf55c4 100644 --- a/public/language/el/category.json +++ b/public/language/el/category.json @@ -7,14 +7,16 @@ "browsing": "περιηγούνται", "no_replies": "Κανείς δεν έχει απαντήσει", "no_new_posts": "Δεν υπάρχουν νέες δημοσιεύσεις", - "share_this_category": "Μοιράσου αυτή την κατηγορία", "watch": "Watch", "ignore": "Αγνόηση", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Αγνόησε", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Watched categories" } \ No newline at end of file diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json index 65cf962be5..8c07ad2261 100644 --- a/public/language/el/notifications.json +++ b/public/language/el/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/el/user.json b/public/language/el/user.json index 93c1d83e49..cbf4ace860 100644 --- a/public/language/el/user.json +++ b/public/language/el/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Ακόλουθοι", "following": "Ακολουθά", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Αλλαγή Φωτογραφίας", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Επεξεργασία", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/en-GB/admin/settings/user.json +++ b/public/language/en-GB/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/en-GB/category.json b/public/language/en-GB/category.json index d581c8277d..96122292f0 100644 --- a/public/language/en-GB/category.json +++ b/public/language/en-GB/category.json @@ -10,16 +10,18 @@ "no_replies": "No one has replied", "no_new_posts": "No new posts.", - "share_this_category": "Share this category", "watch": "Watch", "ignore": "Ignore", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Watched categories" } diff --git a/public/language/en-GB/flags.json b/public/language/en-GB/flags.json index 35fc87011a..9b8658dceb 100644 --- a/public/language/en-GB/flags.json +++ b/public/language/en-GB/flags.json @@ -9,6 +9,7 @@ "updated": "Updated", "target-purged": "The content this flag referred to has been purged and is no longer available.", + "graph-label": "Daily Flags", "quick-filters": "Quick Filters", "filter-active": "There are one or more filters active in this list of flags", "filter-reset": "Remove Filters", diff --git a/public/language/en-GB/notifications.json b/public/language/en-GB/notifications.json index 70bc156f63..3716089d71 100644 --- a/public/language/en-GB/notifications.json +++ b/public/language/en-GB/notifications.json @@ -62,6 +62,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index 5c94a03779..571c9fc1bd 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -30,6 +30,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Followers", "following": "Following", "blocks": "Blocks", @@ -51,6 +52,7 @@ "change_picture": "Change Picture", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Edit", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/en-US/admin/settings/user.json b/public/language/en-US/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/en-US/admin/settings/user.json +++ b/public/language/en-US/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/en-US/category.json b/public/language/en-US/category.json index ec91137d81..4cf2cb8f11 100644 --- a/public/language/en-US/category.json +++ b/public/language/en-US/category.json @@ -7,14 +7,16 @@ "browsing": "browsing", "no_replies": "No one has replied", "no_new_posts": "No new posts.", - "share_this_category": "Share this category", "watch": "Watch", "ignore": "Ignore", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Watched categories" } \ No newline at end of file diff --git a/public/language/en-US/notifications.json b/public/language/en-US/notifications.json index cff71bdf47..04b6b94b2f 100644 --- a/public/language/en-US/notifications.json +++ b/public/language/en-US/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/en-US/user.json b/public/language/en-US/user.json index c617da50ba..7d5fba3e5e 100644 --- a/public/language/en-US/user.json +++ b/public/language/en-US/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Followers", "following": "Following", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Change Picture", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Edit", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/en-x-pirate/admin/settings/user.json b/public/language/en-x-pirate/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/en-x-pirate/admin/settings/user.json +++ b/public/language/en-x-pirate/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/en-x-pirate/category.json b/public/language/en-x-pirate/category.json index fa7ffd33e8..ffbc0870a9 100644 --- a/public/language/en-x-pirate/category.json +++ b/public/language/en-x-pirate/category.json @@ -7,14 +7,16 @@ "browsing": "browsin'", "no_replies": "No one has replied to ye message", "no_new_posts": "Thar be no new posts.", - "share_this_category": "Share 'tis category", "watch": "Be watchin'", "ignore": "Be ignorin'", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categories ye be watchin'" } \ No newline at end of file diff --git a/public/language/en-x-pirate/notifications.json b/public/language/en-x-pirate/notifications.json index b1508ddfee..e41dc6b9e4 100644 --- a/public/language/en-x-pirate/notifications.json +++ b/public/language/en-x-pirate/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/en-x-pirate/user.json b/public/language/en-x-pirate/user.json index 7f7d59e4cf..6bf3e62fd8 100644 --- a/public/language/en-x-pirate/user.json +++ b/public/language/en-x-pirate/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Followers", "following": "Following", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Change Picture", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Edit", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/es/admin/settings/user.json b/public/language/es/admin/settings/user.json index 7b522e3410..e253c318d8 100644 --- a/public/language/es/admin/settings/user.json +++ b/public/language/es/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Enviar un correo electrónico cuando se hacen respuestas a temas a los que estoy suscrito/a", "follow-created-topics": "Seguir los temas que tu crees", "follow-replied-topics": "Seguir los temas a los que contestas", - "default-notification-settings": "Configuración de notificación por defecto" + "default-notification-settings": "Configuración de notificación por defecto", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/es/category.json b/public/language/es/category.json index 1874242a1f..8090f614b0 100644 --- a/public/language/es/category.json +++ b/public/language/es/category.json @@ -7,14 +7,16 @@ "browsing": "viendo ahora", "no_replies": "Nadie ha respondido aún", "no_new_posts": "No hay mensajes nuevos.", - "share_this_category": "Compartir esta categoría", "watch": "Seguir", "ignore": "Ignorar", "watching": "Siguiendo", + "not-watching": "Not Watching", "ignoring": "Ignorando", - "watching.description": "Mostrar temas en no leidos", - "ignoring.description": "No mostrar temas en no leidos", - "watch.message": "Ahora puede ver la actualizaciones de esta categoría y todas las subcategorías", - "ignore.message": "Dejar de ver las actualizaciones de esta categoría y todas las subcategorías", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categorías seguidas" } \ No newline at end of file diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json index 377fa231b7..5931dd0a08 100644 --- a/public/language/es/notifications.json +++ b/public/language/es/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Cuando alguien comienza a seguirte", "notificationType_new-chat": "Cuando recibes un mensaje de chat", "notificationType_group-invite": "Cuando recibes una invitación a un grupo", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Cuando alguien es añadido a una cola de registro", "notificationType_post-queue": "Cuando un mensaje nuevo entra en la cola", "notificationType_new-post-flag": "Cuando un mensaje es denunciado", diff --git a/public/language/es/user.json b/public/language/es/user.json index 623e26793e..226d5522c0 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Suscritos", "ignored": "Ignorado", + "default-category-watch-state": "Default category watch state", "followers": "Seguidores", "following": "Siguiendo", "blocks": "Bloqueos", @@ -48,6 +49,7 @@ "change_picture": "Cambiar imagen", "change_username": "Cambiar nombre de usuario", "change_email": "Cambiar email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Editar", "edit-profile": "Editar Perfil", "default_picture": "Icono por defecto", diff --git a/public/language/et/admin/settings/user.json b/public/language/et/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/et/admin/settings/user.json +++ b/public/language/et/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/et/category.json b/public/language/et/category.json index 3202f90ab4..479061ae84 100644 --- a/public/language/et/category.json +++ b/public/language/et/category.json @@ -7,14 +7,16 @@ "browsing": "vaatab", "no_replies": "Keegi pole vastanud", "no_new_posts": "Uusi postitusi pole", - "share_this_category": "Jaga seda kategooriat", "watch": "Vaata", "ignore": "Ignoreeri", "watching": "Vaatab", + "not-watching": "Not Watching", "ignoring": "Ignoreerib", - "watching.description": "Näita teemasid lugemata teemade hulgas", - "ignoring.description": "Ära näita teemasid lugemata teemade hulgas", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Jälgitavad kategooriad" } \ No newline at end of file diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json index 63cd373727..f884227d8e 100644 --- a/public/language/et/notifications.json +++ b/public/language/et/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/et/user.json b/public/language/et/user.json index 0436624647..7c7535443c 100644 --- a/public/language/et/user.json +++ b/public/language/et/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Vaadatud", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Jälgijad", "following": "Jälgimised", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Vaheta pilti", "change_username": "Vaheta kasutajanime", "change_email": "Vaheta emaili", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Muuda", "edit-profile": "Redigeeri profiili", "default_picture": "Algne ikoon", diff --git a/public/language/fa-IR/admin/settings/user.json b/public/language/fa-IR/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/fa-IR/admin/settings/user.json +++ b/public/language/fa-IR/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/fa-IR/category.json b/public/language/fa-IR/category.json index 174e85bb67..4d324e5adf 100644 --- a/public/language/fa-IR/category.json +++ b/public/language/fa-IR/category.json @@ -7,14 +7,16 @@ "browsing": "بیننده‌ها", "no_replies": "هیچ کسی پاسخ نداده است.", "no_new_posts": "هیچ پست جدیدی وجود ندارد.", - "share_this_category": "به اشتراک‌گذاری این دسته بندی", "watch": "پیگیری", "ignore": "نادیده گرفتن", "watching": "درحال پیگیری", + "not-watching": "Not Watching", "ignoring": "در حال نادیده گرفتن", - "watching.description": "نمایش موضوعات خوانده نشده", - "ignoring.description": "هنوز موضوعات خوانده نشده را نشان نده", - "watch.message": "شما در حال حاضر در حال مشاهده به‌روزرسانی این دسته‌بندی و همه زیر شاخه‌های آن هستید", - "ignore.message": "شما در حال حاضر نادیده گرفته‌اید به‌روزرسانی این دسته‌بندی و همه زیر شاخه‌های آن", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "دسته بندی های پیگیری شده" } \ No newline at end of file diff --git a/public/language/fa-IR/notifications.json b/public/language/fa-IR/notifications.json index 18ca7e936a..2fc82e6cf8 100644 --- a/public/language/fa-IR/notifications.json +++ b/public/language/fa-IR/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "هنگامی که کسی شما را دنبال می کند", "notificationType_new-chat": "هنگامی که شما پیام چتی دریافت می کنید", "notificationType_group-invite": "هنگامی که شما دعوتنامه گروه دریافت می کنید", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "وقتی کسی به صف ثبت نام اضافه می شود", "notificationType_post-queue": "هنگامی که یک پست جدید در صف قرار می گیرد", "notificationType_new-post-flag": "هنگامی که پستی گزارش می شود", diff --git a/public/language/fa-IR/user.json b/public/language/fa-IR/user.json index cef401a447..b3e504f877 100644 --- a/public/language/fa-IR/user.json +++ b/public/language/fa-IR/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "پیگیری شده", "ignored": "نادیده گرفته شده", + "default-category-watch-state": "Default category watch state", "followers": "دنبال‌کننده‌ها", "following": "دنبال‌شونده‌ها", "blocks": "کاربران مسدود شده", @@ -48,6 +49,7 @@ "change_picture": "تغییر تصویر", "change_username": "تغییر نام کاربری", "change_email": "تغییر ایمیل", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "ویرایش", "edit-profile": "ویرایش پروفایل", "default_picture": "آیکون پیش فرض", diff --git a/public/language/fi/admin/settings/user.json b/public/language/fi/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/fi/admin/settings/user.json +++ b/public/language/fi/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/fi/category.json b/public/language/fi/category.json index a328811300..3f3b596cab 100644 --- a/public/language/fi/category.json +++ b/public/language/fi/category.json @@ -7,14 +7,16 @@ "browsing": "selaamassa", "no_replies": "Kukaan ei ole vastannut", "no_new_posts": "No new posts.", - "share_this_category": "Jaa tämä kategoria", "watch": "Watch", "ignore": "Sivuuta", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Watched categories" } \ No newline at end of file diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json index 35e73e39df..629bc9d74c 100644 --- a/public/language/fi/notifications.json +++ b/public/language/fi/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/fi/user.json b/public/language/fi/user.json index 5400db1afc..97254790f6 100644 --- a/public/language/fi/user.json +++ b/public/language/fi/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Seurattu", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Seuraajat", "following": "Seuratut", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Vaihda kuva", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Muokkaa", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/fr/admin/advanced/database.json b/public/language/fr/admin/advanced/database.json index dbf8bf2c69..29be4f8f26 100644 --- a/public/language/fr/admin/advanced/database.json +++ b/public/language/fr/admin/advanced/database.json @@ -18,8 +18,8 @@ "mongo.resident-memory": "Mémoire résidente", "mongo.virtual-memory": "Mémoire virtuelle", "mongo.mapped-memory": "Configuration de mémoire", - "mongo.bytes-in": "Octets entrés", - "mongo.bytes-out": "Octets sortants", + "mongo.bytes-in": "Données entrées", + "mongo.bytes-out": "Données sorties", "mongo.num-requests": "Nombre de requêtes", "mongo.raw-info": "Informations brutes MongoDB", diff --git a/public/language/fr/admin/settings/user.json b/public/language/fr/admin/settings/user.json index 1780aeed77..d17ff27680 100644 --- a/public/language/fr/admin/settings/user.json +++ b/public/language/fr/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Envoyer un email lors de réponses envoyées aux sujets auxquels je suis abonné", "follow-created-topics": "S'abonner aux sujets que vous créez", "follow-replied-topics": "S'abonner aux sujets auxquels vous répondez", - "default-notification-settings": "Paramètres des notifications par défaut" + "default-notification-settings": "Paramètres des notifications par défaut", + "categoryWatchState": "Abonnement par défaut", + "categoryWatchState.watching": "Abonné", + "categoryWatchState.notwatching": "Non abonné", + "categoryWatchState.ignoring": "Ignoré" } \ No newline at end of file diff --git a/public/language/fr/category.json b/public/language/fr/category.json index 5c70da5593..a24c215232 100644 --- a/public/language/fr/category.json +++ b/public/language/fr/category.json @@ -7,14 +7,16 @@ "browsing": "parcouru par", "no_replies": "Personne n'a répondu", "no_new_posts": "Pas de nouveau message", - "share_this_category": "Partager cette catégorie", "watch": "S'abonner", "ignore": "Ne plus surveiller", "watching": "Abonné", + "not-watching": "Ne plus être abonné", "ignoring": "Ignoré", - "watching.description": "Affiche les sujets dans la section Non lus", - "ignoring.description": "N'affiche pas les sujets dans la section Non lus", - "watch.message": "Vous êtes désormais abonné aux mises à jour de cette catégorie et de ses sous-catégories.", - "ignore.message": "Vous n'êtes plus abonné aux mises à jour de cette catégorie et de ses sous-catégories.", + "watching.description": "Afficher les sujets non lus et récents", + "not-watching.description": "Ne pas afficher les sujets non lus, afficher les récents", + "ignoring.description": "Ne pas afficher les sujets non lus et récents", + "watching.message": "Vous êtes désormais abonné aux mises à jour de cette catégorie et de ses sous-catégories. ", + "notwatching.message": "Vous n'êtes plus abonné aux mises à jour de cette catégorie et de ses sous-catégories.", + "ignoring.message": "Vous ignorez maintenant les mises à jour de cette catégorie et de toutes les sous-catégories.", "watched-categories": "Abonnements" } \ No newline at end of file diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json index 3bd87c7968..a5be7f8c4f 100644 --- a/public/language/fr/notifications.json +++ b/public/language/fr/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Lorsque quelqu'un commence à vous suivre", "notificationType_new-chat": "Lorsque vous recevez un message du chat ", "notificationType_group-invite": "Lorsque vous recevez une invitation d'un groupe", + "notificationType_group-request-membership": "Quand quelqu'un demande à rejoindre un groupe que vous administrez", "notificationType_new-register": "Lorsque quelqu'un est ajouté à la file d'attente d'inscription", "notificationType_post-queue": "Lorsque un nouveau message est mis en file d'attente", "notificationType_new-post-flag": "Lorsque un message est marqué", diff --git a/public/language/fr/user.json b/public/language/fr/user.json index 01a5e6529c..fa334e8d68 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -28,6 +28,7 @@ "watched_categories": "Catégories surveillées", "watched": "Abonnements", "ignored": "Ignorés", + "default-category-watch-state": "Abonnement par da catégorie", "followers": "Abonnés", "following": "Abonnements", "blocks": "Bloqués", @@ -48,6 +49,7 @@ "change_picture": "Changer d'image", "change_username": "Changer le nom d'utilisateur", "change_email": "Changer l'e-mail", + "email_same_as_password": "Veuillez entrer votre mot de passe actuel pour continuer – vous devez saisir à nouveau votre email", "edit": "Éditer", "edit-profile": "Éditer le profil", "default_picture": "Icône par défaut", diff --git a/public/language/gl/admin/settings/user.json b/public/language/gl/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/gl/admin/settings/user.json +++ b/public/language/gl/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/gl/category.json b/public/language/gl/category.json index d1668273a3..7c941fce02 100644 --- a/public/language/gl/category.json +++ b/public/language/gl/category.json @@ -7,14 +7,16 @@ "browsing": "vendo agora", "no_replies": "Ninguén respondeu", "no_new_posts": "Non hai publicacións novas.", - "share_this_category": "Comparte esta categoría", "watch": "Vixiar", "ignore": "Ignorar", "watching": "Seguindo", + "not-watching": "Not Watching", "ignoring": "Ignorando", - "watching.description": "Amosa-los temas en \"non lidos\"", - "ignoring.description": "Non amosa-los temas en \"non lidos\"", - "watch.message": "Agora pode ver actualizacións desta categoría en tódalas subcategorías", - "ignore.message": "Agora estás ignorando as actualizacións desta categoría e tódalas subcategorías.", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categorías vixiadas" } \ No newline at end of file diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json index 947cbc0cea..1e5e01e984 100644 --- a/public/language/gl/notifications.json +++ b/public/language/gl/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/gl/user.json b/public/language/gl/user.json index f6e30aeb29..13640d1535 100644 --- a/public/language/gl/user.json +++ b/public/language/gl/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Visto", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Seguidores", "following": "Seguindo", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Cambia-la foto", "change_username": "Cambia-lo nome de usuario", "change_email": "Cambia-lo correo", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Editar", "edit-profile": "Editar Perfil", "default_picture": "Icona por defecto.", diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/he/category.json b/public/language/he/category.json index 2d3fbfb4e1..feb657b487 100644 --- a/public/language/he/category.json +++ b/public/language/he/category.json @@ -7,14 +7,16 @@ "browsing": "צופים בנושא זה כעת", "no_replies": "אין תגובות", "no_new_posts": "אין פוסטים חדשים.", - "share_this_category": "שתף קטגוריה זו", "watch": "עקוב", "ignore": "התעלם", "watching": "עוקב", + "not-watching": "Not Watching", "ignoring": "מתעלם", - "watching.description": "צפה בנושאים שלא נקראו", - "ignoring.description": "אל תציג נושאים שאינם נקראו", - "watch.message": "אתה כעת עוקב אחר עדכונים בקטגוריה זו וכל תת-הקטגוריות", - "ignore.message": "אתה כעת מתעלם מעדכונים בקטגוריה זו וכל תת-הקטגוריות", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "קטגוריות נעקבות" } \ No newline at end of file diff --git a/public/language/he/flags.json b/public/language/he/flags.json index 74f7316034..141dd1607e 100644 --- a/public/language/he/flags.json +++ b/public/language/he/flags.json @@ -18,7 +18,7 @@ "filter-type": "סוג סימון", "filter-type-all": "כל התוכן", "filter-type-post": "פרסום", - "filter-type-user": "User", + "filter-type-user": "משתמש", "filter-state": "מצב", "filter-assignee": "UID של הממונה", "filter-cid": "קטגוריה", diff --git a/public/language/he/global.json b/public/language/he/global.json index e6dc05db67..3eaf5764f9 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -98,7 +98,7 @@ "enter_page_number": "הכנס מספר עמוד", "upload_file": "העלה קובץ", "upload": "העלה", - "uploads": "Uploads", + "uploads": "העלאות", "allowed-file-types": "פורמטי הקבצים המורשים הם %1", "unsaved-changes": "יש לך שינויים שאינם נשמרו. האם הנך בטוח שברצונך להמשיך?", "reconnecting-message": "נראה שההתחברות שלך אל %1 אבדה, אנא המתן בזמן שהמערכת מנסה לחבר אותך מחדש", diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index d68e6ef820..e7cb6abe5a 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "כשמישהו מתחיל לעקוב אחריך", "notificationType_new-chat": "כשאתה מקבל הודעת צאט", "notificationType_group-invite": "כשאתה מקבל הזמנה מקבוצה", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "כאשר מישהו מתווסף לתור הרישום", "notificationType_post-queue": "כשהודעה חדשה נכנסת לתור", "notificationType_new-post-flag": "כאשר פוסט מסומן", diff --git a/public/language/he/search.json b/public/language/he/search.json index e2fdd2cedb..4501b556c9 100644 --- a/public/language/he/search.json +++ b/public/language/he/search.json @@ -17,7 +17,7 @@ "at-most": "לכל היותר", "relevance": "רלוונטיות", "post-time": "זמן הפוסט", - "votes": "Votes", + "votes": "הצבעות", "newer-than": "חדש מ", "older-than": "ישן מ", "any-date": "כל תאריך", diff --git a/public/language/he/user.json b/public/language/he/user.json index e21859a7d4..e21cbae3c3 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -28,9 +28,10 @@ "watched_categories": "Watched categories", "watched": "נצפה", "ignored": "התעלם", + "default-category-watch-state": "Default category watch state", "followers": "עוקבים", "following": "עוקב אחרי", - "blocks": "Blocks", + "blocks": "חסימות", "block_toggle": "Toggle Block", "block_user": "חסום משתמש", "unblock_user": "בטל חסימת משתמש", @@ -48,6 +49,7 @@ "change_picture": "שנה תמונה", "change_username": "שנה שם משתמש", "change_email": "שנה מייל", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "ערוך", "edit-profile": "ערוך פרופיל", "default_picture": "אייקון ברירת מחדל", diff --git a/public/language/hr/admin/settings/user.json b/public/language/hr/admin/settings/user.json index 66766134d5..650d4bfbcb 100644 --- a/public/language/hr/admin/settings/user.json +++ b/public/language/hr/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Pošalji email pri odgovoru u teme na koje pratim", "follow-created-topics": "Prati teme koje kreiram", "follow-replied-topics": "Prati teme na koje odgovorim", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/hr/category.json b/public/language/hr/category.json index c4eb7644fa..598e22486c 100644 --- a/public/language/hr/category.json +++ b/public/language/hr/category.json @@ -7,14 +7,16 @@ "browsing": "pregledavanje", "no_replies": "Nema odgovora", "no_new_posts": "Nema novih tema.", - "share_this_category": "Podijeli ovu kategoriju", "watch": "Prati", "ignore": "Ignoriraj", "watching": "Pratim", + "not-watching": "Not Watching", "ignoring": "Ignoriram", - "watching.description": "Prikaži nepročitane teme", - "ignoring.description": "Ne prikazuj nepročitane teme", - "watch.message": "Sada pratite nove objave iz ove kategorije i svih potkategorija", - "ignore.message": "Sada ignorirate nove objave iz ove kategorije i svih potkategorija", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Praćene Kategorije" } \ No newline at end of file diff --git a/public/language/hr/notifications.json b/public/language/hr/notifications.json index 14b92c7c82..85e1eb3bf1 100644 --- a/public/language/hr/notifications.json +++ b/public/language/hr/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/hr/user.json b/public/language/hr/user.json index e3ed734d0f..9d032a630e 100644 --- a/public/language/hr/user.json +++ b/public/language/hr/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Gledano", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Pratitelji", "following": "Prati", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Promjeni sliku", "change_username": "Promjeni korisničko ime", "change_email": "Promjeni email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Uredi", "edit-profile": "Uredi profil", "default_picture": "Zadana ikona", diff --git a/public/language/hu/admin/settings/user.json b/public/language/hu/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/hu/admin/settings/user.json +++ b/public/language/hu/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/hu/category.json b/public/language/hu/category.json index 5f0d9370ea..e9f3ac3325 100644 --- a/public/language/hu/category.json +++ b/public/language/hu/category.json @@ -7,14 +7,16 @@ "browsing": "böngészés", "no_replies": "Nem érkezett válasz", "no_new_posts": "Nincs új hozzászólás.", - "share_this_category": "Kategória megosztása", "watch": "Figyelés", "ignore": "Mellőzés", "watching": "Figyelés", + "not-watching": "Not Watching", "ignoring": "Mellőzés", - "watching.description": "Témakörök megjelenítése az olvasatlanok között", - "ignoring.description": "Témakörök ne jelenjenek meg az olvasatlanok között", - "watch.message": "Mostantól figyeled a kategória és minden alkategóriája frissítéseit", - "ignore.message": "Mostantól figyelmen kívül hagyod a kategória és minden alkategóriája frissítéseit", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Figyelt kategóriák" } \ No newline at end of file diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json index 7fafe411b3..540fa91141 100644 --- a/public/language/hu/notifications.json +++ b/public/language/hu/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Mikor valaki elkezd követni téged", "notificationType_new-chat": "Mikor chat üzenetet kapsz", "notificationType_group-invite": "Mikor csoportmeghívást kapsz", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Mikor valaki a regisztrációs várólistára kerül", "notificationType_post-queue": "Mikor egy új hozzászólás várólistára kerül", "notificationType_new-post-flag": "Mikor egy hozzászólás megjelölésre kerül", diff --git a/public/language/hu/user.json b/public/language/hu/user.json index 0cb9bd1c3d..1423cdda68 100644 --- a/public/language/hu/user.json +++ b/public/language/hu/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Figyelve", "ignored": "Mellőzve", + "default-category-watch-state": "Default category watch state", "followers": "Követők", "following": "Követve", "blocks": "Blokkolások", @@ -48,6 +49,7 @@ "change_picture": "Kép módosítása", "change_username": "Felhasználónév módosítása", "change_email": "E-mail módosítása", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Szerkesztés", "edit-profile": "Profil szerkesztése", "default_picture": "Alapértelmezett ikon", diff --git a/public/language/id/admin/settings/user.json b/public/language/id/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/id/admin/settings/user.json +++ b/public/language/id/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/id/category.json b/public/language/id/category.json index ff5174c5f0..8b4eb093bb 100644 --- a/public/language/id/category.json +++ b/public/language/id/category.json @@ -7,14 +7,16 @@ "browsing": "penjelajahan", "no_replies": "Belum ada orang yang menjawab", "no_new_posts": "Tidak ada post terbaru", - "share_this_category": "Bagikan kategori ini", "watch": "mengamati", "ignore": "Abaikan", "watching": "mengamati", + "not-watching": "Not Watching", "ignoring": "Abaikan", - "watching.description": "Tunjukan topik yang belum dibaca", - "ignoring.description": "Jangan menunjukan topik yang belum dibaca", - "watch.message": "Anda mengamari pembaruan dalam kategori ini dan semua subkategori sekarang", - "ignore.message": "Anda mengabaikan pembaruan dalam kategori ini dan semua subkategori sekarang", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Kategori yang diamati" } \ No newline at end of file diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json index 61f6ae8cff..868c40f63c 100644 --- a/public/language/id/notifications.json +++ b/public/language/id/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/id/user.json b/public/language/id/user.json index 703caef891..42e5727956 100644 --- a/public/language/id/user.json +++ b/public/language/id/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Pengikut", "following": "Mengikuti", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Ganti Gambar/Foto", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Perbarui", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/it/admin/settings/user.json b/public/language/it/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/it/admin/settings/user.json +++ b/public/language/it/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/it/category.json b/public/language/it/category.json index a4dd47ce50..4dd7aa06b1 100644 --- a/public/language/it/category.json +++ b/public/language/it/category.json @@ -7,14 +7,16 @@ "browsing": "visualizzando", "no_replies": "Nessuno ha risposto", "no_new_posts": "Nessun nuovo post.", - "share_this_category": "Condividi questa Categoria", "watch": "Osserva", "ignore": "Ignora", "watching": "Seguito", + "not-watching": "Not Watching", "ignoring": "Ignorato", - "watching.description": "Mostra discussione in non letti", - "ignoring.description": "Non mostrare discussione in non letti", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categorie osservate" } \ No newline at end of file diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index 5271035074..66fe877d72 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Quando qualcuno inizia a seguirti", "notificationType_new-chat": "Quando ricevi un messaggio in chat", "notificationType_group-invite": "Quando ricevi un invito ad un gruppo", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Quando qualcuno viene aggiunto alla coda di registrazione", "notificationType_post-queue": "Quando un nuovo post è in attesa di revisione", "notificationType_new-post-flag": "Quando un post viene segnalato", diff --git a/public/language/it/user.json b/public/language/it/user.json index 9418426c49..86f37b7f5a 100644 --- a/public/language/it/user.json +++ b/public/language/it/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Osservati", "ignored": "Ignorati", + "default-category-watch-state": "Default category watch state", "followers": "Da chi è seguito", "following": "Chi segue", "blocks": "Blocchi", @@ -48,6 +49,7 @@ "change_picture": "Cambia Foto", "change_username": "Modifica il nome utente", "change_email": "Modifica Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Modifica", "edit-profile": "Modifica Profilo", "default_picture": "Icona di default", diff --git a/public/language/ja/admin/settings/user.json b/public/language/ja/admin/settings/user.json index 0458f6212d..3bb00cd12d 100644 --- a/public/language/ja/admin/settings/user.json +++ b/public/language/ja/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "購読中のスレッドに返信があった場合、メールで通知する。", "follow-created-topics": "投稿したスレッドをフォローします", "follow-replied-topics": "返信したスレッドをフォローします", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ja/category.json b/public/language/ja/category.json index 9878b194e7..1a18ffaa44 100644 --- a/public/language/ja/category.json +++ b/public/language/ja/category.json @@ -7,14 +7,16 @@ "browsing": "閲覧中", "no_replies": "返事はまだありません", "no_new_posts": "新しい投稿はありません", - "share_this_category": "このカテゴリを共有する", "watch": "ウォッチする", "ignore": "無視する", "watching": "ウォッチ中", + "not-watching": "Not Watching", "ignoring": "無視中", - "watching.description": "未読スレッドを表示する", - "ignoring.description": "未読スレッドを表示しない", - "watch.message": "あなたは現在、このカテゴリと全てのサブカテゴリで行われる更新をウォッチしています。", - "ignore.message": "あなたは現在、このカテゴリと全てのサブカテゴリで行われる更新を無視しています。", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "ウォッチ中のカテゴリ" } \ No newline at end of file diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json index 1be1639f93..3ac7457961 100644 --- a/public/language/ja/notifications.json +++ b/public/language/ja/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/ja/user.json b/public/language/ja/user.json index d762ea9aba..91a965ca6c 100644 --- a/public/language/ja/user.json +++ b/public/language/ja/user.json @@ -28,6 +28,7 @@ "watched_categories": "ウォッチ中のカテゴリ", "watched": "ウォッチ済み", "ignored": "無視済み", + "default-category-watch-state": "Default category watch state", "followers": "フォロワー", "following": "フォロー中", "blocks": "ブロックの設定", @@ -48,6 +49,7 @@ "change_picture": "画像を変更", "change_username": "ユーザー名の変更", "change_email": "メール変更", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "編集", "edit-profile": "プロフィールを編集", "default_picture": "元のアイコン", @@ -89,7 +91,7 @@ "has_no_posts": "このユーザーはまだ一つも投稿していません", "has_no_topics": "このユーザーはまだ一つもスレッドを作っていません", "has_no_watched_topics": "このユーザーはまだ一つもスレッドをウォッチしていません", - "has_no_ignored_topics": "This user hasn't ignored any topics yet.", + "has_no_ignored_topics": "この利用者はまだトピックを無視していません。", "has_no_upvoted_posts": "このユーザーはまだ一つも投稿に高評価を付けていません。", "has_no_downvoted_posts": "このユーザーはまだ一つも投稿に低評価を付けていません。", "has_no_voted_posts": "このユーザーは投稿を評価していません。", @@ -99,21 +101,21 @@ "paginate_description": "無限スクロールの代わりに、投稿やスレッドをページ別で切り替える。", "topics_per_page": "ページごとのスレッド数", "posts_per_page": "ページごとの投稿数", - "max_items_per_page": "Maximum %1", - "acp_language": "Admin Page Language", + "max_items_per_page": "最大 %1", + "acp_language": "ページ言語の管理", "notification_sounds": "通知の時に音を鳴らします", "notifications_and_sounds": "通知 & サウンド", "incoming-message-sound": "受信メッセージの音", "outgoing-message-sound": "送信メッセージの音", "notification-sound": "通知音", "no-sound": "無音", - "upvote-notif-freq": "Upvote Notification Frequency", - "upvote-notif-freq.all": "All Upvotes", - "upvote-notif-freq.first": "First Per Post", - "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq": "投票の通知頻度", + "upvote-notif-freq.all": "すべての高評価", + "upvote-notif-freq.first": "はじめの投稿", + "upvote-notif-freq.everyTen": "10の投票数", "upvote-notif-freq.threshold": "On 1, 5, 10, 25, 50, 100, 150, 200...", "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", - "upvote-notif-freq.disabled": "Disabled", + "upvote-notif-freq.disabled": "無効", "browsing": "ブラウジングの設定", "open_links_in_new_tab": "外部リンクを新しいタブで開く", "enable_topic_searching": "スレッド内検索を有効にする", @@ -132,9 +134,9 @@ "sso.title": "シングルサインオンサービス", "sso.associated": "関連付けられています", "sso.not-associated": "ここを押して、関連付けられています", - "sso.dissociate": "Dissociate", - "sso.dissociate-confirm-title": "Confirm Dissociation", - "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", + "sso.dissociate": "離脱する", + "sso.dissociate-confirm-title": "離脱の際に確認する", + "sso.dissociate-confirm": "アカウントと %1 の関連付けを解除しますか?", "info.latest-flags": "最近のフラグ", "info.no-flags": "フラグのついた投稿はありません", "info.ban-history": "最近停止した履歴", @@ -148,25 +150,25 @@ "info.moderation-note": "モデレーションノート", "info.moderation-note.success": "モデレーションは保存されませんでした", "info.moderation-note.add": "ノートに追加", - "sessions.description": "This page allows you to view any active sessions on this forum and revoke them if necessary. You can revoke your own session by logging out of your account.", - "consent.title": "Your Rights & Consent", - "consent.lead": "This community forum collects and processes your personal information.", + "sessions.description": "このページでは、このフォーラムでアクティブなセッションを表示し、必要に応じてそれらを取り消すことができます。あなたのアカウントからログアウトすることによって自分のセッションを取り消すことができます。", + "consent.title": "あなたの権利& 同意", + "consent.lead": "このコミュニティフォーラムはあなたの個人情報を収集し処理します。", "consent.intro": "We use this information strictly to personalise your experience in this community, as well as to associate the posts you make to your user account. During the registration step you were asked to provide a username and email address, you can also optionally provide additional information to complete your user profile on this website.

We retain this information for the life of your user account, and you are able to withdraw consent at any time by deleting your account. At any time you may request a copy of your contribution to this website, via your Rights & Consent page.

If you have any questions or concerns, we encourage you to reach out to this forum's administrative team.", "consent.email_intro": "Occasionally, we may send emails to your registered email address in order to provide updates and/or to notify you of new activity that is pertinent to you. You can customise the frequency of the community digest (including disabling it outright), as well as select which types of notifications to receive via email, via your user settings page.", "consent.digest_frequency": "Unless explicitly changed in your user settings, this community delivers email digests every %1.", "consent.digest_off": "Unless explicitly changed in your user settings, this community does not send out email digests", "consent.received": "You have provided consent for this website to collect and process your information. No additional action is required.", "consent.not_received": "You have not provided consent for data collection and processing. At any time this website's administration may elect to delete your account in order to become compliant with the General Data Protection Regulation.", - "consent.give": "Give consent", - "consent.right_of_access": "You have the Right of Access", + "consent.give": "同意を与える", + "consent.right_of_access": "あなたにはアクセス権があります", "consent.right_of_access_description": "You have the right to access any data collected by this website upon request. You can retrieve a copy of this data by clicking the appropriate button below.", - "consent.right_to_rectification": "You have the Right to Rectification", + "consent.right_to_rectification": "あなたには矯正の権利があります", "consent.right_to_rectification_description": "You have the right to change or update any inaccurate data provided to us. Your profile can be updated by editing your profile, and post content can always be edited. If this is not the case, please contact this site's administrative team.", "consent.right_to_erasure": "You have the Right to Erasure", "consent.right_to_erasure_description": "At any time, you are able to revoke your consent to data collection and/or processing by deleting your account. Your individual profile can be deleted, although your posted content will remain. If you wish to delete both your account and your content, please contact the administrative team for this website.", "consent.right_to_data_portability": "You have the Right to Data Portability", "consent.right_to_data_portability_description": "You may request from us a machine-readable export of any collected data about you and your account. You can do so by clicking the appropriate button below.", - "consent.export_profile": "Export Profile (.csv)", - "consent.export_uploads": "Export Uploaded Content (.zip)", - "consent.export_posts": "Export Posts (.csv)" + "consent.export_profile": "プロファイルをエクスポート(.csv)", + "consent.export_uploads": "アップデートしたコンテンツをエクスポート(.zip)", + "consent.export_posts": "投稿をエクスポート (.csv)" } \ No newline at end of file diff --git a/public/language/ko/admin/advanced/database.json b/public/language/ko/admin/advanced/database.json index 2f3b2dad8a..9504b749de 100644 --- a/public/language/ko/admin/advanced/database.json +++ b/public/language/ko/admin/advanced/database.json @@ -2,8 +2,8 @@ "x-b": "%1 B", "x-mb": "%1 MB", "x-gb": "%1 GB", - "uptime-seconds": "Uptime (초)", - "uptime-days": "Uptime (일)", + "uptime-seconds": "초 단위의 가동 시간", + "uptime-days": "일간 가동시간", "mongo": "Mongo", "mongo.version": "MongoDB 버젼", @@ -46,6 +46,6 @@ "redis.raw-info": "Redis Raw Info", "postgres": "Postgres", - "postgres.version": "PostgreSQL Version", + "postgres.version": "PostgreSQL 버전", "postgres.raw-info": "Postgres Raw Info" } diff --git a/public/language/ko/admin/general/dashboard.json b/public/language/ko/admin/general/dashboard.json index a077eaa2b5..f2af1170ad 100644 --- a/public/language/ko/admin/general/dashboard.json +++ b/public/language/ko/admin/general/dashboard.json @@ -14,7 +14,7 @@ "page-views-custom-help": "페이지 뷰를 확인하고 싶은 기간을 입력하세요. 만약 데이트 피커를 사용할 수 없다면, YYYY-MM-DD 포맷으로 입력해주세요.", "page-views-custom-error": "유효한 기간을 다음과 같은 포맷으로 입력하세요 YYYY-MM-DD", - "stats.day": "날", + "stats.day": "일", "stats.week": "주", "stats.month": "월", "stats.all": "항상", @@ -65,12 +65,12 @@ "high-presence-topics": "활동량이 많은 토픽", "graphs.page-views": "페이지 뷰", - "graphs.page-views-registered": "Page Views Registered", - "graphs.page-views-guest": "Page Views Guest", - "graphs.page-views-bot": "Page Views Bot", + "graphs.page-views-registered": "가입한 사용자의 페이지 조회", + "graphs.page-views-guest": "손님의 페이지 조회", + "graphs.page-views-bot": "봇의 페이지 조회", "graphs.unique-visitors": "고유 방문자", "graphs.registered-users": "등록된 사용자", "graphs.anonymous-users": "익명의 사용자", "last-restarted-by": "마지막으로 재시작", - "no-users-browsing": "No users browsing" + "no-users-browsing": "보고있는 사용자가 없습니다" } diff --git a/public/language/ko/admin/general/navigation.json b/public/language/ko/admin/general/navigation.json index 41edec7abb..360b15d596 100644 --- a/public/language/ko/admin/general/navigation.json +++ b/public/language/ko/admin/general/navigation.json @@ -8,7 +8,7 @@ "id": "ID: 선택 사항", "properties": "속성:", - "groups": "Groups:", + "groups": "그룹:", "open-new-window": "새 창에서 열기", "btn.delete": "삭제", diff --git a/public/language/ko/admin/manage/admins-mods.json b/public/language/ko/admin/manage/admins-mods.json index fa8bd1e2c9..89b5e67e4f 100644 --- a/public/language/ko/admin/manage/admins-mods.json +++ b/public/language/ko/admin/manage/admins-mods.json @@ -1,10 +1,10 @@ { "administrators": "최고관리자", - "global-moderators": "Global Moderators", - "no-global-moderators": "No Global Moderators", - "moderators-of-category": "%1 Moderators", - "no-moderators": "No Moderators", - "add-administrator": "Add Administrator", - "add-global-moderator": "Add Global Moderator", - "add-moderator": "Add Moderator" + "global-moderators": "글로벌 관리자", + "no-global-moderators": "글로벌 관리자가 없습니다", + "moderators-of-category": "%1 명의 관리자", + "no-moderators": "관리자 없음", + "add-administrator": "최고관리자 추가", + "add-global-moderator": "글로벌 관리자 추가", + "add-moderator": "관리자 추가" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/categories.json b/public/language/ko/admin/manage/categories.json index e26f3ab292..6e80d12e2b 100644 --- a/public/language/ko/admin/manage/categories.json +++ b/public/language/ko/admin/manage/categories.json @@ -19,7 +19,7 @@ "parent-category-none": "(없음)", "copy-settings": "에서 설정 복사", "optional-clone-settings": "(선택) 게시판에서 설정 복사", - "clone-children": "Clone Children Categories And Settings", + "clone-children": "하위 카테고리 및 설정 복사", "purge": "게시판 삭제", "enable": "활성화", @@ -29,8 +29,8 @@ "select-category": "게시판 선택", "set-parent-category": "상위 게시판 설정", - "privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. Select the domain of effect from the dropdown below.", - "privileges.category-selector": "Configuring privileges for ", + "privileges.description": "이 섹션에서 이 카테고리에 대한 접근 제어 권한을 구성 할 수 있습니다. 권한은 사용자별 또는 그룹별로 부여 할 수 있습니다. 아래 드롭 다운에서 적용하고자 하는 도메인을 선택하십시오.", + "privileges.category-selector": "다음에 대한 권한 구성", "privileges.warning": "참고: 권한 설정은 즉시 적용됩니다. 설정을 변경한 후 게시판을 따로 저장할 필요가 없습니다.", "privileges.section-viewing": "권한 보기", "privileges.section-posting": "게시물 작성 권한", @@ -68,7 +68,7 @@ "alert.user-search": "여기서 사용자를 검색하십시오...", "alert.find-group": "그룹 검색", "alert.group-search": "여기서 그룹을 검색하십시오...", - "collapse-all": "Collapse All", - "expand-all": "Expand All", - "disable-on-create": "Disable on create" + "collapse-all": "모두 축소", + "expand-all": "모두 확장", + "disable-on-create": "생성시 사용 중지" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/ip-blacklist.json b/public/language/ko/admin/manage/ip-blacklist.json index 85ee1607f0..8567606792 100644 --- a/public/language/ko/admin/manage/ip-blacklist.json +++ b/public/language/ko/admin/manage/ip-blacklist.json @@ -15,5 +15,5 @@ "analytics.blacklist-hourly": "Figure 1 – Blacklist hits per hour", "analytics.blacklist-daily": "Figure 2 – Blacklist hits per day", - "ip-banned": "IP banned" + "ip-banned": "IP 차단됨" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/privileges.json b/public/language/ko/admin/manage/privileges.json index 07d0a4de50..25b734b39b 100644 --- a/public/language/ko/admin/manage/privileges.json +++ b/public/language/ko/admin/manage/privileges.json @@ -1,30 +1,30 @@ { - "global": "Global", - "global.no-users": "No user-specific global privileges.", + "global": "글로벌", + "global.no-users": "사용자별 글로벌 권한이 없습니다.", - "chat": "Chat", - "upload-images": "Upload Images", - "upload-files": "Upload Files", - "signature": "Signature", - "ban": "Ban", - "search-content": "Search Content", - "search-users": "Search Users", - "search-tags": "Search Tags", - "allow-local-login": "Local Login", + "chat": "대화", + "upload-images": "이미지 업로드", + "upload-files": "파일 업로드", + "signature": "서명", + "ban": "차단", + "search-content": "콘텐츠 검색", + "search-users": "사용자 검색", + "search-tags": "태그 검색", + "allow-local-login": "로컬 로그인", - "find-category": "Find Category", - "access-category": "Access Category", - "access-topics": "Access Topics", - "create-topics": "Create Topics", - "reply-to-topics": "Reply to Topics", - "tag-topics": "Tag Topics", - "edit-posts": "Edit Posts", - "view-edit-history": "View Edit History", - "delete-posts": "Delete Posts", - "view_deleted": "View Deleted Posts", - "upvote-posts": "Upvote Posts", - "downvote-posts": "Downvote Posts", - "delete-topics": "Delete Topics", + "find-category": "카테고리 찾기", + "access-category": "카테고리 접근", + "access-topics": "글 접근", + "create-topics": "게시글 작성", + "reply-to-topics": "답글 작성", + "tag-topics": "태그 달기", + "edit-posts": "글 수정", + "view-edit-history": "편집 기록 보기", + "delete-posts": "글 삭제", + "view_deleted": "삭제된 게시물 보기", + "upvote-posts": "글 추천", + "downvote-posts": "글 비추천", + "delete-topics": "게시물 삭제", "purge": "Purge", "moderate": "Moderate" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/uploads.json b/public/language/ko/admin/manage/uploads.json index 21bc8201fc..c29416fa27 100644 --- a/public/language/ko/admin/manage/uploads.json +++ b/public/language/ko/admin/manage/uploads.json @@ -1,9 +1,9 @@ { - "upload-file": "Upload File", - "filename": "Filename", + "upload-file": "파일 업로드", + "filename": "파일명", "usage": "Post Usage", "orphaned": "Orphaned", - "size/filecount": "Size / Filecount", - "confirm-delete": "Do you really want to delete this file?", - "filecount": "%1 files" + "size/filecount": "크기 / 파일 수", + "confirm-delete": "이 파일을 정말로 삭제 하시겠습니까?", + "filecount": "%1 파일" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/users.json b/public/language/ko/admin/manage/users.json index fe83e61fe2..e81fb03392 100644 --- a/public/language/ko/admin/manage/users.json +++ b/public/language/ko/admin/manage/users.json @@ -28,7 +28,7 @@ "pills.search": "사용자 검색", "search.uid": "By User ID", - "search.uid-placeholder": "Enter a user ID to search", + "search.uid-placeholder": "검색 할 사용자 ID를 입력하십시오", "search.username": "이름으로", "search.username-placeholder": "검색할 사용자명을 입력하세요", "search.email": "이메일로", @@ -71,7 +71,7 @@ "alerts.lockout-reset-success": "락아웃이 리셋됐습니다!", "alerts.flag-reset-success": "신고가 리셋됐습니다!", "alerts.no-remove-yourself-admin": "관리자이기 때문에 본인을 삭제할 수 없습니다!", - "alerts.make-admin-success": "User is now administrator.", + "alerts.make-admin-success": "이 사용자는 이제 최고관리자 입니다.", "alerts.confirm-remove-admin": "Do you really want to remove this administrator?", "alerts.remove-admin-success": "User is no longer administrator.", "alerts.make-global-mod-success": "User is now global moderator.", @@ -93,7 +93,7 @@ "alerts.error-x": "에러

%1

", "alerts.create-success": "사용자가 생성됐습니다!", - "alerts.prompt-email": "Emails: ", + "alerts.prompt-email": "이메일:", "alerts.email-sent-to": "%1에게 초대 이메일이 발송됐습니다.", "alerts.x-users-found": "%1명의 사용자를 찾았습니다! 검색에 %2 ms가 소요됐습니다." } \ No newline at end of file diff --git a/public/language/ko/admin/menu.json b/public/language/ko/admin/menu.json index 357b673ee5..e2c30adbaf 100644 --- a/public/language/ko/admin/menu.json +++ b/public/language/ko/admin/menu.json @@ -9,15 +9,15 @@ "section-manage": "관리", "manage/categories": "게시판", - "manage/privileges": "Privileges", + "manage/privileges": "권한", "manage/tags": "태그", "manage/users": "사용자", - "manage/admins-mods": "Admins & Mods", + "manage/admins-mods": "관리 & 모드", "manage/registration": "회원 가입 승인 대기자", "manage/post-queue": "게시 대기열", "manage/groups": "그룹", "manage/ip-blacklist": "IP 블랙리스트", - "manage/uploads": "Uploads", + "manage/uploads": "업로드", "section-settings": "설정", "settings/general": "일반", @@ -42,7 +42,7 @@ "section-appearance": "스타일", "appearance/themes": "테마", "appearance/skins": "스킨", - "appearance/customise": "Custom Content (HTML/JS/CSS)", + "appearance/customise": "사용자 정의 콘텐츠 ((HTML/JS/CSS)", "section-extend": "추가 기능", "extend/plugins": "플러그인", @@ -64,7 +64,7 @@ "development/logger": "로거", "development/info": "정보", - "rebuild-and-restart-forum": "Rebuild & Restart Forum", + "rebuild-and-restart-forum": "리빌드 & 포럼 재시작", "restart-forum": "포럼 재시작", "logout": "로그아웃", "view-forum": "포럼 보기", @@ -78,5 +78,5 @@ "connection-lost": "%1과의 연결이 끊어졌습니다. 다시 연결을 시도하는 중입니다...", "alerts.version": "Running NodeBB v%1", - "alerts.upgrade": "Upgrade to v%1" + "alerts.upgrade": "v%1 로 업그레이드" } \ No newline at end of file diff --git a/public/language/ko/admin/settings/reputation.json b/public/language/ko/admin/settings/reputation.json index 278bc58dcc..c72b4d83fb 100644 --- a/public/language/ko/admin/settings/reputation.json +++ b/public/language/ko/admin/settings/reputation.json @@ -4,7 +4,7 @@ "disable-down-voting": "비추천 비활성화", "votes-are-public": "모든 투표는 공개적입니다.", "thresholds": "포럼 활동 기준선", - "min-rep-downvote": "평판이 낮아 이 게시물을 다운보트할 수 없습니다.", + "min-rep-downvote": "평판이 낮아 이 게시물을 다운로드 할 수 없습니다.", "min-rep-flag": "평판이 낮아 이 게시물을 신고할 수 없습니다.", "min-rep-website": "Minimum reputation to add \"Website\" to user profile", "min-rep-aboutme": "Minimum reputation to add \"About me\" to user profile", diff --git a/public/language/ko/admin/settings/user.json b/public/language/ko/admin/settings/user.json index a935574415..19ff1c4711 100644 --- a/public/language/ko/admin/settings/user.json +++ b/public/language/ko/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "내가 구독한 주제에 답글이 달리면 메일 보내기", "follow-created-topics": "작성한 게시물 팔로우", "follow-replied-topics": "답글 단 게시물을 팔로우", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ko/category.json b/public/language/ko/category.json index ad9e576507..f8ac18a799 100644 --- a/public/language/ko/category.json +++ b/public/language/ko/category.json @@ -7,14 +7,16 @@ "browsing": "이 주제를 읽고 있는 사용자", "no_replies": "답글이 없습니다.", "no_new_posts": "새로운 게시물이 없습니다.", - "share_this_category": "이 카테고리를 공유", "watch": "관심 주제", "ignore": "관심 해제", "watching": "관심있음", + "not-watching": "Not Watching", "ignoring": "무시하기", - "watching.description": "읽지 않은 주제를 표시합니다", - "ignoring.description": "읽지 않은 주제를 표시하지 않습니다", - "watch.message": "이 게시판 밑 모든 하위게시판의 업데이트에 대해 알림을 받습니다.", - "ignore.message": "이 게시판 밑 모든 하위게시판의 업데이트에 대해 알림을 받지 않습니다.", + "watching.description": "읽지 않은 글 및 최근 글 보기", + "not-watching.description": "읽지 않은 글 및 최근 글 보지 않기", + "ignoring.description": "읽지 않은 글과 최근 글 보지 않기", + "watching.message": "이 카테고리 및 모든 하위 카테고리의 업데이트를 주시중입니다", + "notwatching.message": "이 카테고리 및 모든 하위 카테고리의 업데이트를 주시하고 있지 않습니다", + "ignoring.message": "이 카테고리 및 모든 하위 카테고리의 업데이트를 무시하고 있습니다", "watched-categories": "관심 카테고리" } \ No newline at end of file diff --git a/public/language/ko/email.json b/public/language/ko/email.json index 3b56627055..b08137e554 100644 --- a/public/language/ko/email.json +++ b/public/language/ko/email.json @@ -1,18 +1,18 @@ { - "test-email.subject": "Test Email", - "password-reset-requested": "Password Reset Requested!", + "test-email.subject": "이메일 테스트", + "password-reset-requested": "비밀번호 재설정을 요청했습니다!", "welcome-to": "%1에 오신 것을 환영합니다.", "invite": "%1 님이 초대하였습니다.", "greeting_no_name": "안녕하세요", "greeting_with_name": "안녕하세요 %1님", - "email.verify-your-email.subject": "Please verify your email", - "email.verify.text1": "Your email address has changed!", + "email.verify-your-email.subject": "사용자님의 이메일을 확인하십시오", + "email.verify.text1": "사용자님의 이메일 주소가 변경되었습니다!", "welcome.text1": "%1님 가입해주셔서 감사합니다.", "welcome.text2": "계정을 활성화하려면 등록하신 메일 주소가 유효한지 확인이 필요합니다.", "welcome.text3": "관리자에 의해 승인되었습니다. 사용자명/비밀번호를 통해 지금 로그인 하실 수 있습니다.", "welcome.cta": "메일 주소를 확인하려면 여기를 클릭하세요.", "invitation.text1": "%1님이 %2에 귀하를 초대하였습니다.", - "invitation.text2": "Your invitation will expire in %1 days.", + "invitation.text2": "사용자님의 초대장은 %1 일 후에 만료됩니다.", "invitation.ctr": "이곳을 클릭하여 계정을 생성하세요.", "reset.text1": "비밀번호 재설정 요청을 받았습니다. 비밀번호를 분실해서 요청한 것이 아니라면 이 메일을 무시하셔도 좋습니다.", "reset.text2": "비밀번호를 재설정하려면 다음 링크를 클릭하세요.", @@ -34,7 +34,7 @@ "notif.chat.unsub.info": "이 대화 알림은 사용자의 구독 설정에 따라 전송되었습니다.", "notif.post.cta": "이곳을 클릭하여 전체 내용 보기", "notif.post.unsub.info": "이 게시물 알림은 사용자의 구독 설정에 따라 전송되었습니다.", - "notif.cta": "Click here to go to forum", + "notif.cta": "포럼으로 이동하려면 여기를 클릭하십시오", "test.text1": "이 시험용 메일은 NodeBB에 설정된 메일 송신자가 정상적으로 메일을 송신할 수 있는지 시험할 목적으로 발송되었습니다.", "unsub.cta": "설정을 변경하려면 여기를 클릭하세요.", "banned.subject": "귀하는 %1 로 부터 차단되었습니다.", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 58e62f625f..b4504edde5 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -18,7 +18,7 @@ "invalid-username-or-password": "사용자명과 패스워드를 모두 설정해주세요.", "invalid-search-term": "올바르지 않은 검색어입니다.", "invalid-url": "올바르지 않은 URL 입니다.", - "local-login-disabled": "Local login system has been disabled for non-privileged accounts.", + "local-login-disabled": "계정의 권한이 없어 로컬 로그인 시스템이 비활성화 되었습니다.", "csrf-invalid": "세션이 만료되어 로그인에 실패하였습니다. 다시 시도해 주세요.", "invalid-pagination-value": "올바르지 않은 페이지 값입니다. 최소 1% 에서 최대 2% 사이로 설정해야 합니다.", "username-taken": "이미 사용 중인 사용자명 입니다.", @@ -78,7 +78,7 @@ "still-uploading": "업로드가 끝날 때까지 기다려주세요.", "file-too-big": "업로드 가능한 파일크기는 최대 %1 KB 입니다 - 파일의 용량을 줄이거나 압축을 활용하세요.", "guest-upload-disabled": "미가입 사용자의 파일 업로드는 제한되어 있습니다.", - "cors-error": "Unable to upload image due to misconfigured CORS", + "cors-error": "잘못 구성된 CORS로 인해 이미지를 업로드 할 수 없습니다", "already-bookmarked": "이미 즐겨찾기에 추가한 포스트 입니다.", "already-unbookmarked": "이미 즐겨찾기를 해제한 포스트 입니다.", "cant-ban-other-admins": "다른 관리자를 차단할 수 없습니다.", @@ -88,7 +88,7 @@ "invalid-image-type": "올바르지 않은 이미지입니다. 사용가능한 유형: %1", "invalid-image-extension": "올바르지 않은 이미지 확장자입니다.", "invalid-file-type": "올바르지 않은 파일 유형입니다. 사용가능한 유형: %1", - "invalid-image-dimensions": "Image dimensions are too big", + "invalid-image-dimensions": "이미지 크기가 너무 큽니다", "group-name-too-short": "그룹 이름이 너무 짧습니다.", "group-name-too-long": "그룹 이름이 너무 깁니다.", "group-already-exists": "이미 존재하는 그룹입니다.", @@ -120,19 +120,19 @@ "chat-edit-duration-expired": "You are only allowed to edit chat messages for %1 second(s) after posting", "chat-delete-duration-expired": "You are only allowed to delete chat messages for %1 second(s) after posting", "chat-deleted-already": "이미 삭제된 대화 메시지입니다.", - "chat-restored-already": "This chat message has already been restored.", + "chat-restored-already": "이 채팅 메시지는 이미 복원되었습니다.", "already-voting-for-this-post": "이미 이 포스트에 투표하셨습니다.", "reputation-system-disabled": "인지도 시스템이 비활성 상태입니다.", "downvoting-disabled": "비추천 기능이 비활성 상태입니다.", "not-enough-reputation-to-downvote": "인지도가 낮아 이 포스트를 비추천할 수 없습니다.", "not-enough-reputation-to-flag": "인지도가 낮아 이 포스트를 신고할 수 없습니다.", - "not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website", - "not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me", - "not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature", - "not-enough-reputation-min-rep-profile-picture": "You do not have enough reputation to add a profile picture", - "not-enough-reputation-min-rep-cover-picture": "You do not have enough reputation to add a cover picture", + "not-enough-reputation-min-rep-website": "인지도가 낮아 웹사이트를 추가 할 수 없습니다.", + "not-enough-reputation-min-rep-aboutme": "인지도가 낮아 자기소개를 추가 할 수 없습니다.", + "not-enough-reputation-min-rep-signature": "인지도가 낮아 서명을 추가 할 수 없습니다.", + "not-enough-reputation-min-rep-profile-picture": "인지도가 낮아 프로필 사진을 추가 할 수 없습니다.", + "not-enough-reputation-min-rep-cover-picture": "인지도가 낮아 표지 사진을 추가 할 수 없습니다.", "already-flagged": "이미 이 게시물을 신고했습니다.", - "self-vote": "You cannot vote on your own post", + "self-vote": "자신의 게시물에는 투표 할 수 없습니다.", "reload-failed": "NodeBB 서버를 다시 읽어들이는 중 다음과 같은 문제가 발생했으나 사용자측은 지속적으로 자원을 제공받습니다. 오류 문구: \"%1\" 문제를 해결하시려면 다시 읽어들이기 전의 수정사항을 원래대로 되돌려주세요. ", "registration-error": "등록 오류", "parse-error": "서버로 부터의 응답을 읽는 동안 문제가 발생했습니다.", @@ -149,12 +149,12 @@ "invalid-home-page-route": "올바르지 않은 홈페이지 경로입니다. ", "invalid-session": "일치하지 않는 세션입니다.", "invalid-session-text": "로그인 세션이 비활성화 되었거나 서버와 일치하지 않습니다. 페이지를 새로 고쳐주세요.", - "no-topics-selected": "No topics selected!", - "cant-move-to-same-topic": "Can't move post to same topic!", - "cannot-block-self": "You cannot block yourself!", + "no-topics-selected": "선택된 글이 없습니다!", + "cant-move-to-same-topic": "동일한 주제글로 게시물을 이동할 수 없습니다!", + "cannot-block-self": "자신을 차단 할 수 없습니다!", "cannot-block-privileged": "관리자나 글로벌 매니저는 차단할 수 없습니다", - "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", - "no-connection": "There seems to be a problem with your internet connection" + "cannot-block-guest": "손님은 다른 사용자를 차단할 수 없습니다", + "already-blocked": "이 사용자는 이미 차단 되었습니다", + "already-unblocked": "이 사용자는 이미 차단 해제 되었습니다", + "no-connection": "사용자님의 인터넷 연결에 문제가있는 것 같습니다" } \ No newline at end of file diff --git a/public/language/ko/flags.json b/public/language/ko/flags.json index af87ffe045..6804d4f59a 100644 --- a/public/language/ko/flags.json +++ b/public/language/ko/flags.json @@ -18,7 +18,7 @@ "filter-type": "신고 유형", "filter-type-all": "모든 컨텐츠", "filter-type-post": "포스트", - "filter-type-user": "User", + "filter-type-user": "사용자", "filter-state": "처리 상태", "filter-assignee": "담당자 ID", "filter-cid": "게시판", @@ -55,11 +55,11 @@ "modal-body": "%1 %2 에 대한 신고 사유를 적어주시거나, 빠른 신고 버튼 중 하나를 사용해 주세요.", "modal-reason-spam": "스팸", "modal-reason-offensive": "부적절한 글", - "modal-reason-other": "Other (specify below)", + "modal-reason-other": "기타 (아래에 작성)", "modal-reason-custom": "신고 사유", "modal-submit": "리포트 제출", "modal-submit-success": "이 컨텐츠는 신고되었습니다.", - "modal-submit-confirm": "Confirm Submission", + "modal-submit-confirm": "제출 확인", "modal-submit-confirm-text": "You have a custom reason specified already. Are you sure you wish to submit via quick-report?", "modal-submit-confirm-text-help": "Submitting a quick report will overwrite any custom reasons defined." } \ No newline at end of file diff --git a/public/language/ko/global.json b/public/language/ko/global.json index ede3367a3b..253a85bda0 100644 --- a/public/language/ko/global.json +++ b/public/language/ko/global.json @@ -53,7 +53,7 @@ "topics": "게시물", "posts": "포스트", "best": "베스트", - "votes": "Votes", + "votes": "투표", "upvoters": "추천한 사용자", "upvoted": "추천된 게시물", "downvoters": "비추천한 사용자", @@ -76,7 +76,7 @@ "norecenttopics": "최근 작성된 게시물이 없습니다.", "recentposts": "최근 포스트", "recentips": "최근에 로그인한 IP", - "moderator_tools": "(준)관리자 도구모음", + "moderator_tools": "관리 도구", "away": "자리 비움", "dnd": "방해 금지", "invisible": "오프라인으로 표시", @@ -85,7 +85,7 @@ "language": "언어", "guest": "익명 사용자", "guests": "익명 사용자", - "former_user": "A Former User", + "former_user": "이전 사용자", "updated.title": "포럼이 업데이트 되었습니다.", "updated.message": "이 포럼은 지금 최신 버전으로 업데이트 되었습니다. 페이지를 새로고침 하시려면 여기를 클릭해주세요.", "privacy": "개인정보", @@ -98,7 +98,7 @@ "enter_page_number": "페이지 번호를 입력하세요", "upload_file": "파일 업로드", "upload": "업로드", - "uploads": "Uploads", + "uploads": "업로드", "allowed-file-types": "사용가능한 파일 유형: %1", "unsaved-changes": "저장되지 않은 변경사항이 있습니다. 저장하지 않고 페이지를 떠나시겠습니까?", "reconnecting-message": "%1 사이트로의 연결이 끊어졌습니다. 다시 연결을 시도하는동안 잠시만 기다려 주십시오.", @@ -109,5 +109,5 @@ "edited": "수정 되었습니다.", "disabled": "비활성화", "select": "선택", - "user-search-prompt": "Type something here to find users..." + "user-search-prompt": "사용자를 찾기 위해 여기에 검색어를 입력하십시오..." } \ No newline at end of file diff --git a/public/language/ko/language.json b/public/language/ko/language.json index 9a19e01124..f052cb6449 100644 --- a/public/language/ko/language.json +++ b/public/language/ko/language.json @@ -1,5 +1,5 @@ { - "name": "한국어", + "name": "영어 (영국/캐나다)", "code": "ko", "dir": "ltr" } \ No newline at end of file diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index c0db90a820..31846c1a3a 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -12,7 +12,7 @@ "chat.recent-chats": "최근 채팅", "chat.contacts": "연락처", "chat.message-history": "대화 기록", - "chat.options": "Chat options", + "chat.options": "채팅 옵션", "chat.pop-out": "분리된 창에서 채팅", "chat.minimize": "최소화", "chat.maximize": "최대화", @@ -23,17 +23,17 @@ "chat.retrieving-users": "Retrieving users...", "chat.manage-room": "Manage Chat Room", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", - "chat.confirm-chat-with-dnd-user": "이 사용자의 상태는 \"방해금지\" 입니다. 그래도 대화를 요청 하시겠습니까?", - "chat.rename-room": "Rename Room", - "chat.rename-placeholder": "Enter your room name here", + "chat.confirm-chat-with-dnd-user": "이 사용자는 자신의 상태를 DnD (방해금지)로 설정했습니다. 그래도 대화를 요청 하시겠습니까?", + "chat.rename-room": "방 이름 바꾸기", + "chat.rename-placeholder": "여기에 방명을 입력하십시오", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "채팅에서 나가기", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", "chat.in-room": "In this room", - "chat.kick": "Kick", - "chat.show-ip": "Show IP", - "chat.owner": "Room Owner", + "chat.kick": "추방", + "chat.show-ip": "IP 보이기", + "chat.owner": "방 소유자", "composer.compose": "작성", "composer.show_preview": "미리보기", "composer.hide_preview": "미리보기 숨김", @@ -47,7 +47,7 @@ "composer.formatting.italic": "이탤릭체", "composer.formatting.list": "목록", "composer.formatting.strikethrough": "취소선", - "composer.formatting.code": "Code", + "composer.formatting.code": "코드", "composer.formatting.link": "링크", "composer.formatting.picture": "사진", "composer.upload-picture": "이미지 업로드", diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json index 391e826e58..b9b7954075 100644 --- a/public/language/ko/notifications.json +++ b/public/language/ko/notifications.json @@ -8,7 +8,7 @@ "outgoing_link_message": "%1 를 떠납니다.", "continue_to": "%1 사이트로 이동", "return_to": "%1 사이트로 돌아가기", - "new_notification": "You have a new notification", + "new_notification": "새로운 알림이 있습니다", "you_have_unread_notifications": "읽지 않은 알림이 있습니다.", "all": "모든 알림", "topics": "게시물", @@ -46,18 +46,19 @@ "email-confirmed-message": "이메일을 인증해주셔서 감사합니다. 계정이 완전히 활성화되었습니다.", "email-confirm-error-message": "이메일 주소를 인증하지 못했습니다. 코드가 올바르지 않거나 만료 되었을 수 있습니다.", "email-confirm-sent": "확인 이메일이 발송되었습니다.", - "none": "None", - "notification_only": "Notification Only", - "email_only": "Email Only", - "notification_and_email": "Notification & Email", - "notificationType_upvote": "When someone upvotes your post", + "none": "없음", + "notification_only": "알림만", + "email_only": "이메일만", + "notification_and_email": "알림 & 이메일", + "notificationType_upvote": "누군가 사용자님의 글을 추천해 줄 때", "notificationType_new-topic": "When someone you follow posts a topic", - "notificationType_new-reply": "When a new reply is posted in a topic you are watching", - "notificationType_follow": "When someone starts following you", - "notificationType_new-chat": "When you receive a chat message", - "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-reply": "주시중인 글에 새로운 답글이 게시되면", + "notificationType_follow": "누군가 사용자님을 팔로우 하면", + "notificationType_new-chat": "채팅 메시지를 받으면", + "notificationType_group-invite": "그룹 초대를 받으면", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", - "notificationType_new-post-flag": "When a post is flagged", - "notificationType_new-user-flag": "When a user is flagged" + "notificationType_new-post-flag": "게시글이 신고되면", + "notificationType_new-user-flag": "사용자가 신고되면" } \ No newline at end of file diff --git a/public/language/ko/pages.json b/public/language/ko/pages.json index bf40d3e8f3..0c5bc7a2ee 100644 --- a/public/language/ko/pages.json +++ b/public/language/ko/pages.json @@ -1,19 +1,19 @@ { "home": "홈", "unread": "읽지 않은 게시물", - "popular-day": "인기있는 게시물 (오늘)", - "popular-week": "인기있는 게시물 (주간)", - "popular-month": "인기있는 게시물 (월간)", + "popular-day": "오늘의 인기 게시물", + "popular-week": "이번주 인기 게시물", + "popular-month": "이번달 인기 게시물", "popular-alltime": "인기있는 게시물", "recent": "최근 게시물", - "top-day": "Top voted topics today", - "top-week": "Top voted topics this week", - "top-month": "Top voted topics this month", - "top-alltime": "Top Voted Topics", - "moderator-tools": "Moderator Tools", + "top-day": "투표가 많은 오늘의 게시물", + "top-week": "투표가 많은 이번주 게시물", + "top-month": "투표가 많은 이번달 게시물", + "top-alltime": "투표가 많은 게시물", + "moderator-tools": "관리 도구", "flagged-content": "신고된 컨텐츠", "ip-blacklist": "IP 블랙리스트", - "post-queue": "Post Queue", + "post-queue": "게시 대기열", "users/online": "접속중인 사용자", "users/latest": "최근 사용자", "users/sort-posts": "가장 많은 게시물을 작성한 사용자", @@ -23,7 +23,7 @@ "users/search": "사용자 검색", "notifications": "알림", "tags": "태그", - "tag": "Topics tagged under "%1"", + "tag": ""%1" 태그의 게시물", "register": "회원가입", "registration-complete": "회원가입 완료", "login": "로그인", @@ -45,17 +45,17 @@ "account/posts": "%1 님이 작성한 포스트", "account/topics": "%1 님이 생성한 게시물", "account/groups": "%1 님의 그룹", - "account/watched_categories": "%1's Watched Categories", + "account/watched_categories": "%1 님이 주시중인 카테고리", "account/bookmarks": "%1 님이 즐겨찾기 한 포스트", "account/settings": "사용자 설정", "account/watched": "%1 님이 관심 가진 게시물", - "account/ignored": "Topics ignored by %1", + "account/ignored": "%1 님에 의해 무시됨", "account/upvoted": "%1 님이 추천한 포스트", "account/downvoted": "%1 님에 비추천한 포스트", "account/best": "%1 님 최고의 포스트", "account/blocks": "Blocked users for %1", - "account/uploads": "Uploads by %1", - "account/sessions": "Login Sessions", + "account/uploads": "%1 님이 업로드", + "account/sessions": "로그인 세션", "confirm": "이메일 인증 되었습니다", "maintenance.text": "%1 사이트는 현재 점검 중입니다. 나중에 다시 방문해주세요.", "maintenance.messageIntro": "다음은 관리자가 전하는 메시지입니다.", diff --git a/public/language/ko/register.json b/public/language/ko/register.json index 873c2e36b3..dd3f7534ad 100644 --- a/public/language/ko/register.json +++ b/public/language/ko/register.json @@ -20,7 +20,7 @@ "registration-added-to-queue": "회원가입이 요청되었습니다. 관리자의 승인 후 메일이 발송됩니다.", "interstitial.intro": "계정을 생성하기 전 추가 정보가 더 필요합니다.", "interstitial.errors-found": "회원가입을 완료하지 못했습니다.", - "gdpr_agree_data": "I consent to the collection and processing of my personal information on this website.", - "gdpr_agree_email": "I consent to receive digest and notification emails from this website.", - "gdpr_consent_denied": "You must give consent to this site to collect/process your information, and to send you emails." + "gdpr_agree_data": "나는 이 웹 사이트에서 개인 정보를 수집하고 처리하는데 동의합니다.", + "gdpr_agree_email": "나는 이 웹 사이트에서 다이제스트 및 알림 메일을 수신하는데 동의합니다.", + "gdpr_consent_denied": "사용자님은 이 사이트가 사용자님의 정보를 수집/처리하고 이메일을 보내는것에 동의해야합니다." } \ No newline at end of file diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index 1e6528c8e1..ec9759b160 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -56,13 +56,13 @@ "not-watching.description": "새로운 답글에 대해 알림 받지 않기. 해당 게시판을 팔로우 중이라면 \"읽지않은 게시물\" 에서 보여주기.", "ignoring.description": "새로운 답글에 대한 알림 받지 않기. \"읽지않은 게시물\"에서 보여주지 않기.", "thread_tools.title": "게시물 관리", - "thread_tools.markAsUnreadForAll": "Mark Unread For All", + "thread_tools.markAsUnreadForAll": "모두에게 읽지 않음으로 표시", "thread_tools.pin": "상단 고정", "thread_tools.unpin": "상단 고정 해제", "thread_tools.lock": "잠금", "thread_tools.unlock": "잠금 해제", "thread_tools.move": "이동", - "thread_tools.move-posts": "Move Posts", + "thread_tools.move-posts": "글 이동", "thread_tools.move_all": "모두 이동", "thread_tools.select_category": "게시판 선택", "thread_tools.fork": "주제 분리", @@ -73,8 +73,8 @@ "thread_tools.restore_confirm": "이 게시물을 복원 하시겠습니까?", "thread_tools.purge": "게시물 폐기", "thread_tools.purge_confirm": "이 게시물을 폐기 하시겠습니까?", - "thread_tools.merge_topics": "Merge Topics", - "thread_tools.merge": "Merge", + "thread_tools.merge_topics": "게시물 병합", + "thread_tools.merge": "병합", "topic_move_success": "성공적으로 이 게시물을 %1로 이동했습니다.", "post_delete_confirm": "이 포스트를 삭제 하시겠습니까?", "post_restore_confirm": "이 포스트를 복원 하시겠습니까?", @@ -125,9 +125,9 @@ "stale.create": "새로운 게시물 작성", "stale.reply_anyway": "이 게시물에 답글 작성", "link_back": "답글: [%1](%2)", - "diffs.title": "Post Edit History", + "diffs.title": "글 수정 기록", "diffs.description": "This post has %1 revisions. Click one of the revisions below to see the post content at that point in time.", "diffs.no-revisions-description": "This post has %1 revisions.", - "diffs.current-revision": "current revision", - "diffs.original-revision": "original revision" + "diffs.current-revision": "현재 리비젼", + "diffs.original-revision": "원래의 리비젼" } \ No newline at end of file diff --git a/public/language/ko/uploads.json b/public/language/ko/uploads.json index c43a90c59e..26582d6b93 100644 --- a/public/language/ko/uploads.json +++ b/public/language/ko/uploads.json @@ -3,7 +3,7 @@ "select-file-to-upload": "업로드할 파일을 선택해 주세요!", "upload-success": "파일이 성공적으로 업로드 되었습니다!", "maximum-file-size": "최대 %1 kb", - "no-uploads-found": "No uploads found", - "public-uploads-info": "Uploads are public, all visitors can see them.", - "private-uploads-info": "Uploads are private, only logged in users can see them." + "no-uploads-found": "업로드한 파일이 없습니다", + "public-uploads-info": "업로드는 공개되어 모든 방문자가 볼 수 있습니다.", + "private-uploads-info": "업로드는 비공개이며 로그인 한 사용자 만 볼 수 있습니다." } \ No newline at end of file diff --git a/public/language/ko/user.json b/public/language/ko/user.json index 1d9947dbd7..83e2946fcd 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -25,15 +25,16 @@ "profile_views": "프로필 조회 수", "reputation": "등급", "bookmarks": "즐겨찾기", - "watched_categories": "Watched categories", + "watched_categories": "주시중인 카테고리", "watched": "관심있는 게시물", "ignored": "무시됨", + "default-category-watch-state": "Default category watch state", "followers": "팔로워", "following": "팔로잉", "blocks": "차단", "block_toggle": "차단 전환", "block_user": "사용자 차단", - "unblock_user": "Unblock User", + "unblock_user": "사용자 차단 해제", "aboutme": "자기소개", "signature": "서명", "birthday": "생일", @@ -48,6 +49,7 @@ "change_picture": "사진 변경", "change_username": "사용자명 변경", "change_email": "이메일 변경", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "수정", "edit-profile": "프로필 수정", "default_picture": "기본 아이콘", @@ -148,18 +150,18 @@ "info.moderation-note": "관리자 노트", "info.moderation-note.success": "관리자 노트 저장완료", "info.moderation-note.add": "노트 추가", - "sessions.description": "This page allows you to view any active sessions on this forum and revoke them if necessary. You can revoke your own session by logging out of your account.", + "sessions.description": "이 페이지에서는 이 포럼의 모든 활성 세션을 보고 필요할 경우 취소 할 수 있습니다. 계정에서 로그아웃하여 자신의 세션을 취소 할 수 있습니다.", "consent.title": "권리 동의", "consent.lead": "이 커뮤니티 포럼은 당신의 개인 정보를 수집하고 처리합니다.", "consent.intro": "We use this information strictly to personalise your experience in this community, as well as to associate the posts you make to your user account. During the registration step you were asked to provide a username and email address, you can also optionally provide additional information to complete your user profile on this website.

We retain this information for the life of your user account, and you are able to withdraw consent at any time by deleting your account. At any time you may request a copy of your contribution to this website, via your Rights & Consent page.

If you have any questions or concerns, we encourage you to reach out to this forum's administrative team.", "consent.email_intro": "가끔, 우리는 당신의 등록된 이메일로 당신에게 중요할수 있는, 새로운 활동이나 갱신사항을 알리기 위해 이메일을 보낼 수도 있습니다. 당신은 이메일로 전송받을 알림의 종류와 커뮤니티 요약본(완전 비활성화를 포함해서)의 주기를, 당신의 사용자 설정 페이지에서 커스터마이즈 할 수 있습니다.", - "consent.digest_frequency": "Unless explicitly changed in your user settings, this community delivers email digests every %1.", - "consent.digest_off": "Unless explicitly changed in your user settings, this community does not send out email digests", - "consent.received": "You have provided consent for this website to collect and process your information. No additional action is required.", - "consent.not_received": "You have not provided consent for data collection and processing. At any time this website's administration may elect to delete your account in order to become compliant with the General Data Protection Regulation.", + "consent.digest_frequency": "사용자 설정에서 변경하지 않으면 이 커뮤니티는 %1 마다 요약 이메일을 전송합니다.", + "consent.digest_off": "사용자 설정에서 명시적으로 변경하지 않는 한 이 커뮤니티는 요약 이메일을 발송하지 않습니다", + "consent.received": "사용자님은 이 웹사이트가 사용자님의 정보를 수집하고 처리하는것에 동의 했습니다. 추가 조치가 필요하지 않습니다.", + "consent.not_received": "사용자님은 데이터 수집 및 처리에 대해 동의하지 않았습니다. 이 웹 사이트는 언제든지 일반 데이터 보호 규정을 준수하기 위해 사용자님의 계정을 삭제할 수 있습니다.", "consent.give": "제공 동의", "consent.right_of_access": "당신은 접근 권한이 있습니다.", - "consent.right_of_access_description": "You have the right to access any data collected by this website upon request. You can retrieve a copy of this data by clicking the appropriate button below.", + "consent.right_of_access_description": "사용자님은 우리가 수집한 사용자님의 계정에 대한 어떠한 수집 데이터라도 기계가 읽을 수 있는 형태로 출력본을 요청할 수 있습니다. 아래에 적절한 버튼을 클릭하여 해당 처리를 수행할 수 있습니다.", "consent.right_to_rectification": "당신은 교정 권한이 있습니다.", "consent.right_to_rectification_description": "당신은 우리에게 제공된 부정확한 데이터를 교체하거나 갱신할 권한이 있습니다. 당신의 프로필을 프로필 편집을 통해 갱신할 수 있으며, 포스트의 콘텐츠 또한 언제나 편집가능합니다. 만약 불가능한 경우에는, 이 사이트의 관리 팀에게 연락해주세요.", "consent.right_to_erasure": "당신은 삭제 권한이 있습니다.", diff --git a/public/language/ko/users.json b/public/language/ko/users.json index 4ec5b8dc43..9895d4ee1a 100644 --- a/public/language/ko/users.json +++ b/public/language/ko/users.json @@ -10,7 +10,7 @@ "filter-by": "필터 기준", "online-only": "접속한 사용자", "invite": "초대", - "prompt-email": "Emails:", + "prompt-email": "이메일:", "invitation-email-sent": "%1님에게 초대 메일을 보냈습니다.", "user_list": "사용자 목록", "recent_topics": "최근 게시물", diff --git a/public/language/lt/admin/settings/user.json b/public/language/lt/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/lt/admin/settings/user.json +++ b/public/language/lt/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/lt/category.json b/public/language/lt/category.json index 18464becb7..9bd1154adf 100644 --- a/public/language/lt/category.json +++ b/public/language/lt/category.json @@ -7,14 +7,16 @@ "browsing": "naršo", "no_replies": "Nėra atsakymų", "no_new_posts": "Nėra naujų pranešimų.", - "share_this_category": "Pasidalinti šią kategoriją", "watch": "Stebėti", "ignore": "Ignoruoti", "watching": "Stebima", + "not-watching": "Not Watching", "ignoring": "Ignoruojama", - "watching.description": "Parodyti neperskaitytas temas", - "ignoring.description": "Nerodyti neskaitytų temų", - "watch.message": "Jūs dabar stebite šios kategorijos ir jos sub-kategorijų atnaujinimus", - "ignore.message": "Jūs dabar ignoruojate šios kategorijos ir jos sub-kaategorijųu atnaujinimus", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Stebimos kategorijos" } \ No newline at end of file diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json index 51892af7a8..e82ca030c2 100644 --- a/public/language/lt/notifications.json +++ b/public/language/lt/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/lt/user.json b/public/language/lt/user.json index f63b071d04..2734192872 100644 --- a/public/language/lt/user.json +++ b/public/language/lt/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Peržiūrėjo", "ignored": "Ignoruojami", + "default-category-watch-state": "Default category watch state", "followers": "Sekėjai", "following": "Seka", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Pakeisti paveikslėlį", "change_username": "Keisti vartotojo vardą", "change_email": "Keisti el. pašto adresą", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Redaguoti", "edit-profile": "Redaguoti profilį", "default_picture": "Standartinis paveikslėlis", diff --git a/public/language/lv/admin/settings/user.json b/public/language/lv/admin/settings/user.json index 9ef2438fc2..1e95e7e2ce 100644 --- a/public/language/lv/admin/settings/user.json +++ b/public/language/lv/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Sūtīt e-pastu, kad kāds raksta tematā, kuru esmu abonējis", "follow-created-topics": "Sekot tematiem, kurus esi izveidojis(-jusi)", "follow-replied-topics": "Sekot tematiem, kuros esi rakstījis(-jusi)", - "default-notification-settings": "Noklusējuma ziņojumu iestatījumi" + "default-notification-settings": "Noklusējuma ziņojumu iestatījumi", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/lv/category.json b/public/language/lv/category.json index 6c9e75ce2d..df91317f9a 100644 --- a/public/language/lv/category.json +++ b/public/language/lv/category.json @@ -7,14 +7,16 @@ "browsing": "pārlūko", "no_replies": "Nav atbilžu", "no_new_posts": "Nav jaunu rakstu.", - "share_this_category": "Dalīties ar šo kategoriju", "watch": "Novērošana", "ignore": "Ignorēt", "watching": "Novērots", + "not-watching": "Not Watching", "ignoring": "Ignorēts", - "watching.description": "Rādīt neizlasītos tematus", - "ignoring.description": "Nerādīt neizlasītos tematus", - "watch.message": "Tu tagad novēro maiņas šinī kategorijā un visās tās apakškategorijās", - "ignore.message": "Tu tagad ignorē maiņas šinī kategorijā un visās tās apakškategorijās", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Novērotās kategorijas" } \ No newline at end of file diff --git a/public/language/lv/notifications.json b/public/language/lv/notifications.json index 76ff3f1e45..12631ea58f 100644 --- a/public/language/lv/notifications.json +++ b/public/language/lv/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Kad kāds sāk Tev sekot", "notificationType_new-chat": "Kad saņemi sarunu", "notificationType_group-invite": "Kad saņemi ielūgumu pievienoties grupai", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Kad kāds tiek ievietots reģistrācijas rindā", "notificationType_post-queue": "Kad raksts tiek ievietots apstiprināšanas rindā", "notificationType_new-post-flag": "Kad raksts tiek atzīmēts", diff --git a/public/language/lv/user.json b/public/language/lv/user.json index ad1f37946d..5359dd5058 100644 --- a/public/language/lv/user.json +++ b/public/language/lv/user.json @@ -28,6 +28,7 @@ "watched_categories": "Novērotās kategorijas", "watched": "Novērotie", "ignored": "Ignorētie", + "default-category-watch-state": "Default category watch state", "followers": "Man seko", "following": "Es sekoju", "blocks": "Bloķētie", @@ -48,6 +49,7 @@ "change_picture": "Mainīt bildi", "change_username": "Mainīt lietotājvārdu", "change_email": "Mainīt e-pasta adresi", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Rediģēt", "edit-profile": "Rediģēt profilu", "default_picture": "Noklusējuma ikona", diff --git a/public/language/ms/admin/settings/user.json b/public/language/ms/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/ms/admin/settings/user.json +++ b/public/language/ms/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ms/category.json b/public/language/ms/category.json index 3b9d9455a4..9246c58458 100644 --- a/public/language/ms/category.json +++ b/public/language/ms/category.json @@ -7,14 +7,16 @@ "browsing": "melihat", "no_replies": "Tiada jawapan", "no_new_posts": "Tiada kiriman baru.", - "share_this_category": "Kongsi kategori ini", "watch": "Melihat", "ignore": "Abai", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Kategori Dilihat" } \ No newline at end of file diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json index 7346cb552b..80a877b632 100644 --- a/public/language/ms/notifications.json +++ b/public/language/ms/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/ms/user.json b/public/language/ms/user.json index fe77d4c974..fa9db38044 100644 --- a/public/language/ms/user.json +++ b/public/language/ms/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Melihat", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Pengikut", "following": "Mengikuti", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Tukar gambar", "change_username": "Tukar Nama Pengguna", "change_email": "Tukar Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Kemaskini", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/nb/admin/settings/user.json b/public/language/nb/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/nb/admin/settings/user.json +++ b/public/language/nb/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/nb/category.json b/public/language/nb/category.json index 759889274b..1cda65c591 100644 --- a/public/language/nb/category.json +++ b/public/language/nb/category.json @@ -7,14 +7,16 @@ "browsing": "leser", "no_replies": "Ingen har svart", "no_new_posts": "Ingen nye innlegg.", - "share_this_category": "Del denne kategorien", "watch": "Overvåk", "ignore": "Ignorer", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Overvåkede kategorier" } \ No newline at end of file diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index 7825e4cc85..484addbd1f 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/nb/user.json b/public/language/nb/user.json index 49c7521284..6eef33184c 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Overvåkede", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Følgere", "following": "Følger", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Bytt bilde", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Endre", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/nl/admin/advanced/database.json b/public/language/nl/admin/advanced/database.json index a3187bb795..b31a089494 100644 --- a/public/language/nl/admin/advanced/database.json +++ b/public/language/nl/admin/advanced/database.json @@ -18,16 +18,16 @@ "mongo.resident-memory": "Resident geheugen", "mongo.virtual-memory": "Virtueel geheugen", "mongo.mapped-memory": "Mapped geheugen", - "mongo.bytes-in": "Bytes In", - "mongo.bytes-out": "Bytes Out", - "mongo.num-requests": "Number of Requests", + "mongo.bytes-in": "Bytes Inkomend", + "mongo.bytes-out": "Bytes Uitgaand", + "mongo.num-requests": "Aantal requests", "mongo.raw-info": "MongoDB Raw Info", "redis": "Redis", "redis.version": "Redis versie", - "redis.keys": "Keys", - "redis.expires": "Expires", - "redis.avg-ttl": "Average TTL", + "redis.keys": "Sleutels", + "redis.expires": "Verloopt", + "redis.avg-ttl": "Gemiddelde TTL", "redis.connected-clients": "Verbonden clients", "redis.connected-slaves": "Verbonden slaves", "redis.blocked-clients": "Geblokkeerde clients", diff --git a/public/language/nl/admin/general/dashboard.json b/public/language/nl/admin/general/dashboard.json index cfec2cd754..7e99e1f24b 100644 --- a/public/language/nl/admin/general/dashboard.json +++ b/public/language/nl/admin/general/dashboard.json @@ -49,7 +49,7 @@ "active-users.users": "Users", "active-users.guests": "Guests", "active-users.total": "Total", - "active-users.connections": "Connections", + "active-users.connections": "Connecties", "anonymous-registered-users": "Anonymous vs Registered Users", "anonymous": "Anonymous", @@ -71,6 +71,6 @@ "graphs.unique-visitors": "Unique Visitors", "graphs.registered-users": "Registered Users", "graphs.anonymous-users": "Anonymous Users", - "last-restarted-by": "Last restarted by", + "last-restarted-by": "Laatst herstart door", "no-users-browsing": "No users browsing" } diff --git a/public/language/nl/admin/manage/categories.json b/public/language/nl/admin/manage/categories.json index c14eadea0c..a48f5a9301 100644 --- a/public/language/nl/admin/manage/categories.json +++ b/public/language/nl/admin/manage/categories.json @@ -62,7 +62,7 @@ "alert.copy-success": "Settings Copied!", "alert.set-parent-category": "Set Parent Category", "alert.updated": "Updated Categories", - "alert.updated-success": "Category IDs %1 successfully updated.", + "alert.updated-success": "Category IDs %1 zijn succesvol geüpdatet.", "alert.upload-image": "Upload category image", "alert.find-user": "Find a User", "alert.user-search": "Search for a user here...", diff --git a/public/language/nl/admin/settings/general.json b/public/language/nl/admin/settings/general.json index 948123f7cb..1977c9678a 100644 --- a/public/language/nl/admin/settings/general.json +++ b/public/language/nl/admin/settings/general.json @@ -1,33 +1,33 @@ { - "site-settings": "Site Settings", - "title": "Site Title", + "site-settings": "Site Instellingen", + "title": "Site Titel", "title.url": "URL", - "title.url-placeholder": "The URL of the site title", - "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index.", - "title.name": "Your Community Name", - "title.show-in-header": "Show Site Title in Header", - "browser-title": "Browser Title", - "browser-title-help": "If no browser title is specified, the site title will be used", - "title-layout": "Title Layout", - "title-layout-help": "Define how the browser title will be structured ie. {pageTitle} | {browserTitle}", - "description.placeholder": "A short description about your community", - "description": "Site Description", - "keywords": "Site Keywords", - "keywords-placeholder": "Keywords describing your community, comma-separated", + "title.url-placeholder": "De URL van de site titel", + "title.url-help": "Wanneer de titel word aangeklikt stuur gebruikers naar dit adress. Is het leeg gelaten dan worden gebruikers naar de forum hoofdpagina gestuurd.", + "title.name": "Jouw Communiy Naam", + "title.show-in-header": "Toon Site Titel in Header", + "browser-title": "Browser Titel", + "browser-title-help": "Als geen browser titel is gespecificeerd dan word de site titel gebruikt", + "title-layout": "Titel Lay-out", + "title-layout-help": "Defineer hoe de browser titel gestructureerd word. bijv: {paginaTitel} | {browserTitel}", + "description.placeholder": "Een korte beschrijving van uw gemeenschap", + "description": "Site Beschrijving", + "keywords": "Site Trefwoorden", + "keywords-placeholder": "Trefwoorden die uw community beschrijven, kommagescheiden", "logo": "Site Logo", - "logo.image": "Image", - "logo.image-placeholder": "Path to a logo to display on forum header", - "logo.upload": "Upload", + "logo.image": "Afbeelding", + "logo.image-placeholder": "Pad naar een logo om te tonen op de forum header", + "logo.upload": "Uploaden", "logo.url": "URL", - "logo.url-placeholder": "The URL of the site logo", - "logo.url-help": "When the logo is clicked, send users to this address. If left blank, user will be sent to the forum index.", - "logo.alt-text": "Alt Text", - "log.alt-text-placeholder": "Alternative text for accessibility", - "favicon": "Favicon", - "favicon.upload": "Upload", - "touch-icon": "Homescreen/Touch Icon", - "touch-icon.upload": "Upload", - "touch-icon.help": "Recommended size and format: 192x192, PNG format only. If no touch icon is specified, NodeBB will fall back to using the favicon.", + "logo.url-placeholder": "De URL van de site logo", + "logo.url-help": "Wanneer het logo aangeklikt is stuur gebruikers naar dit adress. Is het leeg gelaten dan worden gebruikers naar de forum hoofdpagina gestuurd.", + "logo.alt-text": "Alt Tekst", + "log.alt-text-placeholder": "Alternatieve tekst voor toegankelijkheid", + "favicon": "Favoicon", + "favicon.upload": "Uploaden", + "touch-icon": "Startscherm / Aanraakpictogram", + "touch-icon.upload": "Uploaden", + "touch-icon.help": "Aangeraden grootte en formaat: 192x192, alleen PNG formaat. Als er geen touch icoon is gespecificeerd zal NodeBB terugvallen op het favicon.", "outgoing-links": "Outgoing Links", "outgoing-links.warning-page": "Use Outgoing Links Warning Page", "search-default-sort-by": "Search default sort by", diff --git a/public/language/nl/admin/settings/user.json b/public/language/nl/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/nl/admin/settings/user.json +++ b/public/language/nl/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/nl/category.json b/public/language/nl/category.json index 15a78d7d92..c330b224f0 100644 --- a/public/language/nl/category.json +++ b/public/language/nl/category.json @@ -7,14 +7,16 @@ "browsing": "browsing", "no_replies": "Niemand heeft gereageerd", "no_new_posts": "Geen nieuwe berichten.", - "share_this_category": "Deel deze categorie", "watch": "Volgen", "ignore": "Negeren", "watching": "Volgend", + "not-watching": "Niet gevolgd", "ignoring": "Negerend", - "watching.description": "Toon ongelezen onderwerpen", - "ignoring.description": "Toon geen onderwerpen onder ongelezen onderwerpen", - "watch.message": "Van deze categorie en alle sub-categorieën worden nu meldingen ontvangen ", - "ignore.message": " Er worden geen meldingen van deze categorie en alle sub-categorieën ontvangen ", + "watching.description": "Toon ongelezen en recente onderwerpen", + "not-watching.description": "Toon geen ongelezen onderwerpen, toon wel recente onderwerpen", + "ignoring.description": "Toon geen onderwerpen onder ongelezen en recent", + "watching.message": "Van deze categorie en alle sub-categorieën worden nu meldingen ontvangen ", + "notwatching.message": "Deze categorie en alle sub-categorieën worden niet gevolgd", + "ignoring.message": " Er worden geen meldingen van deze categorie en alle sub-categorieën ontvangen ", "watched-categories": "Categorieën die bekeken zijn." } \ No newline at end of file diff --git a/public/language/nl/email.json b/public/language/nl/email.json index 78b7b6c1e8..5020f76c72 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -1,6 +1,6 @@ { - "test-email.subject": "Test Email", - "password-reset-requested": "Password Reset Requested!", + "test-email.subject": "Test e-mail", + "password-reset-requested": "Wachtwoord Reset Aangevraagd!", "welcome-to": "Welkom bij %1", "invite": "Uitnodiging van %1 ", "greeting_no_name": "Hallo", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index b45124a929..9a3ac6922e 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -120,7 +120,7 @@ "chat-edit-duration-expired": "Het is slechts toegestaan om binnen %1 seconde(n) na plaatsen van het chat bericht, deze te bewerken.", "chat-delete-duration-expired": "Het is slechts toegestaan om binnen %1 seconde(n) na plaatsen van het chat bericht, deze te verwijderen.", "chat-deleted-already": "Dit chat bericht is al verwijderd.", - "chat-restored-already": "This chat message has already been restored.", + "chat-restored-already": "Dit chat bericht is al hersteld.", "already-voting-for-this-post": "Je hebt al gestemd voor deze post.", "reputation-system-disabled": "Reputatie systeem is uitgeschakeld.", "downvoting-disabled": "Negatief stemmen is uitgeschakeld", @@ -153,8 +153,8 @@ "cant-move-to-same-topic": "Een bericht kan niet naar hetzelfde onderwerp worden verplaatst!", "cannot-block-self": "Je kan jezelf niet blokkeren!", "cannot-block-privileged": "Je kan geen administrators of global moderators blokkeren", - "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", + "cannot-block-guest": "Gasten kunnen geen andere gebruikers blokkeren", + "already-blocked": "Deze gebruiker is al geblokkeerd", + "already-unblocked": "Deze gebruiker is al gedeblokkeerd", "no-connection": "Er lijkt een probleem te zijn met je internetverbinding" } \ No newline at end of file diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index 61ad176be9..a03b742f16 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -8,8 +8,8 @@ "outgoing_link_message": "U verlaat nu %1", "continue_to": "Door naar %1", "return_to": "Terug naar %1", - "new_notification": "You have a new notification", - "you_have_unread_notifications": "Je hebt nieuwe notificaties.", + "new_notification": "U heeft een nieuwe notificatie", + "you_have_unread_notifications": "U heeft ongelezen notificaties.", "all": "Alles", "topics": "Onderwerpen", "replies": "Antwoorden", @@ -56,6 +56,7 @@ "notificationType_follow": "Als iemand begint met jou te volgen", "notificationType_new-chat": "Als je een chat-bericht ontvangt", "notificationType_group-invite": "Als je een uitnodiging voor een groep ontvangt", + "notificationType_group-request-membership": "Als iemand vraagt om lid te worden van een groep waarvan je eigenaar bent", "notificationType_new-register": "Als iemand wordt toegevoegd aan een registratiewachtrij", "notificationType_post-queue": "Als een bericht aan de wachtrij wordt toegevoegd", "notificationType_new-post-flag": "Als een bericht wordt gevlagd", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index f7ab6390dc..76409927f1 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -28,6 +28,7 @@ "watched_categories": "Gevolgde categorieën", "watched": "Bekeken", "ignored": "Genegeerd", + "default-category-watch-state": "Standaard bekeken status van categorie", "followers": "Volgers", "following": "Volgend", "blocks": "Blokkeringen", @@ -48,6 +49,7 @@ "change_picture": "Bewerk afbeelding", "change_username": "Wijzig gebruikersnaam", "change_email": "Wijzig email", + "email_same_as_password": "Voer uw huidige wachtwoord in om door te gaan – u heeft uw nieuwe e-mail weer ingevoered", "edit": "Bewerken", "edit-profile": "Profiel wijzigen", "default_picture": "Standaard icoon", diff --git a/public/language/pl/admin/settings/user.json b/public/language/pl/admin/settings/user.json index 718d668ec7..ae83a9df44 100644 --- a/public/language/pl/admin/settings/user.json +++ b/public/language/pl/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Wyślij wiadomość email, kiedy w tematach, które subskrybuję, pojawią się odpowiedzi", "follow-created-topics": "Obserwuj tematy, które stworzyłeś", "follow-replied-topics": "Obserwuj tematy, w których się wypowiedziałeś ", - "default-notification-settings": "Domyślne ustawienia powiadomień" + "default-notification-settings": "Domyślne ustawienia powiadomień", + "categoryWatchState": "Domyślny stan oglądania kategorii", + "categoryWatchState.watching": "Obserwowane", + "categoryWatchState.notwatching": "Nie obserwowane", + "categoryWatchState.ignoring": "Ignorowane" } \ No newline at end of file diff --git a/public/language/pl/category.json b/public/language/pl/category.json index 482e42f43a..14d23dca3a 100644 --- a/public/language/pl/category.json +++ b/public/language/pl/category.json @@ -7,14 +7,16 @@ "browsing": "przegląda", "no_replies": "Nikt jeszcze nie odpowiedział", "no_new_posts": "Brak nowych postów.", - "share_this_category": "Udostępnij tę kategorię", "watch": "Obserwuj", "ignore": "Ignoruj", "watching": "Obserwowane", + "not-watching": "Nie obserwowane", "ignoring": "Ignorowane", - "watching.description": "Pokazuj tematy w nieprzeczytanych", - "ignoring.description": "Nie pokazuj tematów w nieprzeczytanych", - "watch.message": "Od teraz obserwujesz tę kategorię i wszystkie podkategorie.", - "ignore.message": "Od teraz ignorujesz tę kategorię i wszystkie podkategorie.", + "watching.description": "Pokaż tematy w nieprzeczytanych i najnowszych", + "not-watching.description": "Nie pokazuj tematów w nieprzeczytanym, pokaż je w ostatnim czasie", + "ignoring.description": "Nie pokazuj tematów w nieprzeczytanych i najnowszych", + "watching.message": "Obserwujesz teraz aktualizacje tej kategorii i wszystkie podkategorie", + "notwatching.message": "Obserwujesz teraz aktualizacje tej kategorii i wszystkie podkategorie", + "ignoring.message": "Obserwujesz teraz aktualizacje tej kategorii i wszystkie podkategorie", "watched-categories": "Obserwowane kategorie" } \ No newline at end of file diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json index b0bc4c4e72..52fdbd5052 100644 --- a/public/language/pl/notifications.json +++ b/public/language/pl/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Kiedy ktoś zacznie Cię obserwować", "notificationType_new-chat": "Kiedy otrzymasz wiadomość na czacie", "notificationType_group-invite": "Kiedy otrzymasz grupowe zaproszenie", + "notificationType_group-request-membership": "Kiedy ktoś prosi o dołączenie do grupy, którą posiadasz", "notificationType_new-register": "Kiedy ktoś zostaje dodany do kolejki rejestracyjnej", "notificationType_post-queue": "Kiedy nowy post jest kolejkowany", "notificationType_new-post-flag": "Kiedy post zostanie oflagowany", diff --git a/public/language/pl/user.json b/public/language/pl/user.json index 160ac88452..6b0d91a284 100644 --- a/public/language/pl/user.json +++ b/public/language/pl/user.json @@ -28,6 +28,7 @@ "watched_categories": "Obserwowane kategorie", "watched": "Obserwowane", "ignored": "Zignorowane", + "default-category-watch-state": "Domyślny stan oglądania kategorii", "followers": "Obserwujący", "following": "Obserwowani", "blocks": "Blokady", @@ -48,6 +49,7 @@ "change_picture": "Zmień zdjęcie", "change_username": "Zmień nazwę użytkownika", "change_email": "Zmień adres e-mail", + "email_same_as_password": "Wprowadź bieżące hasło, aby kontynuować – ponownie wprowadziłeś nową wiadomość e-mail", "edit": "Edytuj", "edit-profile": "Edytuj profil", "default_picture": "Domyślna ikona", diff --git a/public/language/pt-BR/admin/settings/user.json b/public/language/pt-BR/admin/settings/user.json index 0f3f449006..f154d884e7 100644 --- a/public/language/pt-BR/admin/settings/user.json +++ b/public/language/pt-BR/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Enviar um email quando respostas forem dadas à tópicos que estou inscrito", "follow-created-topics": "Seguir tópicos que você criar", "follow-replied-topics": "Seguir os tópicos que você responder", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/pt-BR/category.json b/public/language/pt-BR/category.json index 2f925a0e37..6cc5f96f88 100644 --- a/public/language/pt-BR/category.json +++ b/public/language/pt-BR/category.json @@ -7,14 +7,16 @@ "browsing": "navegando", "no_replies": "Ninguém respondeu", "no_new_posts": "Nenhum post novo.", - "share_this_category": "Compartilhar esta categoria", "watch": "Acompanhar", "ignore": "Ignorar", "watching": "Seguindo", + "not-watching": "Not Watching", "ignoring": "Ignorando", - "watching.description": "Mostrar tópicos em não-lido", - "ignoring.description": "Não mostrar tópicos em não-lido", - "watch.message": "Agora você está seguindo as atualizações desta categoria e de todas as subcategorias", - "ignore.message": "Agora você está ignorando as atualizações desta categoria e de todas as suas subcategorias", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categorias acompanhadas" } \ No newline at end of file diff --git a/public/language/pt-BR/notifications.json b/public/language/pt-BR/notifications.json index d415a911ab..9685b6656f 100644 --- a/public/language/pt-BR/notifications.json +++ b/public/language/pt-BR/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Quando alguém começar a seguir você", "notificationType_new-chat": "Quando você receber uma mensagem de chat", "notificationType_group-invite": "Quando você receber um convite para um grupo", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Quando alguém for adicionado a fila de registro", "notificationType_post-queue": "Quando um novo post entrar na fila", "notificationType_new-post-flag": "Quando um post for marcado", diff --git a/public/language/pt-BR/user.json b/public/language/pt-BR/user.json index fb8e71069e..e7108ed96e 100644 --- a/public/language/pt-BR/user.json +++ b/public/language/pt-BR/user.json @@ -28,6 +28,7 @@ "watched_categories": "Categorias acompanhadas", "watched": "Acompanhado", "ignored": "Ignorado", + "default-category-watch-state": "Default category watch state", "followers": "Seguidores", "following": "Seguindo", "blocks": "Bloqueados", @@ -48,6 +49,7 @@ "change_picture": "Alterar Foto", "change_username": "Mudar nome de usuário", "change_email": "Mudar email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Editar", "edit-profile": "Editar Perfil", "default_picture": "Ícone Padrão", diff --git a/public/language/pt-PT/admin/extend/plugins.json b/public/language/pt-PT/admin/extend/plugins.json index 2076169c40..a26ce33aff 100644 --- a/public/language/pt-PT/admin/extend/plugins.json +++ b/public/language/pt-PT/admin/extend/plugins.json @@ -23,7 +23,7 @@ "plugin-item.install": "Instalar", "plugin-item.uninstall": "Desinstalar", "plugin-item.settings": "Definições", - "plugin-item.installed": "Instalado", + "plugin-item.installed": "Versão Instalada", "plugin-item.latest": "Última Versão", "plugin-item.upgrade": "Atualizar", "plugin-item.more-info": "Para mais informações:", @@ -44,7 +44,7 @@ "alert.package-manager-unreachable": "

NodeBB could not reach the package manager, an upgrade is not suggested at this time.

", "alert.incompatible": "

Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.

", "alert.possibly-incompatible": "

No Compatibility Information Found

This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.

In the event that NodeBB cannot boot properly:

$ ./nodebb reset plugin=\"%1\"

Continue installation of latest version of this plugin?

", - "alert.reorder": "Plugins Re-ordered", + "alert.reorder": "Plugins reordenados", "alert.reorder-success": "Por favor reconstrói e reinicia o teu NodeBB para completar totalmente o processo.", "license.title": "Plugin License Information", diff --git a/public/language/pt-PT/admin/manage/ip-blacklist.json b/public/language/pt-PT/admin/manage/ip-blacklist.json index 20ef000e5f..cf99ea2c9c 100644 --- a/public/language/pt-PT/admin/manage/ip-blacklist.json +++ b/public/language/pt-PT/admin/manage/ip-blacklist.json @@ -1,9 +1,9 @@ { - "lead": "Configure your IP blacklist here.", + "lead": "Configura a tua lista negra de IPs aqui.", "description": "Occasionally, a user account ban is not enough of a deterrant. Other times, restricting access to the forum to a specific IP or a range of IPs is the best way to protect a forum. In these scenarios, you can add troublesome IP addresses or entire CIDR blocks to this blacklist, and they will be prevented from logging in to or registering a new account.", "active-rules": "Regras Ativas", - "validate": "Validate Blacklist", - "apply": "Apply Blacklist", + "validate": "Validar Lista Negra", + "apply": "Aplicar Lista Negra", "hints": "Dicas de Sintaxe", "hint-1": "Define a single IP addresses per line. You can add IP blocks as long as they follow the CIDR format (e.g. 192.168.100.0/22).", "hint-2": "Podes adicionar comentários começando linhas com o símbolo #.", @@ -11,9 +11,9 @@ "validate.x-valid": "%1 out of %2 rule(s) valid.", "validate.x-invalid": "The following %1 rules are invalid:", - "alerts.applied-success": "Blacklist Applied", + "alerts.applied-success": "Lista Negra Aplicada", "analytics.blacklist-hourly": "Figure 1 – Blacklist hits per hour", "analytics.blacklist-daily": "Figure 2 – Blacklist hits per day", - "ip-banned": "IP banned" + "ip-banned": "IP banido" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/manage/tags.json b/public/language/pt-PT/admin/manage/tags.json index c90f7baf34..034cf190e0 100644 --- a/public/language/pt-PT/admin/manage/tags.json +++ b/public/language/pt-PT/admin/manage/tags.json @@ -1,5 +1,5 @@ { - "none": "O teu fórum não tem nenhum tópico com marcadores ainda.", + "none": "O teu fórum ainda não tem nenhum tópico com marcadores.", "bg-color": "Cor de Fundo", "text-color": "Cor do Texto", "create-modify": "Criar e Modificar Marcadores", diff --git a/public/language/pt-PT/admin/menu.json b/public/language/pt-PT/admin/menu.json index ca6ccc2be4..d2eea76956 100644 --- a/public/language/pt-PT/admin/menu.json +++ b/public/language/pt-PT/admin/menu.json @@ -71,12 +71,12 @@ "search.placeholder": "Procurar por definições", "search.no-results": "Sem resultados...", - "search.search-forum": "Search the forum for ", + "search.search-forum": "Procurar no fórum por ", "search.keep-typing": "Digita mais para veres resultados...", "search.start-typing": "Comece a digitar para ver resultados...", "connection-lost": "A conexão a %1 foi perdida, tentando reconectar...", "alerts.version": "A executar NodeBB v%1", - "alerts.upgrade": "Upgrade to v%1" + "alerts.upgrade": "Atualiza para a v%1" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/settings/advanced.json b/public/language/pt-PT/admin/settings/advanced.json index f989898d05..01565b0c35 100644 --- a/public/language/pt-PT/admin/settings/advanced.json +++ b/public/language/pt-PT/admin/settings/advanced.json @@ -1,7 +1,7 @@ { - "maintenance-mode": "Maintenance Mode", + "maintenance-mode": "Modo de Manutenção", "maintenance-mode.help": "When the forum is in maintenance mode, all requests will be redirected to a static holding page. Administrators are exempt from this redirection, and are able to access the site normally.", - "maintenance-mode.message": "Maintenance Message", + "maintenance-mode.message": "Mensagem de Manutenção", "headers": "Headers", "headers.allow-from": "Set ALLOW-FROM to Place NodeBB in an iFrame", "headers.powered-by": "Customise the \"Powered By\" header sent by NodeBB", diff --git a/public/language/pt-PT/admin/settings/post.json b/public/language/pt-PT/admin/settings/post.json index 08c8b83f97..7d5bd452d9 100644 --- a/public/language/pt-PT/admin/settings/post.json +++ b/public/language/pt-PT/admin/settings/post.json @@ -3,14 +3,14 @@ "sorting.post-default": "Default Post Sorting", "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", - "sorting.most-votes": "Most Votes", + "sorting.most-votes": "Mais votos", "sorting.most-posts": "Mais publicações", "sorting.topic-default": "Default Topic Sorting", "length": "Post Length", "restrictions": "Posting Restrictions", - "restrictions-new": "New User Restrictions", + "restrictions-new": "Restrições para Novos Utilizadores", "restrictions.post-queue": "Ativar publicações em fila de espera", - "restrictions-new.post-queue": "Enable new user restrictions", + "restrictions-new.post-queue": "Ativar restrições para novos utilizadores", "restrictions.post-queue-help": "Ativar publicações em fila de espera vai colocar as publicações de novos utilizadores numa fila de espera para serem aprovadas.", "restrictions-new.post-queue-help": "Enabling new user restrictions will set restrictions on posts created by new users.", "restrictions.seconds-between": "Seconds between posts", diff --git a/public/language/pt-PT/admin/settings/reputation.json b/public/language/pt-PT/admin/settings/reputation.json index 0ee7f0001d..9ed5e150e9 100644 --- a/public/language/pt-PT/admin/settings/reputation.json +++ b/public/language/pt-PT/admin/settings/reputation.json @@ -1,14 +1,14 @@ { "reputation": "Reputation Settings", "disable": "Disable Reputation System", - "disable-down-voting": "Disable Down Voting", + "disable-down-voting": "Desativar Votos Negativos", "votes-are-public": "Todos os Votos São Públicos", "thresholds": "Activity Thresholds", - "min-rep-downvote": "Minimum reputation to downvote posts", - "min-rep-flag": "Mínimo de reputação para denunciar publicações", - "min-rep-website": "Minimum reputation to add \"Website\" to user profile", - "min-rep-aboutme": "Minimum reputation to add \"About me\" to user profile", - "min-rep-signature": "Minimum reputation to add \"Signature\" to user profile", + "min-rep-downvote": "Reputação mínima para votar negativamente em publicações", + "min-rep-flag": "Reputação mínima para denunciar publicações", + "min-rep-website": "Reputação mínima para adicionar \"Website\" ao perfil do utilizador", + "min-rep-aboutme": "Reputação mínima para adicionar \"Sobre mim\" ao perfil do utilizador", + "min-rep-signature": "Reputação mínima para adicionar \"Assinatura\" ao perfil do utilizador", "min-rep-profile-picture": "Reputação mínima para adicionar \"Fotografia de Perfil\" ao perfil do utilizador", "min-rep-cover-picture": "Reputação mínima para adicionar \"Fotografia de Capa\" ao perfil do utilizador" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/settings/sockets.json b/public/language/pt-PT/admin/settings/sockets.json index d04ee42fcf..f6445f5191 100644 --- a/public/language/pt-PT/admin/settings/sockets.json +++ b/public/language/pt-PT/admin/settings/sockets.json @@ -1,6 +1,6 @@ { "reconnection": "Reconnection Settings", "max-attempts": "Max Reconnection Attempts", - "default-placeholder": "Default: %1", + "default-placeholder": "Predefinição: %1", "delay": "Reconnection Delay" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/settings/user.json b/public/language/pt-PT/admin/settings/user.json index 849e54fa8a..625d910ec8 100644 --- a/public/language/pt-PT/admin/settings/user.json +++ b/public/language/pt-PT/admin/settings/user.json @@ -17,7 +17,7 @@ "user-info-private": "Hide user list and data from guests", "hide-fullname": "Esconder o nome completo dos utilizadores", "hide-email": "Esconder o e-mail dos utilizadores", - "themes": "Themes", + "themes": "Temas", "disable-user-skins": "Impedir utilizadores de escolherem uma máscara personalizada", "account-protection": "Account Protection", "admin-relogin-duration": "Admin relogin duration (minutes)", @@ -51,7 +51,7 @@ "max-username-length": "Comprimento Máximo do Nome de Utilizador", "min-password-length": "Minimum Password Length", "min-password-strength": "Minimum Password Strength", - "max-about-me-length": "Maximum About Me Length", + "max-about-me-length": "Comprimento Máximo do \"Sobre Mim\"", "terms-of-use": "Forum Terms of Use (Leave blank to disable)", "user-search": "User Search", "user-search-results-per-page": "Number of results to display", @@ -66,9 +66,13 @@ "digest-freq.daily": "Daily", "digest-freq.weekly": "Weekly", "digest-freq.monthly": "Monthly", - "email-chat-notifs": "Send an email if a new chat message arrives and I am not online", + "email-chat-notifs": "Enviar um e-mail se receber uma nova mensagem e não estiver online", "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/pt-PT/category.json b/public/language/pt-PT/category.json index 542f79c693..bfc4e394e7 100644 --- a/public/language/pt-PT/category.json +++ b/public/language/pt-PT/category.json @@ -5,16 +5,18 @@ "guest-login-post": "Inicia sessão para publicar algo", "no_topics": "Não existe nenhum tópico nesta categoria.
Que tal seres o primeiro a publicar aqui?", "browsing": "navegação", - "no_replies": "Sem respostas", + "no_replies": "Ainda sem respostas", "no_new_posts": "Não existem publicações novas.", - "share_this_category": "Partilhar esta categoria", - "watch": "Seguir", + "watch": "Subscrever", "ignore": "Ignorar", - "watching": "Seguir", - "ignoring": "Ignorar", - "watching.description": "Mostrar tópicos em não lido", - "ignoring.description": "Não mostrar tópicos em não lido", - "watch.message": "Estás agora a ver atualizações desta categoria e todas as suas subcategorias", - "ignore.message": "Estás agora a ignorar todas as atualizações desta categoria e todas as suas subcategorias", + "watching": "A seguir", + "not-watching": "Não seguir", + "ignoring": "A ignorar", + "watching.description": "Mostrar tópicos em \"não lidos\" e \"recentes\"", + "not-watching.description": "Não mostrar tópicos em \"não lidos\", mostrar em \"recentes\"", + "ignoring.description": "Não mostrar tópicos em \"não lidos\" e \"recentes\"", + "watching.message": "Estás agora a seguir todas as atualizações desta categoria e de todas as suas subcategorias", + "notwatching.message": "Não estás a seguir atualizações desta categoria e de todas as suas subcategorias", + "ignoring.message": "Estás agora a ignorar todas as atualizações desta categoria e de todas as suas subcategorias", "watched-categories": "Categorias subscritas" } \ No newline at end of file diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index 01ab8ae01e..94d39e0acc 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -107,7 +107,7 @@ "invalid-file": "Ficheiro inválido", "uploads-are-disabled": "Os carregamentos estão desativados", "signature-too-long": "Desculpa, a tua assinatura não pode ser superior a %1 caracter(es).", - "about-me-too-long": "Desculpa, o teu \"sobre ti\" não pode ser superior a %1 caracter(es).", + "about-me-too-long": "Desculpa, o teu \"sobre mim\" não pode ser superior a %1 caracter(es).", "cant-chat-with-yourself": "Não podes conversar contigo mesmo!", "chat-restricted": "Este utilizador colocou restrições sobre as suas mensagens de chat. Ele deve primeiro seguir-te antes que possas conversar com ele", "chat-disabled": "Sistema de conversas desativado", @@ -123,16 +123,16 @@ "chat-restored-already": "This chat message has already been restored.", "already-voting-for-this-post": "Já votaste nesta publicação.", "reputation-system-disabled": "Sistema de reputação desativado.", - "downvoting-disabled": "Voto negativo desativado", + "downvoting-disabled": "Os votos negativos estão desativados", "not-enough-reputation-to-downvote": "Não tens reputação suficiente para atribuir um voto negativo a esta publicação", "not-enough-reputation-to-flag": "Não tens reputação suficiente para denunciar esta publicação", - "not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website", - "not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me", - "not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature", + "not-enough-reputation-min-rep-website": "Não tens reputação suficiente para adicionar um website", + "not-enough-reputation-min-rep-aboutme": "Não tens reputação suficiente para escreveres sobre ti", + "not-enough-reputation-min-rep-signature": "Não tens reputação suficiente para adicionar uma assinatura", "not-enough-reputation-min-rep-profile-picture": "Não tens reputação suficiente para adicionar uma fotografia de perfil", "not-enough-reputation-min-rep-cover-picture": "Não tens reputação suficiente para adicionar uma fotografia de capa", "already-flagged": "Já denunciaste esta publicação antes", - "self-vote": "You cannot vote on your own post", + "self-vote": "Não podes votar na tua própria publicação", "reload-failed": "NodeBB encontrou um erro enquanto recarregava: \"%1\". NodeBB irá continuar a servir os ativos existentes do lado do utilizador. No entanto deverias desfazer o que fizeste mesmo antes de teres voltado a recarregar.", "registration-error": "Erro de registro", "parse-error": "Ocorreu um erro enquanto analisávamos a resposta do servidor", @@ -141,7 +141,7 @@ "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "sso-multiple-association": "You cannot associate multiple accounts from this service to your NodeBB account. Please dissociate your existing account and try again.", "invite-maximum-met": "Convidaste o máximo de pessoas (%1 em %2).", - "no-session-found": "Não foram encontradas sessões iniciadas!", + "no-session-found": "Não foram encontradas sessões ativas!", "not-in-room": "Utilizador não se encontra na sala", "no-users-in-room": "Não existem utilizadores nesta sala", "cant-kick-self": "Não te podes expulsar a ti próprio do grupo", @@ -154,7 +154,7 @@ "cannot-block-self": "Não podes bloquear-te a ti próprio!", "cannot-block-privileged": "Não podes bloquear administradores ou moderadores globais", "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", + "already-blocked": "Este utilizador já está bloqueado", + "already-unblocked": "Este utilizador já está desbloqueado", "no-connection": "Parece haver um problema com a tua conexão à Internet" } \ No newline at end of file diff --git a/public/language/pt-PT/flags.json b/public/language/pt-PT/flags.json index 84e94db522..57f97ca6c1 100644 --- a/public/language/pt-PT/flags.json +++ b/public/language/pt-PT/flags.json @@ -4,7 +4,7 @@ "reported-at": "Denunciado em", "description": "Descrição", "no-flags": "Fantástico! Não foram encontradas denúncias.", - "assignee": "Assignee", + "assignee": "Responsável", "update": "Atualizar", "updated": "Atualizado", "target-purged": "The content this flag referred to has been purged and is no longer available.", @@ -20,7 +20,7 @@ "filter-type-post": "Publicação", "filter-type-user": "Utilizador", "filter-state": "Estado", - "filter-assignee": "Assignee UID", + "filter-assignee": "UID do responsável", "filter-cid": "Categoria", "filter-quick-mine": "Atribuído a mim", "filter-cid-all": "Todas as categorias", diff --git a/public/language/pt-PT/global.json b/public/language/pt-PT/global.json index 53c85eba80..63d969ec1f 100644 --- a/public/language/pt-PT/global.json +++ b/public/language/pt-PT/global.json @@ -6,7 +6,7 @@ "403.message": "Parece que encontraste uma página à qual não tens acesso.", "403.login": "Talvez devesses tentar iniciar sessão?", "404.title": "Não encontrado", - "404.message": "Parece que encontraste uma página que não existe. Regressa para a página principal.", + "404.message": "Parece que encontraste uma página que não existe. Regressa à página principal.", "500.title": "Erro interno.", "500.message": "Oops! Parece que algo correu mal!", "400.title": "O pedido não correu bem.", @@ -54,9 +54,9 @@ "posts": "Publicações", "best": "Melhores", "votes": "Votos", - "upvoters": "Votantes a favor", + "upvoters": "Votos positivos", "upvoted": "Votado favoravelmente", - "downvoters": "Votantes contra", + "downvoters": "Votos negativos", "downvoted": "Votado negativamente", "views": "Visualizações", "reputation": "Reputação", @@ -93,7 +93,7 @@ "unfollow": "Deixar de seguir", "delete_all": "Apagar tudo", "map": "Mapa", - "sessions": "Sessões Iniciadas", + "sessions": "Sessões ativas", "ip_address": "Endereço IP", "enter_page_number": "Introduzir número da página", "upload_file": "Enviar ficheiro", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index f45454efd3..699868bf9c 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -23,12 +23,12 @@ "chat.retrieving-users": "A recuperar utilizadores...", "chat.manage-room": "Gerir sala de conversa", "chat.add-user-help": "Encontra utilizadores aqui. Quando selecionado, o utilizador vai ser adicionado à conversa. O novo utilizador não conseguirá ver mensagens que foram enviadas antes de ele entrar na sala. Apenas os donos das salas () poderão remover participantes das salas de conversa", - "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.confirm-chat-with-dnd-user": "Este utilizador definiu o seu estado como \"não perturbar\". Mesmo assim pretendes conversar com ele?", "chat.rename-room": "Renomear esta sala", "chat.rename-placeholder": "Insere o nome da conversa aqui", "chat.rename-help": "O nome desta conversa vai ser visualizada por todos os participantes desta sala.", - "chat.leave": "Abandonar conversa", - "chat.leave-prompt": "Are you sure you wish to leave this chat?", + "chat.leave": "Sair da conversa", + "chat.leave-prompt": "Tens a certeza que pretendes sair desta conversa?", "chat.leave-help": "Deixar esta sala vai te remover de receber futuras mensagens importantes nesta conversa. Se fores novamente adicionado no futuro, não conseguirás ver nenhum histórico das conversas de antes da tua re-adesão.", "chat.in-room": "Participantes nesta sala", "chat.kick": "Expulsar", diff --git a/public/language/pt-PT/notifications.json b/public/language/pt-PT/notifications.json index 03c99f518e..9ce82f98d7 100644 --- a/public/language/pt-PT/notifications.json +++ b/public/language/pt-PT/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Quando alguém começa a seguir-te", "notificationType_new-chat": "Quando recebes uma mensagem numa conversa", "notificationType_group-invite": "Quando recebes um convite para um grupo", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Quando alguém é adicionado à fila de espera de registo", "notificationType_post-queue": "Quando uma nova publicação está à espera de aprovação", "notificationType_new-post-flag": "Quando uma publicação é denunciada", diff --git a/public/language/pt-PT/pages.json b/public/language/pt-PT/pages.json index ce38a372c0..7d68622db7 100644 --- a/public/language/pt-PT/pages.json +++ b/public/language/pt-PT/pages.json @@ -55,9 +55,9 @@ "account/best": "Melhores publicações feitas por %1", "account/blocks": "Utilizadores bloqueados para %1", "account/uploads": "Carregamentos feitos por %1", - "account/sessions": "Login Sessions", + "account/sessions": "Sessões ativas", "confirm": "E-mail confirmado", - "maintenance.text": "%1 está atualmente sobre manutenção. Por favor, volta noutra altura.", + "maintenance.text": "%1 está atualmente sobre manutenção.
Por favor, volta noutra altura.", "maintenance.messageIntro": "Adicionalmente, o administrador deixou esta mensagem:", "throttled.text": "%1 não está disponível de momento devido a um carregamento excesso. Por favor, volta mais tarde." } \ No newline at end of file diff --git a/public/language/pt-PT/search.json b/public/language/pt-PT/search.json index 12cc79ece8..fb78ef1d25 100644 --- a/public/language/pt-PT/search.json +++ b/public/language/pt-PT/search.json @@ -6,8 +6,8 @@ "titles": "Títulos", "titles-posts": "Títulos e Publicações", "match-words": "Corresponder palavras", - "all": "All", - "any": "Any", + "all": "Todas", + "any": "Qualquer", "posted-by": "Publicado por", "in-categories": "Nas Categorias", "search-child-categories": "Procurar categorias infantis", diff --git a/public/language/pt-PT/topic.json b/public/language/pt-PT/topic.json index a596922813..74945e942e 100644 --- a/public/language/pt-PT/topic.json +++ b/public/language/pt-PT/topic.json @@ -30,30 +30,30 @@ "locked": "Bloqueado", "pinned": "Afixado", "moved": "Movido", - "copy-ip": "Copy IP", - "ban-ip": "Ban IP", + "copy-ip": "Copiar IP", + "ban-ip": "Banir IP", "view-history": "Histórico de Edição", "bookmark_instructions": "Carrega aqui para voltares à última publicação lide assunto.", "flag_title": "Denunciar esta publicação para moderação", - "merged_message": "This topic has been merged into %2", + "merged_message": "Este tópico foi fundido no tópico %2", "deleted_message": "Este tópico foi eliminado. Apenas utilizadores com privilégios de moderação do tópico podem vê-lo.", "following_topic.message": "A partir de agora receberás uma notificação sempre que alguém publicar neste tópico.", "not_following_topic.message": "Verás este tópico na lista de tópicos por ler mas não irás receber notificações quando alguém publicar neste tópico.", "ignoring_topic.message": "Não verás mais este tópico na tua lista de tópicos por ler. Serás notificado sempre que fores mencionado ou o teu tópico seja votado favoravelmente.", "login_to_subscribe": "Por favor regista-te ou inicia sessão para subscreveres este tópico.", - "markAsUnreadForAll.success": "Tópico marcado como \"por ler\" para todos.", + "markAsUnreadForAll.success": "Tópico marcado como \"não lido\" para todos.", "mark_unread": "Marcar como não lido", "mark_unread.success": "Tópico marcado como \"não lido\".", "watch": "Ver", - "unwatch": "Marcar como \"não visto\"", + "unwatch": "Marcar como não visto", "watch.title": "Ser notificado de novas respostas neste tópicos", "unwatch.title": "Parar de seguir este tópico", "share_this_post": "Partilhar esta publicação", - "watching": "Vendo", - "not-watching": "Não está a ver", - "ignoring": "Ignorando", + "watching": "Seguir", + "not-watching": "Não seguir", + "ignoring": "Ignorar", "watching.description": "Notificar-me sobre novas respostas.
Mostrar o tópico em \"não lidos\".", - "not-watching.description": "Não me notificar de novas respostas.
Mostrar tópico em \"não lidos\" se a categoria não está ignorada.", + "not-watching.description": "Não me notificar de novas respostas.
Mostrar tópico em \"não lidos\" caso a categoria não esteja a ser ignorada.", "ignoring.description": "Não me notificar de novas respostas.
Não mostrar este tópico em \"não lidos\".", "thread_tools.title": "Ferramentas de tópicos", "thread_tools.markAsUnreadForAll": "Marcar como não lido para todos", @@ -73,8 +73,8 @@ "thread_tools.restore_confirm": "Tens a certeza que pretendes restaurar este tópico?", "thread_tools.purge": "Eliminar tópico", "thread_tools.purge_confirm": "Tens a certeza que queres eliminar este tópico?", - "thread_tools.merge_topics": "Merge Topics", - "thread_tools.merge": "Merge", + "thread_tools.merge_topics": "Fundir Tópicos", + "thread_tools.merge": "Fundir", "topic_move_success": "Este tópico foi movido com sucesso para %1", "post_delete_confirm": "Tens a certeza que desejas eliminar esta publicação?", "post_restore_confirm": "Tens a certeza que desejas restaurar esta publicação?", @@ -96,12 +96,12 @@ "fork_pid_count": "%1 publicação(ões) selecionada(s)", "fork_success": "Clonaste um tópico com sucesso! Carrega aqui para ires para o tópico clonado.", "delete_posts_instruction": "Carrega nas publicações que queres apagar/eliminar", - "merge_topics_instruction": "Click the topics you want to merge", + "merge_topics_instruction": "Clica nos tópicos que queres fundir", "move_posts_instruction": "Clica nas publicações que queres mover", "composer.title_placeholder": "Insere aqui o título do tópico...", "composer.handle_placeholder": "Nome", "composer.discard": "Descartar", - "composer.submit": "Submeter", + "composer.submit": "Publicar", "composer.replying_to": "Respondendo a %1", "composer.new_topic": "Novo tópico", "composer.uploading": "carregando...", diff --git a/public/language/pt-PT/user.json b/public/language/pt-PT/user.json index 18acea7320..d2cde8e4fc 100644 --- a/public/language/pt-PT/user.json +++ b/public/language/pt-PT/user.json @@ -3,7 +3,7 @@ "offline": "Offline", "deleted": "Apagar", "username": "Nome de utilizador", - "joindate": "Juntar data", + "joindate": "Data de Adesão", "postcount": "Quantidade de publicações", "email": "E-mail", "confirm_email": "Confirmar o e-mail", @@ -12,7 +12,7 @@ "ban_account_confirm": "Queres realmente banir este utilizador?", "unban_account": "Deixar de banir esta conta", "delete_account": "Eliminar conta", - "delete_account_confirm": "Are you sure you want to delete your account?
This action is irreversible and you will not be able to recover any of your data

Enter your password to confirm that you wish to destroy this account.", + "delete_account_confirm": "Tens a certeza que queres eliminar a tua conta?
Esta ação é irreversível e não terás oportunidade de recuperar nenhuma das tuas informações

Insere a tua palavra-passe para confirmar que desejas destruir esta conta.", "delete_this_account_confirm": "Tens a certeza que queres apagar esta conta?
Esta acção é irreversível e não terás oportunidade de recuperar nenhuma informação

", "account-deleted": "Conta eliminada", "fullname": "Nome completo", @@ -26,11 +26,12 @@ "reputation": "Reputação", "bookmarks": "Marcadores", "watched_categories": "Categorias subscritas", - "watched": "Visto ", - "ignored": "Ignored", + "watched": "Subscritos", + "ignored": "Ignorados", + "default-category-watch-state": "Default category watch state", "followers": "Seguidores", "following": "Seguindo", - "blocks": "Blocks", + "blocks": "Bloqueados", "block_toggle": "Toggle Block", "block_user": "Bloquear Utilizador", "unblock_user": "Desbloquear Utilizador", @@ -40,7 +41,7 @@ "chat": "Conversa", "chat_with": "Continuar a conversa com %1", "new_chat_with": "Começa nova conversa com %1", - "flag-profile": "Flag Profile", + "flag-profile": "Denunciar Perfil", "follow": "Segue", "unfollow": "Deixar de seguir", "more": "Mais", @@ -48,6 +49,7 @@ "change_picture": "Mudar fotografia", "change_username": "Mudar nome de utilizador", "change_email": "Mudar e-mail", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Editar", "edit-profile": "Editar perfil", "default_picture": "Icon pré-definido", @@ -88,7 +90,7 @@ "follows_no_one": "Este utilizador não está a seguir ninguém :(", "has_no_posts": "Este utilizador ainda não publicou nada.", "has_no_topics": "Este utilizar ainda não publicou nenhum tópico.", - "has_no_watched_topics": "Este utilizador ainda não subscreveu qualquer tópico até ao momento.", + "has_no_watched_topics": "Este utilizador ainda não subscreveu nenhum tópico até ao momento.", "has_no_ignored_topics": "Este utilizador ainda não ignorou nenhum tópico.", "has_no_upvoted_posts": "Este utilizador ainda não votou favoravelmente em nenhuma publicação.", "has_no_downvoted_posts": "Este utilizador ainda não votou negativamente em nenhuma publicação.", @@ -149,7 +151,7 @@ "info.moderation-note.success": "Nota de moderação guardada", "info.moderation-note.add": "Adicionar nota", "sessions.description": "This page allows you to view any active sessions on this forum and revoke them if necessary. You can revoke your own session by logging out of your account.", - "consent.title": "Your Rights & Consent", + "consent.title": "Direitos e privacidade", "consent.lead": "This community forum collects and processes your personal information.", "consent.intro": "We use this information strictly to personalise your experience in this community, as well as to associate the posts you make to your user account. During the registration step you were asked to provide a username and email address, you can also optionally provide additional information to complete your user profile on this website.

We retain this information for the life of your user account, and you are able to withdraw consent at any time by deleting your account. At any time you may request a copy of your contribution to this website, via your Rights & Consent page.

If you have any questions or concerns, we encourage you to reach out to this forum's administrative team.", "consent.email_intro": "Occasionally, we may send emails to your registered email address in order to provide updates and/or to notify you of new activity that is pertinent to you. You can customise the frequency of the community digest (including disabling it outright), as well as select which types of notifications to receive via email, via your user settings page.", diff --git a/public/language/ro/admin/settings/user.json b/public/language/ro/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/ro/admin/settings/user.json +++ b/public/language/ro/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ro/category.json b/public/language/ro/category.json index a090e3ac07..e96906a4a9 100644 --- a/public/language/ro/category.json +++ b/public/language/ro/category.json @@ -7,14 +7,16 @@ "browsing": "navighează", "no_replies": "Nu a răspuns nimeni", "no_new_posts": "Nici o postare nouă", - "share_this_category": "Distribuie această categorie", "watch": "Urmărește", "ignore": "Ignoră", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Categorii urmărite" } \ No newline at end of file diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json index 49e1f8da66..d331649a66 100644 --- a/public/language/ro/notifications.json +++ b/public/language/ro/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/ro/user.json b/public/language/ro/user.json index 23689372bc..24649152c8 100644 --- a/public/language/ro/user.json +++ b/public/language/ro/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Urmărit de", "following": "Îi urmărește pe", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Schimbă Poza", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Editează", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/ru/admin/settings/user.json b/public/language/ru/admin/settings/user.json index e9088c9ea4..7f8fc4231e 100644 --- a/public/language/ru/admin/settings/user.json +++ b/public/language/ru/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Отправлять уведомления по электронной почте при появлении новых ответов в подписанных темах", "follow-created-topics": "Следить за темами которые вы создаёте", "follow-replied-topics": "Следить за темами в которых вы отвечаете", - "default-notification-settings": "Настройки уведомлений по умолчанию" + "default-notification-settings": "Настройки уведомлений по умолчанию", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/ru/category.json b/public/language/ru/category.json index cee642a44c..50ae1221bf 100644 --- a/public/language/ru/category.json +++ b/public/language/ru/category.json @@ -7,14 +7,16 @@ "browsing": "просматривают", "no_replies": "Нет ответов", "no_new_posts": "Нет новых записей", - "share_this_category": "Поделиться этим сообществом", "watch": "Следить", "ignore": "Игнорировать", "watching": "Отслеживать", + "not-watching": "Not Watching", "ignoring": "Игнорировать", - "watching.description": "Показывать тему в непрочитанных", - "ignoring.description": "Не показывать тему в непрочитанных", - "watch.message": "Вы теперь подписаны на обновления этого сообщества и всех его рубрик", - "ignore.message": "Вы теперь игнорируете обновления этого сообщества и всех его рубрик", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Ваши сообщества" } \ No newline at end of file diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json index 247d1bb0b4..f3b479299a 100644 --- a/public/language/ru/notifications.json +++ b/public/language/ru/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Когда кто-то подписался на ваши обновления", "notificationType_new-chat": "Когда вы получили сообщение", "notificationType_group-invite": "Когда вы получили приглашение в группу", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Когда кто-то добавляется в очередь регистрации", "notificationType_post-queue": "Когда новое сообщение помещается в очередь", "notificationType_new-post-flag": "Когда сообщение помечено", diff --git a/public/language/ru/user.json b/public/language/ru/user.json index 3710fe7a4f..10dcf94401 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -28,6 +28,7 @@ "watched_categories": "Просмотренные категории", "watched": "Подписка", "ignored": "Игнорировать", + "default-category-watch-state": "Default category watch state", "followers": "Подписчиков", "following": "Подписок", "blocks": "Блокировки", @@ -48,6 +49,7 @@ "change_picture": "Изменить фото", "change_username": "Изменить имя участника", "change_email": "Изменить электронную почту", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Редактировать", "edit-profile": "Редактировать профиль", "default_picture": "Иконка по умолчанию", diff --git a/public/language/rw/admin/settings/user.json b/public/language/rw/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/rw/admin/settings/user.json +++ b/public/language/rw/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/rw/category.json b/public/language/rw/category.json index f9b137bdbf..069195dbb9 100644 --- a/public/language/rw/category.json +++ b/public/language/rw/category.json @@ -7,14 +7,16 @@ "browsing": "abari kureba", "no_replies": "Nta muntu urasubiza", "no_new_posts": "Nta bishya.", - "share_this_category": "Sangiza iki cyiciro", "watch": "Kurikirana", "ignore": "Ihorere", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Ibyiciro Bikurikirwa" } \ No newline at end of file diff --git a/public/language/rw/notifications.json b/public/language/rw/notifications.json index 88f3e772aa..9b407a2fe7 100644 --- a/public/language/rw/notifications.json +++ b/public/language/rw/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/rw/user.json b/public/language/rw/user.json index 8203a0bbce..b160b96f45 100644 --- a/public/language/rw/user.json +++ b/public/language/rw/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Ibikurikiranwa", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Abamukurikira", "following": "Akurikira", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Hindura Ifoto", "change_username": "Hindura Izina", "change_email": "Hindura Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Hinduraho", "edit-profile": "Hinduraho ku Ishusho", "default_picture": "Akamenyetso Gasanzwe", diff --git a/public/language/sc/admin/settings/user.json b/public/language/sc/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/sc/admin/settings/user.json +++ b/public/language/sc/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/sc/category.json b/public/language/sc/category.json index 324b42de64..b15dfea64c 100644 --- a/public/language/sc/category.json +++ b/public/language/sc/category.json @@ -7,14 +7,16 @@ "browsing": "navighende", "no_replies": "Perunu at rispostu", "no_new_posts": "No new posts.", - "share_this_category": "Share this category", "watch": "Watch", "ignore": "Ignore", "watching": "Watching", + "not-watching": "Not Watching", "ignoring": "Ignoring", - "watching.description": "Show topics in unread", - "ignoring.description": "Do not show topics in unread", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Watched categories" } \ No newline at end of file diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json index fd68a1f973..2eb3857af0 100644 --- a/public/language/sc/notifications.json +++ b/public/language/sc/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/sc/user.json b/public/language/sc/user.json index 4ffc4f1c6d..2684295353 100644 --- a/public/language/sc/user.json +++ b/public/language/sc/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Watched", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Sighidores", "following": "Sighende", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Muda Immàgine", "change_username": "Change Username", "change_email": "Change Email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Acontza", "edit-profile": "Edit Profile", "default_picture": "Default Icon", diff --git a/public/language/sk/admin/settings/user.json b/public/language/sk/admin/settings/user.json index 2f7e292e96..f69cf571da 100644 --- a/public/language/sk/admin/settings/user.json +++ b/public/language/sk/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Poslať e-mail, ak sa objaví odpoveď v téme, ktorú sledujem", "follow-created-topics": "Sledovať mnou vytvorené témy", "follow-replied-topics": "Sledovať témy, na ktoré ste odpovedal", - "default-notification-settings": "Predvolené nastavenia oznámení" + "default-notification-settings": "Predvolené nastavenia oznámení", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/sk/category.json b/public/language/sk/category.json index f7067b92e3..f32b7ee376 100644 --- a/public/language/sk/category.json +++ b/public/language/sk/category.json @@ -7,14 +7,16 @@ "browsing": "prehliada", "no_replies": "Nikto ešte neodpovedal", "no_new_posts": "Žiadne nové príspevky.", - "share_this_category": "Zdieľať túto kategóriu", "watch": "Sledovať", "ignore": "Ignorovať", "watching": "Sledované", + "not-watching": "Not Watching", "ignoring": "Ignorovať", - "watching.description": "Zobrazovať témy ako neprečítané", - "ignoring.description": "Nezobrazovať témy v neprečítaných", - "watch.message": "Práve sledujete novinky s tejto kategórie a všetkých podkategórií", - "ignore.message": "Práve ignorujete novinky s tejto kategórie a všetkých podkategórií", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Sledované kategórie" } \ No newline at end of file diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json index f86817dabd..5e3818ca46 100644 --- a/public/language/sk/notifications.json +++ b/public/language/sk/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Ak Vás začne niekto sledovať", "notificationType_new-chat": "Ak obdržíte novú správu konverzácie", "notificationType_group-invite": "Ak obdržíte pozvanie do skupiny", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Ak bude niekto pridaný do registračnej fronty", "notificationType_post-queue": "Ak bude pridaný nový príspevok do fronty", "notificationType_new-post-flag": "Ak bude príspevok označený", diff --git a/public/language/sk/user.json b/public/language/sk/user.json index ecc263c8be..b75deff38c 100644 --- a/public/language/sk/user.json +++ b/public/language/sk/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Sledované", "ignored": "Ignorovaný", + "default-category-watch-state": "Default category watch state", "followers": "Nasledovatelia", "following": "Nasleduje", "blocks": "Zablokovaný", @@ -48,6 +49,7 @@ "change_picture": "Zmeniť obrázok", "change_username": "Zmeniť užívateľské meno", "change_email": "Zmeniť e-mail", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Upraviť", "edit-profile": "Upraviť profil", "default_picture": "Predvolená ikona", diff --git a/public/language/sl/admin/settings/user.json b/public/language/sl/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/sl/admin/settings/user.json +++ b/public/language/sl/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/sl/category.json b/public/language/sl/category.json index 450f1c6841..3377b262a9 100644 --- a/public/language/sl/category.json +++ b/public/language/sl/category.json @@ -7,14 +7,16 @@ "browsing": "Brskanje", "no_replies": "Nihče ni odgovoril.", "no_new_posts": "Ni novih objav.", - "share_this_category": "Deli to kategorijo.", "watch": "Spremljaj.", "ignore": "Prezri.", "watching": "Spremljano", + "not-watching": "Not Watching", "ignoring": "Prezrto", - "watching.description": "Pokaži teme v razdelku Neprebrano.", - "ignoring.description": "Ne pokaži tem v razdelku Neprebrano.", - "watch.message": "Od sedaj naprej spremljate posodobitve te kategorije in njenih podkategorij.", - "ignore.message": "Od sedaj naprej ne spremljate posodobitev te kategorije in njenih podkategorij.", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Spremljane kategorije" } \ No newline at end of file diff --git a/public/language/sl/notifications.json b/public/language/sl/notifications.json index 936b7c8ba6..b416d1054a 100644 --- a/public/language/sl/notifications.json +++ b/public/language/sl/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/sl/user.json b/public/language/sl/user.json index e3be52ffd1..708f26fd1e 100644 --- a/public/language/sl/user.json +++ b/public/language/sl/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Spremljano", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "Spremljevalci", "following": "Spremljano", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "Spremeni sliko", "change_username": "Spremeni uporabniško ime", "change_email": "Spremeni e-poštni naslov", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Uredi", "edit-profile": "Uredi profil", "default_picture": "Privzeta ikona", diff --git a/public/language/sr/admin/settings/user.json b/public/language/sr/admin/settings/user.json index 7dcd94b087..7cc55264a2 100644 --- a/public/language/sr/admin/settings/user.json +++ b/public/language/sr/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Pošalji email kada odgovori su načinjeni u temu u kojoj sam ja pretplaćen", "follow-created-topics": "Prati teme koje si ti napravio", "follow-replied-topics": "Prati teme na koje si ti odgovorio", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/sr/category.json b/public/language/sr/category.json index 7952be22e8..8d50f2e04e 100644 --- a/public/language/sr/category.json +++ b/public/language/sr/category.json @@ -7,14 +7,16 @@ "browsing": "гледа", "no_replies": "Још увек нема одговора", "no_new_posts": "Нема нових порука", - "share_this_category": "Дели ову категорију", "watch": "Надгледај", "ignore": "Игнориши", "watching": "Надгледај", + "not-watching": "Не надгледај", "ignoring": "Игнориши", - "watching.description": "Прикажи теме у непрочитаним", - "ignoring.description": "Не приказуј теме у непрочитаним", - "watch.message": "Сада надгледате ажурирања из ове категорије и свих поткатегорија", - "ignore.message": "Сада игноришете ажурирања из ове категорије и свих поткатегорија", + "watching.description": "Прикажи теме у непрочитаним и недавним", + "not-watching.description": "Не приказуј теме у непрочитаним, прикажи у недавним", + "ignoring.description": "Не приказуј теме у непрочитаним и недавним", + "watching.message": "Сада надгледате ажурирања из ове категорије и свих поткатегорија", + "notwatching.message": "Не надгледате ажурирања из ове категорије и свих поткатегорија", + "ignoring.message": "Сада игноришете ажурирања из ове категорије и свих поткатегорија", "watched-categories": "Надгледане категорије" } \ No newline at end of file diff --git a/public/language/sr/error.json b/public/language/sr/error.json index b2fd6d3db5..3302a06b65 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -120,7 +120,7 @@ "chat-edit-duration-expired": "Време у којем вам је дозвољено уређивање порука ћаскања након објављивања: %1 сек.", "chat-delete-duration-expired": "Време у којем вам је дозвољено брисање порука ћаскања након објављивања: %1 сек.", "chat-deleted-already": "Ова порука ћаскања је већ избрисана.", - "chat-restored-already": "This chat message has already been restored.", + "chat-restored-already": "Ова порука ћаскања је већ обновљена.", "already-voting-for-this-post": "Већ сте гласали за ову поруку.", "reputation-system-disabled": "Угледи су онемогућени.", "downvoting-disabled": "Негативно гласање је онемогућено", @@ -153,8 +153,8 @@ "cant-move-to-same-topic": "Није могуће преместити поруку у исту тему!", "cannot-block-self": "Не можете блокирати себе!", "cannot-block-privileged": "Не можете блокирати администраторе или глобалне модераторе", - "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", + "cannot-block-guest": "Гости нису у могућности да блокирају друге кориснике", + "already-blocked": "Овај корисник је већ блокиран", + "already-unblocked": "Овај корисник је већ одблокиран", "no-connection": "Изгледа да постоји проблем са вашом интернет везом" } \ No newline at end of file diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json index 24e4c2feb0..2587d82844 100644 --- a/public/language/sr/notifications.json +++ b/public/language/sr/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Када неко почне да вас прати", "notificationType_new-chat": "Када примите поруку за ћаскање", "notificationType_group-invite": "Када примите позивницу за групу", + "notificationType_group-request-membership": "Када неко затражи да се придружи групи коју поседујете", "notificationType_new-register": "Када је неко додат на чекање за регистрацију", "notificationType_post-queue": "Када је нова порука на чекању", "notificationType_new-post-flag": "Када је порука означена", diff --git a/public/language/sr/user.json b/public/language/sr/user.json index b5cd6199b9..11808881ef 100644 --- a/public/language/sr/user.json +++ b/public/language/sr/user.json @@ -28,6 +28,7 @@ "watched_categories": "Надгледане категорије", "watched": "Надгледано", "ignored": "Игнорисано", + "default-category-watch-state": "Стање надгледања подразумеване категорије", "followers": "Пратиоци", "following": "Праћења", "blocks": "Блокирања", @@ -48,6 +49,7 @@ "change_picture": "Промена слике", "change_username": "Промена корисничког имена", "change_email": "Промена е-поште", + "email_same_as_password": "Унесите тренутну лозинку за наставак; поново сте унели нову е-пошту", "edit": "Уреди", "edit-profile": "Уреди профил", "default_picture": "Подразумевана икона", diff --git a/public/language/sv/admin/settings/user.json b/public/language/sv/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/sv/admin/settings/user.json +++ b/public/language/sv/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/sv/category.json b/public/language/sv/category.json index c3811b12df..c44a23bdc4 100644 --- a/public/language/sv/category.json +++ b/public/language/sv/category.json @@ -7,14 +7,16 @@ "browsing": "läser", "no_replies": "Ingen har svarat", "no_new_posts": "Inga nya inlägg.", - "share_this_category": "Dela den här kategorin", "watch": "Bevaka", "ignore": "Ignorera", "watching": "Bevakar", + "not-watching": "Not Watching", "ignoring": "Ignorerar", - "watching.description": "Visa ämnen i olästa", - "ignoring.description": "Visa inte ämnen i olästa", - "watch.message": "Du bevakar nu uppdateringar i denna kategori och alla underkategorier", - "ignore.message": "Du ignorerar nu uppdateringar i denna kategori och alla underkategorier", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Bevakade kategorier" } \ No newline at end of file diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index 83386f9fdc..7f9c3cbe74 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "När någon börjar följa dig", "notificationType_new-chat": "När du får ett chattmeddelande", "notificationType_group-invite": "När du får en gruppinbjudan", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "När någon läggs till i registreringskön", "notificationType_post-queue": "När ett nytt inlägg läggs i kön", "notificationType_new-post-flag": "När ett nytt inlägg flaggas", diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 4e7796c1ad..3eb1de8fe6 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Bevakad", "ignored": "Ignorerad", + "default-category-watch-state": "Default category watch state", "followers": "Följare", "following": "Följer", "blocks": "Blockerar", @@ -48,6 +49,7 @@ "change_picture": "Ändra bild", "change_username": "Ändra användarnamn", "change_email": "Ändra e-postadress", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Ändra", "edit-profile": "Redigera profil", "default_picture": "Standard-ikon", diff --git a/public/language/th/admin/settings/user.json b/public/language/th/admin/settings/user.json index 7fc818212c..eda2151395 100644 --- a/public/language/th/admin/settings/user.json +++ b/public/language/th/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/th/category.json b/public/language/th/category.json index 8daa641ba5..0b1c096fef 100644 --- a/public/language/th/category.json +++ b/public/language/th/category.json @@ -7,14 +7,16 @@ "browsing": "เรียกดู", "no_replies": "ยังไม่มีใครตอบ", "no_new_posts": "ไม่มีกระทู้ใหม่", - "share_this_category": "แชร์หมวดนี้", "watch": "ตามดู", "ignore": "ไม่ต้องสนใจอีก", "watching": "กำลังตามดู", + "not-watching": "Not Watching", "ignoring": "เมินเฉย", - "watching.description": "แสดงกระทู้ที่ยังไม่ได้อ่าน", - "ignoring.description": "ไม่แสดงกระทู้ที่ยังไม่ได้อ่าน", - "watch.message": "ตอนนี้คุณกำลังตามดูอัพเดทจากกระทู้หมวดนี้และหมวดหมู่ย่อยทั้งหมดในนี้", - "ignore.message": "ตอนนี้คุณกำลังเมินเฉยต่ออัพเดทจากกระทู้หมวดนี้และหมวดหมู่ย่อยทั้งหมดในนี้", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "หมวดหมู่ที่ดูแล้ว" } \ No newline at end of file diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json index 9d0246ce53..f107a25937 100644 --- a/public/language/th/notifications.json +++ b/public/language/th/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "เมื่อมีคนติดตามคุณ", "notificationType_new-chat": "เมื่อคุณได้รับข้อความใหม่", "notificationType_group-invite": "เมื่อคุณได้รับเชิญเข้ากลุ่ม", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "เมื่อมีคนถูกเพิ่มในคิวลงทะเบียน", "notificationType_post-queue": "เมื่อมีโพสต์ใหม่อยู่ในคิว", "notificationType_new-post-flag": "เมื่อโพสต์ถูกตั้งค่าสถานะ", diff --git a/public/language/th/user.json b/public/language/th/user.json index 9339035d5a..1ddf1cbe70 100644 --- a/public/language/th/user.json +++ b/public/language/th/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "ดูแล้ว", "ignored": "ยกเว้นแล้ว", + "default-category-watch-state": "Default category watch state", "followers": "คนติดตาม", "following": "ติดตาม", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "เปลี่ยนรูป", "change_username": "เปลี่ยนชื่อผู้ใช้", "change_email": "เปลี่ยนอีเมล", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "แก้ไข", "edit-profile": "แก้ไขข้อมูลส่วนตัว", "default_picture": "แก้ไขไอคอน", diff --git a/public/language/tr/admin/advanced/database.json b/public/language/tr/admin/advanced/database.json index fa3e59edad..8fa44d8074 100644 --- a/public/language/tr/admin/advanced/database.json +++ b/public/language/tr/admin/advanced/database.json @@ -18,31 +18,31 @@ "mongo.resident-memory": "Yerleşik Bellek", "mongo.virtual-memory": "Sanal Hafıza", "mongo.mapped-memory": "Planlanan Hafıza", - "mongo.bytes-in": "Bytes In", - "mongo.bytes-out": "Bytes Out", - "mongo.num-requests": "Number of Requests", + "mongo.bytes-in": "alınan bayt", + "mongo.bytes-out": "gönderilen bayt", + "mongo.num-requests": "İsteklerin Sayısı", "mongo.raw-info": "İşlenmemiş MongoDB Bilgisi", "redis": "Redis", "redis.version": "Redis Versiyonu", - "redis.keys": "Keys", - "redis.expires": "Expires", - "redis.avg-ttl": "Average TTL", + "redis.keys": "Anahtarlar", + "redis.expires": "Sona erenler", + "redis.avg-ttl": "Ortalama TTL", "redis.connected-clients": "Bağlı İstemciler", "redis.connected-slaves": "İlişkili Bağımlılar", "redis.blocked-clients": "Engellenen İstemciler", "redis.used-memory": "Kullanılan Hafıza", "redis.memory-frag-ratio": "Bellek Parçalanma Oranı", - "redis.total-connections-recieved": "Alınan Bağlantılar (Toplam)", - "redis.total-commands-processed": "İşlenen Komutlar (Toplam)", - "redis.iops": "Saniyede işlenen komut sayısı (Redis)", - "redis.iinput": "Instantaneous Input Per Second", - "redis.ioutput": "Instantaneous Output Per Second", - "redis.total-input": "Total Input", - "redis.total-output": "Total Ouput", + "redis.total-connections-recieved": "Toplam Alınan Bağlantılar", + "redis.total-commands-processed": "Toplam İşlenen Komutlar", + "redis.iops": "Saniyede işlenen komut sayısı", + "redis.iinput": "Saniyede yapılan giriş", + "redis.ioutput": "Saniyede yapılan çıkış", + "redis.total-input": "Toplam giriş", + "redis.total-output": "Toplam çıkış", - "redis.keyspace-hits": "Başarılı anahtar arama sayısı: keyspace_hits (Redis)", - "redis.keyspace-misses": "Başarısız anahtar arama sayısı: keyspace_misses (Redis)", + "redis.keyspace-hits": "Başarılı anahtar arama sayısı: keyspace_hits", + "redis.keyspace-misses": "Başarısız anahtar arama sayısı: keyspace_misses", "redis.raw-info": "İşlenmemiş Redis Bilgisi", "postgres": "Postgres", diff --git a/public/language/tr/admin/general/navigation.json b/public/language/tr/admin/general/navigation.json index 1be5d07c77..42d907d2be 100644 --- a/public/language/tr/admin/general/navigation.json +++ b/public/language/tr/admin/general/navigation.json @@ -2,18 +2,18 @@ "icon": "İkon:", "change-icon": "değiştir", "route": "Yol:", - "tooltip": "Araç Bilgisi:", + "tooltip": "Araç ipucu:", "text": "Yazı:", "text-class": "Metin Sınıfı: opsiyonel", "id": "ID: opsiyonel", "properties": "Özellikler:", - "groups": "Groups:", + "groups": "Gruplar", "open-new-window": "Yeni pencerede aç", "btn.delete": "Sil", - "btn.disable": "Devre dışı", - "btn.enable": "Etkin", + "btn.disable": "Kapalı", + "btn.enable": "Açık", "available-menu-items": "Kullanılabilir Menü Öğeleri", "custom-route": "Özel Yol", diff --git a/public/language/tr/admin/manage/categories.json b/public/language/tr/admin/manage/categories.json index e4114adc8c..5064cc9781 100644 --- a/public/language/tr/admin/manage/categories.json +++ b/public/language/tr/admin/manage/categories.json @@ -29,8 +29,8 @@ "select-category": "Kategori Seç", "set-parent-category": "Ana Kategori Ayarla", - "privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. Select the domain of effect from the dropdown below.", - "privileges.category-selector": "Configuring privileges for ", + "privileges.description": "Bu bölümde bu kategori için erişim denetimi ayrıcalıklarını yapılandırabilirsiniz. Ayrıcalıklar kullanıcı başına veya grup bazında verilebilir. Aşağıdaki açılır listeden etki alanını seçin.", + "privileges.category-selector": "için yapılandırılan ayrıcalıklar", "privileges.warning": "Not: Ayrıcalık ayarları hemen yürürlüğe girer. Bu ayarları yaptıktan sonra kategoriyi kaydetmek gerekli değildir.", "privileges.section-viewing": "Ayrıcalıkları Görüntüle", "privileges.section-posting": "Gönderme Ayrıcalıkları", diff --git a/public/language/tr/admin/manage/uploads.json b/public/language/tr/admin/manage/uploads.json index 21bc8201fc..d38de46fab 100644 --- a/public/language/tr/admin/manage/uploads.json +++ b/public/language/tr/admin/manage/uploads.json @@ -1,9 +1,9 @@ { - "upload-file": "Upload File", - "filename": "Filename", - "usage": "Post Usage", - "orphaned": "Orphaned", - "size/filecount": "Size / Filecount", - "confirm-delete": "Do you really want to delete this file?", - "filecount": "%1 files" + "upload-file": "Dosya yükle", + "filename": "Dosya adı", + "usage": "İleti Kullanımı", + "orphaned": "Sahipsiz", + "size/filecount": "Boyut / Dosya sayısı", + "confirm-delete": "Bu dosyayı silmek istediğinden emin misin?", + "filecount": "%1 dosya" } \ No newline at end of file diff --git a/public/language/tr/admin/menu.json b/public/language/tr/admin/menu.json index 7433046c6a..a3960f0b39 100644 --- a/public/language/tr/admin/menu.json +++ b/public/language/tr/admin/menu.json @@ -57,7 +57,7 @@ "section-advanced": "Gelişmiş", "advanced/database": "Veritabanı", "advanced/events": "Olaylar", - "advanced/hooks": "Hooks", + "advanced/hooks": "Kancalar", "advanced/logs": "Kayıtlar", "advanced/errors": "Hatalar", "advanced/cache": "Önbellek", diff --git a/public/language/tr/admin/settings/uploads.json b/public/language/tr/admin/settings/uploads.json index 872368d039..dfd4537417 100644 --- a/public/language/tr/admin/settings/uploads.json +++ b/public/language/tr/admin/settings/uploads.json @@ -4,14 +4,14 @@ "private": "Yüklenen dosyaları gizli yap", "private-extensions": "Gizli yapılacak dosya uzantıları", "private-uploads-extensions-help": "Buraya gizli yapılacak dosya uzantıları listesini virgülle ayırarak giriniz. (ör. pdf,xls,doc). Boş bırakmak, tüm dosyaların gizli olacağı anlamına gelir.", - "resize-image-width-threshold": "Resize images if they are wider than specified width", - "resize-image-width-threshold-help": "(in pixels, default: 1520 pixels, set to 0 to disable)", + "resize-image-width-threshold": "Belirtilen genişlikten daha genişse görüntüleri yeniden boyutlandırın", + "resize-image-width-threshold-help": "(piksel olarak, varsayılan: 1520 piksel, devre dışı bırakmak için 0 yazın.)", "resize-image-width": "Görüntüleri belirtilen genişliğe yeniden boyutlandır", - "resize-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)", + "resize-image-width-help": "(piksel olarak, varsayılan: 760 piksel, devre dışı bırakmak için 0 yazın.)", "resize-image-quality": "Resimleri yeniden boyutlandırırken kullanılacak kalite", "resize-image-quality-help": "Yeniden boyutlandırılan görüntülerin dosya boyutunu azaltmak için daha düşük bir kalite ayarı kullan.", "max-file-size": "Maksimum Dosya Boyutu (KiB)", - "max-file-size-help": "(Kilobayt, varsayılan: 2,048 KiB)", + "max-file-size-help": "(Kilobayt, varsayılan: 2048 KiB)", "reject-image-width": "Maksimum Görsel Genişliği (piksel)", "reject-image-width-help": "Bu değerden daha geniş olan görseller reddedilecektir.", "reject-image-height": "Maksimum Görsel Yüksekliği (piksel)", diff --git a/public/language/tr/admin/settings/user.json b/public/language/tr/admin/settings/user.json index e64625bbe2..58348a09b0 100644 --- a/public/language/tr/admin/settings/user.json +++ b/public/language/tr/admin/settings/user.json @@ -1,15 +1,15 @@ { "authentication": "Kimlik Doğrulama", "require-email-confirmation": "E-posta Onayı Gerektirir", - "email-confirm-interval": "Kullanıcı onay e-postasını gönderemez", + "email-confirm-interval": "Kullanıcı onay e-postasını tekrar gönderemez", "email-confirm-email2": "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ı", "allow-login-with.email": "Sadece E-posta", "account-settings": "Hesap Ayarları", - "gdpr_enabled": "Enable GDPR consent collection", - "gdpr_enabled_help": "When enabled, all new registrants will be required to explicitly give consent for data collection and usage under the General Data Protection Regulation (GDPR). Note: Enabling GDPR does not force pre-existing users to provide consent. To do so, you will need to install the GDPR plugin.", + "gdpr_enabled": "GDPR veri toplamayı etkinleştir", + "gdpr_enabled_help": "Etkinleştirildiğinde, tüm yeni tescil ettirenlerin Veri Toplama Yönetmeliği (GDPR) kapsamında veri toplanması ve kullanımı için açık bir şekilde onay vermeleri gerekecektir. Not: GDPR'yi etkinleştirmek, önceden var olan kullanıcıları onay vermesi için zorlamaz. Bunu yapmak için GDPR eklentisini yüklemeniz gerekir.", "disable-username-changes": "Kullanıcı adı değişikliği kapalı", "disable-email-changes": "E-posta değişikliklerini devre dışı bırak", "disable-password-changes": "Parola değişikliği kapalı", @@ -30,9 +30,9 @@ "session-time": "Oturum Süresi", "session-time-days": "Gün", "session-time-seconds": "Saniye", - "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-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.", "online-cutoff": "Kullanıcının atıl olarak değerlendirileceği dakika cinsinden geçen süre", - "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", + "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ı", "registration-type": "Kayıt Tipi", "registration-type.normal": "Normal", @@ -70,5 +70,9 @@ "email-post-notif": "Abone olduğum konulara cevap gelince bana e-posta gönder", "follow-created-topics": "Kendi konularımı takip et", "follow-replied-topics": "Cevap verdiğim konuları takip et", - "default-notification-settings": "Varsayılan bildirim ayarları" + "default-notification-settings": "Varsayılan bildirim ayarları", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/tr/category.json b/public/language/tr/category.json index 4317cfc2ec..3681fa37e6 100644 --- a/public/language/tr/category.json +++ b/public/language/tr/category.json @@ -7,14 +7,16 @@ "browsing": "gözden geçiriliyor", "no_replies": "Kimse yanıtlamadı", "no_new_posts": "Yeni ileti yok", - "share_this_category": "Bu kategoriyi paylaş", "watch": "İzle", "ignore": "Yoksay", "watching": "İzleniyor", + "not-watching": "Not Watching", "ignoring": "Yoksayılıyor", - "watching.description": "Okunmamış başlıkları göster", - "ignoring.description": "Okunmamış başlıkları gösterme", - "watch.message": "Sen bu kategori ve bütün alt kategorileri hareketleri izlemeye aldın", - "ignore.message": "Sen bu kategori ve bütün alt kategorileri hareketlere karşı susturdun", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Takip edilen kategoriler" } \ No newline at end of file diff --git a/public/language/tr/email.json b/public/language/tr/email.json index 00695038cb..c865d121b9 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -1,6 +1,6 @@ { - "test-email.subject": "Test Email", - "password-reset-requested": "Password Reset Requested!", + "test-email.subject": "Test E-posta", + "password-reset-requested": "Şifre Sıfırlama İstendi!", "welcome-to": "Hoş geldin %1", "invite": "%1 sizi davet etti", "greeting_no_name": "Merhaba", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index c0ead28478..f6666f72ba 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -120,7 +120,7 @@ "chat-edit-duration-expired": "Gönderildikten sonra yalnızca %1 saniye mesajı(ları) düzenlemene izin verilir", "chat-delete-duration-expired": "Gönderildikten sonra yalnızca %1 saniye mesajı(ları) silmene izin verilir", "chat-deleted-already": "Bu sohbet mesajı zaten silinmiş.", - "chat-restored-already": "This chat message has already been restored.", + "chat-restored-already": "Bu sohbet mesajı zaten geri yüklendi.", "already-voting-for-this-post": "Bu gönderi için zaten oy verdin.", "reputation-system-disabled": "İtibar sistemi devre dışı.", "downvoting-disabled": "Aşagı oylama kapatılmış", @@ -153,8 +153,8 @@ "cant-move-to-same-topic": "İletiyi aynı başlığa taşıyamazsın!", "cannot-block-self": "Kendi kendinizi engelleyemezsiniz!", "cannot-block-privileged": "Yöneticileri veya genel moderatörleri engelleyemezsiniz", - "cannot-block-guest": "Guest are not able to block other users", - "already-blocked": "This user is already blocked", - "already-unblocked": "This user is already unblocked", + "cannot-block-guest": "Misafir diğer kullanıcıları engelleyemez", + "already-blocked": "Bu kullanıcı zaten engellendi", + "already-unblocked": "Bu kullanıcı zaten engellenmedi", "no-connection": "İnternet bağlantınızda sorun var gibi görünüyor" } \ No newline at end of file diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json index e526219118..826b51d401 100644 --- a/public/language/tr/notifications.json +++ b/public/language/tr/notifications.json @@ -8,7 +8,7 @@ "outgoing_link_message": "%1 ayrılıyorsunuz", "continue_to": "Devam et", "return_to": "Geri dön.", - "new_notification": "You have a new notification", + "new_notification": "Yeni bir bildiriminiz var", "you_have_unread_notifications": "Okunmamış bildirimleriniz var.", "all": "Hepsi", "topics": "Başlıklar", @@ -56,6 +56,7 @@ "notificationType_follow": "Birisi seni takip etmeye başlayınca", "notificationType_new-chat": "Bir sohbet mesajı aldığınızda", "notificationType_group-invite": "Bir grup davetiyesi aldığınızda", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Birisi kayıt kuyruğuna eklendiğinde", "notificationType_post-queue": "Yeni bir ileti sıraya alındığında", "notificationType_new-post-flag": "Bir ileti bayraklandığında", diff --git a/public/language/tr/search.json b/public/language/tr/search.json index c7c82eb745..2b5090339f 100644 --- a/public/language/tr/search.json +++ b/public/language/tr/search.json @@ -17,7 +17,7 @@ "at-most": "En fazla", "relevance": "İlgi", "post-time": "Yayınlama zamanı", - "votes": "Votes", + "votes": "Oylar", "newer-than": "Daha yeni", "older-than": "Daha eski", "any-date": "Herhangi bir tarih", @@ -31,17 +31,17 @@ "sort-by": "Şuna göre filtrele", "last-reply-time": "En son cevaplama süresi", "topic-title": "Konu başlığı", - "topic-votes": "Topic votes", + "topic-votes": "Oylanan konular", "number-of-replies": "Cevap sayısı", "number-of-views": "Görüntüleme sayısı", - "topic-start-date": "Başlık açılma tarihi", + "topic-start-date": "Konu açılma tarihi", "username": "Kullanıcı Adı", "category": "Kategori", "descending": "Azalan düzene göre", "ascending": "Artan düzene göre", "save-preferences": "Tercihleri Kaydet", "clear-preferences": "Tercihleri Sil", - "search-preferences-saved": "Kaydedilmiş Arama tercihleri", - "search-preferences-cleared": "Silinmiş Arama Tercihleri", + "search-preferences-saved": "Arama tercihleri kaydedildi", + "search-preferences-cleared": "Arama tercihleri temizlendi", "show-results-as": "Sonuçları göster : " } \ No newline at end of file diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index 691c7d4610..e190274bf5 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -1,11 +1,11 @@ { "topic": "Konu", - "topic_id": "Başlık ID", - "topic_id_placeholder": "Başlık ID gir", + "topic_id": "Konu ID", + "topic_id_placeholder": "Konu ID gir", "no_topics_found": "Hiç konu bulunamadı!", "no_posts_found": "Hiç bir ileti bulunamadı!", "post_is_deleted": "Bu ileti silinmiş!", - "topic_is_deleted": "Bu başlık silindi!", + "topic_is_deleted": "Bu konu silindi!", "profile": "Profil", "posted_by": "%1 tarafından gönderildi", "posted_by_guest": "Ziyaretçi tarafından yayımlandı", @@ -16,7 +16,7 @@ "replies_to_this_post": "%1 Cevap", "one_reply_to_this_post": "1 Cevap", "last_reply_time": "Son cevap", - "reply-as-topic": "İletiye Cevap Ver", + "reply-as-topic": "Konuyu cevapla", "guest-login-reply": "Cevaplamak için giriş yapın", "edit": "Düzenle", "delete": "Sil", @@ -31,51 +31,51 @@ "pinned": "İğnelendi", "moved": "Taşındı", "copy-ip": "IP Kopyala", - "ban-ip": "IP Engelle", + "ban-ip": "IP Yasakla", "view-history": "Geçmişi Düzenle", - "bookmark_instructions": "Bu başlıkta en son kaldığın yere dönmek için tıklayın.", + "bookmark_instructions": "Bu konuda en son kaldığın yere dönmek için tıkla.", "flag_title": "Bu iletiyi moderatöre haber et", "merged_message": "Bu konu %2 olarak birleştirildi", - "deleted_message": "Bu başlık silindi. Sadece başlık düzenleme yetkisi olan kullanıcılar görebilir.", - "following_topic.message": "Artık bir kullanıcı bu başlığa ileti gönderdiğinde bildirim alacaksınız.", - "not_following_topic.message": "Bu başlığı okunmamışlarda göreceksiniz ama biri bir şey yazdığında bildirim gelmeyecek.", - "ignoring_topic.message": "Bu başlığı okunmamış başlıklar alanında görmeyeceksin. Eğer bir iletide bahsedilirsen veya iletin oylanırsa bildiri alacaksın.", - "login_to_subscribe": "Lütfen bu iletiyi başlığa üye olmak için giriş yapın.", - "markAsUnreadForAll.success": "Başlık herkes için okunmadı olarak işaretlendi.", + "deleted_message": "Bu konu silindi. Sadece konu düzenleme yetkisi olan kullanıcılar görebilir.", + "following_topic.message": "Artık bir kullanıcı bu konuya ileti gönderdiğinde bildirim alacaksınız.", + "not_following_topic.message": "Bu konuyu okunmamışlarda göreceksiniz ama biri bir şey yazdığında bildirim gelmeyecek.", + "ignoring_topic.message": "Bu konuyu okunmamış başlıklar alanında görmeyeceksin. Eğer bir iletide bahsedilirsen veya iletin oylanırsa bildiri alacaksın.", + "login_to_subscribe": "Lütfen bu konuya katılmak için üye olun veya giriş yapın.", + "markAsUnreadForAll.success": "Konu herkes için okunmadı olarak işaretlendi.", "mark_unread": "Okunmadı olarak işaretle", - "mark_unread.success": "Başlık okunmamış olarak işaretlendi.", - "watch": "İzle", - "unwatch": "İzleme", - "watch.title": "Bu başlığa gelen yeni iletilerden haberdar ol", + "mark_unread.success": "Konu okunmamış olarak işaretlendi.", + "watch": "Takip", + "unwatch": "Takip etme", + "watch.title": "Bu konuya gelen yeni iletilerden haberdar ol", "unwatch.title": "Bu konuyu izleme", "share_this_post": "Bu iletiyi paylaş", - "watching": "Takip Et", - "not-watching": "Takip etme", + "watching": "Takip ediliyor", + "not-watching": "Takip edilmiyor", "ignoring": "Sustur", "watching.description": "Yeni bir ileti geldiğinde beni bildir.
Okunmamış olarak göster.", "not-watching.description": "Yeni bir ileti geldiğinde bildirme.
Kategori susturulmamışsa okunmamış olarak göster.", "ignoring.description": "Yeni bir ileti geldiğinde bildirme.
Okunmamış olarak gösterme.", "thread_tools.title": "Konu Ayarları", "thread_tools.markAsUnreadForAll": "Okunmamış olarak İşaretle", - "thread_tools.pin": "Başlığı Sabitle", - "thread_tools.unpin": "Başlığı Sabitleme", - "thread_tools.lock": "Başlığı Kitle", - "thread_tools.unlock": "Başlığı Aç", - "thread_tools.move": "Başlığı Taşı", + "thread_tools.pin": "Konuyu Sabitle", + "thread_tools.unpin": "Konuyu Sabitleme", + "thread_tools.lock": "Konuyu Kilitle", + "thread_tools.unlock": "Konuyu Aç", + "thread_tools.move": "Konuyu Taşı", "thread_tools.move-posts": "İletiyi Taşı", "thread_tools.move_all": "Hepsini Taşı", "thread_tools.select_category": "Kategori Seç", - "thread_tools.fork": "Başlığı Ayır", - "thread_tools.delete": "Başlığı Sil", + "thread_tools.fork": "Konuyu Ayır", + "thread_tools.delete": "Konuyu Sil", "thread_tools.delete-posts": "İletileri Sil", "thread_tools.delete_confirm": "Bu konuyu gerçekten silmek istediğinize emin misiniz?", - "thread_tools.restore": "Başlığı Geri Getir", + "thread_tools.restore": "Konuyu Geri Getir", "thread_tools.restore_confirm": "Bu konuyu gerçekten geri getirmek istiyor musun?", "thread_tools.purge": "Konuyu Temizle", - "thread_tools.purge_confirm": "Bu konuyu temizlemek istediğinize eminmisiniz?", - "thread_tools.merge_topics": "Başlık Birleştir", + "thread_tools.purge_confirm": "Bu konuyu temizlemek istediğinize emin misiniz?", + "thread_tools.merge_topics": "Konu Birleştir", "thread_tools.merge": "Taşı", - "topic_move_success": "Başlık %1 kategorisine başarıyla taşındı.", + "topic_move_success": "Konu %1 kategorisine başarıyla taşındı.", "post_delete_confirm": "Bu iletiyi gerçekten silmek istediğinize emin misiniz?", "post_restore_confirm": "Bu iletiyi gerçekten geri getirmek istiyor musun?", "post_purge_confirm": "Bu iletiyi temizlemek istediğinize eminmisiniz?", @@ -86,7 +86,7 @@ "bookmarks": "Yer imleri", "bookmarks.has_no_bookmarks": "Henüz hiç bir iletiyi yer imine eklemedin", "loading_more_posts": "Daha fazla ileti ", - "move_topic": "Başlığı Taş", + "move_topic": "Konuyu Taşı", "move_topics": "Konuları Taşı", "move_post": "İletiyi Taşı", "post_moved": "İleti taşındı!", @@ -94,19 +94,19 @@ "fork_topic_instruction": "Ayırmak istediğiniz iletileri tıklayın", "fork_no_pids": "Hiçbir ileti seçilmedi!", "fork_pid_count": "%1 ileti(ler) seçildi", - "fork_success": "Başlık başarıyla ayrıldı!", + "fork_success": "Konu başarıyla ayrıldı!", "delete_posts_instruction": "Silmek/temizlemek istediğiniz iletilere tıklayın.", - "merge_topics_instruction": "Birleştirmek istediğiniz başlıklara tıklayın", + "merge_topics_instruction": "Birleştirmek istediğiniz konulara tıklayın", "move_posts_instruction": "Taşımak istediğin iletilere tıklayın", - "composer.title_placeholder": "Başlık ismini buraya girin...", + "composer.title_placeholder": "Konu ismini buraya girin...", "composer.handle_placeholder": "İsim", "composer.discard": "Vazgeç", "composer.submit": "Gönder", "composer.replying_to": "Yanıtlanan Konu %1", - "composer.new_topic": "Yeni Başlık", + "composer.new_topic": "Yeni Konu", "composer.uploading": "yükleniyor...", - "composer.thumb_url_label": "Başlık resmi adresi yapıştır", - "composer.thumb_title": "Bu başlığa bir resim ekle", + "composer.thumb_url_label": "Konu resmi adresi yapıştır", + "composer.thumb_title": "Bu konuya bir resim ekle", "composer.thumb_url_placeholder": "http://example.com/thumb.png", "composer.thumb_file_label": "Veya bir dosya yükle", "composer.thumb_remove": "Alanları temizle", @@ -120,14 +120,14 @@ "newest_to_oldest": "En yeniden en eskiye", "most_votes": "En Çok Oylanan", "most_posts": "En Çok Yazılan", - "stale.title": "Bunun yerine yeni bir başlık oluşturun?", + "stale.title": "Bunun yerine yeni bir konu oluşturun?", "stale.warning": "Yanıtlamak istediğin konu oldukca eskidir. Bu konuya referans oluşturacak yeni bir konu oluşturmak ister misin?", - "stale.create": "Yeni bir başlık yarat", + "stale.create": "Yeni bir konu yarat", "stale.reply_anyway": "Bu konuyu cevapla", "link_back": "Re: [%1](%2)", "diffs.title": "İleti Geçmiş Düzenle", "diffs.description": "Bu iletinin %1revizyonu var. Zaman içerisinde ileti içeriğinin tamamını görmek için aşağıdaki düzeltmelerden birine tıklayın.", "diffs.no-revisions-description": "Bu iletinin %1 revizyonu var.", - "diffs.current-revision": "Mevcut revizyon", - "diffs.original-revision": "Orijinal revizyon" + "diffs.current-revision": "mevcut revizyon", + "diffs.original-revision": "orijinal revizyon" } \ No newline at end of file diff --git a/public/language/tr/unread.json b/public/language/tr/unread.json index d45c31e8f9..29dbed8cc7 100644 --- a/public/language/tr/unread.json +++ b/public/language/tr/unread.json @@ -1,15 +1,15 @@ { "title": "Okunmamış", - "no_unread_topics": "Okunmamış başlık mevcut değil.", + "no_unread_topics": "Okunmamış konu mevcut değil.", "load_more": "Daha Fazla", "mark_as_read": "Okundu Olarak İşaretle", "selected": "Seçili", "all": "Hepsi", "all_categories": "Tüm kategoriler", - "topics_marked_as_read.success": "Başlıklar okundu olarak işaretlendi!", - "all-topics": "Tüm Başlıklar", - "new-topics": "Yeni Başlıklar", - "watched-topics": "İzlenen Başlıklar", - "unreplied-topics": "Okunmamış Başlıklar", + "topics_marked_as_read.success": "Konular okundu olarak işaretlendi!", + "all-topics": "Tüm Konular", + "new-topics": "Yeni Konular", + "watched-topics": "Takipteki Konular", + "unreplied-topics": "Okunmamış Konular", "multiple-categories-selected": "Çoklu Seçildi" } \ No newline at end of file diff --git a/public/language/tr/user.json b/public/language/tr/user.json index fc29e1b720..e391472d01 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -8,9 +8,9 @@ "email": "E-posta", "confirm_email": "Eposta Adresini Onayla", "account_info": "Hesap Bilgisi", - "ban_account": "Hesabı Dondur", - "ban_account_confirm": "Hesabı dondurmak istediğinizden emin misiniz!", - "unban_account": "Hesabı Kullanıma Aç", + "ban_account": "Hesabı Yasakla", + "ban_account_confirm": "Hesabı yasaklamak istediğinizden emin misiniz!", + "unban_account": "Hesabın Yasağını Kaldır", "delete_account": "Hesabı Sil", "delete_account_confirm": "Hesabınızı silmek istediğinize emin misiniz?
Bu işlem geri döndürülemez ve verilerinizin herhangi bir bölümünü kurtaramazsınız

Bu hesabı yoketme isteğinizi onaylamak için şifrenizi girin.", "delete_this_account_confirm": "Bu hesabı silmek istediğinizden emin misiniz?
Bu işlem geri döndürülemez ve hiç bir veriyi kurtaramazsınız

", @@ -26,8 +26,9 @@ "reputation": "Saygınlık", "bookmarks": "Yer İmleri", "watched_categories": "Takip edilen kategoriler", - "watched": "İzlendi", + "watched": "Takip edildi", "ignored": "Susturuldu", + "default-category-watch-state": "Default category watch state", "followers": "Takipçiler", "following": "Takip Ediyor", "blocks": "Blok", @@ -48,6 +49,7 @@ "change_picture": "Resmi Değiştir", "change_username": "Kullanıcı Adı Değiştir", "change_email": "E-posta Değiştir", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Düzenle", "edit-profile": "Profil Düzenle", "default_picture": "Varsayılan İkon", @@ -87,9 +89,9 @@ "has_no_follower": "Bu kullanıcının hiç takipçisi yok :(", "follows_no_one": "Bu kullanıcı kimseyi takip etmiyor :(", "has_no_posts": "Bu kullanıcı henüz herhangi bir ileti yazmamış.", - "has_no_topics": "Bu kullanıcı henüz hiç bir başlık açmamış.", - "has_no_watched_topics": "Bu kullanıcı henüz hiç bir başlık okumamış.", - "has_no_ignored_topics": "Bu kullanıcı henüz hiçbir başlığı yok saymadı.", + "has_no_topics": "Bu kullanıcı henüz hiç bir konu açmamış.", + "has_no_watched_topics": "Bu kullanıcı henüz hiç bir konu okumamış.", + "has_no_ignored_topics": "Bu kullanıcı henüz hiçbir konuyu yok saymadı.", "has_no_upvoted_posts": "Bu kullanıcı henüz hiç bir gönderiyi artılamamış.", "has_no_downvoted_posts": "Bu kullanıcı henüz hiç bir gönderiyi eksilememiş.", "has_no_voted_posts": "Bu kullanıcının hiç oylanmış gönderisi yok.", @@ -108,7 +110,7 @@ "notification-sound": "Bildirim sesi", "no-sound": "Ses yok", "upvote-notif-freq": "Artı Oy Bildiri Sıklığı", - "upvote-notif-freq.all": "Büyün Artı Oylar", + "upvote-notif-freq.all": "Bütün Artı Oylar", "upvote-notif-freq.first": "İleti Başına İlk", "upvote-notif-freq.everyTen": "Her Artı On Oy", "upvote-notif-freq.threshold": "1, 5, 10, 25, 50, 100, 150, 200...", @@ -119,11 +121,11 @@ "enable_topic_searching": "Konu içi aramayı aktive et", "topic_search_help": "Aktive edilirse, konu içi arama tarayıcının normal arama davranışını değiştirerek tüm konuyu aramanızı sağlar", "scroll_to_my_post": "Cevap yazdıktan sonra yeni gönderiyi göster", - "follow_topics_you_reply_to": "Cevap verdiğin başlıkları izle", - "follow_topics_you_create": "Oluşturduğunuz başlıkları izle", + "follow_topics_you_reply_to": "Cevap verdiğim konuları takip et", + "follow_topics_you_create": "Oluşturduğum konuları takip et", "grouptitle": "Grup Başlığı", "no-group-title": "Grup başlığı yok", - "select-skin": "Bir deri şeçin", + "select-skin": "Bir tema seçin", "select-homepage": "Bir anasayfa seçin", "homepage": "Anasayfa", "homepage_description": "Anasayfa olarak kullanacağınız sayfayı seçin veya \"Hiçbiri\" diyerek varsayılan sayfayı kullanın.", diff --git a/public/language/uk/admin/settings/user.json b/public/language/uk/admin/settings/user.json index 6ee75a05ab..cb24270d1c 100644 --- a/public/language/uk/admin/settings/user.json +++ b/public/language/uk/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Надсилати листа, коли в темах на які я підписаний з'являються відповіді", "follow-created-topics": "Стежити за темами які ви створюєте", "follow-replied-topics": "Стежити за темами в котрих ви відповідаєте", - "default-notification-settings": "Стандартні налаштування сповіщень" + "default-notification-settings": "Стандартні налаштування сповіщень", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/uk/category.json b/public/language/uk/category.json index bdd53de08b..0ebb159ac6 100644 --- a/public/language/uk/category.json +++ b/public/language/uk/category.json @@ -7,14 +7,16 @@ "browsing": "переглядають", "no_replies": "Немає відповідей", "no_new_posts": "Немає нових постів.", - "share_this_category": "Поділитися цією категорією", "watch": "Стежити", "ignore": "Ігнорувати", "watching": "Відстежується", + "not-watching": "Not Watching", "ignoring": "Ігнорувати", - "watching.description": "Показати тему в непрочитаних", - "ignoring.description": "Не показувати тему в непрочитаних", - "watch.message": "Ви переглядаєте оновлення цієї категорії та підкатегорії", - "ignore.message": "Ви ігноруєте оновлення цієї категорії та її підкатегорій", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Переглянуті категорії" } \ No newline at end of file diff --git a/public/language/uk/notifications.json b/public/language/uk/notifications.json index 34d481c560..0015cd1c7f 100644 --- a/public/language/uk/notifications.json +++ b/public/language/uk/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Коли хтось починає слідкувати за вами", "notificationType_new-chat": "Коли ви отримуєте повідомлення чату", "notificationType_group-invite": "Коли ви отримуєте запрошення до групи", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Коли когось додано до черги на реєстрацію", "notificationType_post-queue": "Коли новий пост знаходиться в черзі", "notificationType_new-post-flag": "Коли повідомлення позначено", diff --git a/public/language/uk/user.json b/public/language/uk/user.json index d709efbe55..22be9c69d2 100644 --- a/public/language/uk/user.json +++ b/public/language/uk/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Переглянуті", "ignored": "Ігнорується", + "default-category-watch-state": "Default category watch state", "followers": "Відстежувачі", "following": "Відстежувані", "blocks": "Блокування", @@ -48,6 +49,7 @@ "change_picture": "Змінити зображення", "change_username": "Змінити ім'я користувача", "change_email": "Змінити електронну пошту", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Редагувати", "edit-profile": "Редагувати профіль", "default_picture": "Стандартна іконка", diff --git a/public/language/vi/admin/settings/user.json b/public/language/vi/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/vi/admin/settings/user.json +++ b/public/language/vi/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/vi/category.json b/public/language/vi/category.json index f9cf6a500a..e2d279794d 100644 --- a/public/language/vi/category.json +++ b/public/language/vi/category.json @@ -7,14 +7,16 @@ "browsing": "đang xem", "no_replies": "Chưa có bình luận nào", "no_new_posts": "Không có bài mới.", - "share_this_category": "Chia sẻ chuyên mục này", "watch": "Quan tâm", "ignore": "Bỏ qua", "watching": "Đang quan tâm", + "not-watching": "Not Watching", "ignoring": "Bỏ qua", - "watching.description": "Hiện các chủ đề chưa đọc", - "ignoring.description": "Không hiện những chủ đề chưa đọc", - "watch.message": "Bạn đang theo dõi các cập nhật ở chuyên mục này và các chuyên mục con", - "ignore.message": "Bạn đang bỏ qua các cập nhật ở chuyên mục này và các chuyên mục con", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "Các chuyên mục đã quan tâm" } \ No newline at end of file diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json index d9a4057312..8f3c8ccf87 100644 --- a/public/language/vi/notifications.json +++ b/public/language/vi/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "Khi ai đó theo dõi bạn", "notificationType_new-chat": "Khi bạn nhận được thông điệp chat", "notificationType_group-invite": "Khi bạn nhận được lời mời gia nhập nhóm", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "Khi ai đó được thêm vào lượt chờ đăng ký", "notificationType_post-queue": "Khi bài đăng được thêm vào lượt chờ", "notificationType_new-post-flag": "Khi bài đăng được cảnh báo", diff --git a/public/language/vi/user.json b/public/language/vi/user.json index d8f53a8f5e..b069abbff1 100644 --- a/public/language/vi/user.json +++ b/public/language/vi/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "Đã quan tâm", "ignored": "Phớt lờ", + "default-category-watch-state": "Default category watch state", "followers": "Số người theo dõi", "following": "Đang theo dõi", "blocks": "Khóa", @@ -48,6 +49,7 @@ "change_picture": "Thay đổi hình ảnh", "change_username": "Đổi tên đăng nhập", "change_email": "Đổi email", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "Chỉnh sửa", "edit-profile": "Sửa thông tin cá nhân", "default_picture": "Icon mặc định", diff --git a/public/language/zh-CN/admin/admin.json b/public/language/zh-CN/admin/admin.json index 4c36fa9cc2..5bd6c878bd 100644 --- a/public/language/zh-CN/admin/admin.json +++ b/public/language/zh-CN/admin/admin.json @@ -2,6 +2,6 @@ "alert.confirm-rebuild-and-restart": "您确定要部署并重启 NodeBB 吗?", "alert.confirm-restart": "您确定要重启 NodeBB 吗?", - "acp-title": "%1 | NodeBB 控制面板", + "acp-title": "%1 | NodeBB 管理员控制面板", "settings-header-contents": "内容" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/advanced/database.json b/public/language/zh-CN/admin/advanced/database.json index 6fe4a9358b..fad0bff091 100644 --- a/public/language/zh-CN/admin/advanced/database.json +++ b/public/language/zh-CN/admin/advanced/database.json @@ -20,14 +20,14 @@ "mongo.mapped-memory": "已映射内存", "mongo.bytes-in": "Bytes In", "mongo.bytes-out": "Bytes Out", - "mongo.num-requests": "Number of Requests", + "mongo.num-requests": "请求数量", "mongo.raw-info": "MongoDB 原始信息", "redis": "Redis", "redis.version": "Redis 版本", - "redis.keys": "Keys", - "redis.expires": "Expires", - "redis.avg-ttl": "Average TTL", + "redis.keys": "键", + "redis.expires": "有效期", + "redis.avg-ttl": "平均生存时间(TTL通常表示包在被丢弃前最多能经过的路由器个数,由发送主机设置)", "redis.connected-clients": "已连接客户端", "redis.connected-slaves": "已连接从", "redis.blocked-clients": "受阻的客户端", diff --git a/public/language/zh-CN/admin/settings/user.json b/public/language/zh-CN/admin/settings/user.json index 70e6be100e..1b10507fbb 100644 --- a/public/language/zh-CN/admin/settings/user.json +++ b/public/language/zh-CN/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "当我订阅的主题有新回复时,给我发送邮件通知", "follow-created-topics": "关注您创建的主题", "follow-replied-topics": "关注您回复的主题", - "default-notification-settings": "默认通知设置" + "default-notification-settings": "默认通知设置", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/zh-CN/category.json b/public/language/zh-CN/category.json index 4c9902d3d8..4ea0397b66 100644 --- a/public/language/zh-CN/category.json +++ b/public/language/zh-CN/category.json @@ -7,14 +7,16 @@ "browsing": "正在浏览", "no_replies": "尚无回复", "no_new_posts": "没有新主题", - "share_this_category": "分享此版块", "watch": "关注", "ignore": "忽略", "watching": "已关注", + "not-watching": "Not Watching", "ignoring": "已忽略", - "watching.description": "显示未读主题", - "ignoring.description": "不显示未读主题", - "watch.message": "您关注了此版块的动态。", - "ignore.message": "您未关注此版块的动态。", + "watching.description": "显示未读和最近的主题", + "not-watching.description": "不显示未读主题,显示最近主题", + "ignoring.description": "不显示未读和最近的主题", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "已关注的版块" } \ No newline at end of file diff --git a/public/language/zh-CN/notifications.json b/public/language/zh-CN/notifications.json index 699dc72652..32e8a6b9f2 100644 --- a/public/language/zh-CN/notifications.json +++ b/public/language/zh-CN/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "当有人关注您时", "notificationType_new-chat": "当您收到聊天消息时", "notificationType_group-invite": "当您收到群组邀请时", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "当有人被添加到申请队列时", "notificationType_post-queue": "当有新帖子等待审核时", "notificationType_new-post-flag": "当有新的帖子举报时", diff --git a/public/language/zh-CN/user.json b/public/language/zh-CN/user.json index 938bd7b6d0..e19808dad7 100644 --- a/public/language/zh-CN/user.json +++ b/public/language/zh-CN/user.json @@ -28,6 +28,7 @@ "watched_categories": "已关注的版块", "watched": "已关注", "ignored": "忽略", + "default-category-watch-state": "Default category watch state", "followers": "粉丝", "following": "关注", "blocks": "屏蔽", @@ -48,6 +49,7 @@ "change_picture": "更改头像", "change_username": "更改用户名", "change_email": "更改电子邮箱", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "编辑", "edit-profile": "编辑资料", "default_picture": "默认图标", diff --git a/public/language/zh-TW/admin/settings/user.json b/public/language/zh-TW/admin/settings/user.json index 0268336e5a..a504f5ef8d 100644 --- a/public/language/zh-TW/admin/settings/user.json +++ b/public/language/zh-TW/admin/settings/user.json @@ -70,5 +70,9 @@ "email-post-notif": "Send an email when replies are made to topics I am subscribed to", "follow-created-topics": "Follow topics you create", "follow-replied-topics": "Follow topics that you reply to", - "default-notification-settings": "Default notification settings" + "default-notification-settings": "Default notification settings", + "categoryWatchState": "Default category watch state", + "categoryWatchState.watching": "Watching", + "categoryWatchState.notwatching": "Not Watching", + "categoryWatchState.ignoring": "Ignoring" } \ No newline at end of file diff --git a/public/language/zh-TW/category.json b/public/language/zh-TW/category.json index 06bd70351d..86eb793e4b 100644 --- a/public/language/zh-TW/category.json +++ b/public/language/zh-TW/category.json @@ -7,14 +7,16 @@ "browsing": "正在瀏覽", "no_replies": "還沒有回覆", "no_new_posts": "沒有新的張貼", - "share_this_category": "分享這類別", "watch": "關注", "ignore": "忽略", "watching": "關注", + "not-watching": "未關注", "ignoring": "忽略", - "watching.description": "顯示未讀的主題", - "ignoring.description": "不要顯示未讀的主題", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", + "watching.description": "Show topics in unread and recent", + "not-watching.description": "Do not show topics in unread, show in recent", + "ignoring.description": "Do not show topics in unread and recent", + "watching.message": "You are now watching updates from this category and all subcategories", + "notwatching.message": "You are not watching updates from this category and all subcategories", + "ignoring.message": "You are now ignoring updates from this category and all subcategories", "watched-categories": "關注的類別" } \ No newline at end of file diff --git a/public/language/zh-TW/global.json b/public/language/zh-TW/global.json index 2ef28ccf7a..8c453a3d1f 100644 --- a/public/language/zh-TW/global.json +++ b/public/language/zh-TW/global.json @@ -19,7 +19,7 @@ "welcome_back": "歡迎回來!", "you_have_successfully_logged_in": "你已成功登入!", "save_changes": "儲存變更", - "save": "Save", + "save": "儲存", "close": "關閉", "pagination": "分頁", "pagination.out_of": "%1 於 %2", diff --git a/public/language/zh-TW/notifications.json b/public/language/zh-TW/notifications.json index 4d91597886..784dc0447f 100644 --- a/public/language/zh-TW/notifications.json +++ b/public/language/zh-TW/notifications.json @@ -56,6 +56,7 @@ "notificationType_follow": "When someone starts following you", "notificationType_new-chat": "When you receive a chat message", "notificationType_group-invite": "When you receive a group invite", + "notificationType_group-request-membership": "When someone requests to join a group you own", "notificationType_new-register": "When someone gets added to registration queue", "notificationType_post-queue": "When a new post is queued", "notificationType_new-post-flag": "When a post is flagged", diff --git a/public/language/zh-TW/user.json b/public/language/zh-TW/user.json index 3a780c93a8..2e6a45f06f 100644 --- a/public/language/zh-TW/user.json +++ b/public/language/zh-TW/user.json @@ -28,6 +28,7 @@ "watched_categories": "Watched categories", "watched": "觀看者", "ignored": "Ignored", + "default-category-watch-state": "Default category watch state", "followers": "跟隨者", "following": "正在關注", "blocks": "Blocks", @@ -48,6 +49,7 @@ "change_picture": "改變頭像", "change_username": "更改帳號", "change_email": "更改電子郵件", + "email_same_as_password": "Please enter your current password to continue – you've entered your new email again", "edit": "編輯", "edit-profile": "編輯個人資料", "default_picture": "預設圖示", diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 16dff9d563..9a772ae08e 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -23,6 +23,7 @@ @import "./extend/rewards"; @import "./extend/widgets"; @import "./advanced/database"; +@import "./advanced/events"; @import "./advanced/logs"; @import "./advanced/errors"; @import "./advanced/hooks"; diff --git a/public/less/admin/advanced/events.less b/public/less/admin/advanced/events.less new file mode 100644 index 0000000000..1ab80d047c --- /dev/null +++ b/public/less/admin/advanced/events.less @@ -0,0 +1,6 @@ +.delete-event { + i { + cursor: pointer; + margin-left: 10px; + } +} \ No newline at end of file diff --git a/public/less/admin/general/navigation.less b/public/less/admin/general/navigation.less index 583ec382e1..9d0316ee3a 100644 --- a/public/less/admin/general/navigation.less +++ b/public/less/admin/general/navigation.less @@ -1,4 +1,13 @@ #navigation { + .fa-nbb-none { + display: inline-block; + width: 16px; + height: 16px; + border: 2px dashed #aaa; + position: relative; + top: 0.2em; + } + #active-navigation { float: none; min-height: 50px; diff --git a/public/src/admin/advanced/events.js b/public/src/admin/advanced/events.js index 0645f8e799..42895451dc 100644 --- a/public/src/admin/advanced/events.js +++ b/public/src/admin/advanced/events.js @@ -14,6 +14,17 @@ define('admin/advanced/events', function () { }); }); + $('.delete-event').on('click', function () { + var parentEl = $(this).parents('[data-eid]'); + var eid = parentEl.attr('data-eid'); + socket.emit('admin.deleteEvents', [eid], function (err) { + if (err) { + return app.alertError(err.message); + } + parentEl.remove(); + }); + }); + $('#filter').on('change', function () { var filter = $(this).val(); ajaxify.go('admin/advanced/events' + (filter ? '?filter=' + filter : '')); diff --git a/public/src/admin/manage/admins-mods.js b/public/src/admin/manage/admins-mods.js index 9f642f1456..1c7022339a 100644 --- a/public/src/admin/manage/admins-mods.js +++ b/public/src/admin/manage/admins-mods.js @@ -103,7 +103,7 @@ define('admin/manage/admins-mods', ['translator', 'benchpress', 'autocomplete'], return; } - app.parseAndTranslate('admin/manage/admins-mods', 'globalMods', { globalMods: [ui.item.user] }, function (html) { + app.parseAndTranslate('admin/manage/admins-mods', 'globalMods.members', { globalMods: { members: [ui.item.user] } }, function (html) { $('.moderator-area[data-cid="' + cid + '"]').prepend(html); $('.no-moderator-warning[data-cid="' + cid + '"]').addClass('hidden'); }); diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index 31d0b0a6ef..6a8372dc88 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -39,16 +39,9 @@ define('admin/manage/category', [ handleTags(); - $('#category-settings input, #category-settings select').not($('.privilege-table-container input')) - .on('change', function (ev) { - modified(ev.target); - }) - .on('keydown', function (ev) { - if (ev.which === 13) { - ev.preventDefault(); - return false; - } - }); + $('#category-settings input, #category-settings select').on('change', function (ev) { + modified(ev.target); + }); $('[data-name="imageClass"]').on('change', function () { $('.category-preview').css('background-size', $(this).val()); diff --git a/public/src/app.js b/public/src/app.js index e2783f17b2..c1a21be21e 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -124,6 +124,10 @@ app.cacheBuster = null; config = data.config; Benchpress.setGlobal('config', config); + var htmlEl = $('html'); + htmlEl.attr('data-dir', data.header.languageDirection); + htmlEl.css('direction', data.header.languageDirection); + // Manually reconnect socket.io socket.close(); socket.open(); @@ -145,8 +149,15 @@ app.cacheBuster = null; Unread.initUnreadTopics(); Notifications.prepareDOM(); Chat.prepareDOM(); - app.reskin(data.config.bootswatchSkin); + app.reskin(data.header.bootswatchSkin); translator.switchTimeagoLanguage(callback); + bootbox.setLocale(config.userLang); + + if (config.searchEnabled) { + app.handleSearch(); + } + + $(window).trigger('action:app.updateHeader'); }); }); }; @@ -183,6 +194,11 @@ app.cacheBuster = null; $(window).trigger('action:app.loggedOut', data); if (data.next) { + if (data.next.startsWith('http')) { + window.location.href = data.next; + return; + } + ajaxify.go(data.next); } else { ajaxify.refresh(); @@ -236,6 +252,8 @@ app.cacheBuster = null; app.flags = app.flags || {}; app.flags._sessionRefresh = true; + socket.disconnect(); + require(['translator'], function (translator) { translator.translate('[[error:invalid-session-text]]', function (translated) { bootbox.alert({ @@ -283,12 +301,12 @@ app.cacheBuster = null; }; function highlightNavigationLink() { - var path = window.location.pathname + window.location.search; - $('#main-nav li').removeClass('active'); - if (path) { - $('#main-nav li').removeClass('active').find('a[href="' + path + '"]').parent() - .addClass('active'); - } + $('#main-nav li') + .removeClass('active') + .find('a') + .filter(function (i, x) { return window.location.pathname.startsWith(x.getAttribute('href')); }) + .parent() + .addClass('active'); } app.createUserTooltips = function (els, placement) { @@ -756,15 +774,30 @@ app.cacheBuster = null; if (!clientEl) { return; } - // Update client.css link element to point to selected skin variant - clientEl.href = config.relative_path + '/assets/client' + (skinName ? '-' + skinName : '') + '.css'; var currentSkinClassName = $('body').attr('class').split(/\s+/).filter(function (className) { return className.startsWith('skin-'); }); - $('body').removeClass(currentSkinClassName.join(' ')); - if (skinName) { - $('body').addClass('skin-' + skinName); + var currentSkin = currentSkinClassName[0].slice(5); + currentSkin = currentSkin !== 'noskin' ? currentSkin : ''; + + // Stop execution if skin didn't change + if (skinName === currentSkin) { + return; } + + var linkEl = document.createElement('link'); + linkEl.rel = 'stylesheet'; + linkEl.type = 'text/css'; + linkEl.href = config.relative_path + '/assets/client' + (skinName ? '-' + skinName : '') + '.css'; + linkEl.onload = function () { + clientEl.parentNode.removeChild(clientEl); + + // Update body class with proper skin name + $('body').removeClass(currentSkinClassName.join(' ')); + $('body').addClass('skin-' + (skinName || 'noskin')); + }; + + document.head.appendChild(linkEl); }; }()); diff --git a/public/src/client/account/categories.js b/public/src/client/account/categories.js index b5feb6faa6..7acebaec4a 100644 --- a/public/src/client/account/categories.js +++ b/public/src/client/account/categories.js @@ -14,25 +14,28 @@ define('forum/account/categories', ['forum/account/header'], function (header) { function handleIgnoreWatch(cid) { var category = $('[data-cid="' + cid + '"]'); - category.find('[component="category/watching"], [component="category/ignoring"]').on('click', function () { + category.find('[component="category/watching"], [component="category/ignoring"], [component="category/notwatching"]').on('click', function () { var $this = $(this); - var command = $this.attr('component') === 'category/watching' ? 'watch' : 'ignore'; + var state = $this.attr('data-state'); - socket.emit('categories.' + command, { cid: cid, uid: ajaxify.data.uid }, function (err, modified_cids) { + socket.emit('categories.setWatchState', { cid: cid, state: state, uid: ajaxify.data.uid }, function (err, modified_cids) { if (err) { return app.alertError(err.message); } modified_cids.forEach(function (cid) { var category = $('[data-cid="' + cid + '"]'); - category.find('[component="category/watching/menu"]').toggleClass('hidden', command !== 'watch'); - category.find('[component="category/watching/check"]').toggleClass('fa-check', command === 'watch'); + category.find('[component="category/watching/menu"]').toggleClass('hidden', state !== 'watching'); + category.find('[component="category/watching/check"]').toggleClass('fa-check', state === 'watching'); - category.find('[component="category/ignoring/menu"]').toggleClass('hidden', command !== 'ignore'); - category.find('[component="category/ignoring/check"]').toggleClass('fa-check', command === 'ignore'); + category.find('[component="category/notwatching/menu"]').toggleClass('hidden', state !== 'notwatching'); + category.find('[component="category/notwatching/check"]').toggleClass('fa-check', state === 'notwatching'); + + category.find('[component="category/ignoring/menu"]').toggleClass('hidden', state !== 'ignoring'); + category.find('[component="category/ignoring/check"]').toggleClass('fa-check', state === 'ignoring'); }); - app.alertSuccess('[[category:' + command + '.message]]'); + app.alertSuccess('[[category:' + state + '.message]]'); }); }); } diff --git a/public/src/client/account/edit/email.js b/public/src/client/account/edit/email.js index ae182029f0..28bac37978 100644 --- a/public/src/client/account/edit/email.js +++ b/public/src/client/account/edit/email.js @@ -8,10 +8,11 @@ define('forum/account/edit/email', ['forum/account/header'], function (header) { header.init(); $('#submitBtn').on('click', function () { + var curPasswordEl = $('#inputCurrentPassword'); var userData = { uid: $('#inputUID').val(), email: $('#inputNewEmail').val(), - password: $('#inputCurrentPassword').val(), + password: curPasswordEl.val(), }; if (!userData.email) { @@ -19,6 +20,7 @@ define('forum/account/edit/email', ['forum/account/header'], function (header) { } if (userData.email === userData.password) { + curPasswordEl.parents('.control-group').toggleClass('has-error', true); return app.alertError('[[user:email_same_as_password]]'); } diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js index 62358760d5..37d6f93f19 100644 --- a/public/src/client/account/settings.js +++ b/public/src/client/account/settings.js @@ -1,7 +1,7 @@ 'use strict'; -define('forum/account/settings', ['forum/account/header', 'components', 'sounds'], function (header, components, sounds) { +define('forum/account/settings', ['forum/account/header', 'components', 'sounds', 'translator'], function (header, components, sounds, translator) { var AccountSettings = {}; // If page skin is changed but not saved, switch the skin back @@ -96,6 +96,11 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' sounds.loadMap(); if (requireReload && parseInt(app.user.uid, 10) === parseInt(ajaxify.data.theirid, 10)) { + translator.translate('[[language:dir]]', config.userLang, function (translated) { + var htmlEl = $('html'); + htmlEl.attr('data-dir', translated); + htmlEl.css('direction', translated); + }); ajaxify.refresh(); } }); diff --git a/public/src/client/category.js b/public/src/client/category.js index 9fdd4dcd5b..f02eeb7c40 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -62,22 +62,25 @@ define('forum/category', [ } function handleIgnoreWatch(cid) { - $('[component="category/watching"], [component="category/ignoring"]').on('click', function () { + $('[component="category/watching"], [component="category/ignoring"], [component="category/notwatching"]').on('click', function () { var $this = $(this); - var command = $this.attr('component') === 'category/watching' ? 'watch' : 'ignore'; + var state = $this.attr('data-state'); - socket.emit('categories.' + command, cid, function (err) { + socket.emit('categories.setWatchState', { cid: cid, state: state }, function (err) { if (err) { return app.alertError(err.message); } - $('[component="category/watching/menu"]').toggleClass('hidden', command !== 'watch'); - $('[component="category/watching/check"]').toggleClass('fa-check', command === 'watch'); + $('[component="category/watching/menu"]').toggleClass('hidden', state !== 'watching'); + $('[component="category/watching/check"]').toggleClass('fa-check', state === 'watching'); - $('[component="category/ignoring/menu"]').toggleClass('hidden', command !== 'ignore'); - $('[component="category/ignoring/check"]').toggleClass('fa-check', command === 'ignore'); + $('[component="category/notwatching/menu"]').toggleClass('hidden', state !== 'notwatching'); + $('[component="category/notwatching/check"]').toggleClass('fa-check', state === 'notwatching'); - app.alertSuccess('[[category:' + command + '.message]]'); + $('[component="category/ignoring/menu"]').toggleClass('hidden', state !== 'ignoring'); + $('[component="category/ignoring/check"]').toggleClass('fa-check', state === 'ignoring'); + + app.alertSuccess('[[category:' + state + '.message]]'); }); }); } diff --git a/public/src/client/category/tools.js b/public/src/client/category/tools.js index 6dca6671a3..ae0358d966 100644 --- a/public/src/client/category/tools.js +++ b/public/src/client/category/tools.js @@ -259,12 +259,15 @@ define('forum/category/tools', [ return; } app.loadJQueryUI(function () { - $('[component="category"]').sortable({ + var topicListEl = $('[component="category"]').filter(function (i, e) { + return !$(e).parents('[widget-area]').length; + }); + topicListEl.sortable({ items: '[component="category/topic"].pinned', update: function () { var data = []; - var pinnedTopics = $('[component="category/topic"].pinned'); + var pinnedTopics = topicListEl.find('[component="category/topic"].pinned'); pinnedTopics.each(function (index, element) { data.push({ tid: $(element).attr('data-tid'), order: pinnedTopics.length - index - 1 }); }); diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 65534df0aa..10704698ac 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -40,6 +40,7 @@ define('forum/groups/details', [ paramName: 'groupName', paramValue: groupName, }, function (imageUrlOnServer) { + imageUrlOnServer = (!imageUrlOnServer.startsWith('http') ? config.relative_path : '') + imageUrlOnServer + '?' + Date.now(); components.get('groups/cover').css('background-image', 'url(' + imageUrlOnServer + ')'); }); }, diff --git a/public/src/client/groups/list.js b/public/src/client/groups/list.js index 72536a1352..d263639b85 100644 --- a/public/src/client/groups/list.js +++ b/public/src/client/groups/list.js @@ -70,6 +70,8 @@ define('forum/groups/list', ['forum/infinitescroll', 'benchpress'], function (in options: { sort: sortEl.val(), filterHidden: true, + showMembers: true, + hideEphemeralGroups: true, }, }, function (err, groups) { if (err) { diff --git a/public/src/client/header/chat.js b/public/src/client/header/chat.js index ccd7aa0098..fbea548f03 100644 --- a/public/src/client/header/chat.js +++ b/public/src/client/header/chat.js @@ -18,19 +18,28 @@ define('forum/header/chat', ['components'], function (components) { requireAndCall('loadChatsDropdown', chatsListEl); } - socket.on('event:chats.receive', function (data) { - requireAndCall('onChatMessageReceived', data); - }); + socket.removeListener('event:chats.receive', onChatMessageReceived); + socket.on('event:chats.receive', onChatMessageReceived); - socket.on('event:user_status_change', function (data) { - requireAndCall('onUserStatusChange', data); - }); + socket.removeListener('event:user_status_change', onUserStatusChange); + socket.on('event:user_status_change', onUserStatusChange); - socket.on('event:chats.roomRename', function (data) { - requireAndCall('onRoomRename', data); - }); + socket.removeListener('event:chats.roomRename', onRoomRename); + socket.on('event:chats.roomRename', onRoomRename); }; + function onChatMessageReceived(data) { + requireAndCall('onChatMessageReceived', data); + } + + function onUserStatusChange(data) { + requireAndCall('onUserStatusChange', data); + } + + function onRoomRename(data) { + requireAndCall('onRoomRename', data); + } + function requireAndCall(method, param) { require(['chat'], function (chat) { chat[method](param); diff --git a/public/src/client/header/notifications.js b/public/src/client/header/notifications.js index ff532f52c7..b30535f0fd 100644 --- a/public/src/client/header/notifications.js +++ b/public/src/client/header/notifications.js @@ -21,15 +21,21 @@ define('forum/header/notifications', ['components'], function (components) { requireAndCall('loadNotifications', notifList); } - socket.on('event:new_notification', function (data) { - requireAndCall('onNewNotification', data); - }); + socket.removeListener('event:new_notification', onNewNotification); + socket.on('event:new_notification', onNewNotification); - socket.on('event:notifications.updateCount', function (data) { - requireAndCall('updateNotifCount', data); - }); + socket.removeListener('event:notifications.updateCount', onUpdateCount); + socket.on('event:notifications.updateCount', onUpdateCount); }; + function onNewNotification(data) { + requireAndCall('onNewNotification', data); + } + + function onUpdateCount(data) { + requireAndCall('updateNotifCount', data); + } + function requireAndCall(method, param) { require(['notifications'], function (notifications) { notifications[method](param); diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index e7be097e79..f4f69ef215 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -60,9 +60,9 @@ define('forum/topic/postTools', [ postEl.find('[component="post/quote"], [component="post/bookmark"], [component="post/reply"], [component="post/flag"], [component="user/chat"]') .toggleClass('hidden', isDeleted); - postEl.find('[component="post/delete"]').toggleClass('hidden', isDeleted); - postEl.find('[component="post/restore"]').toggleClass('hidden', !isDeleted); - postEl.find('[component="post/purge"]').toggleClass('hidden', !isDeleted); + postEl.find('[component="post/delete"]').toggleClass('hidden', isDeleted).parent().attr('hidden', isDeleted ? '' : null); + postEl.find('[component="post/restore"]').toggleClass('hidden', !isDeleted).parent().attr('hidden', !isDeleted ? '' : null); + postEl.find('[component="post/purge"]').toggleClass('hidden', !isDeleted).parent().attr('hidden', !isDeleted ? '' : null); PostTools.removeMenu(postEl); }; diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index 14d581a80f..7fc6ced0e9 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -183,8 +183,8 @@ define('forum/topic/threadTools', [ var isLocked = data.isLocked && !ajaxify.data.privileges.isAdminOrMod; - components.get('topic/lock').toggleClass('hidden', data.isLocked); - components.get('topic/unlock').toggleClass('hidden', !data.isLocked); + components.get('topic/lock').toggleClass('hidden', data.isLocked).parent().attr('hidden', data.isLocked ? '' : null); + components.get('topic/unlock').toggleClass('hidden', !data.isLocked).parent().attr('hidden', !data.isLocked ? '' : null); var hideReply = (data.isLocked || ajaxify.data.deleted) && !ajaxify.data.privileges.isAdminOrMod; @@ -207,9 +207,9 @@ define('forum/topic/threadTools', [ return; } - components.get('topic/delete').toggleClass('hidden', data.isDelete); - components.get('topic/restore').toggleClass('hidden', !data.isDelete); - components.get('topic/purge').toggleClass('hidden', !data.isDelete); + components.get('topic/delete').toggleClass('hidden', data.isDelete).parent().attr('hidden', data.isDelete ? '' : null); + components.get('topic/restore').toggleClass('hidden', !data.isDelete).parent().attr('hidden', !data.isDelete ? '' : null); + components.get('topic/purge').toggleClass('hidden', !data.isDelete).parent().attr('hidden', !data.isDelete ? '' : null); components.get('topic/deleted/message').toggleClass('hidden', !data.isDelete); var hideReply = data.isDelete && !ajaxify.data.privileges.isAdminOrMod; @@ -229,8 +229,8 @@ define('forum/topic/threadTools', [ return; } - components.get('topic/pin').toggleClass('hidden', data.isPinned); - components.get('topic/unpin').toggleClass('hidden', !data.isPinned); + components.get('topic/pin').toggleClass('hidden', data.isPinned).parent().attr('hidden', data.isPinned ? '' : null); + components.get('topic/unpin').toggleClass('hidden', !data.isPinned).parent().attr('hidden', !data.isPinned ? '' : null); $('[component="post/header"] i.fa-thumb-tack').toggleClass('hidden', !data.isPinned); ajaxify.data.pinned = data.isPinned; }; diff --git a/public/src/client/unread.js b/public/src/client/unread.js index 9df088a16f..504f72e613 100644 --- a/public/src/client/unread.js +++ b/public/src/client/unread.js @@ -4,6 +4,12 @@ define('forum/unread', ['topicSelect', 'components', 'topicList'], function (topicSelect, components, topicList) { var Unread = {}; + var watchStates = { + ignoring: 1, + notwatching: 2, + watching: 3, + }; + Unread.init = function () { app.enterRoom('unread_topics'); @@ -90,46 +96,49 @@ define('forum/unread', ['topicSelect', 'components', 'topicList'], function (top } Unread.initUnreadTopics = function () { - var unreadTopics = {}; + var unreadTopics = app.user.unreadData; function onNewPost(data) { if (data && data.posts && data.posts.length) { var post = data.posts[0]; + if (parseInt(post.uid, 10) === parseInt(app.user.uid, 10) || + (!post.topic.isFollowing && post.categoryWatchState !== watchStates.watching) + ) { + return; + } - if (parseInt(post.uid, 10) !== parseInt(app.user.uid, 10) && !unreadTopics[post.topic.tid]) { - increaseUnreadCount(post); - markTopicsUnread(post.topic.tid); - unreadTopics[post.topic.tid] = true; + var tid = post.topic.tid; + if (!unreadTopics[''][tid] || !unreadTopics.new[tid] || + !unreadTopics.watched[tid] || !unreadTopics.unreplied[tid]) { + markTopicsUnread(tid); + } + + if (!unreadTopics[''][tid]) { + increaseUnreadCount(''); + unreadTopics[''][tid] = true; + } + var isNewTopic = post.isMain && parseInt(post.uid, 10) !== parseInt(app.user.uid, 10); + if (isNewTopic && !unreadTopics.new[tid]) { + increaseUnreadCount('new'); + unreadTopics.new[tid] = true; + } + var isUnreplied = parseInt(post.topic.postcount, 10) <= 1; + if (isUnreplied && !unreadTopics.unreplied[tid]) { + increaseUnreadCount('unreplied'); + unreadTopics.unreplied[tid] = true; + } + + if (post.topic.isFollowing && !unreadTopics.watched[tid]) { + increaseUnreadCount('watched'); + unreadTopics.watched[tid] = true; } } } - function increaseUnreadCount(post) { - var unreadTopicCount = parseInt($('a[href="' + config.relative_path + '/unread"].navigation-link i').attr('data-content'), 10) + 1; - updateUnreadTopicCount('/unread', unreadTopicCount); - - var isNewTopic = post.isMain && parseInt(post.uid, 10) !== parseInt(app.user.uid, 10); - if (isNewTopic) { - var unreadNewTopicCount = parseInt($('a[href="' + config.relative_path + '/unread?filter=new"].navigation-link i').attr('data-content'), 10) + 1; - updateUnreadTopicCount('/unread?filter=new', unreadNewTopicCount); - } - - var isUnreplied = parseInt(post.topic.postcount, 10) <= 1; - if (isUnreplied) { - var unreadUnrepliedTopicCount = parseInt($('a[href="' + config.relative_path + '/unread?filter=unreplied"].navigation-link i').attr('data-content'), 10) + 1; - updateUnreadTopicCount('/unread?filter=unreplied', unreadUnrepliedTopicCount); - } - if ($('a[href="' + config.relative_path + '/unread?filter=watched"].navigation-link i').length) { - socket.emit('topics.isFollowed', post.topic.tid, function (err, isFollowed) { - if (err) { - return app.alertError(err.message); - } - if (isFollowed) { - var unreadWatchedTopicCount = parseInt($('a[href="' + config.relative_path + '/unread?filter=watched"].navigation-link i').attr('data-content'), 10) + 1; - updateUnreadTopicCount('/unread?filter=watched', unreadWatchedTopicCount); - } - }); - } + function increaseUnreadCount(filter) { + var unreadUrl = '/unread' + (filter ? '?filter=' + filter : ''); + var newCount = 1 + parseInt($('a[href="' + config.relative_path + unreadUrl + '"].navigation-link i').attr('data-content'), 10); + updateUnreadTopicCount(unreadUrl, newCount); } function markTopicsUnread(tid) { @@ -138,7 +147,9 @@ define('forum/unread', ['topicSelect', 'components', 'topicList'], function (top $(window).on('action:ajaxify.end', function () { if (ajaxify.data.template.topic) { - delete unreadTopics[ajaxify.data.tid]; + ['', 'new', 'watched', 'unreplied'].forEach(function (filter) { + delete unreadTopics[filter][ajaxify.data.tid]; + }); } }); socket.removeListener('event:new_post', onNewPost); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 0ed0c33230..d952d6abbc 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -258,6 +258,12 @@ define('chat', [ } }; + // TODO: see taskbar.js:44 + module.closeByUUID = function (uuid) { + var chatModal = $('.chat-modal[data-uuid="' + uuid + '"]'); + module.close(chatModal); + }; + module.center = function (chatModal) { var hideAfter = false; if (chatModal.hasClass('hide')) { diff --git a/public/src/modules/pictureCropper.js b/public/src/modules/pictureCropper.js index 25bfd6794b..8f7ba364dd 100644 --- a/public/src/modules/pictureCropper.js +++ b/public/src/modules/pictureCropper.js @@ -34,7 +34,7 @@ define('pictureCropper', ['cropper'], function (Cropper) { }, function (cropperModal) { cropperModal.modal({ backdrop: 'static', - }).modal('hide'); + }).modal('show'); // Set cropper image max-height based on viewport var cropBoxHeight = parseInt($(window).height() / 2, 10); @@ -62,11 +62,9 @@ define('pictureCropper', ['cropper'], function (Cropper) { }, ready: function () { if (!checkCORS(cropperTool, data)) { - return; + return cropperModal.modal('hide'); } - cropperModal.modal('show'); - if (data.restrictImageDimension) { var origDimension = (img.width < img.height) ? img.width : img.height; var dimension = (origDimension > data.imageDimension) ? data.imageDimension : origDimension; diff --git a/public/src/modules/taskbar.js b/public/src/modules/taskbar.js index 5a1c0d886f..d285756391 100644 --- a/public/src/modules/taskbar.js +++ b/public/src/modules/taskbar.js @@ -34,6 +34,42 @@ define('taskbar', ['benchpress', 'translator'], function (Benchpress, translator return false; }); }); + + $(window).on('action:app.loggedOut', function () { + taskbar.closeAll(); + }); + }; + + taskbar.close = function (module, uuid) { + // Sends signal to the appropriate module's .close() fn (if present) + var btnEl = taskbar.tasklist.find('[data-module="' + module + '"][data-uuid="' + uuid + '"]'); + var fnName = 'close'; + + // TODO: Refactor chat module to not take uuid in close instead of by jQuery element + if (module === 'chat') { + fnName = 'closeByUUID'; + } + + if (btnEl.length) { + require([module], function (module) { + if (typeof module[fnName] === 'function') { + module[fnName](uuid); + } + }); + } + }; + + taskbar.closeAll = function (module) { + // module is optional + var selector = '[data-uuid]'; + + if (module) { + selector = '[data-module="' + module + '"]' + selector; + } + + taskbar.tasklist.find(selector).each(function (idx, el) { + taskbar.close(module || el.getAttribute('data-module'), el.getAttribute('data-uuid')); + }); }; taskbar.discard = function (module, uuid) { diff --git a/public/src/modules/topicList.js b/public/src/modules/topicList.js index fbe5675011..f002665904 100644 --- a/public/src/modules/topicList.js +++ b/public/src/modules/topicList.js @@ -82,10 +82,19 @@ define('topicList', [ socket.removeListener('event:new_post', onNewPost); }; + function isCategoryVisible(cid) { + return ajaxify.data.categories && ajaxify.data.categories.length && ajaxify.data.categories.some(function (c) { + return parseInt(c.cid, 10) === parseInt(cid, 10); + }); + } + function onNewTopic(data) { - if ((ajaxify.data.selectedCids && ajaxify.data.selectedCids.length && ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1) || + if ( + (ajaxify.data.selectedCids && ajaxify.data.selectedCids.length && ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1) || (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') || - (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10))) { + (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10)) || + (!isCategoryVisible(data.cid)) + ) { return; } @@ -94,35 +103,23 @@ define('topicList', [ } function onNewPost(data) { - function showAlert() { - newPostCount += 1; - updateAlertText(); - } - var post = data.posts[0]; - if ( - (!post || !post.topic) || + if (!post || !post.topic) { + return; + } + if (!post.topic.isFollowing && ( (parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10)) || (ajaxify.data.selectedCids && ajaxify.data.selectedCids.length && ajaxify.data.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1) || (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'new') || - (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10)) - ) { + (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched' && !post.topic.isFollowing) || + (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10)) || + (!isCategoryVisible(post.topic.cid)) + )) { return; } - if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') { - socket.emit('topics.isFollowed', post.tid, function (err, isFollowed) { - if (err) { - app.alertError(err.message); - } - if (isFollowed) { - showAlert(); - } - }); - return; - } - - showAlert(); + newPostCount += 1; + updateAlertText(); } function updateAlertText() { diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index 8bce483e44..0495b23306 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -586,6 +586,10 @@ if (!adaptor.timeagoShort) { var languageCode = utils.userLangToTimeagoCode(config.userLang); + if (!config.timeagoCodes.includes(languageCode + '-short')) { + languageCode = 'en'; + } + var originalSettings = assign({}, jQuery.timeago.settings.strings); jQuery.getScript(config.relative_path + '/assets/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '-short.js').done(function () { adaptor.timeagoShort = assign({}, jQuery.timeago.settings.strings); @@ -602,6 +606,9 @@ delete adaptor.timeagoShort; var languageCode = utils.userLangToTimeagoCode(config.userLang); + if (!config.timeagoCodes.includes(languageCode + '-short')) { + languageCode = 'en'; + } jQuery.getScript(config.relative_path + '/assets/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').done(callback); }, diff --git a/public/src/overrides.js b/public/src/overrides.js index 4e987e9b85..33376ccad3 100644 --- a/public/src/overrides.js +++ b/public/src/overrides.js @@ -120,7 +120,16 @@ if (typeof window !== 'undefined') { $.timeago.settings.allowFuture = true; var userLang = config.userLang.replace('_', '-'); var options = { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }; - var dtFormat = new Intl.DateTimeFormat(userLang, options); + var formatFn; + if (typeof Intl === 'undefined') { + formatFn = function (date) { + return date.toLocaleString(userLang, options); + }; + } else { + var dtFormat = new Intl.DateTimeFormat(userLang, options); + formatFn = dtFormat.format; + } + var iso; var date; $.fn.timeago = function () { @@ -134,7 +143,7 @@ if (typeof window !== 'undefined') { this.setAttribute('datetime', iso); date = new Date(iso); if (!isNaN(date)) { - this.textContent = dtFormat.format(date); + this.textContent = formatFn(date); } }); diff --git a/public/src/sockets.js b/public/src/sockets.js index f80fdc157e..cad6a67e70 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -51,8 +51,9 @@ app.isConnected = false; }); socket.on('event:banned', onEventBanned); - - socket.on('event:alert', app.alert); + socket.on('event:alert', function (params) { + app.alert(params); + }); } function onConnect() { diff --git a/src/analytics.js b/src/analytics.js index ef7656f674..b9649f85cc 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -26,7 +26,7 @@ var uniquevisitors = 0; * the cache could be exhausted continuously if there are more than 500 concurrently * active users */ -var ipCache = LRU({ +var ipCache = new LRU({ max: 500, length: function () { return 1; }, maxAge: 0, diff --git a/src/cache.js b/src/cache.js index 6e54b7e0f1..02a0ffed2e 100644 --- a/src/cache.js +++ b/src/cache.js @@ -3,7 +3,7 @@ var LRU = require('lru-cache'); var pubsub = require('./pubsub'); -var cache = LRU({ +var cache = new LRU({ max: 1000, maxAge: 0, }); diff --git a/src/categories/delete.js b/src/categories/delete.js index 69f5a24045..3024791b2a 100644 --- a/src/categories/delete.js +++ b/src/categories/delete.js @@ -52,7 +52,7 @@ module.exports = function (Categories) { 'cid:' + cid + ':tids:posts', 'cid:' + cid + ':pids', 'cid:' + cid + ':read_by_uid', - 'cid:' + cid + ':ignorers', + 'cid:' + cid + ':uid:watch:state', 'cid:' + cid + ':children', 'cid:' + cid + ':tag:whitelist', 'category:' + cid, diff --git a/src/categories/index.js b/src/categories/index.js index cba2da02c8..a1275481e8 100644 --- a/src/categories/index.js +++ b/src/categories/index.js @@ -6,7 +6,7 @@ var _ = require('lodash'); var db = require('../database'); var user = require('../user'); -var Groups = require('../groups'); +var groups = require('../groups'); var plugins = require('../plugins'); var privileges = require('../privileges'); const cache = require('../cache'); @@ -21,6 +21,7 @@ require('./unread')(Categories); require('./activeusers')(Categories); require('./recentreplies')(Categories); require('./update')(Categories); +require('./watch')(Categories); Categories.exists = function (cid, callback) { db.exists('category:' + cid, callback); @@ -45,8 +46,8 @@ Categories.getCategoryById = function (data, callback) { topicCount: function (next) { Categories.getTopicCount(data, next); }, - isIgnored: function (next) { - Categories.isIgnored([data.cid], data.uid, next); + watchState: function (next) { + Categories.getWatchState([data.cid], data.uid, next); }, parent: function (next) { if (category.parentCid) { @@ -64,7 +65,9 @@ Categories.getCategoryById = function (data, callback) { category.topics = results.topics.topics; category.nextStart = results.topics.nextStart; category.topic_count = results.topicCount; - category.isIgnored = results.isIgnored[0]; + category.isWatched = results.watchState[0] === Categories.watchStates.watching; + category.isNotWatched = results.watchState[0] === Categories.watchStates.notwatching; + category.isIgnored = results.watchState[0] === Categories.watchStates.ignoring; category.parent = results.parent; calculateTopicPostCount(category); @@ -76,14 +79,6 @@ Categories.getCategoryById = function (data, callback) { ], callback); }; -Categories.isIgnored = function (cids, uid, callback) { - if (parseInt(uid, 10) <= 0) { - return setImmediate(callback, null, cids.map(() => false)); - } - const keys = cids.map(cid => 'cid:' + cid + ':ignorers'); - db.isMemberOfSortedSets(keys, uid, callback); -}; - Categories.getAllCidsFromSet = function (key, callback) { const cids = cache.get(key); if (cids) { @@ -135,10 +130,45 @@ Categories.getCategoriesByPrivilege = function (set, uid, privilege, callback) { Categories.getModerators = function (cid, callback) { async.waterfall([ function (next) { - Groups.getMembers('cid:' + cid + ':privileges:moderate', 0, -1, next); + Categories.getModeratorUids([cid], next); }, function (uids, next) { - user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture'], next); + user.getUsersFields(uids[0], ['uid', 'username', 'userslug', 'picture'], next); + }, + ], callback); +}; + +Categories.getModeratorUids = function (cids, callback) { + var sets; + async.waterfall([ + function (next) { + var groupNames = cids.reduce(function (memo, cid) { + memo.push('cid:' + cid + ':privileges:moderate'); + memo.push('cid:' + cid + ':privileges:groups:moderate'); + return memo; + }, []); + + groups.getMembersOfGroups(groupNames, next); + }, + function (memberSets, next) { + // Every other set is actually a list of user groups, not uids, so convert those to members + sets = memberSets.reduce(function (memo, set, idx) { + if (idx % 2) { + memo.groupNames.push(set); + } else { + memo.uids.push(set); + } + + return memo; + }, { groupNames: [], uids: [] }); + + groups.getMembersOfGroups(sets.groupNames, next); + }, + function (groupUids, next) { + const moderatorUids = cids.map(function (cid, index) { + return _.union(sets.uids[index].concat(groupUids[index])); + }); + next(null, moderatorUids); }, ], callback); }; @@ -443,20 +473,4 @@ Categories.buildForSelectCategories = function (categories, callback) { callback(null, categoriesData); }; -Categories.getIgnorers = function (cid, start, stop, callback) { - db.getSortedSetRevRange('cid:' + cid + ':ignorers', start, stop, callback); -}; - -Categories.filterIgnoringUids = function (cid, uids, callback) { - async.waterfall([ - function (next) { - db.isSortedSetMembers('cid:' + cid + ':ignorers', uids, next); - }, - function (isIgnoring, next) { - const readingUids = uids.filter((uid, index) => uid && !isIgnoring[index]); - next(null, readingUids); - }, - ], callback); -}; - Categories.async = require('../promisify')(Categories); diff --git a/src/categories/watch.js b/src/categories/watch.js new file mode 100644 index 0000000000..66a9ec6594 --- /dev/null +++ b/src/categories/watch.js @@ -0,0 +1,80 @@ +'use strict'; + +const async = require('async'); + +const db = require('../database'); +const user = require('../user'); + +module.exports = function (Categories) { + Categories.watchStates = { + ignoring: 1, + notwatching: 2, + watching: 3, + }; + + Categories.isIgnored = function (cids, uid, callback) { + if (!(parseInt(uid, 10) > 0)) { + return setImmediate(callback, null, cids.map(() => false)); + } + async.waterfall([ + function (next) { + Categories.getWatchState(cids, uid, next); + }, + function (states, next) { + next(null, states.map(state => state === Categories.watchStates.ignoring)); + }, + ], callback); + }; + + Categories.getWatchState = function (cids, uid, callback) { + if (!(parseInt(uid, 10) > 0)) { + return setImmediate(callback, null, cids.map(() => Categories.watchStates.notwatching)); + } + if (!Array.isArray(cids) || !cids.length) { + return setImmediate(callback, null, []); + } + async.waterfall([ + function (next) { + const keys = cids.map(cid => 'cid:' + cid + ':uid:watch:state'); + async.parallel({ + userSettings: async.apply(user.getSettings, uid), + states: async.apply(db.sortedSetsScore, keys, uid), + }, next); + }, + function (results, next) { + next(null, results.states.map(state => state || Categories.watchStates[results.userSettings.categoryWatchState])); + }, + ], callback); + }; + + Categories.getIgnorers = function (cid, start, stop, callback) { + const count = (stop === -1) ? -1 : (stop - start + 1); + db.getSortedSetRevRangeByScore('cid:' + cid + ':uid:watch:state', start, count, Categories.watchStates.ignoring, Categories.watchStates.ignoring, callback); + }; + + Categories.filterIgnoringUids = function (cid, uids, callback) { + async.waterfall([ + function (next) { + Categories.getUidsWatchStates(cid, uids, next); + }, + function (states, next) { + const readingUids = uids.filter((uid, index) => uid && states[index] !== Categories.watchStates.ignoring); + next(null, readingUids); + }, + ], callback); + }; + + Categories.getUidsWatchStates = function (cid, uids, callback) { + async.waterfall([ + function (next) { + async.parallel({ + userSettings: async.apply(user.getMultipleUserSettings, uids), + states: async.apply(db.sortedSetScores, 'cid:' + cid + ':uid:watch:state', uids), + }, next); + }, + function (results, next) { + next(null, results.states.map((state, index) => state || Categories.watchStates[results.userSettings[index].categoryWatchState])); + }, + ], callback); + }; +}; diff --git a/src/cli/index.js b/src/cli/index.js index 7b7cbf8cf2..a7d937d416 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -3,6 +3,8 @@ var fs = require('fs'); var path = require('path'); +require('../../require-main'); + var packageInstall = require('./package-install'); var dirname = require('./paths').baseDir; diff --git a/src/controllers/404.js b/src/controllers/404.js index adcc9f68a8..b34926aa5e 100644 --- a/src/controllers/404.js +++ b/src/controllers/404.js @@ -7,9 +7,9 @@ var validator = require('validator'); var meta = require('../meta'); var plugins = require('../plugins'); -exports.handle404 = function (req, res) { +exports.handle404 = function handle404(req, res) { var relativePath = nconf.get('relative_path'); - var isClientScript = new RegExp('^' + relativePath + '\\/assets\\/src\\/.+\\.js'); + var isClientScript = new RegExp('^' + relativePath + '\\/assets\\/src\\/.+\\.js(\\?v=\\w+)?$'); if (plugins.hasListeners('action:meta.override404')) { return plugins.fireHook('action:meta.override404', { diff --git a/src/controllers/accounts/categories.js b/src/controllers/accounts/categories.js index 43eff07889..1371435f49 100644 --- a/src/controllers/accounts/categories.js +++ b/src/controllers/accounts/categories.js @@ -21,8 +21,8 @@ categoriesController.get = function (req, res, callback) { } async.parallel({ - ignored: function (next) { - user.getIgnoredCategories(userData.uid, next); + states: function (next) { + user.getCategoryWatchState(userData.uid, next); }, categories: function (next) { categories.buildForSelect(userData.uid, 'find', next); @@ -32,7 +32,9 @@ categoriesController.get = function (req, res, callback) { function (results) { results.categories.forEach(function (category) { if (category) { - category.isIgnored = results.ignored.includes(String(category.cid)); + category.isIgnored = results.states[category.cid] === categories.watchStates.ignoring; + category.isWatched = results.states[category.cid] === categories.watchStates.watching; + category.isNotWatched = results.states[category.cid] === categories.watchStates.notwatching; } }); userData.categories = results.categories; diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index a75513331a..62ce87065d 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -41,11 +41,13 @@ profileController.get = function (req, res, callback) { } userData = _userData; - req.session.uids_viewed = req.session.uids_viewed || {}; + if (req.uid >= 0) { + req.session.uids_viewed = req.session.uids_viewed || {}; - if (req.uid !== userData.uid && (!req.session.uids_viewed[userData.uid] || req.session.uids_viewed[userData.uid] < Date.now() - 3600000)) { - user.incrementUserFieldBy(userData.uid, 'profileviews', 1); - req.session.uids_viewed[userData.uid] = Date.now(); + if (req.uid !== userData.uid && (!req.session.uids_viewed[userData.uid] || req.session.uids_viewed[userData.uid] < Date.now() - 3600000)) { + user.incrementUserFieldBy(userData.uid, 'profileviews', 1); + req.session.uids_viewed[userData.uid] = Date.now(); + } } async.parallel({ diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 9cc3561c5f..991b0a8e24 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -1,7 +1,10 @@ 'use strict'; var async = require('async'); +var nconf = require('nconf'); +var winston = require('winston'); var _ = require('lodash'); +var jwt = require('jsonwebtoken'); var user = require('../../user'); var languages = require('../../languages'); @@ -161,6 +164,8 @@ settingsController.get = function (req, res, callback) { }; }); + userData.categoryWatchState = { [userData.settings.categoryWatchState]: true }; + userData.disableCustomUserSkins = meta.config.disableCustomUserSkins; userData.allowUserHomePage = meta.config.allowUserHomePage; @@ -181,6 +186,52 @@ settingsController.get = function (req, res, callback) { ], callback); }; +settingsController.unsubscribe = function (req, res) { + if (!req.params.token) { + return res.sendStatus(404); + } + + jwt.verify(req.params.token, nconf.get('secret'), function (err, payload) { + if (err) { + return res.sendStatus(403); + } + + switch (payload.template) { + case 'digest': + async.parallel([ + async.apply(user.setSetting, payload.uid, 'dailyDigestFreq', 'off'), + async.apply(user.updateDigestSetting, payload.uid, 'off'), + ], function (err) { + if (err) { + winston.error('[settings/unsubscribe] One-click unsubscribe failed with error: ' + err.message); + return res.sendStatus(500); + } + + return res.sendStatus(200); + }); + break; + case 'notification': + async.waterfall([ + async.apply(db.getObjectField, 'user:' + payload.uid + ':settings', 'notificationType_' + payload.type), + (current, next) => { + user.setSetting(payload.uid, 'notificationType_' + payload.type, (current === 'notificationemail' ? 'notification' : 'none'), next); + }, + ], function (err) { + if (err) { + winston.error('[settings/unsubscribe] One-click unsubscribe failed with error: ' + err.message); + return res.sendStatus(500); + } + + return res.sendStatus(200); + }); + break; + default: + res.sendStatus(404); + break; + } + }); +}; + function getNotificationSettings(userData, callback) { var privilegedTypes = []; diff --git a/src/controllers/admin/hooks.js b/src/controllers/admin/hooks.js index 40e84e5fc6..f3440d5689 100644 --- a/src/controllers/admin/hooks.js +++ b/src/controllers/admin/hooks.js @@ -1,5 +1,6 @@ 'use strict'; +const validator = require('validator'); var plugins = require('../../plugins'); var hooksController = module.exports; @@ -18,7 +19,7 @@ hooksController.get = function (req, res) { current.methods.push({ id: hookData.id, priority: hookData.priority, - method: hookData.method ? hookData.method.toString() : 'No plugin function!', + method: hookData.method ? validator.escape(hookData.method.toString()) : 'No plugin function!', index: hookIndex + '-code-' + methodIndex, }); }); diff --git a/src/controllers/api.js b/src/controllers/api.js index b53e0d0ad1..746f67184f 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -12,6 +12,7 @@ var categories = require('../categories'); var privileges = require('../privileges'); var plugins = require('../plugins'); var translator = require('../translator'); +var languages = require('../languages'); var apiController = module.exports; @@ -57,11 +58,12 @@ apiController.loadConfig = function (req, callback) { config.requireEmailConfirmation = meta.config.requireEmailConfirmation === 1; config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest'; config.categoryTopicSort = meta.config.categoryTopicSort || 'newest_to_oldest'; - config.csrf_token = req.csrfToken && req.csrfToken(); + config.csrf_token = req.uid >= 0 && req.csrfToken && req.csrfToken(); config.searchEnabled = plugins.hasListeners('filter:search.query'); config.bootswatchSkin = meta.config.bootswatchSkin || ''; config.enablePostHistory = (meta.config.enablePostHistory || 1) === 1; config.notificationAlertTimeout = meta.config.notificationAlertTimeout || 5000; + config.timeagoCodes = languages.timeagoCodes; if (config.useOutgoingLinksPage) { config.outgoingLinksWhitelist = meta.config['outgoingLinks:whitelist']; @@ -101,6 +103,10 @@ apiController.loadConfig = function (req, callback) { config.bootswatchSkin = (meta.config.disableCustomUserSkins !== 1 && settings.bootswatchSkin && settings.bootswatchSkin !== '') ? settings.bootswatchSkin : ''; plugins.fireHook('filter:config.get', config, next); }, + function (config, next) { + req.res.locals.config = config; + process.nextTick(next, null, config); + }, ], callback); }; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index b2f456691d..31b59eee93 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -19,7 +19,6 @@ var privileges = require('../privileges'); var sockets = require('../socket.io'); var authenticationController = module.exports; -var apiController = require('./api'); authenticationController.register = function (req, res) { var registrationType = meta.config.registrationType || 'normal'; @@ -286,10 +285,10 @@ function continueLogin(req, res, next) { } else { delete req.query.lang; - async.parallel({ + async.series({ doLogin: async.apply(authenticationController.doLogin, req, userData.uid), + buildHeader: async.apply(middleware.buildHeader, req, res), header: async.apply(middleware.generateHeader, req, res, {}), - config: async.apply(apiController.loadConfig, req), }, function (err, payload) { if (err) { return helpers.noScriptErrors(req, res, err.message, 403); @@ -309,7 +308,7 @@ function continueLogin(req, res, next) { res.status(200).send({ next: destination, header: payload.header, - config: payload.config, + config: res.locals.config, }); } }); @@ -474,33 +473,40 @@ authenticationController.logout = function (req, res, next) { req.logout(); req.session.regenerate(function (err) { req.uid = 0; + req.headers['x-csrf-token'] = req.csrfToken(); next(err); }); }, function (next) { - user.setUserField(req.uid, 'lastonline', Date.now() - 300000, next); + user.setUserField(req.uid, 'lastonline', Date.now() - (meta.config.onlineCutoff * 60000), next); + }, + function (next) { + db.sortedSetRemove('users:online', req.uid, next); }, function (next) { plugins.fireHook('static:user.loggedOut', { req: req, res: res, uid: req.uid }, next); }, + async.apply(middleware.autoLocale, req, res), function () { // Force session check for all connected socket.io clients with the same session id sockets.in('sess_' + req.sessionID).emit('checkSession', 0); if (req.body.noscript === 'true') { res.redirect(nconf.get('relative_path') + '/'); } else { - async.parallel({ + async.series({ + buildHeader: async.apply(middleware.buildHeader, req, res), header: async.apply(middleware.generateHeader, req, res, {}), - config: async.apply(apiController.loadConfig, req), }, function (err, payload) { if (err) { return res.status(500); } - res.status(200).send({ + payload = { header: payload.header, - config: payload.config, - }); + config: res.locals.config, + }; + plugins.fireHook('filter:user.logout', payload); + res.status(200).send(payload); }); } }, diff --git a/src/controllers/errors.js b/src/controllers/errors.js index 0887de8c9b..849750e391 100644 --- a/src/controllers/errors.js +++ b/src/controllers/errors.js @@ -5,7 +5,7 @@ var winston = require('winston'); var validator = require('validator'); var plugins = require('../plugins'); -exports.handleURIErrors = function (err, req, res, next) { +exports.handleURIErrors = function handleURIErrors(err, req, res, next) { // Handle cases where malformed URIs are passed in if (err instanceof URIError) { const cleanPath = req.path.replace(new RegExp('^' + nconf.get('relative_path')), ''); @@ -36,7 +36,7 @@ exports.handleURIErrors = function (err, req, res, next) { // this needs to have four arguments or express treats it as `(req, res, next)` // don't remove `next`! -exports.handleErrors = function (err, req, res, next) { // eslint-disable-line no-unused-vars +exports.handleErrors = function handleErrors(err, req, res, next) { // eslint-disable-line no-unused-vars var cases = { EBADCSRFTOKEN: function () { winston.error(req.path + '\n', err.message); diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 5eef187cf8..6068de3091 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -239,6 +239,20 @@ helpers.getCategories = function (set, uid, privilege, selectedCid, callback) { ], callback); }; +helpers.getCategoriesByStates = function (uid, selectedCid, states, callback) { + async.waterfall([ + function (next) { + user.getCategoriesByStates(uid, states, next); + }, + function (cids, next) { + privileges.categories.filterCids('read', cids, uid, next); + }, + function (cids, next) { + getCategoryData(cids, uid, selectedCid, next); + }, + ], callback); +}; + helpers.getWatchedCategories = function (uid, selectedCid, callback) { async.waterfall([ function (next) { diff --git a/src/controllers/index.js b/src/controllers/index.js index ed94cd4713..494b0e9f02 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -92,7 +92,7 @@ Controllers.login = function (req, res, next) { var registrationType = meta.config.registrationType || 'normal'; var allowLoginWith = (meta.config.allowLoginWith || 'username-email'); - var returnTo = (req.headers['x-return-to'] || '').replace(nconf.get('base_url'), ''); + var returnTo = (req.headers['x-return-to'] || '').replace(nconf.get('base_url') + nconf.get('relative_path'), ''); var errorText; if (req.query.error === 'csrf-invalid') { @@ -214,7 +214,7 @@ Controllers.registerInterstitial = function (req, res, next) { // No interstitials, redirect to home const returnTo = req.session.returnTo || req.session.registration.returnTo; delete req.session.registration; - return helpers.redirect(res, returnTo || nconf.get('relative_path') + '/'); + return helpers.redirect(res, returnTo || '/'); } var renders = data.interstitials.map(function (interstitial) { return async.apply(req.app.render.bind(req.app), interstitial.template, interstitial.data || {}); @@ -252,6 +252,7 @@ Controllers.robots = function (req, res) { res.send('User-agent: *\n' + 'Disallow: ' + nconf.get('relative_path') + '/admin/\n' + 'Disallow: ' + nconf.get('relative_path') + '/reset/\n' + + 'Disallow: ' + nconf.get('relative_path') + '/compose\n' + 'Sitemap: ' + nconf.get('url') + '/sitemap.xml'); } }; diff --git a/src/controllers/recent.js b/src/controllers/recent.js index aee3890067..e18c853c68 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -5,6 +5,7 @@ var async = require('async'); var nconf = require('nconf'); var user = require('../user'); +var categories = require('../categories'); var topics = require('../topics'); var meta = require('../meta'); var helpers = require('./helpers'); @@ -47,8 +48,8 @@ recentController.getData = function (req, url, sort, callback) { settings: function (next) { user.getSettings(req.uid, next); }, - watchedCategories: function (next) { - helpers.getWatchedCategories(req.uid, cid, next); + categories: function (next) { + helpers.getCategoriesByStates(req.uid, cid, [categories.watchStates.watching, categories.watchStates.notwatching], next); }, rssToken: function (next) { user.auth.getFeedToken(req.uid, next); @@ -58,7 +59,7 @@ recentController.getData = function (req, url, sort, callback) { function (results, next) { rssToken = results.rssToken; settings = results.settings; - categoryData = results.watchedCategories; + categoryData = results.categories; var start = Math.max(0, (page - 1) * settings.topicsPerPage); stop = start + settings.topicsPerPage - 1; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index aca8445872..d5bdffbb3f 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -3,6 +3,7 @@ var async = require('async'); var nconf = require('nconf'); +var winston = require('winston'); var user = require('../user'); var meta = require('../meta'); @@ -17,7 +18,7 @@ var analytics = require('../analytics'); var topicsController = module.exports; -topicsController.get = function (req, res, callback) { +topicsController.get = function getTopic(req, res, callback) { var tid = req.params.topic_id; var currentPage = parseInt(req.query.page, 10) || 1; var pageCount = 1; @@ -161,16 +162,18 @@ topicsController.get = function (req, res, callback) { res.locals.linkTags.push(rel); }); - req.session.tids_viewed = req.session.tids_viewed || {}; - if (!req.session.tids_viewed[tid] || req.session.tids_viewed[tid] < Date.now() - 3600000) { - topics.increaseViewCount(tid); - req.session.tids_viewed[tid] = Date.now(); + if (req.uid >= 0) { + req.session.tids_viewed = req.session.tids_viewed || {}; + if (!req.session.tids_viewed[tid] || req.session.tids_viewed[tid] < Date.now() - 3600000) { + topics.increaseViewCount(tid); + req.session.tids_viewed[tid] = Date.now(); + } } if (req.loggedIn) { topics.markAsRead([tid], req.uid, function (err, markedRead) { if (err) { - return callback(err); + return winston.error(err); } if (markedRead) { topics.pushUnreadCount(req.uid); diff --git a/src/controllers/unread.js b/src/controllers/unread.js index 3c2259bb4f..c1f9804437 100644 --- a/src/controllers/unread.js +++ b/src/controllers/unread.js @@ -8,6 +8,7 @@ var querystring = require('querystring'); var meta = require('../meta'); var pagination = require('../pagination'); var user = require('../user'); +var categories = require('../categories'); var topics = require('../topics'); var plugins = require('../plugins'); var helpers = require('./helpers'); @@ -35,7 +36,7 @@ unreadController.get = function (req, res, next) { if (plugins.hasListeners('filter:unread.categories')) { plugins.fireHook('filter:unread.categories', { uid: req.uid, cid: cid }, next); } else { - helpers.getWatchedCategories(req.uid, cid, next); + helpers.getCategoriesByStates(req.uid, cid, [categories.watchStates.watching], next); } }, settings: function (next) { diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 5ea85d7b6b..4e33bb4602 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -168,31 +168,6 @@ uploadsController.uploadThumb = function (req, res, next) { }, next); }; -uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) { - if (plugins.hasListeners('filter:uploadImage')) { - return plugins.fireHook('filter:uploadImage', { - image: uploadedFile, - uid: uid, - }, callback); - } - - if (plugins.hasListeners('filter:uploadFile')) { - return plugins.fireHook('filter:uploadFile', { - file: uploadedFile, - uid: uid, - }, callback); - } - - async.waterfall([ - function (next) { - file.isFileTypeAllowed(uploadedFile.path, next); - }, - function (next) { - saveFileToLocal(uid, uploadedFile, next); - }, - ], callback); -}; - uploadsController.uploadFile = function (uid, uploadedFile, callback) { if (plugins.hasListeners('filter:uploadFile')) { return plugins.fireHook('filter:uploadFile', { diff --git a/src/coverPhoto.js b/src/coverPhoto.js index ec1b3f7be9..c1ceb31133 100644 --- a/src/coverPhoto.js +++ b/src/coverPhoto.js @@ -15,17 +15,24 @@ coverPhoto.getDefaultProfileCover = function (uid) { }; function getCover(type, id) { + const defaultCover = nconf.get('relative_path') + '/assets/images/cover-default.png'; if (meta.config[type + ':defaultCovers']) { - var covers = meta.config[type + ':defaultCovers'].trim().split(/[\s,]+/g); + var covers = String(meta.config[type + ':defaultCovers']).trim().split(/[\s,]+/g); + let coverPhoto = defaultCover; + if (!covers.length) { + return coverPhoto; + } if (typeof id === 'string') { id = (id.charCodeAt(0) + id.charCodeAt(1)) % covers.length; } else { id %= covers.length; } - - return covers[id]; + if (covers[id] && !covers[id].startsWith('http')) { + coverPhoto = nconf.get('relative_path') + covers[id]; + } + return coverPhoto; } - return nconf.get('relative_path') + '/assets/images/cover-default.png'; + return defaultCover; } diff --git a/src/database/cache.js b/src/database/cache.js index b8f48e5b73..5bb6cb8c33 100644 --- a/src/database/cache.js +++ b/src/database/cache.js @@ -4,7 +4,7 @@ module.exports.create = function (name) { var LRU = require('lru-cache'); var pubsub = require('../pubsub'); - var cache = LRU({ + var cache = new LRU({ max: 20000, length: function () { return 1; }, maxAge: 0, diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index 0f1437e010..54a45edf60 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -16,10 +16,9 @@ module.exports = function (db, module) { if (!key || !data) { return callback(); } - if (data.hasOwnProperty('')) { - delete data['']; - } - db.collection('objects').updateOne({ _key: key }, { $set: data }, { upsert: true, w: 1 }, function (err) { + + const writeData = helpers.serializeData(data); + db.collection('objects').updateOne({ _key: key }, { $set: writeData }, { upsert: true, w: 1 }, function (err) { if (err) { return callback(err); } @@ -34,7 +33,6 @@ module.exports = function (db, module) { return callback(); } var data = {}; - field = helpers.fieldToString(field); data[field] = value; module.setObject(key, data, callback); }; @@ -76,7 +74,7 @@ module.exports = function (db, module) { if (err) { return callback(err); } - + data = data.map(helpers.deserializeData); var map = helpers.toMap(data); unCachedKeys.forEach(function (key) { cachedData[key] = map[key] || null; diff --git a/src/database/mongo/helpers.js b/src/database/mongo/helpers.js index 29c83ea3b9..a02c658a3d 100644 --- a/src/database/mongo/helpers.js +++ b/src/database/mongo/helpers.js @@ -22,8 +22,27 @@ helpers.fieldToString = function (field) { field = field.toString(); } // if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E - field = field.replace(/\./g, '\uff0E'); - return field; + return field.replace(/\./g, '\uff0E'); +}; + +helpers.serializeData = function (data) { + const serialized = {}; + for (const field in data) { + if (data.hasOwnProperty(field) && field !== '') { + serialized[helpers.fieldToString(field)] = data[field]; + } + } + return serialized; +}; + +helpers.deserializeData = function (data) { + const deserialized = {}; + for (const field in data) { + if (data.hasOwnProperty(field)) { + deserialized[field.replace(/\uff0E/g, '.')] = data[field]; + } + } + return deserialized; }; helpers.valueToString = function (value) { diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index 7d628d9b69..97f8371a35 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -55,6 +55,9 @@ module.exports = function (db, module) { } bulk.execute(function (err) { + if (err && err.message.startsWith('E11000 duplicate key error')) { + return process.nextTick(module.setsAdd, keys, value, callback); + } callback(err); }); }; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index cd90546e39..21a1a6e61c 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -56,6 +56,10 @@ module.exports = function (db, module) { query.score.$lte = max; } + if (max === min) { + query.score = max; + } + const fields = { _id: 0, _key: 0 }; if (!withScores) { fields.score = 0; @@ -115,10 +119,10 @@ module.exports = function (db, module) { }; function getSortedSetRangeByScore(key, start, count, min, max, sort, withScores, callback) { - if (parseInt(count, 10) === -1) { - count = 0; + if (parseInt(count, 10) === 0) { + return setImmediate(callback, null, []); } - var stop = start + count - 1; + const stop = (parseInt(count, 10) === -1) ? -1 : (start + count - 1); getSortedSetRange(key, start, stop, min, max, sort, withScores, callback); } @@ -261,7 +265,7 @@ module.exports = function (db, module) { module.sortedSetsScore = function (keys, value, callback) { if (!Array.isArray(keys) || !keys.length) { - return callback(); + return callback(null, []); } value = helpers.valueToString(value); db.collection('objects').find({ _key: { $in: keys }, value: value }, { projection: { _id: 0, value: 0 } }).toArray(function (err, result) { @@ -269,22 +273,27 @@ module.exports = function (db, module) { return callback(err); } - var map = helpers.toMap(result); - var returnData = []; - var item; + var map = {}; + result.forEach(function (item) { + if (item) { + map[item._key] = item; + } + }); - for (var i = 0; i < keys.length; i += 1) { - item = map[keys[i]]; - returnData.push(item ? item.score : null); - } + result = keys.map(function (key) { + return map[key] ? map[key].score : null; + }); - callback(null, returnData); + callback(null, result); }); }; module.sortedSetScores = function (key, values, callback) { if (!key) { - return callback(null, null); + return setImmediate(callback, null, null); + } + if (!values.length) { + return setImmediate(callback, null, []); } values = values.map(helpers.valueToString); db.collection('objects').find({ _key: key, value: { $in: values } }, { projection: { _id: 0, _key: 0 } }).toArray(function (err, result) { diff --git a/src/database/postgres/sets.js b/src/database/postgres/sets.js index 615cb6ad42..d0c41e6233 100644 --- a/src/database/postgres/sets.js +++ b/src/database/postgres/sets.js @@ -1,6 +1,7 @@ 'use strict'; var async = require('async'); +var _ = require('lodash'); module.exports = function (db, module) { var helpers = module.helpers.postgres; @@ -44,9 +45,7 @@ SELECT $1::TEXT, m value = [value]; } - keys = keys.filter(function (k, i, a) { - return a.indexOf(k) === i; - }); + keys = _.uniq(keys); module.transaction(function (tx, done) { var query = tx.client.query.bind(tx.client); diff --git a/src/database/postgres/sorted.js b/src/database/postgres/sorted.js index ad749c19bd..4b1dfa41c6 100644 --- a/src/database/postgres/sorted.js +++ b/src/database/postgres/sorted.js @@ -348,7 +348,7 @@ SELECT z."score" s module.sortedSetsScore = function (keys, value, callback) { if (!Array.isArray(keys) || !keys.length) { - return callback(); + return callback(null, []); } value = helpers.valueToString(value); @@ -382,9 +382,11 @@ SELECT o."_key" k, module.sortedSetScores = function (key, values, callback) { if (!key) { - return callback(null, null); + return setImmediate(callback, null, null); + } + if (!values.length) { + return setImmediate(callback, null, []); } - values = values.map(helpers.valueToString); query({ diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 43b797e2f9..6dac8955aa 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -170,6 +170,9 @@ module.exports = function (redisClient, module) { }; module.sortedSetsScore = function (keys, value, callback) { + if (!Array.isArray(keys) || !keys.length) { + return callback(null, []); + } helpers.execKeysValue(redisClient, 'batch', 'zscore', keys, value, function (err, scores) { if (err) { return callback(err); @@ -182,6 +185,9 @@ module.exports = function (redisClient, module) { }; module.sortedSetScores = function (key, values, callback) { + if (!values.length) { + return setImmediate(callback, null, []); + } helpers.execKeyValues(redisClient, 'batch', 'zscore', key, values, function (err, scores) { if (err) { return callback(err); diff --git a/src/emailer.js b/src/emailer.js index e5ec56ddea..33048b7ed1 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -11,6 +11,7 @@ var url = require('url'); var path = require('path'); var fs = require('fs'); var _ = require('lodash'); +var jwt = require('jsonwebtoken'); var User = require('./user'); var Plugins = require('./plugins'); @@ -110,7 +111,7 @@ Emailer.setupFallbackTransport = function (config) { smtpOptions.ignoreTLS = false; } } else { - smtpOptions.service = config['email:smtpTransport:service']; + smtpOptions.service = String(config['email:smtpTransport:service']); } Emailer.transports.smtp = nodemailer.createTransport(smtpOptions); @@ -216,6 +217,31 @@ Emailer.sendToEmail = function (template, email, language, params, callback) { 'List-Unsubscribe': '<' + [nconf.get('url'), 'uid', params.uid, 'settings'].join('/') + '>', }, params.headers); + // Digests and notifications can be one-click unsubbed + let payload = { + template: template, + uid: params.uid, + }; + + switch (template) { + case 'digest': + payload = jwt.sign(payload, nconf.get('secret'), { + expiresIn: '30d', + }); + params.headers['List-Unsubscribe'] = '<' + [nconf.get('url'), 'email', 'unsubscribe', payload].join('/') + '>'; + params.headers['List-Unsubscribe-Post'] = 'List-Unsubscribe=One-Click'; + break; + + case 'notification': + payload.type = params.notification.type; + payload = jwt.sign(payload, nconf.get('secret'), { + expiresIn: '30d', + }); + params.headers['List-Unsubscribe'] = '<' + [nconf.get('url'), 'email', 'unsubscribe', payload].join('/') + '>'; + params.headers['List-Unsubscribe-Post'] = 'List-Unsubscribe=One-Click'; + break; + } + async.waterfall([ function (next) { Plugins.fireHook('filter:email.params', { diff --git a/src/events.js b/src/events.js index 9d727e8451..f6fe006d02 100644 --- a/src/events.js +++ b/src/events.js @@ -158,9 +158,7 @@ events.deleteEvents = function (eids, callback) { var keys; async.waterfall([ function (next) { - keys = eids.map(function (eid) { - return 'event:' + eid; - }); + keys = eids.map(eid => 'event:' + eid); db.getObjectsFields(keys, ['type'], next); }, function (eventData, next) { diff --git a/src/groups/cache.js b/src/groups/cache.js index 627327ff94..70e4f85472 100644 --- a/src/groups/cache.js +++ b/src/groups/cache.js @@ -3,7 +3,7 @@ var LRU = require('lru-cache'); var pubsub = require('../pubsub'); -var cache = LRU({ +var cache = new LRU({ max: 40000, maxAge: 0, }); diff --git a/src/groups/cover.js b/src/groups/cover.js index ae2f86c90f..fc336d0e0d 100644 --- a/src/groups/cover.js +++ b/src/groups/cover.js @@ -2,12 +2,10 @@ var async = require('async'); var path = require('path'); -var mime = require('mime'); var db = require('../database'); var image = require('../image'); var file = require('../file'); -var uploadsController = require('../controllers/uploads'); module.exports = function (Groups) { Groups.updateCoverPosition = function (groupName, position, callback) { @@ -25,7 +23,7 @@ module.exports = function (Groups) { var tempPath = data.file ? data.file : ''; var url; - var type = data.file ? mime.getType(data.file) : 'image/png'; + async.waterfall([ function (next) { if (tempPath) { @@ -36,10 +34,10 @@ module.exports = function (Groups) { function (_tempPath, next) { tempPath = _tempPath; - uploadsController.uploadGroupCover(uid, { - name: 'groupCover' + path.extname(tempPath), + const filename = 'groupCover-' + data.groupName + path.extname(tempPath); + image.uploadImage(filename, 'files', { path: tempPath, - type: type, + uid: uid, }, next); }, function (uploadData, next) { @@ -53,10 +51,9 @@ module.exports = function (Groups) { }, next); }, function (next) { - uploadsController.uploadGroupCover(uid, { - name: 'groupCoverThumb' + path.extname(tempPath), + image.uploadImage('groupCoverThumb-' + data.groupName + path.extname(tempPath), 'files', { path: tempPath, - type: type, + uid: uid, }, next); }, function (uploadData, next) { diff --git a/src/groups/data.js b/src/groups/data.js index 041a87fe9f..21fcc7911e 100644 --- a/src/groups/data.js +++ b/src/groups/data.js @@ -2,6 +2,7 @@ var async = require('async'); var validator = require('validator'); +var nconf = require('nconf'); var db = require('../database'); var plugins = require('../plugins'); @@ -91,8 +92,20 @@ function modifyGroup(group, fields) { group.createtimeISO = utils.toISOString(group.createtime); group.private = ([null, undefined].includes(group.private)) ? 1 : group.private; - group['cover:url'] = group['cover:url'] || require('../coverPhoto').getDefaultGroupCover(group.name); group['cover:thumb:url'] = group['cover:thumb:url'] || group['cover:url']; + + if (group['cover:url']) { + group['cover:url'] = group['cover:url'].startsWith('http') ? group['cover:url'] : (nconf.get('relative_path') + group['cover:url']); + } else { + group['cover:url'] = require('../coverPhoto').getDefaultGroupCover(group.name); + } + + if (group['cover:thumb:url']) { + group['cover:thumb:url'] = group['cover:thumb:url'].startsWith('http') ? group['cover:thumb:url'] : (nconf.get('relative_path') + group['cover:thumb:url']); + } else { + group['cover:thumb:url'] = require('../coverPhoto').getDefaultGroupCover(group.name); + } + group['cover:position'] = validator.escape(String(group['cover:position'] || '50% 50%')); } } diff --git a/src/groups/index.js b/src/groups/index.js index 0d21f24525..4a19b4e0d3 100644 --- a/src/groups/index.js +++ b/src/groups/index.js @@ -105,7 +105,7 @@ Groups.getGroupsAndMembers = function (groupNames, callback) { data.groups.forEach(function (group, index) { if (group) { group.members = data.members[index] || []; - group.truncated = group.memberCount > data.members.length; + group.truncated = group.memberCount > group.members.length; } }); next(null, data.groups); diff --git a/src/groups/membership.js b/src/groups/membership.js index bfce9947de..09b8242202 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -20,6 +20,7 @@ module.exports = function (Groups) { async.parallel({ notification: function (next) { notifications.create({ + type: 'group-request-membership', bodyShort: '[[groups:request.notification_title, ' + username + ']]', bodyLong: '[[groups:request.notification_text, ' + username + ', ' + groupName + ']]', nid: 'group:' + groupName + ':uid:' + uid + ':request', @@ -133,9 +134,7 @@ module.exports = function (Groups) { }; Groups.getMembersOfGroups = function (groupNames, callback) { - db.getSortedSetsMembers(groupNames.map(function (name) { - return 'group:' + name + ':members'; - }), callback); + db.getSortedSetsMembers(groupNames.map(name => 'group:' + name + ':members'), callback); }; Groups.isMember = function (uid, groupName, callback) { diff --git a/src/groups/search.js b/src/groups/search.js index 6f8e6c82d5..62005ce308 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -15,20 +15,23 @@ module.exports = function (Groups) { async.waterfall([ async.apply(db.getSortedSetRange, 'groups:createtime', 0, -1), function (groupNames, next) { - // Ephemeral groups and the registered-users groups are searchable - groupNames = Groups.ephemeralGroups.concat(groupNames); + if (!options.hideEphemeralGroups) { + groupNames = Groups.ephemeralGroups.concat(groupNames); + } groupNames = groupNames.filter(function (name) { return name.toLowerCase().includes(query) && name !== 'administrators' && !Groups.isPrivilegeGroup(name); }); groupNames = groupNames.slice(0, 100); - Groups.getGroupsData(groupNames, next); + if (options.showMembers) { + Groups.getGroupsAndMembers(groupNames, next); + } else { + Groups.getGroupsData(groupNames, next); + } }, function (groupsData, next) { groupsData = groupsData.filter(Boolean); if (options.filterHidden) { - groupsData = groupsData.filter(function (group) { - return !group.hidden; - }); + groupsData = groupsData.filter(group => !group.hidden); } Groups.sort(options.sort, groupsData, next); diff --git a/src/image.js b/src/image.js index 7789caa0b6..bc495bf9ef 100644 --- a/src/image.js +++ b/src/image.js @@ -139,3 +139,28 @@ image.writeImageDataToTempFile = function (imageData, callback) { image.sizeFromBase64 = function (imageData) { return Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64').length; }; + +image.uploadImage = function (filename, folder, image, callback) { + if (plugins.hasListeners('filter:uploadImage')) { + return plugins.fireHook('filter:uploadImage', { + image: image, + uid: image.uid, + }, callback); + } + + async.waterfall([ + function (next) { + file.isFileTypeAllowed(image.path, next); + }, + function (next) { + file.saveFileToLocal(filename, folder, image.path, next); + }, + function (upload, next) { + next(null, { + url: upload.url, + path: upload.path, + name: image.name, + }); + }, + ], callback); +}; diff --git a/src/languages.js b/src/languages.js index 65d5c2113d..2d23c55375 100644 --- a/src/languages.js +++ b/src/languages.js @@ -7,6 +7,9 @@ var async = require('async'); var Languages = module.exports; var languagesPath = path.join(__dirname, '../build/public/language'); +const files = fs.readdirSync(path.join(__dirname, '../public/vendor/jquery/timeago/locales')); +Languages.timeagoCodes = files.filter(f => f.startsWith('jquery.timeago')).map(f => f.split('.')[2]); + Languages.get = function (language, namespace, callback) { fs.readFile(path.join(languagesPath, language, namespace + '.json'), { encoding: 'utf-8' }, function (err, data) { if (err) { diff --git a/src/meta/build.js b/src/meta/build.js index c5fc937d30..224f22d508 100644 --- a/src/meta/build.js +++ b/src/meta/build.js @@ -167,19 +167,14 @@ function build(targets, options, callback) { return aliases[target]; }) // filter nonexistent targets - .filter(Boolean) - // map multitargets to their sets - .reduce(function (prev, target) { - if (Array.isArray(targetHandlers[target])) { - return prev.concat(targetHandlers[target]); - } + .filter(Boolean); - return prev.concat(target); - }, []) - // unique - .filter(function (target, i, arr) { - return arr.indexOf(target) === i; - }); + // map multitargets to their sets + targets = _.uniq(_.flatMap(targets, target => ( + Array.isArray(targetHandlers[target]) ? + targetHandlers[target] : + target + ))); winston.verbose('[build] building the following targets: ' + targets.join(', ')); diff --git a/src/meta/minifier.js b/src/meta/minifier.js index e4722e1339..0024bbb9af 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -232,7 +232,7 @@ function minifyAndSave(data, callback) { var minified = uglify.minify(scripts, { sourceMap: { filename: data.filename, - url: data.filename + '.map', + url: String(data.filename).split(/[/\\]/).pop() + '.map', includeSources: true, }, compress: false, diff --git a/src/middleware/header.js b/src/middleware/header.js index 55e596fef5..c7992c8eb2 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -4,6 +4,7 @@ var path = require('path'); var async = require('async'); var nconf = require('nconf'); var jsesc = require('jsesc'); +var _ = require('lodash'); var db = require('../database'); var user = require('../user'); @@ -24,12 +25,16 @@ var controllers = { }; module.exports = function (middleware) { - middleware.buildHeader = function (req, res, next) { + middleware.buildHeader = function buildHeader(req, res, next) { res.locals.renderHeader = true; res.locals.isAPI = false; async.waterfall([ function (next) { - middleware.applyCSRF(req, res, next); + if (req.uid >= 0) { + middleware.applyCSRF(req, res, next); + } else { + setImmediate(next); + } }, function (next) { async.parallel({ @@ -42,13 +47,13 @@ module.exports = function (middleware) { }, next); }, function (results, next) { - res.locals.config = results.config; - next(); + // Return no arguments + setImmediate(next); }, ], next); }; - middleware.generateHeader = function (req, res, data, callback) { + middleware.generateHeader = function generateHeader(req, res, data, callback) { var registrationType = meta.config.registrationType || 'normal'; res.locals.config = res.locals.config || {}; var templateValues = { @@ -108,7 +113,7 @@ module.exports = function (middleware) { banned: async.apply(user.isBanned, req.uid), banReason: async.apply(user.getBannedReason, req.uid), - unreadCounts: async.apply(topics.getUnreadTids, { uid: req.uid, count: true }), + unreadData: async.apply(topics.getUnreadData, { uid: req.uid }), unreadChatCount: async.apply(messaging.getUnreadCount, req.uid), unreadNotificationCount: async.apply(user.notifications.getUnreadCount, req.uid), }, next); @@ -119,6 +124,14 @@ module.exports = function (middleware) { return res.redirect('/'); } + const unreadData = { + '': {}, + new: {}, + watched: {}, + unreplied: {}, + }; + + results.user.unreadData = unreadData; results.user.isAdmin = results.isAdmin; results.user.isGlobalMod = results.isGlobalMod; results.user.isMod = !!results.isModerator; @@ -129,13 +142,15 @@ module.exports = function (middleware) { results.user['email:confirmed'] = results.user['email:confirmed'] === 1; results.user.isEmailConfirmSent = !!results.isEmailConfirmSent; - templateValues.bootswatchSkin = parseInt(meta.config.disableCustomUserSkins, 10) !== 1 ? res.locals.config.bootswatchSkin || '' : ''; + templateValues.bootswatchSkin = (parseInt(meta.config.disableCustomUserSkins, 10) !== 1 ? res.locals.config.bootswatchSkin : '') || meta.config.bootswatchSkin || ''; + templateValues.config.bootswatchSkin = templateValues.bootswatchSkin || 'noskin'; // TODO remove in v1.12.0+ + const unreadCounts = results.unreadData.counts; var unreadCount = { - topic: results.unreadCounts[''] || 0, - newTopic: results.unreadCounts.new || 0, - watchedTopic: results.unreadCounts.watched || 0, - unrepliedTopic: results.unreadCounts.unreplied || 0, + topic: unreadCounts[''] || 0, + newTopic: unreadCounts.new || 0, + watchedTopic: unreadCounts.watched || 0, + unrepliedTopic: unreadCounts.unreplied || 0, chat: results.unreadChatCount || 0, notification: results.unreadNotificationCount || 0, }; @@ -146,19 +161,21 @@ module.exports = function (middleware) { } }); + const tidsByFilter = results.unreadData.tidsByFilter; results.navigation = results.navigation.map(function (item) { - function modifyNavItem(item, route, count, content) { + function modifyNavItem(item, route, filter, content) { if (item && item.originalRoute === route) { + unreadData[filter] = _.zipObject(tidsByFilter[filter], tidsByFilter[filter].map(() => true)); item.content = content; - if (count > 0) { + if (unreadCounts[filter] > 0) { item.iconClass += ' unread-count'; } } } - modifyNavItem(item, '/unread', results.unreadCounts[''], unreadCount.topic); - modifyNavItem(item, '/unread?filter=new', results.unreadCounts.new, unreadCount.newTopic); - modifyNavItem(item, '/unread?filter=watched', results.unreadCounts.watched, unreadCount.watchedTopic); - modifyNavItem(item, '/unread?filter=unreplied', results.unreadCounts.unreplied, unreadCount.unrepliedTopic); + modifyNavItem(item, '/unread', '', unreadCount.topic); + modifyNavItem(item, '/unread?filter=new', 'new', unreadCount.newTopic); + modifyNavItem(item, '/unread?filter=watched', 'watched', unreadCount.watchedTopic); + modifyNavItem(item, '/unread?filter=unreplied', 'unreplied', unreadCount.unrepliedTopic); return item; }); @@ -202,7 +219,7 @@ module.exports = function (middleware) { }); }; - middleware.renderHeader = function (req, res, data, callback) { + middleware.renderHeader = function renderHeader(req, res, data, callback) { async.waterfall([ async.apply(middleware.generateHeader, req, res, data), function (templateValues, next) { @@ -211,7 +228,7 @@ module.exports = function (middleware) { ], callback); }; - middleware.renderFooter = function (req, res, data, callback) { + middleware.renderFooter = function renderFooter(req, res, data, callback) { async.waterfall([ function (next) { plugins.fireHook('filter:middleware.renderFooter', { @@ -224,20 +241,18 @@ module.exports = function (middleware) { async.parallel({ scripts: async.apply(plugins.fireHook, 'filter:scripts.get', []), timeagoLocale: (next) => { - const userLang = res.locals.config.userLang; - const pathToLocaleFile = '/vendor/jquery/timeago/locales/jquery.timeago.' + utils.userLangToTimeagoCode(userLang) + '.js'; - async.waterfall([ - async.apply(languages.list), - (languages, next) => { - if (!languages.some(obj => obj.code === userLang)) { - return next(null, false); - } + async.apply(languages.listCodes), + (languageCodes, next) => { + const userLang = res.locals.config.userLang; + const timeagoCode = utils.userLangToTimeagoCode(userLang); - file.exists(path.join(__dirname, '../../public', pathToLocaleFile), next); - }, - (exists, next) => { - next(null, exists ? (nconf.get('relative_path') + '/assets' + pathToLocaleFile) : null); + if (languageCodes.includes(userLang) && languages.timeagoCodes.includes(timeagoCode)) { + const pathToLocaleFile = '/vendor/jquery/timeago/locales/jquery.timeago.' + timeagoCode + '.js'; + next(null, (nconf.get('relative_path') + '/assets' + pathToLocaleFile)); + } else { + next(null, false); + } }, ], next); }, @@ -255,7 +270,7 @@ module.exports = function (middleware) { data.templateValues.useCustomJS = meta.config.useCustomJS; data.templateValues.customJS = data.templateValues.useCustomJS ? meta.config.customJS : ''; - data.templateValues.isSpider = req.isSpider(); + data.templateValues.isSpider = req.uid === -1; req.app.render('footer', data.templateValues, next); }, ], callback); diff --git a/src/middleware/headers.js b/src/middleware/headers.js index ef9935ec37..8be72ee9c7 100644 --- a/src/middleware/headers.js +++ b/src/middleware/headers.js @@ -8,7 +8,7 @@ var meta = require('../meta'); var languages = require('../languages'); module.exports = function (middleware) { - middleware.addHeaders = function (req, res, next) { + middleware.addHeaders = function addHeaders(req, res, next) { var headers = { 'X-Powered-By': encodeURI(meta.config['powered-by'] || 'NodeBB'), 'X-Frame-Options': meta.config['allow-from-uri'] ? 'ALLOW-FROM ' + encodeURI(meta.config['allow-from-uri']) : 'SAMEORIGIN', @@ -64,7 +64,7 @@ module.exports = function (middleware) { }; let langs = []; - middleware.autoLocale = function (req, res, next) { + middleware.autoLocale = function autoLocale(req, res, next) { if (parseInt(req.uid, 10) > 0 || !meta.config.autoDetectLang) { return next(); } diff --git a/src/middleware/index.js b/src/middleware/index.js index ffeece7980..896ddbf76c 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -21,7 +21,7 @@ var controllers = { helpers: require('../controllers/helpers'), }; -var delayCache = LRU({ +var delayCache = new LRU({ maxAge: 1000 * 60, }); @@ -42,7 +42,7 @@ require('./maintenance')(middleware); require('./user')(middleware); require('./headers')(middleware); -middleware.stripLeadingSlashes = function (req, res, next) { +middleware.stripLeadingSlashes = function stripLeadingSlashes(req, res, next) { var target = req.originalUrl.replace(nconf.get('relative_path'), ''); if (target.startsWith('//')) { res.redirect(nconf.get('relative_path') + target.replace(/^\/+/, '/')); @@ -51,7 +51,7 @@ middleware.stripLeadingSlashes = function (req, res, next) { } }; -middleware.pageView = function (req, res, next) { +middleware.pageView = function pageView(req, res, next) { analytics.pageView({ ip: req.ip, uid: req.uid, @@ -73,7 +73,7 @@ middleware.pageView = function (req, res, next) { }; -middleware.pluginHooks = function (req, res, next) { +middleware.pluginHooks = function pluginHooks(req, res, next) { async.each(plugins.loadedHooks['filter:router.page'] || [], function (hookObj, next) { hookObj.method(req, res, next); }, function (err) { @@ -82,7 +82,7 @@ middleware.pluginHooks = function (req, res, next) { }); }; -middleware.validateFiles = function (req, res, next) { +middleware.validateFiles = function validateFiles(req, res, next) { if (!Array.isArray(req.files.files) || !req.files.files.length) { return next(new Error(['[[error:invalid-files]]'])); } @@ -90,12 +90,12 @@ middleware.validateFiles = function (req, res, next) { next(); }; -middleware.prepareAPI = function (req, res, next) { +middleware.prepareAPI = function prepareAPI(req, res, next) { res.locals.isAPI = true; next(); }; -middleware.routeTouchIcon = function (req, res) { +middleware.routeTouchIcon = function routeTouchIcon(req, res) { if (meta.config['brand:touchIcon'] && validator.isURL(meta.config['brand:touchIcon'])) { return res.redirect(meta.config['brand:touchIcon']); } @@ -111,7 +111,7 @@ middleware.routeTouchIcon = function (req, res) { }); }; -middleware.privateTagListing = function (req, res, next) { +middleware.privateTagListing = function privateTagListing(req, res, next) { if (!req.loggedIn && meta.config.privateTagListing) { controllers.helpers.notAllowed(req, res); } else { @@ -119,11 +119,11 @@ middleware.privateTagListing = function (req, res, next) { } }; -middleware.exposeGroupName = function (req, res, next) { +middleware.exposeGroupName = function exposeGroupName(req, res, next) { expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next); }; -middleware.exposeUid = function (req, res, next) { +middleware.exposeUid = function exposeUid(req, res, next) { expose('uid', user.getUidByUserslug, 'userslug', req, res, next); }; @@ -142,7 +142,7 @@ function expose(exposedField, method, field, req, res, next) { ], next); } -middleware.privateUploads = function (req, res, next) { +middleware.privateUploads = function privateUploads(req, res, next) { if (req.loggedIn || !meta.config.privateUploads) { return next(); } @@ -158,7 +158,7 @@ middleware.privateUploads = function (req, res, next) { next(); }; -middleware.busyCheck = function (req, res, next) { +middleware.busyCheck = function busyCheck(req, res, next) { if (global.env === 'production' && meta.config.eventLoopCheckEnabled && toobusy()) { analytics.increment('errors:503'); res.status(503).type('text/html').sendFile(path.join(__dirname, '../../public/503.html')); @@ -167,13 +167,13 @@ middleware.busyCheck = function (req, res, next) { } }; -middleware.applyBlacklist = function (req, res, next) { +middleware.applyBlacklist = function applyBlacklist(req, res, next) { meta.blacklist.test(req.ip, function (err) { next(err); }); }; -middleware.delayLoading = function (req, res, next) { +middleware.delayLoading = function delayLoading(req, res, next) { // Introduces an artificial delay during load so that brute force attacks are effectively mitigated // Add IP to cache so if too many requests are made, subsequent requests are blocked for a minute @@ -186,7 +186,7 @@ middleware.delayLoading = function (req, res, next) { setTimeout(next, 1000); }; -middleware.buildSkinAsset = function (req, res, next) { +middleware.buildSkinAsset = function buildSkinAsset(req, res, next) { // If this middleware is reached, a skin was requested, so it is built on-demand var target = path.basename(req.originalUrl).match(/(client-[a-z]+)/); if (target) { @@ -206,7 +206,7 @@ middleware.buildSkinAsset = function (req, res, next) { } }; -middleware.trimUploadTimestamps = (req, res, next) => { +middleware.trimUploadTimestamps = function trimUploadTimestamps(req, res, next) { // Check match let basename = path.basename(req.path); if (req.path.startsWith('/uploads/files/') && middleware.regexes.timestampedUpload.test(basename)) { @@ -214,5 +214,5 @@ middleware.trimUploadTimestamps = (req, res, next) => { res.header('Content-Disposition', 'inline; filename="' + basename + '"'); } - return next(); + next(); }; diff --git a/src/middleware/maintenance.js b/src/middleware/maintenance.js index 6b7bb65082..4297c88494 100644 --- a/src/middleware/maintenance.js +++ b/src/middleware/maintenance.js @@ -6,7 +6,7 @@ var meta = require('../meta'); var user = require('../user'); module.exports = function (middleware) { - middleware.maintenanceMode = function (req, res, callback) { + middleware.maintenanceMode = function maintenanceMode(req, res, callback) { if (!meta.config.maintenanceMode) { return setImmediate(callback); } diff --git a/src/middleware/render.js b/src/middleware/render.js index 4d6476dc34..56ee550504 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -11,10 +11,10 @@ var widgets = require('../widgets'); var utils = require('../utils'); module.exports = function (middleware) { - middleware.processRender = function (req, res, next) { + middleware.processRender = function processRender(req, res, next) { // res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687 var render = res.render; - res.render = function (template, options, fn) { + res.render = function renderOverride(template, options, fn) { var self = this; var req = this.req; var defaultFn = function (err, str) { @@ -37,7 +37,7 @@ module.exports = function (middleware) { var templateToRender; async.waterfall([ function (next) { - options.loggedIn = !!req.uid; + options.loggedIn = req.uid > 0; options.relative_path = nconf.get('relative_path'); options.template = { name: template }; options.template[template] = true; diff --git a/src/middleware/user.js b/src/middleware/user.js index fb765f0599..1ae72c6260 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -43,21 +43,21 @@ module.exports = function (middleware) { callback(); } - middleware.authenticate = function (req, res, next) { + middleware.authenticate = function middlewareAuthenticate(req, res, next) { authenticate(req, res, next, function () { controllers.helpers.notAllowed(req, res, next); }); }; - middleware.authenticateOrGuest = function (req, res, next) { + middleware.authenticateOrGuest = function authenticateOrGuest(req, res, next) { authenticate(req, res, next, next); }; - middleware.ensureSelfOrGlobalPrivilege = function (req, res, next) { + middleware.ensureSelfOrGlobalPrivilege = function ensureSelfOrGlobalPrivilege(req, res, next) { ensureSelfOrMethod(user.isAdminOrGlobalMod, req, res, next); }; - middleware.ensureSelfOrPrivileged = function (req, res, next) { + middleware.ensureSelfOrPrivileged = function ensureSelfOrPrivileged(req, res, next) { ensureSelfOrMethod(user.isPrivileged, req, res, next); }; @@ -87,7 +87,7 @@ module.exports = function (middleware) { ], next); } - middleware.checkGlobalPrivacySettings = function (req, res, next) { + middleware.checkGlobalPrivacySettings = function checkGlobalPrivacySettings(req, res, next) { if (!req.loggedIn && meta.config.privateUserInfo) { return middleware.authenticate(req, res, next); } @@ -95,7 +95,7 @@ module.exports = function (middleware) { next(); }; - middleware.checkAccountPermissions = function (req, res, next) { + middleware.checkAccountPermissions = function checkAccountPermissions(req, res, next) { // This middleware ensures that only the requested user and admins can pass async.waterfall([ function (next) { @@ -128,8 +128,8 @@ module.exports = function (middleware) { ], next); }; - middleware.redirectToAccountIfLoggedIn = function (req, res, next) { - if (req.session.forceLogin || !req.uid) { + middleware.redirectToAccountIfLoggedIn = function redirectToAccountIfLoggedIn(req, res, next) { + if (req.session.forceLogin || req.uid <= 0) { return next(); } @@ -143,7 +143,7 @@ module.exports = function (middleware) { ], next); }; - middleware.redirectUidToUserslug = function (req, res, next) { + middleware.redirectUidToUserslug = function redirectUidToUserslug(req, res, next) { var uid = parseInt(req.params.uid, 10); if (uid <= 0) { return next(); @@ -164,7 +164,7 @@ module.exports = function (middleware) { ], next); }; - middleware.redirectMeToUserslug = function (req, res, next) { + middleware.redirectMeToUserslug = function redirectMeToUserslug(req, res, next) { var uid = req.uid; async.waterfall([ function (next) { @@ -180,7 +180,7 @@ module.exports = function (middleware) { ], next); }; - middleware.isAdmin = function (req, res, next) { + middleware.isAdmin = function isAdmin(req, res, next) { async.waterfall([ function (next) { user.isAdministrator(req.uid, next); @@ -233,7 +233,7 @@ module.exports = function (middleware) { res.status(403).render('403', { title: '[[global:403.title]]' }); }; - middleware.registrationComplete = function (req, res, next) { + middleware.registrationComplete = function registrationComplete(req, res, next) { // If the user's session contains registration data, redirect the user to complete registration if (!req.session.hasOwnProperty('registration')) { return setImmediate(next); @@ -244,7 +244,7 @@ module.exports = function (middleware) { controllers.helpers.redirect(res, '/register/complete'); } else { - return setImmediate(next); + setImmediate(next); } }; }; diff --git a/src/notifications.js b/src/notifications.js index fbcc978e18..2f0f5ab916 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -24,6 +24,7 @@ Notifications.baseTypes = [ 'notificationType_follow', 'notificationType_new-chat', 'notificationType_group-invite', + 'notificationType_group-request-membership', ]; Notifications.privilegedTypes = [ @@ -557,11 +558,9 @@ Notifications.merge = function (notifications, callback) { case 'notifications:user_posted_to': case 'notifications:user_flagged_post_in': case 'notifications:user_flagged_user': - var usernames = set.map(function (notifObj) { + var usernames = _.uniq(set.map(function (notifObj) { return notifObj && notifObj.user && notifObj.user.username; - }).filter(function (username, idx, array) { - return array.indexOf(username) === idx; - }); + })); var numUsers = usernames.length; var title = utils.decodeHTMLEntities(notifications[modifyIndex].topicTitle || ''); diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index d5f268a80e..fc460fa260 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -84,19 +84,31 @@ module.exports = function (Plugins) { Plugins.fireHook = function (hook, params, callback) { callback = typeof callback === 'function' ? callback : function () {}; - + function done(err, result) { + if (err) { + return callback(err); + } + if (hook !== 'action:plugins.firehook') { + Plugins.fireHook('action:plugins.firehook', { hook: hook, params: params }); + } + if (result !== undefined) { + callback(null, result); + } else { + callback(); + } + } var hookList = Plugins.loadedHooks[hook]; var hookType = hook.split(':')[0]; winston.verbose('[plugins/fireHook]', hook); switch (hookType) { case 'filter': - fireFilterHook(hook, hookList, params, callback); + fireFilterHook(hook, hookList, params, done); break; case 'action': - fireActionHook(hook, hookList, params, callback); + fireActionHook(hook, hookList, params, done); break; case 'static': - fireStaticHook(hook, hookList, params, callback); + fireStaticHook(hook, hookList, params, done); break; default: winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); diff --git a/src/plugins/load.js b/src/plugins/load.js index 4a47b24c21..3d39b24d44 100644 --- a/src/plugins/load.js +++ b/src/plugins/load.js @@ -81,15 +81,6 @@ module.exports = function (Plugins) { } Plugins.prepareForBuild = function (targets, callback) { - Plugins.cssFiles.length = 0; - Plugins.lessFiles.length = 0; - Plugins.acpLessFiles.length = 0; - Plugins.clientScripts.length = 0; - Plugins.acpScripts.length = 0; - Plugins.soundpacks.length = 0; - Plugins.languageData.languages = []; - Plugins.languageData.namespaces = []; - var map = { 'plugin static dirs': ['staticDirs'], 'requirejs modules': ['modules'], @@ -101,13 +92,27 @@ module.exports = function (Plugins) { languages: ['languageData'], }; - var fields = targets.reduce(function (prev, target) { - if (!map[target]) { - return prev; + var fields = _.uniq(_.flatMap(targets, target => map[target] || [])); + + // clear old data before build + fields.forEach((field) => { + switch (field) { + case 'clientScripts': + case 'acpScripts': + case 'cssFiles': + case 'lessFiles': + case 'acpLessFiles': + Plugins[field].length = 0; + break; + case 'soundpack': + Plugins.soundpacks.length = 0; + break; + case 'languageData': + Plugins.languageData.languages = []; + Plugins.languageData.namespaces = []; + break; + // do nothing for modules and staticDirs } - return prev.concat(map[target]); - }, []).filter(function (field, i, arr) { - return arr.indexOf(field) === i; }); winston.verbose('[plugins] loading the following fields from plugin data: ' + fields.join(', ')); diff --git a/src/posts/bookmarks.js b/src/posts/bookmarks.js index 241c5b85c3..c609408821 100644 --- a/src/posts/bookmarks.js +++ b/src/posts/bookmarks.js @@ -86,12 +86,7 @@ module.exports = function (Posts) { Posts.hasBookmarked = function (pid, uid, callback) { if (parseInt(uid, 10) <= 0) { - if (Array.isArray(pid)) { - callback(null, pid.map(() => false)); - } else { - callback(null, false); - } - return; + return callback(null, Array.isArray(pid) ? pid.map(() => false) : false); } if (Array.isArray(pid)) { diff --git a/src/posts/cache.js b/src/posts/cache.js index 7d45ba8631..4d03cd3db1 100644 --- a/src/posts/cache.js +++ b/src/posts/cache.js @@ -3,7 +3,7 @@ var LRU = require('lru-cache'); var meta = require('../meta'); -var cache = LRU({ +var cache = new LRU({ max: meta.config.postCacheSize, length: function (n) { return n.length; }, maxAge: 0, diff --git a/src/posts/queue.js b/src/posts/queue.js index 7dd311aa74..d2203fdc68 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -1,11 +1,14 @@ 'use strict'; var async = require('async'); +const _ = require('lodash'); var db = require('../database'); var user = require('../user'); var meta = require('../meta'); +var groups = require('../groups'); var topics = require('../topics'); +var categories = require('../categories'); var notifications = require('../notifications'); var privileges = require('../privileges'); var plugins = require('../plugins'); @@ -18,7 +21,7 @@ module.exports = function (Posts) { user.getUserFields(uid, ['uid', 'reputation', 'postcount'], next); }, function (userData, next) { - var shouldQueue = meta.config.postQueue && (!userData.uid || userData.reputation < 0 || userData.postcount <= 0); + const shouldQueue = meta.config.postQueue && (!userData.uid || userData.reputation < 0 || userData.postcount <= 0); plugins.fireHook('filter:post.shouldQueue', { shouldQueue: shouldQueue, uid: uid, @@ -31,6 +34,44 @@ module.exports = function (Posts) { ], callback); }; + function removeQueueNotification(id, callback) { + async.waterfall([ + function (next) { + notifications.rescind('post-queue-' + id, next); + }, + function (next) { + getParsedObject(id, next); + }, + function (data, next) { + if (!data) { + return callback(); + } + getCid(data.type, data, next); + }, + function (cid, next) { + getNotificationUids(cid, next); + }, + function (uids, next) { + uids.forEach(uid => user.notifications.pushCount(uid)); + next(); + }, + ], callback); + } + + function getNotificationUids(cid, callback) { + async.waterfall([ + function (next) { + async.parallel([ + async.apply(groups.getMembersOfGroups, ['administrators', 'Global Moderators']), + async.apply(categories.getModeratorUids, [cid]), + ], next); + }, + function (results, next) { + next(null, _.uniq(_.flattenDeep(results))); + }, + ], callback); + } + Posts.addToQueue = function (data, callback) { var type = data.title ? 'topic' : 'reply'; var id = type + '-' + Date.now(); @@ -64,14 +105,21 @@ module.exports = function (Posts) { path: '/post-queue', }, next); }, - cid: function (next) { - getCid(type, data, next); + uids: function (next) { + async.waterfall([ + function (next) { + getCid(type, data, next); + }, + function (cid, next) { + getNotificationUids(cid, next); + }, + ], next); }, }, next); }, function (results, next) { if (results.notification) { - notifications.pushGroups(results.notification, ['administrators', 'Global Moderators', 'cid:' + results.cid + ':privileges:moderate'], next); + notifications.push(results.notification, results.uids, next); } else { next(); } @@ -127,15 +175,15 @@ module.exports = function (Posts) { Posts.removeFromQueue = function (id, callback) { async.waterfall([ + function (next) { + removeQueueNotification(id, next); + }, function (next) { db.sortedSetRemove('post:queue', id, next); }, function (next) { db.delete('post:queue:' + id, next); }, - function (next) { - notifications.rescind('post-queue-' + id, next); - }, ], callback); }; diff --git a/src/routes/api.js b/src/routes/api.js index 4ff12e4895..1fc95c6764 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -8,7 +8,13 @@ module.exports = function (app, middleware, controllers) { var router = express.Router(); app.use('/api', router); - router.get('/config', middleware.applyCSRF, controllers.api.getConfig); + router.get('/config', function (req, res, next) { + if (req.uid >= 0) { + middleware.applyCSRF(req, res, next); + } else { + setImmediate(next); + } + }, controllers.api.getConfig); router.get('/me', middleware.checkGlobalPrivacySettings, controllers.user.getCurrentUser); router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUID); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 0068e389b4..a4341ddf36 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -3,10 +3,10 @@ var async = require('async'); var passport = require('passport'); var passportLocal = require('passport-local').Strategy; -var nconf = require('nconf'); var winston = require('winston'); var controllers = require('../controllers'); +var helpers = require('../controllers/helpers'); var plugins = require('../plugins'); var loginStrategies = []; @@ -14,8 +14,14 @@ var loginStrategies = []; var Auth = module.exports; Auth.initialize = function (app, middleware) { - app.use(passport.initialize()); - app.use(passport.session()); + const passwortInitMiddleware = passport.initialize(); + app.use(function passportInitialize(req, res, next) { + passwortInitMiddleware(req, res, next); + }); + const passportSessionMiddleware = passport.session(); + app.use(function passportSession(req, res, next) { + passportSessionMiddleware(req, res, next); + }); app.use(Auth.setAuthVars); @@ -23,7 +29,7 @@ Auth.initialize = function (app, middleware) { Auth.middleware = middleware; }; -Auth.setAuthVars = function (req, res, next) { +Auth.setAuthVars = function setAuthVars(req, res, next) { var isSpider = req.isSpider(); req.loggedIn = !isSpider && !!req.user; if (req.user) { @@ -68,8 +74,12 @@ Auth.reloadRoutes = function (router, callback) { }); } - router.get(strategy.callbackURL, function (req, res, next) { - // Ensure the passed-back state value is identical to the saved ssoState + router[strategy.callbackMethod || 'get'](strategy.callbackURL, function (req, res, next) { + // Ensure the passed-back state value is identical to the saved ssoState (unless explicitly skipped) + if (strategy.checkState === false) { + return next(); + } + next(req.query.state !== req.session.ssoState ? new Error('[[error:csrf-invalid]]') : null); }, function (req, res, next) { // Trigger registration interstitial checks @@ -78,10 +88,27 @@ Auth.reloadRoutes = function (router, callback) { // passport seems to remove `req.session.returnTo` after it redirects req.session.registration.returnTo = req.session.returnTo; next(); - }, passport.authenticate(strategy.name, { - successReturnToOrRedirect: nconf.get('relative_path') + (strategy.successUrl !== undefined ? strategy.successUrl : '/'), - failureRedirect: nconf.get('relative_path') + (strategy.failureUrl !== undefined ? strategy.failureUrl : '/login'), - })); + }, function (req, res, next) { + passport.authenticate(strategy.name, function (err, user) { + if (err) { + delete req.session.registration; + return next(err); + } + + if (!user) { + delete req.session.registration; + return helpers.redirect(res, strategy.failureUrl !== undefined ? strategy.failureUrl : '/login'); + } + + req.login(user, function (err) { + if (err) { + return next(err); + } + + helpers.redirect(res, strategy.successUrl !== undefined ? strategy.successUrl : '/'); + }); + })(req, res, next); + }); }); router.post('/register', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.register); diff --git a/src/routes/index.js b/src/routes/index.js index d684b881d1..40abf06e42 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -35,6 +35,7 @@ function mainRoutes(app, middleware, controllers) { setupPageRoute(app, '/tos', middleware, [], controllers.termsOfUse); app.post('/compose', middleware.applyCSRF, controllers.composer.post); + app.post('/email/unsubscribe/:token', controllers.accounts.settings.unsubscribe); } function modRoutes(app, middleware, controllers) { @@ -53,7 +54,9 @@ function topicRoutes(app, middleware, controllers) { } function postRoutes(app, middleware, controllers) { - setupPageRoute(app, '/post/:pid', middleware, [], controllers.posts.redirectToPost); + const middlewares = [middleware.maintenanceMode, middleware.registrationComplete, middleware.pluginHooks]; + app.get('/post/:pid', middleware.busyCheck, middleware.buildHeader, middlewares, controllers.posts.redirectToPost); + app.get('/api/post/:pid', middlewares, controllers.posts.redirectToPost); } function tagRoutes(app, middleware, controllers) { diff --git a/src/search.js b/src/search.js index 978db18cc9..321c8f4619 100644 --- a/src/search.js +++ b/src/search.js @@ -330,7 +330,7 @@ function getSearchCids(data, callback) { async.parallel({ watchedCids: function (next) { if (data.categories.includes('watched')) { - user.getWatchedCategories(data.uid, next); + user.getCategoriesByStates(data.uid, [categories.watchStates.watching], next); } else { setImmediate(next, null, []); } diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index a2afd326d2..76a3ca6476 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -14,6 +14,7 @@ var userDigest = require('../user/digest'); var userEmail = require('../user/email'); var logger = require('../logger'); var events = require('../events'); +var notifications = require('../notifications'); var emailer = require('../emailer'); var db = require('../database'); var analytics = require('../analytics'); @@ -273,6 +274,30 @@ SocketAdmin.email.test = function (socket, data, callback) { }, callback); break; + case 'notification': + async.waterfall([ + function (next) { + notifications.create({ + type: 'test', + bodyShort: '[[admin-settings-email:testing]]', + bodyLong: '[[admin-settings-email:testing.send-help]]', + nid: 'uid:' + socket.uid + ':test', + path: '/', + from: socket.uid, + }, next); + }, + function (notifObj, next) { + emailer.send('notification', socket.uid, { + path: notifObj.path, + subject: utils.stripHTMLTags(notifObj.subject || '[[notifications:new_notification]]'), + intro: utils.stripHTMLTags(notifObj.bodyShort), + body: notifObj.bodyLong || '', + notification: notifObj, + showUnsubscribe: true, + }, next); + }, + ]); + break; default: emailer.send(data.template, socket.uid, payload, callback); break; @@ -333,6 +358,10 @@ SocketAdmin.errors.clear = function (socket, data, callback) { meta.errors.clear(callback); }; +SocketAdmin.deleteEvents = function (socket, eids, callback) { + events.deleteEvents(eids, callback); +}; + SocketAdmin.deleteAllEvents = function (socket, data, callback) { events.deleteAll(callback); }; diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 2af93cad2d..c65cbba9be 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -155,20 +155,28 @@ SocketCategories.getSelectCategories = function (socket, data, callback) { ], callback); }; -SocketCategories.watch = function (socket, cid, callback) { - ignoreOrWatch(user.watchCategory, socket, cid, callback); +SocketCategories.setWatchState = function (socket, data, callback) { + if (!data || !data.cid || !data.state) { + return callback(new Error('[[error:invalid-data]]')); + } + ignoreOrWatch(function (uid, cid, next) { + user.setCategoryWatchState(uid, cid, categories.watchStates[data.state], next); + }, socket, data, callback); }; -SocketCategories.ignore = function (socket, cid, callback) { - ignoreOrWatch(user.ignoreCategory, socket, cid, callback); +SocketCategories.watch = function (socket, data, callback) { + ignoreOrWatch(user.watchCategory, socket, data, callback); }; -function ignoreOrWatch(fn, socket, cid, callback) { +SocketCategories.ignore = function (socket, data, callback) { + ignoreOrWatch(user.ignoreCategory, socket, data, callback); +}; + +function ignoreOrWatch(fn, socket, data, callback) { var targetUid = socket.uid; - var cids = [parseInt(cid, 10)]; - if (typeof cid === 'object') { - targetUid = cid.uid; - cids = [parseInt(cid.cid, 10)]; + var cids = [parseInt(data.cid, 10)]; + if (data.hasOwnProperty('uid')) { + targetUid = data.uid; } async.waterfall([ diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 256389cac6..9a54d87f99 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -2,12 +2,14 @@ var async = require('async'); var winston = require('winston'); +var _ = require('lodash'); var db = require('../database'); var websockets = require('./index'); var user = require('../user'); var posts = require('../posts'); var topics = require('../topics'); +var categories = require('../categories'); var privileges = require('../privileges'); var notifications = require('../notifications'); var plugins = require('../plugins'); @@ -16,21 +18,32 @@ var utils = require('../utils'); var SocketHelpers = module.exports; SocketHelpers.notifyNew = function (uid, type, result) { + let watchStateUids; + let categoryWatchStates; + let topicFollowState; + const post = result.posts[0]; + const tid = post.topic.tid; + const cid = post.topic.cid; async.waterfall([ function (next) { user.getUidsFromSet('users:online', 0, -1, next); }, function (uids, next) { - privileges.topics.filterUids('read', result.posts[0].topic.tid, uids, next); + uids = uids.filter(toUid => parseInt(toUid, 10) !== uid); + privileges.topics.filterUids('read', tid, uids, next); }, function (uids, next) { - filterTidCidIgnorers(uids, result.posts[0].topic.tid, result.posts[0].topic.cid, next); + watchStateUids = uids; + getWatchStates(watchStateUids, tid, cid, next); }, - function (uids, next) { + function (watchStates, next) { + categoryWatchStates = _.zipObject(watchStateUids, watchStates.categoryWatchStates); + topicFollowState = _.zipObject(watchStateUids, watchStates.topicFollowed); + const uids = filterTidCidIgnorers(watchStateUids, watchStates); user.blocks.filterUids(uid, uids, next); }, function (uids, next) { - user.blocks.filterUids(result.posts[0].topic.uid, uids, next); + user.blocks.filterUids(post.topic.uid, uids, next); }, function (uids, next) { plugins.fireHook('filter:sockets.sendNewPostToUids', { uidsTo: uids, uidFrom: uid, type: type }, next); @@ -40,42 +53,38 @@ SocketHelpers.notifyNew = function (uid, type, result) { return winston.error(err.stack); } - result.posts[0].ip = undefined; + post.ip = undefined; data.uidsTo.forEach(function (toUid) { - if (parseInt(toUid, 10) !== uid) { - websockets.in('uid_' + toUid).emit('event:new_post', result); - if (result.topic && type === 'newTopic') { - websockets.in('uid_' + toUid).emit('event:new_topic', result.topic); - } + post.categoryWatchState = categoryWatchStates[toUid]; + post.topic.isFollowing = topicFollowState[toUid]; + websockets.in('uid_' + toUid).emit('event:new_post', result); + if (result.topic && type === 'newTopic') { + websockets.in('uid_' + toUid).emit('event:new_topic', result.topic); } }); }); }; -function filterTidCidIgnorers(uids, tid, cid, callback) { - async.waterfall([ - function (next) { - async.parallel({ - topicFollowed: function (next) { - db.isSetMembers('tid:' + tid + ':followers', uids, next); - }, - topicIgnored: function (next) { - db.isSetMembers('tid:' + tid + ':ignorers', uids, next); - }, - categoryIgnored: function (next) { - db.sortedSetScores('cid:' + cid + ':ignorers', uids, next); - }, - }, next); +function getWatchStates(uids, tid, cid, callback) { + async.parallel({ + topicFollowed: function (next) { + db.isSetMembers('tid:' + tid + ':followers', uids, next); }, - function (results, next) { - uids = uids.filter(function (uid, index) { - return results.topicFollowed[index] || - (!results.topicFollowed[index] && !results.topicIgnored[index] && !results.categoryIgnored[index]); - }); - next(null, uids); + topicIgnored: function (next) { + db.isSetMembers('tid:' + tid + ':ignorers', uids, next); }, - ], callback); + categoryWatchStates: function (next) { + categories.getUidsWatchStates(cid, uids, next); + }, + }, callback); +} + +function filterTidCidIgnorers(uids, watchStates) { + return uids.filter(function (uid, index) { + return watchStates.topicFollowed[index] || + (!watchStates.topicIgnored[index] && watchStates.categoryWatchStates[index] !== categories.watchStates.ignoring); + }); } SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, notification) { diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 1ced452877..91d660317d 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -10,6 +10,7 @@ var cookieParser = require('cookie-parser')(nconf.get('secret')); var db = require('../database'); var user = require('../user'); var logger = require('../logger'); +var plugins = require('../plugins'); var ratelimit = require('../middleware/ratelimit'); @@ -179,12 +180,17 @@ function validateSession(socket, callback) { if (!req.signedCookies || !req.signedCookies[nconf.get('sessionKey')]) { return callback(); } + db.sessionStore.get(req.signedCookies[nconf.get('sessionKey')], function (err, sessionData) { if (err || !sessionData) { return callback(err || new Error('[[error:invalid-session]]')); } - callback(); + plugins.fireHook('static:sockets.validateSession', { + req: req, + socket: socket, + session: sessionData, + }, callback); }); } diff --git a/src/topics/index.js b/src/topics/index.js index 6828f8eae3..fb57fcd5d9 100644 --- a/src/topics/index.js +++ b/src/topics/index.js @@ -188,13 +188,15 @@ Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, topicData.bookmark = results.bookmark; topicData.postSharing = results.postSharing; topicData.deleter = results.deleter; - topicData.deletedTimestampISO = utils.toISOString(topicData.deletedTimestamp); + if (results.deleter) { + topicData.deletedTimestampISO = utils.toISOString(topicData.deletedTimestamp); + } topicData.merger = results.merger; - topicData.mergedTimestampISO = utils.toISOString(topicData.mergedTimestamp); + if (results.merger) { + topicData.mergedTimestampISO = utils.toISOString(topicData.mergedTimestamp); + } topicData.related = results.related || []; - topicData.unreplied = topicData.postcount === 1; - topicData.icons = []; plugins.fireHook('filter:topic.get', { topic: topicData, uid: uid }, next); @@ -245,14 +247,14 @@ function getMainPostAndReplies(topic, set, uid, start, stop, reverse, callback) } function getDeleter(topicData, callback) { - if (!topicData.deleterUid) { + if (!parseInt(topicData.deleterUid, 10)) { return setImmediate(callback, null, null); } user.getUserFields(topicData.deleterUid, ['username', 'userslug', 'picture'], callback); } function getMerger(topicData, callback) { - if (!topicData.mergerUid) { + if (!parseInt(topicData.mergerUid, 10)) { return setImmediate(callback, null, null); } async.waterfall([ diff --git a/src/topics/posts.js b/src/topics/posts.js index 005e5d4eed..33dd80ef44 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -154,7 +154,7 @@ module.exports = function (Topics) { if (!parentPids.length) { return setImmediate(callback); } - + parentPids = _.uniq(parentPids); var parentPosts; async.waterfall([ async.apply(posts.getPostsFields, parentPids, ['uid']), diff --git a/src/topics/tags.js b/src/topics/tags.js index 4acc8810b5..2be85a2c73 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -232,13 +232,13 @@ module.exports = function (Topics) { }; Topics.getTagData = function (tags, callback) { - var keys = tags.map(function (tag) { - return 'tag:' + tag.value; - }); + if (!tags.length) { + return setImmediate(callback, null, []); + } async.waterfall([ function (next) { - db.getObjects(keys, next); + db.getObjects(tags.map(tag => 'tag:' + tag.value), next); }, function (tagData, next) { tags.forEach(function (tag, index) { diff --git a/src/topics/unread.js b/src/topics/unread.js index 2f9b2048a6..9efe5c8363 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -64,15 +64,37 @@ module.exports = function (Topics) { }; Topics.getUnreadTids = function (params, callback) { - var uid = parseInt(params.uid, 10); - var counts = { + async.waterfall([ + function (next) { + Topics.getUnreadData(params, next); + }, + function (results, next) { + next(null, params.count ? results.counts : results.tids); + }, + ], callback); + }; + + Topics.getUnreadData = function (params, callback) { + const uid = parseInt(params.uid, 10); + const counts = { '': 0, new: 0, watched: 0, unreplied: 0, }; + const noUnreadData = { + tids: [], + counts: counts, + tidsByFilter: { + '': [], + new: [], + watched: [], + unreplied: [], + }, + }; + if (uid <= 0) { - return callback(null, params.count ? counts : []); + return setImmediate(callback, null, noUnreadData); } params.filter = params.filter || ''; @@ -102,7 +124,7 @@ module.exports = function (Topics) { }, function (results, next) { if (results.recentTids && !results.recentTids.length && !results.tids_unread.length) { - return callback(null, params.count ? counts : []); + return callback(null, noUnreadData); } filterTopics(params, results, next); @@ -117,9 +139,6 @@ module.exports = function (Topics) { filter: params.filter, }, next); }, - function (results, next) { - next(null, params.count ? results.counts : results.tids); - }, ], callback); }; @@ -166,7 +185,7 @@ module.exports = function (Topics) { tids = tids.slice(0, 200); if (!tids.length) { - return callback(null, { counts: counts, tids: tids }); + return callback(null, { counts: counts, tids: tids, tidsByFilter: tidsByFilter }); } async.waterfall([ @@ -194,8 +213,8 @@ module.exports = function (Topics) { isTopicsFollowed: function (next) { db.sortedSetScores('uid:' + uid + ':followed_tids', tids, next); }, - ignoredCids: function (next) { - categories.isIgnored(cids, uid, next); + categoryWatchState: function (next) { + categories.getWatchState(cids, uid, next); }, readableCids: function (next) { privileges.categories.filterCids('read', cids, uid, next); @@ -205,7 +224,7 @@ module.exports = function (Topics) { function (results, next) { cid = cid && cid.map(String); results.readableCids = results.readableCids.map(String); - const isCidIgnored = _.zipObject(cids, results.ignoredCids); + const userCidState = _.zipObject(cids, results.categoryWatchState); topicData.forEach(function (topic, index) { function cidMatch(topicCid) { @@ -214,7 +233,7 @@ module.exports = function (Topics) { if (topic && topic.cid && cidMatch(topic.cid) && !blockedUids.includes(parseInt(topic.uid, 10))) { topic.tid = parseInt(topic.tid, 10); - if ((results.isTopicsFollowed[index] || !isCidIgnored[topic.cid])) { + if ((results.isTopicsFollowed[index] || userCidState[topic.cid] === categories.watchStates.watching)) { tidsByFilter[''].push(topic.tid); } diff --git a/src/upgrades/1.12.0/category_watch_state.js b/src/upgrades/1.12.0/category_watch_state.js new file mode 100644 index 0000000000..178b7a0354 --- /dev/null +++ b/src/upgrades/1.12.0/category_watch_state.js @@ -0,0 +1,46 @@ +'use strict'; + +var async = require('async'); + +var db = require('../../database'); +var batch = require('../../batch'); +var categories = require('../../categories'); + +module.exports = { + name: 'Update category watch data', + timestamp: Date.UTC(2018, 11, 13), + method: function (callback) { + const progress = this.progress; + let keys; + async.waterfall([ + function (next) { + db.getSortedSetRange('categories:cid', 0, -1, next); + }, + function (cids, next) { + keys = cids.map(cid => 'cid:' + cid + ':ignorers'); + batch.processSortedSet('users:joindate', function (uids, next) { + progress.incr(uids.length); + + async.eachSeries(cids, function (cid, next) { + db.isSortedSetMembers('cid:' + cid + ':ignorers', uids, function (err, isMembers) { + if (err) { + return next(err); + } + uids = uids.filter((uid, index) => isMembers[index]); + if (!uids.length) { + return setImmediate(next); + } + const states = uids.map(() => categories.watchStates.ignoring); + db.sortedSetAdd('cid:' + cid + ':uid:watch:state', states, uids, next); + }); + }, next); + }, { + progress: progress, + }, next); + }, + function (next) { + db.deleteAll(keys, next); + }, + ], callback); + }, +}; diff --git a/src/user/blocks.js b/src/user/blocks.js index 3dfa429935..934a3cba87 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -9,7 +9,7 @@ var pubsub = require('../pubsub'); module.exports = function (User) { User.blocks = { - _cache: LRU({ + _cache: new LRU({ max: 100, length: function () { return 1; }, maxAge: 0, diff --git a/src/user/categories.js b/src/user/categories.js index b81bb8935e..23492d2b3b 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -1,15 +1,39 @@ 'use strict'; -var async = require('async'); +const async = require('async'); +const _ = require('lodash'); -var db = require('../database'); -var categories = require('../categories'); +const db = require('../database'); +const categories = require('../categories'); module.exports = function (User) { - User.getIgnoredCategories = function (uid, callback) { - if (parseInt(uid, 10) <= 0) { - return setImmediate(callback, null, []); + User.setCategoryWatchState = function (uid, cid, state, callback) { + if (!(parseInt(uid, 10) > 0)) { + return setImmediate(callback); } + const isStateValid = Object.keys(categories.watchStates).some(key => categories.watchStates[key] === parseInt(state, 10)); + if (!isStateValid) { + return setImmediate(callback, new Error('[[error:invalid-watch-state]]')); + } + async.waterfall([ + function (next) { + categories.exists(cid, next); + }, + function (exists, next) { + if (!exists) { + return next(new Error('[[error:no-category]]')); + } + + db.sortedSetAdd('cid:' + cid + ':uid:watch:state', state, uid, next); + }, + ], callback); + }; + + User.getCategoryWatchState = function (uid, callback) { + if (parseInt(uid, 10) <= 0) { + return setImmediate(callback, null, {}); + } + let cids; async.waterfall([ function (next) { @@ -17,69 +41,49 @@ module.exports = function (User) { }, function (_cids, next) { cids = _cids; - db.isMemberOfSortedSets(cids.map(cid => 'cid:' + cid + ':ignorers'), uid, next); + categories.getWatchState(cids, uid, next); }, - function (isMembers, next) { - next(null, cids.filter((cid, index) => isMembers[index])); + function (states, next) { + next(null, _.zipObject(cids, states)); }, ], callback); }; + User.getIgnoredCategories = function (uid, callback) { + if (parseInt(uid, 10) <= 0) { + return setImmediate(callback, null, []); + } + User.getCategoriesByStates(uid, [categories.watchStates.ignoring], callback); + }; + User.getWatchedCategories = function (uid, callback) { + if (parseInt(uid, 10) <= 0) { + return setImmediate(callback, null, []); + } + User.getCategoriesByStates(uid, [categories.watchStates.watching], callback); + }; + + User.getCategoriesByStates = function (uid, states, callback) { + if (!(parseInt(uid, 10) > 0)) { + return categories.getAllCidsFromSet('categories:cid', callback); + } + async.waterfall([ function (next) { - async.parallel({ - ignored: function (next) { - User.getIgnoredCategories(uid, next); - }, - all: function (next) { - categories.getAllCidsFromSet('categories:cid', next); - }, - }, next); + User.getCategoryWatchState(uid, next); }, - function (results, next) { - const ignored = new Set(results.ignored); - const watched = results.all.filter(cid => cid && !ignored.has(String(cid))); - next(null, watched); + function (userState, next) { + const cids = Object.keys(userState); + next(null, cids.filter(cid => states.includes(userState[cid]))); }, ], callback); }; User.ignoreCategory = function (uid, cid, callback) { - if (uid <= 0) { - return setImmediate(callback); - } - - async.waterfall([ - function (next) { - categories.exists(cid, next); - }, - function (exists, next) { - if (!exists) { - return next(new Error('[[error:no-category]]')); - } - - db.sortedSetAdd('cid:' + cid + ':ignorers', Date.now(), uid, next); - }, - ], callback); + User.setCategoryWatchState(uid, cid, categories.watchStates.ignoring, callback); }; User.watchCategory = function (uid, cid, callback) { - if (uid <= 0) { - return callback(); - } - - async.waterfall([ - function (next) { - categories.exists(cid, next); - }, - function (exists, next) { - if (!exists) { - return next(new Error('[[error:no-category]]')); - } - - db.sortedSetRemove('cid:' + cid + ':ignorers', uid, next); - }, - ], callback); + User.setCategoryWatchState(uid, cid, categories.watchStates.watching, callback); }; }; diff --git a/src/user/index.js b/src/user/index.js index d8c19ed705..40fda6ab91 100644 --- a/src/user/index.js +++ b/src/user/index.js @@ -291,32 +291,10 @@ User.getModeratorUids = function (callback) { async.waterfall([ async.apply(categories.getAllCidsFromSet, 'categories:cid'), function (cids, next) { - var groupNames = cids.reduce(function (memo, cid) { - memo.push('cid:' + cid + ':privileges:moderate'); - memo.push('cid:' + cid + ':privileges:groups:moderate'); - return memo; - }, []); - - groups.getMembersOfGroups(groupNames, next); + categories.getModeratorUids(cids, next); }, - function (memberSets, next) { - // Every other set is actually a list of user groups, not uids, so convert those to members - var sets = memberSets.reduce(function (memo, set, idx) { - if (idx % 2) { - memo.working.push(set); - } else { - memo.regular.push(set); - } - - return memo; - }, { working: [], regular: [] }); - - groups.getMembersOfGroups(sets.working, function (err, memberSets) { - next(err, sets.regular.concat(memberSets || [])); - }); - }, - function (memberSets, next) { - next(null, _.union.apply(_, memberSets)); + function (uids, next) { + next(null, _.union(uids)); }, ], callback); }; diff --git a/src/user/online.js b/src/user/online.js index 6cb19cd22f..5e788d4c75 100644 --- a/src/user/online.js +++ b/src/user/online.js @@ -5,6 +5,7 @@ var async = require('async'); var db = require('../database'); var topics = require('../topics'); var plugins = require('../plugins'); +var meta = require('../meta'); module.exports = function (User) { User.updateLastOnlineTime = function (uid, callback) { @@ -52,7 +53,7 @@ module.exports = function (User) { }, function (lastonline, next) { function checkOnline(lastonline) { - return now - lastonline < 300000; + return (now - lastonline) < (meta.config.onlineCutoff * 60000); } var isOnline; diff --git a/src/user/picture.js b/src/user/picture.js index caae45e3e9..a7740ed28e 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -3,7 +3,6 @@ var async = require('async'); var winston = require('winston'); -var plugins = require('../plugins'); var file = require('../file'); var image = require('../image'); var meta = require('../meta'); @@ -58,7 +57,7 @@ module.exports = function (User) { var extension = file.typeToExtension(type); var filename = generateProfileImageFilename(data.uid, 'profilecover', extension); - uploadProfileOrCover(filename, picture, next); + image.uploadImage(filename, 'profile', picture, next); }, function (uploadData, next) { url = uploadData.url; @@ -130,7 +129,7 @@ module.exports = function (User) { }, function (next) { var filename = generateProfileImageFilename(data.uid, 'profileavatar', extension); - uploadProfileOrCover(filename, picture, next); + image.uploadImage(filename, 'profile', picture, next); }, function (_uploadedImage, next) { uploadedImage = _uploadedImage; @@ -162,41 +161,12 @@ module.exports = function (User) { ], callback); } - function uploadProfileOrCover(filename, image, callback) { - if (plugins.hasListeners('filter:uploadImage')) { - return plugins.fireHook('filter:uploadImage', { - image: image, - uid: image.uid, - }, callback); - } - - saveFileToLocal(filename, image, callback); - } - function generateProfileImageFilename(uid, type, extension) { var keepAllVersions = meta.config['profile:keepAllUserImages'] === 1; var convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1; return uid + '-' + type + (keepAllVersions ? '-' + Date.now() : '') + (convertToPNG ? '.png' : extension); } - function saveFileToLocal(filename, image, callback) { - async.waterfall([ - function (next) { - file.isFileTypeAllowed(image.path, next); - }, - function (next) { - file.saveFileToLocal(filename, 'profile', image.path, next); - }, - function (upload, next) { - next(null, { - url: upload.url, - path: upload.path, - name: image.name, - }); - }, - ], callback); - } - User.removeCoverPicture = function (data, callback) { db.deleteObjectFields('user:' + data.uid, ['cover:url', 'cover:position'], callback); }; diff --git a/src/user/settings.js b/src/user/settings.js index c59af120cd..ca532e52cb 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -79,6 +79,7 @@ module.exports = function (User) { settings.topicSearchEnabled = parseInt(getSetting(settings, 'topicSearchEnabled', 0), 10) === 1; settings.bootswatchSkin = settings.bootswatchSkin || ''; settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1; + settings.categoryWatchState = getSetting(settings, 'categoryWatchState', 'notwatching'); notifications.getAllNotificationTypes(next); }, @@ -137,6 +138,7 @@ module.exports = function (User) { outgoingChatSound: data.outgoingChatSound, upvoteNotifFreq: data.upvoteNotifFreq, bootswatchSkin: data.bootswatchSkin, + categoryWatchState: data.categoryWatchState, }; async.waterfall([ diff --git a/src/views/admin/advanced/events.tpl b/src/views/admin/advanced/events.tpl index 4372d12b93..55ad612a56 100644 --- a/src/views/admin/advanced/events.tpl +++ b/src/views/admin/advanced/events.tpl @@ -13,7 +13,7 @@
-
+
#{events.eid} {events.type} @@ -23,6 +23,7 @@ {events.user.username} (uid {events.uid}) (IP {events.ip}) + {events.timestampISO}

{events.jsonString}
diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index 79a19664d7..4b70b1f8a2 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -1,4 +1,4 @@ -
+

+
diff --git a/src/views/admin/settings/uploads.tpl b/src/views/admin/settings/uploads.tpl index 175aef06fc..cc4a1ab07c 100644 --- a/src/views/admin/settings/uploads.tpl +++ b/src/views/admin/settings/uploads.tpl @@ -178,7 +178,7 @@

[[admin/settings/uploads:default-covers-help]]

- +
diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index 5094b297e0..a10867a271 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -307,6 +307,15 @@
+
+ + +
+ diff --git a/src/webserver.js b/src/webserver.js index 76e96a3ffb..bdf2e1cd4f 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -166,16 +166,22 @@ function setupExpressApp(app, callback) { app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(cookieParser()); - app.use(useragent.express()); - app.use(detector.middleware()); + const userAgentMiddleware = useragent.express(); + app.use(function userAgent(req, res, next) { + userAgentMiddleware(req, res, next); + }); + const spiderDetectorMiddleware = detector.middleware(); + app.use(function spiderDetector(req, res, next) { + spiderDetectorMiddleware(req, res, next); + }); app.use(session({ store: db.sessionStore, secret: nconf.get('secret'), key: nconf.get('sessionKey'), cookie: setupCookie(), - resave: true, - saveUninitialized: true, + resave: nconf.get('sessionResave') || false, + saveUninitialized: nconf.get('sessionSaveUninitialized') || false, })); var hsts_option = { diff --git a/test/categories.js b/test/categories.js index 448655acbc..5eae36d1f9 100644 --- a/test/categories.js +++ b/test/categories.js @@ -284,18 +284,22 @@ describe('Categories', function () { }); it('should ignore category', function (done) { - socketCategories.ignore({ uid: posterUid }, categoryObj.cid, function (err) { + socketCategories.ignore({ uid: posterUid }, { cid: categoryObj.cid }, function (err) { assert.ifError(err); Categories.isIgnored([categoryObj.cid], posterUid, function (err, isIgnored) { assert.ifError(err); assert.equal(isIgnored[0], true); - done(); + Categories.getIgnorers(categoryObj.cid, 0, -1, function (err, ignorers) { + assert.ifError(err); + assert.deepEqual(ignorers, [posterUid]); + done(); + }); }); }); }); it('should watch category', function (done) { - socketCategories.watch({ uid: posterUid }, categoryObj.cid, function (err) { + socketCategories.watch({ uid: posterUid }, { cid: categoryObj.cid }, function (err) { assert.ifError(err); Categories.isIgnored([categoryObj.cid], posterUid, function (err, isIgnored) { assert.ifError(err); @@ -305,6 +309,13 @@ describe('Categories', function () { }); }); + it('should error if watch state does not exist', function (done) { + socketCategories.setWatchState({ uid: posterUid }, { cid: categoryObj.cid, state: 'invalid-state' }, function (err) { + assert.equal(err.message, '[[error:invalid-watch-state]]'); + done(); + }); + }); + it('should check if user is moderator', function (done) { socketCategories.isModerator({ uid: posterUid }, {}, function (err, isModerator) { assert.ifError(err); @@ -789,6 +800,33 @@ describe('Categories', function () { done(); }); }); + + describe('Categories.getModeratorUids', function () { + before(function (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); + }); + + it('should retrieve all users with moderator bit in category privilege', function (done) { + Categories.getModeratorUids([1, 2], function (err, uids) { + assert.ifError(err); + assert.strictEqual(2, uids.length); + assert.strictEqual(1, parseInt(uids[0], 10)); + assert.strictEqual(0, uids[1].length); + done(); + }); + }); + + after(function (done) { + async.series([ + async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup'), + async.apply(groups.destroy, 'testGroup'), + ], done); + }); + }); }); diff --git a/test/controllers.js b/test/controllers.js index 064f4e96a3..2e101b9d87 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -60,6 +60,35 @@ describe('Controllers', function () { }); }); + it('should load /config with csrf_token', function (done) { + request({ + url: nconf.get('url') + '/api/config', + json: true, + }, function (err, response, body) { + assert.ifError(err); + assert.equal(response.statusCode, 200); + assert(body.csrf_token); + done(); + }); + }); + + it('should load /config with no csrf_token as spider', function (done) { + request({ + url: nconf.get('url') + '/api/config', + json: true, + headers: { + 'user-agent': 'yandex', + }, + }, function (err, response, body) { + assert.ifError(err); + assert.equal(response.statusCode, 200); + assert.strictEqual(body.csrf_token, false); + assert.strictEqual(body.uid, -1); + assert.strictEqual(body.loggedIn, false); + done(); + }); + }); + describe('homepage', function () { function hookMethod(hookData) { assert(hookData.req); diff --git a/test/coverPhoto.js b/test/coverPhoto.js index cb80e72938..1f3cfc27e9 100644 --- a/test/coverPhoto.js +++ b/test/coverPhoto.js @@ -1,7 +1,7 @@ 'use strict'; var assert = require('assert'); -var async = require('async'); +var nconf = require('nconf'); var db = require('./mocks/databasemock'); var coverPhoto = require('../src/coverPhoto'); @@ -9,16 +9,16 @@ var meta = require('../src/meta'); describe('coverPhoto', function () { it('should get default group cover', function (done) { - meta.config['groups:defaultCovers'] = 'image1.png,image2.png'; + meta.config['groups:defaultCovers'] = '/assets/image1.png, /assets/image2.png'; var result = coverPhoto.getDefaultGroupCover('registered-users'); - assert.equal(result, 'image2.png'); + assert.equal(result, nconf.get('relative_path') + '/assets/image2.png'); done(); }); it('should get default default profile cover', function (done) { - meta.config['profile:defaultCovers'] = ' image1.png ,image2.png '; + meta.config['profile:defaultCovers'] = ' /assets/image1.png, /assets/image2.png '; var result = coverPhoto.getDefaultProfileCover(1); - assert.equal(result, 'image2.png'); + assert.equal(result, nconf.get('relative_path') + '/assets/image2.png'); done(); }); }); diff --git a/test/database/hash.js b/test/database/hash.js index 925c45e02b..392379e66b 100644 --- a/test/database/hash.js +++ b/test/database/hash.js @@ -52,6 +52,17 @@ describe('Hash methods', function () { }); }); }); + + it('should work for field names with "." in them', function (done) { + db.setObject('dotObject', { 'my.dot.field': 'foo' }, function (err) { + assert.ifError(err); + db.getObject('dotObject', function (err, data) { + assert.ifError(err); + assert.equal(data['my.dot.field'], 'foo'); + done(); + }); + }); + }); }); describe('setObjectField()', function () { @@ -70,6 +81,17 @@ describe('Hash methods', function () { done(); }); }); + + it('should work for field names with "." in them', function (done) { + db.setObjectField('dotObject2', 'my.dot.field', 'foo2', function (err) { + assert.ifError(err); + db.getObjectField('dotObject2', 'my.dot.field', function (err, value) { + assert.ifError(err); + assert.equal(value, 'foo2'); + done(); + }); + }); + }); }); describe('getObject()', function () { diff --git a/test/database/sorted.js b/test/database/sorted.js index da2e25c951..35adcdfd8a 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -228,6 +228,22 @@ describe('Sorted Set methods', function () { }); }); + it('should return empty array if count is 0', function (done) { + db.getSortedSetRevRangeByScore('sortedSetTest1', 0, 0, '+inf', '-inf', function (err, values) { + assert.ifError(err); + assert.deepEqual(values, []); + done(); + }); + }); + + it('should return elements from 1 to end', function (done) { + db.getSortedSetRevRangeByScore('sortedSetTest1', 1, -1, '+inf', '-inf', function (err, values) { + assert.ifError(err); + assert.deepEqual(values, ['value2', 'value1']); + done(); + }); + }); + it('should return elements from 3 to last', function (done) { db.sortedSetAdd('partialZset', [1, 2, 3, 4, 5], ['value1', 'value2', 'value3', 'value4', 'value5'], function (err) { assert.ifError(err); @@ -523,6 +539,15 @@ describe('Sorted Set methods', function () { done(); }); }); + + it('should return empty array if keys is empty array', function (done) { + db.sortedSetsScore([], 'value1', function (err, scores) { + assert.equal(err, null); + assert.equal(arguments.length, 2); + assert.deepEqual(scores, []); + done(); + }); + }); }); describe('sortedSetScores()', function () { @@ -556,6 +581,15 @@ describe('Sorted Set methods', function () { }); }); + it('should return empty array if values is an empty array', function (done) { + db.sortedSetScores('sortedSetTest1', [], function (err, scores) { + assert.ifError(err); + assert.equal(arguments.length, 2); + assert.deepStrictEqual(scores, []); + done(); + }); + }); + it('should return scores properly', function (done) { db.sortedSetsScore(['zeroScore', 'sortedSetTest1', 'doesnotexist'], 'value1', function (err, scores) { assert.ifError(err); diff --git a/test/groups.js b/test/groups.js index 078f871d7f..c247652650 100644 --- a/test/groups.js +++ b/test/groups.js @@ -1297,7 +1297,11 @@ describe('Groups', function () { assert.ifError(err); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); - assert.equal(data.url, groupData['cover:url']); + assert.equal(nconf.get('relative_path') + data.url, groupData['cover:url']); + if (nconf.get('relative_path')) { + assert(!data.url.startsWith(nconf.get('relative_path'))); + assert(groupData['cover:url'].startsWith(nconf.get('relative_path')), groupData['cover:url']); + } done(); }); }); @@ -1313,7 +1317,7 @@ describe('Groups', function () { assert.ifError(err); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); - assert.equal(data.url, groupData['cover:url']); + assert.equal(nconf.get('relative_path') + data.url, groupData['cover:url']); done(); }); }); @@ -1361,7 +1365,7 @@ describe('Groups', function () { assert.equal(res.statusCode, 200); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); - assert.equal(body[0].url, groupData['cover:url']); + assert.equal(nconf.get('relative_path') + body[0].url, groupData['cover:url']); done(); }); }); diff --git a/test/messaging.js b/test/messaging.js index fa6bc96cf7..2dcf1bc833 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -349,7 +349,7 @@ describe('Messaging Library', function () { it('should notify offline users of message', function (done) { Messaging.notificationSendDelay = 100; - db.sortedSetAdd('users:online', Date.now() - 350000, herpUid, function (err) { + db.sortedSetAdd('users:online', Date.now() - ((meta.config.onlineCutoff * 60000) + 50000), herpUid, function (err) { assert.ifError(err); socketModules.chats.send({ uid: fooUid }, { roomId: roomId, message: 'second chat message' }, function (err) { assert.ifError(err); diff --git a/test/posts.js b/test/posts.js index 4036bc8427..c6678b30fc 100644 --- a/test/posts.js +++ b/test/posts.js @@ -464,7 +464,7 @@ describe('Post\'s', function () { it('should load diffs and reconstruct post', function (done) { posts.diffs.load(replyPid, 0, voterUid, function (err, data) { assert.ifError(err); - assert.equal(data.content, 'A reply to edit\n'); + assert.equal(data.content, 'A reply to edit'); done(); }); }); diff --git a/test/socket.io.js b/test/socket.io.js index 736f2a6378..72b883e841 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -580,6 +580,20 @@ describe('socket.io', function () { }); }); + it('should delete a single event', function (done) { + db.getSortedSetRevRange('events:time', 0, 0, function (err, eids) { + assert.ifError(err); + socketAdmin.deleteEvents({ uid: adminUid }, eids, function (err) { + assert.ifError(err); + db.isSortedSetMembers('events:time', eids, function (err, isMembers) { + assert.ifError(err); + assert(!isMembers.includes(true)); + done(); + }); + }); + }); + }); + it('should delete all events', function (done) { socketAdmin.deleteAllEvents({ uid: adminUid }, {}, function (err) { assert.ifError(err); diff --git a/test/topics.js b/test/topics.js index 633293739f..0c467acdb6 100644 --- a/test/topics.js +++ b/test/topics.js @@ -1377,6 +1377,38 @@ describe('Topic\'s', function () { ], done); }); + it('should not return topics in category you ignored/not watching', function (done) { + var ignoredCid; + var tid; + async.waterfall([ + function (next) { + categories.create({ + name: 'ignored category', + description: 'ignored category', + }, next); + }, + function (category, next) { + ignoredCid = category.cid; + privileges.categories.rescind(['read'], category.cid, 'registered-users', next); + }, + function (next) { + topics.post({ uid: adminUid, title: 'topic in private category', content: 'registered-users cant see this', cid: ignoredCid }, next); + }, + function (data, next) { + tid = data.topicData.tid; + User.ignoreCategory(uid, ignoredCid, next); + }, + function (next) { + topics.getUnreadTids({ uid: uid }, next); + }, + function (unreadTids, next) { + unreadTids = unreadTids.map(String); + assert(!unreadTids.includes(String(tid))); + next(); + }, + ], done); + }); + it('should not return topic as unread if new post is from blocked user', function (done) { var blockedUid; var topic; diff --git a/test/uploads.js b/test/uploads.js index 077ce55704..578b99515d 100644 --- a/test/uploads.js +++ b/test/uploads.js @@ -158,14 +158,21 @@ describe('Upload Controllers', function () { it('should fail if file is not an image', function (done) { file.isFileTypeAllowed(path.join(__dirname, '../test/files/notanimage.png'), function (err) { - assert.equal(err.message, 'Input file is missing or of an unsupported image format'); + assert.equal(err.message, 'Input file contains unsupported image format'); done(); }); }); it('should fail if file is not an image', function (done) { image.size(path.join(__dirname, '../test/files/notanimage.png'), function (err) { - assert.equal(err.message, 'Input file is missing or of an unsupported image format'); + assert.equal(err.message, 'Input file contains unsupported image format'); + done(); + }); + }); + + it('should fail if file is missing', function (done) { + image.size(path.join(__dirname, '../test/files/doesnotexist.png'), function (err) { + assert.equal(err.message, 'Input file is missing'); done(); }); }); diff --git a/test/user.js b/test/user.js index 2137d6aec4..c59021cbde 100644 --- a/test/user.js +++ b/test/user.js @@ -5,6 +5,7 @@ var async = require('async'); var path = require('path'); var nconf = require('nconf'); var request = require('request'); +var jwt = require('jsonwebtoken'); var db = require('./mocks/databasemock'); var User = require('../src/user'); @@ -1257,6 +1258,9 @@ describe('User', function () { function (next) { User.setSetting(uid, 'dailyDigestFreq', 'day', next); }, + function (next) { + User.setSetting(uid, 'notificationType_test', 'notificationemail', next); + }, ], done); }); @@ -1273,6 +1277,110 @@ describe('User', function () { done(); }); }); + + describe('unsubscribe via POST', function () { + it('should unsubscribe from digest if one-click unsubscribe is POSTed', function (done) { + const token = jwt.sign({ + template: 'digest', + uid: uid, + }, nconf.get('secret')); + + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/' + token, + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200); + + db.getObjectField('user:' + uid + ':settings', 'dailyDigestFreq', function (err, value) { + assert.ifError(err); + assert.strictEqual(value, 'off'); + done(); + }); + }); + }); + + it('should unsubscribe from notifications if one-click unsubscribe is POSTed', function (done) { + const token = jwt.sign({ + template: 'notification', + type: 'test', + uid: uid, + }, nconf.get('secret')); + + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/' + token, + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200); + + db.getObjectField('user:' + uid + ':settings', 'notificationType_test', function (err, value) { + assert.ifError(err); + assert.strictEqual(value, 'notification'); + done(); + }); + }); + }); + + it('should return errors on missing template in token', function (done) { + const token = jwt.sign({ + uid: uid, + }, nconf.get('secret')); + + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/' + token, + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 404); + done(); + }); + }); + + it('should return errors on wrong template in token', function (done) { + const token = jwt.sign({ + template: 'user', + uid: uid, + }, nconf.get('secret')); + + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/' + token, + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 404); + done(); + }); + }); + + it('should return errors on missing token', function (done) { + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/', + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 404); + done(); + }); + }); + + it('should return errors on token signed with wrong secret (verify-failure)', function (done) { + const token = jwt.sign({ + template: 'notification', + type: 'test', + uid: uid, + }, nconf.get('secret') + 'aababacaba'); + + request({ + method: 'post', + url: nconf.get('url') + '/email/unsubscribe/' + token, + }, function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403); + done(); + }); + }); + }); }); describe('socket methods', function () {