diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3e7d8120be..c97b7fb8da 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,7 +65,7 @@ jobs: - 5432:5432 redis: - image: 'redis:7.0.11' + image: 'redis:7.0.12' # Set health checks to wait until redis has started options: >- --health-cmd "redis-cli ping" @@ -77,7 +77,7 @@ jobs: - 6379:6379 mongo: - image: 'mongo:3.7' + image: 'mongo:6.0' ports: # Maps port 27017 on service container to the host - 27017:27017 @@ -88,7 +88,7 @@ jobs: - run: cp install/package.json package.json - name: Install Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -194,7 +194,7 @@ jobs: run: npm run coverage - name: Test coverage - uses: coverallsapp/github-action@v2.2.0 + uses: coverallsapp/github-action@v2.2.1 if: matrix.coverage with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -208,7 +208,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Coveralls Finished - uses: coverallsapp/github-action@v2.2.0 + uses: coverallsapp/github-action@v2.2.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true diff --git a/CHANGELOG.md b/CHANGELOG.md index fe73393c69..5fe54cca1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +#### v3.2.3 (2023-07-19) + +##### Chores + +* downgrade harmony to correct version (7c94506b) +* incrementing version number - v3.2.2 (758ecfcd) +* update changelog for v3.2.2 (91a432ad) +* incrementing version number - v3.2.1 (20145074) +* incrementing version number - v3.2.0 (9ecac38e) +* incrementing version number - v3.1.7 (0b4e81ab) +* incrementing version number - v3.1.6 (b3a3b130) +* incrementing version number - v3.1.5 (ec19343a) +* incrementing version number - v3.1.4 (2452783c) +* incrementing version number - v3.1.3 (3b4e9d3f) +* incrementing version number - v3.1.2 (40fa3489) +* incrementing version number - v3.1.1 (40250733) +* incrementing version number - v3.1.0 (0cb386bd) +* incrementing version number - v3.0.1 (26f6ea49) +* incrementing version number - v3.0.0 (224e08cd) + +##### Bug Fixes + +* typo in replied to link (3024dac1) +* logs page whitespace (2a3d6d5c) +* version alert in acp (05c9cca7) +* #11804, fix direction of dropdown on rtl (a4dba8d3) +* #11802, fix anchor ids in acp settings (562e4d6e) +* #11803, fix rtl in acp (a0478c70) + #### v3.2.2 (2023-07-12) ##### Chores diff --git a/Gruntfile.js b/Gruntfile.js index 6c02efa808..dcfa831cd6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -49,8 +49,8 @@ module.exports = function (grunt) { if (!pluginList.includes('nodebb-plugin-composer-default')) { pluginList.push('nodebb-plugin-composer-default'); } - if (!pluginList.includes('nodebb-theme-persona')) { - pluginList.push('nodebb-theme-persona'); + if (!pluginList.includes('nodebb-theme-harmony')) { + pluginList.push('nodebb-theme-harmony'); } } diff --git a/install/data/defaults.json b/install/data/defaults.json index f5317337e3..12acc55fd6 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -64,6 +64,7 @@ "maximumAboutMeLength": 1000, "maximumUsersInChatRoom": 0, "maximumChatMessageLength": 1000, + "maximumChatRoomNameLength": 50, "maximumProfileImageSize": 256, "maximumCoverImageSize": 2048, "profileImageDimension": 200, diff --git a/install/package.json b/install/package.json index 6c3983fc66..1b0e6b64fa 100644 --- a/install/package.json +++ b/install/package.json @@ -29,27 +29,28 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", - "@fontsource/inter": "5.0.3", - "@fontsource/poppins": "5.0.3", - "@isaacs/ttlcache": "1.4.0", + "@fontsource/inter": "5.0.8", + "@fontsource/poppins": "5.0.8", + "@fortawesome/fontawesome-free": "6.4.2", + "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", - "ace-builds": "1.23.1", + "ace-builds": "1.24.1", "archiver": "5.3.1", "async": "3.2.4", - "autoprefixer": "10.4.14", + "autoprefixer": "10.4.15", "bcryptjs": "2.4.3", "benchpressjs": "2.5.1", "body-parser": "1.20.2", "bootbox": "6.0.0", - "bootstrap": "5.2.3", - "bootswatch": "5.2.3", + "bootstrap": "5.3.1", + "bootswatch": "5.3.1", "chalk": "4.1.2", "chart.js": "2.9.4", "cli-graph": "3.2.2", "clipboard": "2.0.11", "colors": "1.4.0", "commander": "11.0.0", - "compare-versions": "5.0.3", + "compare-versions": "6.1.0", "compression": "1.7.4", "connect-flash": "0.1.1", "connect-mongo": "5.0.0", @@ -57,12 +58,12 @@ "connect-pg-simple": "9.0.0", "connect-redis": "7.1.0", "cookie-parser": "1.4.6", - "cron": "2.3.1", + "cron": "2.4.1", "cropperjs": "1.5.13", "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.10", + "esbuild": "0.19.2", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", @@ -71,6 +72,7 @@ "graceful-fs": "4.2.11", "helmet": "7.0.0", "html-to-text": "9.0.5", + "imagesloaded": "5.0.0", "ipaddr.js": "2.1.0", "jquery": "3.7.0", "jquery-deserialize": "2.0.0", @@ -79,41 +81,40 @@ "jquery-ui": "1.13.2", "jsesc": "3.0.2", "json2csv": "5.0.7", - "jsonwebtoken": "9.0.0", - "less": "4.1.3", + "jsonwebtoken": "9.0.1", "lodash": "4.17.21", "logrotate-stream": "0.2.9", - "lru-cache": "10.0.0", + "lru-cache": "10.0.1", "mime": "3.0.0", "mkdirp": "3.0.1", - "mongodb": "5.6.0", + "mongodb": "5.7.0", "morgan": "1.10.0", "mousetrap": "1.6.5", "multiparty": "4.2.3", "nconf": "0.12.0", - "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.4", - "nodebb-plugin-dbsearch": "6.1.0", - "nodebb-plugin-emoji": "5.1.3", + "nodebb-plugin-2factor": "7.2.1", + "nodebb-plugin-composer-default": "10.2.11", + "nodebb-plugin-dbsearch": "6.2.0", + "nodebb-plugin-emoji": "5.1.5", "nodebb-plugin-emoji-android": "4.0.0", - "nodebb-plugin-markdown": "12.1.4", - "nodebb-plugin-mentions": "4.2.0", - "nodebb-plugin-ntfy": "1.0.15", + "nodebb-plugin-markdown": "12.1.7", + "nodebb-plugin-mentions": "4.3.4", + "nodebb-plugin-ntfy": "1.4.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.0.65", - "nodebb-theme-lavender": "7.1.1", - "nodebb-theme-peace": "2.0.32", - "nodebb-theme-persona": "13.1.8", + "nodebb-theme-harmony": "1.1.35", + "nodebb-theme-lavender": "7.1.3", + "nodebb-theme-peace": "2.1.10", + "nodebb-theme-persona": "13.2.17", "nodebb-widget-essentials": "7.0.13", - "nodemailer": "6.9.3", + "nodemailer": "6.9.4", "nprogress": "0.2.0", "passport": "0.6.0", "passport-http-bearer": "1.0.1", "passport-local": "1.0.0", - "pg": "8.11.1", - "pg-cursor": "2.10.1", - "postcss": "8.4.24", + "pg": "8.11.2", + "pg-cursor": "2.10.2", + "postcss": "8.4.28", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", @@ -124,14 +125,13 @@ "rss": "1.2.2", "rtlcss": "4.1.0", "sanitize-html": "2.11.0", - "sass": "1.63.6", - "semver": "7.5.3", + "sass": "1.65.1", + "semver": "7.5.4", "serve-favicon": "2.5.0", - "sharp": "0.32.1", + "sharp": "0.32.5", "sitemap": "7.1.1", - "slideout": "1.0.1", - "socket.io": "4.7.1", - "socket.io-client": "4.7.1", + "socket.io": "4.7.2", + "socket.io-client": "4.7.2", "@socket.io/redis-adapter": "8.2.1", "sortablejs": "1.15.0", "spdx-license-list": "6.6.0", @@ -142,10 +142,10 @@ "timeago": "1.6.7", "tinycon": "0.6.8", "toobusy-js": "0.5.1", - "validator": "13.9.0", - "webpack": "5.88.0", + "validator": "13.11.0", + "webpack": "5.88.2", "webpack-merge": "5.9.0", - "winston": "3.9.0", + "winston": "3.10.0", "xml": "1.0.1", "xregexp": "5.1.1", "yargs": "17.7.2", @@ -153,25 +153,25 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "@commitlint/cli": "17.6.6", - "@commitlint/config-angular": "17.6.6", + "@commitlint/cli": "17.7.1", + "@commitlint/config-angular": "17.7.0", "coveralls": "3.1.1", - "eslint": "8.43.0", + "eslint": "8.47.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.27.5", "grunt": "1.6.1", "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "22.1.0", - "lint-staged": "13.2.3", + "lint-staged": "14.0.0", "mocha": "10.2.0", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", "nyc": "15.1.0", - "smtp-server": "3.12.0" + "smtp-server": "3.13.0" }, "optionalDependencies": { - "sass-embedded": "1.63.6" + "sass-embedded": "1.64.2" }, "resolutions": { "*/jquery": "3.7.0" diff --git a/public/language/ar/admin/admin.json b/public/language/ar/admin/admin.json index 28ad0d39d4..626d8e2212 100644 --- a/public/language/ar/admin/admin.json +++ b/public/language/ar/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ar/admin/dashboard.json b/public/language/ar/admin/dashboard.json index 29970f33c1..584e28374b 100644 --- a/public/language/ar/admin/dashboard.json +++ b/public/language/ar/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "تم تعطيل إعادة بناء NodeBB وإعادة تشغيله حيث لا يبدو أنك تقوم بتشغيله عبر البرنامج الخفي المناسب.", "maintenance-mode": "وضع الصيانة", "maintenance-mode-title": "انقر هنا لإعداد وضع الصيانة لـNodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "التحديث الفوري للرسم البياني", "active-users": "المستخدمين النشطين", @@ -89,5 +90,9 @@ "details.logins-login-time": "وقت تسجيل الدخول", "start": "بدء", "end": "إنهاء", - "filter": "تصفية" + "filter": "تصفية", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ar/admin/manage/categories.json b/public/language/ar/admin/manage/categories.json index 2f371d2292..ae485deeaa 100644 --- a/public/language/ar/admin/manage/categories.json +++ b/public/language/ar/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/ar/admin/manage/users.json b/public/language/ar/admin/manage/users.json index 33df2dcad5..58ec6cb0d4 100644 --- a/public/language/ar/admin/manage/users.json +++ b/public/language/ar/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ar/admin/menu.json b/public/language/ar/admin/menu.json index 1b091099bf..845ad3fcbf 100644 --- a/public/language/ar/admin/menu.json +++ b/public/language/ar/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "الأعضاء", "manage/admins-mods": "Admins & Mods", "manage/registration": "قائمة انتظار التسجيل", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "قائمة انتظار المشاركة", "manage/groups": "المجموعات", "manage/ip-blacklist": "قائمة حظر عناوين IP", diff --git a/public/language/ar/admin/settings/chat.json b/public/language/ar/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ar/admin/settings/chat.json +++ b/public/language/ar/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ar/admin/settings/guest.json b/public/language/ar/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ar/admin/settings/guest.json +++ b/public/language/ar/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ar/email.json b/public/language/ar/email.json index f807ddbfa3..8ee0473c61 100644 --- a/public/language/ar/email.json +++ b/public/language/ar/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "تم تغيير كلمة المرور بنجاح", "reset.notify.text1": "نحيطك علما أن كلمة مرورك قد تم تغييرها في %1", "reset.notify.text2": "إن لم يكن لديك علم بهذا، المرجو إشعار مدبر النظام بأسرع مايمكن.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "آخر المستجدات من %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 5006890609..f5fee4def9 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "عذرا, يجب أن تنتظر 1% ثواني قبل قيامك بأول مشاركة", "blacklisted-ip": "نأسف، لقد تم حظرك من استخدام وتصفح المنتدى. إذا كنت تعتقد أن هذا خطأ رجاءًا اتصل بالإدارة. ", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "رجاءًا ضع تاريخ نهاية الحظر. ", "no-category": "قائمة غير موجودة", "no-topic": "موضوع غير موجود", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "لقد شاركت بالتصويت ، ألا تذكر؟", "reputation-system-disabled": "نظام السمعة معطل", "downvoting-disabled": "التصويتات السلبية معطلة", @@ -199,6 +200,7 @@ "not-in-room": "المستخدم غير موجود في الغرفة.", "cant-kick-self": "لا يمكنك طرد نفسك من المجموعة.", "no-users-selected": "لا يوجد مستخدم محدد.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ar/global.json b/public/language/ar/global.json index e6ebcd7b45..abeee6f705 100644 --- a/public/language/ar/global.json +++ b/public/language/ar/global.json @@ -51,6 +51,8 @@ "nextpage": "الصفحة التالية", "alert.success": "نجاح", "alert.error": "خطأ", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "محظور", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 3a30828fbf..80e6716909 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "لا يوجد لديك دردشات نشطة.", "chat.user_typing": "%1 يكتب رسالة...", "chat.user_has_messaged_you": "%1 أرسل لك رسالة.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "المرجو اختيار مرسل إليه لمعاينة تاريخ الدردشات", @@ -27,22 +28,43 @@ "chat.three_months": "3 أشهر", "chat.delete_message_confirm": "هل أنت متأكد من أنك تريد حذف هذه الرسالة؟", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "اكتب", "composer.show_preview": "عرض المعاينة", "composer.hide_preview": "إخفاء المعاينة", diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 7ec59eaff4..44e149abdf 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -1,6 +1,6 @@ { "topic": "موضوع", - "title": "Title", + "title": "العنوان", "no_topics_found": "لا توجد مواضيع !", "no_posts_found": "لا توجد مشاركات!", "post_is_deleted": "هذه المشاركة محذوفة!", @@ -12,12 +12,12 @@ "notify_me": "تلق تنبيهات بالردود الجديدة في هذا الموضوع", "quote": "اقتبس", "reply": "رد", - "replies_to_this_post": "%1 Replies", - "one_reply_to_this_post": "1 Reply", - "last_reply_time": "Last reply", + "replies_to_this_post": "%1 الردود", + "one_reply_to_this_post": "1 رد", + "last_reply_time": "آخر رد", "reply-as-topic": "رد بموضوع", "guest-login-reply": "يجب عليك تسجيل الدخول للرد", - "login-to-view": "🔒 Log in to view", + "login-to-view": "سجل الدخول للمشاهدة", "edit": "تعديل", "delete": "حذف", "delete-event": "Delete Event", @@ -32,7 +32,7 @@ "tools": "أدوات", "locked": "مقفل", "pinned": "مثبت", - "pinned-with-expiry": "Pinned until %1", + "pinned-with-expiry": "مثبت حتى %1", "scheduled": "Scheduled", "moved": "منقول", "moved-from": "Moved from %1", @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/bg/admin/admin.json b/public/language/bg/admin/admin.json index eebf1de05c..01ae9b511d 100644 --- a/public/language/bg/admin/admin.json +++ b/public/language/bg/admin/admin.json @@ -12,5 +12,7 @@ "min": "Мин.:", "max": "Макс.:", "view": "Преглед", - "edit": "Редактиране" + "edit": "Редактиране", + "add": "Добавяне", + "select-icon": "Изберете иконка" } \ No newline at end of file diff --git a/public/language/bg/admin/dashboard.json b/public/language/bg/admin/dashboard.json index c0c76cf473..1702728fc7 100644 --- a/public/language/bg/admin/dashboard.json +++ b/public/language/bg/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Възможностите за повторно изграждане и рестартиране на NodeBB са изключени, тъй като изглежда, че NodeBB не се изпълнява чрез подходящия демон.", "maintenance-mode": "Режим на профилактика", "maintenance-mode-title": "Щракнете тук, за да зададете режим на профилактика на NodeBB", + "dark-mode": "Тъмен режим", "realtime-chart-updates": "Актуализации на таблиците в реално време", "active-users": "Дейни потребители", @@ -89,5 +90,9 @@ "details.logins-login-time": "Време на вписване", "start": "Начало", "end": "Край", - "filter": "Филтриране" + "filter": "Филтриране", + "view-as-json": "Преглед като JSON", + "expand-analytics": "Разгъване на данните за анализ", + "clear-search-history": "Изчистване на историята на търсенията", + "clear-search-history-confirm": "Наистина ли искате да изчистите историята на търсенията?" } diff --git a/public/language/bg/admin/manage/categories.json b/public/language/bg/admin/manage/categories.json index 1afecd591e..034169a831 100644 --- a/public/language/bg/admin/manage/categories.json +++ b/public/language/bg/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Списък от разрешени етикети", "upload-image": "Качване на изображение", "upload": "Качване", - "select-icon": "Изберете иконка", "delete-image": "Премахване", "category-image": "Изображение на категорията", "image-and-icon": "Изображение и иконка", diff --git a/public/language/bg/admin/manage/users.json b/public/language/bg/admin/manage/users.json index bd7b12a61f..03bc24b017 100644 --- a/public/language/bg/admin/manage/users.json +++ b/public/language/bg/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Изтриване на потребителя/ите и съдържанието", "download-csv": "Сваляне във формат „CSV“", "manage-groups": "Управление на групите", + "set-reputation": "Задаване на репутация", "add-group": "Добавяне на група", "create": "Създаване на потребител", "invite": "Поканване по е-поща", diff --git a/public/language/bg/admin/menu.json b/public/language/bg/admin/menu.json index f777ef8105..4216318024 100644 --- a/public/language/bg/admin/menu.json +++ b/public/language/bg/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Потребители", "manage/admins-mods": "Администратори и модератори", "manage/registration": "Регистрационна опашка", + "manage/flagged-content": "Докладвано съдържание", "manage/post-queue": "Опашка за публикации", "manage/groups": "Групи", "manage/ip-blacklist": "Черен списък за IP адреси", diff --git a/public/language/bg/admin/settings/chat.json b/public/language/bg/admin/settings/chat.json index 6f4e7627e9..0c87d9d35d 100644 --- a/public/language/bg/admin/settings/chat.json +++ b/public/language/bg/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Изключване на редактирането и изтриването на съобщения в разговорите", "disable-editing-help": "Това ограничение не засяга администраторите и глобалните модератори", "max-length": "Максимална дължина на съобщенията в разговорите", + "max-chat-room-name-length": "Максимална дължина на имената на стаи за разговори", "max-room-size": "Максимален брой потребители в стая за разговор", "delay": "Време между съобщенията в разговорите (в милисекунди)", "notification-delay": "Забавяне преди известяване за съобщения в разговорите. (0 – без забавяне)", diff --git a/public/language/bg/email.json b/public/language/bg/email.json index b7d616f427..5a62e0594f 100644 --- a/public/language/bg/email.json +++ b/public/language/bg/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Паролата беше променена успешно", "reset.notify.text1": "Известяваме Ви, че на %1, Вашата парола беше променена успешно.", "reset.notify.text2": "Ако не сте поискали това, моля, свържете се незабавно с администратор.", + "digest.unread-rooms": "Непрочетени стаи", + "digest.room-name-unreadcount": "%1 (%2 непрочетени)", "digest.latest_topics": "Последни теми от %1", "digest.top-topics": "Най-интересните теми от %1", "digest.popular-topics": "Популярни теми от %1", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 779b067093..82bc0a5d3a 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "За съжаление, този акаунт е блокиран до %1 (Причина: %2)", "user-too-new": "Съжаляваме, но трябва да изчакате поне %1 секунда/и, преди да направите първата си публикация", "blacklisted-ip": "Съжаляваме, но Вашият IP адрес е забранен за ползване в тази общност. Ако смятате, че това е грешка, моля, свържете се с администратор.", + "cant-blacklist-self-ip": "Не може да добавите собствения си IP адрес в черния списък", "ban-expiry-missing": "Моля, задайте крайна дата за това блокиране", "no-category": "Категорията не съществува", "no-topic": "Темата не съществува", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Стаята за разговори не съществува.", "cant-add-users-to-chat-room": "Към стаята за разговори не могат да бъдат добавяни потребители.", "cant-remove-users-from-chat-room": "От стаята за разговори не могат да бъдат премахвани потребители.", - "chat-room-name-too-long": "Името на стаята за разговори е твърде дълго.", + "chat-room-name-too-long": "Името на стаята е твърде дълго. Имената не може да са по-дълги от %1 знака.", "already-voting-for-this-post": "Вече сте дали глас за тази публикация.", "reputation-system-disabled": "Системата за репутация е изключена.", "downvoting-disabled": "Отрицателното гласуване е изключено", @@ -199,6 +200,7 @@ "not-in-room": "Потребителят не е в стаята", "cant-kick-self": "Не можете да изритате себе си от групата", "no-users-selected": "Няма избран(и) потребител(и)", + "no-groups-selected": "Няма избрана/и група/и", "invalid-home-page-route": "Грешен път към началната страница", "invalid-session": "Изтекла сесия", "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла. Моля, опреснете страницата.", diff --git a/public/language/bg/global.json b/public/language/bg/global.json index 0efa6c2100..b8f2f1e085 100644 --- a/public/language/bg/global.json +++ b/public/language/bg/global.json @@ -51,6 +51,8 @@ "nextpage": "Следваща страница", "alert.success": "Готово", "alert.error": "Грешка", + "alert.warning": "Предупреждение", + "alert.info": "Информация", "alert.banned": "Блокиран", "alert.banned.message": "Вие току-що бяхте блокиран. Достъпът Ви до системата е ограничен.", "alert.unbanned": "Деблокиран", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 83cd1dd6af..72be8a42bb 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Нямате текущи разговори.", "chat.user_typing": "%1 пише...", "chat.user_has_messaged_you": "%1 Ви написа съобщение.", + "chat.replying-to": "Отговор до %1", "chat.see_all": "Всички разговори", "chat.mark_all_read": "Отбелязване на всички като прочетени", "chat.no-messages": "Моля, изберете получател, за да видите историята на съобщенията", @@ -27,22 +28,43 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Наистина ли искате да изтриете това съобщение?", "chat.retrieving-users": "Получаване на потребителите…", + "chat.view-users-list": "Преглед на списъка с потребители", + "chat.public-rooms": "Публични стаи (%1)", + "chat.private-rooms": "Частни стаи (%1)", + "chat.create-room": "Създаване на стая за разговор", + "chat.private.option": "Частна (видима само за потребителите добавени в стаята)", + "chat.public.option": "Публична (видима за всички в избраните групи)", + "chat.public.groups-help": "За да създадете стая за разговор видима за всички потребители изберете групата с регистрирани потребители от списъка.", "chat.manage-room": "Управление на стаята за разговори", + "chat.add-user": "Добавяне на потребител", + "chat.notification-settings": "Настройки за известията", + "chat.default-notification-setting": "Стандартни настройки за известията", + "chat.notification-setting-room-default": "По подразбиране за стаята", + "chat.notification-setting-none": "Без известия", + "chat.notification-setting-at-mention-only": "Само @споменавания", + "chat.notification-setting-all-messages": "Всички съобщения", + "chat.select-groups": "Избиране на групи", "chat.add-user-help": "Тук можете да потърсите потребители. Когато някой потребител бъде избран, той ще бъде добавен в разговора. Новият потребител няма да може да вижда съобщенията, написани преди включването му в разговора. Само собствениците на стаята () могат да премахват потребители от нея.", "chat.confirm-chat-with-dnd-user": "Този потребител е в състояние „не ме безпокойте“. Наистина ли искате да разговаряте с него?", + "chat.room-name-optional": "Име на стаята (незадължително)", "chat.rename-room": "Преименуване на стаята", "chat.rename-placeholder": "Въведете името на стаята си тук", "chat.rename-help": "Зададеното тук име на стаята ще се вижда от всички участници в нея.", - "chat.leave": "Напускане на разговора", + "chat.leave": "Напускане", + "chat.leave-room": "Напускане на стаята", "chat.leave-prompt": "Наистина ли искате да напуснете този разговор?", "chat.leave-help": "Ако напуснете този разговор, няма да виждате следващите съобщения в него. Ако бъдете добавен(а) отново, няма да виждате историята на разговора отпреди добавянето Ви.", + "chat.delete": "Изтриване", + "chat.delete-room": "Изтриване на стаята", + "chat.delete-prompt": "Наистина ли искате да изтриете тази стая за разговор?", "chat.in-room": "В тази стая", "chat.kick": "Изгонване", "chat.show-ip": "Показване на IP адреса", "chat.owner": "Собственик на стаята", - "chat.system.user-join": "%1 се присъедини към стаята", - "chat.system.user-leave": "%1 напусна стаята", - "chat.system.room-rename": "%2 преименува тази стая: %1", + "chat.grant-rescind-ownership": "Даване/отнемане на собственост", + "chat.system.user-join": "%1 се присъедини към стаята ", + "chat.system.user-leave": "%1 напусна стаята ", + "chat.system.room-rename": "%2 преименува тази стая на „%1“ ", "composer.compose": "Писане", "composer.show_preview": "Показване на прегледа", "composer.hide_preview": "Скриване на прегледа", diff --git a/public/language/bg/topic.json b/public/language/bg/topic.json index 70f8d1e8f3..156670b1aa 100644 --- a/public/language/bg/topic.json +++ b/public/language/bg/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "писа ", "wrote-on": "писа на ", "replied-to-user-ago": "отговори на %3 ", - "replied-to-user-on": "отговори на %3 на ", + "replied-to-user-on": "отговори на %3 на ", "user-locked-topic-ago": "%1 заключи тази тема %2", "user-locked-topic-on": "%1 заключи тази тема на %2", "user-unlocked-topic-ago": "%1 отключи тази тема %2", diff --git a/public/language/bn/admin/admin.json b/public/language/bn/admin/admin.json index a909f03faa..ce847c502d 100644 --- a/public/language/bn/admin/admin.json +++ b/public/language/bn/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/bn/admin/dashboard.json b/public/language/bn/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/bn/admin/dashboard.json +++ b/public/language/bn/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/bn/admin/manage/categories.json b/public/language/bn/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/bn/admin/manage/categories.json +++ b/public/language/bn/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/bn/admin/manage/users.json b/public/language/bn/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/bn/admin/manage/users.json +++ b/public/language/bn/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/bn/admin/menu.json b/public/language/bn/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/bn/admin/menu.json +++ b/public/language/bn/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/bn/admin/settings/chat.json b/public/language/bn/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/bn/admin/settings/chat.json +++ b/public/language/bn/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/bn/admin/settings/guest.json b/public/language/bn/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/bn/admin/settings/guest.json +++ b/public/language/bn/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/bn/email.json b/public/language/bn/email.json index a8870a96bb..89e667c75f 100644 --- a/public/language/bn/email.json +++ b/public/language/bn/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "পাসওয়ার্ড পরিবর্তন সফল হয়েছে", "reset.notify.text1": "আপনাকে জানাচ্ছি যে %1 এ আপনার পাসওয়ার্ড পরিবর্তন হয়েছে", "reset.notify.text2": "এটা আপনার অজান্তে হলে এখনই প্রশাসককে আবহিত করুন", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1 এর সর্বশেষ টপিকসমূহ", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index c7d852a2cb..44f4bdd2b2 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "বিভাগটি খুজে পাওয়া যায় নি", "no-topic": "এই টপিক নেই", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "সম্মাননা ব্যাবস্থা নিস্ক্রীয় রাখা হয়েছে", "downvoting-disabled": "ঋণাত্মক ভোট নিস্ক্রীয় রাখা হয়েছে।", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/bn/global.json b/public/language/bn/global.json index 2a0ae42d9f..5398406fb6 100644 --- a/public/language/bn/global.json +++ b/public/language/bn/global.json @@ -51,6 +51,8 @@ "nextpage": "পরের পাতা", "alert.success": "সফল", "alert.error": "ত্রুটি", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "নিষিদ্ধ", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index 28331cd7da..18793084f6 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "আপনার কোন সচল কথোপকথন নেই", "chat.user_typing": "%1 লিখছেন", "chat.user_has_messaged_you": "%1 আপনাকে বার্তা পাঠিয়েছেন", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "মেসেজ হিস্টোরী দেখতে প্রাপক নির্বাচন করুন", @@ -27,22 +28,43 @@ "chat.three_months": "৩ মাস", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/bn/topic.json b/public/language/bn/topic.json index 6f1ee4c364..2d59e3907c 100644 --- a/public/language/bn/topic.json +++ b/public/language/bn/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/cs/admin/admin.json b/public/language/cs/admin/admin.json index 379f1103cf..5fb62a418b 100644 --- a/public/language/cs/admin/admin.json +++ b/public/language/cs/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/cs/admin/dashboard.json b/public/language/cs/admin/dashboard.json index ce0e5128cc..8d7013572b 100644 --- a/public/language/cs/admin/dashboard.json +++ b/public/language/cs/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Znovu sestavení a restartování vašeho NodeBB bylo zakázáno, protože se nezdá, že byste byl/a připojena přes příslušného „daemona”.", "maintenance-mode": "Režim údržby", "maintenance-mode-title": "Pro nastavení režimu údržby NodeBB, klikněte zde", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Aktualizace grafů v reálném čase", "active-users": "Aktivní uživatelé", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/cs/admin/manage/categories.json b/public/language/cs/admin/manage/categories.json index 89271ab6c2..4fa89573c0 100644 --- a/public/language/cs/admin/manage/categories.json +++ b/public/language/cs/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Seznam povolených značek", "upload-image": "Nahrát obrázek", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Vyjmout", "category-image": "Obrázek kategorie", "image-and-icon": "Image & Icon", diff --git a/public/language/cs/admin/manage/users.json b/public/language/cs/admin/manage/users.json index 8b6cec0b2f..4fbf8835ea 100644 --- a/public/language/cs/admin/manage/users.json +++ b/public/language/cs/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Odstranit uživatele a obsah", "download-csv": "Stáhnout jako CSV", "manage-groups": "Spravovat skupiny", + "set-reputation": "Set Reputation", "add-group": "Přidat skupinu", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/cs/admin/menu.json b/public/language/cs/admin/menu.json index fe6b907b4f..d34e12f605 100644 --- a/public/language/cs/admin/menu.json +++ b/public/language/cs/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Uživatelé", "manage/admins-mods": "Správci a moderátoři", "manage/registration": "Registrační fronta", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fronta příspěvků", "manage/groups": "Skupiny", "manage/ip-blacklist": "Černá listina IP", diff --git a/public/language/cs/admin/settings/chat.json b/public/language/cs/admin/settings/chat.json index 7421f4bd3a..d2873a58db 100644 --- a/public/language/cs/admin/settings/chat.json +++ b/public/language/cs/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Zakázat upravení/odstranění konverzační zprávy", "disable-editing-help": "Správci a globální moderátoři jsou vyjmuti z tohoto omezení", "max-length": "Maximální délka konverzační zprávy", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximální počet uživatelů v konverzační místnosti", "delay": "Čas mezi konverzačními zprávami v milisekundách", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/cs/admin/settings/guest.json b/public/language/cs/admin/settings/guest.json index 27d0bfef44..7f818a9774 100644 --- a/public/language/cs/admin/settings/guest.json +++ b/public/language/cs/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Povolit upravení zacházení s hosty", "handles.enabled-help": "Tato možnost odkryje nové pole, které umožňuje hostům vybrat jméno, které se připojí ke každému příspěvku, který vytvoří. Bude-li zakázáno, budou jednoduše nazýváni „Host”", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/cs/email.json b/public/language/cs/email.json index fada8d0597..8ee84565ae 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Heslo úspěšně změněno", "reset.notify.text1": "Informujeme Vás, že na %1 vaše heslo bylo úspěšně změněno.", "reset.notify.text2": "Pokud jste to neschválil, prosíme neprodleně kontaktujte správce.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Nejnovější témata od %1", "digest.top-topics": "Nejlepší témata od %1", "digest.popular-topics": "Oblíbená témata od %1", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index d310f4a236..e0fefa01b8 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Omlouváme se, ale tento účet je zablokován do %1 (důvod: %2)", "user-too-new": "Omlouváme se, ale před vytvoření vašeho prvního příspěvku musíte vyčkat %1 sekund/u/y", "blacklisted-ip": "Omlouváme se, ale vaše adresa IP byla u této komunity zablokována. Máte-li pocit, že je to chyba, kontaktujte správce.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Zadejte prosím datum konce této blokace", "no-category": "Kategorie neexistuje", "no-topic": "Téma neexistuje", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "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", @@ -199,6 +200,7 @@ "not-in-room": "Uživatel není přítomen v místnosti", "cant-kick-self": "Nemůžete vyhodit sami sebe ze skupiny", "no-users-selected": "Žádný uživatel/é nebyl/y vybrán/i", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Neplatná cesta k domovské stránkce", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/cs/global.json b/public/language/cs/global.json index 863553af20..f483d3f446 100644 --- a/public/language/cs/global.json +++ b/public/language/cs/global.json @@ -51,6 +51,8 @@ "nextpage": "Další stránka", "alert.success": "Úspěšné", "alert.error": "Chyba", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Zabanován", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index 73de1bebd5..369e9b0b4f 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemáte žádné aktivní konverzace.", "chat.user_typing": "%1 píše…", "chat.user_has_messaged_you": "%1 Vám napsal.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vyberte příjemce k prohlédnutí historie zpráv.", @@ -27,22 +28,43 @@ "chat.three_months": "3 měsíce", "chat.delete_message_confirm": "Jste si jist/a, že chcete odstranit tuto zprávu?", "chat.retrieving-users": "Získávání seznamu uživatelů...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovat konverzační místnosti", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Zde můžete vyhledávat uživatele. Jakmile si ho vyberete, uživatel bude přidán do konverzace. Nový uživatel nebude mít zobrazeny zprávy konverzace napsané dříve, než byl do konverzace přidán. Jen majitelé místnosti () mohou odebrat uživatele z konverzační místnosti.", "chat.confirm-chat-with-dnd-user": "Tento uživatel nastavil svůj stav na NERUŠIT. Opravdu chcete začít s ním konverzaci.", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Přejmenovat místnost", "chat.rename-placeholder": "Zde zadejte název místnosti", "chat.rename-help": "Název místnosti zde nastavený bude viditelný pro všechny účastníky komunikace v místnosti", - "chat.leave": "Opustit konverzaci", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Jste si jist/a, že chcete ukončit tuto konverzaci?", "chat.leave-help": "Ukončením této konverzace budete vyjmuti z budoucí možné komunikace v této konverzaci. Následně budete-li znovu přidán/a, neuvidíte historii komunikace od Vašeho odchodu.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "V této místnosti", "chat.kick": "Vykopnout", "chat.show-ip": "Zobrazit IP", "chat.owner": "Majitel místnosti", - "chat.system.user-join": "%1 se připojil k místnosti", - "chat.system.user-leave": "%1 opustil místnost", - "chat.system.room-rename": "%2 přejmenoval tuto místnost: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napsat", "composer.show_preview": "Ukázat náhled", "composer.hide_preview": "Skrýt náhled", diff --git a/public/language/cs/topic.json b/public/language/cs/topic.json index f553244383..4198b2384f 100644 --- a/public/language/cs/topic.json +++ b/public/language/cs/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/da/admin/admin.json b/public/language/da/admin/admin.json index 22c8e30f83..027ab1edae 100644 --- a/public/language/da/admin/admin.json +++ b/public/language/da/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/da/admin/dashboard.json b/public/language/da/admin/dashboard.json index 31a110b826..a3436a43f7 100644 --- a/public/language/da/admin/dashboard.json +++ b/public/language/da/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/da/admin/manage/categories.json b/public/language/da/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/da/admin/manage/categories.json +++ b/public/language/da/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/da/admin/manage/users.json b/public/language/da/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/da/admin/manage/users.json +++ b/public/language/da/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/da/admin/menu.json b/public/language/da/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/da/admin/menu.json +++ b/public/language/da/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/da/admin/settings/chat.json b/public/language/da/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/da/admin/settings/chat.json +++ b/public/language/da/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/da/admin/settings/guest.json b/public/language/da/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/da/admin/settings/guest.json +++ b/public/language/da/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/da/email.json b/public/language/da/email.json index f8fe687dff..2687f24acb 100644 --- a/public/language/da/email.json +++ b/public/language/da/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Dit kodeord er nu ændret", "reset.notify.text1": "Bemærk: %1 gang blev dit kodeord ændret.", "reset.notify.text2": "Hvis du ikke godkendte dette, kontakt straks en administrator.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Nyeste emne fra %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/da/error.json b/public/language/da/error.json index 7331a1c8c3..a78dffdf52 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Beklager, du er nødt til at vente %1 sekund(er) før du opretter dit indlæg", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Kategorien eksisterer ikke", "no-topic": "Tråden eksisterer ikke", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Vurderingssystem er slået fra.", "downvoting-disabled": "Nedvurdering er slået fra", @@ -199,6 +200,7 @@ "not-in-room": "Bruger er ikke i rummet", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/da/global.json b/public/language/da/global.json index 39154ea051..b719cb368d 100644 --- a/public/language/da/global.json +++ b/public/language/da/global.json @@ -51,6 +51,8 @@ "nextpage": "Næste side", "alert.success": "Succes", "alert.error": "Fejl", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Forment adgang", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index 66e1c623f5..ed8526fabd 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har ingen aktive chats.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har skrevet til dig.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vælg en modtager for at se beskedhistorikken", @@ -27,22 +28,43 @@ "chat.three_months": "3 måneder", "chat.delete_message_confirm": "Er du sikker på at du vil slette denne besked?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Skriv", "composer.show_preview": "Vis forhåndsvisning", "composer.hide_preview": "Fjern forhåndsvisning", diff --git a/public/language/da/topic.json b/public/language/da/topic.json index ecd42e9d00..dab738c0a5 100644 --- a/public/language/da/topic.json +++ b/public/language/da/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/de/admin/admin.json b/public/language/de/admin/admin.json index b3b9384c0b..d4211ebc5f 100644 --- a/public/language/de/admin/admin.json +++ b/public/language/de/admin/admin.json @@ -4,13 +4,15 @@ "acp-title": "%1 | NodeBB Admin Systemsteuerung", "settings-header-contents": "Inhalte", - "changes-saved": "Changes Saved", - "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", + "changes-saved": "Änderungen gespeichert", + "changes-saved-message": "Deine Änderungen an der NodeBB Konfiguration wurden gespeichert.", "changes-not-saved": "Änderungen verworfen", "changes-not-saved-message": "Beim Speichern der Änderungen ist ein Problem aufgetreten. (%1)", - "save-changes": "Save changes", + "save-changes": "Änderungen speichern", "min": "Min:", "max": "Max:", - "view": "View", - "edit": "Edit" + "view": "Anzeigen", + "edit": "Bearbeiten", + "add": "Hinzufügen", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/de/admin/advanced/errors.json b/public/language/de/admin/advanced/errors.json index d7f4995ba4..92143eaabe 100644 --- a/public/language/de/admin/advanced/errors.json +++ b/public/language/de/admin/advanced/errors.json @@ -1,5 +1,5 @@ { - "errors": "Errors", + "errors": "Fehler", "figure-x": "Abbildung %1", "error-events-per-day": "%1 Ereignisse pro Tag", "error.404": "404 Nicht gefunden", diff --git a/public/language/de/admin/appearance/customise.json b/public/language/de/admin/appearance/customise.json index b46fb2c98a..6de993b5cf 100644 --- a/public/language/de/admin/appearance/customise.json +++ b/public/language/de/admin/appearance/customise.json @@ -1,8 +1,8 @@ { - "customise": "Customise", - "custom-css": "Custom CSS/SASS", - "custom-css.description": "Enter your own CSS/SASS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS/SASS", + "customise": "Personalisieren", + "custom-css": "Benutzerdefiniertes CSS/SASS", + "custom-css.description": "Füge deine eigenen CSS/SASS Deklarationen hier ein, die nach allen anderen Styles angewandt werden.", + "custom-css.enable": "Benutzerdefiniertes CSS/SASS aktivieren", "custom-js": "Benutzerdefiniertes Javascript", "custom-js.description": "Füge dein eigenes Javascipt hier ein.\nEs wird ausgeführt nachdem die Seite komplett geladen wurde.", @@ -15,6 +15,6 @@ "custom-css.livereload": "Live-Aktualisierung aktivieren", "custom-css.livereload.description": "Aktiviere diese Einstellung um alle Sitzungen auf allen Geräten mit deinem Konto dazu zu zwingen Neuzuladen sobald du \"Speichern\" drückst", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
Changes require a rebuild & restart.", - "bsvariables.enable": "Enable _variables.scss" + "bsvariables.description": "Überschreibe Bootstrap-Variablen hier. Du kannst außerdem ein Tool wie bootstrap.build benutzen und das Ergebnis hier hereinkopieren.
Änderungen benötigen einen Rebuild & Neustart.", + "bsvariables.enable": "_variables.scss aktivieren" } \ No newline at end of file diff --git a/public/language/de/admin/appearance/skins.json b/public/language/de/admin/appearance/skins.json index f6ce726fad..47b07a986c 100644 --- a/public/language/de/admin/appearance/skins.json +++ b/public/language/de/admin/appearance/skins.json @@ -1,16 +1,16 @@ { "skins": "Skins", "bootswatch-skins": "Bootswatch Skins", - "custom-skins": "Custom Skins", - "add-skin": "Add Skin", - "save-custom-skins": "Save Custom Skins", - "save-custom-skins-success": "Custom skins saved successfully", - "custom-skin-name": "Custom Skin Name", - "custom-skin-variables": "Custom Skin Variables", + "custom-skins": "Benutzerdefinierte Skins", + "add-skin": "Skin hinzufügen", + "save-custom-skins": "Benutzerdefinierten Skin speichern", + "save-custom-skins-success": "Benutzerdefinierte Skins erfolgreich gespeichert", + "custom-skin-name": "Name des benutzerdefinierten Skins", + "custom-skin-variables": "Variablen des benutzerdefinierten Skins", "loading": "Skins werden geladen...", "homepage": "Startseite", "select-skin": "Skin auswählen", - "revert-skin": "Revert Skin", + "revert-skin": "Skin zurücksetzen", "current-skin": "Aktueller Skin", "skin-updated": "Skin aktualisiert", "applied-success": "Skin %1 wurde erfolgreich angewendet", diff --git a/public/language/de/admin/appearance/themes.json b/public/language/de/admin/appearance/themes.json index 83005bccf5..ebf3facd43 100644 --- a/public/language/de/admin/appearance/themes.json +++ b/public/language/de/admin/appearance/themes.json @@ -3,7 +3,7 @@ "checking-for-installed": "Auf installierte Themes wird geprüft...", "homepage": "Startseite", "select-theme": "Theme wählen", - "revert-theme": "Revert Theme", + "revert-theme": "Theme zurücksetzen", "current-theme": "Aktuelles Theme", "no-themes": "Keine installierten Theme gefunden.", "revert-confirm": "Bist du sicher, dass du das standardmäßige NodeBB-Design wiederherstellen möchten?", diff --git a/public/language/de/admin/dashboard.json b/public/language/de/admin/dashboard.json index 672fcc508d..6e3fe813fc 100644 --- a/public/language/de/admin/dashboard.json +++ b/public/language/de/admin/dashboard.json @@ -3,15 +3,15 @@ "page-views": "Seitenaufrufe", "unique-visitors": "Individuelle Besucher", "logins": "Anmeldungen", - "new-users": "Neue nutzende Person", + "new-users": "Neue Benutzer", "posts": "Beiträge", "topics": "Themen", "page-views-seven": "Letzte 7 Tage", "page-views-thirty": "Letzte 30 Tage", "page-views-last-day": "Letzte 24 Stunden", - "page-views-custom": "Benutzerdefinierte Tagesspanne", - "page-views-custom-start": "Spannen-Anfang", - "page-views-custom-end": "Spannen-Ende", + "page-views-custom": "Benutzerdefinierter Zeitraum", + "page-views-custom-start": "Anfang Zeitraum", + "page-views-custom-end": "Ende Zeitraum", "page-views-custom-help": "Gebe einen Datumsbereich für Seitenaufrufe ein, die du anzeigen möchtest. Wenn keine Datumsauswahl verfügbar ist, ist das akzeptierte Format YYYY-MM-DD", "page-views-custom-error": "Bitte gib eine gültige Zeitspanne im Format YYYY-MM-DD an", @@ -26,13 +26,13 @@ "updates": "Updates", "running-version": "Es läuft NodeBB v%1.", "keep-updated": "Stelle sicher, dass dein NodeBB immer auf dem neuesten Stand für die neuesten Sicherheits-Patches und Bug-fixes ist.", - "up-to-date": "You are up-to-date ", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur. ", + "up-to-date": "Die NodeBB Version ist aktuell ", + "upgrade-available": "Eine neuere Version (v%1) ist erschienen. Erwäge, NodeBB zu upgraden.", + "prerelease-upgrade-available": "Dies ist eine veraltete NodeBB-Vorabversion. Eine neuere Version (v%1) ist erschienen. Erwäge, NodeBB zu upgraden.", + "prerelease-warning": "Dies ist eine Vorabversion von NodeBB. Es können ungewollte Fehler auftreten. ", "fallback-emailer-not-found": "Fallback-Emailer nicht gefunden", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator", - "latest-lookup-failed": "Failed to look up latest available version of NodeBB", + "running-in-development": "Das Forum wurde im Entwicklermodus gestartet. Das Forum könnte potenziellen Gefahren ausgeliefert sein. Bitte kontaktiere den Systemadministrator.", + "latest-lookup-failed": "Die neueste verfügbare Version von NodeBB konnte nicht abgerufen werden", "notices": "Hinweise", "restart-not-required": "Kein Neustart benötigt", @@ -48,6 +48,7 @@ "restart-disabled": "Das Regenerieren und Neustarten von NodeBB wurde deaktiviert, da es nicht so aussieht als ob es über einem kompatiblem daemon läuft.", "maintenance-mode": "Wartungsmodus", "maintenance-mode-title": "Hier klicken um NodeBB in den Wartungsmodus zu versetzen", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Echtzeit Chartaktualisierung", "active-users": "Aktive Benutzer", @@ -82,12 +83,16 @@ "back-to-dashboard": "Zurück zur Übersicht", "details.no-users": "Keine Benutzer sind im gewählten Zeitraum beigetreten", - "details.no-topics": "Keine Themen wurden im gewählten Zeitraum beigetreten", - "details.no-searches": "No searches have been made within the selected timeframe", - "details.no-logins": "Keine Logins wurden im gewählten Zeitraum festgestellt", + "details.no-topics": "Im ausgewählten Zeitraum wurden keine Themen erstellt", + "details.no-searches": "Es wurden im ausgewählten Zeitraum keine Suchen durchgeführt", + "details.no-logins": "Im ausgewählten Zeitraum wurden keine Logins getätigt", "details.logins-static": "NodeBB speichert Sitzungsdaten nur für %1 Tage, deshalb zeigt die untere Tabelle nur die neuesten, aktiven Sitzungen", - "details.logins-login-time": "Anmelde Zeit", + "details.logins-login-time": "Anmeldezeit", "start": "Start", - "end": "End", - "filter": "Filter" + "end": "Ende", + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/de/admin/extend/plugins.json b/public/language/de/admin/extend/plugins.json index ef2d032d2c..b647be021f 100644 --- a/public/language/de/admin/extend/plugins.json +++ b/public/language/de/admin/extend/plugins.json @@ -1,5 +1,5 @@ { - "plugins": "Plugins", + "plugins": "Erweiterungen", "trending": "Beliebt", "installed": "Installiert", "active": "Aktiv", diff --git a/public/language/de/admin/extend/rewards.json b/public/language/de/admin/extend/rewards.json index 39d7e72818..bcd5099b99 100644 --- a/public/language/de/admin/extend/rewards.json +++ b/public/language/de/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Belohnungen", - "add-reward": "Add reward", + "add-reward": "Belohnung hinzufügen", "condition-if-users": "Wenn Benutzer", "condition-is": "Ist:", "condition-then": "Dann:", "max-claims": "Anzahl der Male von Belohnungen, die beansprucht werden können", "zero-infinite": "0 für unendlich eingeben", - "select-reward": "Select reward", + "select-reward": "Belohnung auswählen", "delete": "Löschen", "enable": "Aktivieren", "disable": "Deaktivieren", diff --git a/public/language/de/admin/extend/widgets.json b/public/language/de/admin/extend/widgets.json index 5d63c1ae1b..7aeab42f52 100644 --- a/public/language/de/admin/extend/widgets.json +++ b/public/language/de/admin/extend/widgets.json @@ -9,9 +9,9 @@ "containers.none": "Nichts", "container.well": "Well", "container.jumbotron": "Jumbotron", - "container.card": "Card", - "container.card-header": "Card Header", - "container.card-body": "Card Body", + "container.card": "Karte", + "container.card-header": "Karten-Kopfzeile", + "container.card-body": "Karten-Körper", "container.alert": "Alarm", "alert.confirm-delete": "Möchtest Du dieses Widget wirklich löschen?", @@ -27,7 +27,7 @@ "container.placeholder": "Ziehe einen Container per Drag-and-Drop oder gebe hier HTML ein.", "show-to-groups": "Gruppen anzeigen", "hide-from-groups": "Vor Gruppen verstecken", - "start-date": "Start date", - "end-date": "End date", + "start-date": "Anfangsdatum", + "end-date": "Enddatum", "hide-on-mobile": "Auf dem Handy verstecken" } \ No newline at end of file diff --git a/public/language/de/admin/manage/admins-mods.json b/public/language/de/admin/manage/admins-mods.json index 5badc78f01..7a1c1532b1 100644 --- a/public/language/de/admin/manage/admins-mods.json +++ b/public/language/de/admin/manage/admins-mods.json @@ -1,11 +1,11 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "Admins & Mods verwalten", "administrators": "Administratoren", "global-moderators": "Globale Moderatoren", "moderators": "Moderatoren", "no-global-moderators": "Keine globalen Moderatoren", "no-sub-categories": "Keine Unterkategorien", - "view-children": "View children (%1)", + "view-children": "Aufklappen (%1)", "no-moderators": "Keine Moderatoren", "add-administrator": "Administrator hinzufügen", "add-global-moderator": "Globalen Moderator hinzufügen", diff --git a/public/language/de/admin/manage/categories.json b/public/language/de/admin/manage/categories.json index aad37fd987..d914363786 100644 --- a/public/language/de/admin/manage/categories.json +++ b/public/language/de/admin/manage/categories.json @@ -1,11 +1,11 @@ { - "manage-categories": "Manage Categories", - "add-category": "Add category", - "jump-to": "Jump to...", + "manage-categories": "Kategorien verwalten", + "add-category": "Kategorie hinzufügen", + "jump-to": "Springen zu...", "settings": "Kategorieeinstellungen", - "edit-category": "Edit Category", + "edit-category": "Kategorie bearbeiten", "privileges": "Berechtigungen", - "back-to-categories": "Back to categories", + "back-to-categories": "Zurück zu Kategorien", "name": "Kategoriename", "description": "Kategorie-Beschreibung", "bg-color": "Hintergrundfarbe", @@ -19,11 +19,10 @@ "post-queue": "Warteschlange", "tag-whitelist": "Tag Whitelist", "upload-image": "Bild hochladen", - "upload": "Upload", - "select-icon": "Select Icon", + "upload": "Hochladen", "delete-image": "Entfernen", "category-image": "Kategoriebild", - "image-and-icon": "Image & Icon", + "image-and-icon": "Bild & Icon", "parent-category": "Übergeordnete Kategorie", "optional-parent-category": "(Optional) Übergeordnete Kategorie", "top-level": "Top Level", diff --git a/public/language/de/admin/manage/groups.json b/public/language/de/admin/manage/groups.json index 49119b854d..927acb195c 100644 --- a/public/language/de/admin/manage/groups.json +++ b/public/language/de/admin/manage/groups.json @@ -1,10 +1,10 @@ { - "manage-groups": "Manage Groups", - "add-group": "Add group", - "edit-group": "Edit Group", - "back-to-groups": "Back to groups", - "view-group": "View group", - "icon-and-title": "Icon & Title", + "manage-groups": "Gruppen verwalten", + "add-group": "Gruppe hinzufügen", + "edit-group": "Gruppe bearbeiten", + "back-to-groups": "Zurück zu Gruppen", + "view-group": "Gruppe anzeigen", + "icon-and-title": "Icon & Titel", "name": "Gruppenname", "badge": "Abzeichen", "properties": "Eigenschaften", @@ -16,7 +16,7 @@ "edit": "Ändern", "delete": "Löschen", "privileges": "Berechtigungen", - "members-csv": "Members (CSV)", + "members-csv": "Benutzer (CSV)", "search-placeholder": "Suchen", "create": "Gruppe erstellen", "description-placeholder": "Eine kurze Beschreibung deiner Gruppe", diff --git a/public/language/de/admin/manage/privileges.json b/public/language/de/admin/manage/privileges.json index 816c5e2d2d..a651c1320d 100644 --- a/public/language/de/admin/manage/privileges.json +++ b/public/language/de/admin/manage/privileges.json @@ -1,6 +1,6 @@ { - "manage-privileges": "Manage Privileges", - "discard-changes": "Discard changes", + "manage-privileges": "Berechtigungen verwalten", + "discard-changes": "Änderungen verwerfen", "global": "Global", "admin": "Administrator", "group-privileges": "Gruppen Rechte", diff --git a/public/language/de/admin/manage/tags.json b/public/language/de/admin/manage/tags.json index 64ec38aaeb..9cc615cfcf 100644 --- a/public/language/de/admin/manage/tags.json +++ b/public/language/de/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Tags verwalten", "none": "Das Forum hat bisher noch keine Themen mit Tags.", "bg-color": "Hintergrundfarbe", "text-color": "Textfarbe", "description": "Wählen Sie Tags durch Klicken oder Ziehen aus, verwenden Sie STRG, um mehrere Tags auszuwählen.", "create": "Tag erstellen", - "add-tag": "Add tag", + "add-tag": "Tag hinzufügen", "modify": "Tag bearbeiten", "rename": "Tags umbenennen", "delete": "Ausgewählte Tags entfernen", diff --git a/public/language/de/admin/manage/uploads.json b/public/language/de/admin/manage/uploads.json index 84989bda5b..dbb3579e42 100644 --- a/public/language/de/admin/manage/uploads.json +++ b/public/language/de/admin/manage/uploads.json @@ -1,5 +1,5 @@ { - "manage-uploads": "Manage Uploads", + "manage-uploads": "Uploads verwalten", "upload-file": "Datei hochladen", "filename": "Dateiname", "usage": "Beitragsnutzung", diff --git a/public/language/de/admin/manage/users.json b/public/language/de/admin/manage/users.json index 73a0abb45e..5a990efdf7 100644 --- a/public/language/de/admin/manage/users.json +++ b/public/language/de/admin/manage/users.json @@ -1,5 +1,5 @@ { - "manage-users": "Manage Users", + "manage-users": "Benutzer verwalten", "users": "Benutzer", "edit": "Aktionen", "make-admin": "Zum Administrator befördern", @@ -18,6 +18,7 @@ "purge": "Benutzer und Benutzer-Inhalte löschen", "download-csv": "CSV herunterladen", "manage-groups": "Gruppen verwalten", + "set-reputation": "Set Reputation", "add-group": "Gruppe hinzufügen", "create": "Benutzer erstellen", "invite": "Einladung per E-Mail", @@ -50,16 +51,16 @@ "users.username": "Nutzername", "users.email": "E-Mail", "users.no-email": "(keine Email)", - "users.validated": "Validated", - "users.not-validated": "Not Validated", - "users.validation-pending": "Validation Pending", - "users.validation-expired": "Validation Expired", + "users.validated": "Bestätigt", + "users.not-validated": "Nicht bestätigt", + "users.validation-pending": "Bestätigung ausstehend", + "users.validation-expired": "Bestätigung abgelaufen", "users.ip": "IP", "users.postcount": "Anzahl der Beiträge", "users.reputation": "Ansehen", "users.flags": "Meldungen", "users.joined": "Beigetreten am", - "users.last-online": "Letztes mal online", + "users.last-online": "Zuletzt online", "users.banned": "Gebannt", "create.username": "Benutzername", diff --git a/public/language/de/admin/menu.json b/public/language/de/admin/menu.json index e4edd966a8..a36d520ff1 100644 --- a/public/language/de/admin/menu.json +++ b/public/language/de/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Benutzer", "manage/admins-mods": "Admins & Mods", "manage/registration": "Warteliste", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Beitragswarteschlange", "manage/groups": "Gruppen", "manage/ip-blacklist": "IP Blacklist", @@ -72,9 +73,9 @@ "development/info": "Info", "rebuild-and-restart-forum": "Forum regenerieren & neustarten", - "rebuild-and-restart": "Rebuild & Restart", + "rebuild-and-restart": "Rebuild & Neustart", "restart-forum": "Forum neu starten", - "restart": "Restart", + "restart": "Neustarten", "logout": "Abmelden", "view-forum": "Forum anzeigen", diff --git a/public/language/de/admin/settings/advanced.json b/public/language/de/admin/settings/advanced.json index 1f75026bc5..9310b773b2 100644 --- a/public/language/de/admin/settings/advanced.json +++ b/public/language/de/admin/settings/advanced.json @@ -3,7 +3,7 @@ "maintenance-mode.help": "Wenn sich das Forum im Wartungsmodus befindet, werden alle Anfragen auf eine statische Warteseite umgeleitet. Administratoren sind von dieser Umleitung ausgenommen und können normal auf die Site zugreifen.", "maintenance-mode.status": "Statuscode für Wartungsmodus", "maintenance-mode.message": "Wartungsnachricht", - "maintenance-mode.groups-exempt-from-maintenance-mode": "Select groups that should be exempt from maintenance mode", + "maintenance-mode.groups-exempt-from-maintenance-mode": "Wähle Gruppen, welche vom Wartungsmodus ausgenommen werden sollen", "headers": "Headers", "headers.allow-from": "ALLOW-FROM setzen um NodeBB in einem iFrame zu platzieren", "headers.csp-frame-ancestors": "Content-Security-Policy frame-ancestors header setzen, um NodeBB in einem iFrame zu platzieren", @@ -20,8 +20,8 @@ "headers.coep-help": "Wenn aktiviert (Standard), wird der Header auf require-corp gesetzt", "headers.coop": "Cross-Origin-Opener-Policy", "headers.corp": "Cross-Origin-Resource-Policy", - "headers.permissions-policy": "Permissions-Policy", - "headers.permissions-policy-help": "Allows setting permissions policy header, for example \"geolocation=*, camera=()\", see this for more info.", + "headers.permissions-policy": "Berechtigungs-Richtlinie", + "headers.permissions-policy-help": "Erlaubt das Setzen eines Headers für die Berechtigungs-Richtlinie, z. B. \"geolocation=*, camera=()\". Siehe hier für mehr Informationen.", "hsts": "Strict Transport Security", "hsts.enabled": "HSTS Aktivieren (empfohlen)", "hsts.maxAge": "HSTS Maximales Alter", diff --git a/public/language/de/admin/settings/api.json b/public/language/de/admin/settings/api.json index 0248bc09cc..37deb3c67e 100644 --- a/public/language/de/admin/settings/api.json +++ b/public/language/de/admin/settings/api.json @@ -3,7 +3,7 @@ "settings": "Einstellungen", "lead-text": "Auf dieser Seite kanst Du den Zugriff auf die Write-API in NodeBB konfigurieren.", "intro": "Standardmäßig authentifiziert die Write-API Benutzer basierend auf ihrem Sitzungscookie, aber NodeBB unterstützt auch die Bearer-Authentifizierung über Token, die über diese Seite generiert werden.", - "warning": "Be advised — treat tokens like passwords. If they are leaked, your account should be considered compromised.", + "warning": "Hinweis — Behandle Tokens wie Passwörter. Wenn diese geleakt werden, sollte Dein Account als kompromittiert behandelt werden.", "docs": "Klicke hier, um auf die vollständige API-Spezifikation zuzugreifen", "require-https": "API-Nutzung nur über HTTPS möglich", @@ -13,17 +13,17 @@ "token": "Token", "uid-help-text": "Gebe eine Benutzer-ID an, die diesem Token zugeordnet werden soll. Wenn die Benutzer-ID 0 ist, wird sie als Master-Token betrachtet, das basierend auf dem _uid-Parameter die Identität anderer Benutzer annehmen kann", "description": "Beschreibung", - "last-seen": "Last seen", - "created": "Created", - "create-token": "Create Token", - "update-token": "Update Token", - "master-token": "Master token", - "last-seen-never": "This key has never been used.", + "last-seen": "Zuletzt gesehen", + "created": "Erstellt", + "create-token": "Token erstellen", + "update-token": "Token aktualisieren", + "master-token": "Master-Token", + "last-seen-never": "Dieser Schlüssel wurde noch nie benutzt.", "no-description": "Keine Beschreibung angegeben.", - "actions": "Actions", - "edit": "Edit", - "roll": "Roll", + "actions": "Aktionen", + "edit": "Bearbeiten", + "roll": "Würfeln", - "delete-confirm": "Are you sure you wish to delete this token? It will not be recoverable.", - "roll-confirm": "Are you sure you wish to regenerate this token? The old token will be immediately revoked and will not be recoverable." + "delete-confirm": "Bist Du Dir sicher, dass Du diesen Token löschen willst? Dieser kann nicht wiederhergestellt werden.", + "roll-confirm": "Bist Du Dir sicher, dass Du diesen Token neu generieren willst? Der alte Token verliert sofort seine Gültigkeit und kann nicht wiederhergestellt werden." } \ No newline at end of file diff --git a/public/language/de/admin/settings/chat.json b/public/language/de/admin/settings/chat.json index d97665c221..17ae89bc7a 100644 --- a/public/language/de/admin/settings/chat.json +++ b/public/language/de/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Chatnachrichtenbearbeitung/löschung deaktivieren", "disable-editing-help": "Administratoren und globale Moderatoren sind von dieser Einschränkung ausgenommen", "max-length": "Maximale Länge von Chatnachrichten", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximale Anzahl von Benutzern in Chatrooms", "delay": "Zeit zwischen Chatnachrichten in Millisekunden", "notification-delay": "Benachrichtigungsverzögerung für Chatnachrichten. (0 für keine Verzögerung)", diff --git a/public/language/de/admin/settings/email.json b/public/language/de/admin/settings/email.json index 9c6e6c9bb0..1eca3b3fe7 100644 --- a/public/language/de/admin/settings/email.json +++ b/public/language/de/admin/settings/email.json @@ -42,7 +42,7 @@ "subscriptions.hour-help": "Bitte geben Sie eine Nummer ein, welche die Stunde repräsentiert zu welcher geplante Emails versandt werden sollen (z.B. 0 für Mitternacht, 17 für 5 Uhr Nachmittags). Beachten Sie, dass die Zeit auf der Serverzeit basiert und daher nicht umbedingt mit ihrer Systemzeit übereinstimmen muss.
Die ungefähre Serverzeit ist:
Die nächste tägliche Sendung ist um geplant", "notifications.remove-images": "Bilder aus E-Mail-Benachrichtigungen entfernen", "require-email-address": "Neue Benutzer auffordern, eine E-Mail-Adresse anzugeben", - "require-email-address-warning": "By default, users can opt-out of entering an email address by leaving the field blank. Enabling this option means new users will have to enter and confirm an email address in order to proceed with registration and subsequent access to the forum. It does not ensure user will enter a real email address, nor even an address they own.", + "require-email-address-warning": "Standardmäßig können Benutzer die Eingabe einer E-Mail-Adresse ablehnen, indem sie das Feld leer lassen. Wenn Du diese Option aktivierst, müssen neue Benutzer eine E-Mail-Adresse eingeben und diese bestätigen, um mit der Registrierung fortzufahren und Zugang zum Forum zu erhalten. Es stellt weder sicher, dass der Benutzer eine echte E-Mail-Adresse eingibt, noch, dass eine Adresse ihm gehört.", "send-validation-email": "Validierungs-E-Mails senden, wenn eine E-Mail hinzugefügt oder geändert wird", "include-unverified-emails": "E-Mails an Empfänger senden, die ihre E-Mails nicht explizit bestätigt haben", "include-unverified-warning": "Standardmäßig wurden Benutzer mit E-Mail-Adressen, die mit ihrem Konto verknüpft sind, bereits verifiziert, aber es existieren Situationen, in denen dies nicht der Fall ist (z. B. SSO-Anmeldungen, Großvater-Benutzer usw.). Aktiviere diese Einstellung auf eigenes Risiko – Das Senden von E-Mails an nicht verifizierte Adressen kann einen Verstoß gegen regionale Anti-Spam-Gesetze darstellen.", diff --git a/public/language/de/admin/settings/general.json b/public/language/de/admin/settings/general.json index 3a0f5e8512..7fd7af5cde 100644 --- a/public/language/de/admin/settings/general.json +++ b/public/language/de/admin/settings/general.json @@ -1,13 +1,13 @@ { - "general-settings": "General Settings", - "on-this-page": "On this page:", + "general-settings": "Allgemeine Einstellungen", + "on-this-page": "Auf dieser Seite:", "site-settings": "Forum Einstellungen", "title": "Forum Titel", "title.short": "Kurzbezeichnung", "title.short-placeholder": "Wenn kein Kurztitel angegeben ist, wird der Forum-Titel verwendet.", "title.url": "Titel Link-URL", "title.url-placeholder": "Die URL des Seitentitels", - "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. Note: This is not the external URL used in emails, etc. That is set by the url property in config.json", + "title.url-help": "Wenn der Titel angeklickt wird, werden die Benutzer an diese Adresse weitergeleitet. Wenn nichts angegeben wird, werden Benutzer zum Forum-Index weitergeleitet. Hinweis: Dies ist nicht die externe URL, die in E-Mails etc. verwendet wird. Diese wird über die Eigenschaft url in config.json festgelegt.", "title.name": "Name Deiner Community", "title.show-in-header": "Titel im Header anzeigen", "browser-title": "Browser Titel", @@ -18,7 +18,7 @@ "description": "Forum Beschreibung", "keywords": "Forum Schlüsselworte", "keywords-placeholder": "Schlüsselworte, die ihre Community beschreiben, mit Komma getrennt", - "logo-and-icons": "Site Logo & Icons", + "logo-and-icons": "Website-Logo & Icons", "logo.image": "Bild", "logo.image-placeholder": "Pfad zu einem Logo, welches im Header des Forums angezeigt werden soll", "logo.upload": "Hochladen", diff --git a/public/language/de/admin/settings/group.json b/public/language/de/admin/settings/group.json index df50632f6b..7100499aba 100644 --- a/public/language/de/admin/settings/group.json +++ b/public/language/de/admin/settings/group.json @@ -2,7 +2,7 @@ "general": "Allgemein", "private-groups": "Private Gruppen", "private-groups.help": "Wenn aktiviert, erfordert das Beitreten einer Gruppe die Bestätigung des jeweiligen Besitzers(Standard: aktiviert)", - "private-groups.warning": "Vorsicht! Wenn diese Option deaktiviert ist, und es private Gruppen gibt, werden diese automatisch öffentlich.", + "private-groups.warning": "Vorsicht! Wenn diese Option deaktiviert ist, werden private Gruppen automatisch öffentlich.", "allow-multiple-badges": "Mehrere Abzeichen erlauben", "allow-multiple-badges-help": "Diese Eintellung kann verwendet werden um Benutzern zu erlauben mehrere Gruppen abzeichen auszuwählen, benötigt Theme unterstützung.", "max-name-length": "Maximale Länge von Gruppennamen", diff --git a/public/language/de/admin/settings/guest.json b/public/language/de/admin/settings/guest.json index 56dbc50c1c..e8e26b311b 100644 --- a/public/language/de/admin/settings/guest.json +++ b/public/language/de/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Einstellungen", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Gastzugänge erlauben", "handles.enabled-help": "Diese Option zeigt ein neues Feld an, in dem Gäste einen Namen auswählen können, der jedem von ihnen erstellten Beitrag zugeordnet werden soll. Wenn sie deaktiviert sind, werden sie einfach „Gast“ genannt.", "topic-views.enabled": "Gästen erlauben, die gezählte Anzahl der Themenaufrufe zu erhöhen", diff --git a/public/language/de/admin/settings/navigation.json b/public/language/de/admin/settings/navigation.json index 8e152b503b..0fe6f19e9c 100644 --- a/public/language/de/admin/settings/navigation.json +++ b/public/language/de/admin/settings/navigation.json @@ -13,7 +13,7 @@ "groups": "Gruppen:", "open-new-window": "In neuem Fenster öffnen", "dropdown": "Dropdown", - "dropdown-placeholder": "Place your dropdown menu items below, ie:
<li><a class="dropdown-item" href="https://myforum.com">Link 1</a></li>", + "dropdown-placeholder": "Platziere deine Dropdown-Menüpunkte unten, d. h.:
<li><a class="dropdown-item" href="https://myforum.com">Link 1</a></li>", "btn.delete": "Löschen", "btn.disable": "Deaktivieren", diff --git a/public/language/de/admin/settings/post.json b/public/language/de/admin/settings/post.json index f5bee5e51d..3e96171244 100644 --- a/public/language/de/admin/settings/post.json +++ b/public/language/de/admin/settings/post.json @@ -1,5 +1,5 @@ { - "general": "General", + "general": "Allgemein", "sorting": "Beitragssortierung", "sorting.post-default": "Standardmäßige sortierung von Beiträgen", "sorting.oldest-to-newest": "Von Alt bis Neu", @@ -24,8 +24,8 @@ "restrictions.seconds-edit-after": "Anzahl der Sekunden, die ein Beitrag bearbeitet werden kann (zum Deaktivieren auf 0 setzen)", "restrictions.seconds-delete-after": "Anzahl der Sekunden, die ein Beitrag löschbar bleibt (zum Deaktivieren auf 0 setzen)", "restrictions.replies-no-delete": "Anzahl der Antworten, nachdem Benutzern das Löschen ihrer eigenen Themen verweigert wurde (zum Deaktivieren auf 0 setzen)", - "restrictions.title-length": "Title Length", - "restrictions.post-length": "Post Length", + "restrictions.title-length": "Titellänge", + "restrictions.post-length": "Beitragslänge", "restrictions.days-until-stale": "Tage bis ein Thema als alt angesehen wird", "restrictions.stale-help": "Wenn ein Thema als \"veraltet\" angesehen wird, wird Nutzern die versuchen diesem Thema zu antworten eine Warnung gezeigt", "timestamp": "Zeitstempel", @@ -40,7 +40,7 @@ "teaser.last-reply": "Letzter - Den neuesten Beitrag oder einen \"Keine Antworten\" Platzhalter, wenn es keine Antworten gibt anzeigen", "teaser.first": "Erster", "showPostPreviewsOnHover": "Eine Vorschau der Beiträge zeigen, wenn Du mit der Maus darüber fährst", - "unread-and-recent": "Unread & Recent Settings", + "unread-and-recent": "Ungelesene & neue Einstellungen", "unread.cutoff": "Ungelesen-Limit (in Tagen)", "unread.min-track-last": "Minimale Anzahl an Beiträgen pro Thema bevor die letzte Sichtung mitgeschrieben wird", "recent.max-topics": "Maximale Themen auf /recent", diff --git a/public/language/de/admin/settings/reputation.json b/public/language/de/admin/settings/reputation.json index 230fa4d142..1f98481e0a 100644 --- a/public/language/de/admin/settings/reputation.json +++ b/public/language/de/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "Führe Folgendes aus, wenn eine Flagge aufgelöst wird", "flags.action-on-reject": "Gehe folgendermaßen vor, wenn eine Flagge abgelehnt wird", "flags.action.nothing": "Nichts tun", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "Zurückziehen der Benachrichtigung an Moderatoren/Administratoren" } \ No newline at end of file diff --git a/public/language/de/admin/settings/tags.json b/public/language/de/admin/settings/tags.json index 4c20332297..adbc0cefaf 100644 --- a/public/language/de/admin/settings/tags.json +++ b/public/language/de/admin/settings/tags.json @@ -3,7 +3,7 @@ "link-to-manage": "Tags managen", "system-tags": "System-Tags", "system-tags-help": "Nur berechtige Benutzer können diese Tags verwenden.", - "tags-per-topic": "Tags per topic", + "tags-per-topic": "Tags pro Thema", "min-per-topic": "Minimale Tags pro Thema", "max-per-topic": "Maximale Tags pro Thema", "min-length": "Minimale Tag Länge", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index f995ca135f..fe6e9590c1 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -29,8 +29,8 @@ "session-time-days": "Tage", "session-time-seconds": "Sekunden", "session-time-help": "Diese Werte legen fest, wie lange ein Benutzer angemeldet bleibt, wenn er die Option "Eingeloggt bleiben" beim Login aktiviert. Beachte, dass nur einer dieser Werte verwendet wird. Wenn Sekunden nicht festgelegt wurden, greifen wir auf Tage zurück. Wenn Tage nicht festlegt wurden, werden standardmäßig 14 Tage verwendet.", - "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", - "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", + "session-duration": "Sitzungslänge, wenn \"Eingeloggt bleiben\" nicht ausgewählt ist (Sekunden)", + "session-duration-help": "Standardmäßig — oder wenn auf 0 gesetzt — bleibt ein Benutzer für die Dauer seiner Session angemeldet (d. h. solange das Browserfenster/der Tab geöffnet bleibt). Durch das Setzen dieser Einstellung wird die Session nach der angegebenen Anzahl an Sekunden ungültig gesetzt.", "online-cutoff": "Minuten nachdem der Benutzer als inaktiv betrachtet wird", "online-cutoff-help": "Wenn der Benutzer für diese Dauer keine Aktionen ausführt, wird er als inaktiv betrachtet und erhält keine Echtzeit-Updates.", "registration": "Benutzer Registrierung", @@ -49,17 +49,17 @@ "registration-queue-show-average-time": "Zeigen Sie Benutzern die durchschnittliche Zeit, die es dauert, einen neuen Benutzer zu genehmigen", "registration.max-invites": "Maximale Einladungen pro Benutzer", "max-invites": "Maximale Einladungen pro Benutzer", - "max-invites-help": "0 für keine Beschränkung. Admins haben keine beschränkung.
Nur praktikabel für \"Nur Einladungen\".", + "max-invites-help": "0 für keine Beschränkung. Admins haben keine Beschränkung.
Nur angewendet für \"Nur Einladungen\".", "invite-expiration": "Einladungsfrist", "invite-expiration-help": "# der Tage nachdem Einladungen auslaufen.", - "min-username-length": "Minimale länge des Benutzernamens", - "max-username-length": "Maximale länge des Benutzernamens", - "min-password-length": "Minimale länge des Passwortes", - "min-password-strength": "Minimale Passwort stärke", - "max-about-me-length": "Maximale länge von Über Mich", + "min-username-length": "Minimale Länge des Benutzernamens", + "max-username-length": "Maximale Länge des Benutzernamens", + "min-password-length": "Minimale Länge des Passwortes", + "min-password-strength": "Minimale Passwortstärke", + "max-about-me-length": "Maximale Länge von \"Über Mich\"", "terms-of-use": "Forum Nutzungsbedingungen (Leer lassen um es zu deaktivieren)", "user-search": "Benutzersuche", - "user-search-results-per-page": "Number of users to display in search results", + "user-search-results-per-page": "Anzahl Benutzer, die in der Suche angezeigt werden", "default-user-settings": "Standard Benutzer Einstellungen", "show-email": "Zeige E-Mail-Adresse", "show-fullname": "Zeige vollen Namen", diff --git a/public/language/de/email.json b/public/language/de/email.json index 212334e87f..f025b5fcdd 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Passwort erfolgreich geändert", "reset.notify.text1": "Wir benachrichtigen dich, dass dein Passwort am %1 erfolgreich geändert wurde.", "reset.notify.text2": "Bitte benachrichtige umgehend einen Administrator, wenn du dies nicht autorisiert hast.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Neueste Themen auf %1", "digest.top-topics": "Top-Themen von %1", "digest.popular-topics": "Beliebte Themen von %1", diff --git a/public/language/de/error.json b/public/language/de/error.json index 7bef0f0167..010103fa7b 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -42,7 +42,7 @@ "user-doesnt-have-email": "Für den Benutzer \"%1\" ist keine E-Mail eingetragen.", "email-confirm-failed": "Wir konnten deine E-Mail-Adresse nicht bestätigen, bitte versuch es später noch einmal", "confirm-email-already-sent": "Die Bestätigungsmail wurde verschickt. Bitte warte %1 Minute(n), um eine weitere zu verschicken.", - "confirm-email-expired": "Confirmation email expired", + "confirm-email-expired": "Bestätigungs-E-Mail abgelaufen", "sendmail-not-found": "Sendmail wurde nicht gefunden. Bitte stelle sicher, dass es installiert ist und durch den Benutzer unter dem NodeBB läuft ausgeführt werden kann.", "digest-not-enabled": "Dieser Benutzer hat Email-Zusammenfassungen deaktiviert oder das Aussenden von Email-Zusammenfassungen is in den Defaulteinstellungen des Systems nicht aktiviert.", "username-too-short": "Benutzername ist zu kurz", @@ -55,6 +55,7 @@ "user-banned-reason-until": "Entschuldigung, dieses Konto wurde bis %1 (Reason: %2) gesperrt.", "user-too-new": "Entschuldigung, du musst %1 Sekunde(n) warten, bevor du deinen ersten Beitrag schreiben kannst.", "blacklisted-ip": "Deine IP-Adresse ist für dieses Forum gesperrt. Sollte dies ein Irrtum sein, dann kontaktiere bitte einen Administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Bitte gib ein Enddatum für diese Sperrung an", "no-category": "Die Kategorie existiert nicht", "no-topic": "Das Thema existiert nicht", @@ -63,7 +64,7 @@ "no-user": "Der Benutzer existiert nicht", "no-teaser": "Zusammenfassung existiert nicht", "no-flag": "Markierung existiert nicht", - "no-chat-room": "Chat room does not exist", + "no-chat-room": "Der Chatroom existiert nicht", "no-privileges": "Du verfügst nicht über ausreichende Berechtigungen, um die Aktion durchzuführen.", "category-disabled": "Kategorie ist deaktiviert", "topic-locked": "Thema ist gesperrt", @@ -90,10 +91,10 @@ "category-not-selected": "Kategorie nicht ausgewählt", "too-many-posts": "Du kannst nur einen Beitrag innerhalb von %1 Sekunden erstellen - Bitte warte bevor Du erneut einen Beitrag erstellst.", "too-many-posts-newbie": "Als neuer Benutzer kannst du nur einmal alle %1 Sekunde(n) posten, bis du %2 Reputation erworben hast - bitte warte, bevor du erneut postest", - "already-posting": "You are already posting", + "already-posting": "Du bist bereits am Posten", "tag-too-short": "Bitte gebe ein längeres Schlagwort ein. Schlagworte sollten mindestens %1 Zeichen enthalten.", "tag-too-long": "Bitte gebe ein kürzeres Schlagwort ein. Schlagworte können nicht länger als %1 Zeichen sein.", - "tag-not-allowed": "Tag not allowed", + "tag-not-allowed": "Tag nicht erlaubt", "not-enough-tags": "Nicht genügend Schlagworte. Themen müssen mindestens %1 Schlagwort(e) enthalten", "too-many-tags": "Zu viele Schlagworte. Themen dürfen nicht mehr als %1 Schlagwort(e) enthalten", "cant-use-system-tag": "Sie können dieses System-Tag nicht verwenden.", @@ -103,7 +104,7 @@ "guest-upload-disabled": "Uploads für Gäste wurden deaktiviert.", "cors-error": "Das Hochladen von Bildern ist aufgrund von falsch konfigurierten CORS nicht möglich.", "upload-ratelimit-reached": "Sie haben zu viele Dateien auf einmal hochgeladen. Bitte versuchen Sie es später noch einmal.", - "upload-error-fallback": "Unable to upload image — %1", + "upload-error-fallback": "Bild konnte nicht hochgeladen werden — %1", "scheduling-to-past": "Wählen Sie bitte ein Datum in der Zukunft.", "invalid-schedule-date": "Geben Sie bitte ein gültiges Datum und eine Uhrzeit ein.", "cant-pin-scheduled": "Geplante Themen können nicht (un)angeheftet werden.", @@ -137,8 +138,8 @@ "group-already-requested": "Deine Mitgliedsanfrage wurde bereits eingereicht", "group-join-disabled": "Du kannst dieser Gruppe zur Zeit nicht beitreten", "group-leave-disabled": "Du kannst diese Gruppe zur Zeit nicht verlassen", - "group-user-not-pending": "User does not have a pending request to join this group.", - "gorup-user-not-invited": "User has not been invited to join this group.", + "group-user-not-pending": "Benutzer hat keine ausstehende Anfrage zum Beitritt dieser Gruppe", + "gorup-user-not-invited": "Benutzer wurde nicht zur Gruppe eingeladen", "post-already-deleted": "Dieser Beitrag ist bereits gelöscht worden", "post-already-restored": "Dieser Beitrag ist bereits wiederhergestellt worden", "topic-already-deleted": "Dieses Thema ist bereits gelöscht worden", @@ -161,10 +162,10 @@ "chat-delete-duration-expired": "Du darfst Chat-Nachrichten nur bis zu %1 Sekunde(n) nach der erstellung löschen", "chat-deleted-already": "Diese Chatnachricht wurde bereits gelöscht.", "chat-restored-already": "Diese Chatnachricht wurde bereits wiederhergestellt.", - "chat-room-does-not-exist": "Der Chatraum existiert nicht.", - "cant-add-users-to-chat-room": "Can't add users to chat room.", - "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-does-not-exist": "Der Chatroom existiert nicht.", + "cant-add-users-to-chat-room": "Kann Benutzer nicht zu Chatroom hinzufügen", + "cant-remove-users-from-chat-room": "Kann Benutzer nicht aus Chatroom entfernen.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du hast diesen Beitrag bereits bewertet.", "reputation-system-disabled": "Das Reputationssystem ist deaktiviert.", "downvoting-disabled": "Downvotes sind deaktiviert.", @@ -199,6 +200,7 @@ "not-in-room": "Benutzer nicht im Raum", "cant-kick-self": "Du kannst dich nicht selber aus der Gruppe entfernen.", "no-users-selected": "Kein(e) Benutzer ausgewählt", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ungültiger Startseitenpfad", "invalid-session": "Ungültige Session", "invalid-session-text": "Es scheint als wäre deine Login-Sitzung nicht mehr aktiv. Bitte aktualisiere diese Seite.", @@ -230,5 +232,5 @@ "api.500": "Beim Versuch, Ihre Anfrage zu bearbeiten, ist ein unerwarteter Fehler aufgetreten.", "api.501": "Die Route, die Sie anrufen möchten, ist noch nicht implementiert. Bitte versuchen Sie es morgen erneut", "api.503": "Die Route, die Sie anrufen möchten, ist derzeit aufgrund einer Serverkonfiguration nicht verfügbar", - "api.reauth-required": "The resource you are trying to access requires (re-)authentication." + "api.reauth-required": "Die angeforderte Ressource erfordert eine (Re-)Authentifizierung." } \ No newline at end of file diff --git a/public/language/de/flags.json b/public/language/de/flags.json index 7fb7563221..8c8d5eda3b 100644 --- a/public/language/de/flags.json +++ b/public/language/de/flags.json @@ -3,27 +3,27 @@ "reports": "Reports", "first-reported": "Zuerst gemeldet", "no-flags": "Hurra! Keine Meldungen gefunden.", - "x-flags-found": "%1 flag(s) found.", + "x-flags-found": "%1 Flags gefunden.", "assignee": "Zugeordneter Benutzer", "update": "Aktualisieren", "updated": "Aktualisiert", "resolved": "Gelöst", "target-purged": "Der Inhalt auf den diese Meldung hingewiesen hat, wurde gelöscht und ist nicht mehr verfügbar.", - "target-aboutme-empty": "This user has no "About Me" set.", + "target-aboutme-empty": "Dieser Benutzer hat kein \"Über mich\" gesetzt.", "graph-label": "Tägliche Meldungen", "quick-filters": "Schnell-Filter", "filter-active": "Ein oder mehrere Filter sind in dieser Meldungs-Liste aktiv", "filter-reset": "Filter Entfernen", "filters": "Filter Optionen", - "filter-reporterId": "Reporter", - "filter-targetUid": "Reportee", + "filter-reporterId": "Meldender", + "filter-targetUid": "Gemeldeter", "filter-type": "Meldungstyp", "filter-type-all": "Gesamter Inhalt", "filter-type-post": "Beitrag", "filter-type-user": "Benutzer", "filter-state": "Status", - "filter-assignee": "Assignee", + "filter-assignee": "Zugewiesener Benutzer", "filter-cid": "Kategorie", "filter-quick-mine": "Mir zugewiesen", "filter-cid-all": "Alle Kategorien", @@ -47,7 +47,7 @@ "notes": "Meldungsnotizen", "add-note": "Notiz hinzufügen", - "edit-note": "Edit Note", + "edit-note": "Notiz bearbeiten", "no-notes": "Keine geteilten Notizen", "delete-note-confirm": "Bist du sicher, dass du diese Notiz löschen möchtest?", "delete-flag-confirm": "Möchtest Du diese Markierung wirklich löschen?", diff --git a/public/language/de/global.json b/public/language/de/global.json index aa86f77ece..68bae68ffd 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -4,13 +4,13 @@ "buttons.close": "Schließen", "403.title": "Zugriff verweigert", "403.message": "Du hast keine Zugriffsberechtigung für diese Seite.", - "403.login": "Perhaps you should try logging in?", + "403.login": "Du solltest Dich anmelden.", "404.title": " Nicht Gefunden", - "404.message": "You seem to have stumbled upon a page that does not exist.
Return to the home page.
", + "404.message": "Du bist über eine nicht vorhandene Seite gestolpert.
Zur Startseite zurückkehren.
", "500.title": "Interner Fehler.", "500.message": "Ups! Scheint als wäre etwas schief gelaufen!", "400.title": "Ungültige Anforderung", - "400.message": "It looks like this link is malformed, please double-check and try again.
Return to the home page.
", + "400.message": "Es scheint als wäre dieser Link fehlerhaft, bitte überprüfe ihn und versuche es erneut.
Gehe zurück zur Startseite.
", "register": "Registrieren", "login": "Anmelden", "please_log_in": "Bitte anmelden", @@ -20,8 +20,8 @@ "you_have_successfully_logged_in": "Du hast dich erfolgreich angemeldet", "save_changes": "Änderungen speichern", "save": "Speichern", - "create": "Create", - "cancel": "Cancel", + "create": "Erstellen", + "cancel": "Abbrechen", "close": "Schließen", "pagination": "Seitennummerierung", "pagination.out_of": "%1 von %2", @@ -39,18 +39,20 @@ "header.notifications": "Benachrichtigungen", "header.search": "Suche", "header.profile": "Profil", - "header.account": "Account", + "header.account": "Konto", "header.navigation": "Navigation", - "header.manage": "Manage", - "header.drafts": "Drafts", + "header.manage": "Verwalten", + "header.drafts": "Entwürfe", "notifications.loading": "Benachrichtigungen werden geladen", "chats.loading": "Nachrichten werden geladen", - "drafts.loading": "Loading Drafts", + "drafts.loading": "Entwürfe werden geladen", "motd.welcome": "Willkommen auf NodeBB, der Diskussionsplattform der Zukunft.", "previouspage": "Vorherige Seite", "nextpage": "Nächste Seite", "alert.success": "Erfolg", "alert.error": "Fehler", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Gesperrt", "alert.banned.message": "Sie wurden gerade gesperrt, Ihr Zugang ist jetzt eingeschränkt.", "alert.unbanned": "Nicht gesperrt", @@ -60,9 +62,9 @@ "users": "Benutzer", "topics": "Themen", "posts": "Beiträge", - "x-posts": "%1 posts", - "x-topics": "%1 topics", - "x-reputation": "%1 reputation", + "x-posts": "%1 Beiträge", + "x-topics": "%1 Themen", + "x-reputation": "%1 Reputation", "best": "Bestbewertet", "controversial": "Umstritten", "votes": "Stimmen", @@ -77,7 +79,7 @@ "reputation": "Ansehen", "lastpost": "Letzter Beitrag", "firstpost": "Erster Beitrag", - "about": "About", + "about": "Über", "read_more": "weiterlesen", "more": "Mehr", "none": "Nichts", @@ -91,7 +93,7 @@ "user_posted_ago": "%1 schrieb %2", "guest_posted_ago": "Gast schrieb %1", "last_edited_by": "zuletzt editiert von %1", - "edited-timestamp": "Edited %1", + "edited-timestamp": "Bearbeitet %1", "norecentposts": "Keine aktuellen Beiträge", "norecenttopics": "Keine aktuellen Themen", "recentposts": "Aktuelle Beiträge", @@ -133,9 +135,9 @@ "edited": "Bearbeitet", "disabled": "Deaktiviert", "select": "Auswählen", - "copied": "Copied", + "copied": "Kopiert", "user-search-prompt": "Gib hier etwas ein um Benutzer zu finden...", - "hidden": "Hidden", - "sort": "Sort", - "actions": "Actions" + "hidden": "Versteckt", + "sort": "Sortieren", + "actions": "Aktionen" } \ No newline at end of file diff --git a/public/language/de/groups.json b/public/language/de/groups.json index 5c192ff8ac..1a0457258a 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -1,7 +1,7 @@ { - "all-groups": "All groups", + "all-groups": "Alle Gruppen", "groups": "Gruppen", - "members": "Members", + "members": "Mitglieder", "view_group": "Gruppe zeigen", "owner": "Gruppenbesitzer", "new_group": "Neue Gruppe erstellen", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index 741c616cfb..23a5321dc8 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -1,15 +1,16 @@ { "chat.chatting_with": "Chatte mit", "chat.placeholder": "Gebe hier eine Chatnachricht ein, ziehe Bilder per Drag & Drop und drücke die Eingabetaste, um sie zu senden", - "chat.placeholder.mobile": "Type chat message here", - "chat.scroll-up-alert": "Go to most recent message", - "chat.usernames-and-x-others": "%1 & %2 others", - "chat.chat-with-usernames": "Chat with %1", - "chat.chat-with-usernames-and-x-others": "Chat with %1 & %2 others", + "chat.placeholder.mobile": "Hier Chatnachricht eingeben", + "chat.scroll-up-alert": "Zur neuesten Nachricht gehen", + "chat.usernames-and-x-others": "%1 & %2 andere", + "chat.chat-with-usernames": "Chatte mit %1", + "chat.chat-with-usernames-and-x-others": "Chatte mit %1 & %2 anderen", "chat.send": "Senden", "chat.no_active": "Du hast keine aktiven Chats.", "chat.user_typing": "%1 tippt gerade ...", "chat.user_has_messaged_you": "%1 hat dir geschrieben.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle Chats", "chat.mark_all_read": "Alle als gelesen markieren", "chat.no-messages": "Bitte wähle einen Empfänger, um den jeweiligen Nachrichtenverlauf anzuzeigen.", @@ -27,26 +28,47 @@ "chat.three_months": "3 Monate", "chat.delete_message_confirm": "Bist du sicher, dass du diese Nachricht löschen möchtest?", "chat.retrieving-users": "Rufe Benutzer ab", - "chat.manage-room": "Chat-Room managen", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.manage-room": "Chatroom managen", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Suche hier nach Usern. Auswählen fügt den User hinzu. Der neue User wird nicht in der Lage sein Chat Nachrichten zu lesen, die geschrieben wurden bevor er der Konversation hinzugefügt wurde. Ausschließlich Raumbesitzer () können User von Chat Rooms entfernen.", "chat.confirm-chat-with-dnd-user": "Dieser Benutzer hat seinen Status auf DnD (Bitte nicht stören) gesetzt. Möchtest du dennoch mit ihm chatten?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Raum umbenennen", "chat.rename-placeholder": "Gib deinen Chatraumnamen hier ein", "chat.rename-help": "Den Namen des Chatraums den du hier setzt, wird für alle Teilnehmer sichtbar sein.", - "chat.leave": "Chat verlassen", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Bist du sicher, dass du diesen Chat verlassen willst?", "chat.leave-help": "Den Chat zu verlassen wird dich von weiterem Schriftverkehr in diesem Chat entfernen. Solltest du in der Zukunft wieder hinzugefügt werden, würdest du keinen Chatverlauf sehen können, der in der Zwischenzeit geschrieben wurde.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In diesem Chat-Room", "chat.kick": "Rauswerfen", "chat.show-ip": "IP anzeigen", "chat.owner": "Raumbesitzer", - "chat.system.user-join": "%1 ist dem Raum beigetreten", - "chat.system.user-leave": "%1 hat den Raum verlassen", - "chat.system.room-rename": "%2 hat den Raum umbenannt: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Verfassen", "composer.show_preview": "Vorschau zeigen", "composer.hide_preview": "Vorschau ausblenden", - "composer.help": "Help", + "composer.help": "Hilfe", "composer.user_said_in": "%1 sagte in %2:", "composer.user_said": "%1 sagte:", "composer.discard": "Bist du sicher, dass du diesen Beitrag verwerfen möchtest?", @@ -69,11 +91,11 @@ "composer.schedule-date": "Datum", "composer.schedule-time": "Zeit", "composer.cancel-scheduling": "Planung abbrechen", - "composer.change-schedule-date": "Change Date", + "composer.change-schedule-date": "Datum ändern", "composer.set-schedule-date": "Datum einstellen", - "composer.discard-all-drafts": "Discard all drafts", - "composer.no-drafts": "You have no drafts", - "composer.discard-draft-confirm": "Do you want to discard this draft?", + "composer.discard-all-drafts": "Alle Entwürfe verwerfen", + "composer.no-drafts": "Keine Entwürfe vorhanden", + "composer.discard-draft-confirm": "Möchtest Du diesen Entwurf verwerfen?", "bootbox.ok": "OK", "bootbox.cancel": "Abbrechen", "bootbox.confirm": "Bestätigen", diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 004efbd804..07d2c7e72c 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -14,7 +14,7 @@ "flagged-content": "Gemeldeter Inhalt", "ip-blacklist": "IP Blacklist", "post-queue": "Beitragswarteschlange", - "registration-queue": "Registration Queue", + "registration-queue": "Warteliste", "users/online": "Benutzer online", "users/latest": "Neuste Benutzer", "users/sort-posts": "Benutzer mit den meisten Beiträgen", @@ -50,7 +50,7 @@ "account/watched_categories": "Beobachtete Kategorien von %1", "account/bookmarks": "Lesezeichen von %1", "account/settings": "Benutzer-Einstellungen", - "account/settings-of": "Changing settings of %1", + "account/settings-of": "Einstellungen von %1 ändern", "account/watched": "Von %1 beobachtete Themen", "account/ignored": "Ignorierte Themen von %1", "account/upvoted": "Von %1 positiv bewertete Beiträge", @@ -61,7 +61,7 @@ "account/uploads": "Uploads von %1", "account/sessions": "Login-Sitzungen", "confirm": "E-Mail bestätigt", - "maintenance.text": "%1 is currently undergoing maintenance.
Please come back another time.", + "maintenance.text": "%1 befindet sich derzeit in der Wartung.
Bitte komme später wieder.", "maintenance.messageIntro": "Zusätzlich hat der Administrator diese Nachricht hinterlassen:", "throttled.text": "%1 ist momentan aufgrund von Überlastung nicht verfügbar. Bitte komm später wieder." } \ No newline at end of file diff --git a/public/language/de/post-queue.json b/public/language/de/post-queue.json index babd93f44a..9afe19ad05 100644 --- a/public/language/de/post-queue.json +++ b/public/language/de/post-queue.json @@ -1,12 +1,12 @@ { "post-queue": "Beitragswarteschlange", - "no-queued-posts": "There are no posts in the post queue.", - "no-single-post": "The topic or post you are looking for is no longer in the queue. It has likely been approved or deleted already.", - "enabling-help": "To enable this feature, go to Settings → Post → Post Queue and enable Post Queue.", - "back-to-list": "Back to Post Queue", + "no-queued-posts": "Es sind keine Beiträge in der Beitragswarteschlange", + "no-single-post": "Dieses Thema oder dieser Beitrag ist nicht mehr in der Warteschlange. Er wurde wahrscheinlich angenommen oder gelöscht.", + "enabling-help": "Um diese Funktion zu aktivieren, gehe zu Einstellungen → Posts → Beitragswarteschlange und aktiviere die Beitragswarteschlange.", + "back-to-list": "Zurück zur Beitragswarteschlange", "user": "Benutzer", - "when": "When", + "when": "Wann", "category": "Kategorie", "title": "Titel", "content": "Inhalt", @@ -23,7 +23,7 @@ "notify": "Benachrichtigen", "notify-user": "Benutzer benachrichtigen", "confirm-reject": "Möchtest Du diesen Beitrag ablehnen?", - "confirm-remove": "Do you want to remove this post?", + "confirm-remove": "Möchtest Du diesen Beitrag entfernen?", "bulk-actions": "Massenaktionen", "accept-all": "Alle akzeptieren", "accept-selected": "Ausgewählte akzeptieren", @@ -31,10 +31,10 @@ "reject-all-confirm": "Möchtest Du alle Beiträge ablehnen?", "reject-selected": "Ausgewählte ablehnen", "reject-selected-confirm": "Möchtest Du %1 ausgewählte Beiträge ablehnen?", - "remove-all": "Remove all", - "remove-all-confirm": "Do you want to remove all posts?", - "remove-selected": "Remove Selected", - "remove-selected-confirm": "Do you want to remove %1 selected posts?", + "remove-all": "Alle entfernen", + "remove-all-confirm": "Möchtest Du alle Beiträge entfernen?", + "remove-selected": "Ausgewählte entfernen", + "remove-selected-confirm": "Möchtest Du %1 ausgewählte Beiträge entfernen?", "bulk-accept-success": "%1 Beiträge akzeptiert", "bulk-reject-success": "%1 Beiträge abgelehnt" } \ No newline at end of file diff --git a/public/language/de/recent.json b/public/language/de/recent.json index 7f007472c0..8305fdd38b 100644 --- a/public/language/de/recent.json +++ b/public/language/de/recent.json @@ -7,5 +7,5 @@ "alltime": "Gesamter Zeitraum", "no_recent_topics": "Es gibt keine aktuellen Themen.", "no_popular_topics": "Es gibt keine beliebten Themen.", - "load-new-posts": "Load new posts" + "load-new-posts": "Neue Beiträge laden" } \ No newline at end of file diff --git a/public/language/de/register.json b/public/language/de/register.json index eb2f6f335b..c82ce59f50 100644 --- a/public/language/de/register.json +++ b/public/language/de/register.json @@ -1,6 +1,6 @@ { "register": "Registrieren", - "already-have-account": "Already have an account?", + "already-have-account": "Du hast bereits ein Konto?", "cancel_registration": "Registrierungsvorgang abbrechen", "help.email": "Deine E-Mail Adresse ist standardmäßig nicht öffentlich sichtbar.", "help.username_restrictions": "Einen einmaligen Benutzernamen. %1-%2 Zeichen. Andere Benutzer können dich mit @Benutzername anschreiben.", diff --git a/public/language/de/search.json b/public/language/de/search.json index 146eadba90..2dc958f823 100644 --- a/public/language/de/search.json +++ b/public/language/de/search.json @@ -1,41 +1,41 @@ { - "type-to-search": "Type to search", + "type-to-search": "Tippen, um zu suchen", "results_matching": "%1 Ergebnis(se) stimmen mit \"%2\" überein, (%3 Sekunden)", "no-matches": "Keine Ergebnisse gefunden", "advanced-search": "Erweiterte Suche", "in": "In", - "in-titles": "In titles", - "in-titles-posts": "In titles and posts", - "in-posts": "In posts", - "in-categories": "In categories", - "in-users": "In users", - "in-tags": "In tags", - "categories": "Categories", - "all-categories": "All categories", - "categories-x": "Categories: %1", - "categories-watched-categories": "Categories: Watched categories", - "type-a-category": "Type a category", + "in-titles": "In Titeln", + "in-titles-posts": "In Titeln und Beiträgen", + "in-posts": "In Beiträgen", + "in-categories": "In Kategorien", + "in-users": "In Benutzern", + "in-tags": "In Tags", + "categories": "Kategorien", + "all-categories": "Alle Kategorien", + "categories-x": "Kategorien: %1", + "categories-watched-categories": "Kategorien: Beobachtete Kategorien", + "type-a-category": "Kategorie eingeben", "tags": "Tags", "tags-x": "Tags: %1", - "type-a-tag": "Type a tag", + "type-a-tag": "Tag eingeben", "match-words": "Übereinstimmende Worte", - "match-all-words": "Match all words", - "match-any-word": "Match any word", + "match-all-words": "Alle Wörter abgleichen", + "match-any-word": "Irgendein Wort abgleichen", "all": "Alle", "any": "Alles", "posted-by": "Geschrieben von", - "posted-by-usernames": "Posted by: %1", - "type-a-username": "Type a username", + "posted-by-usernames": "Verfasst von %1", + "type-a-username": "Benutzernamen eingeben", "search-child-categories": "Suche in Unterkategorien", "has-tags": "Hat Markierungen", "reply-count": "Anzahl Antworten", - "replies": "Replies", - "replies-atleast-count": "Replies: At least %1", - "replies-atmost-count": "Replies: At most %1", + "replies": "Antworten", + "replies-atleast-count": "Antworten: Mindestens %1", + "replies-atmost-count": "Antworten: Maximal %1", "at-least": "Mindestens", "at-most": "Höchstens", "relevance": "Relevanz", - "time": "Time", + "time": "Zeit", "post-time": "Verfaßt am", "votes": "Stimmen", "newer-than": "Neuer als", @@ -48,22 +48,22 @@ "three-months": "Drei Monate", "six-months": "Sechs Monate", "one-year": "Ein Jahr", - "time-newer-than-86400": "Time: Newer than yesterday", - "time-older-than-86400": "Time: Older than yesterday", - "time-newer-than-604800": "Time: Newer than one week", - "time-older-than-604800": "Time: Older than one week", - "time-newer-than-1209600": "Time: Newer than two weeks", - "time-older-than-1209600": "Time: Older than two weeks", - "time-newer-than-2592000": "Time: Newer than one month", - "time-older-than-2592000": "Time: Older than one month", - "time-newer-than-7776000": "Time: Newer than three months", - "time-older-than-7776000": "Time: Older than three months", - "time-newer-than-15552000": "Time: Newer than six months", - "time-older-than-15552000": "Time: Older than six months", - "time-newer-than-31104000": "Time: Newer than one year", - "time-older-than-31104000": "Time: Older than one year", + "time-newer-than-86400": "Zeitraum: Neuer als gestern", + "time-older-than-86400": "Zeitraum: Älter als gestern", + "time-newer-than-604800": "Zeitraum: Neuer als eine Woche", + "time-older-than-604800": "Zeitraum: Älter als eine Woche", + "time-newer-than-1209600": "Zeitraum: Neuer als zwei Wochen", + "time-older-than-1209600": "Zeitraum: Älter als zwei Wochen", + "time-newer-than-2592000": "Zeitraum: Neuer als einen Monat", + "time-older-than-2592000": "Zeitraum: Älter als einen Monat", + "time-newer-than-7776000": "Zeitraum: Neuer als drei Monate", + "time-older-than-7776000": "Zeitraum: Älter als drei Monate", + "time-newer-than-15552000": "Zeitraum: Neuer als sechs Monate", + "time-older-than-15552000": "Zeitraum: Älter als sechs Monate", + "time-newer-than-31104000": "Zeitraum: Neuer als ein Jahr", + "time-older-than-31104000": "Zeitraum: Älter als ein Jahr", "sort-by": "Sortieren nach", - "sort": "Sort", + "sort": "Sortieren", "last-reply-time": "Zeitpunkt der letzten Antwort", "topic-title": "Thementitel", "topic-votes": "Themenstimmen", @@ -74,36 +74,36 @@ "category": "Kategorie", "descending": "In absteigender Reihenfolge", "ascending": "In aufsteigender Reihenfolge", - "sort-by-relevance-desc": "Sort by: Relevance in descending order", - "sort-by-relevance-asc": "Sort by: Relevance in ascending order", - "sort-by-timestamp-desc": "Sort by: Post time in descending order", - "sort-by-timestamp-asc": "Sort by: Post time in ascending order", - "sort-by-votes-desc": "Sort by: Votes in descending order", - "sort-by-votes-asc": "Sort by: Votes in ascending order", - "sort-by-topic.lastposttime-desc": "Sort by: Last reply time in descending order", - "sort-by-topic.lastposttime-asc": "Sort by: Last reply time in ascending order", - "sort-by-topic.title-desc": "Sort by: Topic title in descending order", - "sort-by-topic.title-asc": "Sort by: Topic title in ascending order", - "sort-by-topic.postcount-desc": "Sort by: Number of replies in descending order", - "sort-by-topic.postcount-asc": "Sort by: Number of replies in ascending order", - "sort-by-topic.viewcount-desc": "Sort by: Number of views in descending order", - "sort-by-topic.viewcount-asc": "Sort by: Number of views in ascending order", - "sort-by-topic.votes-desc": "Sort by: Topic votes in descending order", - "sort-by-topic.votes-asc": "Sort by: Topic votes in ascending order", - "sort-by-topic.timestamp-desc": "Sort by: Topic start date in descending order", - "sort-by-topic.timestamp-asc": "Sort by: Topic start date in ascending order", - "sort-by-user.username-desc": "Sort by: Username in descending order", - "sort-by-user.username-asc": "Sort by: Username in ascending order", - "sort-by-category.name-desc": "Sort by: Category in descending order", - "sort-by-category.name-asc": "Sort by: Category in ascending order", - "save": "Save", + "sort-by-relevance-desc": "Sortieren nach: Relevanz (absteigend)", + "sort-by-relevance-asc": "Sortieren nach: Relevanz (aufsteigend)", + "sort-by-timestamp-desc": "Sortieren nach: Beitragszeit (absteigend)", + "sort-by-timestamp-asc": "Sortieren nach: Beitragszeit (aufsteigend)", + "sort-by-votes-desc": "Sortieren nach: Bewertung (absteigend)", + "sort-by-votes-asc": "Sortieren nach: Bewertung (aufsteigend)", + "sort-by-topic.lastposttime-desc": "Sortieren nach: Letzter Beitrag (absteigend)", + "sort-by-topic.lastposttime-asc": "Sortieren nach: Letzter Beitrag (aufsteigend)", + "sort-by-topic.title-desc": "Sortieren nach: Titel (absteigend)", + "sort-by-topic.title-asc": "Sortieren nach: Titel (aufsteigend)", + "sort-by-topic.postcount-desc": "Sortieren nach: Anzahl an Antworten (absteigend)", + "sort-by-topic.postcount-asc": "Sortieren nach: Anzahl an Antworten (aufsteigend)", + "sort-by-topic.viewcount-desc": "Sortieren nach: Anzahl der Aufrufe (absteigend)", + "sort-by-topic.viewcount-asc": "Sortieren nach: Anzahl der Aufrufe (aufsteigend)", + "sort-by-topic.votes-desc": "Sortieren nach: Bewertung (absteigend)", + "sort-by-topic.votes-asc": "Sortieren nach: Bewertung (aufsteigend)", + "sort-by-topic.timestamp-desc": "Sortieren nach: Erstelldatum (absteigend)", + "sort-by-topic.timestamp-asc": "Sortieren nach: Erstelldatum (aufsteigend)", + "sort-by-user.username-desc": "Sortieren nach: Benutzername (absteigend)", + "sort-by-user.username-asc": "Sortieren nach: Benutzername (aufsteigend)", + "sort-by-category.name-desc": "Sortieren nach: Kategorie (absteigend)", + "sort-by-category.name-asc": "Sortieren nach: Kategorie (aufsteigend)", + "save": "Speichern", "save-preferences": "Einstellungen speichern", "clear-preferences": "Einstellungen löschen", "search-preferences-saved": "Sucheinstellungen gespeichert", "search-preferences-cleared": "Sucheinstellungen gelöscht", "show-results-as": "Ergebnisse anzeigen als", - "show-results-as-topics": "Show results as topics", - "show-results-as-posts": "Show results as posts", + "show-results-as-topics": "Ergebnisse anzeigen als Themen", + "show-results-as-posts": "Ergebnisse anzeigen als Beiträge", "see-more-results": "Weitere Ergebnisse anzeigen (%1)", "search-in-category": "Suche in \"%1\"" } \ No newline at end of file diff --git a/public/language/de/tags.json b/public/language/de/tags.json index d7b9423646..2f309b93f3 100644 --- a/public/language/de/tags.json +++ b/public/language/de/tags.json @@ -1,7 +1,7 @@ { - "all-tags": "All tags", + "all-tags": "Alle Tags", "no_tag_topics": "Es gibt keine Themen mit diesem Schlagwort.", - "no-tags-found": "No tags found", + "no-tags-found": "Keine Tags gefunden", "tags": "Schlagworte", "enter_tags_here": "Hier Schlagworte eingeben. Jeweils %1 bis %2 Zeichen.", "enter_tags_here_short": "Schlagworte eingeben...", diff --git a/public/language/de/themes/harmony.json b/public/language/de/themes/harmony.json index f915155306..041c938859 100644 --- a/public/language/de/themes/harmony.json +++ b/public/language/de/themes/harmony.json @@ -1,16 +1,16 @@ { "theme-name": "Harmony Theme", "skins": "Skins", - "collapse": "Collapse", - "expand": "Expand", - "login-register-to-search": "Login or register to search.", - "settings.title": "Theme settings", - "settings.enableQuickReply": "Enable quick reply", - "settings.centerHeaderElements": "Center header elements", - "settings.mobileTopicTeasers": "Show topic teasers on mobile", - "settings.stickyToolbar": "Sticky toolbar", - "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", - "settings.autohideBottombar": "Auto hide bottom bar", - "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", - "settings.chatModals": "Enable chat modals" + "collapse": "Einklappen", + "expand": "Ausklappen", + "login-register-to-search": "Anmelden oder registrieren, um zu suchen", + "settings.title": "Theme-Einstellungen", + "settings.enableQuickReply": "Schnelle Antworten aktivieren", + "settings.centerHeaderElements": "Header-Elemente zentrieren", + "settings.mobileTopicTeasers": "Themen-Vorschau auf Mobilgeräten anzeigen", + "settings.stickyToolbar": "Klebrige Toolbar", + "settings.stickyToolbar.help": "Die Toolbar auf Themen- und Kategorieseiten bleibt oben an der Seite kleben", + "settings.autohideBottombar": "Fußzeile automatisch verbergen", + "settings.autohideBottombar.help": "Die Fußzeile wird auf Mobilgeräten versteckt, sobald nach unten gescrollt wird", + "settings.chatModals": "Chatfenster aktivieren" } \ No newline at end of file diff --git a/public/language/de/themes/persona.json b/public/language/de/themes/persona.json index fdf9070861..93264e1d78 100644 --- a/public/language/de/themes/persona.json +++ b/public/language/de/themes/persona.json @@ -1,10 +1,10 @@ { - "settings.title": "Theme settings", - "settings.intro": "You can customise your theme settings here. Settings are stored on a per-device basis, so you are able to have different settings on different devices (phone, tablet, desktop, etc.)", + "settings.title": "Theme-Einstellungen", + "settings.intro": "Hier kannst Du Deine Theme-Einstellungen anpassen. Die Einstellungen werden auf dem aktuellen Gerät gespeichert, sodass die Einstellungen sich auf unterschiedlichen Geräten (Handy, Tablet, PC etc.) unterscheiden können.", "settings.mobile-menu-side": "Menüposition der mobilen Seiten umschalten", - "settings.autoHidingNavbar": "Automatically hide the navbar on scroll", - "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)", - "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)", - "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)", - "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)" + "settings.autoHidingNavbar": "Navigationsleiste bei Scrollen automatisch verbergen", + "settings.autoHidingNavbar-xs": "Sehr kleine Bildschirme (z. B. Handys in aufrechter Anzeige)", + "settings.autoHidingNavbar-sm": "Kleinere Bildschirme (z. B. Handys, manche Tablets)", + "settings.autoHidingNavbar-md": "Mittelgroße Bildschirme (z. B. Tablets in seitlicher Anzeige)", + "settings.autoHidingNavbar-lg": "Größere Bildschirme (z. B. Computer-Bildschirme)" } \ No newline at end of file diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 03d1539bff..a00bd53389 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -36,34 +36,34 @@ "scheduled": "Geplant", "moved": "Verschoben", "moved-from": "Verschoben von %1", - "copy-code": "Copy Code", + "copy-code": "Code kopieren", "copy-ip": "IP-Adresse Kopieren", "ban-ip": "IP-Adresse bannen", "view-history": "Verlauf bearbeiten", - "wrote-ago": "wrote ", - "wrote-on": "wrote on ", - "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", - "user-locked-topic-ago": "%1 locked this topic %2", - "user-locked-topic-on": "%1 locked this topic on %2", - "user-unlocked-topic-ago": "%1 unlocked this topic %2", - "user-unlocked-topic-on": "%1 unlocked this topic on %2", - "user-pinned-topic-ago": "%1 pinned this topic %2", - "user-pinned-topic-on": "%1 pinned this topic on %2", - "user-unpinned-topic-ago": "%1 unpinned this topic %2", - "user-unpinned-topic-on": "%1 unpinned this topic on %2", - "user-deleted-topic-ago": "%1 deleted this topic %2", - "user-deleted-topic-on": "%1 deleted this topic on %2", - "user-restored-topic-ago": "%1 restored this topic %2", - "user-restored-topic-on": "%1 restored this topic on %2", - "user-moved-topic-from-ago": "%1 moved this topic from %2 %3", - "user-moved-topic-from-on": "%1 moved this topic from %2 on %3", - "user-queued-post-ago": "%1 queued post for approval %3", - "user-queued-post-on": "%1 queued post for approval on %3", - "user-referenced-topic-ago": "%1 referenced this topic %3", - "user-referenced-topic-on": "%1 referenced this topic on %3", - "user-forked-topic-ago": "%1 forked this topic %3", - "user-forked-topic-on": "%1 forked this topic on %3", + "wrote-ago": "schrieb ", + "wrote-on": "schrieb am ", + "replied-to-user-ago": "antwortete an %3 ", + "replied-to-user-on": "replied to %3 on ", + "user-locked-topic-ago": "%1 sperrte dieses Thema %2", + "user-locked-topic-on": "%1 sperrte dieses Thema am %2", + "user-unlocked-topic-ago": "%1 entsperrte dieses Thema %2", + "user-unlocked-topic-on": "%1 entsperrte dieses Thema am %2", + "user-pinned-topic-ago": "%1 hat dieses Thema angepinnt %2", + "user-pinned-topic-on": "%1 hat dieses Thema am %2 angepinnt", + "user-unpinned-topic-ago": "%1 hat dieses Thema abgepinnt %2", + "user-unpinned-topic-on": "%1 hat dieses Thema am %2 abgepinnt", + "user-deleted-topic-ago": "%1 hat dieses Thema gelöscht %2", + "user-deleted-topic-on": "%1 hat dieses Thema am %2 gelöscht", + "user-restored-topic-ago": "%1 stellte dieses Thema wieder her %2", + "user-restored-topic-on": "%1 stellte dieses Thema am %2 wieder her", + "user-moved-topic-from-ago": "%1 verschob dieses Thema von %2 %3", + "user-moved-topic-from-on": "%1 verschob dieses Thema von %2 am %3", + "user-queued-post-ago": "%1 hat Beitrag für Überprüfung markiert %3", + "user-queued-post-on": "%1 hat Beitrag am %3 für Überprüfung markiert", + "user-referenced-topic-ago": "%1 hat auf dieses Thema verwiesen %3", + "user-referenced-topic-on": "%1 hat am %3 auf dieses Thema verwiesen", + "user-forked-topic-ago": "%1 hat dieses Thema aufgespalten %3", + "user-forked-topic-on": "%1 hat dieses Thema am %3 aufgespalten", "bookmark_instructions": "Klicke hier, um zum letzten gelesenen Beitrag des Themas zurückzukehren.", "flag-post": "Diesen Post melden", "flag-user": "Diesen Benutzer melden", @@ -102,7 +102,7 @@ "thread_tools.change_owner": "Besitzer ändern", "thread_tools.select_category": "Kategorie auswählen", "thread_tools.fork": "Thema aufspalten", - "thread_tools.tag": "Tag Topic", + "thread_tools.tag": "Thema taggen", "thread_tools.delete": "Thema löschen", "thread_tools.delete-posts": "Beiträge entfernen", "thread_tools.delete_confirm": "Bist du sicher, dass du dieses Thema löschen möchtest?", @@ -111,7 +111,7 @@ "thread_tools.purge": "Thema endgültig löschen", "thread_tools.purge_confirm": "Bist du sicher, dass du dieses Thema endgültig löschen möchtest?", "thread_tools.merge_topics": "Themen vereinen", - "thread_tools.merge": "Merge Topic", + "thread_tools.merge": "Themen zusammenführen", "topic_move_success": "Dieses Thema wird in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", "topic_move_multiple_success": "Diese Themen werden in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", "topic_move_all_success": "Alle Themen werden in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", @@ -137,7 +137,7 @@ "post_moved": "Beitrag wurde verschoben!", "fork_topic": "Thema aufspalten", "enter-new-topic-title": "Neuen Thementitel eingeben", - "fork_topic_instruction": "Click the posts you want to fork, enter a title for the new topic and click fork topic", + "fork_topic_instruction": "Klicke auf die Beiträge, die aufgespalten werden sollen, gib einen Namen für das neue Thema an und klicke auf \"Thema aufspalten\"", "fork_no_pids": "Keine Beiträge ausgewählt!", "no-posts-selected": "Keine Beiträge ausgewählt!", "x-posts-selected": "%1 Beitrag(Beiträge) ausgewählt", @@ -152,19 +152,19 @@ "merge-new-title-for-topic": "Neuer Titel für das Thema", "topic-id": "Themen-ID", "move_posts_instruction": "Klicken Sie auf die Beiträge, die Sie verschieben möchten, und geben Sie dann eine Themen-ID ein oder gehen Sie zum Zielthema", - "move_topic_instruction": "Select the target category and then click move", + "move_topic_instruction": "Wähle die Ziel-Kategorie und klicke \"Verschieben\"", "change_owner_instruction": "Klicke auf die Beiträge, die einem anderen Benutzer zugeordnet werden sollen", "composer.title_placeholder": "Hier den Titel des Themas eingeben...", "composer.handle_placeholder": "Gib deinen Namen/Nick hier ein", - "composer.hide": "Hide", + "composer.hide": "Verstecken", "composer.discard": "Verwerfen", "composer.submit": "Absenden", "composer.additional-options": "Zusätzliche Optionen", - "composer.post-later": "Post Later", + "composer.post-later": "Später posten", "composer.schedule": "Zeitplan", "composer.replying_to": "Antworte auf %1", "composer.new_topic": "Neues Thema", - "composer.editing-in": "Editing post in %1", + "composer.editing-in": "Bearbeite Beitrag in %1", "composer.uploading": "Lade hoch...", "composer.thumb_url_label": "Vorschaubild-URL hier einfügen", "composer.thumb_title": "Vorschaubild zu diesem Thema hinzufügen", @@ -203,7 +203,7 @@ "last-post": "Letzter Beitrag", "go-to-my-next-post": "Zu meinem nächsten Beitrag gehen", "no-more-next-post": "Du hast keine weiteren Beiträge zu diesem Thema", - "post-quick-reply": "Quick reply", - "navigator.index": "Post %1 of %2", - "navigator.unread": "%1 unread" + "post-quick-reply": "Schnell antworten", + "navigator.index": "Beitrag %1 von %2", + "navigator.unread": "%1 ungelesen" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index 3b3ae57418..a570dded91 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -19,8 +19,8 @@ "delete_account_as_admin": "Konto löschen", "delete_content": "Konto-Inhalt löschen", "delete_all": "Konto und Inhalt löschen", - "delete_account_confirm": "Bist du sicher, dass du diesen Account löschen und deine Beiträge anonymisieren mnöchtest?
Diese Aktion kann nicht rückgängig gemacht werden und die Daten können nicht wiederhergestellt werden.

Gib dein Passwort ein um das Löschen des Accounts zu bestätigen.", - "delete_this_account_confirm": "Bist du sicher, dass du diesen Account löschen und seine Inhalte beibehalten möchstes?
Diese Aktion kann nicht rückgängig gemacht werden. Beiträge werden anonymisiert und können nicht wieder mit dem gelöschten Account verknüpft werden.

", + "delete_account_confirm": "Bist du sicher, dass du Deinen Account löschen und Deine Beiträge anonymisieren möchtest?
Diese Aktion kann nicht rückgängig gemacht werden und die Daten können nicht wiederhergestellt werden.

Gib dein Passwort ein, um das Löschen des Accounts zu bestätigen.", + "delete_this_account_confirm": "Bist du sicher, dass du diesen Account löschen und seine Inhalte beibehalten möchstest?
Diese Aktion kann nicht rückgängig gemacht werden. Beiträge werden anonymisiert und können nicht wieder mit dem gelöschten Account verknüpft werden.

", "delete_account_content_confirm": "Bist du sicher, dass du die Inhalte dieses Accounts (Beiträge/Themen/Uploads) löschen möchtest?
Diese Aktion ist irreversibel und die Daten können nicht wiederhergestellt werden.

", "delete_all_confirm": "Bist du sicher, dass du diesen Account und seinen gesamten Inhalt (Beiträge/Themen/Uploads) löschen möchtest?
Diese Aktion ist irreversibel und die Daten können nicht wiederhergestellt werden.

", "account-deleted": "Konto gelöscht", @@ -43,7 +43,7 @@ "followers": "Follower", "following": "Folge ich", "blocks": "Blockiert", - "blocked-users": "Blocked users", + "blocked-users": "Blockierte Benutzer", "block_toggle": "Ent-/Blocken", "block_user": "User blockieren", "unblock_user": "User entblocken", @@ -69,7 +69,7 @@ "upload_new_picture": "Neues Bild hochladen", "upload_new_picture_from_url": "Neues Bild von URL hochladen", "current_password": "Aktuelles Passwort", - "new_password": "New Password", + "new_password": "Neues Passwort", "change_password": "Passwort ändern", "change_password_error": "Ungültiges Passwort!", "change_password_error_wrong_current": "Ihr derzeitiges Passwort ist ungültig!", @@ -117,8 +117,8 @@ "paginate_description": "Themen und Beiträge in Seiten aufteilen, anstatt unendlich zu scrollen", "topics_per_page": "Themen pro Seite", "posts_per_page": "Beiträge pro Seite", - "category-topic-sort": "Category topic sort", - "topic-post-sort": "Topic post sort", + "category-topic-sort": "Sortierung nach Kategorie", + "topic-post-sort": "Sortierung nach Thema", "max_items_per_page": "Maximal %1", "acp_language": "Sprache der Admin Seiten", "notifications": "Benachrichtigungen", @@ -141,8 +141,8 @@ "group-order-help": "Wähle eine Gruppe und ordne die Titel mit den Pfeiltasten", "no-group-title": "Kein Gruppentitel", "select-skin": "Einen Skin auswählen", - "default": "Default (%1)", - "no-skin": "No Skin", + "default": "Standard: (%1)", + "no-skin": "Kein Skin", "select-homepage": "Startseite", "homepage": "Startseite", "homepage_description": "Wähle eine Seite, die als Forumstartseite verwendet werden soll, aus oder 'Keine' um die Standardstartseite zu verwenden.", @@ -174,8 +174,8 @@ "info.moderation-note.success": "Moderationsnotiz gespeichert", "info.moderation-note.add": "Notitz hinzufügen", "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.", - "revoke-session": "Revoke Session", - "browser-version-on-platform": "%1 %2 on %3", + "revoke-session": "Widerrufen der Session", + "browser-version-on-platform": "%1 %2 auf %3", "consent.title": "Deine Rechte & Zustimmungen", "consent.lead": "Dieses Community-Forum sammelt und verarbeitet deine persönlichen Daten.", "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.", @@ -204,5 +204,5 @@ "emailUpdate.required": "Dieses Feld ist erforderlich.", "emailUpdate.change-instructions": "An die eingegebene E-Mail-Adresse wird eine Bestätigungs-E-Mail mit einem eindeutigen Link gesendet. Durch den Zugriff auf diesen Link wird dein Eigentum an der E-Mail-Adresse bestätigt und diese wird in deinem Konto aktiv. Du kannst deine E-Mail-Adresse jederzeit auf deiner Kontoseite aktualisieren.", "emailUpdate.password-challenge": "Bitte gib dein Passwort ein, um dein Konto zu verifizieren.", - "emailUpdate.pending": "Your email address has not yet been confirmed, but an email has been sent out requesting confirmation. If you wish to invalidate that request and send a new confirmation request, please fill in the form below." + "emailUpdate.pending": "Deine E-Mailadresse wurde noch nicht bestätigt, aber eine E-Mail zur Bestätigung wurde versendet. Wenn Du diese Anfrage abbrechen und eine neue Bestätigung anfordern möchtest, fülle bitte das untenstehende Formular aus." } \ No newline at end of file diff --git a/public/language/de/users.json b/public/language/de/users.json index 1dc934af76..d88f941a9b 100644 --- a/public/language/de/users.json +++ b/public/language/de/users.json @@ -1,12 +1,12 @@ { - "all-users": "All Users", + "all-users": "Alle Benutzer", "latest_users": "Neuste Benutzer", "top_posters": "Meiste Beiträge", "most_reputation": "Höchstes Ansehen", "most_flags": "Meiste Meldungen", "search": "Suchen", "enter_username": "Benutzer durchsuchen", - "search-user-for-chat": "Search for a user to start chat", + "search-user-for-chat": "Suche nach einem Benutzer, um den Chat zu starten", "load_more": "Mehr laden", "users-found-search-took": "%1 Benutzer gefunden! Die Suche dauerte %2 s.", "filter-by": "Filtern nach", diff --git a/public/language/el/admin/admin.json b/public/language/el/admin/admin.json index d4d20945ba..8a79e434f6 100644 --- a/public/language/el/admin/admin.json +++ b/public/language/el/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/el/admin/dashboard.json b/public/language/el/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/el/admin/dashboard.json +++ b/public/language/el/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/el/admin/manage/categories.json b/public/language/el/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/el/admin/manage/categories.json +++ b/public/language/el/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/el/admin/manage/users.json b/public/language/el/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/el/admin/manage/users.json +++ b/public/language/el/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/el/admin/menu.json b/public/language/el/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/el/admin/menu.json +++ b/public/language/el/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/el/admin/settings/chat.json b/public/language/el/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/el/admin/settings/chat.json +++ b/public/language/el/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/el/admin/settings/guest.json b/public/language/el/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/el/admin/settings/guest.json +++ b/public/language/el/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/el/email.json b/public/language/el/email.json index 83a2f5c64e..fd5957829e 100644 --- a/public/language/el/email.json +++ b/public/language/el/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Πρόσφατα θέματα στο %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/el/error.json b/public/language/el/error.json index cf0873a294..f329ff5f2e 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Category does not exist", "no-topic": "Topic does not exist", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Το σύστημα φήμης έχει απενεργοποιηθεί.", "downvoting-disabled": "Η καταψήφιση έχει απενεργοποιηθεί", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/el/global.json b/public/language/el/global.json index 5d40fbd663..5b4c1031ae 100644 --- a/public/language/el/global.json +++ b/public/language/el/global.json @@ -51,6 +51,8 @@ "nextpage": "Επόμενη Σελίδα", "alert.success": "Επιτυχία", "alert.error": "Σφάλμα", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Αποκλεισμένος/η", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index 5f6d4149f0..070d1ba4f4 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", @@ -27,22 +28,43 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/el/topic.json b/public/language/el/topic.json index dd96139266..e360ec36f6 100644 --- a/public/language/el/topic.json +++ b/public/language/el/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/en-GB/admin/admin.json b/public/language/en-GB/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/en-GB/admin/admin.json +++ b/public/language/en-GB/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-GB/admin/dashboard.json b/public/language/en-GB/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/en-GB/admin/dashboard.json +++ b/public/language/en-GB/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/en-GB/admin/manage/categories.json b/public/language/en-GB/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-GB/admin/manage/categories.json +++ b/public/language/en-GB/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/en-GB/admin/manage/users.json b/public/language/en-GB/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-GB/admin/manage/users.json +++ b/public/language/en-GB/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/en-GB/admin/menu.json b/public/language/en-GB/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-GB/admin/menu.json +++ b/public/language/en-GB/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/en-GB/admin/settings/chat.json b/public/language/en-GB/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-GB/admin/settings/chat.json +++ b/public/language/en-GB/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-GB/email.json b/public/language/en-GB/email.json index 15cbf3cf26..3f8043cc67 100644 --- a/public/language/en-GB/email.json +++ b/public/language/en-GB/email.json @@ -30,6 +30,8 @@ "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index a76f180081..a374787ea6 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -62,6 +62,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Category does not exist", @@ -190,7 +191,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", @@ -230,6 +231,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", diff --git a/public/language/en-GB/global.json b/public/language/en-GB/global.json index 857bd05377..635b52a6e7 100644 --- a/public/language/en-GB/global.json +++ b/public/language/en-GB/global.json @@ -61,6 +61,8 @@ "alert.success": "Success", "alert.error": "Error", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banned", "alert.banned.message": "You have just been banned, your access is now restricted.", diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index 4a752ea387..0fd767d049 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", @@ -27,23 +28,44 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", diff --git a/public/language/en-US/admin/admin.json b/public/language/en-US/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/en-US/admin/admin.json +++ b/public/language/en-US/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-US/admin/dashboard.json b/public/language/en-US/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/en-US/admin/dashboard.json +++ b/public/language/en-US/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/en-US/admin/manage/categories.json b/public/language/en-US/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-US/admin/manage/categories.json +++ b/public/language/en-US/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/en-US/admin/manage/users.json b/public/language/en-US/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-US/admin/manage/users.json +++ b/public/language/en-US/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/en-US/admin/menu.json b/public/language/en-US/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-US/admin/menu.json +++ b/public/language/en-US/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/en-US/admin/settings/chat.json b/public/language/en-US/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-US/admin/settings/chat.json +++ b/public/language/en-US/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-US/admin/settings/guest.json b/public/language/en-US/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/en-US/admin/settings/guest.json +++ b/public/language/en-US/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/en-US/email.json b/public/language/en-US/email.json index 9f748a2e61..3e35d7514c 100644 --- a/public/language/en-US/email.json +++ b/public/language/en-US/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json index b4b0db8f20..9ec0963641 100644 --- a/public/language/en-US/error.json +++ b/public/language/en-US/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Category does not exist", "no-topic": "Topic does not exist", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/en-US/global.json b/public/language/en-US/global.json index d0846ffdfa..938e1d04a8 100644 --- a/public/language/en-US/global.json +++ b/public/language/en-US/global.json @@ -51,6 +51,8 @@ "nextpage": "Next Page", "alert.success": "Success", "alert.error": "Error", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banned", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index 5f6d4149f0..070d1ba4f4 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", @@ -27,22 +28,43 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/en-US/topic.json b/public/language/en-US/topic.json index 6ca9450d0f..30bbd10cd7 100644 --- a/public/language/en-US/topic.json +++ b/public/language/en-US/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/en-x-pirate/admin/admin.json b/public/language/en-x-pirate/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/en-x-pirate/admin/admin.json +++ b/public/language/en-x-pirate/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-x-pirate/admin/dashboard.json b/public/language/en-x-pirate/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/en-x-pirate/admin/dashboard.json +++ b/public/language/en-x-pirate/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/en-x-pirate/admin/manage/categories.json b/public/language/en-x-pirate/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-x-pirate/admin/manage/categories.json +++ b/public/language/en-x-pirate/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/en-x-pirate/admin/manage/users.json b/public/language/en-x-pirate/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-x-pirate/admin/manage/users.json +++ b/public/language/en-x-pirate/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/en-x-pirate/admin/menu.json b/public/language/en-x-pirate/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-x-pirate/admin/menu.json +++ b/public/language/en-x-pirate/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/en-x-pirate/admin/settings/chat.json b/public/language/en-x-pirate/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-x-pirate/admin/settings/chat.json +++ b/public/language/en-x-pirate/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-x-pirate/admin/settings/guest.json b/public/language/en-x-pirate/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/en-x-pirate/admin/settings/guest.json +++ b/public/language/en-x-pirate/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/en-x-pirate/email.json b/public/language/en-x-pirate/email.json index fe7ea95293..e31b3cf3cd 100644 --- a/public/language/en-x-pirate/email.json +++ b/public/language/en-x-pirate/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json index b4b0db8f20..9ec0963641 100644 --- a/public/language/en-x-pirate/error.json +++ b/public/language/en-x-pirate/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Category does not exist", "no-topic": "Topic does not exist", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/en-x-pirate/global.json b/public/language/en-x-pirate/global.json index dbf9e3e41d..6d01b5d682 100644 --- a/public/language/en-x-pirate/global.json +++ b/public/language/en-x-pirate/global.json @@ -51,6 +51,8 @@ "nextpage": "Next Page", "alert.success": "Success", "alert.error": "Somethin' broke", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Exiled", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index c7dfd3c200..7bd33c38ec 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ye be a lonely sailor.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", @@ -27,22 +28,43 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/en-x-pirate/topic.json b/public/language/en-x-pirate/topic.json index 6ca9450d0f..30bbd10cd7 100644 --- a/public/language/en-x-pirate/topic.json +++ b/public/language/en-x-pirate/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/es/admin/admin.json b/public/language/es/admin/admin.json index d9318a8105..458e023a41 100644 --- a/public/language/es/admin/admin.json +++ b/public/language/es/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/es/admin/dashboard.json b/public/language/es/admin/dashboard.json index f617609684..642065819c 100644 --- a/public/language/es/admin/dashboard.json +++ b/public/language/es/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Reconstruir y Reiniciar tu NodeBB ha sido deshabilitado, ya que parece que no lo estás ejecutando desde el daemon adecuado.", "maintenance-mode": "Modo de Mantenimiento", "maintenance-mode-title": "Haz clic aquí para activar el modo de mantenimiento de NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Actualizar el Grafo en Tiempo Real", "active-users": "Usuarios Activos", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/es/admin/manage/categories.json b/public/language/es/admin/manage/categories.json index 94bc8ff37d..4ca9a9d5d8 100644 --- a/public/language/es/admin/manage/categories.json +++ b/public/language/es/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Etiquetas permitidas", "upload-image": "Subir Imagen", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Eliminar", "category-image": "Imagen de Categoría", "image-and-icon": "Image & Icon", diff --git a/public/language/es/admin/manage/users.json b/public/language/es/admin/manage/users.json index 05d0112765..8c138a43ed 100644 --- a/public/language/es/admin/manage/users.json +++ b/public/language/es/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Descargar CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/es/admin/menu.json b/public/language/es/admin/menu.json index d34611740a..597b17270d 100644 --- a/public/language/es/admin/menu.json +++ b/public/language/es/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Usuarios", "manage/admins-mods": "Administradores & Mods", "manage/registration": "Cola de Registro", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Cola de mensajes", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista negra de IP", diff --git a/public/language/es/admin/settings/chat.json b/public/language/es/admin/settings/chat.json index dbdf26b7c5..7afc3f0342 100644 --- a/public/language/es/admin/settings/chat.json +++ b/public/language/es/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Deshabilitar edición y borrado de mensajes de chat", "disable-editing-help": "Los administradores y los moderadores globales están exentos de esta restricción", "max-length": "Maxima longitud de mensajes de chat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Máximo numero de usuarios en las salas de chat", "delay": "Tiempo entre envío de mensajes de chat en milisegundos", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/es/admin/settings/guest.json b/public/language/es/admin/settings/guest.json index 2ec54ccb9c..c0bfdf5877 100644 --- a/public/language/es/admin/settings/guest.json +++ b/public/language/es/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir manejo de visitantes", "handles.enabled-help": "Esta opción expone un nuevo campo que permite a los invitados escoger un nombre para asociarse con cada entrada/respuesta que hagan. Si está desactivado, se les llamará simplemente \"Invitado\".", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/es/email.json b/public/language/es/email.json index aba236eb0d..a07a86913e 100644 --- a/public/language/es/email.json +++ b/public/language/es/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Se ha modificado correctamente la contraseña.", "reset.notify.text1": "Te estamos notificando que en %1, tu contraseña ha sido cambiada correctamente.", "reset.notify.text2": "Si no has sido tú, por favor notifica al administrador inmediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos temas de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/es/error.json b/public/language/es/error.json index c99fa1c0f7..d5313d6d70 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Lo siento, esta cuenta ha sido baneada hasta %1 ( Razon: %2 )", "user-too-new": "Lo sentimos, es necesario que esperes %1 segundo(s) antes poder hacer tu primera publicación", "blacklisted-ip": "Lo sentimos, tu dirección IP ha sido baneada de esta comunidad. Si crees que debe de haber un error, por favor contacte con un administrador.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Por favor pon una fecha de fin del ban", "no-category": "La categoría no existe", "no-topic": "El tema no existe", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ya has votado a este mensaje.", "reputation-system-disabled": "El sistema de reputación está deshabilitado.", "downvoting-disabled": "La votación negativa está deshabilitada.", @@ -199,6 +200,7 @@ "not-in-room": "El usuario no está en la sala", "cant-kick-self": "No te puedes expulsar a ti mismo del grupo", "no-users-selected": "Ningun usuario(s) seleccionado", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ruta de página de inicio invalida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/es/global.json b/public/language/es/global.json index bd2dac6526..4e43821ee4 100644 --- a/public/language/es/global.json +++ b/public/language/es/global.json @@ -51,6 +51,8 @@ "nextpage": "Página siguiente", "alert.success": "¡Éxito!", "alert.error": "Error", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Baneado", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index b08bc94649..55d8684a87 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "No tiene conversaciones activas.", "chat.user_typing": "%1 está escribiendo...", "chat.user_has_messaged_you": "%1 te ha enviado un mensaje.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, selecciona un contacto para ver el historial de mensajes", @@ -27,22 +28,43 @@ "chat.three_months": "3 meses", "chat.delete_message_confirm": "¿Estás seguro de que deseas eliminar este mensaje?", "chat.retrieving-users": "Cargando usuarios...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Sala de Chat", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "Este usuario está en modo No molestar. ¿ Estás seguro de que quieres chatear con él ?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renombrar Sala", "chat.rename-placeholder": "Introduzca el nombre de su sala aquí", "chat.rename-help": "El nombre de sala elegido será visible por todos los participantes en la sala", - "chat.leave": "Abandonar Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Está seguro/a de que desea abandonar este chat?", "chat.leave-help": "Abandonar este chat te excluirá de futuras interacciones en este chat. Si eres re-añadido en el futuro, no verás ningún historial de chat anterior a tu vuelta.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "En esta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Crear", "composer.show_preview": "Ver Previsualización", "composer.hide_preview": "Ocultar Previsualización", diff --git a/public/language/es/topic.json b/public/language/es/topic.json index f46e57a467..477dc3a6c5 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "escribió ", "wrote-on": "escribió en ", "replied-to-user-ago": "respondió a %3 ", - "replied-to-user-on": "respondió a %3 en ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/et/admin/admin.json b/public/language/et/admin/admin.json index d430b9e319..1e904fd12e 100644 --- a/public/language/et/admin/admin.json +++ b/public/language/et/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/et/admin/dashboard.json b/public/language/et/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/et/admin/dashboard.json +++ b/public/language/et/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/et/admin/manage/categories.json b/public/language/et/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/et/admin/manage/categories.json +++ b/public/language/et/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/et/admin/manage/users.json b/public/language/et/admin/manage/users.json index 266a22b3a9..8e2d9da587 100644 --- a/public/language/et/admin/manage/users.json +++ b/public/language/et/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Lae alla CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/et/admin/menu.json b/public/language/et/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/et/admin/menu.json +++ b/public/language/et/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/et/admin/settings/chat.json b/public/language/et/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/et/admin/settings/chat.json +++ b/public/language/et/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/et/admin/settings/guest.json b/public/language/et/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/et/admin/settings/guest.json +++ b/public/language/et/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/et/email.json b/public/language/et/email.json index ae0b32b56a..7bb5323856 100644 --- a/public/language/et/email.json +++ b/public/language/et/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parool edukalt muudetud", "reset.notify.text1": "Teatame, et sinu parooli muutmine kuupäeval %1 oli edukas.", "reset.notify.text2": "Kui te ei ole lubanud seda, siis teavitage koheselt administraatorit.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Viimased teemad %1 poolt", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/et/error.json b/public/language/et/error.json index a88bb0e0c7..11a4fc8249 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Vabandust, te peate ootama %1 sekund(it) enne esimese postituse loomist.", "blacklisted-ip": "Vabandust! Sinu IP-aadress on siin kogukonnas keelatud. Kui arvad, et see on eksitus, palun leia kontakti administraatoriga.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Palun sisesta keelu lõpukuupäev", "no-category": "Kategooriat ei eksisteeri", "no-topic": "Teemat ei eksisteeri", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Sa oled juba hääletanud sellel postitusel.", "reputation-system-disabled": "Reputatsiooni süsteem ei ole aktiveeritud", "downvoting-disabled": "Negatiivsete häälte andmine ei ole võimaldatud", @@ -199,6 +200,7 @@ "not-in-room": "Kasutaja pole ruumis", "cant-kick-self": "Sa ei saa ennast ära visata gruppist", "no-users-selected": "Ühtki kasutajat pole valitud", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Vigane avalehe suunamine", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/et/global.json b/public/language/et/global.json index 17b4ae6fb5..caf350fec8 100644 --- a/public/language/et/global.json +++ b/public/language/et/global.json @@ -51,6 +51,8 @@ "nextpage": "Järgmine leht", "alert.success": "Õnnestus", "alert.error": "Viga", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Bannitud", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index f01fed2a2c..93a3f5a21f 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Sul ei ole hetkel aktiivseid vestlusi.", "chat.user_typing": "%1 kirjutab sõnumit...", "chat.user_has_messaged_you": "%1 saatis sulle sõnumi.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vali sõnumisaaja, et vaadata sõnumite ajalugu.", @@ -27,22 +28,43 @@ "chat.three_months": "3 Kuud", "chat.delete_message_confirm": "Oled kindel, et soovid selle sõnumi kustutada?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Koosta", "composer.show_preview": "Kuva eelvaadet", "composer.hide_preview": "Peida eelvaade", diff --git a/public/language/et/topic.json b/public/language/et/topic.json index 777797037a..1fb9c80cdf 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/fa-IR/admin/admin.json b/public/language/fa-IR/admin/admin.json index 681ce4a2a1..34435717b6 100644 --- a/public/language/fa-IR/admin/admin.json +++ b/public/language/fa-IR/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/fa-IR/admin/dashboard.json b/public/language/fa-IR/admin/dashboard.json index 239407fa56..b5fc4c9f28 100644 --- a/public/language/fa-IR/admin/dashboard.json +++ b/public/language/fa-IR/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/fa-IR/admin/manage/categories.json b/public/language/fa-IR/admin/manage/categories.json index c940769f68..4f21de69fe 100644 --- a/public/language/fa-IR/admin/manage/categories.json +++ b/public/language/fa-IR/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/fa-IR/admin/manage/users.json b/public/language/fa-IR/admin/manage/users.json index e6b082afe0..e7ad339098 100644 --- a/public/language/fa-IR/admin/manage/users.json +++ b/public/language/fa-IR/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/fa-IR/admin/menu.json b/public/language/fa-IR/admin/menu.json index 575786e68e..722f482140 100644 --- a/public/language/fa-IR/admin/menu.json +++ b/public/language/fa-IR/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "کاربران", "manage/admins-mods": "Admins & Mods", "manage/registration": "صف ثبت نام", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/fa-IR/admin/settings/chat.json b/public/language/fa-IR/admin/settings/chat.json index 0d10f1cb68..a5544ca116 100644 --- a/public/language/fa-IR/admin/settings/chat.json +++ b/public/language/fa-IR/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "بیشترین طول پیام‌های چت ", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "بیشترین تعداد کاربران در چت‌روم ", "delay": "زمان بین پیام های چت به میلی ثانیه", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/fa-IR/admin/settings/guest.json b/public/language/fa-IR/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/fa-IR/admin/settings/guest.json +++ b/public/language/fa-IR/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/fa-IR/email.json b/public/language/fa-IR/email.json index cc9a6b6964..64225662e5 100644 --- a/public/language/fa-IR/email.json +++ b/public/language/fa-IR/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "کلمه عبور با موفقیت تغییر کرد", "reset.notify.text1": "به شما اعلام میداریم که در %1، کلمه عبور شما با موفقیت بازنشانی شد.", "reset.notify.text2": "اگر این را تایید نمیکنید، لطفا بلافاصله به یک مدیر اطلاع دهید.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "آخرین پست های %1:", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json index 5b3bf5543d..a0a901833f 100644 --- a/public/language/fa-IR/error.json +++ b/public/language/fa-IR/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "با عرض پوزش، این حساب کاربری تا %1 اخراج شده است (دلیل: %2)", "user-too-new": "با عرض پوزش، شما باید %1 ثانیه پیش از فرستادن پست نخست خود صبر کنید", "blacklisted-ip": "با عرض پوزش، آدرس IP شما در انجمن مسدود شده است، اگر فکر می‌کنید اشتباهی رخ داده با مدیریت انجمن تماس بگیرید.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "لطفا تاریخ پایان برای این مسدود کردن ارائه دهید", "no-category": "دسته بندی وجود ندارد", "no-topic": "موضوع وجود ندارد.", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "چت روم وجود ندارد", "cant-add-users-to-chat-room": "نمی‌توانید کاربری به چت‌روم اضافه کنید ", "cant-remove-users-from-chat-room": "نمی‌توانید کاربران را از چت‌روم حذف کنید ", - "chat-room-name-too-long": "نام چت‌روم خیلی طولانی است ", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "شما قبلا به این پست رای داده اید.", "reputation-system-disabled": "سیستم اعتبار غیر فعال شده است", "downvoting-disabled": "رأی منفی غیر فعال شده است", @@ -199,6 +200,7 @@ "not-in-room": "هیچ کاربری در این گفتگو نیست", "cant-kick-self": "شما نمی توانید خودتان را از گروه کیک کنید", "no-users-selected": "هیچ کاربر(های) انتخاب نشده", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "مسیر صفحه اصلی نامعتبر است", "invalid-session": "seesion نامعتبر، دوباره وارد حساب کاربری خود شوید ", "invalid-session-text": "به نظر می رسد این جلسه برای ورود شما دیگر فعال نیست. لطفا این صفحه را رفرش کنید", diff --git a/public/language/fa-IR/global.json b/public/language/fa-IR/global.json index 0331c8da0f..159936e3b8 100644 --- a/public/language/fa-IR/global.json +++ b/public/language/fa-IR/global.json @@ -51,6 +51,8 @@ "nextpage": "برگهٔ پسین", "alert.success": "موفقیت", "alert.error": "خطا", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "بن شده ها", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index dc4a40d7b9..7034b505e5 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "شما هیچ گفتگوی فعالی ندارید.", "chat.user_typing": "%1 در حال نوشتن است...", "chat.user_has_messaged_you": "%1 به شما پیام داده است.", + "chat.replying-to": "Replying to %1", "chat.see_all": "همه‌ی چت‌ها", "chat.mark_all_read": "همه را خوانده‌شده بگیر", "chat.no-messages": "مشخص کنید تاریخچه گفتگوها با چه کاربری را می‌خواهید ببینید", @@ -27,22 +28,43 @@ "chat.three_months": "3 ماه", "chat.delete_message_confirm": "آیا مطمئن هستید که می خواهید این پیام را حذف کنید؟", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "مدیریت چت روم", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "کاربران را در اینجا جستجو کنید. پس از انتخاب، کاربر به چت اضافه می شود. کاربر جدید نمی‌تواند پیام‌های چت نوشته شده قبل از اضافه شدن به مکالمه را ببیند. فقط مالک اتاق () می توانند کاربران را از اتاق های گفتگو حذف کنند.", "chat.confirm-chat-with-dnd-user": "این کاربر وضعیت خود را روی حالت مزاحم نشوید قرار داده است. آیا همچنان می خواهید با او چت کنید؟", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "تعویض اسم چت روم", "chat.rename-placeholder": "اسم چت روم را اینجا وارد کنید", "chat.rename-help": "اسم چت روم برای همه کاربران چت روم قابل رویت خواهد بود.", - "chat.leave": "ترک چت روم", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "آیا شما مطمئن هستید که می خواهید چت روم را ترک کنید؟", "chat.leave-help": "ترک این چت روم باعث از دست دادن ارتباط شما می شود. اگر شما بعدا به چت روم اضافه بشوید، قادر به مشاهده تاریخچه پیام ها نخواهید بود.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "در این چت روم", "chat.kick": "اخراج", "chat.show-ip": "نشان دادن IP", "chat.owner": "مدیر چت روم", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "ارسال", "composer.show_preview": "نمایش پیش‌نمایش", "composer.hide_preview": "مخفی کردن پیش‌نمایش", diff --git a/public/language/fa-IR/topic.json b/public/language/fa-IR/topic.json index 32128f8391..f415d3e46c 100644 --- a/public/language/fa-IR/topic.json +++ b/public/language/fa-IR/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "نوشته‌شده ", "wrote-on": "نوشته‌شده در ", "replied-to-user-ago": "پاسخ داده شده به %3 در", - "replied-to-user-on": "پاسخ به %3 در", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "1% این موضوع را قفل کرد%2", "user-locked-topic-on": "1% این موضوع را در %2 قفل کرد ", "user-unlocked-topic-ago": "1% قفل این موضوع را باز کرد %2", diff --git a/public/language/fi/admin/admin.json b/public/language/fi/admin/admin.json index 25faab4d88..211d49e84c 100644 --- a/public/language/fi/admin/admin.json +++ b/public/language/fi/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/fi/admin/dashboard.json b/public/language/fi/admin/dashboard.json index 80ac78d658..4113ed55bd 100644 --- a/public/language/fi/admin/dashboard.json +++ b/public/language/fi/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "NodeBB:si udelleenrakennus ja -käynnistys on estetty; vaikuttaa siltä, ettet käytä siihen sopivaa daemonia.", "maintenance-mode": "Huoltotila", "maintenance-mode-title": "Valitse tämä pohjustaaksesi huoltotilan NodeBB:llesi.", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Reaaliaikaiset kuvaajien päivitykset", "active-users": "Aktiiviset käyttäjät", @@ -89,5 +90,9 @@ "details.logins-login-time": "Sisäänkirjautumisaika", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/fi/admin/manage/categories.json b/public/language/fi/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/fi/admin/manage/categories.json +++ b/public/language/fi/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/fi/admin/manage/users.json b/public/language/fi/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/fi/admin/manage/users.json +++ b/public/language/fi/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/fi/admin/menu.json b/public/language/fi/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/fi/admin/menu.json +++ b/public/language/fi/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/fi/admin/settings/chat.json b/public/language/fi/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/fi/admin/settings/chat.json +++ b/public/language/fi/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/fi/admin/settings/guest.json b/public/language/fi/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/fi/admin/settings/guest.json +++ b/public/language/fi/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/fi/email.json b/public/language/fi/email.json index 9147b31642..f0e2f1e2fa 100644 --- a/public/language/fi/email.json +++ b/public/language/fi/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Salasana onnistuneesti vaihdettu", "reset.notify.text1": "Ilmoitamme sinua että %1, salasanasi vaihdettiin onnistuneesti.", "reset.notify.text2": "Jos et tunnista tätä toimintoa, ilmoita välittömästi ylläpitäjälle.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Viimeisimmät viestiketjut henkilöltä %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 39a4632623..e701f5d6d1 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Anteeksi, mutta sinun täytyy odottaa %1 sekunti(a) ennen sinun ensimmäisen viestin lähettämistä", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Kategoriaa ei ole olemassa", "no-topic": "Aihetta ei ole olemassa", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", @@ -199,6 +200,7 @@ "not-in-room": "Käyttäjä ei ole huoneessa", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/fi/global.json b/public/language/fi/global.json index 88dadbefb6..2181b0d3ee 100644 --- a/public/language/fi/global.json +++ b/public/language/fi/global.json @@ -51,6 +51,8 @@ "nextpage": "Seuraava sivu", "alert.success": "Onnistui", "alert.error": "Virhe", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Estetty", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 50e0207b75..38dc299ac9 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Sinulla ei ole aktiivisia keskusteluita.", "chat.user_typing": "%1 kirjoittaa ...", "chat.user_has_messaged_you": "%1 lähetti sinulle viestin.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Valitse vastaanottaja katsellaksesi keskusteluhistoriaa", @@ -27,22 +28,43 @@ "chat.three_months": "3 kuukautta", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/fi/topic.json b/public/language/fi/topic.json index 20026d743f..b882d88949 100644 --- a/public/language/fi/topic.json +++ b/public/language/fi/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/fr/admin/admin.json b/public/language/fr/admin/admin.json index ac55751183..30e90b3093 100644 --- a/public/language/fr/admin/admin.json +++ b/public/language/fr/admin/admin.json @@ -4,13 +4,15 @@ "acp-title": "%1 | Panneau d'administration NodeBB", "settings-header-contents": "Contenus", - "changes-saved": "Changes Saved", - "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", + "changes-saved": "Changements sauvegardés", + "changes-saved-message": "Vos modifications de la configuration NodeBB ont été enregistrées.", "changes-not-saved": "Changements non sauvegardés !", "changes-not-saved-message": "NodeBB a rencontré un problème lors de l'enregistrement de vos modifications ! (%1)", - "save-changes": "Save changes", + "save-changes": "Enregistrer les changements", "min": "Min:", "max": "Max:", - "view": "View", - "edit": "Edit" + "view": "Voir", + "edit": "Éditer ", + "add": "Ajouter", + "select-icon": "Sélectionner un icône" } \ No newline at end of file diff --git a/public/language/fr/admin/appearance/customise.json b/public/language/fr/admin/appearance/customise.json index eeff047b45..52942da8a3 100644 --- a/public/language/fr/admin/appearance/customise.json +++ b/public/language/fr/admin/appearance/customise.json @@ -15,6 +15,6 @@ "custom-css.livereload": "Activer le rechargement en direct", "custom-css.livereload.description": "Activez cette option pour forcer toutes les sessions sur chaque appareil connecté à votre compte à se rafraichir lorsque vous cliquez sur Enregistrer.", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
Changes require a rebuild & restart.", - "bsvariables.enable": "Enable _variables.scss" + "bsvariables.description": "Remplacez les variables de lancement ici. Vous pouvez également utiliser un outil comme bootstrap.build et copier coller le code ici.
Les modifications nécessitent une reconstruction et un redémarrage.", + "bsvariables.enable": "Activer _variables.scss" } \ No newline at end of file diff --git a/public/language/fr/admin/appearance/skins.json b/public/language/fr/admin/appearance/skins.json index 283e53ebb8..0f3e380e01 100644 --- a/public/language/fr/admin/appearance/skins.json +++ b/public/language/fr/admin/appearance/skins.json @@ -1,6 +1,6 @@ { "skins": "Skins", - "bootswatch-skins": "Bootswatch Skins", + "bootswatch-skins": "Skins de lancement", "custom-skins": "Skins personnalisé", "add-skin": "Ajouter un Skin", "save-custom-skins": "Sauvegarder le Skin personnalisé", diff --git a/public/language/fr/admin/dashboard.json b/public/language/fr/admin/dashboard.json index 9ba7dde267..df6995a46f 100644 --- a/public/language/fr/admin/dashboard.json +++ b/public/language/fr/admin/dashboard.json @@ -26,13 +26,13 @@ "updates": "Mises à jour", "running-version": "NodeBB v%1 est actuellement installé.", "keep-updated": "Assurez-vous que votre version de NodeBB est à jour pour les derniers patchs de sécurité et correctifs de bugs.", - "up-to-date": "You are up-to-date ", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur. ", + "up-to-date": "

Votre version est à jour

", + "upgrade-available": "

Une nouvelle version (v%1) est disponible. Veuillez mettre à jour NodeBB.

", + "prerelease-upgrade-available": "

Votre version est dépassée. Une nouvelle version (v%1) est disponible. Veuillez mettre à jour NodeBB.

", + "prerelease-warning": "

Ceci est une version préliminaire de NodeBB. Des bugs inattendus peuvent se produire.

", "fallback-emailer-not-found": "Email de secours introuvable!", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator", - "latest-lookup-failed": "Failed to look up latest available version of NodeBB", + "running-in-development": "Le forum est en mode développement. Il peut être sujet à certaines vulnérabilités, veuillez contacter votre administrateur système.", + "latest-lookup-failed": "Erreur de vérification de la dernière version disponible de NodeBB", "notices": "Informations", "restart-not-required": "Pas de redémarrage nécessaire", @@ -48,6 +48,7 @@ "restart-disabled": "La régénération et le redémarrage de votre forum ont été désactivés car vous ne semblez pas les exécuter à l'aide du serveur approprié.", "maintenance-mode": "Mode maintenance", "maintenance-mode-title": "Cliquez ici pour passer NodeBB en mode maintenance", + "dark-mode": "Mode sombre", "realtime-chart-updates": "Mises à jour des graphiques en temps réel", "active-users": "Utilisateurs actifs", @@ -89,5 +90,9 @@ "details.logins-login-time": "Heure de connexion", "start": "Début", "end": "Fin", - "filter": "Filtre" + "filter": "Filtre", + "view-as-json": "Voir le JSON", + "expand-analytics": "Développer les statistiques", + "clear-search-history": "Effacer l'historique", + "clear-search-history-confirm": "Êtes-vous sûr de vouloir effacer tout l'historique de recherche ?" } diff --git a/public/language/fr/admin/extend/rewards.json b/public/language/fr/admin/extend/rewards.json index b0c72b2bcb..49973403a5 100644 --- a/public/language/fr/admin/extend/rewards.json +++ b/public/language/fr/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Récompenses", - "add-reward": "Add reward", + "add-reward": "Nouvelle récompense", "condition-if-users": "Si la propriété de l'utilisateur", "condition-is": "Est :", "condition-then": "Alors :", "max-claims": "Nombre de fois que la récompense peut être obtenue", "zero-infinite": "Entrez 0 pour infini", - "select-reward": "Select reward", + "select-reward": "Sélectionner une récompense", "delete": "Supprimer", "enable": "Activer", "disable": "Désactiver", diff --git a/public/language/fr/admin/extend/widgets.json b/public/language/fr/admin/extend/widgets.json index 66eb113295..d8b8fa5088 100644 --- a/public/language/fr/admin/extend/widgets.json +++ b/public/language/fr/admin/extend/widgets.json @@ -27,7 +27,7 @@ "container.placeholder": "Glissez et déposez un bloc ou entrez HTML ici.", "show-to-groups": "Visible pour les groupes", "hide-from-groups": "Masquer pour les groupes", - "start-date": "Start date", - "end-date": "End date", + "start-date": "Date de début", + "end-date": "Date de fin", "hide-on-mobile": "Masquer sur mobile" } \ No newline at end of file diff --git a/public/language/fr/admin/manage/admins-mods.json b/public/language/fr/admin/manage/admins-mods.json index d5a6aaa1c5..35579e669b 100644 --- a/public/language/fr/admin/manage/admins-mods.json +++ b/public/language/fr/admin/manage/admins-mods.json @@ -1,11 +1,11 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "Gérer les admins et les modos", "administrators": "Administrateurs", "global-moderators": "Modérateurs Globaux", "moderators": "Modérateurs", "no-global-moderators": "Aucun Modérateur Global ", "no-sub-categories": "Aucunes sous-catégories", - "view-children": "View children (%1)", + "view-children": "Afficher les enfants (%1)", "no-moderators": "Aucun Modérateur", "add-administrator": "Ajouter un Administrateur", "add-global-moderator": "Ajouter un Modérateur Global", diff --git a/public/language/fr/admin/manage/categories.json b/public/language/fr/admin/manage/categories.json index 3340bf8fb1..28e32bd26d 100644 --- a/public/language/fr/admin/manage/categories.json +++ b/public/language/fr/admin/manage/categories.json @@ -1,11 +1,11 @@ { - "manage-categories": "Manage Categories", - "add-category": "Add category", - "jump-to": "Jump to...", + "manage-categories": "Gérer les catégories", + "add-category": "Ajouter une catégorie", + "jump-to": "Aller à...", "settings": "Paramètres de la catégorie", - "edit-category": "Edit Category", + "edit-category": "Retour aux catégories", "privileges": "Privilèges", - "back-to-categories": "Back to categories", + "back-to-categories": "Retour aux catégories", "name": "Nom de la catégorie", "description": "Description de la catégorie", "bg-color": "Couleur d'arrière plan", @@ -19,11 +19,10 @@ "post-queue": "File d'attente", "tag-whitelist": "Liste blanche de mots clés", "upload-image": "Envoyer une image", - "upload": "Upload", - "select-icon": "Select Icon", + "upload": "Envoi", "delete-image": "Enlever", "category-image": "Image de la catégorie", - "image-and-icon": "Image & Icon", + "image-and-icon": "Image et icône", "parent-category": "Catégorie parente", "optional-parent-category": "Catégorie parente (optionnel)", "top-level": "Vers le haut", diff --git a/public/language/fr/admin/manage/groups.json b/public/language/fr/admin/manage/groups.json index 1c73034c21..b8159c5705 100644 --- a/public/language/fr/admin/manage/groups.json +++ b/public/language/fr/admin/manage/groups.json @@ -1,10 +1,10 @@ { - "manage-groups": "Manage Groups", - "add-group": "Add group", - "edit-group": "Edit Group", - "back-to-groups": "Back to groups", - "view-group": "View group", - "icon-and-title": "Icon & Title", + "manage-groups": "Gérer les groupes", + "add-group": "Ajouter un groupe", + "edit-group": "Éditer un groupe", + "back-to-groups": "Retour aux groupes", + "view-group": "Voir le groupe", + "icon-and-title": "Icône & titre", "name": "Nom du groupe", "badge": "Badge", "properties": "Propriétées", @@ -16,7 +16,7 @@ "edit": "Éditer", "delete": "Supprimer", "privileges": "Privilèges", - "members-csv": "Members (CSV)", + "members-csv": "Membres (CSV)", "search-placeholder": "Rechercher", "create": "Créer un groupe", "description-placeholder": "Une courte description de votre groupe", diff --git a/public/language/fr/admin/manage/privileges.json b/public/language/fr/admin/manage/privileges.json index b9b29d5bf3..c8ddcfed56 100644 --- a/public/language/fr/admin/manage/privileges.json +++ b/public/language/fr/admin/manage/privileges.json @@ -1,6 +1,6 @@ { - "manage-privileges": "Manage Privileges", - "discard-changes": "Discard changes", + "manage-privileges": "Gérer les privilèges", + "discard-changes": "Annuler les modifications", "global": "Global", "admin": "Admin", "group-privileges": "Privilèges de groupe", diff --git a/public/language/fr/admin/manage/tags.json b/public/language/fr/admin/manage/tags.json index 7e1ebd3584..f7fc238bfd 100644 --- a/public/language/fr/admin/manage/tags.json +++ b/public/language/fr/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Gérer les mots-clés", "none": "Votre forum n'a pour l'instant aucun sujet avec mots-clés.", "bg-color": "Couleur d'arrière plan", "text-color": "Couleur du texte", "description": "Pour une sélection multiple :\nSélectionnez des mots-clés en cliquant ou en sélectionnant avec votre souris ou utilisez la touche CTRL .", "create": "Créer le mot-clés", - "add-tag": "Add tag", + "add-tag": "Ajouter un mots-clés", "modify": "Modifier les mots-clés", "rename": "Renommer les mots-clés", "delete": "Supprimer la sélection", diff --git a/public/language/fr/admin/manage/uploads.json b/public/language/fr/admin/manage/uploads.json index 73e359622d..4edb3d8152 100644 --- a/public/language/fr/admin/manage/uploads.json +++ b/public/language/fr/admin/manage/uploads.json @@ -1,5 +1,5 @@ { - "manage-uploads": "Manage Uploads", + "manage-uploads": "Gérer les téléchargements", "upload-file": "Envoyer un fichier", "filename": "Nom du fichier", "usage": "Utilisé dans le message", diff --git a/public/language/fr/admin/manage/users.json b/public/language/fr/admin/manage/users.json index 4cbded2a09..3d55eb623a 100644 --- a/public/language/fr/admin/manage/users.json +++ b/public/language/fr/admin/manage/users.json @@ -1,5 +1,5 @@ { - "manage-users": "Manage Users", + "manage-users": "Gérer les utilisateurs", "users": "Utilisateurs", "edit": "Actions", "make-admin": "Promouvoir Admin", @@ -18,6 +18,7 @@ "purge": "Supprimer le(s) compte(s) et le contenu", "download-csv": "Exporter en CSV", "manage-groups": "Gérer les groupes", + "set-reputation": "Définir une réputation", "add-group": "Ajouter un groupe", "create": "Créer un utilisateur", "invite": "Inviter par mail", diff --git a/public/language/fr/admin/menu.json b/public/language/fr/admin/menu.json index 9ba612ce00..e6af9b58c5 100644 --- a/public/language/fr/admin/menu.json +++ b/public/language/fr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utilisateurs", "manage/admins-mods": "Modération", "manage/registration": "File d'inscription", + "manage/flagged-content": "Contenu signalé", "manage/post-queue": "File d’attente des messages", "manage/groups": "Groupes", "manage/ip-blacklist": "Liste noire d'IPs", @@ -72,9 +73,9 @@ "development/info": "Info", "rebuild-and-restart-forum": "Régénérer & Redémarrer votre forum", - "rebuild-and-restart": "Rebuild & Restart", + "rebuild-and-restart": "Régénérer & Redémarrer", "restart-forum": "Redémarrer le forum", - "restart": "Restart", + "restart": "Redémarrer", "logout": "Déconnexion ", "view-forum": "Voir le forum", diff --git a/public/language/fr/admin/settings/api.json b/public/language/fr/admin/settings/api.json index e8215ecfb7..fad2658239 100644 --- a/public/language/fr/admin/settings/api.json +++ b/public/language/fr/admin/settings/api.json @@ -3,27 +3,27 @@ "settings": "Paramètres", "lead-text": "À partir de cette page, vous pouvez paramétrer l'accès à l'API dans NodeBB.", "intro": "Par défaut, l'API authentifie les utilisateurs en fonction de leur cookie de session, mais NodeBB prend également en charge l'authentification du porteur via des tokens générés via cette page.", - "warning": "Be advised — treat tokens like passwords. If they are leaked, your account should be considered compromised.", + "warning": "Soyez Informé : Utiliser les jetons comme des mots de passe. S'ils sont divulgués, votre compte doit être considéré comme compromis.", "docs": "Cliquez ici pour accéder à la documentation de l'API", "require-https": "Forcer l'utilisation de l'API via HTTPS uniquement", "require-https-caveat": "Remarque: certaines installations impliquant des load balancer peuvent transmettre leurs requêtes à NodeBB via HTTP, auquel cas cette option doit rester désactivée.", "uid": "ID Utilisateur", - "token": "Token", + "token": "Jeton", "uid-help-text": "Spécifiez un ID utilisateur à associer à ce token. Si l'ID utilisateur est 0, il sera considéré comme un token maître, qui peut prendre l'identité d'autres utilisateurs en fonction du paramètre _uid", "description": "Description", - "last-seen": "Last seen", - "created": "Created", - "create-token": "Create Token", - "update-token": "Update Token", - "master-token": "Master token", + "last-seen": "Vu pour la dernière fois", + "created": "Créée", + "create-token": "Créer un Jeton", + "update-token": "Mettre à jour le Jeton", + "master-token": "Jeton maître", "last-seen-never": "Cette clé n'a jamais été utilisée.", "no-description": "Aucune description spécifiée.", "actions": "Actions", "edit": "Éditer ", - "roll": "Roll", + "roll": "Jeter", - "delete-confirm": "Are you sure you wish to delete this token? It will not be recoverable.", - "roll-confirm": "Are you sure you wish to regenerate this token? The old token will be immediately revoked and will not be recoverable." + "delete-confirm": "Voulez-vous vraiment supprimer ce jeton ? Il ne sera pas récupérable.", + "roll-confirm": "Voulez-vous vraiment régénérer ce jeton ? L'ancien jeton sera immédiatement révoqué et ne sera pas récupérable." } \ No newline at end of file diff --git a/public/language/fr/admin/settings/chat.json b/public/language/fr/admin/settings/chat.json index 7efc130f0e..0cd3d8201f 100644 --- a/public/language/fr/admin/settings/chat.json +++ b/public/language/fr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Désactiver l'édition/la suppression des messages des discussions", "disable-editing-help": "Les administrateurs et modérateurs globaux sont dispensés de cette restriction", "max-length": "Longueur maximales des messages de discussion", + "max-chat-room-name-length": "Longueur maximale des noms de salons", "max-room-size": "Nombre maximum d'utilisateurs dans une même discussion", "delay": "Temps entre chaque message de discussion (en millisecondes)", "notification-delay": "Délai de notification pour les messages de chat. (0 pour aucun délai)", diff --git a/public/language/fr/admin/settings/email.json b/public/language/fr/admin/settings/email.json index f44a23d0d7..2d1e56a0db 100644 --- a/public/language/fr/admin/settings/email.json +++ b/public/language/fr/admin/settings/email.json @@ -42,7 +42,7 @@ "subscriptions.hour-help": "Veuillez entrer un nombre représentant l'heure à laquelle envoyer les lettres d'activités (c'est à dire 0 pour minuit, 17 pour 5:00 pm). Gardez à l'esprit qu'il s'agit de l'heure du serveur, et peut ne pas correspondre à votre heure locale.
L'heure du serveur est :
La prochaine lettre d'activités sera envoyée à ", "notifications.remove-images": "Supprimer les images des notifications par e-mail", "require-email-address": "Exiger une adresse e-mail aux nouveaux utilisateurs ", - "require-email-address-warning": "By default, users can opt-out of entering an email address by leaving the field blank. Enabling this option means new users will have to enter and confirm an email address in order to proceed with registration and subsequent access to the forum. It does not ensure user will enter a real email address, nor even an address they own.", + "require-email-address-warning": "Par défaut, les utilisateurs peuvent refuser de saisir une adresse e-mail en laissant le champ vide. L'activation de cette option signifie que les nouveaux utilisateurs devront entrer et confirmer une adresse e-mail afin de procéder à l'inscription et à l'accès ultérieur au forum. Cela ne garantit pas que l'utilisateur saisira une véritable adresse e-mail, ni même une adresse qu'il possède.", "send-validation-email": "Envoyer une confirmation de validation lorsqu'un e-mail est ajouté ou modifié", "include-unverified-emails": "Envoyer des mails aux destinataires qui n'ont pas explicitement confirmé leurs mails", "include-unverified-warning": "Par défaut, les utilisateurs dont les mails sont associés à leur compte ont déjà été vérifiés, mais il existe des situations où ce n'est pas le cas (par exemple, les connexions SSO, les utilisateurs bénéficiant de droits acquis, etc.). Activez ce paramètre à vos risques et périls – l'envoi de mails à des adresses non vérifiées peut constituer une violation des lois anti-spam régionales.", diff --git a/public/language/fr/admin/settings/general.json b/public/language/fr/admin/settings/general.json index acd5e41788..47dcf81c8c 100644 --- a/public/language/fr/admin/settings/general.json +++ b/public/language/fr/admin/settings/general.json @@ -1,13 +1,13 @@ { - "general-settings": "General Settings", - "on-this-page": "On this page:", + "general-settings": "Réglages Principaux", + "on-this-page": "Sur cette page:", "site-settings": "Réglages du site", "title": "Titre du site", "title.short": "Titre court", "title.short-placeholder": "Si aucun titre court n'est spécifié, le titre du site sera utilisé", "title.url": "URL du lien du titre", "title.url-placeholder": "URL du titre du site", - "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. Note: This is not the external URL used in emails, etc. That is set by the url property in config.json", + "title.url-help": "Lorsque le titre est cliqué, il renvoi les utilisateurs à cette adresse. Si laissé vide, l'utilisateur sera envoyé à l'index du forum. Remarque : il ne s'agit pas de l'URL externe utilisée dans les e-mails, etc. Elle est définie par la propriété url dans config.json", "title.name": "Nom de votre communauté", "title.show-in-header": "Afficher le titre du site dans l'en-tête", "browser-title": "Titre dans le navigateur", @@ -18,7 +18,7 @@ "description": "Description du site", "keywords": "Mots-clés du site", "keywords-placeholder": "Mots-clés décrivant votre communauté, séparés par des virgules", - "logo-and-icons": "Site Logo & Icons", + "logo-and-icons": "Logo et icônes du site", "logo.image": "Image", "logo.image-placeholder": "Chemin vers un logo à afficher dans l'en-tête du site", "logo.upload": "Télécharger", diff --git a/public/language/fr/admin/settings/post.json b/public/language/fr/admin/settings/post.json index 8f2c807cd7..41b9ea9b66 100644 --- a/public/language/fr/admin/settings/post.json +++ b/public/language/fr/admin/settings/post.json @@ -40,7 +40,7 @@ "teaser.last-reply": "Dernier – Affiche le dernier message, ou \"Aucune réponse\" si il n'y a pas de réponse", "teaser.first": "Premier", "showPostPreviewsOnHover": "Afficher un aperçu des messages au survol des liens", - "unread-and-recent": "Unread & Recent Settings", + "unread-and-recent": "Paramètres non lus et récents", "unread.cutoff": "Nombre de jours pour les messages non-lus", "unread.min-track-last": "Nombre minimum de messages dans le sujet avant de garder en mémoire le dernier message lu", "recent.max-topics": "Maximum de sujets récents", diff --git a/public/language/fr/admin/settings/reputation.json b/public/language/fr/admin/settings/reputation.json index a5063ef3a9..a888590efc 100644 --- a/public/language/fr/admin/settings/reputation.json +++ b/public/language/fr/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "Procédez comme suit lorsqu'un signalement est résolu", "flags.action-on-reject": "Procédez comme suit lorsqu'un signalement est rejeté", "flags.action.nothing": "Ne rien faire", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "Annuler la notification envoyée aux modérateurs/administrateurs" } \ No newline at end of file diff --git a/public/language/fr/admin/settings/user.json b/public/language/fr/admin/settings/user.json index 1e8fcc0d2c..e1648547fe 100644 --- a/public/language/fr/admin/settings/user.json +++ b/public/language/fr/admin/settings/user.json @@ -59,7 +59,7 @@ "max-about-me-length": "Longueur maximum du À propos de moi", "terms-of-use": "Conditions générales d'utilisation du forum (Laisser vide pour désactiver)", "user-search": "Rechercher un utilisateur", - "user-search-results-per-page": "Number of users to display in search results", + "user-search-results-per-page": "Nombre d'utilisateurs à afficher dans les résultats de recherche", "default-user-settings": "Réglages par défaut des utilisateurs", "show-email": "Afficher l'adresse e-mail", "show-fullname": "Afficher le nom complet", diff --git a/public/language/fr/email.json b/public/language/fr/email.json index 21542e57d6..161cf7ed0b 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Mot de passe modifié", "reset.notify.text1": "Nous vous informons que le %1, votre mot de passe a été modifié.", "reset.notify.text2": "Si vous n'avez pas autorisé ceci, veuillez contacter immédiatement un administrateur.", + "digest.unread-rooms": "Discussions Non-Lus", + "digest.room-name-unreadcount": "%1 (%2 non lu)", "digest.latest_topics": "Derniers sujets de %1 :", "digest.top-topics": "Meilleurs sujets de %1", "digest.popular-topics": "Sujets populaires de %1", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index bb850baf7f..71304010e0 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Désolé, ce compte a été banni jusqu'au %1 (Raison : %2).", "user-too-new": "Désolé, vous devez attendre encore %1 seconde(s) avant d'envoyer votre premier message", "blacklisted-ip": "Désolé, votre adresse IP a été bannie de cette communauté. Si vous pensez que c'est une erreur, veuillez contacter un administrateur.", + "cant-blacklist-self-ip": "Vous ne pouvez pas mettre votre propre IP sur liste noire", "ban-expiry-missing": "Veuillez entrer une date de fin de banissement.", "no-category": "Cette catégorie n'existe pas", "no-topic": "Ce sujet n'existe pas", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Le salon de discussion n'existe pas.", "cant-add-users-to-chat-room": "Impossible d'ajouter des utilisateurs au salon.", "cant-remove-users-from-chat-room": "Impossible de supprimer des utilisateurs du salon.", - "chat-room-name-too-long": "Nom de salon trop long.", + "chat-room-name-too-long": "Le nom de la salon est trop long. Les noms ne peuvent pas contenir plus de %1 caractères.", "already-voting-for-this-post": "Vous avez déjà voté pour ce message.", "reputation-system-disabled": "Le système de réputation est désactivé", "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", @@ -199,6 +200,7 @@ "not-in-room": "L'utilisateur n'est pas dans cette salle", "cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe", "no-users-selected": "Aucun utilisateur sélectionné", + "no-groups-selected": "Aucun groupe(s) sélectionné", "invalid-home-page-route": "Chemin vers la page d'accueil invalide", "invalid-session": "Session Invalide", "invalid-session-text": "Il semblerait que votre session de connexion ne soit plus active. Merci de rafraîchir cette page.", diff --git a/public/language/fr/global.json b/public/language/fr/global.json index 3b0401132f..fbd61b0d5f 100644 --- a/public/language/fr/global.json +++ b/public/language/fr/global.json @@ -51,6 +51,8 @@ "nextpage": "Page suivante", "alert.success": "Succès", "alert.error": "Erreur", + "alert.warning": "Avertissement", + "alert.info": "Info", "alert.banned": "Bannis", "alert.banned.message": "Vous venez d'être banni, votre accès est désormais restreint.", "alert.unbanned": "Dé-banni", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 2a81ace788..31b7833088 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -2,7 +2,7 @@ "chat.chatting_with": "Discuter avec", "chat.placeholder": "Écrivez vos message ici, faites glisser / déposez les images, validez sur entrée pour envoyer", "chat.placeholder.mobile": "Tapez le message ici", - "chat.scroll-up-alert": "Go to most recent message", + "chat.scroll-up-alert": "Aller au message le plus récent", "chat.usernames-and-x-others": "%1 & %2 autres", "chat.chat-with-usernames": "Discuter avec %1", "chat.chat-with-usernames-and-x-others": "Discuter avec %1 & %2 autres", @@ -10,6 +10,7 @@ "chat.no_active": "Vous n'avez aucune discussion en cours.", "chat.user_typing": "%1 est en train d'écrire ...", "chat.user_has_messaged_you": "%1 vous a envoyé un message.", + "chat.replying-to": "En réponse à %1", "chat.see_all": "Tous les chats", "chat.mark_all_read": "Marquez tous comme lu", "chat.no-messages": "Veuillez sélectionner un destinataire pour voir l'historique des discussions", @@ -27,22 +28,43 @@ "chat.three_months": "3 Mois", "chat.delete_message_confirm": "Êtes-vous sûr de vouloir supprimer ce message ?", "chat.retrieving-users": "Ajouter des utilisateurs ...", + "chat.view-users-list": "Afficher la liste de utilisateurs", + "chat.public-rooms": "Salon Publique (ù1)", + "chat.private-rooms": "Salon Privé (%1)", + "chat.create-room": "Créer une salon de discussion", + "chat.private.option": "Privé (uniquement visible pour les utilisateurs ajoutés au salon)", + "chat.public.option": "Public (Visible par tous les utilisateurs des groupes sélectionnés)", + "chat.public.groups-help": "Pour créer une salon de discussion visible par tous les utilisateurs, sélectionnez les utilisateurs enregistrés dans la liste des groupes.", "chat.manage-room": "Gérer l'espace de discussion", + "chat.add-user": "Ajouter un utilisateur", + "chat.notification-settings": "Paramètres de notification", + "chat.default-notification-setting": "Paramètres des notifications par défaut", + "chat.notification-setting-room-default": "Salon par défaut", + "chat.notification-setting-none": "Aucunes notifications", + "chat.notification-setting-at-mention-only": "@mention seulement", + "chat.notification-setting-all-messages": "Tous les messages", + "chat.select-groups": "Sélectionner des groupes", "chat.add-user-help": "Rechercher des utilisateurs ici. Lorsque cette option est sélectionnée, l'utilisateur sera ajouté à l'espace de discussion. Le nouvel utilisateur ne pourra pas visualiser les échanges avant d'être ajoutés à la conversation. Seuls les propriétaires de l'espace de discussion () peuvent supprimer des utilisateurs.", "chat.confirm-chat-with-dnd-user": "Cet utilisateur a son statut en mode \"Ne pas déranger\". Voulez-vous quand même discuter avec lui ?", + "chat.room-name-optional": "Renommer l'espace de discussion (optionnel)", "chat.rename-room": "Renommer l'espace de discussion ", "chat.rename-placeholder": "Entrer le nom ici ", "chat.rename-help": "Le nom de l'espace de discussion défini ici sera visible par tous les participants à la discussion.", - "chat.leave": "Quitter la discussion", + "chat.leave": "Partir", + "chat.leave-room": "Quitter l'espace de discussion", "chat.leave-prompt": "Êtes-vous sûr de vouloir quitter la discussion ?", "chat.leave-help": "Si vous quittez vous ne pourrez plus suivre la discussion. Si vous êtes de nouveau ajouté, vous ne verrez aucun historique de la discussion avant votre réintégration.", + "chat.delete": "Supprimer", + "chat.delete-room": "Supprimer l'espace de discussion ", + "chat.delete-prompt": "Êtes-vous sûr de vouloir supprimer cet espace de discussion ?", "chat.in-room": "Dans cet espace de discussion", "chat.kick": "Exclure", "chat.show-ip": "Voir IP", "chat.owner": "Espace Admin", - "chat.system.user-join": "%1 a rejoint la discussion", - "chat.system.user-leave": "%1 a quitté la discussion", - "chat.system.room-rename": "%2 a renommé la discussion: %1", + "chat.grant-rescind-ownership": "Promouvoir/rétrograder comme propriétaire", + "chat.system.user-join": "%1 a rejoint la discussion ", + "chat.system.user-leave": "%1 a quitté la discussion ", + "chat.system.room-rename": "%2 a renommé cette discussion en \"%1\" ", "composer.compose": "Écrire", "composer.show_preview": "Afficher l'aperçu", "composer.hide_preview": "Masquer l'aperçu", diff --git a/public/language/fr/themes/harmony.json b/public/language/fr/themes/harmony.json index dc3c021cc2..9c6527fee9 100644 --- a/public/language/fr/themes/harmony.json +++ b/public/language/fr/themes/harmony.json @@ -7,10 +7,10 @@ "settings.title": "Configuration du thème", "settings.enableQuickReply": "Activer les réponses rapide", "settings.centerHeaderElements": "Centrer les éléments d'en-tête", - "settings.mobileTopicTeasers": "Show topic teasers on mobile", - "settings.stickyToolbar": "Sticky toolbar", - "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", - "settings.autohideBottombar": "Auto hide bottom bar", - "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", - "settings.chatModals": "Enable chat modals" + "settings.mobileTopicTeasers": "Afficher les teasers de sujet sur mobile", + "settings.stickyToolbar": "Barre d'outils", + "settings.stickyToolbar.help": "La barre d'outils sur les pages de sujets et de catégories restera en haut de la page", + "settings.autohideBottombar": "Masquer automatiquement la barre inférieure", + "settings.autohideBottombar.help": "La barre inférieure de la vue mobile sera masquée lorsque la page défilera vers le bas", + "settings.chatModals": "Activer les discussions" } \ No newline at end of file diff --git a/public/language/fr/themes/persona.json b/public/language/fr/themes/persona.json index c6aec765ad..f0cc2ac77a 100644 --- a/public/language/fr/themes/persona.json +++ b/public/language/fr/themes/persona.json @@ -1,10 +1,10 @@ { - "settings.title": "Theme settings", - "settings.intro": "You can customise your theme settings here. Settings are stored on a per-device basis, so you are able to have different settings on different devices (phone, tablet, desktop, etc.)", + "settings.title": "Configuration du thème", + "settings.intro": "Vous pouvez personnaliser les paramètres de votre thème ici. Les paramètres sont stockés sur une base par appareil, vous pouvez donc avoir différents paramètres sur différents appareils (téléphone, tablette, ordinateur de bureau, etc.)", "settings.mobile-menu-side": "Changer la position du menu en version mobiles", - "settings.autoHidingNavbar": "Automatically hide the navbar on scroll", - "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)", - "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)", - "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)", - "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)" + "settings.autoHidingNavbar": "Masquer automatiquement la barre de navigation lors du défilement", + "settings.autoHidingNavbar-xs": "Très petits écrans (par exemple, téléphones en mode portrait)", + "settings.autoHidingNavbar-sm": "Petits écrans (par exemple, téléphones, certaines tablettes)", + "settings.autoHidingNavbar-md": "Moyen écrans (ex. tablettes en mode paysage)", + "settings.autoHidingNavbar-lg": "Grands écrans (par exemple, ordinateurs de bureau)" } \ No newline at end of file diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index c7009253f3..582860ef1c 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "écrit ", "wrote-on": "a écrit sur ", "replied-to-user-ago": "a répondu à %3 ", - "replied-to-user-on": "a répondu à %3 sur ", + "replied-to-user-on": "a répondu à %3 le ", "user-locked-topic-ago": "%1 a verrouillé ce sujet %2", "user-locked-topic-on": "%1 a verrouillé ce sujet sur %2", "user-unlocked-topic-ago": "%1 a déverrouillé ce sujet %2", @@ -164,7 +164,7 @@ "composer.schedule": "Planification", "composer.replying_to": "En réponse à %1", "composer.new_topic": "Nouveau sujet", - "composer.editing-in": "Editing post in %1", + "composer.editing-in": "Modification du message dans %1", "composer.uploading": "envoi en cours…", "composer.thumb_url_label": "Coller une URL de vignette du sujet", "composer.thumb_title": "Ajouter une vignette à ce sujet", diff --git a/public/language/fr/users.json b/public/language/fr/users.json index 21a2ac5df0..36b9dd9a45 100644 --- a/public/language/fr/users.json +++ b/public/language/fr/users.json @@ -6,7 +6,7 @@ "most_flags": "Les plus signalés", "search": "Rechercher", "enter_username": "Entrez le nom d'un utilisateur", - "search-user-for-chat": "Search for a user to start chat", + "search-user-for-chat": "Rechercher un utilisateur pour démarrer la discussion", "load_more": "Charger la suite", "users-found-search-took": "%1 utilisateur(s) trouvé(s)! La recherche a pris %2 secondes.", "filter-by": "Filtrer par", diff --git a/public/language/gl/admin/admin.json b/public/language/gl/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/gl/admin/admin.json +++ b/public/language/gl/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/gl/admin/dashboard.json b/public/language/gl/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/gl/admin/dashboard.json +++ b/public/language/gl/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/gl/admin/manage/categories.json b/public/language/gl/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/gl/admin/manage/categories.json +++ b/public/language/gl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/gl/admin/manage/users.json b/public/language/gl/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/gl/admin/manage/users.json +++ b/public/language/gl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/gl/admin/menu.json b/public/language/gl/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/gl/admin/menu.json +++ b/public/language/gl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/gl/admin/settings/chat.json b/public/language/gl/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/gl/admin/settings/chat.json +++ b/public/language/gl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/gl/admin/settings/guest.json b/public/language/gl/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/gl/admin/settings/guest.json +++ b/public/language/gl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/gl/email.json b/public/language/gl/email.json index ca56e064bd..6cd015df60 100644 --- a/public/language/gl/email.json +++ b/public/language/gl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Contrasinal cambiado", "reset.notify.text1": "Estámosche a notificar que nun %1, o seu contrasinal foi cambiado correctamente.", "reset.notify.text2": "Se ti non autorizache isto, por favor notifica inmediatamente a un administrador.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos temas de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index effa37c1f2..aae9e55d49 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Desculpa, agarda %1 second(s) antes de facer a túa primeira publicación.", "blacklisted-ip": "Sentímolo, o teu enderezo IP foi baneado desta comunidade. Se crees que se debe a un erro, por favor, contacte cun administrador.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Por favor, engade unha data de fin do ban", "no-category": "A categoría non existe", "no-topic": "O tema non existe", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Xa votache esta mensaxe.", "reputation-system-disabled": "O sistema de reputación está deshabilitado", "downvoting-disabled": "Os votos negativos están deshabilitados", @@ -199,6 +200,7 @@ "not-in-room": "O usuario non se atopa nesta sala", "cant-kick-self": "Non te podes expulsar a ti mesmo do grupo", "no-users-selected": "Ningún usuario seleccionado", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ruta de páxina de inicio inválida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/gl/global.json b/public/language/gl/global.json index c66ea8404d..d3d1bfdfe6 100644 --- a/public/language/gl/global.json +++ b/public/language/gl/global.json @@ -51,6 +51,8 @@ "nextpage": "Páxina Seguinte", "alert.success": "Éxito", "alert.error": "Erro", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Expulsado", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index f35c6944b1..985ed67510 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non tes charlas activas.", "chat.user_typing": "%1 está a escribir...", "chat.user_has_messaged_you": "%1 enviouche unha mensaxe.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, seleccione un destinatario para ver o historial das mensaxes ", @@ -27,22 +28,43 @@ "chat.three_months": "3 Meses", "chat.delete_message_confirm": "Estás seguro de que desexas eliminar esta mensaxe?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Elaborar", "composer.show_preview": "Amosar vista previa", "composer.hide_preview": "Agochar vista previa", diff --git a/public/language/gl/topic.json b/public/language/gl/topic.json index a72421dc7a..e3e1c1d0fd 100644 --- a/public/language/gl/topic.json +++ b/public/language/gl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/he/admin/admin.json b/public/language/he/admin/admin.json index 5fa1d8a035..05c6ac70fb 100644 --- a/public/language/he/admin/admin.json +++ b/public/language/he/admin/admin.json @@ -11,6 +11,8 @@ "save-changes": "שמור שינויים", "min": "מינימום:", "max": "מקסימום:", - "view": "View", - "edit": "עריכה" + "view": "צפייה", + "edit": "עריכה", + "add": "הוספה", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/errors.json b/public/language/he/admin/advanced/errors.json index eb5715f142..ac86dbfdbf 100644 --- a/public/language/he/admin/advanced/errors.json +++ b/public/language/he/admin/advanced/errors.json @@ -1,15 +1,15 @@ { "errors": "שגיאות", "figure-x": "דוגמא %1", - "error-events-per-day": "%1 ארועים ביום", + "error-events-per-day": "%1 אירועים ביום", "error.404": "לא נמצא 404", "error.503": "השירות אינו זמין 503", - "manage-error-log": "נהל רישום שגיאות", - "export-error-log": "יצא רישום שגיאות (CSV)", - "clear-error-log": "נקה רישום שגיאות", + "manage-error-log": "נהל לוג שגיאות", + "export-error-log": "יצא לוג שגיאות (CSV)", + "clear-error-log": "נקה לוג שגיאות", "route": "נתיב", "count": "ספירה", "no-routes-not-found": "הידד! אין שגיאות 404!", - "clear404-confirm": "האם אתה בטוח שאתה רוצה לנקות את רישום שגיאות 404?", + "clear404-confirm": "האם אתה בטוח שאתה רוצה לנקות את לוג שגיאות 404?", "clear404-success": "שגיאות \"404 לא נמצא\" נוקו" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/events.json b/public/language/he/admin/advanced/events.json index 37da405a88..757d5ae8a8 100644 --- a/public/language/he/admin/advanced/events.json +++ b/public/language/he/admin/advanced/events.json @@ -1,8 +1,8 @@ { - "events": "ארועים", - "no-events": "אין ארועים", - "control-panel": "בקרת ארועים\n ", - "delete-events": "מחיקת ארועים", + "events": "אירועים", + "no-events": "אין אירועים", + "control-panel": "בקרת אירועים", + "delete-events": "מחיקת אירועים", "confirm-delete-all-events": "האם אתה בטוח שאתה רוצה למחוק את כל האירועים שנרשמו?", "filters": "מסננים", "filters-apply": "החל מסננים", diff --git a/public/language/he/admin/advanced/logs.json b/public/language/he/admin/advanced/logs.json index 7c503395a1..5c1dd85a15 100644 --- a/public/language/he/admin/advanced/logs.json +++ b/public/language/he/admin/advanced/logs.json @@ -1,7 +1,7 @@ { - "logs": "רישומים", - "control-panel": "בקרת רישומים", - "reload": "טען רישומים מחדש", - "clear": "נקה רישומים", - "clear-success": "הרישומים נוקו!" + "logs": "לוגים", + "control-panel": "בקרת לוגים", + "reload": "טען לוג מחדש", + "clear": "נקה לוגים", + "clear-success": "הלוגים נוקו!" } \ No newline at end of file diff --git a/public/language/he/admin/appearance/customise.json b/public/language/he/admin/appearance/customise.json index f138c80090..fc2c805f5f 100644 --- a/public/language/he/admin/appearance/customise.json +++ b/public/language/he/admin/appearance/customise.json @@ -15,6 +15,6 @@ "custom-css.livereload": "הפעלת טעינה מחדש אוטומטית.", "custom-css.livereload.description": "הפעלה זו נועדה כדי לרענן את כל החיבורים מכל מכשיר, כאשר תשמרו את הדף המותאם אישית.", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
Changes require a rebuild & restart.", + "bsvariables.description": "ניתן לעקוף משתני Bootstrap כאן. אתה יכול גם להשתמש בכלי כמו bootstrap.build ולהדביק את הפלט כאן.
שינויים דורשים בנייה מחדש והפעלה מחדש.", "bsvariables.enable": "Enable _variables.scss" } \ No newline at end of file diff --git a/public/language/he/admin/dashboard.json b/public/language/he/admin/dashboard.json index 50e58da897..472c01a389 100644 --- a/public/language/he/admin/dashboard.json +++ b/public/language/he/admin/dashboard.json @@ -26,8 +26,8 @@ "updates": "עדכונים", "running-version": "הפורום מעודכן לגרסה %1", "keep-updated": "לעדכוני אבטחה מעודכנים ותיקוני באגים, וודא שהפורום שלך עדכני לגרסה האחרונה.", - "up-to-date": " אתה מעודכן", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", + "up-to-date": "אתה מעודכן ", + "upgrade-available": "גרסה חדשה (v%1) שוחררה. שקול לעדכן את הפורום שלך.", "prerelease-upgrade-available": "זוהי גרסת טרום-הפצה מיושנת של NodeBB. גרסה חדשה (v%1) שוחררה. שקול לשדרג את ה-NodeBB שלך.", "prerelease-warning": " זוהי גרסת טרום-הפצה של NodeBB. עלולים להתרחש באגים לא מכוונים.", "fallback-emailer-not-found": "Fallback emailer לא נמצא!", @@ -35,19 +35,20 @@ "latest-lookup-failed": "לא הצליח לחפש את הגרסה האחרונה הזמינה של NodeBB", "notices": "התראות", - "restart-not-required": "לא נדרש אתחול מחדש", - "restart-required": "נדרש אתחול מחדש", + "restart-not-required": "לא נדרשת הפעלה מחדש", + "restart-required": "נדרשת הפעלה מחדש", "search-plugin-installed": "תוסף חיפוש הותקן", "search-plugin-not-installed": "תוסף חיפוש לא הותקן", "search-plugin-tooltip": "התקן את תוסף החיפוש מעמוד התוספים על מנת להפעיל את אפשרות החיפוש", "control-panel": "שליטת מערכת", "rebuild-and-restart": "בנייה והפעלה מחדש", - "restart": "הפעל מחדש", + "restart": "הפעלה מחדש", "restart-warning": "הפעלה או בניה מחדש של הפורום תנתק את כל החיבורים הקיימים למספר שניות", "restart-disabled": "הפעלה או בניה מחדש של הפורום בוטלה, נראה שאינך מפעיל את הפורום דרך שרת מתאים.", "maintenance-mode": "מצב תחזוקה", "maintenance-mode-title": "לחץ כאן על מנת להכניס את הפורום למצב תחזוקה", + "dark-mode": "Dark Mode", "realtime-chart-updates": "עדכן תרשים בזמן אמת", "active-users": "משתמשים פעילים", @@ -89,5 +90,9 @@ "details.logins-login-time": "זמן כניסה", "start": "התחלה", "end": "סיום", - "filter": "סינון" + "filter": "סינון", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/he/admin/development/logger.json b/public/language/he/admin/development/logger.json index 5e360652e3..a9b481dc70 100644 --- a/public/language/he/admin/development/logger.json +++ b/public/language/he/admin/development/logger.json @@ -1,13 +1,13 @@ { "logger": "Logger", - "logger-settings": "הגדרות מנהל הרישום", + "logger-settings": "הגדרות לוגים", "description": "על-ידי הפיכת תיבות הסימון לזמינות, תקבל יומני רישום למסוף שלך. אם תציין נתיב, יומני הרישום יישמרו בקובץ במקום זאת. רישום HTTP שימושי לאיסוף נתונים סטטיסטיים אודות מי ומתי אנשים נכנסים לפורום שלך. בנוסף לרישום בקשות ה-HTTP, אנו יכולים גם לרשום אירועי Socket.io, אשר בשילוב עם מודד redis-cli, יכול להיות מאוד מועיל ללימוד הפנימיים של NodeBB.", "explanation": "הפעל או ​בטל את סימון הגדרות הרישום כדי לאפשר או להשבית כניסה במהירות. אין צורך בהפעלה מחדש.", "enable-http": "הפעל רישום HTTP", "enable-socket": "הפעל רישום אירועים ב-socket.io", - "file-path": "נתיב קובץ יומן רישום", + "file-path": "נתיב קובץ לוג", "file-path-placeholder": "/path/to/log/file.log ::: השאר ריק כדי להיכנס לטרמינל שלך", - "control-panel": "לוח בקרת מנהל רישום", - "update-settings": "עדכן הגדרות מנהל רישום" + "control-panel": "ניהול לוגים", + "update-settings": "עדכן הגדרות לוגים" } \ No newline at end of file diff --git a/public/language/he/admin/extend/plugins.json b/public/language/he/admin/extend/plugins.json index 31ef5d4573..65cf7e280f 100644 --- a/public/language/he/admin/extend/plugins.json +++ b/public/language/he/admin/extend/plugins.json @@ -11,7 +11,7 @@ "plugin-search": "חיפוש תוספים", "plugin-search-placeholder": "חפש תוספים...", - "submit-anonymous-usage": "שלח נתוני שימוש אנונימיים בתוסף.", + "submit-anonymous-usage": "שלח נתוני שימוש אנונימיים בתוספים.", "reorder-plugins": "סדר מחדש תוספים", "order-active": "סדר תוספים פעילים", "dev-interested": "מתעניין בכתיבת תוספים ל-NodeBB?", diff --git a/public/language/he/admin/extend/widgets.json b/public/language/he/admin/extend/widgets.json index 6ece7f45ff..949e80ad0c 100644 --- a/public/language/he/admin/extend/widgets.json +++ b/public/language/he/admin/extend/widgets.json @@ -1,11 +1,11 @@ { "widgets": "ווידג'טים", - "available": "וידג'טים זמינים", - "explanation": "בחר וידג'ט מהתפריט הנפתח ואז גרור ושחרר אותו באזור הווידג'ט של התבנית משמאל.", - "none-installed": "לא נמצאו וידג'טים! הפעל את תוספי הוידג'טים ב תוספים בלוח הבקרה.", - "clone-from": "וידג'טים משוכפלים מ", + "available": "ווידג'טים זמינים", + "explanation": "בחר ווידג'ט מהתפריט הנפתח ואז גרור ושחרר אותו באזור הווידג'ט של התבנית משמאל.", + "none-installed": "לא נמצאו ווידג'טים! הפעל את תוספי הווידג'טים ב תוספים בלוח הבקרה.", + "clone-from": "שיבוט ווידג'טים מ", "containers.available": "גורמים מכילים זמינים", - "containers.explanation": "גרור ושחרר מעל כל וידג'ט פעיל", + "containers.explanation": "גרור ושחרר מעל כל ווידג'ט פעיל", "containers.none": "None", "container.well": "Well", "container.jumbotron": "Jumbotron", @@ -14,10 +14,10 @@ "container.card-body": "גוף כרטיס", "container.alert": "התראה", - "alert.confirm-delete": "האם אתה בטוח שאתה רוצה למחוק את הוידג'ט?", - "alert.updated": "העלאת וידג'טים", - "alert.update-success": "הוידג'טים הועלו בהצלחה", - "alert.clone-success": "הוידג'טים שוכפלו בהצלחה", + "alert.confirm-delete": "האם אתה בטוח שאתה רוצה למחוק את הווידג'ט?", + "alert.updated": "העלאת ווידג'טים", + "alert.update-success": "הווידג'טים הועלו בהצלחה", + "alert.clone-success": "הווידג'טים שוכפלו בהצלחה", "error.select-clone": "בחר דף לשכפל ממנו", diff --git a/public/language/he/admin/manage/admins-mods.json b/public/language/he/admin/manage/admins-mods.json index 5fb5065795..f089efd748 100644 --- a/public/language/he/admin/manage/admins-mods.json +++ b/public/language/he/admin/manage/admins-mods.json @@ -1,11 +1,11 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "ניהול מנהלים & מנחים", "administrators": "מנהלים", "global-moderators": "מנחים גלובליים", "moderators": "מנחים", "no-global-moderators": "אין מנחים גלובליים", "no-sub-categories": "אין תתי קטגוריות", - "view-children": "View children (%1)", + "view-children": "הצג ילדים (%1)", "no-moderators": "אין מנחים", "add-administrator": "הוסף מנהל", "add-global-moderator": "הוסף מנחה גלובלי", diff --git a/public/language/he/admin/manage/categories.json b/public/language/he/admin/manage/categories.json index d96db4e2ba..8018e022b1 100644 --- a/public/language/he/admin/manage/categories.json +++ b/public/language/he/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "רשימה לבנה של תגיות", "upload-image": "העלה תמונה", "upload": "העלאה", - "select-icon": "בחר סמל", "delete-image": "הסרה", "category-image": "תמונת קטגוריה", "image-and-icon": "תמונה וסמל", diff --git a/public/language/he/admin/manage/privileges.json b/public/language/he/admin/manage/privileges.json index 3d5104b204..3ec92f2515 100644 --- a/public/language/he/admin/manage/privileges.json +++ b/public/language/he/admin/manage/privileges.json @@ -38,7 +38,7 @@ "downvote-posts": "הצבעה נגד פוסטים", "delete-topics": "מחיקת נושא", "purge": "מחיקה לצמיתות", - "moderate": "Moderate", + "moderate": "הרשאות מנחה", "admin-dashboard": "לוח מחוונים", "admin-categories": "קטגוריות", "admin-privileges": "הרשאות", diff --git a/public/language/he/admin/manage/users.json b/public/language/he/admin/manage/users.json index 0e35cfa297..847a9b871b 100644 --- a/public/language/he/admin/manage/users.json +++ b/public/language/he/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "מחק משתמש(ים) ותוכן", "download-csv": "ייצא משתמשים כ-CSV", "manage-groups": "נהל קבוצות", + "set-reputation": "הגדר מוניטין", "add-group": "הוסף קבוצה", "create": "צור משתמש", "invite": "הזמנה באמצעות דוא\"ל", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index a0ec4cfc00..affb02c2e8 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -12,8 +12,9 @@ "manage/privileges": "הרשאות", "manage/tags": "תגיות", "manage/users": "משתמשים", - "manage/admins-mods": "מנהלים ומנהלים כלליים", + "manage/admins-mods": "מנחים ומנהלים", "manage/registration": "תור הרשמה", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "תור פוסטים", "manage/groups": "קבוצות", "manage/ip-blacklist": "רשימה שחורה של כתובות IP", @@ -53,7 +54,7 @@ "section-extend": "הרחבות", "extend/plugins": "תוספים", - "extend/widgets": "וידג'טים", + "extend/widgets": "ווידג'טים", "extend/rewards": "תגמולים", "section-social-auth": "אימות חיצוני", @@ -63,22 +64,22 @@ "section-advanced": "מתקדם", "advanced/database": "מסד נתונים", - "advanced/events": "ארועים", + "advanced/events": "אירועים", "advanced/hooks": "Hooks", - "advanced/logs": "רישומים", + "advanced/logs": "לוג", "advanced/errors": "שגיאות", "advanced/cache": "עוגיות", - "development/logger": "מנהל הרישומים", + "development/logger": "ניהול לוג", "development/info": "מידע", "rebuild-and-restart-forum": "בנה והפעל מחדש את הפורום", "rebuild-and-restart": "בניה מחדש והפעלה מחדש", "restart-forum": "הפעל מחדש את הפורום", - "restart": "הפעל מחדש", - "logout": "התנתק", + "restart": "הפעלה מחדש", + "logout": "התנתקות", "view-forum": "כניסה לפורום", - "search.placeholder": "הגדרות חיפוש", + "search.placeholder": "חיפוש הגדרות", "search.no-results": "אין תוצאות...", "search.search-forum": "חפש בפורום ", "search.keep-typing": "המשך להקליד על מנת למצוא תוצאות...", diff --git a/public/language/he/admin/settings/advanced.json b/public/language/he/admin/settings/advanced.json index b271d22ecd..bf7d161cbb 100644 --- a/public/language/he/admin/settings/advanced.json +++ b/public/language/he/admin/settings/advanced.json @@ -32,7 +32,7 @@ "traffic.help": "NodeBB משתמש במודול שדוחה אוטומטית בקשות במצבים עם תעבורה גבוהה. אתה יכול לכוונן את ההגדרות האלה כאן, למרות שברירות המחדל הן נקודת התחלה טובה.", "traffic.enable": "הפעל ניהול תעבורה", "traffic.event-lag": "סף השהיית לולאת אירוע (במילישניות)", - "traffic.event-lag-help": "הורדת ערך זה מקטינה את זמני ההמתנה לטעינת הדפים, אך גם תציג את ההודעה \"עומס מופרז\" ליותר משתמשים. (אתחול נדרש)", + "traffic.event-lag-help": "הורדת ערך זה מקטינה את זמני ההמתנה לטעינת הדפים, אך גם תציג את ההודעה \"עומס מופרז\" ליותר משתמשים. (הפעלה מחדש נדרשת)", "traffic.lag-check-interval": "מרווח זמן בין בדיקות (במילישניות)", "traffic.lag-check-interval-help": "הורדת ערך זה גורמת ל-NodeBB להיות רגיש יותר לקוצים בעומס, אך עלולה גם לגרום לסימון להיות רגיש מדי. (הפעלה מחדש נדרשת)", diff --git a/public/language/he/admin/settings/api.json b/public/language/he/admin/settings/api.json index 3ae1efca00..57d0010b67 100644 --- a/public/language/he/admin/settings/api.json +++ b/public/language/he/admin/settings/api.json @@ -3,7 +3,7 @@ "settings": "הגדרות", "lead-text": "מעמוד זה תוכלו להגדיר גישת כתיבה ל-API ב- NodeBB.", "intro": "כברירת מחדל, ה- API של כתיבה מאמת משתמשים בהתבסס על קובץ ה-cookie של ההפעלה שלהם, אך NodeBB תומך גם באימות נושא באמצעות טוקנים (אישורי אבטחה) שנוצרו באמצעות דף זה.", - "warning": "שים לב — יש להתייחס לאסימונים כמו אל סיסמאות. אם הם דולפים, יש לראות בחשבונך כנפרץ. ", + "warning": "שים לב — יש להתייחס לאסימונים כמו אל סיסמאות. אם הם דולפים, יש לראות את חשבונך כנפרץ. ", "docs": "לחץ כאן כדי לגשת למפרט ה- API המלא", "require-https": "אפשר שימוש בAPI באמצעות HTTPS בלבד", diff --git a/public/language/he/admin/settings/chat.json b/public/language/he/admin/settings/chat.json index 389ff33dca..c7a3bdf478 100644 --- a/public/language/he/admin/settings/chat.json +++ b/public/language/he/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "השבת עריכה/מחיקה של הודעות צ'אט", "disable-editing-help": "מנהלי מערכת ומנחים גלובליים פטורים מהגבלה זו", "max-length": "אורך מקסימלי של הודעת צ'אט", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "מספר המשתמשים המרבי בחדרי צ'אט", "delay": "זמן המתנה בין הודעות צ'אט - באלפיות שניה", "notification-delay": "עיכוב התראות להודעות צ'אט. (0 ללא עיכוב)", diff --git a/public/language/he/admin/settings/email.json b/public/language/he/admin/settings/email.json index 30cd68a746..0495768930 100644 --- a/public/language/he/admin/settings/email.json +++ b/public/language/he/admin/settings/email.json @@ -1,7 +1,7 @@ { "email-settings": "הגדרות דוא\"ל", "address": "כתובת דוא\"ל", - "address-help": "The following email address refers to the email that the recipient will see in the \"From\" and \"Reply To\" fields.", + "address-help": "שדה אימייל זה מתייחס לכתובת שהנמען יראה בשדות \"מאת\" ו\"השב אל\".", "from": "מאת", "from-help": "השם 'מאת' יוצג בדוא\"ל.", @@ -39,7 +39,7 @@ "subscriptions": "תקצירי דואר אלקטרוני", "subscriptions.disable": "הפיכת תקצירי דואר אלקטרוני ללא זמינים", "subscriptions.hour": "שעת תקציר", - "subscriptions.hour-help": "Please enter a number representing the hour to send scheduled email digests (e.g. 0 for midnight, 17 for 5:00pm). Keep in mind that this is the hour according to the server itself, and may not exactly match your system clock.
The approximate server time is:
The next daily digest is scheduled to be sent ", + "subscriptions.hour-help": "אנא הזן מספר המייצג את השעה לשליחת תקצירי אימייל מתוזמנים (למשל 0 לחצות,17 לשעה 17:00). זכור שזו השעה בהתאם לשרת עצמו, וייתכן שלא בדיוק תואם את שעון המערכת שלך.
זמן השרת המשוער הוא:
התקציר היומי הבא מתוכנן להישלח", "notifications.remove-images": "הסר תמונות מהודעות דוא\"ל", "require-email-address": "דרוש ממשתמשים חדשים כתובת אימייל", "require-email-address-warning": "כברירת מחדל, משתמשים יכולים לבטל את הסכמתם להזנת כתובת דוא\"ל על ידי השארת השדה ריק. הפעלת אפשרות זו פירושה שמשתמשים חדשים יצטרכו להזין ולאשר כתובת דואר אלקטרוני על מנת להמשיך ברישום ובגישה לאחר מכן לפורום. זה לא מבטיח שהמשתמש יזין כתובת אימייל אמיתית, ואפילו לא כתובת שבבעלותו.", diff --git a/public/language/he/admin/settings/guest.json b/public/language/he/admin/settings/guest.json index 539d292411..fbdf6f275e 100644 --- a/public/language/he/admin/settings/guest.json +++ b/public/language/he/admin/settings/guest.json @@ -2,7 +2,7 @@ "settings": "הגדרות", "guest-settings": "הגדרות אורחים", "handles.enabled": "אפשר נקודות אחיזה לאורחים", - "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם הם מושבתים, הם פשוט יקראו \"אורח\"", + "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם מושבת, הם פשוט יקראו \"אורח\"", "topic-views.enabled": "הגדל מספר צפיות בנושא על-ידי צפיות של אורחים", "reply-notifications.enabled": "אפשר לאורחים ליצור הודעות תשובה" } \ No newline at end of file diff --git a/public/language/he/admin/settings/reputation.json b/public/language/he/admin/settings/reputation.json index 85cf78a260..db9974f451 100644 --- a/public/language/he/admin/settings/reputation.json +++ b/public/language/he/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "בצע את הפעולות הבאות כאשר דיווח נפתר", "flags.action-on-reject": "בצע את הפעולות הבאות כאשר דיווח נדחה", "flags.action.nothing": "אל תעשה כלום", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "בטל את ההודעה שנשלחה למנחים/מנהלי מערכת" } \ No newline at end of file diff --git a/public/language/he/admin/settings/tags.json b/public/language/he/admin/settings/tags.json index be2a1788e7..e533d85ba5 100644 --- a/public/language/he/admin/settings/tags.json +++ b/public/language/he/admin/settings/tags.json @@ -2,7 +2,7 @@ "tag": "הגדרות תגיות", "link-to-manage": "נהל תגיות", "system-tags": "תגיות מערכת", - "system-tags-help": "רק מנהלים יכולים להשתמש בתגית זו", + "system-tags-help": "רק מנהלים יוכלו להשתמש בתגיות אלו", "tags-per-topic": "תגים פר נושא", "min-per-topic": "מינימום תגיות לנושא", "max-per-topic": "מקסימום תגיות לנושא", diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index 3f3942e2b1..419f1ebbe8 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -16,7 +16,7 @@ "hide-email": "החבא כתובת מייל ממשתמשים", "show-fullname-as-displayname": "הצג את השם המלא של המשתמש כשם התצוגה שלו אם הוא זמין", "themes": "ערכות נושא", - "disable-user-skins": "אל תאפשר למשתמשים לבחור ערכת נושא", + "disable-user-skins": "אל תאפשר למשתמשים לבחור עיצוב", "account-protection": "הגנת חשבון", "admin-relogin-duration": "משך חיבור של מנהל מערכת (דקות)", "admin-relogin-duration-help": "לאחר פרק זמן מוגדר של גישה למקטע הניהול ידרוש כניסה מחדש, הגדר ל- 0 על-מנת להפוך ללא זמין", diff --git a/public/language/he/email.json b/public/language/he/email.json index ef5916f6db..9ac51b3bbd 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "הסיסמה שונתה בהצלחה.", "reset.notify.text1": "אנו מודיעים לך שב%1, סיסמתך שונתה בהצלחה.", "reset.notify.text2": "אם לא אישרת בקשה זו, אנא הודע למנהל מיד.", + "digest.unread-rooms": "חדרים שלא נקראו", + "digest.room-name-unreadcount": "%1 (%2 לא נקראו)", "digest.latest_topics": "נושאים אחרונים מ%1", "digest.top-topics": "נושאים עם הכי הרבה הצבעות מ-%1", "digest.popular-topics": "הנושאים הכי פופולריים מ-%1", diff --git a/public/language/he/error.json b/public/language/he/error.json index 43ae9ccccc..c959a0e711 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "מצטערים, חשבון זה הורחק עד %1 (סיבה: %2)", "user-too-new": "אנא המתינו %1 שניות לפני פרסום ההודעה", "blacklisted-ip": "מצטערים, אך הורחקתם מקהילה זו. אם הנכם סבורים שמדובר בטעות, אנא צרו קשר עם מנהלי הקהילה.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "אנא ספקו תאריך סיום להרחקה זו.", "no-category": "קטגוריה אינה קיימת", "no-topic": "נושא אינו קיים", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "חדר צ'אט אינו קיים.", "cant-add-users-to-chat-room": "לא ניתן להוסיף משתמשים לחדר הצ'אט.", "cant-remove-users-from-chat-room": "לא ניתן להסיר משתמשים מחדר הצ'אט.", - "chat-room-name-too-long": "שם חדר הצ'אט ארוך מדי.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "הצבעתם כבר בנושא זה.", "reputation-system-disabled": "מערכת המוניטין לא פעילה.", "downvoting-disabled": "היכולת להצביע נגד מושבתת", @@ -199,6 +200,7 @@ "not-in-room": "משתמש זה אינו בחדר הצ'אט", "cant-kick-self": "אינכם יכולים להסיר את עצמכם מהקבוצה", "no-users-selected": "לא נבחרו משתמשים", + "no-groups-selected": "לא נבחרו קבוצות", "invalid-home-page-route": "כתובת דף הבית שגויה", "invalid-session": "סשן לא תקין", "invalid-session-text": "נראה שסשן ההתחברות שלכם אינה פעילה יותר. אנא רעננו את הדף.", diff --git a/public/language/he/global.json b/public/language/he/global.json index afbd346e7b..4e0395b1dc 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -51,6 +51,8 @@ "nextpage": "העמוד הבא", "alert.success": "הצלחה", "alert.error": "שגיאה", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "מורחק", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 181be76630..1968510ea0 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "אין לכם צ'אטים פעילים.", "chat.user_typing": "%1 מקליד...", "chat.user_has_messaged_you": "ל%1 יש הודעה עבורכם.", + "chat.replying-to": "Replying to %1", "chat.see_all": "צפו בכל הצ'אטים", "chat.mark_all_read": "סמנו את כל הצ'אטים כ'נקראו'", "chat.no-messages": "בחרו משתמש על מנת לראות את שיחות הצ'אט ביניכם", @@ -27,22 +28,43 @@ "chat.three_months": "3 חודשים", "chat.delete_message_confirm": "האם למחוק הודעה זו?", "chat.retrieving-users": "מאחזר משתמשים...", + "chat.view-users-list": "הצג רשימת משתמשים", + "chat.public-rooms": "חדרים ציבוריים (%1)", + "chat.private-rooms": "חדרים פרטיים (%1)", + "chat.create-room": "צור חדר צ'אט", + "chat.private.option": "פרטי (גלוי רק למשתמשים שנוספו לחדר)", + "chat.public.option": "ציבורי (גלוי לכל משתמש בקבוצות שנבחרו)", + "chat.public.groups-help": "כדי ליצור חדר צ'אט הגלוי לכל המשתמשים בחר \"משתמשים רשומים\" מרשימת הקבוצות.", "chat.manage-room": "ניהול חדר צ'אט", + "chat.add-user": "הוסף משתמש", + "chat.notification-settings": "הגדרות התראות", + "chat.default-notification-setting": "הגדרת ברירת מחדל להתראות", + "chat.notification-setting-room-default": "ברירת המחדל של החדר", + "chat.notification-setting-none": "ללא התראות", + "chat.notification-setting-at-mention-only": "@אזכור בלבד", + "chat.notification-setting-all-messages": "כל ההודעות", + "chat.select-groups": "בחר קבוצות", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", + "chat.room-name-optional": "שם חדר (אופציונלי)", "chat.rename-room": "שינוי שם חדר", "chat.rename-placeholder": "הזינו את שם החדר שלכם כאן", "chat.rename-help": "שם החדר המוגדר כאן יהיה זמין לכל המשתתפים בחדר.", - "chat.leave": "עזיבת שיחה", + "chat.leave": "Leave", + "chat.leave-room": "עזוב חדר", "chat.leave-prompt": "האם לעזוב שיחה זו?", "chat.leave-help": "עזיבת שיחה, תסיר אתכם מהתכתבות עתידית בצ'אט זה. אם תצטרפו מחדש בעתיד, לא תראו את היסטוריית הצ'אט שלפני הצטרפותכם מחדש.", + "chat.delete": "מחיקה", + "chat.delete-room": "מחק חדר", + "chat.delete-prompt": "האם אתה בטוח שברצונך למחוק את חדר הצ'אט הזה?", "chat.in-room": "בתוך חדר זה", "chat.kick": "הוצא", "chat.show-ip": "הצג IP", "chat.owner": "מנהלי החדר", - "chat.system.user-join": "%1 הצטרף לחדר", - "chat.system.user-leave": "%1 יצא מהחדר", - "chat.system.room-rename": "%2 שינה את שם החדר: %1", + "chat.grant-rescind-ownership": "הענק/בטל בעלות", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "יצירה", "composer.show_preview": "הצגת תצוגה מקדימה", "composer.hide_preview": "הסתרת תצוגה מקדימה", diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index 2bcca7dd35..5b60088902 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -71,6 +71,6 @@ "notificationType_group-request-membership": "כשמישהו מבקש להירשם לקבוצה שאתה מנהל", "notificationType_new-register": "כאשר מישהו מתווסף לתור הרישום", "notificationType_post-queue": "כאשר פוסט חדש נכנס לתור", - "notificationType_new-post-flag": "כאשר פוסט מסומן", - "notificationType_new-user-flag": "כאשר משתמש מסומן" + "notificationType_new-post-flag": "כאשר פוסט מדווח", + "notificationType_new-user-flag": "כאשר מדווחים על משתמש" } \ No newline at end of file diff --git a/public/language/he/themes/harmony.json b/public/language/he/themes/harmony.json index 87f56a8343..2f460ac2c7 100644 --- a/public/language/he/themes/harmony.json +++ b/public/language/he/themes/harmony.json @@ -7,8 +7,8 @@ "settings.title": "הגדרות ערכת נושא", "settings.enableQuickReply": "הפעלת תגובה מהירה", "settings.centerHeaderElements": "מרכוז אלמנטים של כותרת", - "settings.mobileTopicTeasers": "הצגת טיזרים של נושאים בסלולרי", - "settings.stickyToolbar": "סרגל כלים מוצמד בעת גלילה", + "settings.mobileTopicTeasers": "הצגת טיזרים של נושאים בנייד", + "settings.stickyToolbar": "הצמד את סרגל הכלים בעת גלילה", "settings.stickyToolbar.help": "סרגל הכלים בדפי נושאים וקטגוריות ייצמד לראש העמוד בעת גלילה", "settings.autohideBottombar": "הסתרה אוטומטית של סרגל תחתון", "settings.autohideBottombar.help": "הסרגל התחתון בתצוגת הנייד יוסתר כאשר הדף ייגלל מטה", diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 5bd26e66db..9efe2423e4 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "כתב ", "wrote-on": "כתב ב", "replied-to-user-ago": "השיב ל%3 ", - "replied-to-user-on": "השיב ל%3 ב", + "replied-to-user-on": "השיב ל%3 ב ", "user-locked-topic-ago": "%1 נעל נושא זה %2", "user-locked-topic-on": "%1 נעל נושא זה ב-%2", "user-unlocked-topic-ago": "%1 ביטל את נעילת נושא זה %2", diff --git a/public/language/hr/admin/admin.json b/public/language/hr/admin/admin.json index 1d7b7d1524..4de39987a2 100644 --- a/public/language/hr/admin/admin.json +++ b/public/language/hr/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hr/admin/dashboard.json b/public/language/hr/admin/dashboard.json index 6fa439de2c..ad7919906e 100644 --- a/public/language/hr/admin/dashboard.json +++ b/public/language/hr/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Održavanje", "maintenance-mode-title": "Postavite mod za održavanje foruma", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Ažuriranja u stvarnom vremenu", "active-users": "Aktivni korisnici", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hr/admin/manage/categories.json b/public/language/hr/admin/manage/categories.json index 3f425ed857..15147d3389 100644 --- a/public/language/hr/admin/manage/categories.json +++ b/public/language/hr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Učitaj sliku", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Ukloni", "category-image": "Slika kategorije", "image-and-icon": "Image & Icon", diff --git a/public/language/hr/admin/manage/users.json b/public/language/hr/admin/manage/users.json index 89aa4b8c0e..93f1e680df 100644 --- a/public/language/hr/admin/manage/users.json +++ b/public/language/hr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Preuzmi CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/hr/admin/menu.json b/public/language/hr/admin/menu.json index d8f0bb0b8c..bb2dd87d03 100644 --- a/public/language/hr/admin/menu.json +++ b/public/language/hr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Korisnici", "manage/admins-mods": "Admins & Mods", "manage/registration": "Lista zahtjeva za registraciju", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupe", "manage/ip-blacklist": "IP blokade", diff --git a/public/language/hr/admin/settings/chat.json b/public/language/hr/admin/settings/chat.json index 92c8248d74..225b829618 100644 --- a/public/language/hr/admin/settings/chat.json +++ b/public/language/hr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Onemogući uređivanje/brisanje poruka razgovora", "disable-editing-help": "Administratori i moderatori su izuzeti od ovih restrikcija", "max-length": "Maksimalna dužina poruka u razgovoru", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksimalan broj korisnika u sobama za razgovor", "delay": "Vrijeme između poruka razgovora u milisekundama", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/hr/admin/settings/guest.json b/public/language/hr/admin/settings/guest.json index 7bfe85ba29..35efe569eb 100644 --- a/public/language/hr/admin/settings/guest.json +++ b/public/language/hr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Dozvoli upravljanje gostima", "handles.enabled-help": "Ova opcija omogućava gostima da izaberi ime za svaku objavu koju naprave.Ako je onemogućena gosti će se zvati \"gost\".", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/hr/email.json b/public/language/hr/email.json index 3367f4ef06..f2bbfc0ab2 100644 --- a/public/language/hr/email.json +++ b/public/language/hr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Lozinka uspješno promijenjena.", "reset.notify.text1": "Obavještavamo vas da vam je lozinka na %1 uspješno promijenjena.", "reset.notify.text2": "Ako niste ovo odobrili, molimo vas obavijestite administratora.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Posljednje teme s %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/hr/error.json b/public/language/hr/error.json index 3e8466c908..77ca94bc2f 100644 --- a/public/language/hr/error.json +++ b/public/language/hr/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Ovaj račun je blokiran do %1 (Razlog: %2)", "user-too-new": "Pričekajte %1 sekundi prije prve objave", "blacklisted-ip": "Vaša IP adresa je blokirana. Ako mislite da je ovo greška, kontaktirajte administratora.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Postavite datum isteka blokade", "no-category": "Kategorija ne postoji", "no-topic": "Tema ne postoji", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Već ste glasali za ovu objavu", "reputation-system-disabled": "Sistem reputacije onemogućen.", "downvoting-disabled": "Oduzimanje glasova je onemogućeno", @@ -199,6 +200,7 @@ "not-in-room": "Korisnik nije u sobi", "cant-kick-self": "Ne možete sebe izbaciti iz grupe", "no-users-selected": "Korisnici nisu odabrani", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Netočna putanja naslovnice", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/hr/global.json b/public/language/hr/global.json index 2554d40335..a07f41cb0f 100644 --- a/public/language/hr/global.json +++ b/public/language/hr/global.json @@ -51,6 +51,8 @@ "nextpage": "Sljedeća stranica", "alert.success": "Uspjeh!", "alert.error": "Greška", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Blokiran", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index 2e1446011b..0009842c19 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemate aktivnih razgovora.", "chat.user_typing": "%1 piše poruku ...", "chat.user_has_messaged_you": "%1 vam je poslao poruku.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Odaberite primatelja da vidite povijest razgovora", @@ -27,22 +28,43 @@ "chat.three_months": "3 Mjeseca", "chat.delete_message_confirm": "Sigurni ste da želite izbrisati ovu poruku?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "Korisnik ne želi biti ometan. Jeste li sigurno da mu želite poslati poruku?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sastavi", "composer.show_preview": "Prikaz", "composer.hide_preview": "Sakrij prikaz", diff --git a/public/language/hr/topic.json b/public/language/hr/topic.json index 3bbaf047e7..7c21cd9d3f 100644 --- a/public/language/hr/topic.json +++ b/public/language/hr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/hu/admin/admin.json b/public/language/hu/admin/admin.json index 3cf53e2572..8248580557 100644 --- a/public/language/hu/admin/admin.json +++ b/public/language/hu/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hu/admin/dashboard.json b/public/language/hu/admin/dashboard.json index eeb05d3480..3dd5958b6e 100644 --- a/public/language/hu/admin/dashboard.json +++ b/public/language/hu/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "A NodeBB újraépítése és újraindítása letiltásra került, mivel úgy néz ki nem a megfelelő daemon-al futtatod.", "maintenance-mode": "Karbantartási mód", "maintenance-mode-title": "Kattints ide a NodeBB karbantartási módjának beállításához", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Valós idejű grafikon frissítések ", "active-users": "Aktív felhasználók", @@ -89,5 +90,9 @@ "details.logins-login-time": "Bejelentkezés ideje", "start": "Kezdés", "end": "Vége", - "filter": "Szűrő" + "filter": "Szűrő", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hu/admin/manage/categories.json b/public/language/hu/admin/manage/categories.json index 7cec893e3f..daa6007ca8 100644 --- a/public/language/hu/admin/manage/categories.json +++ b/public/language/hu/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Engedélyezett címkék", "upload-image": "Kép feltöltése", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Kép törlése", "category-image": "Kategóriakép", "image-and-icon": "Image & Icon", diff --git a/public/language/hu/admin/manage/users.json b/public/language/hu/admin/manage/users.json index 329d56b8d9..a36403740f 100644 --- a/public/language/hu/admin/manage/users.json +++ b/public/language/hu/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Felhasználó(k) és minden tartalmának törlése", "download-csv": "CSV letöltése", "manage-groups": "Csoportok kezelése", + "set-reputation": "Set Reputation", "add-group": "Csoport létrehozása", "create": "Felhasználó létrehozása", "invite": "Invite by Email", diff --git a/public/language/hu/admin/menu.json b/public/language/hu/admin/menu.json index 2c6f0fd6b0..4c73bf711d 100644 --- a/public/language/hu/admin/menu.json +++ b/public/language/hu/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Felhasználók", "manage/admins-mods": "Adminok & Moderátorok", "manage/registration": "Regisztrációs várólista", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Hozzászólási várólista", "manage/groups": "Csoportok", "manage/ip-blacklist": "IP tiltólista", diff --git a/public/language/hu/admin/settings/chat.json b/public/language/hu/admin/settings/chat.json index 7565f0dd5a..445944237c 100644 --- a/public/language/hu/admin/settings/chat.json +++ b/public/language/hu/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Csevegési üzenetek szerkesztésének/törlésének letiltása", "disable-editing-help": "Az adminisztrátorok és globális moderátorok kivételnek számítanak ezen korlátozás alól", "max-length": "Csevegési üzenetek maximális hossza", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "A csevegési szobákban lévő felhasználók maximális száma", "delay": "Csevegési üzenetek közötti idő ezredmásodpercben", "notification-delay": "Értesítési késleltetés csevegési üzenetekhez. (0: nincs késleltetés)", diff --git a/public/language/hu/admin/settings/guest.json b/public/language/hu/admin/settings/guest.json index 9a65d80c92..8205281f5b 100644 --- a/public/language/hu/admin/settings/guest.json +++ b/public/language/hu/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Beállítások", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Vendég név beállítás engedélyezése", "handles.enabled-help": "Ez a beállítás engedélyez egy új mezőt, amivel a vendégek minden hozzászólásnál választhatnak egy nevet ami megjelenik ott. Ha nincs engedélyezve, egyszerűen \"Vendég\"-ként jelennek meg.", "topic-views.enabled": "Témakör látogatások számának növelésének engedélyezése vendégek számára", diff --git a/public/language/hu/email.json b/public/language/hu/email.json index c2594b9d37..19ff665c48 100644 --- a/public/language/hu/email.json +++ b/public/language/hu/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Jelszó sikeresen módosítva", "reset.notify.text1": "Értesítünk, hogy a(z) %1 névhez tartozó jelszavad sikeresen megváltozott.", "reset.notify.text2": "Ha nem te voltál az, kérlek, azonnal értesíts egy adminisztrátort.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Legutóbbi témakörök a következőből: %1", "digest.top-topics": "Legfontosabb témakörök innen: %1", "digest.popular-topics": "Népszerű témakörök innen: %1", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index daa6e50508..c0c0fe9794 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Ez a fiók ki lett tiltva %1 -ig (Indoklás: %2)", "user-too-new": "Várnod kell %1 másodpercet mielőtt létre tudod hozni az első hozzászólásod.", "blacklisted-ip": "Az IP címed ki van tiltva ebből a közösségből. Ha úgy érzed, hogy ez valami hiba akkor lépj kapcsolatba egy adminisztrátorral.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Kérlek adj meg lejárati dátumot a kitiltáshoz.", "no-category": "Nem létező kategória", "no-topic": "Nem létező téma", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Csevegő szoba nem létezik.", "cant-add-users-to-chat-room": "Nem lehet felhasználókat hozzáadni a csevegőszobához.", "cant-remove-users-from-chat-room": "A felhasználókat nem lehet eltávolítani a csevegőszobából.", - "chat-room-name-too-long": "A csevegőszoba neve túl hosszú.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Már szavaztál erre a hozzászólásra.", "reputation-system-disabled": "Hírnév funkció kikapcsolva.", "downvoting-disabled": "Leszavazás funkció kikapcsolva", @@ -199,6 +200,7 @@ "not-in-room": "A felhasználó nincs a szobában", "cant-kick-self": "Nem rúghatod ki magad a csoportból", "no-users-selected": "Nincs felhasználó kiválasztva", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Érvénytelen főoldal elérési útvonal", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/hu/global.json b/public/language/hu/global.json index 785fff1ae5..adccf9109c 100644 --- a/public/language/hu/global.json +++ b/public/language/hu/global.json @@ -51,6 +51,8 @@ "nextpage": "Következő oldal", "alert.success": "Sikeres", "alert.error": "Hiba", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Kitiltva", "alert.banned.message": "Kitiltottak, ezért most ki leszel léptetve.", "alert.unbanned": "Kitiltás feloldva", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index 2cdfeab55d..8218e1b19d 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nincs aktív csevegésed.", "chat.user_typing": "%1 éppen ír ...", "chat.user_has_messaged_you": "%1 üzenetet küldött.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Összes csevegés", "chat.mark_all_read": "Összes olvasottként jelölése", "chat.no-messages": "Válasszuk ki a címzettet és tekintsük meg a chat előzményeket", @@ -27,22 +28,43 @@ "chat.three_months": "3 hónap", "chat.delete_message_confirm": "Biztos törölni akarod az üzenetet?", "chat.retrieving-users": "Felhasználók lekérése...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Csevegő szoba kezelése", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Itt keress felhasználókat. Kiválasztás után a felhasználó hozzá lesz adva a chathez. Az új felhasználó nem fogja látni az üzenet előzményeket az előttről, hogy hozzá lett adva a beszélgetéshez. Csak a szoba tulajdonosai () távolíthatnak el felhasználókat a beszélgetésből.", "chat.confirm-chat-with-dnd-user": "A felhasználó \"ne zavarj\"-ra állította az állapotukat. Még így is csevegni akarsz velük?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Szoba átnevezése", "chat.rename-placeholder": "Add meg a szoba nevét", "chat.rename-help": "A megadott szoba név az összes szobában tartózkodó által megtekinthező lesz.", - "chat.leave": "Csevegő elhagyása", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Biztosan el akarod hagyni a beszélgetést?", "chat.leave-help": "A szoba elhagyását követően nem fogod látni az oda érkező üzeneteket. Ha újra hozzá leszel adva a szobához akkor nem fogod látni a beszélgetés előzményeit a kilépésed előttről sem.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Ebben a szobában", "chat.kick": "Kirúgás", "chat.show-ip": "IP cím mutatása", "chat.owner": "Szoba tulajdonos", - "chat.system.user-join": "%1 csatlakozott a szobához", - "chat.system.user-leave": "%1 elhagyta a szobát", - "chat.system.room-rename": "%2 megváltoztatta ennek a szobának a nevét: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Üzenetírás", "composer.show_preview": "Előnézet megjelenítése", "composer.hide_preview": "Előnézet elrejtése", diff --git a/public/language/hu/topic.json b/public/language/hu/topic.json index 7f57b58d8c..40e3cdb3ad 100644 --- a/public/language/hu/topic.json +++ b/public/language/hu/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "írta ", "wrote-on": "írta ", "replied-to-user-ago": "válaszolt %3 ", - "replied-to-user-on": "válaszolt %3", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 lezárta ezt a témakört %2", "user-locked-topic-on": "%1 lezárta ezt a témakört %2", "user-unlocked-topic-ago": "%1 feloldotta ezt a témakört %2", diff --git a/public/language/hy/admin/admin.json b/public/language/hy/admin/admin.json index 066b10b627..3f7a51e4c6 100644 --- a/public/language/hy/admin/admin.json +++ b/public/language/hy/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hy/admin/dashboard.json b/public/language/hy/admin/dashboard.json index 441d5af3fc..56895bd3cc 100644 --- a/public/language/hy/admin/dashboard.json +++ b/public/language/hy/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Ձեր NodeBB-ի վերակառուցումն ու վերագործարկումն անջատված է, քանի որ դուք, կարծես, այն չեք աշխատում համապատասխան դեյմոնի միջոցով:", "maintenance-mode": "Սպասարկման ռեժիմ", "maintenance-mode-title": "Սեղմեք այստեղ՝ NodeBB-ի սպասարկման ռեժիմը կարգավորելու համար", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Իրական ժամանակի գծապատկերների թարմացումներ", "active-users": "Ակտիվ Օգտատերեր", @@ -89,5 +90,9 @@ "details.logins-login-time": "Մուտք գործելու ժամանակը", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hy/admin/manage/categories.json b/public/language/hy/admin/manage/categories.json index af1fb7d6a4..bbe31b7116 100644 --- a/public/language/hy/admin/manage/categories.json +++ b/public/language/hy/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Նշեք Whitelist", "upload-image": "Վերբեռնել նկար", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Հեռացնել ", "category-image": "Կատեգորիայի նկար ", "image-and-icon": "Image & Icon", diff --git a/public/language/hy/admin/manage/users.json b/public/language/hy/admin/manage/users.json index 3c68fe3661..207214d588 100644 --- a/public/language/hy/admin/manage/users.json +++ b/public/language/hy/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Ջնջել օգտատերին(ներ) և բովանդակությունը", "download-csv": "Ներբեռնեք CSV", "manage-groups": "Կառավարել Խմբերը", + "set-reputation": "Set Reputation", "add-group": "Ավելացնել խումբ ", "create": "Ստեղծել օգտատեր", "invite": "հրավիրել էլ. փոստով", diff --git a/public/language/hy/admin/menu.json b/public/language/hy/admin/menu.json index e9eb8657d1..1b483105ee 100644 --- a/public/language/hy/admin/menu.json +++ b/public/language/hy/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Օգտատերեր", "manage/admins-mods": "Admins & Mods", "manage/registration": "Գրանցման հերթ", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Գրառման Queue", "manage/groups": "Խմբեր", "manage/ip-blacklist": "IP սև ցուցակ", diff --git a/public/language/hy/admin/settings/chat.json b/public/language/hy/admin/settings/chat.json index 517f702a81..67178e5984 100644 --- a/public/language/hy/admin/settings/chat.json +++ b/public/language/hy/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Անջատել զրույցի հաղորդագրությունների խմբագրումը/ջնջումը", "disable-editing-help": "Ադմինիստրատորները և ամընդհանուր մոդերատորները ազատված են այս սահմանափակումից", "max-length": "Զրույցի հաղորդագրությունների առավելագույն երկարությունը", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Զրուցարաններում օգտատերերի առավելագույն քանակը", "delay": "Զրույցի հաղորդագրությունների միջև ընկած ժամանակը միլիվայրկյաններով", "notification-delay": "Զրույցի հաղորդագրությունների ծանուցման հետաձգում: (0 առանց ուշացման)", diff --git a/public/language/hy/admin/settings/guest.json b/public/language/hy/admin/settings/guest.json index 4f4946d811..e55fa62efb 100644 --- a/public/language/hy/admin/settings/guest.json +++ b/public/language/hy/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Կարգավորումներ", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Թույլատրել guest handles", "handles.enabled-help": "Այս ընտրանքը բացահայտում է նոր դաշտ, որը թույլ է տալիս հյուրերին ընտրել անուն՝ իրենց կատարած յուրաքանչյուր գրառման հետ կապելու համար: Եթե անջատված են, նրանք պարզապես կանվանվեն «Հյուր»", "topic-views.enabled": "Թույլ տվեք հյուրերին ավելացնել թեմայի դիտումների քանակը", diff --git a/public/language/hy/email.json b/public/language/hy/email.json index 891b72ad04..d14651774b 100644 --- a/public/language/hy/email.json +++ b/public/language/hy/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Գաղտնաբառը հաջողությամբ փոխված է", "reset.notify.text1": "Մենք ծանուցում ենք ձեզ, որ %1-ում ձեր գաղտնաբառը հաջողությամբ փոխվել է:", "reset.notify.text2": "Եթե դուք չեք թույլատրել սա, խնդրում ենք անմիջապես տեղեկացնել ադմինիստրատորին:", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Վերջին թեմաները %1-ից", "digest.top-topics": "Հիմնական թեմաները %1-ից", "digest.popular-topics": "Հանրաճանաչ թեմաներ %1-ից", diff --git a/public/language/hy/error.json b/public/language/hy/error.json index 3b93ebc43c..e0a48e0a41 100644 --- a/public/language/hy/error.json +++ b/public/language/hy/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Ներողություն, այս հաշիվն արգելված է մինչև %1 (պատճառը՝ %2)", "user-too-new": "Ներողություն, ձեզնից պահանջվում է սպասել %1 վայրկյան(եր) նախքան ձեր առաջին գրառումը կատարելը", "blacklisted-ip": "Ներողություն, ձեր IP հասցեն արգելվել է այս համայնքում: Եթե կարծում եք, որ սա սխալ է, դիմեք ադմինիստրատորին:", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Խնդրում ենք նշել այս արգելքի ավարտի ամսաթիվը", "no-category": "Կատեգորիա գոյություն չունի", "no-topic": "Թեման գոյություն չունի", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Այս զրուցարանը գոյություն չունի:", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Դուք արդեն քվեարկել եք այս գրառման օգտին:", "reputation-system-disabled": "Վարկանիշի համակարգը անջատված է:", "downvoting-disabled": "Դեմ քվեարկությունն անջատված է", @@ -199,6 +200,7 @@ "not-in-room": "Օգտատերը սենյակում չէ", "cant-kick-self": "Դուք չեք կարող ձեզ հեռացնել խմբից", "no-users-selected": "Ընտրված օգտատեր(ներ) չկա", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Գլխավոր էջի անվավեր ուղեգիծ", "invalid-session": "Անվավեր սեսիա", "invalid-session-text": "Կարծես թե ձեր մուտքի սեսիան այլևս ակտիվ չէ: Խնդրում ենք թարմացնել այս էջը:", diff --git a/public/language/hy/global.json b/public/language/hy/global.json index f3a871d487..ae51bf5a51 100644 --- a/public/language/hy/global.json +++ b/public/language/hy/global.json @@ -51,6 +51,8 @@ "nextpage": "հաջորդ էջ", "alert.success": "Կատարված է", "alert.error": "Սխալ", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Արգելված", "alert.banned.message": "Ձեզ հենց նոր արգելել են, ձեր մուտքն այժմ սահմանափակված է:", "alert.unbanned": "Չարգելված", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index 3223ffdd2e..15f507dc86 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Դուք չունեք որևէ ակտիվ չաթ", "chat.user_typing": "%1-ը գրում է...", "chat.user_has_messaged_you": "%1-ը ձեզ հաղորդագրություն է ուղարկել:", + "chat.replying-to": "Replying to %1", "chat.see_all": "Բոլոր չաթերը", "chat.mark_all_read": "Նշել բոլորը կարդացված", "chat.no-messages": "Խնդրում ենք ընտրել ստացող՝ զրույցի հաղորդագրության պատմությունը դիտելու համար", @@ -27,22 +28,43 @@ "chat.three_months": "3 ամիս", "chat.delete_message_confirm": "Վստա՞հ եք, որ ցանկանում եք ջնջել այս հաղորդագրությունը:", "chat.retrieving-users": "Օգտատերերի վերականգնում ", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Կարգավորել Զրուցասենյակը", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Որոնել օգտերերին այստեղ: Ընտրվելուց հետո օգտատերը կավելացվի զրուցարանում: Նոր օգտատերը չի կարողանա տեսնել զրույցի հաղորդագրությունները, որոնք գրված են նախքան դրանք ավելացվելը խոսակցությանը: Միայն սենյակների սեփականատերերը կարող են օգտատերերին հեռացնել զրուցարաններից:", "chat.confirm-chat-with-dnd-user": "Այս օգտվողը դրել է իր կարգավիճակը DnD (Մի խանգարեք): Դեռ ցանկանու՞մ եք զրուցել նրանց հետ:", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Վերանվանել սենյակը", "chat.rename-placeholder": "Մուտքագրեք ձեր սենյակի անունը այստեղ", "chat.rename-help": "Այստեղ սահմանված սենյակի անունը տեսանելի կլինի սենյակի բոլոր մասնակիցների համար:", - "chat.leave": "Դուրս գալ զրույցից.", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Վստա՞հ եք, որ ցանկանում եք լքել այս զրույցը:", "chat.leave-help": "Այս զրույցից դուրս գալը ձեզ կհեռացնի այս զրույցի հետագա նամակագրությունից: Եթե ապագայում ձեզ նորից ավելացնեն, դուք չեք տեսնի զրույցի պատմություն, որը տեղի է ունեցել մինչ ձեր նորից միանալը:", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Այս սենյակում ", "chat.kick": "Kick", "chat.show-ip": "Ցույց տալ IP", "chat.owner": "Սենյակի սեփականատեր", - "chat.system.user-join": "%1-ը միացել է սենյակին", - "chat.system.user-leave": "%1 դուրս է եկել սենյակից", - "chat.system.room-rename": "%2-ը վերանվանել է այս սենյակը՝ %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Կազմել", "composer.show_preview": "Ցույց տալ նախադիտումը", "composer.hide_preview": "Թաքցնել նախադիտումը", diff --git a/public/language/hy/topic.json b/public/language/hy/topic.json index 8656434f70..84b6b4ef8f 100644 --- a/public/language/hy/topic.json +++ b/public/language/hy/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/id/admin/admin.json b/public/language/id/admin/admin.json index c98a0b8c34..2470022bd9 100644 --- a/public/language/id/admin/admin.json +++ b/public/language/id/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/id/admin/dashboard.json b/public/language/id/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/id/admin/dashboard.json +++ b/public/language/id/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/id/admin/manage/categories.json b/public/language/id/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/id/admin/manage/categories.json +++ b/public/language/id/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/id/admin/manage/users.json b/public/language/id/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/id/admin/manage/users.json +++ b/public/language/id/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/id/admin/menu.json b/public/language/id/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/id/admin/menu.json +++ b/public/language/id/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/id/admin/settings/chat.json b/public/language/id/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/id/admin/settings/chat.json +++ b/public/language/id/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/id/admin/settings/guest.json b/public/language/id/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/id/admin/settings/guest.json +++ b/public/language/id/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/id/email.json b/public/language/id/email.json index 7ccd3ff608..e4c86cf523 100644 --- a/public/language/id/email.json +++ b/public/language/id/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Kata Sandi berhasil diganti", "reset.notify.text1": "Kami beritahukan bahwa pada %1 password anda berhasil diubah.", "reset.notify.text2": "Jika ini bukan kehendak anda, silakan segera hubungi administrator.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Topik-topik terbaru dari %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/id/error.json b/public/language/id/error.json index a5c4c74ff2..db141c8765 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Kategori tidak ditemukan", "no-topic": "Topik tidak ditemukan", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistem reputasi ditiadakan.", "downvoting-disabled": "Downvoting ditiadakan", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/id/global.json b/public/language/id/global.json index fbd9df6b84..df956b8264 100644 --- a/public/language/id/global.json +++ b/public/language/id/global.json @@ -51,6 +51,8 @@ "nextpage": "Halaman Selanjutnya", "alert.success": "Sukses", "alert.error": "Error", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banned", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index 551ef4ac4f..31b997c2bd 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Kamu tidak memiliki percakapan yang aktif.", "chat.user_typing": "%1 sedang menulis ...", "chat.user_has_messaged_you": "%1 telah mengirimkan pesan untukmu.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Mohon pilih satu penerima untuk melihat riwayat pesan percakapan", @@ -27,22 +28,43 @@ "chat.three_months": "3 Bulan", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/id/topic.json b/public/language/id/topic.json index add9fd3e79..7e4401d006 100644 --- a/public/language/id/topic.json +++ b/public/language/id/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/it/admin/admin.json b/public/language/it/admin/admin.json index 549a8457c6..fdff713a70 100644 --- a/public/language/it/admin/admin.json +++ b/public/language/it/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "Visualizza", - "edit": "Modifica" + "edit": "Modifica", + "add": "Aggiungi", + "select-icon": "Seleziona icona" } \ No newline at end of file diff --git a/public/language/it/admin/dashboard.json b/public/language/it/admin/dashboard.json index 7a9535a418..53bef3d279 100644 --- a/public/language/it/admin/dashboard.json +++ b/public/language/it/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "La Riorganizzazione e il Riavvio del tuo NodeBB sono stati disabilitati in quanto non sembra che tu lo stia eseguendo tramite il demone appropriato.", "maintenance-mode": "Modalità Manutenzione", "maintenance-mode-title": "Clicca qui per impostare la modalità di manutenzione per NodeBB", + "dark-mode": "Modalità scura", "realtime-chart-updates": "Aggiornamento grafici in tempo reale", "active-users": "Utenti Attivi", @@ -89,5 +90,9 @@ "details.logins-login-time": "Tempo di accesso", "start": "Inizio", "end": "Fine", - "filter": "Filtro" + "filter": "Filtro", + "view-as-json": "Visualizza come JSON", + "expand-analytics": "Espandi l'analisi", + "clear-search-history": "Cancella cronologia delle ricerche", + "clear-search-history-confirm": "Sei sicuro di voler cancellare l'intera cronologia delle ricerche?" } diff --git a/public/language/it/admin/extend/widgets.json b/public/language/it/admin/extend/widgets.json index 9b69cc35f4..02bfd45aa5 100644 --- a/public/language/it/admin/extend/widgets.json +++ b/public/language/it/admin/extend/widgets.json @@ -9,9 +9,9 @@ "containers.none": "Nessuno", "container.well": "Bene", "container.jumbotron": "Jumbotron", - "container.card": "Card", - "container.card-header": "Card Header", - "container.card-body": "Card Body", + "container.card": "Scheda", + "container.card-header": "Intestazione della scheda", + "container.card-body": "Corpo della scheda", "container.alert": "Avviso", "alert.confirm-delete": "Sei sicuro di voler eliminare questo widget?", diff --git a/public/language/it/admin/manage/categories.json b/public/language/it/admin/manage/categories.json index 8c0f4d0347..a9a830ae2e 100644 --- a/public/language/it/admin/manage/categories.json +++ b/public/language/it/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Whitelist tag", "upload-image": "Caricamento Immagine", "upload": "Carica", - "select-icon": "Seleziona icona", "delete-image": "Rimuove", "category-image": "Immagine di Categoria", "image-and-icon": "Immagine e icona", diff --git a/public/language/it/admin/manage/groups.json b/public/language/it/admin/manage/groups.json index 11363639ed..978be53017 100644 --- a/public/language/it/admin/manage/groups.json +++ b/public/language/it/admin/manage/groups.json @@ -14,7 +14,7 @@ "hidden": "Nascosto", "private": "Privato", "edit": "Modifica", - "delete": "Cancella", + "delete": "Elimina", "privileges": "Privilegi", "members-csv": "Membri (CSV)", "search-placeholder": "Cerca", diff --git a/public/language/it/admin/manage/users.json b/public/language/it/admin/manage/users.json index 334b721ef9..f06ec1f32c 100644 --- a/public/language/it/admin/manage/users.json +++ b/public/language/it/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Elimina Utenti e Contenuto", "download-csv": "Scarica CSV", "manage-groups": "Gestisci Gruppi", + "set-reputation": "Imposta reputazione", "add-group": "Aggiungi Gruppo", "create": "Crea utente", "invite": "Invita via email", diff --git a/public/language/it/admin/menu.json b/public/language/it/admin/menu.json index 6cfa55b521..b808251105 100644 --- a/public/language/it/admin/menu.json +++ b/public/language/it/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utenti", "manage/admins-mods": "Amministratori e Moderatori", "manage/registration": "Coda di registrazione", + "manage/flagged-content": "Contenuti Segnalati", "manage/post-queue": "Coda post", "manage/groups": "Gruppi", "manage/ip-blacklist": "Lista degli IP bloccati", diff --git a/public/language/it/admin/settings/chat.json b/public/language/it/admin/settings/chat.json index 0faf77ab75..0a38dbb9a9 100644 --- a/public/language/it/admin/settings/chat.json +++ b/public/language/it/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disabilita modifica/cancellazione messaggio chat", "disable-editing-help": "Gli amministratori e i moderatori globali sono esenti da questa restrizione.", "max-length": "Lunghezza massima dei messaggi della chat", + "max-chat-room-name-length": "Lunghezza massima dei nomi delle stanze chat", "max-room-size": "Numero massimo di utenti nelle stanza chat", "delay": "Tempo tra i messaggi della chat in millisecondi", "notification-delay": "Ritardo di notifica per i messaggi di chat. (0 per nessun ritardo)", diff --git a/public/language/it/admin/settings/guest.json b/public/language/it/admin/settings/guest.json index 6798438054..feeff7e25e 100644 --- a/public/language/it/admin/settings/guest.json +++ b/public/language/it/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Impostazioni", - "guest-settings": "Impostazioni dell'ospite", + "guest-settings": "Impostazioni ospite", "handles.enabled": "Consenti nome utente ospite", "handles.enabled-help": "Questa opzione mostra un nuovo campo che permette agli ospiti di scegliere un nome da associare ad ogni post che fanno. Se disabilitata, saranno semplicemente chiamati \"Ospite\".", "topic-views.enabled": "Consentire agli ospiti di aumentare il numero di visualizzazioni della discussione", diff --git a/public/language/it/email.json b/public/language/it/email.json index e6cc55ba1b..8d94bae9db 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password modificata con successo.", "reset.notify.text1": "Ti informiamo che il %1, la password è stata cambiata con successo.", "reset.notify.text2": "Se non hai autorizzato questo, per favore informa immediatamente l'amministratore.", + "digest.unread-rooms": "Stanze non lette", + "digest.room-name-unreadcount": "%1 (%2 non letto)", "digest.latest_topics": "Ultime discussioni da %1", "digest.top-topics": "Argomenti principali da %1", "digest.popular-topics": "Argomenti popolari da %1", diff --git a/public/language/it/error.json b/public/language/it/error.json index bca3af9820..ed1384580e 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Spiacente, questo account è stato bannato fino a %1 (Motivazione: %2)", "user-too-new": "Spiacente, devi attendere %1 secondo(i) prima di creare il tuo primo post", "blacklisted-ip": "Spiacente, il tuo indirizzo IP è stato bannato da questa comunità. Se ritieni che si tratti di un errore, contatta un amministratore.", + "cant-blacklist-self-ip": "Non puoi inserire nella blacklist il tuo IP", "ban-expiry-missing": "Per favore fornire una data di termine per questo ban", "no-category": "La Categoria non esiste", "no-topic": "La Discussione non esiste", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "La stanza chat non esiste.", "cant-add-users-to-chat-room": "Impossibile aggiungere utenti alla stanza chat.", "cant-remove-users-from-chat-room": "Impossibile rimuovere gli utenti dalla stanza chat.", - "chat-room-name-too-long": "Nome della stanza chat troppo lungo.", + "chat-room-name-too-long": "Nome della stanza chat troppo lungo. I nomi non possono essere più lunghi di %1 caratteri.", "already-voting-for-this-post": "Hai già votato per questo post", "reputation-system-disabled": "Il sistema di reputazione è disabilitato.", "downvoting-disabled": "Votata negativamente è disabilitato", @@ -199,6 +200,7 @@ "not-in-room": "L'utente non è in questa stanza", "cant-kick-self": "Non puoi espellerti dal gruppo", "no-users-selected": "Nessun utente selezionato", + "no-groups-selected": "Nessun gruppo(i) selezionato", "invalid-home-page-route": "Percorso della pagina iniziale non valido", "invalid-session": "Sessione non valida", "invalid-session-text": "Sembra che la tua sessione di accesso non sia più attiva. Si prega di aggiornare questa pagina.", diff --git a/public/language/it/global.json b/public/language/it/global.json index 235fa2c35f..7c52a6c4a9 100644 --- a/public/language/it/global.json +++ b/public/language/it/global.json @@ -51,6 +51,8 @@ "nextpage": "Pagina Successiva", "alert.success": "Riuscito", "alert.error": "Errore", + "alert.warning": "Avvertimento", + "alert.info": "Informazioni", "alert.banned": "Bannato", "alert.banned.message": "Sei stato appena bannato, il tuo accesso è ora limitato.", "alert.unbanned": "Non bannato", diff --git a/public/language/it/groups.json b/public/language/it/groups.json index 3df61dcaf0..e8f9c478a0 100644 --- a/public/language/it/groups.json +++ b/public/language/it/groups.json @@ -28,7 +28,7 @@ "details.private": "Privato", "details.disableJoinRequests": "Disabilita le richieste d'iscrizione", "details.disableLeave": "Impedisce agli utenti di lasciare il gruppo", - "details.grant": "Concedi/Revoca la Proprietà", + "details.grant": "Concedi/Revoca Proprietà", "details.kick": "Espelli", "details.kick_confirm": "Sei sicuro di voler rimuovere questo membro dal gruppo?", "details.add-member": "Aggiungi Membro", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 417a5faf5d..3f888dbbe6 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non hai chat attive.", "chat.user_typing": "%1 sta scrivendo...", "chat.user_has_messaged_you": "%1 ti ha scritto.", + "chat.replying-to": "Risposta a %1", "chat.see_all": "Tutte le chat", "chat.mark_all_read": "Segna tutto come letto", "chat.no-messages": "Si prega di selezionare un destinatario per vedere la cronologia dei messaggi", @@ -27,22 +28,43 @@ "chat.three_months": "3 Mesi", "chat.delete_message_confirm": "Sei sicuro di voler eliminare questo messaggio?", "chat.retrieving-users": "Estrapolando gli utenti...", + "chat.view-users-list": "Visualizza elenco utenti", + "chat.public-rooms": "Stanze pubbliche (%1)", + "chat.private-rooms": "Stanze private (%1)", + "chat.create-room": "Crea stanza chat ", + "chat.private.option": "Privato (visibile solo agli utenti aggiunti alla stanza)", + "chat.public.option": "Pubblico (visibile a tutti gli utenti nei gruppi selezionati)", + "chat.public.groups-help": "Per creare una stanza chat visibile a tutti gli utenti, seleziona gli utenti registrati dall'elenco dei gruppi.", "chat.manage-room": "Gestisci stanza chat", + "chat.add-user": "Aggiungi utente", + "chat.notification-settings": "Impostazioni di notifica", + "chat.default-notification-setting": "Impostazioni di notifica predefinite", + "chat.notification-setting-room-default": "Stanza predefinita", + "chat.notification-setting-none": "Nessuna notifica", + "chat.notification-setting-at-mention-only": "@solo menzione", + "chat.notification-setting-all-messages": "Tutti i messaggi", + "chat.select-groups": "Seleziona gruppi", "chat.add-user-help": "Cerca qui gli utenti. Quando selezionato, l'utente sarà aggiunto alla chat.\nIl nuovo utente non sarà in grado di vedere i messaggi della chat scritti prima della sua partecipazione alla conversazione.\nSolo i proprietari della stanza () possono rimuovere gli utenti dalla stanza della chat.", "chat.confirm-chat-with-dnd-user": "Questo utente ha impostato il suo stato su Non Disturbare. Sei sicuro di voler iniziare una conversazione?", + "chat.room-name-optional": "Nome stanza (facoltativo)", "chat.rename-room": "Rinomina stanza", "chat.rename-placeholder": "Inserisci qui il nome della stanza", "chat.rename-help": "Il nome della stanza qui impostato sarà visibile da tutti i partecipanti nella stanza.", - "chat.leave": "Abbandona Chat", + "chat.leave": "Lascia", + "chat.leave-room": "Lascia stanza", "chat.leave-prompt": "Sei sicuro di volere abbandonare questa chat?", "chat.leave-help": "Abbandonando questa chat perderai ogni sua traccia. Anche dopo un tuo eventuale rientro, non vedrai nessun messaggio precedente.", + "chat.delete": "Elimina", + "chat.delete-room": "Elimina stanza", + "chat.delete-prompt": "Sei sicuro di voler eliminare questa stanza chat?", "chat.in-room": "In questa stanza", "chat.kick": "Butta fuori", "chat.show-ip": "Mostra indirizzo IP", "chat.owner": "Propietario stanza", - "chat.system.user-join": "%1 si è iscritto alla stanza", - "chat.system.user-leave": "%1 ha lasciato la stanza", - "chat.system.room-rename": "%2 ha rinominato questa stanza: %1", + "chat.grant-rescind-ownership": "Concedi/Revoca Proprietà", + "chat.system.user-join": "%1 si è unito alla stanza ", + "chat.system.user-leave": "%1 ha lasciato la stanza ", + "chat.system.room-rename": "%2 ha rinominato questa stanza in \"%1\" ", "composer.compose": "Componi", "composer.show_preview": "Visualizza Anteprima", "composer.hide_preview": "Nascondi Anteprima", diff --git a/public/language/it/topic.json b/public/language/it/topic.json index f947fcb09a..9786279944 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "scritto ", "wrote-on": "scritto su ", "replied-to-user-ago": "risposto a %3 ", - "replied-to-user-on": "risposto a %3 su ", + "replied-to-user-on": "risposto a %3 su ", "user-locked-topic-ago": "%1 ha bloccato questa discussione %2", "user-locked-topic-on": "%1 ha bloccato questa discussione su %2", "user-unlocked-topic-ago": "%1 ha sbloccato questa discussione %2", diff --git a/public/language/ja/admin/admin.json b/public/language/ja/admin/admin.json index 73676e27a3..e3a5942b3e 100644 --- a/public/language/ja/admin/admin.json +++ b/public/language/ja/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ja/admin/dashboard.json b/public/language/ja/admin/dashboard.json index bec6cf5b67..936a823210 100644 --- a/public/language/ja/admin/dashboard.json +++ b/public/language/ja/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "適切なデーモンを介してNodeBBを実行しているようには見えないため、NodeBBの再構築および再起動は無効になっています。", "maintenance-mode": "メンテナンスモード", "maintenance-mode-title": "NodeBBのメンテナンスモードを設定するには、ここをクリックしてください", + "dark-mode": "Dark Mode", "realtime-chart-updates": "リアルタイムチャートの更新", "active-users": "アクティブユーザー", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ja/admin/manage/categories.json b/public/language/ja/admin/manage/categories.json index 9a51f63699..df4e0299d0 100644 --- a/public/language/ja/admin/manage/categories.json +++ b/public/language/ja/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "画像をアップロード", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "削除", "category-image": "カテゴリ画像", "image-and-icon": "Image & Icon", diff --git a/public/language/ja/admin/manage/users.json b/public/language/ja/admin/manage/users.json index e7aa34eed4..82381bab7d 100644 --- a/public/language/ja/admin/manage/users.json +++ b/public/language/ja/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "CSVでダウンロード", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ja/admin/menu.json b/public/language/ja/admin/menu.json index 09589fd6ae..ba2914892c 100644 --- a/public/language/ja/admin/menu.json +++ b/public/language/ja/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "ユーザー", "manage/admins-mods": "Admins & Mods", "manage/registration": "登録キュー", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "投稿キュー", "manage/groups": "グループ", "manage/ip-blacklist": "IPブラックリスト", diff --git a/public/language/ja/admin/settings/chat.json b/public/language/ja/admin/settings/chat.json index a0551c713f..fb7bb73e23 100644 --- a/public/language/ja/admin/settings/chat.json +++ b/public/language/ja/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "チャットメッセージの編集/削除を無効にする", "disable-editing-help": "管理者およびグローバルモデレーターはこの制限を免除されます", "max-length": "チャットメッセージの最大の長さ", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "チャットルームの最大ユーザー数", "delay": "ミリ秒単位のチャットメッセージ間の時間", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ja/admin/settings/guest.json b/public/language/ja/admin/settings/guest.json index 94efb6ff4a..7bf33c0014 100644 --- a/public/language/ja/admin/settings/guest.json +++ b/public/language/ja/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "ゲストハンドルを有効にする", "handles.enabled-help": "このオプションでは新しい投稿が表示される時に、ゲストは自分が投稿する各投稿に関連付ける名前を選択できます。無効にすると、単に「ゲスト」と呼ばれます。", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ja/email.json b/public/language/ja/email.json index 4a26703cda..de460531ba 100644 --- a/public/language/ja/email.json +++ b/public/language/ja/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "パスワードをリセットしました", "reset.notify.text1": "%1にてパスワードのリセットが行われたことをお知らせします。", "reset.notify.text2": "もしあなたがリセットを行っていない場合は、すぐに管理者に通報してください。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1からの新しいスレッド", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index 6dd1b14526..6a721ff75e 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "申し訳ありませんが、このアカウントは%1(理由:%2)まで禁止されています。", "user-too-new": "申し訳ありません。登録後に投稿を行うには%1秒お待ち下さい。", "blacklisted-ip": "申し訳ありませんがあなたのIPアドレスは当コミュニティで停止されています。もし誤ったエラーだと思われる場合は管理者にお問い合わせください。", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "この停止の終了日を入力してください。", "no-category": "カテゴリは存在しません", "no-topic": "スレッドは存在しません", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "あなたはすでにこの投稿を評価しました。", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", @@ -199,6 +200,7 @@ "not-in-room": "ユーザーが部屋にいません", "cant-kick-self": "あなたは、グループから自分自身をキックすることが出来ません", "no-users-selected": "ユーザー(s)が選択されていません", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "ホームページのルートが無効", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ja/global.json b/public/language/ja/global.json index c286ed19dc..b0851acc42 100644 --- a/public/language/ja/global.json +++ b/public/language/ja/global.json @@ -51,6 +51,8 @@ "nextpage": "次のページ", "alert.success": "成功", "alert.error": "エラー", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "停止した", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index b478224153..f4b834ebb0 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "チャットはありません。", "chat.user_typing": "%1 が入力中 ...", "chat.user_has_messaged_you": "%1さんからメッセージが届いています。", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "チャットメッセージの履歴を表示するには、受信者を選択してください", @@ -27,22 +28,43 @@ "chat.three_months": "3ヶ月", "chat.delete_message_confirm": "本当にこのメッセージを削除しますか?", "chat.retrieving-users": "ユーザーを所得しています…", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "チャット部屋を管理", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "このユーザーのステータスはDnD(Do not disturb:取り込み中)に設定されています。あなたはまだチャットしたいですか?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "部屋名を変更", "chat.rename-placeholder": "部屋名を入力", "chat.rename-help": "設定した部屋名は、この部屋のすべての参加者に表示されます", - "chat.leave": "チャットから退出", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "このチャットから退出しますか?", "chat.leave-help": "このチャットを終了すると、このチャットからあなたが削除されます。 再度参加しても、前のチャット履歴は表示されません。", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "この部屋内", "chat.kick": "キック", "chat.show-ip": "IP表示", "chat.owner": "部屋の管理者", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "構成", "composer.show_preview": "プレビュー表示", "composer.hide_preview": "プレビュー非表示", diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json index 52befd5df0..ef1ac555ff 100644 --- a/public/language/ja/topic.json +++ b/public/language/ja/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ko/admin/admin.json b/public/language/ko/admin/admin.json index eea7e10b16..86e5585c62 100644 --- a/public/language/ko/admin/admin.json +++ b/public/language/ko/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ko/admin/dashboard.json b/public/language/ko/admin/dashboard.json index e13e4c3b01..4f3677be07 100644 --- a/public/language/ko/admin/dashboard.json +++ b/public/language/ko/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "정상적인 데몬으로 판단할 수 없어 리빌드와 재시작을 할 수 없습니다.", "maintenance-mode": "점검 모드", "maintenance-mode-title": "NodeBB 점검 모드를 설정하시려면 이곳을 클릭하세요.", + "dark-mode": "Dark Mode", "realtime-chart-updates": "실시간 차트 업데이트", "active-users": "활동 중인 사용자", @@ -89,5 +90,9 @@ "details.logins-login-time": "로그인 시점", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ko/admin/manage/categories.json b/public/language/ko/admin/manage/categories.json index abb4733ec9..e450251e09 100644 --- a/public/language/ko/admin/manage/categories.json +++ b/public/language/ko/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "태그 화이트리스트", "upload-image": "이미지 업로드", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "제거", "category-image": "카테고리 이미지", "image-and-icon": "Image & Icon", diff --git a/public/language/ko/admin/manage/users.json b/public/language/ko/admin/manage/users.json index 494c4024f1..49e78ebe3e 100644 --- a/public/language/ko/admin/manage/users.json +++ b/public/language/ko/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "선택한 계정(들)컨텐츠 삭제", "download-csv": "CSV 다운로드", "manage-groups": "그룹 관리", + "set-reputation": "Set Reputation", "add-group": "그룹 추가", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ko/admin/menu.json b/public/language/ko/admin/menu.json index e2acae1c82..0814902509 100644 --- a/public/language/ko/admin/menu.json +++ b/public/language/ko/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "사용자", "manage/admins-mods": "관리자 & 조정자", "manage/registration": "가입 승인 대기열", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "게시 대기열", "manage/groups": "그룹", "manage/ip-blacklist": "IP 블랙리스트", diff --git a/public/language/ko/admin/settings/chat.json b/public/language/ko/admin/settings/chat.json index 979cd5c488..169e6381a5 100644 --- a/public/language/ko/admin/settings/chat.json +++ b/public/language/ko/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "채팅 메시지 수정/삭제 비활성화", "disable-editing-help": "관리자와 조정자는 제한되지 않습니다.", "max-length": "채팅 메시지의 최대 길이", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "채팅방 최대 인원", "delay": "채팅 메시지 발송 지연 (단위: 1/1000초)", "notification-delay": "채팅 메시지 알림 지연 (0으로 놔둘 경우 지연 없음)", diff --git a/public/language/ko/admin/settings/guest.json b/public/language/ko/admin/settings/guest.json index c252faa745..9e03858a44 100644 --- a/public/language/ko/admin/settings/guest.json +++ b/public/language/ko/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "설정", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "비회원 닉네임 설정 허가", "handles.enabled-help": "이 옵션은 비회원들이 포스트를 작성할 때 이름을 적는 공간을 제공합니다. 이 옵션이 비활성화 상태라면 \"Guest\" 라고 표시될 것입니다.", "topic-views.enabled": "비회원의 방문으로 화제 조회수 증가", diff --git a/public/language/ko/email.json b/public/language/ko/email.json index 8209341327..a035d592de 100644 --- a/public/language/ko/email.json +++ b/public/language/ko/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "비밀번호가 성공적으로 변경되었습니다.", "reset.notify.text1": "%1에 관해 통지합니다. 귀하의 비밀번호가 성공적으로 변경되었습니다.", "reset.notify.text2": "만약 이 인증을 요청하지 않았다면 즉시 관리자에게 통보하시기 바랍니다.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1의 최근 주제", "digest.top-topics": "%1의 TOP 주제", "digest.popular-topics": "%1의 인기 주제", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index c44e5f67bb..13e9594b15 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "죄송합니다. 해당 계정은 %1까지 차단되었습니다. (사유: %2)", "user-too-new": "죄송합니다. 첫 번째 게시물은 %1초 후에 작성할 수 있습니다.", "blacklisted-ip": "죄송합니다. 당신의 IP는 이 커뮤니티로부터 차단되었습니다. 만약 오류라고 생각되시면 관리자에게 연락해주세요.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "해당 차단의 만료일을 설정해주세요.", "no-category": "존재하지 않는 카테고리입니다.", "no-topic": "존재하지 않는 화제입니다.", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "채팅이 존재하지 않습니다.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "이미 이 포스트에 투표하셨습니다.", "reputation-system-disabled": "인지도 시스템이 비활성화되어있습니다.", "downvoting-disabled": "비추천 기능이 비활성 상태입니다.", @@ -199,6 +200,7 @@ "not-in-room": "채팅방에 사용자 없음", "cant-kick-self": "스스로 이 그룹을 탈퇴할 수 없습니다.", "no-users-selected": "선택된 사용자가 없습니다.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "올바르지 않은 홈페이지 경로입니다.", "invalid-session": "세션 오류", "invalid-session-text": "로그인 세션이 종료됐습니다. 페이지를 새로고침 해주세요.", diff --git a/public/language/ko/global.json b/public/language/ko/global.json index 09e03f8283..d318f7610f 100644 --- a/public/language/ko/global.json +++ b/public/language/ko/global.json @@ -51,6 +51,8 @@ "nextpage": "다음 페이지", "alert.success": "성공", "alert.error": "오류", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "차단됨", "alert.banned.message": "당신은 차단되었습니다. 당신의 접근이 제한됩니다.", "alert.unbanned": "차단 해제", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index 9f80fdbacd..620530c29f 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "활성화된 채팅이 없습니다.", "chat.user_typing": "%1님이 입력 중...", "chat.user_has_messaged_you": "%1님이 메시지를 보냈습니다.", + "chat.replying-to": "Replying to %1", "chat.see_all": "모든 채팅", "chat.mark_all_read": "Mark all read", "chat.no-messages": "채팅 기록을 보려면 채팅 상대를 선택하세요.", @@ -27,22 +28,43 @@ "chat.three_months": "3개월", "chat.delete_message_confirm": "이 메세지를 삭제하시겠습니까?", "chat.retrieving-users": "사용자 불러오는 중...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "채팅 관리", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "여기에서 사용자를 검색하세요. 선택한 사용자를 채팅에 초대합니다. 새로운 사용자는 이전에 주고받은 채팅을 확인할 수 없습니다. 채팅 관리자들()만 사용자를 채팅방에서 추방할 수 있습니다.", "chat.confirm-chat-with-dnd-user": "이 사용자는 자신의 상태를 방해 금지로 설정했습니다. 그래도 대화를 요청하시겠습니까?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "채팅방 이름 변경", "chat.rename-placeholder": "여기에 채팅방 이름을 입력하세요.", "chat.rename-help": "여기에서 설정된 채팅방 이름은 모든 참여자들에게 보여집니다.", - "chat.leave": "채팅방 나가기", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "정말로 이 채팅에서 나가시겠어요?", "chat.leave-help": "이 채팅방에서 퇴장하면 더 이상 이 채팅방의 메시지를 수신할 수 없습니다. 나중에 다시 입장하게 되더라도 퇴장한 동안의 메시지는 확인할 수 없습니다.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "채팅 참여자", "chat.kick": "추방", "chat.show-ip": "IP 보이기", "chat.owner": "채팅 관리자", - "chat.system.user-join": "%1님이 입장하셨습니다.", - "chat.system.user-leave": "%1님이 퇴장하셨습니다.", - "chat.system.room-rename": "%2님의 채팅방 이름 변경: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "작성", "composer.show_preview": "미리보기", "composer.hide_preview": "미리보기 숨김", diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index 8af1a48a8e..94654f0f42 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/lt/admin/admin.json b/public/language/lt/admin/admin.json index de86c23c77..5aeca68b5e 100644 --- a/public/language/lt/admin/admin.json +++ b/public/language/lt/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/lt/admin/dashboard.json b/public/language/lt/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/lt/admin/dashboard.json +++ b/public/language/lt/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/lt/admin/manage/categories.json b/public/language/lt/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/lt/admin/manage/categories.json +++ b/public/language/lt/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/lt/admin/manage/users.json b/public/language/lt/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/lt/admin/manage/users.json +++ b/public/language/lt/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/lt/admin/menu.json b/public/language/lt/admin/menu.json index ad6fff59be..d3ae8a4504 100644 --- a/public/language/lt/admin/menu.json +++ b/public/language/lt/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/lt/admin/settings/chat.json b/public/language/lt/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/lt/admin/settings/chat.json +++ b/public/language/lt/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/lt/admin/settings/guest.json b/public/language/lt/admin/settings/guest.json index d564091e0f..70d90332d6 100644 --- a/public/language/lt/admin/settings/guest.json +++ b/public/language/lt/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Nustatymai", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/lt/email.json b/public/language/lt/email.json index 6b505399b7..d0cd26dd08 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Slaptažodis sėkmingai pakeistas", "reset.notify.text1": "Mes tikriname ar jūs tikrai esate %1, jūsų slaptažodis buvo pakeistas sėkmingai", "reset.notify.text2": "Jeigu jūs neprašėte šito, prašome perspėti administratoriu nedelsiant", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Paskutinės temos iš %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 1595d4a985..53f5e2743f 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Atsiprašome, ši paskyra užblokuota iki %1 (Priežastis: %2)", "user-too-new": "Atsiprašome, jūs įpareigoti palaukti %1 sekunde(s) prieš rašant pirmą pranešimą", "blacklisted-ip": "Atsiprašome, jūsų IP adresas yra užblokuotas. Jei manote, jog tai klaida, susisiekite su administratoriumi.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Užpildykite šio blokavimo pabaigos datą", "no-category": "Tokios kategorijos nėra", "no-topic": "Tokios temos nėra", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Jūs jau balsavote už šį pranešimą.", "reputation-system-disabled": "Reputacijos sistema išjungta.", "downvoting-disabled": "Downvoting yra išjungtas", @@ -199,6 +200,7 @@ "not-in-room": "Vartotojas ne svetainėje", "cant-kick-self": "Negalite išmesti savęs iš grupės", "no-users-selected": "Nepasirinktas joks vartotojas", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Blogas kelias į pagrindinį puslapį", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/lt/global.json b/public/language/lt/global.json index 331db9dffe..b501ae6e23 100644 --- a/public/language/lt/global.json +++ b/public/language/lt/global.json @@ -51,6 +51,8 @@ "nextpage": "Kitas puslapis", "alert.success": "Pavyko", "alert.error": "Klaida", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Užblokuotas", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index 221532a712..65598f594d 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Jūs neturite aktyvių susirašinėjimų.", "chat.user_typing": "%1 dabar rašo...", "chat.user_has_messaged_you": "%1 parašė jums.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Prašome pasirikti gavėją, norėdami peržiūrėti žinučių istoriją", @@ -27,22 +28,43 @@ "chat.three_months": "3 mėnesiai", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sukomponuoti", "composer.show_preview": "Rodyti pavyzdį", "composer.hide_preview": "Slėpti pavyzdį", diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 9576935b5c..ee5c31be86 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/lv/admin/admin.json b/public/language/lv/admin/admin.json index 9cd1b5d220..2d243e3944 100644 --- a/public/language/lv/admin/admin.json +++ b/public/language/lv/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/lv/admin/dashboard.json b/public/language/lv/admin/dashboard.json index 92e6012cd1..37c238865f 100644 --- a/public/language/lv/admin/dashboard.json +++ b/public/language/lv/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "NodeBB pārkompilēšana un pārstartēšana ir atspējota, jo, šķiet, ka tā nav bijusi palaista ar atbilstošo dēmona procesu.", "maintenance-mode": "Uzturēšanas režīms", "maintenance-mode-title": "Klikšķināt, lai pārietu uz NodeBB uzturēšanas režīmu", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Reālā laika grafiku atjauninājumi", "active-users": "Aktīvie lietotāji", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/lv/admin/manage/categories.json b/public/language/lv/admin/manage/categories.json index 2318d20066..f9f49b5aad 100644 --- a/public/language/lv/admin/manage/categories.json +++ b/public/language/lv/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Augšupielādēt bildi", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Noņemt", "category-image": "Kategorijas bilde", "image-and-icon": "Image & Icon", diff --git a/public/language/lv/admin/manage/users.json b/public/language/lv/admin/manage/users.json index 75178297f2..37b84c7515 100644 --- a/public/language/lv/admin/manage/users.json +++ b/public/language/lv/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Lejupielādēt .csv", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/lv/admin/menu.json b/public/language/lv/admin/menu.json index 82b7f18a89..97544abc7d 100644 --- a/public/language/lv/admin/menu.json +++ b/public/language/lv/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Lietotāji", "manage/admins-mods": "Administratori & moderatori", "manage/registration": "Reģistrācijas rinda", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Rakstu apstiprināšanas rinda", "manage/groups": "Grupas", "manage/ip-blacklist": "IP adrešu melnais saraksts", diff --git a/public/language/lv/admin/settings/chat.json b/public/language/lv/admin/settings/chat.json index 9a6a3540f1..7b3e7969ae 100644 --- a/public/language/lv/admin/settings/chat.json +++ b/public/language/lv/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Atspējot sarunu rediģēšanu/izdzēšanu", "disable-editing-help": "Administratori un globālie moderatori ir atbrīvoti no šī ierobežojuma", "max-length": "Sarunu lielākais garums", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksimālais lietotāju skaits tērzētavā", "delay": "Laiks starp sarunām milisekundēs", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/lv/admin/settings/guest.json b/public/language/lv/admin/settings/guest.json index cfbded0bbc..e8904c3260 100644 --- a/public/language/lv/admin/settings/guest.json +++ b/public/language/lv/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Atļaut viesu iesaukas", "handles.enabled-help": "Parādīt lauku, kas viesiem ļaus izvēlēties savu iesauku, kas saistīts ar katru viņu publicēto rakstu. Ja ir atspējots, viņus vienkārši sauks par \"Viesiem\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/lv/email.json b/public/language/lv/email.json index 8767a5552d..ff037d7d0c 100644 --- a/public/language/lv/email.json +++ b/public/language/lv/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parole veiksmīgi mainīta", "reset.notify.text1": "Mēs Tevi informējam, ka %1 Tava parole tika veiksmīgi mainīta.", "reset.notify.text2": "Ja neesi to pilnvarojis, nekavējoties informē administratoru par to.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Jaunākie temati no %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/lv/error.json b/public/language/lv/error.json index b6f24a4006..cb0695ec6f 100644 --- a/public/language/lv/error.json +++ b/public/language/lv/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Diemžēl šis konts ir bloķēts līdz %1 (Iemesls: %2)", "user-too-new": "Atvaino, pirms pirmā raksta izveides Tev jāgaida %1 sekundes", "blacklisted-ip": "Diemžēl Tava IP adrese ir bloķēta šajā kopienā. Ja Tev liekas, ka esam kļūdījušies, lūdzu, sazinies ar administratoru.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Lūdzu, norādi šīs bloķēšanas beigu datumu", "no-category": "Kategorija nav atrasta", "no-topic": "Temats nav atrasts", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Tu jau balsoji par šo rakstu.", "reputation-system-disabled": "Ranga punktu sistēma ir atspējota.", "downvoting-disabled": "Balsošana \"pret\" ir atspējota", @@ -199,6 +200,7 @@ "not-in-room": "Lietotājs nav tērzētavā", "cant-kick-self": "Nevar sevi izslēgt no grupas", "no-users-selected": "Nav atlasīts neviens lietotājs(-i)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Nederīgs sākumlapas ceļš", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/lv/global.json b/public/language/lv/global.json index 21d491a9ea..691d7a0985 100644 --- a/public/language/lv/global.json +++ b/public/language/lv/global.json @@ -51,6 +51,8 @@ "nextpage": "Nākamā lapa", "alert.success": "Veiksme", "alert.error": "Kļūda", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Bloķētie", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index 778e9f68cc..8e02627ed8 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nav aktīvo sarunu.", "chat.user_typing": "%1 raksta...", "chat.user_has_messaged_you": "%1 ir sācis ar Tevi sarunāties", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Lūdzu, izvēlies adresātu, lai skatītu sarunu vēsturi", @@ -27,22 +28,43 @@ "chat.three_months": "3 mēneši", "chat.delete_message_confirm": "Vai tiešām vēlies izdzēst šo sarunu?", "chat.retrieving-users": "Ielādē lietotājus...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Pārvaldīt tērzētavu", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Meklē lietotājus šeit. Izvēlētais lietotājs tiks pievienots sarunai. Jaunais lietotājs neredzēs sarunas, kas rakstītas pirms viņu pievienoja sarunai. Tikai tērzētavas īpašnieks(-i) var noņemt lietotājus no tērzētavām.", "chat.confirm-chat-with-dnd-user": "Lietotājs ir iestatījis savu statusu uz DnD (netraucējams). Vai Tu joprojām vēlies sarunāties ar viņu?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Pārdēvēt tērzētavu", "chat.rename-placeholder": "Ievadi savas tērzētavas nosaukumu šeit", "chat.rename-help": "Šeit norādītais tērzētavas nosaukums būs redzams visiem dalībniekiem.", - "chat.leave": "Pamest sarunu", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Vai tiešām vēlies pamest šo sarunu?", "chat.leave-help": "Atstājot šo sarunu, Tu tiksi noņemts no turpmākām sarunām. Ja Tu nākotnē atkārtoti pievienojies, Tu neredzēsi nevienu sarunu no pirms tā brīža.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Šajā tērzētavā", "chat.kick": "Izslēgt", "chat.show-ip": "Rādīt IP adresi", "chat.owner": "Tērzētavas īpašnieks", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Rediģēt", "composer.show_preview": "Rādīt priekšskatu", "composer.hide_preview": "Slēpt priekšskatu", diff --git a/public/language/lv/topic.json b/public/language/lv/topic.json index 8a177ee1b7..4f46a3b821 100644 --- a/public/language/lv/topic.json +++ b/public/language/lv/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ms/admin/admin.json b/public/language/ms/admin/admin.json index 413f97994a..aee71766f0 100644 --- a/public/language/ms/admin/admin.json +++ b/public/language/ms/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ms/admin/dashboard.json b/public/language/ms/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/ms/admin/dashboard.json +++ b/public/language/ms/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ms/admin/manage/categories.json b/public/language/ms/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/ms/admin/manage/categories.json +++ b/public/language/ms/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/ms/admin/manage/users.json b/public/language/ms/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/ms/admin/manage/users.json +++ b/public/language/ms/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ms/admin/menu.json b/public/language/ms/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/ms/admin/menu.json +++ b/public/language/ms/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/ms/admin/settings/chat.json b/public/language/ms/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ms/admin/settings/chat.json +++ b/public/language/ms/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ms/admin/settings/guest.json b/public/language/ms/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ms/admin/settings/guest.json +++ b/public/language/ms/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ms/email.json b/public/language/ms/email.json index ed309b518d..1b28462a1d 100644 --- a/public/language/ms/email.json +++ b/public/language/ms/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Kata laluan berjaya ditukar", "reset.notify.text1": "Pada %1, kata laluan anda berjaya ditukar.", "reset.notify.text2": "Sekiranya anda tidak pernah melakukannya, sila hubungi pendtadbir / admin dengan segera.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Topik terkini dari %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 4d4e15f518..ae3c3c686f 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Maaf, anda dikehendaki menunggu %1 saat() sebelum membuat kiriman pertama anda", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Kategori tidak wujud", "no-topic": "Topik tidak wujud", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistem reputasi dilumpuhkan.", "downvoting-disabled": "Undi turun dilumpuhkan", @@ -199,6 +200,7 @@ "not-in-room": "Pengguna tiada dalam bilik", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ms/global.json b/public/language/ms/global.json index 1d227f9c0f..c0662f0fca 100644 --- a/public/language/ms/global.json +++ b/public/language/ms/global.json @@ -51,6 +51,8 @@ "nextpage": "Laman berikut", "alert.success": "Berjaya", "alert.error": "Ralat", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Diharamkan", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 5cedf4f72e..2de5959ea1 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Anda tiada pesanan yang aktif", "chat.user_typing": "%1 menaip", "chat.user_has_messaged_you": "%1 mesej anda.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Sila pilih penerima untuk lihat sejarah sembang", @@ -27,22 +28,43 @@ "chat.three_months": "3 Bulan", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Tulis", "composer.show_preview": "Pra-lihat", "composer.hide_preview": "Sorok pra-lihat", diff --git a/public/language/ms/topic.json b/public/language/ms/topic.json index d2cded93be..98eb032da7 100644 --- a/public/language/ms/topic.json +++ b/public/language/ms/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/nb/admin/admin.json b/public/language/nb/admin/admin.json index 8ed4c165a2..df7e3493a5 100644 --- a/public/language/nb/admin/admin.json +++ b/public/language/nb/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/nb/admin/dashboard.json b/public/language/nb/admin/dashboard.json index 07ed80abde..902e55a91e 100644 --- a/public/language/nb/admin/dashboard.json +++ b/public/language/nb/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/nb/admin/manage/categories.json b/public/language/nb/admin/manage/categories.json index 0b33bd8602..98339a3cc5 100644 --- a/public/language/nb/admin/manage/categories.json +++ b/public/language/nb/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/nb/admin/manage/users.json b/public/language/nb/admin/manage/users.json index d5475117e4..65f1fd05a5 100644 --- a/public/language/nb/admin/manage/users.json +++ b/public/language/nb/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/nb/admin/menu.json b/public/language/nb/admin/menu.json index 3719330a90..8d057028a4 100644 --- a/public/language/nb/admin/menu.json +++ b/public/language/nb/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Brukere", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupper", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/nb/admin/settings/chat.json b/public/language/nb/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/nb/admin/settings/chat.json +++ b/public/language/nb/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/nb/admin/settings/guest.json b/public/language/nb/admin/settings/guest.json index 1d9d08f38e..760cb7000d 100644 --- a/public/language/nb/admin/settings/guest.json +++ b/public/language/nb/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Innstillinger ", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "Dette alternativet viser et nytt felt som lar gjestene velge et navn som kan knyttes til hvert innlegg de lager. Hvis de er deaktivert, vil de bare bli kalt \"Gjest\"", "topic-views.enabled": "La gjestene øke antall visninger av emner", diff --git a/public/language/nb/email.json b/public/language/nb/email.json index e36f798865..29e13b8e98 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Passordet ble endret", "reset.notify.text1": "Vi gjør deg oppmerksom på at du endret passordet ditt den %1.", "reset.notify.text2": "Hvis det ikke var deg som autoriserte dette, vennligst gi beskjed til en administrator umiddelbart.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Siste emner fra %1", "digest.top-topics": "Toppemner fra %1 ", "digest.popular-topics": "Populære emner fra %1", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index c33c8ba5a8..304381b1b2 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Beklager, denne kontoen har blit utestengt til %1 (Grunn: %2)", "user-too-new": "Beklager, du må vente %1 sekund(er) før du oppretter ditt første innlegg", "blacklisted-ip": "Beklager, din IP-adresse har blitt utestengt fra dette forumet. Hvis du mener dette er en feil, vennligst kontakt en sideadministrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Vennligst oppgi et sluttidspunkt for denne utestengingen.", "no-category": "Kategorien eksisterer ikke", "no-topic": "Emne eksisterer ikke", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Dette chatterommet finnes ikke.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du har allerede stemt på dette innlegget", "reputation-system-disabled": "Omdømmesystemet er deaktivert.", "downvoting-disabled": "Nedstemming er deaktivert", @@ -199,6 +200,7 @@ "not-in-room": "Bruker ikke i rom", "cant-kick-self": "Du kan ikke utestenge deg selv fra gruppen", "no-users-selected": "Ingen bruker(e) valgt", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ugyldig hjemmesidelenke", "invalid-session": "Ugyldig økt", "invalid-session-text": "Det ser ut til at din innloggingssesjon ikke lenger er aktiv. Last inn denne siden på nytt.", diff --git a/public/language/nb/global.json b/public/language/nb/global.json index d42357b63a..06bc657a13 100644 --- a/public/language/nb/global.json +++ b/public/language/nb/global.json @@ -51,6 +51,8 @@ "nextpage": "Neste side", "alert.success": "Suksess", "alert.error": "Feil", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Utestengt", "alert.banned.message": "Du har nettop blitt utestengt, din tilgang er nå begrenset.", "alert.unbanned": "Utestengelse opphevet", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 5153061778..5ecd45afe2 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har ingen aktive chatter.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har sendt deg en melding", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle chatter", "chat.mark_all_read": "Marker alle som lest", "chat.no-messages": "Vennligst velg en mottaker for å vise chatte-melding historikk", @@ -27,22 +28,43 @@ "chat.three_months": "3 måneder", "chat.delete_message_confirm": "Er du sikker på at du vil slette denne meldingen?", "chat.retrieving-users": "Henter brukere ...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Søk etter brukere her. Når dette er valgt, blir brukeren lagt til i chatten. Den nye brukeren vil ikke kunne se chatmeldinger skrevet før de ble lagt til i samtalen. Bare romeiere () kan fjerne brukere fra chatterom.", "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.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Komponer", "composer.show_preview": "Vis forhåndsvisning", "composer.hide_preview": "Skjul forhåndsvisning", diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 40b7c1520b..f63153bd45 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/nl/admin/admin.json b/public/language/nl/admin/admin.json index 8ac9574eb6..2f206bce67 100644 --- a/public/language/nl/admin/admin.json +++ b/public/language/nl/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/nl/admin/dashboard.json b/public/language/nl/admin/dashboard.json index 149c182e15..c68cfa7079 100644 --- a/public/language/nl/admin/dashboard.json +++ b/public/language/nl/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Actieve gebruikers", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/nl/admin/manage/categories.json b/public/language/nl/admin/manage/categories.json index 1a786831b4..0ef47bcb70 100644 --- a/public/language/nl/admin/manage/categories.json +++ b/public/language/nl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/nl/admin/manage/users.json b/public/language/nl/admin/manage/users.json index e1376724be..747a92d3b2 100644 --- a/public/language/nl/admin/manage/users.json +++ b/public/language/nl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/nl/admin/menu.json b/public/language/nl/admin/menu.json index 0b26226e19..ce63a54b14 100644 --- a/public/language/nl/admin/menu.json +++ b/public/language/nl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Gebruikers", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groepen", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/nl/admin/settings/chat.json b/public/language/nl/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/nl/admin/settings/chat.json +++ b/public/language/nl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/nl/admin/settings/guest.json b/public/language/nl/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/nl/admin/settings/guest.json +++ b/public/language/nl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/nl/email.json b/public/language/nl/email.json index 3d82870e7c..ab0f933f17 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Wachtwoord succesvol gewijzigd", "reset.notify.text1": "Op %1 is het wachtwoord van je account succesvol gewijzigd.", "reset.notify.text2": "Neem onmiddellijk contact met een beheerder op wanneer je hiervoor geen toestemming hebt gegeven.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "De meest recente onderwerpen van %1", "digest.top-topics": "Top onderwerpen van %1", "digest.popular-topics": "Populaire onderwerpen van %1", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index d9bd55dc51..19ec2babfc 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, dit account is verbannen tot %1 (Reden: %2)", "user-too-new": "Helaas, het is een vereiste om %1 seconde(n) te wachten voordat het eerste bericht geplaatst kan worden.", "blacklisted-ip": "Sorry, uw IP-adres is verbannen uit deze community. Als u meent dat dit onterecht is, neem dan contact op met een beheerder.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Geef een einddatum op voor deze ban.", "no-category": "Categorie bestaat niet", "no-topic": "Onderwerp bestaat niet", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "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", @@ -199,6 +200,7 @@ "not-in-room": "Gebruiker niet in de chat", "cant-kick-self": "Je kunt jezelf niet uit een groep schoppen", "no-users-selected": "Geen gebruiker(s) geselecteerd", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Onbekende homepage route", "invalid-session": "Ongeldige Sessie", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 3e208bdb2c..05eb82749d 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -51,6 +51,8 @@ "nextpage": "Volgende pagina", "alert.success": "Succes", "alert.error": "Fout", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Verbannen", "alert.banned.message": "Je bent net verbannen en je toegang is nu beperkt.", "alert.unbanned": "Verbanning opgeheven", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index 45b80e955c..dfd2fd9879 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Er zijn geen actieve chats.", "chat.user_typing": "%1 is aan het typen ...", "chat.user_has_messaged_you": "%1 heeft een bericht gestuurd", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle chats", "chat.mark_all_read": "Alles markeren als gelezen", "chat.no-messages": "Selecteer een ontvanger om de chatgeschiedenis in te zien", @@ -27,22 +28,43 @@ "chat.three_months": "3 maanden", "chat.delete_message_confirm": "Weet je zeker dat je dit bericht wilt verwijderen?", "chat.retrieving-users": "Gebruikers ophalen...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Chat Room beheren", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Zoek hier naar gebruikers. Indien geselecteerd word de gebruiker toegevoegd aan de chat. De nieuwe gebruiker kan geen chatberichten zien die geschreven zijn voordat de gebruiker was toegevoegd aan de conversatie. Alleen chatroom-eigenaren () kunnen gebruikers verwijderen uit een chatroom.", "chat.confirm-chat-with-dnd-user": "Deze gebruiker heeft de status op Niet Storen (DnD, Do not disturb) gezet. Wil je nog steeds een chat starten met deze persoon?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Hernoem chatroom", "chat.rename-placeholder": "Voer hier de naam van je chat room in", "chat.rename-help": "De naam van de chat room die je hier zet is zichtbaar voor alle deelnemers aan de chat.", - "chat.leave": "Verlaat Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Weet je zeker dat je deze chat wilt verlaten?", "chat.leave-help": "Als je de chat verlaat zul je toekomstige correspondentie in de chat niet meer zien. Als je later weer wordt toegevoegd, dan kun je de chat geschiedenis tot de hertoevoeging niet zien.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In deze chat room", "chat.kick": "Schop", "chat.show-ip": "Geef IP weer", "chat.owner": "Chatroom-eigenaar", - "chat.system.user-join": "%1 neemt nu deel aan de chatroom", - "chat.system.user-leave": "%1 heeft de chatroom verlaten", - "chat.system.room-rename": "%2 heeft deze chatroom hernoemd: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Samenstellen", "composer.show_preview": "Voorbeeldweergave", "composer.hide_preview": "Verberg voorbeeld", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index db0295d2c0..ee43c94b1c 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/pl/admin/admin.json b/public/language/pl/admin/admin.json index c4b06132ea..3611b28fba 100644 --- a/public/language/pl/admin/admin.json +++ b/public/language/pl/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pl/admin/dashboard.json b/public/language/pl/admin/dashboard.json index 570d48cfd0..6a635b8d08 100644 --- a/public/language/pl/admin/dashboard.json +++ b/public/language/pl/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Zablokowano przebudowę i restart, ponieważ wygląda na to, że nie uruchamiasz NodeBB poprzez właściwy serwis.", "maintenance-mode": "Tryb serwisowy", "maintenance-mode-title": "Kliknij tutaj, by skonfigurować tryb konserwacji dla NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Wykresy aktualizowane na żywo", "active-users": "Aktywni użytkownicy", @@ -89,5 +90,9 @@ "details.logins-login-time": "Czas logowania", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pl/admin/manage/categories.json b/public/language/pl/admin/manage/categories.json index 81f50eed3e..e45b15347d 100644 --- a/public/language/pl/admin/manage/categories.json +++ b/public/language/pl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Otaguj białą listę", "upload-image": "Prześlij obrazek", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Usuń", "category-image": "Obrazek kategorii", "image-and-icon": "Image & Icon", diff --git a/public/language/pl/admin/manage/users.json b/public/language/pl/admin/manage/users.json index fee09fa707..7cf406d251 100644 --- a/public/language/pl/admin/manage/users.json +++ b/public/language/pl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Usuń Użytkownika(ów) i Treści", "download-csv": "Pobierz CSV", "manage-groups": "Zarządzaj grupami", + "set-reputation": "Set Reputation", "add-group": "Dodaj grupę", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pl/admin/menu.json b/public/language/pl/admin/menu.json index 2e9bbc9cc6..bd5c68d512 100644 --- a/public/language/pl/admin/menu.json +++ b/public/language/pl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Użytkownicy", "manage/admins-mods": "Administratorzy i Moderatorzy", "manage/registration": "Kolejka rejestracji", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Kolejka postów", "manage/groups": "Grupy", "manage/ip-blacklist": "Czarna lista IP", diff --git a/public/language/pl/admin/settings/chat.json b/public/language/pl/admin/settings/chat.json index 7b0b5f2be6..a1223eca38 100644 --- a/public/language/pl/admin/settings/chat.json +++ b/public/language/pl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Wyłącz edycję/usuwanie wiadomości czat", "disable-editing-help": "Ograniczenie to nie dotyczy administratorów i moderatorów globalnych", "max-length": "Maksymalna długość wiadomości czat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksymalna liczba użytkowników w pokojach czatu", "delay": "Czas pomiędzy wiadomościami czat (w milisekundach)", "notification-delay": "Opóźnienie powiadomienia o wiadomościach na czacie. (0 bez opóźnienia)", diff --git a/public/language/pl/admin/settings/guest.json b/public/language/pl/admin/settings/guest.json index 7bb8cf219d..c18a0defe7 100644 --- a/public/language/pl/admin/settings/guest.json +++ b/public/language/pl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Ustawienia", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Zezwalaj gościom na podpisywanie się", "handles.enabled-help": "Opcja ta udostępnia gościom nowe pole, w którym mogą wybrać nazwę, pod jaką będą publikować posty. Jeśli opcja jest wyłączona, stosowana będzie po prostu nazwa „Gość”", "topic-views.enabled": "Zezwalaj gościom na zwiększenie liczbę wyświetleń tematu", diff --git a/public/language/pl/email.json b/public/language/pl/email.json index 13dd96a274..8b3ea2bfc8 100644 --- a/public/language/pl/email.json +++ b/public/language/pl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Hasło zmienione pomyślnie", "reset.notify.text1": "Informujemy, że Twoje hasło na %1 zostało zmienione.", "reset.notify.text2": "Jeśli nie wyraziłeś na to zgody, niezwłocznie poinformuj administratora.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ostatnie tematy z %1", "digest.top-topics": "Topowe tematy z %1", "digest.popular-topics": "Najpopularniejsze tematy z %1", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 8f9444dec4..d817abed20 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Przepraszamy, to konto zostało zbanowane do %1 (Powód: %2)", "user-too-new": "Przepraszamy, musisz odczekać %1 sekund(y) przed utworzeniem pierwszego posta", "blacklisted-ip": "Twój adres IP został zablokowany na tej społeczności. Jeśli uważasz to za błąd, zgłoś to administratorowi", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Wprowadź datę końca blokady", "no-category": "Kategoria nie istnieje", "no-topic": "Temat nie istnieje", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Już zagłosowałeś na ten post", "reputation-system-disabled": "System reputacji jest wyłączony.", "downvoting-disabled": "Negatywna ocena postów jest wyłączona", @@ -199,6 +200,7 @@ "not-in-room": "Użytkownika nie ma w pokoju", "cant-kick-self": "Nie możesz wyrzucić samego siebie z grupy", "no-users-selected": "Nie wybrano żadnych użytkowników", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Niepoprawny odnośnik strony domowej", "invalid-session": "Nieprawidłowa sesja", "invalid-session-text": "Wygląda na to, że Twoja sesja wygasła. Proszę odśwież stronę.", diff --git a/public/language/pl/global.json b/public/language/pl/global.json index eeb7a4e417..99c02c3cda 100644 --- a/public/language/pl/global.json +++ b/public/language/pl/global.json @@ -51,6 +51,8 @@ "nextpage": "Następna strona", "alert.success": "Udało się", "alert.error": "Błąd", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Ban", "alert.banned.message": "Zostałeś zbanowany i Twoje konto jest teraz w trybie ograniczonych możliwości", "alert.unbanned": "Odbanowany", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 320a089659..fec0d97f12 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Brak aktywnych czatów", "chat.user_typing": "%1 pisze...", "chat.user_has_messaged_you": "%1 napisał do Ciebie", + "chat.replying-to": "Replying to %1", "chat.see_all": "Wszystkie rozmowy", "chat.mark_all_read": "Zaznacz wszystkie jako przeczytane", "chat.no-messages": "Wybierz adresata, by wyświetlić historię czatów", @@ -27,22 +28,43 @@ "chat.three_months": "3 miesiące", "chat.delete_message_confirm": "Czy na pewno chcesz usunąć tę wiadomość?", "chat.retrieving-users": "Pobieram użytkowników...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Zarządzaj pokojami czatu", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu można wyszukiwać użytkowników. Wybrany użytkownik zostanie dodany do czatu. Nowy użytkownik nie zobaczy wiadomości sprzed dołączenia do konwersacji. Tylko właściciele pokoi () mogą usuwać użytkowników z pokoi czatu.", "chat.confirm-chat-with-dnd-user": "Ten użytkownik ustawił status „nie przeszkadzać”. Czy chcesz z nim rozmawiać mimo to?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Zmień nazwę pokoju", "chat.rename-placeholder": "Tu wpisz nazwę pokoju", "chat.rename-help": "Ustawiona tu nazwa pokoju będzie widoczna dla wszystkich obecnych w nim użytkowników.", - "chat.leave": "Opuść czat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Czy na pewno chcesz opuścić ten czat?", "chat.leave-help": "Opuszczając czat, tracisz dostęp do dalszej rozmowy na czacie. Jeśli w przyszłości zostaniesz znów dodany, nie zobaczysz historii czatu sprzed ponownego dołączenia.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "W tym pokoju", "chat.kick": "Wyrzuć", "chat.show-ip": "Pokaż IP", "chat.owner": "Właściciel pokoju", - "chat.system.user-join": "%1 dołączył(a) do pokoju", - "chat.system.user-leave": "%1 opuścił(a) pokój", - "chat.system.room-rename": "%2 zmienił(a) nazwę pokoju: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napisz", "composer.show_preview": "Pokaż podgląd", "composer.hide_preview": "Ukryj podgląd", diff --git a/public/language/pl/topic.json b/public/language/pl/topic.json index 9c265da6b4..52a1296339 100644 --- a/public/language/pl/topic.json +++ b/public/language/pl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/pt-BR/admin/admin.json b/public/language/pt-BR/admin/admin.json index 8af71123c1..313e12bbe3 100644 --- a/public/language/pt-BR/admin/admin.json +++ b/public/language/pt-BR/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/dashboard.json b/public/language/pt-BR/admin/dashboard.json index 43d8053f2e..5f67dcddcc 100644 --- a/public/language/pt-BR/admin/dashboard.json +++ b/public/language/pt-BR/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Recompilar e Reiniciar o seu NodeBB foi desativado, pois parece que você não está fazendo-o por meios apropriados.", "maintenance-mode": "Modo de Manutenção", "maintenance-mode-title": "Clique aqui para ativar o modo de manutenção do NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Atualização de Gráfico em Tempo Real", "active-users": "Usuários Ativos", @@ -89,5 +90,9 @@ "details.logins-login-time": "Hora de Login", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pt-BR/admin/manage/categories.json b/public/language/pt-BR/admin/manage/categories.json index 9ff41af7ed..a222c6f033 100644 --- a/public/language/pt-BR/admin/manage/categories.json +++ b/public/language/pt-BR/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Lista Branca de Tags", "upload-image": "Enviar Imagem", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remover", "category-image": "Imagem da Categoria", "image-and-icon": "Image & Icon", diff --git a/public/language/pt-BR/admin/manage/users.json b/public/language/pt-BR/admin/manage/users.json index 8b30173d39..86b3970b74 100644 --- a/public/language/pt-BR/admin/manage/users.json +++ b/public/language/pt-BR/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Excluir Usuário(s) e Conteúdo", "download-csv": "Baixar CSV", "manage-groups": "Gerenciar Grupos", + "set-reputation": "Set Reputation", "add-group": "Adicionar Grupo", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pt-BR/admin/menu.json b/public/language/pt-BR/admin/menu.json index 809b30d447..d4e8408367 100644 --- a/public/language/pt-BR/admin/menu.json +++ b/public/language/pt-BR/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Usuários", "manage/admins-mods": "Admins & Mods", "manage/registration": "Fila de Registro", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fila de Posts", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista Negra de IPs", diff --git a/public/language/pt-BR/admin/settings/chat.json b/public/language/pt-BR/admin/settings/chat.json index 710c1e29c4..29029d74ea 100644 --- a/public/language/pt-BR/admin/settings/chat.json +++ b/public/language/pt-BR/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Desabilitar editar/apagar mensagem ", "disable-editing-help": "Administradores e moderadores globais não sofrem esta restrição", "max-length": "Tamanho máximo das mensagens de chat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Número máximo de usuários nas salas de chat", "delay": "Tempo entre mensagens de chat em milisegundos", "notification-delay": "Tempo de espera para notificação de mensagens de bate-papo. (0 para não esperar)", diff --git a/public/language/pt-BR/admin/settings/guest.json b/public/language/pt-BR/admin/settings/guest.json index 8f2355f38f..6888fa5c17 100644 --- a/public/language/pt-BR/admin/settings/guest.json +++ b/public/language/pt-BR/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Configurações", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir que visitantes escolham um nome", "handles.enabled-help": "Esta opção mostra um novo campo que permite visitantes de escolher um nome para associar a cada post que eles fizerem. Se desabilitado, eles serão simplesmente chamados de \"Visitante\".", "topic-views.enabled": "Permitir que visitantes aumentem a contagem de visualizações do tópico", diff --git a/public/language/pt-BR/email.json b/public/language/pt-BR/email.json index cbbdcb074d..a608bc6a8d 100644 --- a/public/language/pt-BR/email.json +++ b/public/language/pt-BR/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Senha alterada com sucesso", "reset.notify.text1": "Nós estamos notificando você que em %1, sua senha foi alterada com sucesso.", "reset.notify.text2": "Se você não autorizou isso, por favor notifique um administrador imediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos tópicos de %1", "digest.top-topics": "Tópicos principais de %1", "digest.popular-topics": "Tópicos populares de %1", diff --git a/public/language/pt-BR/error.json b/public/language/pt-BR/error.json index 6c82763848..9fe4d4e34f 100644 --- a/public/language/pt-BR/error.json +++ b/public/language/pt-BR/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Desculpa, esta conta foi banida até %1 (Motivo: %2)", "user-too-new": "Desculpe, é necessário que você aguarde %1 segundo(s) antes de fazer o seu primeiro post.", "blacklisted-ip": "Desculpa, o seu endereço IP foi banido desta comunidade. Se você acha que isso é um engano, por favor, contate um administrador.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Por favor forneça uma data para o fim deste banimento", "no-category": "A categoria não existe", "no-topic": "O tópico não existe", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "A sala de chat não existe.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Você já votou neste post.", "reputation-system-disabled": "O sistema de reputação está desabilitado.", "downvoting-disabled": "Negativação está desabilitada", @@ -199,6 +200,7 @@ "not-in-room": "O usuário não está na sala", "cant-kick-self": "Você não pode kickar a si mesmo do grupo", "no-users-selected": "Nenhuma escolha de usuário(s) foi feita", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Rota de página inicial inválida", "invalid-session": "Sessão Inválida", "invalid-session-text": "Parece que a sua sessão de login não está mais ativa. Por favor, atualize esta página.", diff --git a/public/language/pt-BR/global.json b/public/language/pt-BR/global.json index 62330343be..af1aee0bf8 100644 --- a/public/language/pt-BR/global.json +++ b/public/language/pt-BR/global.json @@ -51,6 +51,8 @@ "nextpage": "Próxima Página", "alert.success": "Sucesso", "alert.error": "Erro", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banido", "alert.banned.message": "Você acaba de ser banido, seu acesso agora está restrito.", "alert.unbanned": "Des-banido", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 21dc86820d..7eff359ffc 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Você não tem chats ativos.", "chat.user_typing": "%1 está digitando ...", "chat.user_has_messaged_you": "%1 te enviou uma mensagem.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, escolha um destinatário para visualizar o histórico de conversas", @@ -27,22 +28,43 @@ "chat.three_months": "3 Meses", "chat.delete_message_confirm": "Tem certeza que deseja excluir esta mensagem?", "chat.retrieving-users": "Carregando usuários", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Salas de Conversa", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Pesquise usuários aqui. Quando selecionado, o usuário será adicionado ao chat. O novo usuário não poderá ver as mensagens de chat que foram enviadas antes de ele ser adicionado à conversa. Somente os donos de salas () podem remover usuários de salas de conversa.", "chat.confirm-chat-with-dnd-user": "Este usuário definiu seu estado como DnD(Do not disturb - Não perturbe). Você ainda assim quer conversar com ele?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renomear sala", "chat.rename-placeholder": "Digite o nome da sala aqui", "chat.rename-help": "O nome informado será visto por todos os participantes desta sala", - "chat.leave": "Sair da conversa", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Tem certeza que deseja sair da conversa?", "chat.leave-help": "Ao sair desta conversa você não receberá mais informações à respeito desta. Se você for adicionado novamente no futuro, você não poderá visualizar o histórico da conversa antes de sua re-entrada.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Nesta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", - "chat.system.user-join": "%1 entrou na sala", - "chat.system.user-leave": "%1 saiu da sala", - "chat.system.room-rename": "%2 renomeou esta sala: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compor", "composer.show_preview": "Exibir Pré-visualização", "composer.hide_preview": "Esconder Pré-visualização", diff --git a/public/language/pt-BR/topic.json b/public/language/pt-BR/topic.json index f1e68d9b62..bcd91e3566 100644 --- a/public/language/pt-BR/topic.json +++ b/public/language/pt-BR/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", @@ -203,7 +203,7 @@ "last-post": "Último post", "go-to-my-next-post": "Go to my next post", "no-more-next-post": "You don't have more posts in this topic", - "post-quick-reply": "Quick reply", + "post-quick-reply": "Resposta rápida", "navigator.index": "Post %1 of %2", "navigator.unread": "%1 unread" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/admin.json b/public/language/pt-PT/admin/admin.json index 19a58da812..8307aaa28f 100644 --- a/public/language/pt-PT/admin/admin.json +++ b/public/language/pt-PT/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/dashboard.json b/public/language/pt-PT/admin/dashboard.json index cc293b8c0f..5b97161633 100644 --- a/public/language/pt-PT/admin/dashboard.json +++ b/public/language/pt-PT/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Modo de Manutenção", "maintenance-mode-title": "Clica aqui para configurar o modo de manutenção para o teu NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Actualizar Gráfico em Tempo Real", "active-users": "Utilizadores Ativos", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pt-PT/admin/manage/categories.json b/public/language/pt-PT/admin/manage/categories.json index b12490364c..c076c33851 100644 --- a/public/language/pt-PT/admin/manage/categories.json +++ b/public/language/pt-PT/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Enviar Imagem", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remover", "category-image": "Imagem da Categoria", "image-and-icon": "Image & Icon", diff --git a/public/language/pt-PT/admin/manage/users.json b/public/language/pt-PT/admin/manage/users.json index 7cd1500112..948989505a 100644 --- a/public/language/pt-PT/admin/manage/users.json +++ b/public/language/pt-PT/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Eliminar Utilizador(es) e os seus Conteúdos", "download-csv": "Transferir CSV", "manage-groups": "Gerir Grupos", + "set-reputation": "Set Reputation", "add-group": "Adicionar Grupo", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pt-PT/admin/menu.json b/public/language/pt-PT/admin/menu.json index 02aa33f416..06371dae8d 100644 --- a/public/language/pt-PT/admin/menu.json +++ b/public/language/pt-PT/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utilizadores", "manage/admins-mods": "Administradores e Moderadores", "manage/registration": "Registos por Aprovar", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Publicações por Aprovar", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista Negra de IPs", diff --git a/public/language/pt-PT/admin/settings/chat.json b/public/language/pt-PT/admin/settings/chat.json index b68f84b072..e49504694e 100644 --- a/public/language/pt-PT/admin/settings/chat.json +++ b/public/language/pt-PT/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Desativar edtitar/apagar mensagens das conversas", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Comprimento máximo das mensagens nas conversas", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Número máximo de utilizadores nas salas de conversa", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/pt-PT/admin/settings/guest.json b/public/language/pt-PT/admin/settings/guest.json index 87ad4aa00d..4dfa11df73 100644 --- a/public/language/pt-PT/admin/settings/guest.json +++ b/public/language/pt-PT/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir nomes para visitantes", "handles.enabled-help": "Esta opção expôe um novo campo que permite a visitantes escolher um nome para associar a cada publicação que eles criem. Se desabilitada, eles simplesmente se chamarão \"Visitante\" ", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/pt-PT/email.json b/public/language/pt-PT/email.json index 6eb33c397a..5123fc6507 100644 --- a/public/language/pt-PT/email.json +++ b/public/language/pt-PT/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "A tua palavra-passe foi alterada com sucesso", "reset.notify.text1": "Estamos a notificar-te que a %1, a tua palavra-passe foi alterada com sucesso.", "reset.notify.text2": "Se não autorizaste isto, por favor notifica o administrador imediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Tópicos recentes de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index cd9fb18d08..7fb7c37596 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Desculpa, esta conta foi banida até %1 (Motivo: %2)", "user-too-new": "Desculpa, é necessário que esperes %1 segundo(s) antes de fazeres a tua primeira publicação", "blacklisted-ip": "Desculpa, o teu endereço IP foi banido desta comunidade. Se sentes que isto é um erro, por favor contacta o administrador.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Por favor providencia uma data para o fim deste banimento", "no-category": "Categoria não existente", "no-topic": "Tópico não existente", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Já votaste nesta publicação.", "reputation-system-disabled": "O sistema de reputação está desativado.", "downvoting-disabled": "Os votos negativos estão desativados", @@ -199,6 +200,7 @@ "not-in-room": "Utilizador não se encontra na sala", "cant-kick-self": "Não te podes expulsar a ti próprio do grupo", "no-users-selected": "Não existe(m) utilizador(es) selecionado(s)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Rota para a página principal inválida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/pt-PT/global.json b/public/language/pt-PT/global.json index 90f748267c..4d290521c9 100644 --- a/public/language/pt-PT/global.json +++ b/public/language/pt-PT/global.json @@ -51,6 +51,8 @@ "nextpage": "Página seguinte", "alert.success": "Sucesso", "alert.error": "Erro", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banido", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index 415bfbb6bc..6476c0ae9f 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Não tens conversas ativas.", "chat.user_typing": "%1 está a escrever ...", "chat.user_has_messaged_you": "%1 enviou-te uma mensagem.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor seleciona um destinatário para veres o histórico de mensagens", @@ -27,22 +28,43 @@ "chat.three_months": "3 meses", "chat.delete_message_confirm": "Tens a certeza que desejas apagar esta mensagem?", "chat.retrieving-users": "A recuperar utilizadores...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gerir sala de conversa", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "Este utilizador definiu o seu estado como \"não perturbar\". Pretendes mesmo assim conversar com ele?", + "chat.room-name-optional": "Room Name (Optional)", "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": "Sair da conversa", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Participantes nesta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", - "chat.system.user-join": "%1 entrou na sala", - "chat.system.user-leave": "%1 saiu da sala", - "chat.system.room-rename": "%2 renomeou esta sala: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compor", "composer.show_preview": "Mostrar pré-visualização", "composer.hide_preview": "Ocultar pré-visualização", diff --git a/public/language/pt-PT/topic.json b/public/language/pt-PT/topic.json index 474f6822b0..f3575fff06 100644 --- a/public/language/pt-PT/topic.json +++ b/public/language/pt-PT/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ro/admin/admin.json b/public/language/ro/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/ro/admin/admin.json +++ b/public/language/ro/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ro/admin/dashboard.json b/public/language/ro/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/ro/admin/dashboard.json +++ b/public/language/ro/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ro/admin/manage/categories.json b/public/language/ro/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/ro/admin/manage/categories.json +++ b/public/language/ro/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/ro/admin/manage/users.json b/public/language/ro/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/ro/admin/manage/users.json +++ b/public/language/ro/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ro/admin/menu.json b/public/language/ro/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/ro/admin/menu.json +++ b/public/language/ro/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/ro/admin/settings/chat.json b/public/language/ro/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ro/admin/settings/chat.json +++ b/public/language/ro/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ro/admin/settings/guest.json b/public/language/ro/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ro/admin/settings/guest.json +++ b/public/language/ro/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ro/email.json b/public/language/ro/email.json index e805de385d..d00213c89c 100644 --- a/public/language/ro/email.json +++ b/public/language/ro/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parola a fost schimbată cu succes", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ultimele mesaje de la %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index 3d5c6e2890..10ad1827b2 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Imi pare rau dar trebuie sa astepti %1 secunda(e) pentru a posta prima oara.", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Categoria nu exista.", "no-topic": "Topicul nu exista.", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistemul de reputație este dezactivat.", "downvoting-disabled": "Votarea negativă este dezactivată", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ro/global.json b/public/language/ro/global.json index be2a10447b..e87ecc00e0 100644 --- a/public/language/ro/global.json +++ b/public/language/ro/global.json @@ -51,6 +51,8 @@ "nextpage": "Următoarea Pagină", "alert.success": "Succes", "alert.error": "Eroare", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Banat", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 2ee45933fc..52887070c8 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nu ai nici o conversație activă", "chat.user_typing": "%1 scrie ...", "chat.user_has_messaged_you": "%1 ți-a trimis un mesaj.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Selectează un recipient pentru a vedea istoria mesajelor chat", @@ -27,22 +28,43 @@ "chat.three_months": "3 Luni", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Scrie", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/ro/topic.json b/public/language/ro/topic.json index dcc47d9645..0c9643ddf6 100644 --- a/public/language/ro/topic.json +++ b/public/language/ro/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ru/admin/admin.json b/public/language/ru/admin/admin.json index 2369366840..f6fae1cf93 100644 --- a/public/language/ru/admin/admin.json +++ b/public/language/ru/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ru/admin/dashboard.json b/public/language/ru/admin/dashboard.json index f5f5efe0f4..232816875c 100644 --- a/public/language/ru/admin/dashboard.json +++ b/public/language/ru/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Пересборка и перезапуск вашего NodeBB была отключена, поскольку вы запустили форум без использования соответствующего демона.", "maintenance-mode": "Режим техобслуживания", "maintenance-mode-title": "Нажмите, чтобы включить и настроить режим техобслуживания", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Обновление графиков в реальном времени", "active-users": "Активных посетителей", @@ -89,5 +90,9 @@ "details.logins-login-time": "Время входа", "start": "Начало", "end": "Окончание", - "filter": "Фильтр" + "filter": "Фильтр", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ru/admin/manage/categories.json b/public/language/ru/admin/manage/categories.json index 02bada0fc5..49ae61f61e 100644 --- a/public/language/ru/admin/manage/categories.json +++ b/public/language/ru/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Разрешенный список меток", "upload-image": "Загрузить изображение", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Удалить", "category-image": "Изображение категории", "image-and-icon": "Image & Icon", diff --git a/public/language/ru/admin/manage/users.json b/public/language/ru/admin/manage/users.json index 17fc3343ab..ac9fa0e2da 100644 --- a/public/language/ru/admin/manage/users.json +++ b/public/language/ru/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Удалить пользователя(-ей) и данные", "download-csv": "Скачать CSV", "manage-groups": "Изменить членство в группах", + "set-reputation": "Set Reputation", "add-group": "Добавить группу", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ru/admin/menu.json b/public/language/ru/admin/menu.json index 86b57b11d9..0c10ad9f1a 100644 --- a/public/language/ru/admin/menu.json +++ b/public/language/ru/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Пользователи", "manage/admins-mods": "Администраторы и модераторы", "manage/registration": "Очередь на регистрацию", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Очередь на публикацию", "manage/groups": "Группы", "manage/ip-blacklist": "Чёрный список IP", diff --git a/public/language/ru/admin/settings/chat.json b/public/language/ru/admin/settings/chat.json index d34673dfcc..5e9f017bb3 100644 --- a/public/language/ru/admin/settings/chat.json +++ b/public/language/ru/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Отключить редактирование и удаление сообщений чата", "disable-editing-help": "Администраторы и общие модераторы освобождены от этого ограничения.", "max-length": "Максимальная длина сообщений в чате", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Максимальное кол-во пользователей в чат-комнатах", "delay": "Пауза между сообщениями (в миллисекундах)", "notification-delay": "Задержка уведомления для сообщений чата. (0 без задержки)", diff --git a/public/language/ru/admin/settings/guest.json b/public/language/ru/admin/settings/guest.json index 40b14618e2..36e489cc74 100644 --- a/public/language/ru/admin/settings/guest.json +++ b/public/language/ru/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Настройки", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Разрешить гостям выбирать имена", "handles.enabled-help": "Эта настройка добавляет поле, в котором гость сможет указать имя, под которым он хочет оставить сообщение. Когда она выключена, вместо имени будет написано просто «Гость».", "topic-views.enabled": "Разрешить гостям увеличивать количество просмотров тем", diff --git a/public/language/ru/email.json b/public/language/ru/email.json index 6c010cff83..94a15a0dd0 100644 --- a/public/language/ru/email.json +++ b/public/language/ru/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Пароль был успешно изменён", "reset.notify.text1": "Мы уведомляем вас о том, что %1 ваш пароль был успешно изменён.", "reset.notify.text2": "Если вы не совершали этого действия, пожалуйста, незамедлительно свяжитесь с администратором сайта.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Последние темы на форуме %1", "digest.top-topics": "Лучшие темы на форуме %1", "digest.popular-topics": "Популярные темы из %1", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 632118b8c5..f21a9bcf0a 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Извините, эта учётная запись заблокирована до %1 (Причина: %2)", "user-too-new": "Вы сможете написать своё первое сообщение через %1 сек.", "blacklisted-ip": "Извините, ваш IP адрес был заблокирован этим сообществом. Если вы считаете, что это ошибка, пожалуйста, свяжитесь с администратором.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Пожалуйста, укажите дату окончания этой блокировки", "no-category": "Такой категории не существует", "no-topic": "Такой темы не существует", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Комната чата не существует.", "cant-add-users-to-chat-room": "Нельзя добавить пользователей в комнату.", "cant-remove-users-from-chat-room": "Нельзя удалять пользователей из комнаты.", - "chat-room-name-too-long": "Название чат комнаты слишком длинное, пожалуйста, сократите его.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Вы уже проголосовали за это сообщение.", "reputation-system-disabled": "Система репутации отключена.", "downvoting-disabled": "Понижение рейтинга отключено", @@ -199,6 +200,7 @@ "not-in-room": "Пользователь отсутствует в этой комнате", "cant-kick-self": "Удалить себя из группы невозможно.", "no-users-selected": "Выберите одного или нескольких пользователей", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Неверная ссылка на домашнюю страницу", "invalid-session": "Недействительная сессия", "invalid-session-text": "Похоже, что ваша сессия входа больше не активна. Пожалуйста, обновите эту страницу.", diff --git a/public/language/ru/global.json b/public/language/ru/global.json index 403d50641e..329cf98c00 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -51,6 +51,8 @@ "nextpage": "Следующая страница", "alert.success": "Успешно", "alert.error": "Ошибка", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Заблокирован", "alert.banned.message": "Вас только что заблокировали, теперь ваш доступ ограничен.", "alert.unbanned": "Разблокирован", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 11f8cacca4..dbe91982a9 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "У вас нет активных чатов.", "chat.user_typing": "%1 пишет...", "chat.user_has_messaged_you": "Пользователь %1 отправил вам сообщение.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Все чаты", "chat.mark_all_read": "Пометить как прочитанное", "chat.no-messages": "Пожалуйста, выберите собеседника для просмотра истории сообщений", @@ -27,22 +28,43 @@ "chat.three_months": "3 месяца", "chat.delete_message_confirm": "Вы уверены, что хотите удалить это сообщение?", "chat.retrieving-users": "Получение списка пользователей...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управлять комнатой чата", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Поиск пользователей здесь. Когда выбрали пользователя, он будет добавлен в чат. Новый пользователь не сможет видеть сообщения чата, написанные до его добавления в беседу. Только владельцы комнат () могут удалить пользователей из чатов.", "chat.confirm-chat-with-dnd-user": "Этот пользователь установил статус \"Не беспокоить\". Вы всё еще хотите написать ему?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Переименовать комнату", "chat.rename-placeholder": "Введите название комнаты здесь", "chat.rename-help": "Название комнаты, установленное здесь, будет доступно для просмотра всеми участниками комнаты.", - "chat.leave": "Покинуть чат", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Вы действительно хотите покинуть чат?", "chat.leave-help": "Оставив этот чат, вы удалите себя из будущей переписки в этом чате. Если вы будете повторно добавлены в будущем, вы не увидите истории чата до вашего повторного присоединения.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "В этой комнате", "chat.kick": "Исключить", "chat.show-ip": "Показать IP", "chat.owner": "Владелец комнаты", - "chat.system.user-join": "%1 присоединился к беседе", - "chat.system.user-leave": "%1 покинул беседу", - "chat.system.room-rename": "%2 переименовал беседу: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Редактор сообщений", "composer.show_preview": "Показать предпросмотр сообщения", "composer.hide_preview": "Скрыть предпросмотр", diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index 3b4f4c88ed..4936adcc0d 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "написал ", "wrote-on": "написал в ", "replied-to-user-ago": "ответил %3 ", - "replied-to-user-on": "ответил %3 в ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 закрыл эту тему %2", "user-locked-topic-on": "%1 закрыл эту тему в %2", "user-unlocked-topic-ago": "%1 открыл эту тему %2", diff --git a/public/language/rw/admin/admin.json b/public/language/rw/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/rw/admin/admin.json +++ b/public/language/rw/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/rw/admin/dashboard.json b/public/language/rw/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/rw/admin/dashboard.json +++ b/public/language/rw/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/rw/admin/manage/categories.json b/public/language/rw/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/rw/admin/manage/categories.json +++ b/public/language/rw/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/rw/admin/manage/users.json b/public/language/rw/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/rw/admin/manage/users.json +++ b/public/language/rw/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/rw/admin/menu.json b/public/language/rw/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/rw/admin/menu.json +++ b/public/language/rw/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/rw/admin/settings/chat.json b/public/language/rw/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/rw/admin/settings/chat.json +++ b/public/language/rw/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/rw/admin/settings/guest.json b/public/language/rw/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/rw/admin/settings/guest.json +++ b/public/language/rw/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/rw/email.json b/public/language/rw/email.json index 5c1e305db6..2bb545eb3f 100644 --- a/public/language/rw/email.json +++ b/public/language/rw/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Ijambobanga ryahinduwe nta ngorane", "reset.notify.text1": "Turakumenyesha ko kuri %1, ijambobanga wakoreshaga ryahinduwe nk'uko byari byasabwe.", "reset.notify.text2": "Niba atari wowe wari wabisabye ku bushake bwawe, bimenyeshe umuyobozi w'urubuga aka kanya. ", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ibiganiro biheruka bya %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index 404e69bb7f..c71287e9e8 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Wihangena kuko usabwa gutegereza amasegonda (isegonda) %1 mbere yo gushyiraho ikintu cyawe cya mbere", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Icyiciro kitabaho", "no-topic": "Ikiganiro kitabaho", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Ibijyanye n'itangwa ry'amanota ntibyemerewe. ", "downvoting-disabled": "Kwambura amanota ntibyemerewe", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/rw/global.json b/public/language/rw/global.json index 6a74db4476..b0b0e062c6 100644 --- a/public/language/rw/global.json +++ b/public/language/rw/global.json @@ -51,6 +51,8 @@ "nextpage": "Paji Ikurikira", "alert.success": "Byaciyemo", "alert.error": "Byanze", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Birukanwe", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index d47842ab0f..e362fcb911 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nta biganiro byo mu gikari ufite. ", "chat.user_typing": "%1 ari kwandika ...", "chat.user_has_messaged_you": "%1 yagusigiye ubutumwa.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Hitamo umuntu ushaka kurebera ibyo mwandikiranye", @@ -27,22 +28,43 @@ "chat.three_months": "Amezi 3", "chat.delete_message_confirm": "Wiringiye neza ko ushaka gusiba ubu butumwa?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Andika", "composer.show_preview": "Bona Uko Biza Gusa", "composer.hide_preview": "Hisha Uko Biza Gusa", diff --git a/public/language/rw/topic.json b/public/language/rw/topic.json index 6957755a88..9d69c81546 100644 --- a/public/language/rw/topic.json +++ b/public/language/rw/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sc/admin/admin.json b/public/language/sc/admin/admin.json index 89e08402cd..96c58b1733 100644 --- a/public/language/sc/admin/admin.json +++ b/public/language/sc/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sc/admin/dashboard.json b/public/language/sc/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/sc/admin/dashboard.json +++ b/public/language/sc/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sc/admin/manage/categories.json b/public/language/sc/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sc/admin/manage/categories.json +++ b/public/language/sc/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sc/admin/manage/users.json b/public/language/sc/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sc/admin/manage/users.json +++ b/public/language/sc/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sc/admin/menu.json b/public/language/sc/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sc/admin/menu.json +++ b/public/language/sc/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sc/admin/settings/chat.json b/public/language/sc/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sc/admin/settings/chat.json +++ b/public/language/sc/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sc/admin/settings/guest.json b/public/language/sc/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sc/admin/settings/guest.json +++ b/public/language/sc/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sc/email.json b/public/language/sc/email.json index 9f748a2e61..3e35d7514c 100644 --- a/public/language/sc/email.json +++ b/public/language/sc/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index b4b0db8f20..9ec0963641 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Please provide an end date for this ban", "no-category": "Category does not exist", "no-topic": "Topic does not exist", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", @@ -199,6 +200,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sc/global.json b/public/language/sc/global.json index 40e9988659..4349e6ebad 100644 --- a/public/language/sc/global.json +++ b/public/language/sc/global.json @@ -51,6 +51,8 @@ "nextpage": "Pàgina chi Sighit", "alert.success": "Andat Bene", "alert.error": "Faddina", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Blocadu", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index 24a6c6a64f..cdf15aa3d9 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non tenes tzarras ativas.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", @@ -27,22 +28,43 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "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.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/sc/topic.json b/public/language/sc/topic.json index 809f67530f..a179e7ff4e 100644 --- a/public/language/sc/topic.json +++ b/public/language/sc/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sk/admin/admin.json b/public/language/sk/admin/admin.json index b8c7612a9a..46a378cdb6 100644 --- a/public/language/sk/admin/admin.json +++ b/public/language/sk/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sk/admin/dashboard.json b/public/language/sk/admin/dashboard.json index ae3ed5b1e9..d30f11dbc7 100644 --- a/public/language/sk/admin/dashboard.json +++ b/public/language/sk/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Znovu zostavenie a reštartovanie vášho NodeBB bolo zablokované, pretože sa nezdá, že ste bol pripojený cez príslušného „daemona”.", "maintenance-mode": "Režim údržby", "maintenance-mode-title": "Pre nastavenia režimu údržby NodeBB, kliknite sem", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Aktualizácie grafov v reálnom čase", "active-users": "Aktívny užívatelia", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sk/admin/manage/categories.json b/public/language/sk/admin/manage/categories.json index b78a199d98..9dc3cc8829 100644 --- a/public/language/sk/admin/manage/categories.json +++ b/public/language/sk/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Nahrať obrázok", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Odobrať", "category-image": "Obrázok kategórie", "image-and-icon": "Image & Icon", diff --git a/public/language/sk/admin/manage/users.json b/public/language/sk/admin/manage/users.json index b1577d230e..d6493bbf0a 100644 --- a/public/language/sk/admin/manage/users.json +++ b/public/language/sk/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Stiahnuť ako CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sk/admin/menu.json b/public/language/sk/admin/menu.json index d8f14024b0..c4b095b963 100644 --- a/public/language/sk/admin/menu.json +++ b/public/language/sk/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Používatelia", "manage/admins-mods": "Správcovia a moderátori", "manage/registration": "Registračná fronta", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fronta príspevkov", "manage/groups": "Skupiny", "manage/ip-blacklist": "Čierny zoznam IP adries", diff --git a/public/language/sk/admin/settings/chat.json b/public/language/sk/admin/settings/chat.json index d6ccdb4f2d..4ba4b96ed5 100644 --- a/public/language/sk/admin/settings/chat.json +++ b/public/language/sk/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Zakázať upravenie/odstránenie konverzačnej správy", "disable-editing-help": "Správcovia a globálny moderátori sú vyňatí z tohto obmedzenia", "max-length": "Maximálna dĺžka konverzačnej správy", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximálny počet používateľov v konverzačnej miestnosti", "delay": "Čas medzi konverzačnými správami v milisekundách", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sk/admin/settings/guest.json b/public/language/sk/admin/settings/guest.json index c366f3e35e..bb1633e743 100644 --- a/public/language/sk/admin/settings/guest.json +++ b/public/language/sk/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Povoliť upravovanie zaobchádzania s hosťami", "handles.enabled-help": "Táto možnosť odkryje nové pole, ktoré umožňuje hosťom vybrať meno, ktoré sa pripojí ku každému príspevku, ktorý vytvorí. Ak bude zakázané, budú jednoducho nazývaní 'Hosť'", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sk/email.json b/public/language/sk/email.json index daaa6d84fe..416a278a74 100644 --- a/public/language/sk/email.json +++ b/public/language/sk/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Heslo bolo úspešne zmenené", "reset.notify.text1": "Oznamujeme Vám že %1, bolo Vaše heslo úspešne zmenené.", "reset.notify.text2": "Ak ste o to nežiadali, kontaktujte čo najskôr správcu.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Najnovšie témy od %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 8132e52263..647f3d03d2 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Ospravedlňujeme sa, tento účet bol zablokovaný do %1 (Dôvod: %2)", "user-too-new": "Prepáčte, musíte počkať %1 sekúnd(y) predtým, ako vytvoríte svoj prvý príspevok", "blacklisted-ip": "Prepáčte, ale vaša IP adresa bola na tejto komunite zablokovaná. Ak sa cítite poškodený, prosím kontaktujte správcu.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Prosím uveďte dátum ukončenia tohto zablokovania", "no-category": "Kategória neexistuje", "no-topic": "Téma neexistuje", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Za tento príspevok ste už hlasovali.", "reputation-system-disabled": "Systém reputácie je zablokovaný.", "downvoting-disabled": "Hlasovanie proti je zablokované", @@ -199,6 +200,7 @@ "not-in-room": "Užívateľ nie je v miestnosti", "cant-kick-self": "Nemôžete vykopnúť samého seba zo skupiny", "no-users-selected": "Žiadny užívateľ(ia) neboli vybratý", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Neplatná cesta pre domovskú stránku", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sk/global.json b/public/language/sk/global.json index 19b7985493..f45c6a4223 100644 --- a/public/language/sk/global.json +++ b/public/language/sk/global.json @@ -51,6 +51,8 @@ "nextpage": "Nasledujúca strana", "alert.success": "Výsledok", "alert.error": "Chyba", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Zablokovaný", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index abb7e3e49c..e214558f6f 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemáte žiadne aktívne konverzácie.", "chat.user_typing": "%1 práve píše...", "chat.user_has_messaged_you": "%1 Vám poslal správu.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Prosím vyberte príjemcu, pre zobrazenie histórie správ v konverzácií", @@ -27,22 +28,43 @@ "chat.three_months": "3 mesiace", "chat.delete_message_confirm": "Ste si istý, že chcete odstrániť túto správu?", "chat.retrieving-users": "Získavanie zoznamu používateľov...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovať konverzačné miestnosti", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu môžete vyhľadávať používateľov. Akonáhle si ho vyberiete, užívateľ bude pridaný do konverzácie. Nový používateľ nebude mať možnosť čítať správy, ktoré boli napísané skôr, ako bol pridaný do konverzácie. Iba majitelia miestnosti () môžu odobrať používateľov z konverzačných miestností.", "chat.confirm-chat-with-dnd-user": "Tento používateľ nastavil svoj stav na NERUŠIŤ. Naozaj chcete s ním začať konverzáciu?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Premenovať miestnosť", "chat.rename-placeholder": "Sem zadajte názov miestnosti", "chat.rename-help": "Názov miestnosti zadaný sem, bude viditeľný pre všetkých účastníkov komunikácie v miestnosti", - "chat.leave": "Opustiť konverzáciu", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ste si istý, že chcete ukončiť túto konverzáciu?", "chat.leave-help": "Ukončením tejto konverzácie budete odstránený z budúcej komunikácie v tejto konverzácií. Ak budete následne znovu pridaný, neuvidíte históriu komunikácie od Vášho odchodu.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "V tejto miestnosti", "chat.kick": "Vykopnúť", "chat.show-ip": "Zobraziť IP adresu", "chat.owner": "Majiteľ miestnosti", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napísať", "composer.show_preview": "Zobraziť náhľad", "composer.hide_preview": "Skryť náhľad", diff --git a/public/language/sk/topic.json b/public/language/sk/topic.json index 7d9be5a489..61418318df 100644 --- a/public/language/sk/topic.json +++ b/public/language/sk/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sl/admin/admin.json b/public/language/sl/admin/admin.json index 84f479a2bc..9c98de272f 100644 --- a/public/language/sl/admin/admin.json +++ b/public/language/sl/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sl/admin/dashboard.json b/public/language/sl/admin/dashboard.json index ec11deb636..0e64701cd0 100644 --- a/public/language/sl/admin/dashboard.json +++ b/public/language/sl/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Obnova in ponovni zagon vašega NodeBB sta onemogočena, saj se zdi, da ga ne izvajate prek ustreznega prikritega procesa.", "maintenance-mode": "Način vzdrževanja", "maintenance-mode-title": "Za nastavitev načina vzdrževanja za NodeBB kliknite tukaj", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Posodobitev grafikona v realnem času", "active-users": "Aktivni uporabniki", @@ -89,5 +90,9 @@ "details.logins-login-time": "Čas prijave", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sl/admin/manage/categories.json b/public/language/sl/admin/manage/categories.json index d2c96483be..c6da77d39b 100644 --- a/public/language/sl/admin/manage/categories.json +++ b/public/language/sl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Bela lista oznak", "upload-image": "Naloži sliko", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Odstrani", "category-image": "Slika kategorije", "image-and-icon": "Image & Icon", diff --git a/public/language/sl/admin/manage/users.json b/public/language/sl/admin/manage/users.json index c20a749a9f..b7604c0d00 100644 --- a/public/language/sl/admin/manage/users.json +++ b/public/language/sl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Izbrišiteuporabnika(e) in vsebino", "download-csv": "Prenesite CSV", "manage-groups": "Upravljaj skupine", + "set-reputation": "Set Reputation", "add-group": "Dodaj skupino", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sl/admin/menu.json b/public/language/sl/admin/menu.json index 37609ee221..0cf578c4ad 100644 --- a/public/language/sl/admin/menu.json +++ b/public/language/sl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Uporabniki", "manage/admins-mods": "Skrbniki in moderatorji", "manage/registration": "Čakalna vrsta registracij", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Čakalna vrsta objav", "manage/groups": "Skupine", "manage/ip-blacklist": "IP črna lista", diff --git a/public/language/sl/admin/settings/chat.json b/public/language/sl/admin/settings/chat.json index 95d7342274..1cf30fe6bd 100644 --- a/public/language/sl/admin/settings/chat.json +++ b/public/language/sl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Onemogoči urejanje/brisanje sporočila klepeta", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Največja dolžina sporočila klepeta", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sl/admin/settings/guest.json b/public/language/sl/admin/settings/guest.json index a01f6934f3..c974a34ef5 100644 --- a/public/language/sl/admin/settings/guest.json +++ b/public/language/sl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Nastavitve", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sl/email.json b/public/language/sl/email.json index cd775ca7e0..bcf7936a0d 100644 --- a/public/language/sl/email.json +++ b/public/language/sl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Geslo je bilo uspešno spremenjeno.", "reset.notify.text1": "Obveščamo vas, da je bilo na forumu %1 uspešno spremenjeno vaše geslo.", "reset.notify.text2": "Če tega niste zahtevali, prosimo, da nemudoma obvestite skrbnika.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Zadnje teme na forumu %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index 3a9cb5ea47..8841ddfcae 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", "user-too-new": " Pred svojo prvo objavo počakajte %1 s.", "blacklisted-ip": "Vaš IP-naslov je izločen. Povprašajte skrbnika za več informacij.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Vnesite končni datum za to izločitev.", "no-category": "Kategorija ne obstaja.", "no-topic": "Tema ne obstaja.", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Za to objavo ste že glasovali.", "reputation-system-disabled": "Sistem za ugled je onemogočen.", "downvoting-disabled": "Negativno glasovanje je onemogočeno.", @@ -199,6 +200,7 @@ "not-in-room": "Uporabnika ni v sobi.", "cant-kick-self": "Sebe ne morete umakniti iz skupine.", "no-users-selected": "Ni izbranih uporabnikov.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Napačna pot do domače strani.", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sl/global.json b/public/language/sl/global.json index 4b41669603..3e1aa48afa 100644 --- a/public/language/sl/global.json +++ b/public/language/sl/global.json @@ -51,6 +51,8 @@ "nextpage": "Naslednja stran", "alert.success": "Uspešno", "alert.error": "Napaka", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Izločen", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index 213f3f373c..ae36dac325 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ni aktivnih klepetov.", "chat.user_typing": "%1 piše sporočilo ...", "chat.user_has_messaged_you": "%1 ti je poslal/-a sporočilo.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Za pregled zgodovine klepeta izberi prejemnika.", @@ -27,22 +28,43 @@ "chat.three_months": "3 meseci", "chat.delete_message_confirm": "Ali ste prepričani, da želite izbrisati to sporočilo?", "chat.retrieving-users": "Pridobivanje uporabnikov...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Upravljaj sobo klepeta", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Zapusti klepet", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ste prepričani, da želite zapustiti ta klepet?", "chat.leave-help": "Če zapustite ta klepet boste izključeni iz prihodnje korespondence v tem klepetu. Če boste v prihodnosti v klepet znova dodani, ne boste videli zgodovine klepeta pred ponovno pridružitvijo.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Pokaži IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sestavljanje", "composer.show_preview": "Pokaži predogled", "composer.hide_preview": "Skrij predogled", diff --git a/public/language/sl/topic.json b/public/language/sl/topic.json index 6da76ee923..c70112203d 100644 --- a/public/language/sl/topic.json +++ b/public/language/sl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sq-AL/admin/admin.json b/public/language/sq-AL/admin/admin.json index c9430ce3da..299d08b5b9 100644 --- a/public/language/sq-AL/admin/admin.json +++ b/public/language/sq-AL/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sq-AL/admin/dashboard.json b/public/language/sq-AL/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/sq-AL/admin/dashboard.json +++ b/public/language/sq-AL/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sq-AL/admin/manage/categories.json b/public/language/sq-AL/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sq-AL/admin/manage/categories.json +++ b/public/language/sq-AL/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sq-AL/admin/manage/users.json b/public/language/sq-AL/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sq-AL/admin/manage/users.json +++ b/public/language/sq-AL/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sq-AL/admin/menu.json b/public/language/sq-AL/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sq-AL/admin/menu.json +++ b/public/language/sq-AL/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sq-AL/admin/settings/chat.json b/public/language/sq-AL/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sq-AL/admin/settings/chat.json +++ b/public/language/sq-AL/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sq-AL/admin/settings/guest.json b/public/language/sq-AL/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sq-AL/admin/settings/guest.json +++ b/public/language/sq-AL/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sq-AL/email.json b/public/language/sq-AL/email.json index efba38a58b..991fbbe5cf 100644 --- a/public/language/sq-AL/email.json +++ b/public/language/sq-AL/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Fjalëkalimi u ndryshua me sukses", "reset.notify.text1": "Po ju njoftojmë se në %1, fjalëkalimi juaj u ndryshua me sukses.", "reset.notify.text2": "Nëse nuk e keni autorizuar këtë, ju lutemi njoftoni menjëherë një administrator të VIAL.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Temat e fundit nga %1", "digest.top-topics": "Temat kryesore nga %1", "digest.popular-topics": "Tema të njohura nga %1", diff --git a/public/language/sq-AL/error.json b/public/language/sq-AL/error.json index 88b27422ba..757a28b5a1 100644 --- a/public/language/sq-AL/error.json +++ b/public/language/sq-AL/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Na vjen keq, kjo llogari është pezulluar deri më %1 (Arsyeja: %2)", "user-too-new": "Na vjen keq, ju duhet të prisni %1 sekond(a) përpara se të bëni postimin tuaj të parë", "blacklisted-ip": "Na vjen keq, por adresa juaj IP është bllokuar nga ky komunitet. Nëse mendoni se ka një gabim, ju lutemi kontaktoni një administrator të VIAL.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Ju lutemi jepni një datë përfundimi për këtë pezullim", "no-category": "Kategoria nuk ekziston", "no-topic": "Tema nuk ekziston", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Kjo dhomë bisede nuk ekziston.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ju keni votuar tashmë për këtë postim.", "reputation-system-disabled": "Sistemi i reputacionit është i çaktivizuar.", "downvoting-disabled": "Votimi kundër është i çaktivizuar", @@ -199,6 +200,7 @@ "not-in-room": "Përdoruesi nuk është në dhomën e bisedës", "cant-kick-self": "Nuk mund ta largosh veten nga grupi", "no-users-selected": "Nuk është zgjedhur asnjë përdorues()", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Link i pavlefshëm", "invalid-session": "Sesion i pavlefshëm", "invalid-session-text": "Duket sikur sesioni juaj i hyrjes nuk është më aktiv. Ju lutemi rifreskojeni këtë faqe.", diff --git a/public/language/sq-AL/global.json b/public/language/sq-AL/global.json index 6d5562d732..6eb4e3654d 100644 --- a/public/language/sq-AL/global.json +++ b/public/language/sq-AL/global.json @@ -51,6 +51,8 @@ "nextpage": "Faqja tjetër", "alert.success": "Sukses", "alert.error": "Gabim", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "I ndaluar", "alert.banned.message": "Sapo je ndaluar, aksesi jot tani është i kufizuar.", "alert.unbanned": "E pandaluar", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index 4a9f23adbd..ba73c8990f 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ju nuk keni biseda aktive.", "chat.user_typing": "%1 është duke shkruajtur...", "chat.user_has_messaged_you": "%1 ju ka dërguar mesazh.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Ju lutemi zgjidhni një person për të parë historikun e mesazheve të bisedës", @@ -27,22 +28,43 @@ "chat.three_months": "3 Muaj", "chat.delete_message_confirm": "A je i sigurt që dëshiron ta fshihni këtë mesazh?", "chat.retrieving-users": "Duke marrë përdoruesit...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Menaxho hapësirën e bisedave", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Kërkoni për përdoruesit këtu. Kur zgjidhet, përdoruesi do të shtohet në bisedë. Përdoruesi i ri nuk do të jetë në gjendje të shohë mesazhet e bisedës të shkruara përpara se të shtoheshin në bisedë. Vetëm krijuesit e bisedes () mund të heqin përdoruesit nga hapesirat e bisedës.", "chat.confirm-chat-with-dnd-user": "Ky përdorues ka vendosur statusin e tij në (Mos shqetëso). Dëshiron ende të bisedosh me ta?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Riemërto dhomën", "chat.rename-placeholder": "Shkruani emrin e dhomës tuaj këtu", "chat.rename-help": "Emri i dhomës i vendosur këtu do të jetë i dukshëm nga të gjithë pjesëmarrësit në dhomë.", - "chat.leave": "Largohu nga biseda", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Jeni i sigurt që dëshironi të largoheni nga kjo bisedë?", "chat.leave-help": "Largimi nga kjo bisedë do t'ju heqë nga korrespondenca e ardhshme në këtë bisedë. Nëse do të rishtoheni në të ardhmen, nuk do të shihni asnjë histori bisede nga para ribashkimit.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Në këtë dhomë", "chat.kick": "Largo", "chat.show-ip": "Shfaq IP", "chat.owner": "Administratori i hapësirës", - "chat.system.user-join": "%1 i është bashkuar hapësirës", - "chat.system.user-leave": "%1 ka dalë nga hapësira", - "chat.system.room-rename": "%2 e ka riemërtuar këtë hapësirë: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Harto", "composer.show_preview": "Shiko rezultatin", "composer.hide_preview": "Mbulo rezultatin", diff --git a/public/language/sq-AL/topic.json b/public/language/sq-AL/topic.json index 7d3ef7d883..6ff59cd6a3 100644 --- a/public/language/sq-AL/topic.json +++ b/public/language/sq-AL/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sr/admin/admin.json b/public/language/sr/admin/admin.json index f53f9c0f51..677c70c226 100644 --- a/public/language/sr/admin/admin.json +++ b/public/language/sr/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sr/admin/dashboard.json b/public/language/sr/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/sr/admin/dashboard.json +++ b/public/language/sr/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sr/admin/manage/categories.json b/public/language/sr/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sr/admin/manage/categories.json +++ b/public/language/sr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sr/admin/manage/users.json b/public/language/sr/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sr/admin/manage/users.json +++ b/public/language/sr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sr/admin/menu.json b/public/language/sr/admin/menu.json index 9c5fbbfa23..e7aa210710 100644 --- a/public/language/sr/admin/menu.json +++ b/public/language/sr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Korisnici", "manage/admins-mods": "Admins & Mods", "manage/registration": "Lista Registracija", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupe", "manage/ip-blacklist": "Crna Lista IP adresa", diff --git a/public/language/sr/admin/settings/chat.json b/public/language/sr/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sr/admin/settings/chat.json +++ b/public/language/sr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sr/admin/settings/guest.json b/public/language/sr/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sr/admin/settings/guest.json +++ b/public/language/sr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sr/email.json b/public/language/sr/email.json index 44c271e691..ebb6c7e76f 100644 --- a/public/language/sr/email.json +++ b/public/language/sr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Лозика је успешно змењена", "reset.notify.text1": "Обавештавамо вас да вам је лозинка на %1 успешно ресетована.", "reset.notify.text2": "Уколико нисте ви ово одобрили, молимо одмах контактирајте администратора.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Недавне теме од %1", "digest.top-topics": "Најбоље теме од %1", "digest.popular-topics": "Популарне теме од %1", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 26b4580399..6e39994dec 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Овај налог је забрањен до %1 (Разлог: %2)", "user-too-new": "Жао нам је, морате сачекати %1 секунде/и пре него што објавите прву поруку", "blacklisted-ip": "Жао нам је, ваша IP је забрањена у овој заједници. Ако мислите да је ово грешка, контактирајте администратора.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Наведите крајњи датум за ову забрану", "no-category": "Категорија не постоји", "no-topic": "Тема не постоји", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Соба за ћаскање не постоји.", "cant-add-users-to-chat-room": "Не могу се додати корисници у собу за ћаскање.", "cant-remove-users-from-chat-room": "Не могу се уклонити корисници из собе за ћаскање.", - "chat-room-name-too-long": "Име собе за ћаскање је предугачко.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Већ сте гласали за ову поруку.", "reputation-system-disabled": "Угледи су онемогућени.", "downvoting-disabled": "Негативно гласање је онемогућено", @@ -199,6 +200,7 @@ "not-in-room": "Корисник није у соби", "cant-kick-self": "Не можете избацити себе из групе", "no-users-selected": "Није одабран корисник", + "no-groups-selected": "Није изабрана ниједна група.", "invalid-home-page-route": "Неважећа путања матичне странице", "invalid-session": "Неважећа сесија", "invalid-session-text": "Изгледа да ваша сесија пријављивања није више активна. Поново учитајте ову страницу.", diff --git a/public/language/sr/global.json b/public/language/sr/global.json index d3b061f54e..eb51b15955 100644 --- a/public/language/sr/global.json +++ b/public/language/sr/global.json @@ -51,6 +51,8 @@ "nextpage": "Следећа страна", "alert.success": "Успешно", "alert.error": "Грешка", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Забрањен", "alert.banned.message": "Управо сте добили забрану, ваш приступ је сада ограничен.", "alert.unbanned": "Укинута забрана", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index d8f3f8f7ed..1bc9404283 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Нема активних ћаскања.", "chat.user_typing": "%1 куца ...", "chat.user_has_messaged_you": "%1 вам је послао поруку.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Сва ћаскања", "chat.mark_all_read": "Означи све као прочитано", "chat.no-messages": "Изаберите примаоца да бисте видели историју ћаскања", @@ -27,22 +28,43 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Да ли сте сигурни да желите да избришете ову поруку?", "chat.retrieving-users": "Преузимање корисника...", + "chat.view-users-list": "Погледај листу корисника", + "chat.public-rooms": "Јавне собе (%1)", + "chat.private-rooms": "Приватне собе (%1)", + "chat.create-room": "Креирај собу за ћаскање", + "chat.private.option": "Приватно (видљиво само корисницима додатим у собу)", + "chat.public.option": "Јавно (видљиво сваком кориснику у изабраним групама)", + "chat.public.groups-help": "За креирање собе за ћаскање која је видљива свим корисницима, изаберите регистроване кориснике са листе група.", "chat.manage-room": "Управљај собом за ћаскање", + "chat.add-user": "Додај корисника", + "chat.notification-settings": "Подешавања обавештења", + "chat.default-notification-setting": "Подразумевано подешавање обавештења", + "chat.notification-setting-room-default": "Подразумевана соба", + "chat.notification-setting-none": "Без обавештења", + "chat.notification-setting-at-mention-only": "@помињање само", + "chat.notification-setting-all-messages": "Све поруке", + "chat.select-groups": "Изаберите групе", "chat.add-user-help": "Потражите кориснике овде. Када буде изабран, корисник ће бити додан у ћаскање. Нови корисник неће бити у могућности да види поруке написане пре него што је додан у преписку. Само власници соба () могу уклонити кориснике из соба за ћаскање.", - "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на \"Не узнемиравај\". Да ли и даље желите да ћаскате са њим?", + "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на „Не узнемиравај”. Да ли и даље желите да ћаскате са њим?", + "chat.room-name-optional": "Име собе (опционо)", "chat.rename-room": "Преименуј собу", "chat.rename-placeholder": "Унесите назив собе овде", "chat.rename-help": "Име собе постављено овде биће видљиво свим учесницима у соби.", - "chat.leave": "Напусти ћаскање", + "chat.leave": "Напусти", + "chat.leave-room": "Напусти собу", "chat.leave-prompt": "Да ли сте сигурни да желите да напустите ово ћаскање?", "chat.leave-help": "Напуштање овог ћаскања ће вас уклонити из будућих преписки у овом ћаскању. Ако будете поново додани у будућности, нећете видети историју ћаскања од пре вашег поновног придруживања.", + "chat.delete": "Избриши", + "chat.delete-room": "Избриши собу", + "chat.delete-prompt": "Да ли сте сигурни да желите да избришете ову собу за ћаскање?", "chat.in-room": "У овој соби", "chat.kick": "Избаци", "chat.show-ip": "Прикажи IP", "chat.owner": "Власник собе", - "chat.system.user-join": "%1 се придружио соби", - "chat.system.user-leave": "%1 је напустио собу", - "chat.system.room-rename": "%2 је преименовао собу: %1", + "chat.grant-rescind-ownership": "Додели/поништи власништво", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Писање поруке", "composer.show_preview": "Прикажи преглед", "composer.hide_preview": "Сакриј преглед", diff --git a/public/language/sr/topic.json b/public/language/sr/topic.json index 65fb76a8d5..3448e4f2f0 100644 --- a/public/language/sr/topic.json +++ b/public/language/sr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "написао ", "wrote-on": "написао ", "replied-to-user-ago": "одговорио кориснику %3 ", - "replied-to-user-on": "одговорио кориснику %3 ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 је закључао ову тему %2", "user-locked-topic-on": "%1 је закључао ову тему %2", "user-unlocked-topic-ago": "%1 је откључао ову тему %2", diff --git a/public/language/sv/admin/admin.json b/public/language/sv/admin/admin.json index 70868783ce..5163abb1c8 100644 --- a/public/language/sv/admin/admin.json +++ b/public/language/sv/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sv/admin/dashboard.json b/public/language/sv/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/sv/admin/dashboard.json +++ b/public/language/sv/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sv/admin/manage/categories.json b/public/language/sv/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sv/admin/manage/categories.json +++ b/public/language/sv/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sv/admin/manage/users.json b/public/language/sv/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sv/admin/manage/users.json +++ b/public/language/sv/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sv/admin/menu.json b/public/language/sv/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sv/admin/menu.json +++ b/public/language/sv/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sv/admin/settings/chat.json b/public/language/sv/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sv/admin/settings/chat.json +++ b/public/language/sv/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sv/admin/settings/guest.json b/public/language/sv/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sv/admin/settings/guest.json +++ b/public/language/sv/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sv/email.json b/public/language/sv/email.json index 4491c449b8..087ab72f79 100644 --- a/public/language/sv/email.json +++ b/public/language/sv/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Lösenordet ändrat", "reset.notify.text1": "Vi vill uppmärksamma dig på att ditt lösenord ändrades den %1.", "reset.notify.text2": "Om du inte godkänt det här så vänligen kontakta en administratör snarast. ", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Senaste ämnen från %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index ec3f18f974..713e3c1c3b 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Vi beklagar, men detta konto har blivit bannlyst till %1 (Anledning: %2)", "user-too-new": "När du är ny medlem måste du vänta %1 sekund(er) innan du gör ditt första inlägg", "blacklisted-ip": "Din IP-adress har blivit bannlyst från det här forumet. Om du tror att det beror på ett misstag, vad god kontakta en administratör. ", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Ange ett slutdatum för denna banning", "no-category": "Kategorin finns inte", "no-topic": "Ämnet finns inte", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du har redan röstat på det här inlägget.", "reputation-system-disabled": "Ryktessystemet är inaktiverat.", "downvoting-disabled": "Nedröstning är inaktiverat", @@ -199,6 +200,7 @@ "not-in-room": "Användaren finns inte i rummet", "cant-kick-self": "Du kan inte sparka ut dig själv från gruppen", "no-users-selected": "Ingen användare vald(a)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ogiltig sidsökväg", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sv/global.json b/public/language/sv/global.json index 6172d35dc6..9eb88df89f 100644 --- a/public/language/sv/global.json +++ b/public/language/sv/global.json @@ -51,6 +51,8 @@ "nextpage": "Nästa sida", "alert.success": "Lyckat", "alert.error": "Fel", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Bannlyst", "alert.banned.message": "Du har precis blivit bannlyst, du har nu begränsad tillgång.", "alert.unbanned": "Unbanned", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 957403eb60..3ddf315fae 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har inte några aktiva chattar.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har skickat ett medelande till dig.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alla chattar", "chat.mark_all_read": "Markera alla chattar som lästa", "chat.no-messages": "Välj mottagare för att visa historik för chattmeddelande", @@ -27,22 +28,43 @@ "chat.three_months": "3 månader", "chat.delete_message_confirm": "Är du säker på att du vill radera det här meddelandet?", "chat.retrieving-users": "Hämtar användare...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Hantera chattrum", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Sök efter användare här. Vid markering läggs användaren till i chatten. Den nya användaren kommer inte kunna se chattmeddelanden som skrevs innan de lades till i konversationen. Endast chattrumsägare () kan avlägsna användare från chattrum.", "chat.confirm-chat-with-dnd-user": "Denna användare har satt sin status till Stör Ej. Vill du fortfarande chatta med dem?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Byt namn på rum", "chat.rename-placeholder": "Skriv in rummets namn här", "chat.rename-help": "Rummets namn som skrivs in här kommer vara synligt för alla deltagare i rummet.", - "chat.leave": "Lämna chatt", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Är du säker att du vill lämna denna chatt?", "chat.leave-help": "Om du lämnar denna chatt kommer du inte vara med i framtida korrespondens i denna chatt. Om du läggs till igen i framtiden, kommer du inte se någon chatthistorik från innan du lades till.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "I detta rum", "chat.kick": "Sparka ut", "chat.show-ip": "Visa IP", "chat.owner": "Rummets ägare", - "chat.system.user-join": "%1 har anslutit till rummet", - "chat.system.user-leave": "%1 har lämnat rummet", - "chat.system.room-rename": "%2 har döpt om rummet: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Komponera", "composer.show_preview": "Visa förhandsgranskning", "composer.hide_preview": "Dölj förhandsgranskning", diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index a946b6fd43..87fb6c8b54 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/th/admin/admin.json b/public/language/th/admin/admin.json index eb6d05a175..ee88fab2c3 100644 --- a/public/language/th/admin/admin.json +++ b/public/language/th/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/th/admin/dashboard.json b/public/language/th/admin/dashboard.json index c77f7ff0c2..681c202f47 100644 --- a/public/language/th/admin/dashboard.json +++ b/public/language/th/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/th/admin/manage/categories.json b/public/language/th/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/th/admin/manage/categories.json +++ b/public/language/th/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/th/admin/manage/users.json b/public/language/th/admin/manage/users.json index eaf40ba943..a3cfe00931 100644 --- a/public/language/th/admin/manage/users.json +++ b/public/language/th/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "ดาวน์โหลด CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/th/admin/menu.json b/public/language/th/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/th/admin/menu.json +++ b/public/language/th/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/th/admin/settings/chat.json b/public/language/th/admin/settings/chat.json index e8f7c02f6a..21e4c4c0a1 100644 --- a/public/language/th/admin/settings/chat.json +++ b/public/language/th/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "ปิดการแก้ไข และการลบแชท", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "จำนวนอักขระมากที่มากที่สุดต่อแชท", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "จำนวนผู้ใช้ในห้องแชทมากที่สุด", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/th/admin/settings/guest.json b/public/language/th/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/th/admin/settings/guest.json +++ b/public/language/th/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/th/email.json b/public/language/th/email.json index cae9571202..d3245240c4 100644 --- a/public/language/th/email.json +++ b/public/language/th/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "ตั้งค่ารหัสผ่านใหม่เรียบร้อยแล้ว", "reset.notify.text1": "เรากำลังแจ้งคุณว่าตอน %1 รหัสผ่านของคุณถูกเปลี่ยนเรียบร้อยแล้ว", "reset.notify.text2": "หากคุณไม่ได้เป็นคนอนุญาตสิ่งนี้ กรุณาแจ้งไปยังผู้ดูแลระบบโดยทันที", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "หัวข้อสนทนาล่าสุดจาก %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/th/error.json b/public/language/th/error.json index 99dabfb1c9..7e396d380f 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "ขออภัย บัญชีผู้ใช้นี้ได้รับการแบนจนถึง %1 (เหตุผล : %2)", "user-too-new": "ขออภัย คุณจำเป็นต้องรอ %1 วินาที(s) ก่อนการสร้างกระทู้แรกของคุณ", "blacklisted-ip": "ขออภัย IP Address ของคุณถูกแบนจากชุมชนนี้ หากคุณคิดว่านี่เป็นเออเร่อของระบบ กรุณาติดต่อผู้ดูแลระบบ", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "กรุณาระบุวันสิ้นสุดสำหรับการแบนในครั้งนี้", "no-category": "ยังไม่มี Category นี้", "no-topic": "ยังไม่มี Topic นี้", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "คุณได้โหวตโพสต์นี้แล้ว", "reputation-system-disabled": "ระบบชื่อเสียงถูกปิดใช้งาน", "downvoting-disabled": "\"การโหวตลง\" ถูกปิดใช้งาน", @@ -199,6 +200,7 @@ "not-in-room": "ผู้ใช้ไม่อยู่ในห้อง", "cant-kick-self": "คุณไม่สามารถเตะตัวเองออกจากกลุ่มได้", "no-users-selected": "ไม่มีผู้ใช้ที่เลือก", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "เส้นทางไปหน้าแรกผิดพลาด", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/th/global.json b/public/language/th/global.json index d94308ef5d..15719027e7 100644 --- a/public/language/th/global.json +++ b/public/language/th/global.json @@ -51,6 +51,8 @@ "nextpage": "หน้าถัดไป", "alert.success": "สำเร็จ", "alert.error": "ผิดพลาด", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "เเบน", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index f4326cac7c..aac0f60788 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "คุณไม่มีแชทที่คุยอยู่", "chat.user_typing": "%1 กำลังพิมพ์อยู่ ...", "chat.user_has_messaged_you": "%1 ได้ส่งข้อความถึงคุณ", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "กรุณาเลือกผู้รับเพื่อดูประวัติข้อความ", @@ -27,22 +28,43 @@ "chat.three_months": "3 เดือน", "chat.delete_message_confirm": "คุณแน่ใจแล้วใช่ไหมว่าต้องการจะลบข้อความนี้?", "chat.retrieving-users": "กำลังเรียกข้อมูลผู้ใช้", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "จัดการห้องแชท", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "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.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "ใส่ชื่อห้องของคุณที่นี่", "chat.rename-help": "ชื่อห้องจะสามารถดูได้โดยผู้เข้าร่วมทั้งหมดในห้อง", - "chat.leave": "ออกแชท", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "คุณแน่ใจหรือไม่ว่าต้องการออกจากการแชทนี้", "chat.leave-help": "การออกจากการแชทนี้จะเป็นการลบคุณออกจากการติดต่อในอนาคตในการแชทนี้ หากคุณถูกเพิ่มเข้ามาใหม่ในอนาคตคุณจะไม่เห็นประวัติการแชทก่อนที่จะเข้าร่วมใหม่", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "ในห้องนี้", "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "เขียน", "composer.show_preview": "แสดงพรีวิว", "composer.hide_preview": "ซ่อนพรีวิว", diff --git a/public/language/th/topic.json b/public/language/th/topic.json index 8f7dfb09e7..469bfde3b6 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/tr/admin/admin.json b/public/language/tr/admin/admin.json index c4718b4700..36cf3b16f9 100644 --- a/public/language/tr/admin/admin.json +++ b/public/language/tr/admin/admin.json @@ -4,13 +4,15 @@ "acp-title": "%1 | NodeBB Yönetici Kontrol Paneli", "settings-header-contents": "İçerikler", - "changes-saved": "Changes Saved", + "changes-saved": "Değişiklikler kaydedildi", "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", "changes-not-saved": "Değişiklikler kaydedilmedi", "changes-not-saved-message": "NodeBB değişiklikleri kaydederken bir hata oluştu (%1)", - "save-changes": "Save changes", - "min": "Min:", - "max": "Max:", + "save-changes": "Değişiklikleri Kaydet", + "min": "En az:", + "max": "En çok:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/tr/admin/dashboard.json b/public/language/tr/admin/dashboard.json index 8762e41cac..a08b3a6082 100644 --- a/public/language/tr/admin/dashboard.json +++ b/public/language/tr/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "NodeBB'nizi yeniden oluşturma ve yeniden başlatma devre dışı bırakıldı.", "maintenance-mode": "Bakım Modu", "maintenance-mode-title": "NodeBB için bakım modunu ayarlamak için buraya tıklayın", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Gerçek Zamanlı Grafik Güncellemeleri", "active-users": "Aktif Kullanıcılar", @@ -89,5 +90,9 @@ "details.logins-login-time": "Giriş zamanı", "start": "Başlangıç", "end": "Bitiş", - "filter": "Filtre" + "filter": "Filtre", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/tr/admin/extend/plugins.json b/public/language/tr/admin/extend/plugins.json index b064fc7bb1..339920ea2e 100644 --- a/public/language/tr/admin/extend/plugins.json +++ b/public/language/tr/admin/extend/plugins.json @@ -1,5 +1,5 @@ { - "plugins": "Plugins", + "plugins": "Eklentiler", "trending": "Popüler", "installed": "Yüklenmiş", "active": "Etkin", diff --git a/public/language/tr/admin/extend/rewards.json b/public/language/tr/admin/extend/rewards.json index a95f454997..7eb384e6ff 100644 --- a/public/language/tr/admin/extend/rewards.json +++ b/public/language/tr/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Ödüller", - "add-reward": "Add reward", + "add-reward": "Ödül Ekle", "condition-if-users": "Eğer bir kullanıcının", "condition-is": "şu ise:", "condition-then": "O halde:", "max-claims": "Ödül kaç kez alınabilir", "zero-infinite": "Sınırsız için 0 girin", - "select-reward": "Select reward", + "select-reward": "Ödül Seç", "delete": "Sil", "enable": "Etkinleştir", "disable": "Etkinsizleştir", diff --git a/public/language/tr/admin/manage/categories.json b/public/language/tr/admin/manage/categories.json index 82137392ff..f79f1fc55a 100644 --- a/public/language/tr/admin/manage/categories.json +++ b/public/language/tr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "İzin Verilen Etiketler", "upload-image": "Görsel Yükle", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Sil", "category-image": "Kategori Görseli", "image-and-icon": "Image & Icon", diff --git a/public/language/tr/admin/manage/users.json b/public/language/tr/admin/manage/users.json index 150cdeb098..4cc0417d38 100644 --- a/public/language/tr/admin/manage/users.json +++ b/public/language/tr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Kullanıcıyı/ları ve İçeriği Sil", "download-csv": "CSV İndir", "manage-groups": "Grupları Düzenle", + "set-reputation": "Set Reputation", "add-group": "Grup ekle", "create": "Kullanıcı Oluştur", "invite": "E-posta ile Davet Et", diff --git a/public/language/tr/admin/menu.json b/public/language/tr/admin/menu.json index 953527aace..a63ce9022e 100644 --- a/public/language/tr/admin/menu.json +++ b/public/language/tr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Kullanıcılar", "manage/admins-mods": "Yöneticiler ve Modlar", "manage/registration": "Kayıt Kuyruğu", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "İleti Kuyruğu", "manage/groups": "Gruplar", "manage/ip-blacklist": "IP Kara Listesi", diff --git a/public/language/tr/admin/settings/chat.json b/public/language/tr/admin/settings/chat.json index ac06420c4d..09719c318a 100644 --- a/public/language/tr/admin/settings/chat.json +++ b/public/language/tr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Sohbet mesajlarını düzenlemeyi/silmeyi kapat", "disable-editing-help": "Yöneticiler ve global moderatörler bu kısıtlamadan muaftır", "max-length": "Maksimum sohbet mesajı uzunluğu", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Sohbet odalarındaki maksimum kullanıcı sayısı", "delay": "Sohbet mesajları arasındaki süre (milisaniye)", "notification-delay": "Sohbet mesajları için bildirim gecikme süresi (gecikme olmaması için 0 yazın)", diff --git a/public/language/tr/admin/settings/guest.json b/public/language/tr/admin/settings/guest.json index 9757591fbd..0f870c7122 100644 --- a/public/language/tr/admin/settings/guest.json +++ b/public/language/tr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Ayarlar", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Misafir üyelere izin ver", "handles.enabled-help": "Bu seçenek, misafirlerin yaptıkları her gönderiyle ilişkilendirebilecekleri bir isim alanı sunar. Devre dışı bırakılırsa, gönderenin ismi basitçe \"Misafir\" olarak adlandırılacaktır.", "topic-views.enabled": "Ziyaretçilerin konu bakış sayısını arttırmasına izin ver", diff --git a/public/language/tr/email.json b/public/language/tr/email.json index 6765b0b154..6698f65f45 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Şifre başarıyla değiştirildi", "reset.notify.text1": "Şifrenizin %1 zamanında başarı ile değiştirildiğini bildirmek isteriz.", "reset.notify.text2": "Bunu siz yetkilendirmediyseniz, lütfen hiç vakit kaybetmeden site yöneticisine bu durumu bildiriniz.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "'daki En Güncel Konular", "digest.top-topics": "%1 tarafından zirve başlıklar", "digest.popular-topics": "%1 tarafından popüler başlıklar", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index 9d5360fc09..761441ed6b 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Maalesef, bu hesap %1 tarihine kadar yasaklandı (Sebep: %2)", "user-too-new": "Özür dileriz, ilk iletinizi göndermeden önce %1 saniye beklemeniz gerekiyor!", "blacklisted-ip": "Üzgünüz, IP adresiniz bu forumda yasaklandı. Bunun bir hata olduğunu düşünüyorsanız bir yönetici ile irtibata geçiniz.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Bu yasak için bir bitiş tarihi girin", "no-category": "Kategori Yok", "no-topic": "Konu Yok", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Sohbet Odası Mevcut Değil", "cant-add-users-to-chat-room": "Kullanıcıları sohbet odasına ekleyemezsiniz!", "cant-remove-users-from-chat-room": "Kullanıcıları sohbet odasından çıkaramazsınız!", - "chat-room-name-too-long": "Sohbet odasının ismi çok uzun!", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Bu gönderi için zaten oy verdin.", "reputation-system-disabled": "İtibar sistemi devre dışı.", "downvoting-disabled": "Eksi oylama devre dışı bırakılmış. ", @@ -199,6 +200,7 @@ "not-in-room": "Odada kullanıcı yok", "cant-kick-self": "Kendinizi gruptan atamazsınız.", "no-users-selected": "Seçili kullanıcı(lar) bulunamadı", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Geçersiz anasayfa yolu", "invalid-session": "Geçersiz Oturum", "invalid-session-text": "Giriş oturumunuz aktif görünmüyor. Lütfen sayfayı yenileyiniz.", diff --git a/public/language/tr/global.json b/public/language/tr/global.json index 3b98b62bed..b245a43775 100644 --- a/public/language/tr/global.json +++ b/public/language/tr/global.json @@ -51,6 +51,8 @@ "nextpage": "Sonraki Sayfa", "alert.success": "Başarılı", "alert.error": "Hata", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Yasaklı", "alert.banned.message": "Yasaklandınız, erişiminiz kısıtlanmıştır. ", "alert.unbanned": "Yasak kaldırıldı", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 72e0181ebe..bd7988f3db 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Aktif sohbet mevcut değil", "chat.user_typing": "%1 yazıyor ...", "chat.user_has_messaged_you": "%1 size bir mesaj gönderdi.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Bütün Sohbetler", "chat.mark_all_read": "Hepsini Okundu Olarak İşaretle", "chat.no-messages": "Lütfen sohbet geçmişini görüntülemek için bir alıcı seçin", @@ -27,22 +28,43 @@ "chat.three_months": "3 Ay", "chat.delete_message_confirm": "Bu mesajı silmek istediğinizden emin misiniz?", "chat.retrieving-users": "Kullanıcılar alınıyor ...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Sohbet Odasını Yönet", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Burada kullanıcılar için arama yapın. Kullanıcı seçildiğinde sohbete eklenecektir. Yeni kullanıcı sohbete eklenmeden önce yazılmış olan sohbet mesajlarını göremeyecektir. Yalnızca oda sahipleri () kullanıcıları sohbet odalarından kaldırabilir.", "chat.confirm-chat-with-dnd-user": "Bu kullanıcı durumunu rahatsız etmeyin olarak ayarladı. Hala onunla sohbet etmek istiyor musunuz?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Odanın ismini değiştir", "chat.rename-placeholder": "Oda isminizi buraya girin", "chat.rename-help": "Buradaki oda ismi odadaki tüm katılımcılar tarafından görülebilir.", - "chat.leave": "Sohbetten Ayrıl", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Sohbetten ayrılmak istediğinizden emin misiniz?", "chat.leave-help": "Bu sohbetten ayrılmak, bu sohbetteki gelecekteki yazışmalardan sizi silecektir. Gelecekte tekrar eklendiyseniz, yeniden katılmadan önce herhangi bir sohbet geçmişi görmezsiniz.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Bu odada", "chat.kick": "Dışarı At", "chat.show-ip": "IP Göster", "chat.owner": "Oda Sahibi", - "chat.system.user-join": "%1 odaya katıldı", - "chat.system.user-leave": "%1 odadan çıktı", - "chat.system.room-rename": "%2 şu grubun ismini değiştirdi: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Yaz", "composer.show_preview": "Önizleme Göster", "composer.hide_preview": "Önizleme Sakla", diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index ee9ccf74cc..885beae1e5 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": " yazdı", "wrote-on": " tarihinde yazdı", "replied-to-user-ago": "%3 başlığına cevap verdi", - "replied-to-user-on": "%3 başlığına tarihinde cevap verdi", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 , %2 bu başlığı kilitledi", "user-locked-topic-on": "%1 , %2 tarihinde bu başlığı kilitledi", "user-unlocked-topic-ago": "%1 , %2 bu başlığın kilidini kaldırdı", diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 5a91331b87..4c18f2409c 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -141,7 +141,7 @@ "group-order-help": "Bir grup seçin ve unvanları sıralamak için yön tuşlarını kullanın", "no-group-title": "Grup unvanı yok", "select-skin": "Bir tema seçin", - "default": "Default (%1)", + "default": "Varsayılan (%1)", "no-skin": "No Skin", "select-homepage": "Bir \"Anasayfa\" seçin", "homepage": "Anasayfa", diff --git a/public/language/uk/admin/admin.json b/public/language/uk/admin/admin.json index e5050a475f..54ce5f0e3c 100644 --- a/public/language/uk/admin/admin.json +++ b/public/language/uk/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/uk/admin/dashboard.json b/public/language/uk/admin/dashboard.json index e1982c1711..b230979fca 100644 --- a/public/language/uk/admin/dashboard.json +++ b/public/language/uk/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Перебудування та перезапуск вашого NodeBB вимкнено, оскільки ви, здається, не запускаєте його через відповідний демон.", "maintenance-mode": "Режим обслуговування", "maintenance-mode-title": "Натисніть тут, щоб налаштувати режим обслуговування NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Оновлення графіків в реальному часі", "active-users": "Активні користувачі", @@ -89,5 +90,9 @@ "details.logins-login-time": "Login Time", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/uk/admin/manage/categories.json b/public/language/uk/admin/manage/categories.json index ccff2556f3..ffec24d057 100644 --- a/public/language/uk/admin/manage/categories.json +++ b/public/language/uk/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Завантажити зображення", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Видалити", "category-image": "Зображення категорії", "image-and-icon": "Image & Icon", diff --git a/public/language/uk/admin/manage/users.json b/public/language/uk/admin/manage/users.json index 010a781379..2b7df34d4f 100644 --- a/public/language/uk/admin/manage/users.json +++ b/public/language/uk/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Скачати CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/uk/admin/menu.json b/public/language/uk/admin/menu.json index ea4e7e89e6..4b731cad0c 100644 --- a/public/language/uk/admin/menu.json +++ b/public/language/uk/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Користувачі", "manage/admins-mods": "Адміністратори та моди", "manage/registration": "Черга реєстрації", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Черга Постів", "manage/groups": "Групи", "manage/ip-blacklist": "Чорний список IP-адрес", diff --git a/public/language/uk/admin/settings/chat.json b/public/language/uk/admin/settings/chat.json index af017b5541..45d3d9af6a 100644 --- a/public/language/uk/admin/settings/chat.json +++ b/public/language/uk/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Вимкнути редагування/видалення повідомлень чату", "disable-editing-help": "Адміністратори на модератори звільнені від цього обмеження", "max-length": "Максимальна довжина повідомлення", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Максимальна кількість людей у кімнаті", "delay": "Час між повідомленнями в мілісекундах", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/uk/admin/settings/guest.json b/public/language/uk/admin/settings/guest.json index 4ce2a3a6aa..0a434cfcc4 100644 --- a/public/language/uk/admin/settings/guest.json +++ b/public/language/uk/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Дозволити гостьові імена", "handles.enabled-help": "Ця опція надає додаткове поле, що дозволяє гостям обрати собі ім'я для кожного посту. Якщо вимкнено, вони будуть просто зватися \"Гість\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/uk/email.json b/public/language/uk/email.json index e5503fab37..d337e16249 100644 --- a/public/language/uk/email.json +++ b/public/language/uk/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Пароль змінено", "reset.notify.text1": "Ми повідомляємо вас, що на %1, ваш пароль було успішно змінено", "reset.notify.text2": "Якщо ви не авторизували це, повідомте негайно адміністратора", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Останні теми від %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/uk/error.json b/public/language/uk/error.json index 87ad050254..664c7cc75e 100644 --- a/public/language/uk/error.json +++ b/public/language/uk/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Вибачте, цей акаунт забанений до %1 (Причина: %2)", "user-too-new": "Вибачте, але вам необхідно зачекати %1 секунд(и), перед першим постом", "blacklisted-ip": "Вибачте, але ваша IP-адреса була забанена в цій спільноті. Якщо ви гадаєте, що це сталось помилково, зв'яжіться з адміністратором.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Вкажіть, будь ласка, кінцеву дату бану", "no-category": "Категорія не існує", "no-topic": "Тема не існує", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ви вже проголосували за цей пост.", "reputation-system-disabled": "Система репутацій вимкнена.", "downvoting-disabled": "Голосування проти вимкнено", @@ -199,6 +200,7 @@ "not-in-room": "Користувача немає в кімнаті", "cant-kick-self": "Ви не можете вигнати самі себе з групи", "no-users-selected": "Не вибрано жодного користувача", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Невірний шлях на головну", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/uk/global.json b/public/language/uk/global.json index 0326777e17..2cecaa6fd7 100644 --- a/public/language/uk/global.json +++ b/public/language/uk/global.json @@ -51,6 +51,8 @@ "nextpage": "Наступна сторінка", "alert.success": "Успіх", "alert.error": "Помилка", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Забанений", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 3af610d79a..1ef15ebb33 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "У вас немає активних чатів.", "chat.user_typing": "%1 друкує...", "chat.user_has_messaged_you": "%1 написав вам.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Будь ласка, оберіть отримувача, щоб переглянути історію повідомлень", @@ -27,22 +28,43 @@ "chat.three_months": "3 місяці", "chat.delete_message_confirm": "Ви впевнені, що хочете видалити це повідомлення?", "chat.retrieving-users": "Отримання користувачів...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управління чат кімнатами", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Шукайте користувачів тут. Користувача можна додати до чату, обравши його. Нові користувачі не можуть бачити повідомлення, написані до того, як їх додали до розмови. Тільки власники кімнат можуть видаляти користувачів з кімнат.", "chat.confirm-chat-with-dnd-user": "Користувач змінив свій статус на DnD (Не турбувати). Ви дійсно бажаєте надіслати йому повідомлення в чат?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Перейменувати Кімнату", "chat.rename-placeholder": "Введіть назву своєї кімнати тут", "chat.rename-help": "Назва кімнати, яку буде встановлено тут, буде доступна для перегляду всіма учасниками в кімнаті.", - "chat.leave": "Залишити чат", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ви впевнені, що хочете залишити цей чат?", "chat.leave-help": "Залишивши цей чат, ви видалите вас із майбутньої кореспонденції у цьому чаті. Якщо ви знову будете додані в майбутньому, ви не побачите жодної історії чату перед тим, як знову приєднатися.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "У цій кімнаті", "chat.kick": "Штурхнути", "chat.show-ip": "Показати IP", "chat.owner": "Власник кімнати", - "chat.system.user-join": "%1 зайшов в кімнату", - "chat.system.user-leave": "%1 покинув кімнату", - "chat.system.room-rename": "%2 перейменував кімнату на: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Редактор повідомлень", "composer.show_preview": "Показати попередній перегляд", "composer.hide_preview": "Сховати попередній перегляд", diff --git a/public/language/uk/topic.json b/public/language/uk/topic.json index f100cd844c..27c4eca889 100644 --- a/public/language/uk/topic.json +++ b/public/language/uk/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/vi/admin/admin.json b/public/language/vi/admin/admin.json index b9b457dfa9..16dd9e8839 100644 --- a/public/language/vi/admin/admin.json +++ b/public/language/vi/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/vi/admin/dashboard.json b/public/language/vi/admin/dashboard.json index d312a0d071..66af8c637c 100644 --- a/public/language/vi/admin/dashboard.json +++ b/public/language/vi/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Việc xây dựng lại và khởi động lại NodeBB của bạn đã bị vô hiệu hóa vì bạn dường như không chạy nó qua daemon thích hợp.", "maintenance-mode": "Chế Độ Bảo Trì", "maintenance-mode-title": "Bấm vào đây để thiết lập chế độ bảo trì cho NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Cập Nhật Biểu Đồ Thời Gian Thực", "active-users": "Người Dùng Hoạt Động", @@ -89,5 +90,9 @@ "details.logins-login-time": "Thời gian đăng nhập", "start": "Start", "end": "End", - "filter": "Bộ lọc" + "filter": "Bộ lọc", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/vi/admin/manage/categories.json b/public/language/vi/admin/manage/categories.json index c47a4feebd..b4d06d17fa 100644 --- a/public/language/vi/admin/manage/categories.json +++ b/public/language/vi/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Danh Sách Trắng Gắn Thẻ ", "upload-image": "Tải Lên Ảnh", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Xóa", "category-image": "Ảnh Chuyên Mục", "image-and-icon": "Image & Icon", diff --git a/public/language/vi/admin/manage/tags.json b/public/language/vi/admin/manage/tags.json index 95cd104447..fb6d662a87 100644 --- a/public/language/vi/admin/manage/tags.json +++ b/public/language/vi/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Quản lý thẻ", "none": "Diễn đàn của bạn chưa có bất kỳ chủ đề nào gắn thẻ.", "bg-color": "Màu Nền", "text-color": "Màu Chữ", "description": "Chọn các thẻ bằng cách nhấp hoặc kéo, bấm CTRL để chọn nhiều thẻ.", "create": "Tạo Thẻ", - "add-tag": "Add tag", + "add-tag": "Thêm thẻ", "modify": "Sửa Đổi Thẻ", "rename": "Đổi Tên Thẻ", "delete": "Xóa Các Thẻ Đã Chọn", diff --git a/public/language/vi/admin/manage/users.json b/public/language/vi/admin/manage/users.json index ad02785a9e..a318c8b711 100644 --- a/public/language/vi/admin/manage/users.json +++ b/public/language/vi/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Xóa Người DùngNội Dung", "download-csv": "Tải về CSV", "manage-groups": "Quản Lý Nhóm", + "set-reputation": "Set Reputation", "add-group": "Thêm Nhóm", "create": "Tạo Người Dùng", "invite": "Mời qua Email", diff --git a/public/language/vi/admin/menu.json b/public/language/vi/admin/menu.json index 23bcfce03d..6f67b8c537 100644 --- a/public/language/vi/admin/menu.json +++ b/public/language/vi/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Người dùng", "manage/admins-mods": "Quản trị viên & Người điều hành", "manage/registration": "Hàng Đợi Đăng Ký", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Hàng Đợi Bài Viết", "manage/groups": "Nhóm", "manage/ip-blacklist": "Danh sách đen IP", diff --git a/public/language/vi/admin/settings/chat.json b/public/language/vi/admin/settings/chat.json index 12397eecf9..bb5cefc672 100644 --- a/public/language/vi/admin/settings/chat.json +++ b/public/language/vi/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Tắt chỉnh sửa / xóa tin nhắn trò chuyện", "disable-editing-help": "Quản trị viên và người kiểm duyệt toàn quyền được miễn hạn chế này", "max-length": "Độ dài tối đa của tin nhắn trò chuyện", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Số lượng người dùng tối đa trong phòng trò chuyện", "delay": "Thời gian giữa các tin nhắn trò chuyện tính bằng mili giây", "notification-delay": "Độ trễ thông báo cho tin nhắn trò chuyện. (0 để không bị chậm trễ)", diff --git a/public/language/vi/admin/settings/guest.json b/public/language/vi/admin/settings/guest.json index 4b9200ce6f..8c7aa35a6d 100644 --- a/public/language/vi/admin/settings/guest.json +++ b/public/language/vi/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Cài đặt", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Cho phép xử lý khách", "handles.enabled-help": "Tùy chọn này hiển thị một trường mới cho phép khách chọn tên để liên kết với mỗi bài đăng mà họ thực hiện. Nếu bị tắt, họ sẽ chỉ được gọi là \"Khách\"", "topic-views.enabled": "Cho phép khách tăng lượt xem chủ đề", diff --git a/public/language/vi/email.json b/public/language/vi/email.json index 88aeb4bb50..f92942ae98 100644 --- a/public/language/vi/email.json +++ b/public/language/vi/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Thay đổi mật khẩu thành công", "reset.notify.text1": "Xin thông báo với bạn: mật khẩu của bạn trên %1 đã được thay đổi thành công.", "reset.notify.text2": "Nếu bạn không cho phép điều này, vui lòng thông báo cho quản trị viên ngay lập tức.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Chủ đề mới nhất từ %1", "digest.top-topics": "Chủ đề hàng đầu từ %1", "digest.popular-topics": "Các chủ đề phổ biến từ %1", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index db16e2ffa8..ae643c3466 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "Xin lỗi, tài khoản này bị cấm cho đến %1 (Lý do: %2)", "user-too-new": "Xin lỗi, bắt buộc bạn phải đợi %1 giây trước khi đăng bài viết đầu tiên.", "blacklisted-ip": "Xin lỗi, địa chỉ IP bạn bị cấm khỏi cộng đồng. Nếu bạn cảm thấy dây là do lỗi, hãy liên lạc với quản trị viên.", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "Vui lòng cung cấp ngày hết lệnh cấm này", "no-category": "Chuyên mục không tồn tại", "no-topic": "Chủ đề không tồn tại", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Phòng trò chuyện không tồn tại.", "cant-add-users-to-chat-room": "Không thể thêm người dùng vào phòng trò chuyện.", "cant-remove-users-from-chat-room": "Không thể xóa người dùng khỏi phòng trò chuyện.", - "chat-room-name-too-long": "Tên phòng trò chuyện quá dài.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Bạn đã bỏ phiếu cho bài viết này", "reputation-system-disabled": "Hệ thống đánh giá uy tính đã bị vô hiệu hóa.", "downvoting-disabled": "Phản đối đã bị tắt", @@ -199,6 +200,7 @@ "not-in-room": "Thành viên không có trong phòng", "cant-kick-self": "Bạn không thể loại mình khỏi nhóm", "no-users-selected": "Chưa có người dùng(s) nào", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Đường dẫn trang chủ không hợp lệ", "invalid-session": "Phiên Không Hợp Lệ", "invalid-session-text": "Có vẻ như phiên đăng nhập của bạn không còn hoạt động. Vui lòng làm mới trang này.", diff --git a/public/language/vi/flags.json b/public/language/vi/flags.json index af7768df0e..7a45d900f8 100644 --- a/public/language/vi/flags.json +++ b/public/language/vi/flags.json @@ -16,7 +16,7 @@ "filter-active": "Có một hoặc nhiều bộ lọc đang hoạt động trong danh sách cờ này", "filter-reset": "Xóa Bộ Lọc", "filters": "Tùy Chỉnh Bộ Lọc", - "filter-reporterId": "Reporter", + "filter-reporterId": "Người báo cáo", "filter-targetUid": "Reportee", "filter-type": "Loại Cờ", "filter-type-all": "Tất Cả Nội Dung", diff --git a/public/language/vi/global.json b/public/language/vi/global.json index 70a120fa29..3bc4d1a268 100644 --- a/public/language/vi/global.json +++ b/public/language/vi/global.json @@ -51,6 +51,8 @@ "nextpage": "Trang kế", "alert.success": "Thành công", "alert.error": "Lỗi", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "Bị cấm", "alert.banned.message": "Bạn vừa bị cấm, quyền truy cập của bạn hiện bị hạn chế.", "alert.unbanned": "Bỏ cấm", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 5c5b1812bc..c40cf10b7b 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Bạn không có cuộc trò chuyện đang hoạt động nào.", "chat.user_typing": "%1 đang nhập...", "chat.user_has_messaged_you": "%1 đã nhắn tin cho bạn.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Tất cả trò chuyện", "chat.mark_all_read": "Đánh dấu tất cả đã đọc", "chat.no-messages": "Vui lòng chọn người nhận để xem lịch sử tin nhắn trò chuyện", @@ -27,22 +28,43 @@ "chat.three_months": "3 tháng", "chat.delete_message_confirm": "Bạn có chắc muốn xoá tin nhắn này không?", "chat.retrieving-users": "Đang truy xuất người dùng...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Quản Lý Phòng Trò Chuyện", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tìm người dùng ở đây. Người dùng được chọn sẽ được thêm vào trò chuyện. Người dùng mới sẽ không thấy tin nhắn trò chuyện được đăng trước khi họ được thêm vào. Chỉ chủ phòng () được xóa người dùng khỏi phòng trò chuyện.", "chat.confirm-chat-with-dnd-user": "Người dùng này đã đặt trạng thái của họ thành DnD (Không làm phiền). Bạn vẫn muốn trò chuyện với họ?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Đổi Tên Phòng", "chat.rename-placeholder": "Nhập tên phòng của bạn ở đây", "chat.rename-help": "Đẳt tên phòng ở đây, tất cả những người tham gia phòng này có thể xem.", - "chat.leave": "Rời Khỏi Trò Chuyện", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Bạn có chắc chắn muốn rời khỏi cuộc trò chuyện này không?", "chat.leave-help": "Rời khỏi cuộc trò chuyện này sẽ xóa các tin nhắn của bạn trong cuộc trò chuyện này. Nếu bạn được thêm lại trong tương lai, bạn sẽ không thấy bất kỳ lịch sử trò chuyện nào từ trước khi bạn tham gia lại.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Trong phòng này", "chat.kick": "Loại ra", "chat.show-ip": "Hiện IP", "chat.owner": "Chủ Phòng", - "chat.system.user-join": "%1 đã vào phòng", - "chat.system.user-leave": "%1 đã rời phòng", - "chat.system.room-rename": "%2 đã đổi tên phòng: %1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Soạn thảo", "composer.show_preview": "Hiện Xem trước", "composer.hide_preview": "Ẩn Xem trước", diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index 19f602ad0c..dcc1eca402 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 đã khóa chủ đề này %2", "user-locked-topic-on": "%1 đã khóa chủ đề này trên %2", "user-unlocked-topic-ago": "%1 đã mở khóa chủ đề này %2", diff --git a/public/language/zh-CN/admin/admin.json b/public/language/zh-CN/admin/admin.json index 554c76b245..218a77c3b5 100644 --- a/public/language/zh-CN/admin/admin.json +++ b/public/language/zh-CN/admin/admin.json @@ -12,5 +12,7 @@ "min": "最小:", "max": "最大:", "view": "浏览", - "edit": "编辑" + "edit": "编辑", + "add": "添加", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/appearance/skins.json b/public/language/zh-CN/admin/appearance/skins.json index 08168437e6..4a054a0425 100644 --- a/public/language/zh-CN/admin/appearance/skins.json +++ b/public/language/zh-CN/admin/appearance/skins.json @@ -1,12 +1,12 @@ { "skins": "皮肤", - "bootswatch-skins": "Bootswatch Skins", - "custom-skins": "Custom Skins", - "add-skin": "Add Skin", - "save-custom-skins": "Save Custom Skins", - "save-custom-skins-success": "Custom skins saved successfully", - "custom-skin-name": "Custom Skin Name", - "custom-skin-variables": "Custom Skin Variables", + "bootswatch-skins": "基于 Bootswatch的皮肤", + "custom-skins": "自定义皮肤", + "add-skin": "添加皮肤", + "save-custom-skins": "保存自定义皮肤", + "save-custom-skins-success": "自定义皮肤保存成功", + "custom-skin-name": "自定义皮肤名称", + "custom-skin-variables": "自定义皮肤变量", "loading": "正在加载皮肤...", "homepage": "主页", "select-skin": "选择皮肤", @@ -14,5 +14,5 @@ "current-skin": "当前皮肤", "skin-updated": "皮肤已更新", "applied-success": "%1 皮肤已成功应用", - "revert-success": "皮肤已恢复到基础颜色" + "revert-success": "皮肤已恢复到原来的颜色" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/dashboard.json b/public/language/zh-CN/admin/dashboard.json index 93d0ec231b..990e68e257 100644 --- a/public/language/zh-CN/admin/dashboard.json +++ b/public/language/zh-CN/admin/dashboard.json @@ -13,26 +13,26 @@ "page-views-custom-start": "范围开始", "page-views-custom-end": "范围结束", "page-views-custom-help": "输入您要查看的网页浏览日期范围。 如果没有日期选择器可用,则接受的格式是 YYYY-MM-DD", - "page-views-custom-error": "请输入 YYYY-MM-DD格式的有效日期范围 ", + "page-views-custom-error": "请输入以YYYY-MM-DD格式的有效的日期范围 ", "stats.yesterday": "昨天", "stats.today": "今天", "stats.last-week": "上一周", - "stats.this-week": "本周", + "stats.this-week": "此周", "stats.last-month": "上一月", - "stats.this-month": "本月", + "stats.this-month": "此月", "stats.all": "总计", "updates": "更新", "running-version": "您正在运行 NodeBB v%1 .", "keep-updated": "请确保您已及时更新 NodeBB 以获得最新的安全补丁与 Bug 修复。", "up-to-date": "你处于最新版本", - "upgrade-available": "一个新的版本(v%1)已经发布。建议您升级你的 NodeBB 。", - "prerelease-upgrade-available": "这是一个过时的预发布版本的 NodeBB 。一个新的版本(v%1)已经发布。考虑升级你的 NodeBB 。", - "prerelease-warning": "这是NodeBB的一个预发布版本。可能会出现意想不到的错误。", - "fallback-emailer-not-found": "找不到备用邮箱", - "running-in-development": "论坛正以开发模式运行。该论坛可能存在潜在的漏洞,请联系您的系统管理员。", - "latest-lookup-failed": "查询NodeBB的最新可用版本失败", + "upgrade-available": "新版本(v%1)已发布。建议您升级您的 NodeBB 。", + "prerelease-upgrade-available": "这是一个过时的预发布版本的 NodeBB 。一个新版本(v%1)已经发布。考虑升级您的 NodeBB 。", + "prerelease-warning": "这是NodeBB的一个预发布版本。可能会出现不平衡。", + "fallback-emailer-not-found": "备用邮箱发送器没有找到!", + "running-in-development": "论坛正以开发模式运行。处于该模式的论坛可能存在潜在的漏洞,请联系您的论坛管理员。", + "latest-lookup-failed": "查询NodeBB的最新版本失败", "notices": "提醒", "restart-not-required": "不需要重启", @@ -42,12 +42,13 @@ "search-plugin-tooltip": "在插件页面安装搜索插件来激活搜索功能", "control-panel": "系统控制", - "rebuild-and-restart": "部署 & 重启", + "rebuild-and-restart": "重载 & 重启", "restart": "重启", "restart-warning": "重载或重启 NodeBB 会丢失数秒内全部的连接。", "restart-disabled": "重建和重新启动NodeBB已被禁用,因为您似乎没有通过适当的守护进程运行它。", "maintenance-mode": "维护模式", "maintenance-mode-title": "点击此处设置 NodeBB 的维护模式", + "dark-mode": "Dark Mode", "realtime-chart-updates": "实时图表更新", "active-users": "活跃用户", @@ -60,7 +61,7 @@ "guest": "游客", "registered": "已注册", - "user-presence": "用户光临", + "user-presence": "用户访问", "on-categories": "在版块列表", "reading-posts": "读帖子", "browsing-topics": "浏览话题", @@ -89,5 +90,9 @@ "details.logins-login-time": "登录时间", "start": "开始", "end": "结束", - "filter": "过滤器" + "filter": "过滤器", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/zh-CN/admin/manage/categories.json b/public/language/zh-CN/admin/manage/categories.json index 2d51d702c9..301bc332ca 100644 --- a/public/language/zh-CN/admin/manage/categories.json +++ b/public/language/zh-CN/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "标签白名单", "upload-image": "上传图片", "upload": "上传", - "select-icon": "选择图标", "delete-image": "移除", "category-image": "版块图片", "image-and-icon": "图片和图标", diff --git a/public/language/zh-CN/admin/manage/users.json b/public/language/zh-CN/admin/manage/users.json index e53a2b051f..94e8dd4cd6 100644 --- a/public/language/zh-CN/admin/manage/users.json +++ b/public/language/zh-CN/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "删除用户和内容", "download-csv": "下载CSV", "manage-groups": "管理用户组", + "set-reputation": "Set Reputation", "add-group": "添加至群组", "create": "创建用户", "invite": "通过邮件邀请", diff --git a/public/language/zh-CN/admin/menu.json b/public/language/zh-CN/admin/menu.json index 0e33098536..b3a78239cf 100644 --- a/public/language/zh-CN/admin/menu.json +++ b/public/language/zh-CN/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "用户", "manage/admins-mods": "权限分配", "manage/registration": "注册申请", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "发帖队列", "manage/groups": "群组", "manage/ip-blacklist": "IP 黑名单", diff --git a/public/language/zh-CN/admin/settings/chat.json b/public/language/zh-CN/admin/settings/chat.json index eb38710164..85fc21ca23 100644 --- a/public/language/zh-CN/admin/settings/chat.json +++ b/public/language/zh-CN/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "禁止编辑/删除聊天消息", "disable-editing-help": "管理员和超级管理员不受此限制", "max-length": "聊天信息的最大长度", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "聊天室的最多用户数", "delay": "聊天信息间的毫秒数", "notification-delay": "聊天信息的通知延迟(0 为即时)", diff --git a/public/language/zh-CN/admin/settings/guest.json b/public/language/zh-CN/admin/settings/guest.json index c9ebe43739..acf4410aab 100644 --- a/public/language/zh-CN/admin/settings/guest.json +++ b/public/language/zh-CN/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "设置", - "guest-settings": "访客设置", + "guest-settings": "Guest Settings", "handles.enabled": "允许游客用户名", "handles.enabled-help": "这个选项将允许游客使用一个额外的输入框来设置发帖时的用户名,如果被禁用,仅会统一显示为“游客”", "topic-views.enabled": "将来自游客的浏览记入帖子的浏览数", diff --git a/public/language/zh-CN/email.json b/public/language/zh-CN/email.json index d4d5e1fc8e..30fff5787f 100644 --- a/public/language/zh-CN/email.json +++ b/public/language/zh-CN/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "更改密码成功", "reset.notify.text1": "您在 %1 上的密码已经成功修改。", "reset.notify.text2": "如果您没有授权此操作,请立即联系管理员。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "来自 %1 的最新主题", "digest.top-topics": "来自 %1 的关注主题", "digest.popular-topics": "来自 %1 的热门主题 ", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index a1df0db9e5..81a756b102 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "抱歉,此账号已被封禁,直到 %1(原因:%2)", "user-too-new": "抱歉,您需要等待 %1 秒后,才可以发帖!", "blacklisted-ip": "对不起,您的 IP 地址已被社区禁用。如果您认为这是一个错误,请与管理员联系。", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "请提供此次禁言结束日期", "no-category": "版块不存在", "no-topic": "主题不存在", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "聊天室不存在。", "cant-add-users-to-chat-room": "无法添加用户到聊天室。", "cant-remove-users-from-chat-room": "无法从聊天室删除用户。", - "chat-room-name-too-long": "聊天室名过长。", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "您已为此帖回复投过票了。", "reputation-system-disabled": "声望系统已禁用。", "downvoting-disabled": "踩已被禁用", @@ -199,6 +200,7 @@ "not-in-room": "用户已不在聊天室中", "cant-kick-self": "您不能把自己踢出群组", "no-users-selected": "尚未选择用户", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "无效的首页路径", "invalid-session": "无效的会话", "invalid-session-text": "您的登录会话似乎不再处于活动状态。请刷新此页面。", diff --git a/public/language/zh-CN/global.json b/public/language/zh-CN/global.json index 6cd895b4b8..077e4061ff 100644 --- a/public/language/zh-CN/global.json +++ b/public/language/zh-CN/global.json @@ -51,6 +51,8 @@ "nextpage": "下一页", "alert.success": "成功", "alert.error": "错误", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "已封禁", "alert.banned.message": "您已被禁止,您当前的访问受到限制。", "alert.unbanned": "已解封", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index c7ce0d5e37..78c10e8929 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "暂无聊天", "chat.user_typing": "%1 正在输入……", "chat.user_has_messaged_you": "%1 向您发送了消息。", + "chat.replying-to": "Replying to %1", "chat.see_all": "全部对话", "chat.mark_all_read": "标记全部已读", "chat.no-messages": "请选择接收人,以查看聊天消息历史", @@ -27,22 +28,43 @@ "chat.three_months": "3个月", "chat.delete_message_confirm": "您确定您要删除此消息吗?", "chat.retrieving-users": "查找用户", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "在这里查找更多用户。被选中的用户会被添加到聊天中。新用户不能他们被加入对话前的聊天消息。只有聊天室所有者()可以从聊天室中移除用户。", "chat.confirm-chat-with-dnd-user": "该用户已将其状态设置为 DnD(请勿打扰)。 您仍希望与其聊天吗?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "重命名房间", "chat.rename-placeholder": "在这里输入房间名字", "chat.rename-help": "这里设置的房间名字能够被房间内所有人都看到。", - "chat.leave": "离开聊天室", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "您确定您要离开聊天室?", "chat.leave-help": "离开此聊天会切断您和此聊天以后的联系。如果您未来重新加入了,您将不能看到您重新加入之前的聊天记录。", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "在此房间", "chat.kick": "踢出", "chat.show-ip": "显示 IP", "chat.owner": "房间所有者", - "chat.system.user-join": "%1 加入了房间", - "chat.system.user-leave": "%1 离开了房间", - "chat.system.room-rename": "%2 更改房间名为:%1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "编写帮助", "composer.show_preview": "显示预览", "composer.hide_preview": "隐藏预览", diff --git a/public/language/zh-CN/topic.json b/public/language/zh-CN/topic.json index 678e3c5ad1..0f7bd5397e 100644 --- a/public/language/zh-CN/topic.json +++ b/public/language/zh-CN/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "编写", "wrote-on": "写于", "replied-to-user-ago": "回复了%3 ", - "replied-to-user-on": "在 中回复了%3", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 锁定了该主题 %2", "user-locked-topic-on": "%1 在 %2 中锁定了该主题", "user-unlocked-topic-ago": "%1 解锁了该主题 %2", diff --git a/public/language/zh-TW/admin/admin.json b/public/language/zh-TW/admin/admin.json index f5814c10c4..2885f18659 100644 --- a/public/language/zh-TW/admin/admin.json +++ b/public/language/zh-TW/admin/admin.json @@ -12,5 +12,7 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/zh-TW/admin/dashboard.json b/public/language/zh-TW/admin/dashboard.json index de215a568e..0f7a66ab6d 100644 --- a/public/language/zh-TW/admin/dashboard.json +++ b/public/language/zh-TW/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "重建和重新啟動NodeBB已被禁用,因為您似乎沒有通過適當的守護進程運行它。", "maintenance-mode": "維護模式", "maintenance-mode-title": "點擊此處設置 NodeBB 的維護模式", + "dark-mode": "Dark Mode", "realtime-chart-updates": "即時圖表更新", "active-users": "活躍使用者", @@ -89,5 +90,9 @@ "details.logins-login-time": "登入時間", "start": "Start", "end": "End", - "filter": "Filter" + "filter": "Filter", + "view-as-json": "View as JSON", + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/zh-TW/admin/manage/categories.json b/public/language/zh-TW/admin/manage/categories.json index 5172bf8f69..b1b4d88422 100644 --- a/public/language/zh-TW/admin/manage/categories.json +++ b/public/language/zh-TW/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "上傳圖片", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "移除", "category-image": "版面圖片", "image-and-icon": "Image & Icon", diff --git a/public/language/zh-TW/admin/manage/users.json b/public/language/zh-TW/admin/manage/users.json index 15d1c53559..403dd12ccf 100644 --- a/public/language/zh-TW/admin/manage/users.json +++ b/public/language/zh-TW/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "下載CSV", "manage-groups": "管理群組", + "set-reputation": "Set Reputation", "add-group": "新增至群組", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/zh-TW/admin/menu.json b/public/language/zh-TW/admin/menu.json index a22836e04f..83151597be 100644 --- a/public/language/zh-TW/admin/menu.json +++ b/public/language/zh-TW/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "使用者", "manage/admins-mods": "權限分配", "manage/registration": "註冊申請", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "貼文隊列", "manage/groups": "群組", "manage/ip-blacklist": "IP 黑名單", diff --git a/public/language/zh-TW/admin/settings/chat.json b/public/language/zh-TW/admin/settings/chat.json index a98f078d7d..b6b7b88f63 100644 --- a/public/language/zh-TW/admin/settings/chat.json +++ b/public/language/zh-TW/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "禁止編輯/刪除聊天消息", "disable-editing-help": "管理員和超級版主不受此限制", "max-length": "聊天訊息的最大長度", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "聊天室的最多使用者數", "delay": "聊天訊息間的毫秒數", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/zh-TW/admin/settings/guest.json b/public/language/zh-TW/admin/settings/guest.json index ca59f2b225..08d7c5c1ab 100644 --- a/public/language/zh-TW/admin/settings/guest.json +++ b/public/language/zh-TW/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "允許訪客使用者名", "handles.enabled-help": "這個選項將允許訪客使用一個額外的輸入框來設置發文時的使用者名,如果被禁用,僅會統一顯示為“訪客”", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/zh-TW/email.json b/public/language/zh-TW/email.json index 66eb2196e4..f97f57a397 100644 --- a/public/language/zh-TW/email.json +++ b/public/language/zh-TW/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "更改密碼成功", "reset.notify.text1": "您在 %1 上的密碼已經成功修改。", "reset.notify.text2": "如果您沒有授權此操作,請立即聯繫管理員。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "來自 %1 的最新主題", "digest.top-topics": "來自 %1 的置頂主題", "digest.popular-topics": "來自 %1 的熱門主題", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index a7f3a3fb44..3dec8cadab 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -55,6 +55,7 @@ "user-banned-reason-until": "抱歉,此帳戶已被停權,直到%1(原因:%2)", "user-too-new": "抱歉,您需要等待 %1 秒後,才可以發文!", "blacklisted-ip": "對不起,您的 IP 地址已被社區封鎖。如果您認為這是一個錯誤,請與管理員聯繫。", + "cant-blacklist-self-ip": "You can't blacklist your own IP", "ban-expiry-missing": "請提供此次停權結束日期", "no-category": "版面不存在", "no-topic": "主題不存在", @@ -164,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "您已讚過此貼文回覆了。", "reputation-system-disabled": "聲望系統已停用。", "downvoting-disabled": "倒讚已被停用", @@ -199,6 +200,7 @@ "not-in-room": "使用者已不在聊天室中", "cant-kick-self": "您不能把自己踢出群組", "no-users-selected": "尚未選擇使用者", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "無效的首頁路徑", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/zh-TW/global.json b/public/language/zh-TW/global.json index 191be4a230..e08e651375 100644 --- a/public/language/zh-TW/global.json +++ b/public/language/zh-TW/global.json @@ -51,6 +51,8 @@ "nextpage": "下一頁", "alert.success": "成功", "alert.error": "錯誤", + "alert.warning": "Warning", + "alert.info": "Info", "alert.banned": "已停權", "alert.banned.message": "You have just been banned, your access is now restricted.", "alert.unbanned": "Unbanned", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index f20afdb943..0f209c2cb1 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "暫無聊天", "chat.user_typing": "%1 正在輸入……", "chat.user_has_messaged_you": "%1 向您發送了訊息。", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "請選擇接收人,以查看聊天訊息紀錄", @@ -27,22 +28,43 @@ "chat.three_months": "3個月", "chat.delete_message_confirm": "您確定刪除此訊息嗎?", "chat.retrieving-users": "搜尋使用者", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", + "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", + "chat.select-groups": "Select Groups", "chat.add-user-help": "在這裡搜尋更多使用者。選中之後加入到聊天中,新使用者在加入聊天之前看不到聊天訊息。只有聊天室所有者()可以從聊天室中移除使用者。", "chat.confirm-chat-with-dnd-user": "該使用者已將其狀態設置為 DnD(請勿打擾)。 您仍希望與其聊天嗎?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "重新命名房間", "chat.rename-placeholder": "在這裡輸入房間名字", "chat.rename-help": "這裡設定的房間名字能夠被房間內所有人都看到。", - "chat.leave": "離開聊天室", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "您確定要離開聊天室?", "chat.leave-help": "離開此聊天會將您在聊天中的未接收的訊息移除。您在重新加入之後不會看到任何聊天記錄", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "在此房間", "chat.kick": "踢出", "chat.show-ip": "顯示 IP", "chat.owner": "房間所有者", - "chat.system.user-join": "%1 加入了房間", - "chat.system.user-leave": "%1 離開了房間", - "chat.system.room-rename": "%2 更改房間名為:%1", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "撰寫", "composer.show_preview": "顯示預覽", "composer.hide_preview": "隱藏預覽", diff --git a/public/language/zh-TW/topic.json b/public/language/zh-TW/topic.json index 5bc0248fdf..9abb730376 100644 --- a/public/language/zh-TW/topic.json +++ b/public/language/zh-TW/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 91c41f777b..36404313ff 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -1,17 +1,29 @@ RoomObject: type: object properties: - owner: - type: number - description: the uid of the chat room owner (usually the user who created the room initially) roomId: type: number description: unique identifier for the chat room roomName: type: string + description: the name of the room, if set this is displayed instead of the usernames groupChat: type: boolean - description: whether the chat room is a group chat or not + description: whether the chat room is a group chat or not (if more than 2 users it is a group chat) + public: + type: boolean + description: whether the chat room is public or private + userCount: + type: number + description: number of users in this chat room + groups: + type: array + description: list of groups that can access the room + timestamp: + type: number + description: Timestamp of when room was created + notificationSetting: + type: number MessageObject: type: object properties: @@ -25,15 +37,17 @@ MessageObject: roomId: type: number deleted: - type: boolean + type: number system: - type: boolean + type: number edited: type: number timestampISO: type: string editedISO: type: string + mid: + type: number messageId: type: number fromUser: @@ -92,8 +106,6 @@ MessageObject: type: number newSet: type: boolean - cleanedContent: - type: string RoomUserList: type: object properties: @@ -132,6 +144,12 @@ RoomUserList: type: boolean canKick: type: boolean + canToggleOwner: + type: boolean + index: + type: number + online: + type: boolean RoomObjectFull: # Messaging.loadRoom allOf: diff --git a/public/openapi/components/schemas/TagObject.yaml b/public/openapi/components/schemas/TagObject.yaml index 2b72c5a1c9..7b3583ef69 100644 --- a/public/openapi/components/schemas/TagObject.yaml +++ b/public/openapi/components/schemas/TagObject.yaml @@ -7,13 +7,12 @@ TagObject: score: type: number description: The number of topics containing this tag + class: + type: string + description: Class name that is applied to the to the tag html element valueEscaped: type: string - color: + description: value escaped with validator.escape + valueEncoded: type: string - description: Six-character hexadecimal string (with `#` prepended) - example: "#ff0000" - bgColor: - type: string - description: Six-character hexadecimal string (with `#` prepended) - example: "#ff0000" \ No newline at end of file + description: value url encoded diff --git a/public/openapi/read/admin/manage/categories/category_id/analytics.yaml b/public/openapi/read/admin/manage/categories/category_id/analytics.yaml index 4805c4729b..eb6922114f 100644 --- a/public/openapi/read/admin/manage/categories/category_id/analytics.yaml +++ b/public/openapi/read/admin/manage/categories/category_id/analytics.yaml @@ -39,4 +39,6 @@ get: type: array items: type: number + selectedCategory: + $ref: ../../../../../components/schemas/CategoryObject.yaml#/CategoryObject - $ref: ../../../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/config.yaml b/public/openapi/read/config.yaml index 61fcfb4bba..795ef2f2d0 100644 --- a/public/openapi/read/config.yaml +++ b/public/openapi/read/config.yaml @@ -275,3 +275,14 @@ get: type: boolean composer-default: type: object + fontawesome: + type: object + properties: + pro: + type: boolean + styles: + type: array + items: + type: string + version: + type: string diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index 767ea88d0c..cb350aa2e0 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -24,12 +24,27 @@ get: allOf: - type: object properties: - owner: - type: number roomId: type: number roomName: type: string + public: + type: boolean + userCount: + type: number + icon: + type: string + groups: + type: array + timestamp: + type: number + description: Timestamp of when room was created + notificationSetting: + type: number + notificationOptions: + type: array + notificationOptionsIcon: + type: string messages: type: array items: @@ -44,9 +59,9 @@ get: roomId: type: string deleted: - type: boolean + type: number system: - type: boolean + type: number edited: type: number timestampISO: @@ -54,6 +69,8 @@ get: description: An ISO 8601 formatted date string (complementing `timestamp`) editedISO: type: string + mid: + type: number messageId: type: number fromUser: @@ -101,8 +118,6 @@ get: type: boolean index: type: number - cleanedContent: - type: string isOwner: type: boolean isOwner: @@ -126,6 +141,8 @@ get: nullable: true status: type: string + online: + type: boolean icon:text: type: string description: A single-letter representation of a username. This is used in the @@ -139,6 +156,8 @@ get: example: "#f44336" isOwner: type: boolean + index: + type: number canReply: type: boolean groupChat: @@ -153,19 +172,26 @@ get: type: boolean isAdminOrGlobalMod: type: boolean + isAdmin: + type: boolean rooms: type: array items: type: object properties: - owner: - oneOf: - - type: number - - type: string roomId: type: number roomName: type: string + public: + type: boolean + userCount: + type: number + groups: + type: array + timestamp: + type: number + description: Timestamp of when room was created users: type: array items: @@ -300,6 +326,159 @@ get: type: string chatWithMessage: type: string + notificationSetting: + type: number + publicRooms: + type: array + items: + type: object + properties: + owner: + oneOf: + - type: number + - type: string + roomId: + type: number + roomName: + type: string + public: + type: boolean + users: + type: array + items: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + lastonlineISO: + type: string + groupChat: + type: boolean + unread: + type: boolean + teaser: + type: object + properties: + fromuid: + type: number + content: + type: string + timestamp: + type: number + timestampISO: + type: string + description: An ISO 8601 formatted date string (complementing `timestamp`) + user: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users + without an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's + auto-generated icon + example: "#f44336" + lastonlineISO: + type: string + nullable: true + lastUser: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + lastonlineISO: + type: string + usernames: + type: string + chatWithMessage: + type: string + privateRoomCount: + type: number nextStart: type: number title: @@ -315,4 +494,6 @@ get: type: boolean chatWithMessage: type: string + bodyClasses: + type: array - $ref: ../../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 101da200d1..e12e1ce2db 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -198,6 +198,8 @@ paths: $ref: 'write/admin/analytics.yaml' /admin/analytics/{set}: $ref: 'write/admin/analytics/set.yaml' + /admin/chats/{roomId}: + $ref: 'write/admin/chats/roomId.yaml' /admin/tokens: $ref: 'write/admin/tokens.yaml' /admin/tokens/{token}: diff --git a/public/openapi/write/admin/chats/roomId.yaml b/public/openapi/write/admin/chats/roomId.yaml new file mode 100644 index 0000000000..a7d2317cd2 --- /dev/null +++ b/public/openapi/write/admin/chats/roomId.yaml @@ -0,0 +1,26 @@ +delete: + tags: + - admin + summary: delete chat room + description: This operation deletes a chat room from the database + parameters: + - in: path + name: roomId + schema: + type: number + description: The roomId to be deleted + example: 1 + required: true + responses: + '200': + description: Chat room deleted + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object + properties: {} \ No newline at end of file diff --git a/public/openapi/write/chats/roomId.yaml b/public/openapi/write/chats/roomId.yaml index 3473c92e1b..62ae9df2bd 100644 --- a/public/openapi/write/chats/roomId.yaml +++ b/public/openapi/write/chats/roomId.yaml @@ -86,8 +86,6 @@ post: newSet: type: boolean description: Whether the message is considered part of a new "set" of messages. It is used in the frontend UI for explicitly denoting that a time gap existed between messages. - cleanedContent: - type: string mid: type: number put: diff --git a/public/scss/admin/admin.scss b/public/scss/admin/admin.scss index c7ee741967..d74d386cf4 100644 --- a/public/scss/admin/admin.scss +++ b/public/scss/admin/admin.scss @@ -17,7 +17,7 @@ @import "./extend/widgets"; @import "settings"; -@import "./modules/alerts"; +@import "../modules/alerts"; @import "./modules/selectable"; @import "./modules/nprogress"; @import "./modules/search"; @@ -37,7 +37,7 @@ body { padding-top: 0; } .acp-page-main-header { - background-color: white; + background-color: var(--bs-body-bg); } .settings, .categories, .category, .admins-mods { @@ -83,17 +83,17 @@ body { } .card:not([data-container-html]) { - background-color: #FFF; + background-color: var(--bs-body-bg); box-sizing: border-box; border-radius: 3px; border-width: 0px; - box-shadow: 0px 1px 3px 0px rgba(165, 165, 165, 0.75); + box-shadow: 0px 1px 3px 0px rgba(var(--bs-secondary-rgb), 0.5); margin-bottom: 20px; >.card-header { @include acp-panel-heading; - background: #fefefe; - color: #333; + background-color: var(--bs-body-bg); + color: var(--bs-body-color); } &.card-danger >.card-header { @@ -113,7 +113,7 @@ body { cursor: pointer; line-height: 36px; text-align: center; - color: $gray-800; + color: $gray-700; margin: 4px; &:hover, &.selected { @@ -136,7 +136,8 @@ body { .bootstrap-tagsinput { box-shadow: $input-box-shadow; width: 100%; - + background-color: var(--bs-body-bg); + border: var(--bs-border-width) solid var(--bs-border-color); input { font-size: 0.875rem; width: 64px; diff --git a/public/scss/admin/common.scss b/public/scss/admin/common.scss index 85cea66ed2..b94eddd2da 100644 --- a/public/scss/admin/common.scss +++ b/public/scss/admin/common.scss @@ -13,8 +13,6 @@ .tracking-tight { letter-spacing: -0.02em; } -$btn-ghost-hover-color: mix($light, $dark, 90%); - @mixin btn-ghost-base { display: flex; align-items: center; @@ -27,12 +25,11 @@ $btn-ghost-hover-color: mix($light, $dark, 90%); padding: ($spacer * 0.25) ($spacer * 0.5); text-align: left; --bs-text-opacity: 1; - color: rgb(73 80 87 / var(--bs-text-opacity)); + color: $btn-ghost-color; font-family: $font-family-secondary; cursor: pointer; &:hover, &.active { background-color: $btn-ghost-hover-color; - color: rgb(73 80 87 / var(--bs-text-opacity)); text-decoration: none; } } @@ -66,6 +63,23 @@ $btn-ghost-hover-color: mix($light, $dark, 90%); line-height: 1.25rem; } +@include color-mode(dark) { + #content { + .btn-light { + @extend .btn-dark; + } + .text-bg-light { + @extend .text-bg-dark; + } + .btn-ghost, .btn-ghost-sm, .btn-outline, .btn-outline-sm { + color: $btn-ghost-color-dark; + &:hover, &.active { + background-color: $btn-ghost-hover-color-dark; + } + } + } +} + .flex-basis-md-200 { @include media-breakpoint-up(md) { flex-basis: 200px!important; diff --git a/public/scss/admin/general/dashboard.scss b/public/scss/admin/general/dashboard.scss index b21799e51c..cecbbb1dbe 100644 --- a/public/scss/admin/general/dashboard.scss +++ b/public/scss/admin/general/dashboard.scss @@ -7,7 +7,7 @@ .graph-container { position: relative; - background: $body-bg; + background: var(--bg-body-bg); &.fullscreen { width: 100%; @@ -70,8 +70,6 @@ list-style-type: none; padding: 0.5rem 1rem; margin: 0; - background: rgba(255, 255, 255, 0.66); - border: 1px solid #ddd; li { div { @@ -138,19 +136,6 @@ } } - .stats { - .formatted-number { - font-size: 22px; - } - - .stat { - text-transform: uppercase; - font-weight: 600; - font-size: 10px; - color: #999; - } - } - .updatePageviewsGraph.active { font-weight: bold; } diff --git a/public/scss/admin/general/navigation.scss b/public/scss/admin/general/navigation.scss index ada36aeeea..7233458abe 100644 --- a/public/scss/admin/general/navigation.scss +++ b/public/scss/admin/general/navigation.scss @@ -11,11 +11,10 @@ #active-navigation { float: none; min-height: 50px; - border: 1px solid #eee; overflow: auto; .active { - background-color: #eee; + background-color: var(--bs-secondary-bg); } li a { @@ -25,9 +24,9 @@ li { display: inline-block; >a:hover, >a:focus { - color: $gray-300; - background-color: $gray-700; - } + color: var(--bs-secondary-color); + background-color: var(--bs-secondary-bg); + } } } diff --git a/public/scss/admin/manage/privileges.scss b/public/scss/admin/manage/privileges.scss index e411bd94e6..f2d11eed4e 100644 --- a/public/scss/admin/manage/privileges.scss +++ b/public/scss/admin/manage/privileges.scss @@ -4,7 +4,7 @@ 100% {background-color: white;} } - [data-group-name].selected, [data-uid].selected { + tr[data-group-name].selected, tr[data-uid].selected { animation-name: fadeOut; animation-duration: 5s; animation-fill-mode: both; diff --git a/public/scss/admin/modules/alerts.scss b/public/scss/admin/modules/alerts.scss deleted file mode 100644 index a42b684a5f..0000000000 --- a/public/scss/admin/modules/alerts.scss +++ /dev/null @@ -1,124 +0,0 @@ -.alert-window { - position: fixed; - width: 300px; - z-index: 10002; - - right: 20px; - bottom: 0px; - - .alert { - .close { - color: inherit; - } - - &::before { - position: relative; - top: -15px; - left: -15px; - display: block; - height: 2px; - width: 0; - transition: inherit; - } - - &.alert-info { - .btn-close { - $btn-close-color: $info; - background-image: escape-svg(url("data:image/svg+xml,")); - } - - &::before { - background-color: $info; - } - } - - &.alert-warning { - .btn-close { - $btn-close-color: $warning; - background-image: escape-svg(url("data:image/svg+xml,")); - } - - ::before { - background-color: $warning; - } - } - - &.alert-success { - .btn-close { - $btn-close-color: $success; - background-image: escape-svg(url("data:image/svg+xml,")); - } - - ::before { - background-color: $success; - } - } - - &.alert-danger { - .btn-close { - $btn-close-color: $danger; - background-image: escape-svg(url("data:image/svg+xml,")); - } - - ::before { - background-color: $danger; - } - } - - &.animate { - &.alert-info::before { - background-color: lighten($info, 25%); - } - - &.alert-warning::before { - background-color: lighten($warning, 25%); - } - - &.alert-success::before { - background-color: lighten($success, 25%); - } - - &.alert-danger::before { - background-color: lighten($danger, 25%); - } - - &::before { - width: calc(100% + 50px); - } - } - - background-color: white; - padding-right: 16px; - border: 0; - border-left: 5px solid !important; - box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.25), 0px 2px 10px 0px rgba(0, 0, 0, 0.25); - - strong { - text-transform: uppercase; - } - - p { - padding: 10px 0px 0px; - } - - &.alert-info { - color: $info; - border-color: $info; - } - - &.alert-warning { - color: $warning; - border-color: $warning; - } - - &.alert-success { - color: $success; - border-color: $success; - } - - &.alert-danger { - color: $danger; - border-color: $danger; - } - } -} diff --git a/public/scss/admin/overrides.scss b/public/scss/admin/overrides.scss index 58922bd310..90f71d908f 100644 --- a/public/scss/admin/overrides.scss +++ b/public/scss/admin/overrides.scss @@ -16,9 +16,17 @@ $yellow: #ffc107 !default; $green: #198754 !default; $cyan: #0dcaf0 !default; +$light: $gray-100 !default; +$dark: $gray-900 !default; + $body-color: $gray-800; $text-muted: $gray-600 !default; +$btn-ghost-color: rgb(73, 80, 87); +$btn-ghost-hover-color: mix($light, $dark, 90%); +$btn-ghost-color-dark: rgb(175, 191, 206); +$btn-ghost-hover-color-dark: mix($dark, $light, 90%); + // Custom fonts $font-family-sans-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; diff --git a/public/scss/client.scss b/public/scss/client.scss index 11e2d14c2f..3d134ceb42 100644 --- a/public/scss/client.scss +++ b/public/scss/client.scss @@ -4,4 +4,5 @@ @import "modals"; @import "modules/picture-switcher"; @import "modules/bottom-sheet"; -@import "modules/icon-picker"; \ No newline at end of file +@import "modules/icon-picker"; +@import "modules/alerts.scss"; \ No newline at end of file diff --git a/public/scss/fontawesome.scss b/public/scss/fontawesome.scss deleted file mode 100644 index cbe2a7e504..0000000000 --- a/public/scss/fontawesome.scss +++ /dev/null @@ -1,7 +0,0 @@ -$fa-font-path: "vendor/fontawesome/webfonts/6.2.0"; -@import "../public/vendor/fontawesome/scss/fontawesome"; -@import "../public/vendor/fontawesome/scss/regular"; -@import "../public/vendor/fontawesome/scss/solid"; -@import "../public/vendor/fontawesome/scss/brands"; -@import "../public/vendor/fontawesome/scss/v4-shims"; -@import "../public/vendor/fontawesome/scss/nodebb-shims"; \ No newline at end of file diff --git a/public/scss/fontawesome/loader.scss b/public/scss/fontawesome/loader.scss new file mode 100644 index 0000000000..81700f154d --- /dev/null +++ b/public/scss/fontawesome/loader.scss @@ -0,0 +1,4 @@ +$fa-font-path: "./fontawesome/webfonts"; +@import "fontawesome"; +@import "v4-shims"; +@import "nodebb-shims"; \ No newline at end of file diff --git a/public/vendor/fontawesome/scss/nodebb-shims.scss b/public/scss/fontawesome/nodebb-shims.scss similarity index 99% rename from public/vendor/fontawesome/scss/nodebb-shims.scss rename to public/scss/fontawesome/nodebb-shims.scss index 8c3bc5230d..04add18cd8 100644 --- a/public/vendor/fontawesome/scss/nodebb-shims.scss +++ b/public/scss/fontawesome/nodebb-shims.scss @@ -1,5 +1,5 @@ -@import "_variables.scss"; +// NodeBB backwards compatibility shims @font-face { font-family: 'FontAwesome'; font-style: normal; diff --git a/public/scss/fontawesome/style-brands.scss b/public/scss/fontawesome/style-brands.scss new file mode 100644 index 0000000000..52da4901e0 --- /dev/null +++ b/public/scss/fontawesome/style-brands.scss @@ -0,0 +1 @@ +@import "brands"; \ No newline at end of file diff --git a/public/scss/fontawesome/style-duotone.scss b/public/scss/fontawesome/style-duotone.scss new file mode 100644 index 0000000000..e285cc86fa --- /dev/null +++ b/public/scss/fontawesome/style-duotone.scss @@ -0,0 +1,2 @@ +@import "duotone"; +@import "_duotone-icons"; \ No newline at end of file diff --git a/public/scss/fontawesome/style-light.scss b/public/scss/fontawesome/style-light.scss new file mode 100644 index 0000000000..989bcd0bc5 --- /dev/null +++ b/public/scss/fontawesome/style-light.scss @@ -0,0 +1 @@ +@import "light"; diff --git a/public/scss/fontawesome/style-regular.scss b/public/scss/fontawesome/style-regular.scss new file mode 100644 index 0000000000..b85bc17bf1 --- /dev/null +++ b/public/scss/fontawesome/style-regular.scss @@ -0,0 +1 @@ +@import "regular"; diff --git a/public/scss/fontawesome/style-sharp-light.scss b/public/scss/fontawesome/style-sharp-light.scss new file mode 100644 index 0000000000..bdf377c050 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-light.scss @@ -0,0 +1 @@ +@import "sharp-light"; diff --git a/public/scss/fontawesome/style-sharp-regular.scss b/public/scss/fontawesome/style-sharp-regular.scss new file mode 100644 index 0000000000..4b9bf9a613 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-regular.scss @@ -0,0 +1 @@ +@import "sharp-regular"; diff --git a/public/scss/fontawesome/style-sharp-solid.scss b/public/scss/fontawesome/style-sharp-solid.scss new file mode 100644 index 0000000000..ae01f10776 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-solid.scss @@ -0,0 +1 @@ +@import "sharp-solid"; diff --git a/public/scss/fontawesome/style-sharp.scss b/public/scss/fontawesome/style-sharp.scss new file mode 100644 index 0000000000..7f2ae6f020 --- /dev/null +++ b/public/scss/fontawesome/style-sharp.scss @@ -0,0 +1,3 @@ +@import "sharp-light"; +@import "sharp-regular"; +@import "sharp-solid"; diff --git a/public/scss/fontawesome/style-solid.scss b/public/scss/fontawesome/style-solid.scss new file mode 100644 index 0000000000..ad46ec9b0b --- /dev/null +++ b/public/scss/fontawesome/style-solid.scss @@ -0,0 +1 @@ +@import "solid"; diff --git a/public/scss/fontawesome/style-thin.scss b/public/scss/fontawesome/style-thin.scss new file mode 100644 index 0000000000..ebe25b67e3 --- /dev/null +++ b/public/scss/fontawesome/style-thin.scss @@ -0,0 +1 @@ +@import "thin"; diff --git a/public/scss/modules/alerts.scss b/public/scss/modules/alerts.scss new file mode 100644 index 0000000000..25cf052df8 --- /dev/null +++ b/public/scss/modules/alerts.scss @@ -0,0 +1,45 @@ +.alert-window { + position: fixed; + width: 300px; + z-index: 10002; + + right: 20px; + bottom: 0px; + + .alert { + overflow: hidden; + position: relative; + + .alert-progress { + width: 0; + &.animate { + width: calc(100% + 50px); + } + } + + &.alert-info { + color: $info; + .alert-progress { background-color: $info; } + } + + &.alert-warning { + color: $warning; + .alert-progress { background-color: $warning; } + } + + &.alert-success { + color: $success; + .alert-progress { background-color: $success; } + } + + &.alert-danger { + color: $danger; + .alert-progress { background-color: $danger; } + } + + background-color: var(--bs-body-bg); + border: 0; + border-left: 5px solid !important; + box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.25), 0px 2px 10px 0px rgba(0, 0, 0, 0.25); + } +} diff --git a/public/src/admin/dashboard.js b/public/src/admin/dashboard.js index ab151a2bad..3cd0b93619 100644 --- a/public/src/admin/dashboard.js +++ b/public/src/admin/dashboard.js @@ -2,8 +2,8 @@ define('admin/dashboard', [ - 'Chart', 'translator', 'benchpress', 'bootbox', 'alerts', -], function (Chart, translator, Benchpress, bootbox, alerts) { + 'Chart', 'translator', 'benchpress', 'bootbox', 'alerts', 'helpers', +], function (Chart, translator, Benchpress, bootbox, alerts, helpers) { const Admin = {}; const intervals = { rooms: false, @@ -43,6 +43,7 @@ define('admin/dashboard', [ isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); + setupDarkModeButton(); setupRealtimeButton(); setupGraphs(function () { socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); @@ -63,20 +64,20 @@ define('admin/dashboard', [ graphData.rooms = data; const html = '
' + - '' + data.onlineRegisteredCount + '' + - '
[[admin/dashboard:active-users.users]]
' + + '' + helpers.formattedNumber(data.onlineRegisteredCount) + '' + + '
[[admin/dashboard:active-users.users]]
' + '
' + '
' + - '' + data.onlineGuestCount + '' + - '
[[admin/dashboard:active-users.guests]]
' + + '' + helpers.formattedNumber(data.onlineGuestCount) + '' + + '
[[admin/dashboard:active-users.guests]]
' + '
' + '
' + - '' + (data.onlineRegisteredCount + data.onlineGuestCount) + '' + - '
[[admin/dashboard:active-users.total]]
' + + '' + helpers.formattedNumber(data.onlineRegisteredCount + data.onlineGuestCount) + '' + + '
[[admin/dashboard:active-users.total]]
' + '
' + '
' + - '' + data.socketCount + '' + - '
[[admin/dashboard:active-users.connections]]
' + + '' + helpers.formattedNumber(data.socketCount) + '' + + '
[[admin/dashboard:active-users.connections]]
' + '
'; updateRegisteredGraph(data.onlineRegisteredCount, data.onlineGuestCount); @@ -436,12 +437,9 @@ define('admin/dashboard', [ } else { graphs.traffic.data.xLabels = utils.getHoursArray(); - $('#pageViewsThirty').html(data.summary.thirty); - $('#pageViewsSeven').html(data.summary.seven); - $('#pageViewsPastDay').html(data.pastDay); - utils.addCommasToNumbers($('#pageViewsThirty')); - utils.addCommasToNumbers($('#pageViewsSeven')); - utils.addCommasToNumbers($('#pageViewsPastDay')); + $('#pageViewsThirty').html(helpers.formattedNumber(data.summary.thirty)); + $('#pageViewsSeven').html(helpers.formattedNumber(data.summary.seven)); + $('#pageViewsPastDay').html(helpers.formattedNumber(data.pastDay)); } graphs.traffic.data.datasets[0].data = data.pageviews; @@ -532,18 +530,20 @@ define('admin/dashboard', [ graphs.topics.update(); } + function setupDarkModeButton() { + let bsTheme = localStorage.getItem('data-bs-theme') || 'light'; + $('#toggle-dark-mode').prop('checked', bsTheme === 'dark') + .on('click', function () { + const isChecked = $(this).is(':checked'); + bsTheme = isChecked ? 'dark' : 'light'; + $('html').attr('data-bs-theme', bsTheme); + localStorage.setItem('data-bs-theme', bsTheme); + }); + } + function setupRealtimeButton() { - $('#toggle-realtime .fa').on('click', function () { - const $this = $(this); - if ($this.hasClass('fa-toggle-on')) { - $this.removeClass('fa-toggle-on').addClass('fa-toggle-off'); - $this.parent().find('strong').html('OFF'); - initiateDashboard(false); - } else { - $this.removeClass('fa-toggle-off').addClass('fa-toggle-on'); - $this.parent().find('strong').html('ON'); - initiateDashboard(true); - } + $('#toggle-realtime').on('click', function () { + initiateDashboard($(this).is(':checked')); }); } diff --git a/public/src/admin/dashboard/searches.js b/public/src/admin/dashboard/searches.js new file mode 100644 index 0000000000..8e53847b64 --- /dev/null +++ b/public/src/admin/dashboard/searches.js @@ -0,0 +1,22 @@ +'use strict'; + +define('admin/dashboard/searches', ['alerts', 'bootbox'], (alerts, bootbox) => { + const ACP = {}; + + ACP.init = () => { + $('#clear-search-history').on('click', () => { + bootbox.confirm('[[admin/dashboard:clear-search-history-confirm]]', function (ok) { + if (ok) { + socket.emit('admin.clearSearchHistory', function (err) { + if (err) { + return alerts.error(err); + } + ajaxify.refresh(); + }); + } + }); + }); + }; + + return ACP; +}); diff --git a/public/src/admin/manage/category-analytics.js b/public/src/admin/manage/category-analytics.js index a4366d07d1..634f7a7e57 100644 --- a/public/src/admin/manage/category-analytics.js +++ b/public/src/admin/manage/category-analytics.js @@ -1,10 +1,20 @@ 'use strict'; -define('admin/manage/category-analytics', ['Chart'], function (Chart) { +define('admin/manage/category-analytics', [ + 'Chart', 'categorySelector', +], function (Chart, categorySelector) { const CategoryAnalytics = {}; CategoryAnalytics.init = function () { + categorySelector.init($('[component="category-selector"]'), { + onSelect: function (selectedCategory) { + ajaxify.go('admin/manage/categories/' + selectedCategory.cid + '/analytics'); + }, + showLinks: true, + template: 'admin/partials/category/selector-dropdown-right', + }); + const hourlyCanvas = document.getElementById('pageviews:hourly'); const dailyCanvas = document.getElementById('pageviews:daily'); const topicsCanvas = document.getElementById('topics:daily'); diff --git a/public/src/admin/manage/tags.js b/public/src/admin/manage/tags.js index ea6ab15c59..aba143ddf7 100644 --- a/public/src/admin/manage/tags.js +++ b/public/src/admin/manage/tags.js @@ -59,7 +59,6 @@ define('admin/manage/tags', [ tags: tags, }, function (html) { $('.tag-list').html(html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); selectable.enable('.tag-management', '.tag-row'); }); } diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index 1fb8e2701d..613389d9f9 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -1,8 +1,8 @@ 'use strict'; define('admin/manage/users', [ - 'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite', -], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite) { + 'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite', 'helpers', +], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite, helpers) { const Users = {}; Users.init = function () { @@ -141,6 +141,53 @@ define('admin/manage/users', [ }); }); + $('.set-reputation').on('click', function () { + const uids = getSelectedUids(); + if (!uids.length) { + alerts.error('[[error:no-users-selected]]'); + return false; + } + let currentValue = ''; + if (uids.length === 1) { + const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uids[0], 10)); + if (user) { + currentValue = String(user.reputation); + } + } + const modal = bootbox.dialog({ + message: ``, + title: '[[admin/manage/users:set-reputation]]', + onEscape: true, + buttons: { + submit: { + label: '[[global:save]]', + callback: function () { + const newReputation = modal.find('#new-reputation').val(); + if (!utils.isNumber(newReputation)) { + alerts.error('[[error:invalid-data]]'); + return false; + } + socket.emit('admin.user.setReputation', { + value: newReputation, + uids: uids, + }).then(() => { + uids.forEach((uid) => { + $(`[component="user/reputation"][data-uid="${uid}"]`).text(helpers.formattedNumber(newReputation)); + const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uid, 10)); + if (user) { + user.reputation = newReputation; + } + }); + }).catch(alerts.error); + }, + }, + }, + }); + modal.on('shown.bs.modal', () => { + modal.find('#new-reputation').selectRange(0, modal.find('#new-reputation').val().length); + }); + }); + $('.ban-user').on('click', function () { const uids = getSelectedUids(); if (!uids.length) { diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 8111f0ef09..be16af3e91 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -1,5 +1,8 @@ 'use strict'; +const benchpress = require('benchpressjs'); +const translator = require('./modules/translator'); +const alerts = require('./modules/alerts'); const hooks = require('./modules/hooks'); const { render } = require('./widgets'); @@ -160,9 +163,7 @@ ajaxify.widgets = { render: render }; $('#footer, #content').removeClass('hide').addClass('ajaxifying'); return renderTemplate(url, status.toString(), data.responseJSON || {}, callback); } else if (status === 401) { - require(['alerts'], function (alerts) { - alerts.error('[[global:please_log_in]]'); - }); + alerts.error('[[global:please_log_in]]'); app.previousUrl = url; window.location.href = config.relative_path + '/login'; } else if (status === 302 || status === 308) { @@ -180,55 +181,51 @@ ajaxify.widgets = { render: render }; } } } else if (textStatus !== 'abort') { - require(['alerts'], function (alerts) { - alerts.error(data.responseJSON.error); - }); + alerts.error(data.responseJSON.error); } } function renderTemplate(url, tpl_url, data, callback) { hooks.fire('action:ajaxify.loadingTemplates', {}); - require(['translator', 'benchpress'], function (translator, Benchpress) { - Benchpress.render(tpl_url, data) - .then(rendered => translator.translate(rendered)) - .then(function (translated) { - translated = translator.unescape(translated); - $('body').removeClass(previousBodyClass).addClass(data.bodyClass); - $('#content').html(translated); + benchpress.render(tpl_url, data) + .then(rendered => translator.translate(rendered)) + .then(function (translated) { + translated = translator.unescape(translated); + $('body').removeClass(previousBodyClass).addClass(data.bodyClass); + $('#content').html(translated); - ajaxify.end(url, tpl_url); + ajaxify.end(url, tpl_url); - if (typeof callback === 'function') { - callback(); - } + if (typeof callback === 'function') { + callback(); + } - $('#content, #footer').removeClass('ajaxifying'); + $('#content, #footer').removeClass('ajaxifying'); - // Only executed on ajaxify. Otherwise these'd be in ajaxify.end() - updateTitle(data.title); - updateTags(); - }); - }); + // Only executed on ajaxify. Otherwise these'd be in ajaxify.end() + updateTitle(data.title); + updateTags(); + }); } function updateTitle(title) { if (!title) { return; } - require(['translator'], function (translator) { - title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}') - .replace('{pageTitle}', function () { return title; }) - .replace('{browserTitle}', function () { return config.browserTitle; }); - // Allow translation strings in title on ajaxify (#5927) - title = translator.unescape(title); - const data = { title: title }; - hooks.fire('action:ajaxify.updateTitle', data); - translator.translate(data.title, function (translated) { - window.document.title = $('
').html(translated).text(); - }); + title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}') + .replace('{pageTitle}', function () { return title; }) + .replace('{browserTitle}', function () { return config.browserTitle; }); + + // Allow translation strings in title on ajaxify (#5927) + title = translator.unescape(title); + const data = { title: title }; + hooks.fire('action:ajaxify.updateTitle', data); + translator.translate(data.title, function (translated) { + window.document.title = $('
').html(translated).text(); }); } + ajaxify.updateTitle = updateTitle; function updateTags() { const metaWhitelist = ['title', 'description', /og:.+/, /article:.+/, 'robots'].map(function (val) { @@ -248,25 +245,25 @@ ajaxify.widgets = { render: render }; .forEach(function (el) { document.head.removeChild(el); }); - require(['translator'], function (translator) { - // Add new meta tags - ajaxify.data._header.tags.meta - .filter(function (tagObj) { - const name = tagObj.name || tagObj.property; - return metaWhitelist.some(function (exp) { - return !!exp.test(name); - }); - }).forEach(async function (tagObj) { - if (tagObj.content) { - tagObj.content = await translator.translate(tagObj.content); - } - const metaEl = document.createElement('meta'); - Object.keys(tagObj).forEach(function (prop) { - metaEl.setAttribute(prop, tagObj[prop]); - }); - document.head.appendChild(metaEl); + + // Add new meta tags + ajaxify.data._header.tags.meta + .filter(function (tagObj) { + const name = tagObj.name || tagObj.property; + return metaWhitelist.some(function (exp) { + return !!exp.test(name); }); - }); + }).forEach(async function (tagObj) { + if (tagObj.content) { + tagObj.content = await translator.translate(tagObj.content); + } + const metaEl = document.createElement('meta'); + Object.keys(tagObj).forEach(function (prop) { + metaEl.setAttribute(prop, tagObj[prop]); + }); + document.head.appendChild(metaEl); + }); + // Delete the old link tags Array.prototype.slice @@ -471,15 +468,13 @@ ajaxify.widgets = { render: render }; hooks.fire('action:ajaxify.cleanup', { url, tpl_url }); }; - require(['translator', 'benchpress', 'navigator'], function (translator, Benchpress) { - translator.translate('[[error:no-connection]]'); - translator.translate('[[error:socket-reconnect-failed]]'); - translator.translate(`[[global:reconnecting-message, ${config.siteTitle}]]`); - Benchpress.registerLoader(ajaxify.loadTemplate); - Benchpress.setGlobal('config', config); - Benchpress.render('500', {}); // loads and caches 500.tpl - Benchpress.render('partials/toast'); // loads and caches partials/toast - }); + translator.translate('[[error:no-connection]]'); + translator.translate('[[error:socket-reconnect-failed]]'); + translator.translate(`[[global:reconnecting-message, ${config.siteTitle}]]`); + benchpress.registerLoader(ajaxify.loadTemplate); + benchpress.setGlobal('config', config); + benchpress.render('500', {}); // loads and caches 500.tpl + benchpress.render('partials/toast'); // loads and caches partials/toast }()); $(document).ready(function () { diff --git a/public/src/app.js b/public/src/app.js index c457ae89f6..599792838f 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -253,8 +253,6 @@ if (document.readyState === 'loading') { highlightNavigationLink(); overrides.overrideTimeagoCutoff(); $('.timeago').timeago(); - utils.makeNumbersHumanReadable($('.human-readable-number')); - utils.addCommasToNumbers($('.formatted-number')); app.createUserTooltips($('#content')); app.createStatusTooltips(); }; diff --git a/public/src/client/account/posts.js b/public/src/client/account/posts.js index fbd7f555c7..deea51d851 100644 --- a/public/src/client/account/posts.js +++ b/public/src/client/account/posts.js @@ -45,7 +45,6 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll', ' $('[component="posts"]').append(html); html.find('img:not(.not-responsive)').addClass('img-fluid'); html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:posts.loaded', { posts: posts }); callback(); }); diff --git a/public/src/client/account/topics.js b/public/src/client/account/topics.js index 565bb9b170..7a95d01ceb 100644 --- a/public/src/client/account/topics.js +++ b/public/src/client/account/topics.js @@ -46,7 +46,6 @@ define('forum/account/topics', [ app.parseAndTranslate(template, 'topics', { topics: topics }, function (html) { $('[component="category"]').append(html); html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:topics.loaded', { topics: topics }); callback(); }); diff --git a/public/src/client/category.js b/public/src/client/category.js index 86f76381ab..a69ef64616 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -104,7 +104,6 @@ define('forum/category', [ app.parseAndTranslate('category', 'children', { children: data }, function (html) { html.find('.timeago').timeago(); $('[component="category/subcategory/container"]').append(html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); ajaxify.data.nextSubCategoryStart += ajaxify.data.subCategoriesPerPage; ajaxify.data.subCategoriesLeft -= data.length; btn.toggleClass('hidden', ajaxify.data.subCategoriesLeft <= 0) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 39cf3519c5..997092b53e 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -3,11 +3,13 @@ define('forum/chats', [ 'components', - 'translator', 'mousetrap', 'forum/chats/recent', - 'forum/chats/search', + 'forum/chats/create', + 'forum/chats/manage', 'forum/chats/messages', + 'forum/chats/user-list', + 'forum/chats/message-search', 'composer/autocomplete', 'hooks', 'bootbox', @@ -16,10 +18,9 @@ define('forum/chats', [ 'api', 'uploadHelpers', ], function ( - components, translator, mousetrap, - recentChats, search, messages, - autocomplete, hooks, bootbox, alerts, chatModule, - api, uploadHelpers + components, mousetrap, recentChats, create, + manage, messages, userList, messageSearch, autocomplete, + hooks, bootbox, alerts, chatModule, api, uploadHelpers ) { const Chats = { initialised: false, @@ -27,14 +28,25 @@ define('forum/chats', [ }; let newMessage = false; + let chatNavWrapper = null; $(window).on('action:ajaxify.start', function () { Chats.destroyAutoComplete(ajaxify.data.roomId); + if (ajaxify.data.template.chats) { + if (ajaxify.data.roomId) { + socket.emit('modules.chats.leave', ajaxify.data.roomId); + } + if (ajaxify.data.publicRooms) { + socket.emit('modules.chats.leavePublic', ajaxify.data.publicRooms.map(r => r.roomId)); + } + } }); Chats.init = function () { + $('.chats-full [data-bs-toggle="tooltip"]').tooltip(); + socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); const env = utils.findBootstrapEnvironment(); - + chatNavWrapper = $('[component="chat/nav-wrapper"]'); if (!Chats.initialised) { Chats.addSocketListeners(); Chats.addGlobalEventListeners(); @@ -43,35 +55,40 @@ define('forum/chats', [ recentChats.init(); Chats.addEventListeners(); - Chats.setActive(); + Chats.setActive(ajaxify.data.roomId); if (env === 'md' || env === 'lg' || env === 'xl' || env === 'xxl') { Chats.addHotkeys(); } - $(document).ready(function () { - hooks.fire('action:chat.loaded', $('.chats-full')); - }); - Chats.initialised = true; - messages.scrollToBottom($('.expanded-chat ul.chat-content')); - messages.wrapImagesInLinks($('.expanded-chat ul.chat-content')); - search.init(); + const changeContentEl = $('[component="chat/message/content"]'); + messages.wrapImagesInLinks(changeContentEl); + messages.scrollToBottomAfterImageLoad(changeContentEl); + create.init(); + + hooks.fire('action:chat.loaded', $('.chats-full')); }; Chats.addEventListeners = function () { - Chats.addSendHandlers(ajaxify.data.roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); + const { roomId } = ajaxify.data; + const mainWrapper = $('[component="chat/main-wrapper"]'); + const chatMessageContent = $('[component="chat/message/content"]'); + const chatControls = components.get('chat/controls'); + Chats.addSendHandlers(roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); Chats.addPopoutHandler(); - Chats.addActionHandlers(components.get('chat/messages'), ajaxify.data.roomId); - Chats.addMemberHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="members"]')); - Chats.addRenameHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="rename"]')); - Chats.addLeaveHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="leave"]')); - Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content')); - Chats.addScrollBottomHandler($('.chat-content')); - Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]')); - Chats.addTextareaResizeHandler($('[component="chat/main-wrapper"]')); - Chats.addIPHandler($('[component="chat/main-wrapper"]')); - Chats.createAutoComplete(ajaxify.data.roomId, $('[component="chat/input"]')); + Chats.addActionHandlers(components.get('chat/messages'), roomId); + Chats.addManageHandler(roomId, chatControls.find('[data-action="manage"]')); + Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]')); + Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]')); + Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]')); + Chats.addScrollHandler(roomId, ajaxify.data.uid, chatMessageContent); + Chats.addScrollBottomHandler(chatMessageContent); + Chats.addParentHandler(chatMessageContent); + Chats.addCharactersLeftHandler(mainWrapper); + Chats.addTextareaResizeHandler(mainWrapper); + Chats.addIPHandler(mainWrapper); + Chats.createAutoComplete(roomId, $('[component="chat/input"]')); Chats.addUploadHandler({ dragDropAreaEl: $('.chats-full'), pasteEl: $('[component="chat/input"]'), @@ -83,8 +100,77 @@ define('forum/chats', [ $('[data-action="close"]').on('click', function () { Chats.switchChat(); }); + userList.init(roomId, mainWrapper); + Chats.addNotificationSettingHandler(roomId, mainWrapper); + messageSearch.init(roomId, mainWrapper); + Chats.addPublicRoomSortHandler(); + Chats.addTooltipHandler(); }; + Chats.addPublicRoomSortHandler = function () { + if (app.user.isAdmin && !utils.isMobile()) { + app.loadJQueryUI(() => { + const publicRoomList = $('[component="chat/public"]'); + publicRoomList.sortable({ + handle: '[component="chat/public/room/sort/handle"]', + items: '[component="chat/public/room"]', + axis: 'y', + update: async function () { + const data = { roomIds: [], scores: [] }; + publicRoomList.find('[data-roomid]').each((idx, el) => { + data.roomIds.push($(el).attr('data-roomid')); + data.scores.push(idx); + }); + await socket.emit('modules.chats.sortPublicRooms', data); + }, + }); + }); + } + }; + + Chats.addTooltipHandler = function () { + $('[data-manual-tooltip]').tooltip({ + trigger: 'manual', + animation: false, + placement: 'bottom', + }).on('mouseenter', function (ev) { + const target = $(ev.target); + const isDropdown = target.hasClass('dropdown-menu') || !!target.parents('.dropdown-menu').length; + if (!isDropdown) { + $(this).tooltip('show'); + } + }).on('click mouseleave', function () { + $(this).tooltip('hide'); + }); + }; + + Chats.addNotificationSettingHandler = function (roomId, containerEl) { + const notifSettingEl = containerEl.find('[component="chat/notification/setting"]'); + + notifSettingEl.find('[data-value]').on('click', async function () { + notifSettingEl.find('i.fa-check').addClass('hidden'); + const $this = $(this); + $this.find('i.fa-check').removeClass('hidden'); + notifSettingEl.find('[component="chat/notification/setting/icon"]').attr('class', `fa ${$this.attr('data-icon')}`); + await socket.emit('modules.chats.setNotificationSetting', { + roomId: roomId, + value: $this.attr('data-value'), + }); + }); + }; + Chats.addParentHandler = function (chatContent) { + chatContent.on('click', '[component="chat/message/parent"]', function () { + const parentEl = $(this); + parentEl.find('[component="chat/message/parent/content"]').toggleClass('line-clamp-1'); + parentEl.find('.chat-timestamp').toggleClass('hidden'); + parentEl.toggleClass('flex-column').toggleClass('flex-row'); + if (chatContent.length && messages.isAtBottom(chatContent)) { + messages.scrollToBottom(chatContent); + } + }); + }; + + Chats.addUploadHandler = function (options) { uploadHelpers.init({ dragDropAreaEl: options.dragDropAreaEl, @@ -141,7 +227,7 @@ define('forum/chats', [ Chats.addScrollHandler = function (roomId, uid, el) { let loading = false; - el.off('scroll').on('scroll', function () { + el.off('scroll').on('scroll', utils.debounce(function () { messages.toggleScrollUpAlert(el); if (loading) { return; @@ -176,7 +262,7 @@ define('forum/chats', [ loading = false; }); }).catch(alerts.error); - }); + }, 100)); }; Chats.addScrollBottomHandler = function (chatContent) { @@ -198,30 +284,32 @@ define('forum/chats', [ // https://stackoverflow.com/questions/454202/creating-a-textarea-with-auto-resize const textarea = parent.find('[component="chat/input"]'); textarea.on('input', function () { - const isAtBottom = messages.isAtBottom(parent.find('.chat-content')); + const chatContentEl = parent.find('[component="chat/message/content"]'); + const isAtBottom = messages.isAtBottom(chatContentEl); textarea.css({ height: 0 }); textarea.css({ height: messages.calcAutoTextAreaHeight(textarea) + 'px' }); if (isAtBottom) { - messages.scrollToBottom(parent.find('.chat-content')); + messages.scrollToBottom(chatContentEl); } }); }; Chats.addActionHandlers = function (element, roomId) { - element.on('click', '[data-action]', function () { - const messageId = $(this).parents('[data-mid]').attr('data-mid'); + element.on('click', '[data-mid] [data-action]', function () { + const msgEl = $(this).parents('[data-mid]'); + const messageId = msgEl.attr('data-mid'); const action = this.getAttribute('data-action'); switch (action) { - case 'edit': { - const inputEl = $('[data-roomid="' + roomId + '"] [component="chat/input"]'); - messages.prepEdit(inputEl, messageId, roomId); + case 'reply': + messages.prepReplyTo(msgEl, roomId); + break; + case 'edit': + messages.prepEdit(msgEl, messageId, roomId); break; - } case 'delete': messages.delete(messageId, roomId); break; - case 'restore': messages.restore(messageId, roomId); break; @@ -231,18 +319,16 @@ define('forum/chats', [ Chats.addHotkeys = function () { mousetrap.bind('ctrl+up', function () { - const activeContact = $('.chats-list .bg-info'); - const prev = activeContact.prev(); - - if (prev.length) { + const activeContact = $('.chats-list .active'); + const prev = activeContact.prevAll('[data-roomid]').first(); + if (prev.length && prev.attr('data-roomid')) { Chats.switchChat(prev.attr('data-roomid')); } }); mousetrap.bind('ctrl+down', function () { - const activeContact = $('.chats-list .bg-info'); - const next = activeContact.next(); - - if (next.length) { + const activeContact = $('.chats-list .active'); + const next = activeContact.nextAll('[data-roomid]').first(); + if (next.length && next.attr('data-roomid')) { Chats.switchChat(next.attr('data-roomid')); } }); @@ -260,50 +346,8 @@ define('forum/chats', [ }); }; - Chats.addMemberHandler = function (roomId, buttonEl) { - let modal; - - buttonEl.on('click', function () { - app.parseAndTranslate('modals/manage-room', {}, function (html) { - modal = bootbox.dialog({ - title: '[[modules:chat.manage-room]]', - message: html, - }); - - modal.attr('component', 'chat/manage-modal'); - - Chats.refreshParticipantsList(roomId, modal); - Chats.addKickHandler(roomId, modal); - - const searchInput = modal.find('input'); - const errorEl = modal.find('.text-danger'); - require(['autocomplete', 'translator'], function (autocomplete, translator) { - autocomplete.user(searchInput, function (event, selected) { - errorEl.text(''); - api.post(`/chats/${roomId}/users`, { - uids: [selected.item.user.uid], - }).then((body) => { - Chats.refreshParticipantsList(roomId, modal, body); - searchInput.val(''); - }).catch((err) => { - translator.translate(err.message, function (translated) { - errorEl.text(translated); - }); - }); - }); - }); - }); - }); - }; - - Chats.addKickHandler = function (roomId, modal) { - modal.on('click', '[data-action="kick"]', function () { - const uid = parseInt(this.getAttribute('data-uid'), 10); - - api.del(`/chats/${roomId}/users/${uid}`, {}).then((body) => { - Chats.refreshParticipantsList(roomId, modal, body); - }).catch(alerts.error); - }); + Chats.addManageHandler = function (roomId, buttonEl) { + manage.init(roomId, buttonEl); }; Chats.addLeaveHandler = function (roomId, buttonEl) { @@ -330,50 +374,56 @@ define('forum/chats', [ }); }; - Chats.refreshParticipantsList = async (roomId, modal, data) => { - const listEl = modal.find('.list-group'); - - if (!data) { - try { - data = await api.get(`/chats/${roomId}/users`, {}); - } catch (err) { - translator.translate('[[error:invalid-data]]', function (translated) { - listEl.find('li').text(translated); - }); - } - } - - app.parseAndTranslate('partials/chats/manage-room-users', data, function (html) { - listEl.html(html); + Chats.addDeleteHandler = function (roomId, buttonEl) { + buttonEl.on('click', function () { + bootbox.confirm({ + size: 'small', + title: '[[modules:chat.delete]]', + message: '

[[modules:chat.delete-prompt]]

', + callback: function (ok) { + if (ok) { + api.del(`/admin/chats/${roomId}`, {}).then(() => { + // Return user to chats page. If modal, close modal. + const modal = buttonEl.parents('.chat-modal'); + if (modal.length) { + chatModule.close(modal); + } else { + Chats.destroyAutoComplete(roomId); + ajaxify.go('chats'); + } + }).catch(alerts.error); + } + }, + }); }); }; - Chats.addRenameHandler = function (roomId, buttonEl, roomName) { - let modal; - - buttonEl.on('click', function () { - app.parseAndTranslate('modals/rename-room', { - name: roomName || ajaxify.data.roomName, - }, function (html) { - modal = bootbox.dialog({ - title: '[[modules:chat.rename-room]]', - message: html, - buttons: { - save: { - label: '[[global:save]]', - className: 'btn-primary', - callback: submit, + Chats.addRenameHandler = function (roomId, buttonEl) { + buttonEl.on('click', async function () { + const { roomName } = await api.get(`/chats/${roomId}`); + const html = await app.parseAndTranslate('modals/rename-room', { + name: roomName, + }); + const modal = bootbox.dialog({ + title: '[[modules:chat.rename-room]]', + message: html, + onEscape: true, + buttons: { + save: { + label: '[[global:save]]', + className: 'btn-primary', + callback: function () { + api.put(`/chats/${roomId}`, { + name: modal.find('#roomName').val(), + }).then(() => { + modal.modal('hide'); + }).catch(alerts.error); + return false; }, }, - }); + }, }); }); - - function submit() { - api.put(`/chats/${roomId}`, { - name: modal.find('#roomName').val(), - }).catch(alerts.error); - } }; Chats.addSendHandlers = function (roomId, inputEl, sendEl) { @@ -446,43 +496,48 @@ define('forum/chats', [ }).catch(alerts.error); }; - Chats.switchChat = function (roomid) { + Chats.switchChat = function (roomId) { // Allow empty arg for return to chat list/close chat - if (!roomid) { - roomid = ''; + if (!roomId) { + roomId = ''; } Chats.destroyAutoComplete(ajaxify.data.roomId); - const url = 'user/' + ajaxify.data.userslug + '/chats/' + roomid + window.location.search; - if (self.fetch) { - fetch(config.relative_path + '/api/' + url, { credentials: 'include' }) - .then(function (response) { - if (response.ok) { - response.json().then(function (payload) { - app.parseAndTranslate('partials/chats/message-window', payload, function (html) { - components.get('chat/main-wrapper').html(html); - html.find('.timeago').timeago(); - ajaxify.data = payload; - Chats.setActive(); - Chats.addEventListeners(); - hooks.fire('action:chat.loaded', $('.chats-full')); - messages.scrollToBottom($('.expanded-chat ul.chat-content')); - if (history.pushState) { - history.pushState({ - url: url, - }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + url); - } - }); - }); - } else { - console.warn('[search] Received ' + response.status); - } - }) - .catch(function (error) { - console.warn('[search] ' + error.message); - }); - } else { - ajaxify.go(url); + socket.emit('modules.chats.leave', ajaxify.data.roomId); + const url = 'user/' + ajaxify.data.userslug + '/chats/' + roomId + window.location.search; + if (!self.fetch) { + return ajaxify.go(url); } + const params = new URL(document.location).searchParams; + params.set('switch', 1); + const dataUrl = `${config.relative_path}/api/user/${ajaxify.data.userslug}/chats/${roomId}?${params.toString()}`; + fetch(dataUrl, { credentials: 'include' }) + .then(async function (response) { + if (!response.ok) { + return console.warn('[search] Received ' + response.status); + } + const payload = await response.json(); + const html = await app.parseAndTranslate('partials/chats/message-window', payload); + const mainWrapper = components.get('chat/main-wrapper'); + mainWrapper.html(html); + chatNavWrapper = $('[component="chat/nav-wrapper"]'); + html.find('.timeago').timeago(); + ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomId }; + ajaxify.updateTitle(ajaxify.data.title); + $('body').toggleClass('chat-loaded', !!roomId); + mainWrapper.find('[data-bs-toggle="tooltip"]').tooltip(); + Chats.setActive(roomId); + Chats.addEventListeners(); + hooks.fire('action:chat.loaded', $('.chats-full')); + messages.scrollToBottomAfterImageLoad(mainWrapper.find('[component="chat/message/content"]')); + if (history.pushState) { + history.pushState({ + url: url, + }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + url); + } + }) + .catch(function (error) { + console.warn('[search] ' + error.message); + }); }; Chats.addGlobalEventListeners = function () { @@ -496,41 +551,33 @@ define('forum/chats', [ Chats.addSocketListeners = function () { socket.on('event:chats.receive', function (data) { + if (chatModule.isFromBlockedUser(data.fromUid)) { + return; + } if (parseInt(data.roomId, 10) === parseInt(ajaxify.data.roomId, 10)) { + data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0; if (!newMessage) { newMessage = data.self === 0; } data.message.self = data.self; data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); - messages.appendChatMessage($('.expanded-chat .chat-content'), data.message); - } else if (ajaxify.data.template.chats) { - const roomEl = $('[data-roomid=' + data.roomId + ']'); - - if (roomEl.length > 0) { - roomEl.addClass('unread'); - - const markEl = roomEl.find('.mark-read').get(0); - if (markEl) { - markEl.querySelector('.read').classList.add('hidden'); - markEl.querySelector('.unread').classList.remove('hidden'); - } - } else { - const recentEl = components.get('chat/recent'); - app.parseAndTranslate('partials/chats/recent_room', { - rooms: { - roomId: data.roomId, - lastUser: data.message.fromUser, - usernames: data.message.fromUser.username, - unread: true, - }, - }, function (html) { - recentEl.prepend(html); - }); - } + messages.appendChatMessage($('[component="chat/message/content"]'), data.message); } }); + socket.on('event:chats.public.unread', function (data) { + if ( + chatModule.isFromBlockedUser(data.fromUid) || + chatModule.isLookingAtRoom(data.roomId) || + app.user.uid === parseInt(data.fromUid, 10) + ) { + return; + } + Chats.markChatPageElUnread(data); + Chats.increasePublicRoomUnreadCount(chatNavWrapper.find('[data-roomid=' + data.roomId + ']')); + }); + socket.on('event:user_status_change', function (data) { app.updateUserStatus($('.chats-list [data-uid="' + data.uid + '"] [component="user/status"]'), data.status); }); @@ -539,46 +586,74 @@ define('forum/chats', [ socket.on('event:chats.roomRename', function (data) { const roomEl = components.get('chat/recent/room', data.roomId); - const titleEl = roomEl.find('[component="chat/title"]'); - ajaxify.data.roomName = data.newName; - - titleEl.text(data.newName); + if (roomEl.length) { + const titleEl = roomEl.find('[component="chat/room/title"]'); + ajaxify.data.roomName = data.newName; + titleEl.translateText(data.newName ? data.newName : ajaxify.data.usernames); + } + const titleEl = $(`[component="chat/main-wrapper"][data-roomid="${data.roomId}"] [component="chat/header/title"]`); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + ajaxify.data.chatWithMessage + ); + } }); socket.on('event:chats.mark', ({ roomId, state }) => { - const roomEls = document.querySelectorAll(`[component="chat/recent"] [data-roomid="${roomId}"], [component="chat/list"] [data-roomid="${roomId}"]`); - - roomEls.forEach((roomEl) => { - roomEl.classList[state ? 'add' : 'remove']('unread'); - - const markEl = roomEl.querySelector('.mark-read'); - if (markEl) { - markEl.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); - markEl.querySelector('.unread').classList[state ? 'remove' : 'add']('hidden'); + const roomEls = $(`[component="chat/recent"] [data-roomid="${roomId}"], [component="chat/list"] [data-roomid="${roomId}"], [component="chat/public"] [data-roomid="${roomId}"]`); + roomEls.each((idx, el) => { + const roomEl = $(el); + chatModule.markChatElUnread(roomEl, state === 1); + if (state === 0) { + Chats.updatePublicRoomUnreadCount(roomEl, 0); } }); }); }; - Chats.setActive = function () { - if (ajaxify.data.roomId) { - const chatEl = document.querySelector(`[component="chat/recent"] [data-roomid="${ajaxify.data.roomId}"]`); - if (chatEl.classList.contains('unread')) { - api.del(`/chats/${ajaxify.data.roomId}/state`, {}); - chatEl.classList.remove('unread'); + Chats.markChatPageElUnread = function (data) { + if (!ajaxify.data.template.chats) { + return; + } + + const roomEl = chatNavWrapper.find('[data-roomid=' + data.roomId + ']'); + chatModule.markChatElUnread(roomEl, true); + }; + + Chats.increasePublicRoomUnreadCount = function (roomEl) { + const unreadCountEl = roomEl.find('[component="chat/public/room/unread/count"]'); + const newCount = (parseInt(unreadCountEl.attr('data-count'), 10) || 0) + 1; + Chats.updatePublicRoomUnreadCount(roomEl, newCount); + }; + + Chats.updatePublicRoomUnreadCount = function (roomEl, count) { + const unreadCountEl = roomEl.find('[component="chat/public/room/unread/count"]'); + const countText = count > 50 ? '50+' : count; + unreadCountEl.toggleClass('hidden', count <= 0).text(countText).attr('data-count', count); + }; + + Chats.setActive = function (roomId) { + chatNavWrapper.find('[data-roomid]').removeClass('active'); + if (roomId) { + socket.emit('modules.chats.enter', roomId); + const chatEl = chatNavWrapper.find(`[data-roomid="${roomId}"]`); + chatEl.addClass('active'); + if (chatEl.hasClass('unread')) { + api.del(`/chats/${roomId}/state`, {}); + chatEl.removeClass('unread'); } if (!utils.isMobile()) { $('.expanded-chat [component="chat/input"]').focus(); } - messages.updateTextAreaHeight($(`[component="chat/messages"][data-roomid="${ajaxify.data.roomId}"]`)); + messages.updateTextAreaHeight($(`[component="chat/messages"][data-roomid="${roomId}"]`)); } - $('.chats-list [data-roomid]').removeClass('active'); - $('.chats-list [data-roomid="' + ajaxify.data.roomId + '"]').addClass('active'); - components.get('chat/nav-wrapper').attr('data-loaded', ajaxify.data.roomId ? '1' : '0'); + chatNavWrapper.attr('data-loaded', roomId ? '1' : '0'); }; - return Chats; }); + diff --git a/public/src/client/chats/create.js b/public/src/client/chats/create.js new file mode 100644 index 0000000000..f9e48c2f13 --- /dev/null +++ b/public/src/client/chats/create.js @@ -0,0 +1,87 @@ +'use strict'; + + +define('forum/chats/create', [ + 'components', 'api', 'alerts', 'forum/chats/user-search', +], function (components, api, alerts, userSearch) { + const create = {}; + create.init = function () { + components.get('chat/create').on('click', handleCreate); + }; + + async function handleCreate() { + let groups = []; + if (app.user.isAdmin) { + groups = await socket.emit('groups.getChatGroups', {}); + } + const html = await app.parseAndTranslate('modals/create-room', { + user: app.user, + groups: groups, + }); + + const modal = bootbox.dialog({ + title: '[[modules:chat.create-room]]', + message: html, + onEscape: true, + buttons: { + save: { + label: '[[global:create]]', + className: 'btn-primary', + callback: function () { + const roomName = modal.find('[component="chat/room/name"]').val(); + const uids = modal.find('[component="chat/room/users"] [component="chat/user"]').find('[data-uid]').map( + (i, el) => $(el).attr('data-uid') + ).get(); + const type = modal.find('[component="chat/room/type"]').val(); + const groups = modal.find('[component="chat/room/groups"]').val(); + + if (type === 'private' && !uids.length) { + alerts.error('[[error:no-users-selected]]'); + return false; + } + if (type === 'public' && !groups.length) { + alerts.error('[[error:no-groups-selected]]'); + return false; + } + if (!app.user.uid) { + alerts.error('[[error:not-logged-in]]'); + return false; + } + + api.post(`/chats`, { + roomName: roomName, + uids: uids, + type: type, + groups: groups, + }).then(({ roomId }) => { + ajaxify.go('chats/' + roomId); + modal.modal('hide'); + }).catch(alerts.error); + return false; + }, + }, + }, + }); + + const chatRoomUsersList = modal.find('[component="chat/room/users"]'); + + userSearch.init({ + onSelect: async function (user) { + const html = await app.parseAndTranslate('modals/create-room', 'selectedUsers', { selectedUsers: [user] }); + chatRoomUsersList.append(html); + }, + }); + + chatRoomUsersList.on('click', '[component="chat/room/users/remove"]', function () { + $(this).parents('[data-uid]').remove(); + }); + + + modal.find('[component="chat/room/type"]').on('change', function () { + const type = $(this).val(); + modal.find('[component="chat/room/public/options"]').toggleClass('hidden', type === 'private'); + }); + } + + return create; +}); diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js new file mode 100644 index 0000000000..73f33c53d3 --- /dev/null +++ b/public/src/client/chats/manage.js @@ -0,0 +1,134 @@ +'use strict'; + + +define('forum/chats/manage', [ + 'api', 'alerts', 'translator', 'autocomplete', 'forum/chats/user-list', +], function (api, alerts, translator, autocomplete, userList) { + const manage = {}; + + manage.init = function (roomId, buttonEl) { + let modal; + + buttonEl.on('click', async function () { + let groups = []; + if (app.user.isAdmin) { + groups = await socket.emit('groups.getChatGroups', {}); + if (Array.isArray(ajaxify.data.groups)) { + groups.forEach((g) => { + g.selected = ajaxify.data.groups.includes(g.name); + }); + } + } + + const html = await app.parseAndTranslate('modals/manage-room', { + groups, + user: app.user, + room: ajaxify.data, + }); + modal = bootbox.dialog({ + title: '[[modules:chat.manage-room]]', + message: html, + onEscape: true, + }); + + modal.attr('component', 'chat/manage-modal'); + + refreshParticipantsList(roomId, modal); + addKickHandler(roomId, modal); + addToggleOwnerHandler(roomId, modal); + + const userListEl = modal.find('[component="chat/manage/user/list"]'); + const userListElSearch = modal.find('[component="chat/manage/user/list/search"]'); + userList.addSearchHandler(roomId, userListElSearch, async (data) => { + if (userListElSearch.val()) { + userListEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + } else { + refreshParticipantsList(roomId, modal); + } + }); + + userList.addInfiniteScrollHandler(roomId, userListEl, async (listEl, data) => { + listEl.append(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + }); + + const searchInput = modal.find('[component="chat/manage/user/add/search"]'); + const errorEl = modal.find('.text-danger'); + autocomplete.user(searchInput, function (event, selected) { + errorEl.text(''); + api.post(`/chats/${roomId}/users`, { + uids: [selected.item.user.uid], + }).then((body) => { + refreshParticipantsList(roomId, modal, body); + searchInput.val(''); + }).catch((err) => { + translator.translate(err.message, function (translated) { + errorEl.text(translated); + }); + }); + }); + + modal.find('[component="chat/manage/save"]').on('click', () => { + const notifSettingEl = modal.find('[component="chat/room/notification/setting"]'); + api.put(`/chats/${roomId}`, { + groups: modal.find('[component="chat/room/groups"]').val(), + notificationSetting: notifSettingEl.val(), + }).then((payload) => { + ajaxify.data.groups = payload.groups; + ajaxify.data.notificationSetting = payload.notificationSetting; + const roomDefaultOption = payload.notificationOptions[0]; + $('[component="chat/notification/setting"] [data-icon]').first().attr( + 'data-icon', roomDefaultOption.icon + ); + $('[component="chat/notification/setting/sub-label"]').translateText( + roomDefaultOption.subLabel + ); + if (roomDefaultOption.selected) { + $('[component="chat/notification/setting/icon"]').attr( + 'class', `fa ${roomDefaultOption.icon}` + ); + } + + modal.modal('hide'); + }).catch(alerts.error); + }); + }); + }; + + function addKickHandler(roomId, modal) { + modal.on('click', '[data-action="kick"]', function () { + const uid = parseInt(this.getAttribute('data-uid'), 10); + + api.del(`/chats/${roomId}/users/${uid}`, {}).then((body) => { + refreshParticipantsList(roomId, modal, body); + }).catch(alerts.error); + }); + } + + function addToggleOwnerHandler(roomId, modal) { + modal.on('click', '[data-action="toggleOwner"]', async function () { + const uid = parseInt(this.getAttribute('data-uid'), 10); + const $this = $(this); + await socket.emit('modules.chats.toggleOwner', { roomId: roomId, uid: uid }); + $this.parents('[data-uid]') + .find('[component="chat/manage/user/owner/icon"]') + .toggleClass('hidden'); + }); + } + + async function refreshParticipantsList(roomId, modal, data) { + const listEl = modal.find('[component="chat/manage/user/list"]'); + + if (!data) { + try { + data = await api.get(`/chats/${roomId}/users`, {}); + } catch (err) { + listEl.find('li').text(await translator.translate('[[error:invalid-data]]')); + } + } + listEl.find('[data-bs-toggle="tooltip"]').tooltip('dispose'); + listEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + listEl.find('[data-bs-toggle="tooltip"]').tooltip(); + } + + return manage; +}); diff --git a/public/src/client/chats/message-search.js b/public/src/client/chats/message-search.js new file mode 100644 index 0000000000..d6490c8b3e --- /dev/null +++ b/public/src/client/chats/message-search.js @@ -0,0 +1,99 @@ +'use strict'; + + +define('forum/chats/message-search', [ + 'components', 'alerts', 'forum/chats/messages', +], function (components, alerts, messages) { + const messageSearch = {}; + let roomId = 0; + let searchInputEl; + let resultListEl; + let chatContent; + let clearEl; + let toggleEl; + let searchContainerEl; + messageSearch.init = function (_roomId, containerEl) { + roomId = _roomId; + + resultListEl = containerEl.find('[component="chat/message/search/results"]'); + chatContent = containerEl.find('[component="chat/message/content"]'); + clearEl = containerEl.find('[component="chat/room/search/clear"]'); + searchContainerEl = containerEl.find('[component="chat/room/search/container"]'); + toggleEl = containerEl.find('[component="chat/room/search/toggle"'); + + searchInputEl = containerEl.find('[component="chat/room/search"]'); + searchInputEl.on('keyup', utils.debounce(doSearch, 250)) + .on('focus', () => { + if (searchInputEl.val()) { + doSearch(); + } + }); + + containerEl.find('[component="chat/input"]').on('focus', () => { + resultListEl.addClass('hidden'); + chatContent.removeClass('hidden'); + }); + clearEl.on('click', clearInputAndResults); + + toggleEl.on('click', () => { + searchContainerEl.removeClass('hidden'); + toggleEl.addClass('hidden'); + searchInputEl.trigger('focus'); + }); + searchInputEl.on('blur', () => { + if (!searchInputEl.val()) { + clearInputAndResults(); + } + }); + }; + + function clearInputAndResults() { + searchInputEl.val(''); + removeResults(); + resultListEl.addClass('hidden'); + clearEl.addClass('hidden'); + searchContainerEl.addClass('hidden'); + chatContent.removeClass('hidden'); + toggleEl.removeClass('hidden'); + } + + async function doSearch() { + const query = searchInputEl.val(); + if (!query || query.length <= 2) { + return; + } + clearEl.removeClass('hidden'); + socket.emit('modules.chats.searchMessages', { + content: query, + roomId: roomId, + }).then(displayResults) + .catch(alerts.error); + } + + function removeResults() { + resultListEl.children('[data-mid]').remove(); + } + + async function displayResults(data) { + removeResults(); + + if (!data.length) { + resultListEl.removeClass('hidden'); + chatContent.addClass('hidden'); + return resultListEl.find('[component="chat/message/search/no-results"]').removeClass('hidden'); + } + resultListEl.find('[component="chat/message/search/no-results"]').addClass('hidden'); + + const html = await app.parseAndTranslate('partials/chats/messages', { + messages: data, + isAdminOrGlobalMod: app.user.isAdmin || app.user.isGlobalMod, + }); + + resultListEl.append(html); + messages.onMessagesAddedToDom(resultListEl.find('[component="chat/message"]')); + chatContent.addClass('hidden'); + resultListEl.removeClass('hidden'); + } + + return messageSearch; +}); diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index f51b261acf..f8adbeae5e 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -3,9 +3,9 @@ define('forum/chats/messages', [ 'components', 'hooks', 'bootbox', 'alerts', - 'messages', 'api', 'forum/topic/images', + 'messages', 'api', 'forum/topic/images', 'imagesloaded', ], function ( - components, hooks, bootbox, alerts, messagesModule, api, images + components, hooks, bootbox, alerts, messagesModule, api, images, imagesLoaded ) { const messages = {}; @@ -21,9 +21,13 @@ define('forum/chats/messages', [ messages.updateTextAreaHeight(chatContent); const payload = { roomId, message }; ({ roomId, message } = await hooks.fire('filter:chat.send', payload)); - - api.post(`/chats/${roomId}`, { message }).then(() => { + const replyToEl = inputEl.parents('[component="chat/composer"]') + .find('[component="chat/composer/replying-to"]'); + const toMid = replyToEl.attr('data-tomid'); + api.post(`/chats/${roomId}`, { message, toMid: toMid }).then(() => { hooks.fire('action:chat.sent', { roomId, message }); + replyToEl.addClass('hidden'); + replyToEl.attr('data-tomid', ''); }).catch((err) => { inputEl.val(message).trigger('input'); messages.updateRemainingLength(inputEl.parent()); @@ -72,25 +76,32 @@ define('forum/chats/messages', [ } messages.appendChatMessage = function (chatContentEl, data) { - const lastSpeaker = parseInt(chatContentEl.find('.chat-message').last().attr('data-uid'), 10); - const lasttimestamp = parseInt(chatContentEl.find('.chat-message').last().attr('data-timestamp'), 10); + const lastMsgEl = chatContentEl.find('.chat-message').last(); + const lastSpeaker = parseInt(lastMsgEl.attr('data-uid'), 10); + const lasttimestamp = parseInt(lastMsgEl.attr('data-timestamp'), 10); if (!Array.isArray(data)) { - data.newSet = lastSpeaker !== parseInt(data.fromuid, 10) || + data.newSet = data.toMid || lastSpeaker !== parseInt(data.fromuid, 10) || parseInt(data.timestamp, 10) > parseInt(lasttimestamp, 10) + (1000 * 60 * 3); } messages.parseMessage(data, function (html) { - onMessagesParsed(chatContentEl, html); + onMessagesParsed(chatContentEl, html, data); }); }; - function onMessagesParsed(chatContentEl, html) { + function onMessagesParsed(chatContentEl, html, msgData) { const newMessage = $(html); const isAtBottom = messages.isAtBottom(chatContentEl); newMessage.appendTo(chatContentEl); messages.onMessagesAddedToDom(newMessage); - if (isAtBottom) { - messages.scrollToBottom(chatContentEl); + if (isAtBottom || msgData.self) { + messages.scrollToBottomAfterImageLoad(chatContentEl); + // remove some message elements if there are too many + const chatMsgEls = chatContentEl.find('[data-mid]'); + if (chatMsgEls.length > 150) { + const removeCount = chatMsgEls.length - 150; + chatMsgEls.slice(0, removeCount).remove(); + } } hooks.fire('action:chat.received', { @@ -101,14 +112,15 @@ define('forum/chats/messages', [ messages.onMessagesAddedToDom = function (messageEls) { messageEls.find('.timeago').timeago(); messageEls.find('img:not(.not-responsive)').addClass('img-fluid'); - messages.wrapImagesInLinks(messageEls.first().parent()); + messageEls.find('img:not(.emoji)').each(function () { + images.wrapImageInLink($(this)); + }); }; messages.parseMessage = function (data, callback) { const tplData = { messages: data, isAdminOrGlobalMod: app.user.isAdmin || app.user.isGlobalMod, - }; if (Array.isArray(data)) { app.parseAndTranslate('partials/chats/messages', tplData).then(callback); @@ -125,6 +137,14 @@ define('forum/chats/messages', [ return distanceToBottom < (threshold || 100); } }; + messages.scrollToBottomAfterImageLoad = function (containerEl) { + if (containerEl && containerEl.length) { + const msgBodyEls = containerEl[0].querySelectorAll('[component="chat/message/body"]'); + imagesLoaded(msgBodyEls, () => { + messages.scrollToBottom(containerEl); + }); + } + }; messages.scrollToBottom = function (containerEl) { if (containerEl && containerEl.length) { @@ -148,14 +168,36 @@ define('forum/chats/messages', [ .toggleClass('hidden', isAtBottom); }; - messages.prepEdit = async function (inputEl, mid, roomId) { + messages.prepReplyTo = async function (msgEl, roomId) { + const chatMessages = msgEl.parents(`[component="chat/messages"][data-roomid="${roomId}"]`); + const chatContent = chatMessages.find('[component="chat/message/content"]'); + const composerEl = chatMessages.find('[component="chat/composer"]'); + const mid = msgEl.attr('data-mid'); + const replyToEl = composerEl.find('[component="chat/composer/replying-to"]'); + replyToEl.attr('data-tomid', mid) + .find('[component="chat/composer/replying-to-text"]') + .translateText(`[[modules:chat.replying-to, ${msgEl.attr('data-username')}]]`); + replyToEl.removeClass('hidden'); + replyToEl.find('[component="chat/composer/replying-to-cancel"]').off('click') + .on('click', () => { + replyToEl.attr('data-tomid', ''); + replyToEl.addClass('hidden'); + }); + + if (chatContent.length && messages.isAtBottom(chatContent)) { + messages.scrollToBottom(chatContent); + } + composerEl.find('[component="chat/input"]').trigger('focus'); + }; + + messages.prepEdit = async function (msgEl, mid, roomId) { const raw = await socket.emit('modules.chats.getRaw', { mid: mid, roomId: roomId }); const editEl = await app.parseAndTranslate('partials/chats/edit-message', { rawContent: raw, }); - const messageBody = $(`[data-roomid="${roomId}"] [data-mid="${mid}"] [component="chat/message/body"]`); - const messageControls = $(`[data-roomid="${roomId}"] [data-mid="${mid}"] [component="chat/message/controls"]`); - const chatContent = messageBody.parents('.chat-content'); + const messageBody = msgEl.find(`[component="chat/message/body"]`); + const messageControls = msgEl.find(`[component="chat/message/controls"]`); + const chatContent = messageBody.parents('[component="chat/message/content"]'); messageBody.addClass('hidden'); messageControls.addClass('hidden'); @@ -166,7 +208,7 @@ define('forum/chats/messages', [ textarea.focus().putCursorAtEnd(); autoresizeTextArea(textarea); - if (messages.isAtBottom(chatContent)) { + if (chatContent.length && messages.isAtBottom(chatContent)) { messages.scrollToBottom(chatContent); } @@ -205,7 +247,7 @@ define('forum/chats/messages', [ }); hooks.fire('action:chat.prepEdit', { - inputEl: inputEl, + msgEl: msgEl, messageId: mid, roomId: roomId, editEl: editEl, @@ -229,27 +271,59 @@ define('forum/chats/messages', [ const self = parseInt(message.fromuid, 10) === parseInt(app.user.uid, 10); message.self = self ? 1 : 0; messages.parseMessage(message, function (html) { - const body = components.get('chat/message', message.messageId); - if (body.length) { - body.replaceWith(html); - messages.onMessagesAddedToDom(html); + const msgEl = components.get('chat/message', message.mid); + if (msgEl.length) { + msgEl.replaceWith(html); + messages.onMessagesAddedToDom(components.get('chat/message', message.mid)); + } + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${message.mid}"]`); + if (parentEl.length) { + parentEl.find('[component="chat/message/parent/content"]').html( + html.find('[component="chat/message/body"]').html() + ); + messages.onMessagesAddedToDom( + $(`[component="chat/message/parent"][data-parent-mid="${message.mid}"]`) + ); } }); }); } function onChatMessageDeleted(messageId) { - components.get('chat/message', messageId) - .toggleClass('deleted', true) - .find('[component="chat/message/body"]') - .translateHtml('[[modules:chat.message-deleted]]'); + const msgEl = components.get('chat/message', messageId); + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${messageId}"]`); + const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + const isParentSelf = parseInt(parentEl.attr('data-uid'), 10) === app.user.uid; + msgEl.toggleClass('deleted', true); + parentEl.toggleClass('deleted', true); + if (!isSelf) { + msgEl.find('[component="chat/message/body"]') + .translateHtml('

[[modules:chat.message-deleted]]

'); + } + if (!isParentSelf) { + parentEl.find('[component="chat/message/parent/content"]') + .translateHtml('

[[modules:chat.message-deleted]]

'); + } } function onChatMessageRestored(message) { - components.get('chat/message', message.messageId) - .toggleClass('deleted', false) - .find('[component="chat/message/body"]') - .html(message.content); + const msgEl = components.get('chat/message', message.messageId); + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${message.messageId}"]`); + const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + const isParentSelf = parseInt(parentEl.attr('data-uid'), 10) === app.user.uid; + msgEl.toggleClass('deleted', false); + parentEl.toggleClass('deleted', false); + if (!isSelf) { + msgEl.find('[component="chat/message/body"]') + .translateHtml(message.content); + messages.onMessagesAddedToDom(components.get('chat/message', message.messageId)); + } + + if (!isParentSelf && parentEl.length) { + parentEl.find('[component="chat/message/parent/content"]') + .translateHtml(message.content); + messages.onMessagesAddedToDom($(`[component="chat/message/parent"][data-parent-mid="${message.messageId}"]`)); + } } messages.delete = function (messageId, roomId) { diff --git a/public/src/client/chats/recent.js b/public/src/client/chats/recent.js index 95532a3df0..a4f6490f4b 100644 --- a/public/src/client/chats/recent.js +++ b/public/src/client/chats/recent.js @@ -1,13 +1,13 @@ 'use strict'; -define('forum/chats/recent', ['alerts', 'api'], function (alerts, api) { +define('forum/chats/recent', ['alerts', 'api', 'chat'], function (alerts, api, chat) { const recent = {}; recent.init = function () { require(['forum/chats'], function (Chats) { - $('[component="chat/recent"]') - .on('click', '[component="chat/recent/room"]', function (e) { + $('[component="chat/nav-wrapper"]') + .on('click', '[component="chat/recent/room"], [component="chat/public/room"]', function (e) { e.stopPropagation(); e.preventDefault(); const roomId = this.getAttribute('data-roomid'); @@ -16,30 +16,16 @@ define('forum/chats/recent', ['alerts', 'api'], function (alerts, api) { .on('click', '.mark-read', function (e) { e.stopPropagation(); const chatEl = this.closest('[data-roomid]'); - const state = !chatEl.classList.contains('unread'); // this is the new state - const roomId = chatEl.getAttribute('data-roomid'); - api[state ? 'put' : 'del'](`/chats/${roomId}/state`, {}).catch((err) => { - alerts.error(err); - - // Revert on failure - chatEl.classList[state ? 'remove' : 'add']('unread'); - this.querySelector('.unread').classList[state ? 'add' : 'remove']('hidden'); - this.querySelector('.read').classList[!state ? 'add' : 'remove']('hidden'); - }); - - // Immediate feedback - chatEl.classList[state ? 'add' : 'remove']('unread'); - this.querySelector('.unread').classList[!state ? 'add' : 'remove']('hidden'); - this.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); + chat.toggleReadState(chatEl); }); - $('[component="chat/recent"]').on('scroll', function () { + $('[component="chat/recent"]').on('scroll', utils.debounce(function () { const $this = $(this); const bottom = ($this[0].scrollHeight - $this.height()) * 0.9; if ($this.scrollTop() > bottom) { loadMoreRecentChats(); } - }); + }, 100)); }); }; diff --git a/public/src/client/chats/user-list.js b/public/src/client/chats/user-list.js new file mode 100644 index 0000000000..2b936c0698 --- /dev/null +++ b/public/src/client/chats/user-list.js @@ -0,0 +1,80 @@ +'use strict'; + + +define('forum/chats/user-list', ['api'], function (api) { + const userList = {}; + + let updateInterval = 0; + + userList.init = function (roomId, container) { + const userListEl = container.find('[component="chat/user/list"]'); + if (!userListEl.length) { + return; + } + container.find('[component="chat/user/list/btn"]').on('click', () => { + userListEl.toggleClass('hidden'); + if (userListEl.hasClass('hidden')) { + stopUpdating(); + } else { + startUpdating(roomId, userListEl); + } + }); + + $(window).off('action:ajaxify.start', stopUpdating) + .one('action:ajaxify.start', stopUpdating); + + userList.addInfiniteScrollHandler(roomId, userListEl, async (listEl, data) => { + listEl.append(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); + }); + }; + + function startUpdating(roomId, userListEl) { + updateInterval = setInterval(() => { + updateUserList(roomId, userListEl); + }, 5000); + } + + function stopUpdating() { + if (updateInterval) { + clearInterval(updateInterval); + updateInterval = 0; + } + } + + async function updateUserList(roomId, userListEl) { + if (ajaxify.data.template.chats && app.isFocused && userListEl.scrollTop() === 0 && !userListEl.hasClass('hidden')) { + const data = await api.get(`/chats/${roomId}/users`, { start: 0 }); + userListEl.find('[data-bs-toggle="tooltip"]').tooltip('dispose'); + userListEl.html(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); + userListEl.find('[data-bs-toggle="tooltip"]').tooltip(); + } + } + + userList.addInfiniteScrollHandler = function (roomId, listEl, callback) { + listEl.on('scroll', utils.debounce(async () => { + const bottom = (listEl[0].scrollHeight - listEl.height()) * 0.85; + if (listEl.scrollTop() > bottom) { + const lastIndex = listEl.find('[data-index]').last().attr('data-index'); + const data = await api.get(`/chats/${roomId}/users`, { + start: parseInt(lastIndex, 10) + 1, + }); + if (data && data.users.length) { + callback(listEl, data); + } + } + }, 200)); + }; + + userList.addSearchHandler = function (roomId, inputEl, callback) { + inputEl.on('keyup', utils.debounce(async () => { + const username = inputEl.val(); + const data = await socket.emit('modules.chats.searchMembers', { + username: username, + roomId: roomId, + }); + callback(data); + }, 200)); + }; + + return userList; +}); diff --git a/public/src/client/chats/search.js b/public/src/client/chats/user-search.js similarity index 60% rename from public/src/client/chats/search.js rename to public/src/client/chats/user-search.js index 1641efcb1e..a07ebd7099 100644 --- a/public/src/client/chats/search.js +++ b/public/src/client/chats/user-search.js @@ -1,26 +1,39 @@ 'use strict'; -define('forum/chats/search', [ +define('forum/chats/user-search', [ 'components', 'api', 'alerts', ], function (components, api, alerts) { - const search = {}; + const userSearch = {}; + let users = []; - search.init = function () { + userSearch.init = function (options) { + options = options || {}; + users.length = 0; components.get('chat/search').on('keyup', utils.debounce(doSearch, 250)); const chatsListEl = $('[component="chat/search/list"]'); chatsListEl.on('click', '[data-uid]', function () { - onUserClick($(this).attr('data-uid')); + if (options.onSelect) { + options.onSelect( + users.find(u => parseInt(u.uid, 10) === parseInt($(this).attr('data-uid'), 10)) + ); + } + clearInputAndResults(chatsListEl); }); }; + function clearInputAndResults(chatsListEl) { + components.get('chat/search').val(''); + removeResults(chatsListEl); + chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); + chatsListEl.find('[component="chat/search/start-typing"]').removeClass('hidden'); + } + function doSearch() { const chatsListEl = $('[component="chat/search/list"]'); const username = components.get('chat/search').val(); if (!username) { - removeResults(chatsListEl); - chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); - return chatsListEl.find('[component="chat/search/start-typing"]').removeClass('hidden'); + return clearInputAndResults(chatsListEl); } chatsListEl.find('[component="chat/search/start-typing"]').addClass('hidden'); api.get('/api/users', { @@ -32,6 +45,7 @@ define('forum/chats/search', [ } function removeResults(chatsListEl) { + users.length = 0; chatsListEl.find('[data-uid]').remove(); } @@ -41,35 +55,15 @@ define('forum/chats/search', [ data.users = data.users.filter(function (user) { return parseInt(user.uid, 10) !== parseInt(app.user.uid, 10); }); - + users = data.users; if (!data.users.length) { return chatsListEl.find('[component="chat/search/no-users"]').removeClass('hidden'); } chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); - const html = await app.parseAndTranslate('chats', 'searchUsers', { searchUsers: data.users }); + const html = await app.parseAndTranslate('modals/create-room', 'searchUsers', { searchUsers: data.users }); chatsListEl.append(html); chatsListEl.parent().toggleClass('show', true); } - function onUserClick(uid) { - if (!uid) { - return; - } - socket.emit('modules.chats.hasPrivateChat', uid, function (err, roomId) { - if (err) { - return alerts.error(err); - } - if (roomId) { - require(['forum/chats'], function (chats) { - chats.switchChat(roomId); - }); - } else { - require(['chat'], function (chat) { - chat.newChat(uid); - }); - } - }); - } - - return search; + return userSearch; }); diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index 2b8bce8107..986257bf9a 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -108,7 +108,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b } function handleMemberInfiniteScroll() { - $('[component="groups/members"] tbody').on('scroll', function () { + $('[component="groups/members"]').on('scroll', function () { const $this = $(this); const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; diff --git a/public/src/client/header/chat.js b/public/src/client/header/chat.js index 6b4a04aaf9..e384291945 100644 --- a/public/src/client/header/chat.js +++ b/public/src/client/header/chat.js @@ -1,6 +1,8 @@ 'use strict'; -define('forum/header/chat', ['components', 'hooks'], function (components, hooks) { +define('forum/header/chat', [ + 'components', 'hooks', +], function (components, hooks) { const chat = {}; chat.prepareDOM = function () { @@ -29,7 +31,20 @@ define('forum/header/chat', ['components', 'hooks'], function (components, hooks socket.removeListener('event:chats.roomRename', onRoomRename); socket.on('event:chats.roomRename', onRoomRename); - socket.on('event:unread.updateChatCount', function (count) { + socket.on('event:unread.updateChatCount', async function (data) { + if (data) { + const [chatModule, chatPage] = await app.require(['chat', 'forum/chats']); + if ( + chatModule.isFromBlockedUser(data.fromUid) || + chatModule.isLookingAtRoom(data.roomId) || + app.user.uid === parseInt(data.fromUid, 10) + ) { + return; + } + chatPage.markChatPageElUnread(data); + } + + let count = await socket.emit('modules.chats.getUnreadCount', {}); const chatIcon = components.get('chat/icon'); count = Math.max(0, count); chatIcon.toggleClass('fa-comment', count > 0) @@ -56,10 +71,9 @@ define('forum/header/chat', ['components', 'hooks'], function (components, hooks requireAndCall('onRoomRename', data); } - function requireAndCall(method, param) { - require(['chat'], function (chat) { - chat[method](param); - }); + async function requireAndCall(method, param) { + const chat = await app.require('chat'); + chat[method](param); } return chat; diff --git a/public/src/client/notifications.js b/public/src/client/notifications.js index af509a1edd..d42b23d51e 100644 --- a/public/src/client/notifications.js +++ b/public/src/client/notifications.js @@ -8,7 +8,7 @@ define('forum/notifications', ['components', 'notifications'], function (compone const listEl = $('.notifications-list'); listEl.on('click', '[component="notifications/item/link"]', function () { const nid = $(this).parents('[data-nid]').attr('data-nid'); - Notifications.markNotification(nid, true); + notifications.markNotification(nid, true); }); notifications.handleUnreadButton(listEl); diff --git a/public/src/client/register.js b/public/src/client/register.js index 3178ee8359..297bbe458a 100644 --- a/public/src/client/register.js +++ b/public/src/client/register.js @@ -124,7 +124,7 @@ define('forum/register', [ showError(username_notify, '[[error:invalid-username]]'); } else { Promise.allSettled([ - api.head(`/users/bySlug/${username}`, {}), + api.head(`/users/bySlug/${userslug}`, {}), api.head(`/groups/${username}`, {}), ]).then((results) => { if (results.every(obj => obj.status === 'rejected')) { diff --git a/public/src/client/search.js b/public/src/client/search.js index f9d7bdbc6d..4ca01b80f9 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -15,7 +15,7 @@ define('forum/search', [ let selectedUsers = []; let selectedTags = []; let selectedCids = []; - + let searchFilters = {}; Search.init = function () { const searchIn = $('#search-in'); searchIn.on('change', function () { @@ -30,9 +30,7 @@ define('forum/search', [ $('#advanced-search form').off('submit').on('submit', function (e) { e.preventDefault(); - searchModule.query(getSearchDataFromDOM(), function () { - $('#search-input').val(''); - }); + searchModule.query(getSearchDataFromDOM()); return false; }); @@ -53,12 +51,20 @@ define('forum/search', [ if (updateFns[$(this).attr('data-filter-name')]) { updateFns[$(this).attr('data-filter-name')](); } + + const searchFiltersNew = getSearchDataFromDOM(); + if (JSON.stringify(searchFilters) !== JSON.stringify(searchFiltersNew)) { + searchFilters = searchFiltersNew; + searchModule.query(searchFilters); + } }); fillOutForm(); updateTimeFilter(); updateReplyCountFilter(); updateSortFilter(); + + searchFilters = getSearchDataFromDOM(); }; function updateTagFilter() { diff --git a/public/src/client/tags.js b/public/src/client/tags.js index ca8036ee76..c754e7bbb9 100644 --- a/public/src/client/tags.js +++ b/public/src/client/tags.js @@ -54,7 +54,6 @@ define('forum/tags', ['forum/infinitescroll', 'alerts'], function (infinitescrol callback = callback || function () {}; app.parseAndTranslate('tags', 'tags', { tags: tags }, function (html) { $('.tag-list')[replace ? 'html' : 'append'](html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); callback(); }); } diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 7a0b228efd..30d58e25c6 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -160,7 +160,7 @@ define('forum/topic', [ alerts.alert({ alert_id: 'bookmark', message: '[[topic:bookmark_instructions]]', - timeout: 0, + timeout: 15000, type: 'info', clickfn: function () { navigator.scrollToIndex(parseInt(bookmark, 10), true); @@ -169,9 +169,6 @@ define('forum/topic', [ storage.removeItem('topic:' + tid + ':bookmark'); }, }); - setTimeout(function () { - alerts.remove('bookmark'); - }, 10000); } } @@ -242,6 +239,15 @@ define('forum/topic', [ function scrollbarVisible(element) { return element.scrollHeight > element.clientHeight; } + function offsetCodeBtn(codeEl) { + if (!codeEl.length) { return; } + if (!codeEl[0].scrollHeight) { + return setTimeout(offsetCodeBtn, 100, codeEl); + } + if (scrollbarVisible(codeEl.get(0))) { + codeEl.parent().parent().find('[component="copy/code/btn"]').css({ margin: '0.5rem 1.5rem 0 0' }); + } + } let codeBlocks = $('[component="topic"] [component="post/content"] code:not([data-button-added])'); codeBlocks = codeBlocks.filter((i, el) => $(el).text().includes('\n')); const container = $('
'); @@ -250,9 +256,7 @@ define('forum/topic', [ preEls.wrap(container).parent().append(buttonDiv); preEls.parent().find('[component="copy/code/btn"]').translateAttr('title', '[[topic:copy-code]]'); preEls.each((index, el) => { - if (scrollbarVisible(el)) { - $(el).parent().find('[component="copy/code/btn"]').css({ margin: '0.5rem 1.5rem 0 0' }); - } + offsetCodeBtn($(el).find('code')); }); codeBlocks.attr('data-button-added', 1); } diff --git a/public/src/client/topic/move-post.js b/public/src/client/topic/move-post.js index 5d02be63ee..490c0cefec 100644 --- a/public/src/client/topic/move-post.js +++ b/public/src/client/topic/move-post.js @@ -50,7 +50,7 @@ define('forum/topic/move-post', [ title: '[[topic:thread_tools.move-posts]]', message: '[[topic:topic_move_posts_success]]', type: 'success', - timeout: 10000, + timeout: config.undoTimeout, timeoutfn: function () { movePosts(data); }, @@ -78,7 +78,7 @@ define('forum/topic/move-post', [ ) { targetTid = ajaxify.data.tid; } - if (targetTid && !tidInput.val()) { + if (targetTid) { tidInput.val(targetTid); } checkMoveButtonEnable(); @@ -149,7 +149,10 @@ define('forum/topic/move-post', [ $(this).remove(); }); }); - + if (data.pids.length === 1 && ajaxify.data.template.topic && + parseInt(data.tid, 10) === parseInt(ajaxify.data.tid, 10)) { + ajaxify.go(`/post/${data.pids[0]}`); + } closeMoveModal(); }).catch(alerts.error); } diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 72de7164b3..5cf95d9374 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -11,7 +11,8 @@ define('forum/topic/postTools', [ 'bootbox', 'alerts', 'hooks', -], function (share, navigator, components, translator, votes, api, bootbox, alerts, hooks) { + 'helpers', +], function (share, navigator, components, translator, votes, api, bootbox, alerts, hooks, helpers) { const PostTools = {}; let staleReplyAnyway = false; @@ -85,8 +86,8 @@ define('forum/topic/postTools', [ PostTools.updatePostCount = function (postCount) { const postCountEl = components.get('topic/post-count'); - postCountEl.html(postCount).attr('title', postCount); - utils.makeNumbersHumanReadable(postCountEl); + postCountEl.attr('title', postCount) + .html(helpers.humanReadableNumber(postCount)); navigator.setCount(postCount); }; diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index e0c09cb96e..d9ce0c613b 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -10,7 +10,8 @@ define('forum/topic/posts', [ 'components', 'translator', 'hooks', -], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks) { + 'helpers', +], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks, helpers) { const Posts = { }; Posts.signaturesShown = {}; @@ -76,8 +77,7 @@ define('forum/topic/posts', [ function updatePostCounts(posts) { for (let i = 0; i < posts.length; i += 1) { const cmp = components.get('user/postcount', posts[i].uid); - cmp.html(parseInt(cmp.attr('data-postcount'), 10) + 1); - utils.addCommasToNumbers(cmp); + cmp.html(helpers.formattedNumber(parseInt(cmp.attr('data-postcount'), 10) + 1)); } } @@ -410,8 +410,6 @@ define('forum/topic/posts', [ Posts.onNewPostsAddedToDom = async function (posts) { await Posts.onTopicPageLoad(posts); - utils.addCommasToNumbers(posts.find('.formatted-number')); - utils.makeNumbersHumanReadable(posts.find('.human-readable-number')); posts.find('.timeago').timeago(); }; diff --git a/public/src/client/topic/votes.js b/public/src/client/topic/votes.js index 6f4c624492..7a5920742b 100644 --- a/public/src/client/topic/votes.js +++ b/public/src/client/topic/votes.js @@ -50,6 +50,7 @@ define('forum/topic/votes', [ el.attr('title', title); (new bootstrap.Tooltip(el, { container: '#content', + html: true, })).show(); } let usernames = data.usernames @@ -57,7 +58,7 @@ define('forum/topic/votes', [ if (!usernames.length) { return; } - if (usernames.length + data.otherCount > 6) { + if (usernames.length + data.otherCount > data.cutoff) { usernames = usernames.join(', ').replace(/,/g, '|'); translator.translate('[[topic:users_and_others, ' + usernames + ', ' + data.otherCount + ']]', function (translated) { translated = translated.replace(/\|/g, ','); diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 4dc9d1aba5..ae30c6c6b3 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -23,7 +23,27 @@ export function success(message, timeout) { title: '[[global:alert.success]]', message: message, type: 'success', - timeout: timeout || 5000, + timeout: timeout !== undefined ? timeout : 5000, + }); +} + +export function info(message, timeout) { + alert({ + alert_id: utils.generateUUID(), + title: '[[global:alert.info]]', + message: message, + type: 'info', + timeout: timeout !== undefined ? timeout : 5000, + }); +} + +export function warning(message, timeout) { + alert({ + alert_id: utils.generateUUID(), + title: '[[global:alert.warning]]', + message: message, + type: 'warning', + timeout: timeout !== undefined ? timeout : 5000, }); } @@ -52,7 +72,8 @@ export function remove(id) { function updateAlert(alert, params) { alert.find('strong').translateHtml(params.title); alert.find('p').translateHtml(params.message); - alert.attr('class', 'alert alert-dismissable alert-' + params.type + ' clearfix'); + alert.removeClass('alert-success alert-danger alert-info alert-warning') + .addClass(`alert-${params.type}`); clearTimeout(parseInt(alert.attr('timeoutId'), 10)); if (params.timeout) { @@ -67,10 +88,10 @@ function updateAlert(alert, params) { alert .addClass('pointer') .on('click', function (e) { - if (!$(e.target).is('.close')) { + if (!$(e.target).is('.btn-close')) { params.clickfn(); } - fadeOut(alert); + close(alert); }); } } @@ -82,19 +103,22 @@ function createNew(params) { return updateAlert(alert, params); } alert = html; - alert.fadeIn(200); - components.get('toaster/tray').prepend(alert); + alert.hide().fadeIn(200).prependTo(components.get('toaster/tray')); - if (typeof params.closefn === 'function') { - alert.find('button').on('click', function () { + alert.on('close.bs.alert', function () { + if (typeof params.closefn === 'function') { params.closefn(); - fadeOut(alert); - return false; - }); - } + } + const timeoutId = alert.attr('timeoutId'); - if (params.timeout) { + if (timeoutId) { + clearTimeout(timeoutId); + alert.removeAttr('timeoutId'); + } + }); + + if (parseInt(params.timeout, 10)) { startTimeout(alert, params); } @@ -102,10 +126,10 @@ function createNew(params) { alert .addClass('pointer') .on('click', function (e) { - if (!$(e.target).is('.close')) { + if (!$(e.target).is('.btn-close')) { params.clickfn(alert, params); } - fadeOut(alert); + close(alert); }); } @@ -113,17 +137,16 @@ function createNew(params) { }); } -function fadeOut(alert) { - alert.fadeOut(500, function () { - $(this).remove(); - }); +function close(alert) { + alert.alert('close'); } function startTimeout(alert, params) { - const timeout = params.timeout; + const timeout = parseInt(params.timeout, 10); const timeoutId = setTimeout(function () { - fadeOut(alert); + alert.removeAttr('timeoutId'); + close(alert); if (typeof params.timeoutfn === 'function') { params.timeoutfn(alert, params); @@ -133,20 +156,21 @@ function startTimeout(alert, params) { alert.attr('timeoutId', timeoutId); // Reset and start animation - alert.css('transition-property', 'none'); - alert.removeClass('animate'); + const alertProgress = alert.find('.alert-progress'); + alertProgress.css('transition-property', 'none'); + alertProgress.removeClass('animate'); setTimeout(function () { - alert.css('transition-property', ''); - alert.css('transition', 'width ' + (timeout + 450) + 'ms linear, background-color ' + (timeout + 450) + 'ms ease-in'); - alert.addClass('animate'); - hooks.fire('action:alert.animate', { alert, params }); + alertProgress.css('transition-property', ''); + alertProgress.css('transition', 'width ' + (timeout + 450) + 'ms linear'); + alertProgress.addClass('animate'); + hooks.fire('action:alert.animate', { alert, alertProgress, params }); }, 50); // Handle mouseenter/mouseleave alert .on('mouseenter', function () { - $(this).css('transition-duration', 0); + alertProgress.css('transition-duration', 0); }); } diff --git a/public/src/modules/api.js b/public/src/modules/api.js index ed0c7c2d2b..bfda975662 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -37,84 +37,106 @@ function call(options, callback) { } async function xhr(options, cb) { + // Normalize body based on type + const { url } = options; + delete options.url; + + if (options.data && !(options.data instanceof FormData)) { + options.data = JSON.stringify(options.data || {}); + options.headers['content-type'] = 'application/json; charset=utf-8'; + } + // Allow options to be modified by plugins, etc. ({ options } = await fireHook('filter:api.options', { options })); - $.ajax(options) - .done((res) => { - cb(null, ( - res && - res.hasOwnProperty('status') && - res.hasOwnProperty('response') ? res.response : (res || {}) - )); - }) - .fail((ev) => { - let errMessage; - if (ev.responseJSON) { - errMessage = ev.responseJSON.status && ev.responseJSON.status.message ? - ev.responseJSON.status.message : - ev.responseJSON.error; - } + /** + * Note: pre-v4 backwards compatibility + * + * This module now passes in "data" to xhr(). + * This is because the "filter:api.options" hook (and plugins using it) expect "data". + * fetch() expects body, so we rename it here. + * + * In v4, replace all instances of "data" with "body" and record as breaking change. + */ + if (options.data) { + options.body = options.data; + delete options.data; + } - cb(new Error(errMessage || ev.statusText)); - }); + const res = await fetch(url, options); + const { headers } = res; + const contentType = headers.get('content-type'); + const isJSON = contentType && contentType.startsWith('application/json'); + + let response; + if (isJSON) { + response = await res.json(); + } else { + response = await res.text(); + } + + if (!res.ok) { + return cb(new Error(isJSON ? response.status.message : response)); + } + + cb(null, ( + isJSON && response.hasOwnProperty('status') && response.hasOwnProperty('response') ? + response.response : + response + )); } -export function get(route, payload, onSuccess) { +export function get(route, data, onSuccess) { return call({ - url: route + (payload && Object.keys(payload).length ? ('?' + $.param(payload)) : ''), + url: route + (data && Object.keys(data).length ? ('?' + $.param(data)) : ''), }, onSuccess); } -export function head(route, payload, onSuccess) { +export function head(route, data, onSuccess) { return call({ - url: route + (payload && Object.keys(payload).length ? ('?' + $.param(payload)) : ''), + url: route + (data && Object.keys(data).length ? ('?' + $.param(data)) : ''), method: 'head', }, onSuccess); } -export function post(route, payload, onSuccess) { +export function post(route, data, onSuccess) { return call({ url: route, method: 'post', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function patch(route, payload, onSuccess) { +export function patch(route, data, onSuccess) { return call({ url: route, method: 'patch', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function put(route, payload, onSuccess) { +export function put(route, data, onSuccess) { return call({ url: route, method: 'put', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function del(route, payload, onSuccess) { +export function del(route, data, onSuccess) { return call({ url: route, method: 'delete', - data: JSON.stringify(payload), - contentType: 'application/json; charset=utf-8', + data, headers: { 'x-csrf-token': config.csrf_token, }, diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index ae435e72bd..277859ce3d 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -1,13 +1,13 @@ 'use strict'; define('autocomplete', ['api', 'alerts'], function (api, alerts) { - const module = {}; + const autocomplete = {}; const _default = { delay: 200, appendTo: null, }; - module.init = (params) => { + autocomplete.init = (params) => { const acParams = { ..._default, ...params }; const { input, onSelect } = acParams; app.loadJQueryUI(function () { @@ -23,14 +23,14 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.user = function (input, params, onSelect) { + autocomplete.user = function (input, params, onSelect) { if (typeof params === 'function') { onSelect = params; params = {}; } params = params || {}; - module.init({ + autocomplete.init({ input, onSelect, source: (request, response) => { @@ -69,8 +69,8 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.group = function (input, onSelect) { - module.init({ + autocomplete.group = function (input, onSelect) { + autocomplete.init({ input, onSelect, source: (request, response) => { @@ -96,8 +96,8 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.tag = function (input, onSelect) { - module.init({ + autocomplete.tag = function (input, onSelect) { + autocomplete.init({ input, onSelect, delay: 100, @@ -129,5 +129,5 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { onselect(event, ui); } - return module; + return autocomplete; }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 54dca63971..23e0b67f6b 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -88,48 +88,49 @@ define('chat', [ if (err) { return alerts.error(err); } - - const rooms = data.rooms.filter(function (room) { - return room.teaser; + const rooms = data.rooms.map((room) => { + if (room && room.teaser) { + room.teaser.timeagoLong = $.timeago(new Date(parseInt(room.teaser.timestamp, 10))); + } + return room; }); - for (let i = 0; i < rooms.length; i += 1) { - rooms[i].teaser.timeagoLong = $.timeago(new Date(parseInt(rooms[i].teaser.timestamp, 10))); - } + translator.toggleTimeagoShorthand(async function () { + rooms.forEach((room) => { + if (room && room.teaser) { + room.teaser.timeago = $.timeago(new Date(parseInt(room.teaser.timestamp, 10))); + room.teaser.timeagoShort = room.teaser.timeago; + } + }); - translator.toggleTimeagoShorthand(function () { - for (let i = 0; i < rooms.length; i += 1) { - rooms[i].teaser.timeago = $.timeago(new Date(parseInt(rooms[i].teaser.timestamp, 10))); - rooms[i].teaser.timeagoShort = rooms[i].teaser.timeago; - } translator.toggleTimeagoShorthand(); - app.parseAndTranslate('partials/chats/dropdown', { rooms: rooms }, function (html) { - const listEl = chatsListEl.get(0); + const html = await app.parseAndTranslate('partials/chats/dropdown', { rooms: rooms }); + const listEl = chatsListEl.get(0); - chatsListEl.find('*').not('.navigation-link').remove(); - chatsListEl.prepend(html); - chatsListEl.off('click').on('click', '[data-roomid]', function (ev) { - if (['.user-link', '.mark-read'].some(className => ev.target.closest(className))) { - return; - } - const roomId = $(this).attr('data-roomid'); - if (!ajaxify.currentPage.match(/^chats\//)) { - module.openChat(roomId); - } else { - ajaxify.go('user/' + app.user.userslug + '/chats/' + roomId); - } - }); + chatsListEl.find('*').not('.navigation-link').remove(); + chatsListEl.prepend(html); + chatsListEl.off('click').on('click', '[data-roomid]', function (ev) { + if (['.user-link', '.mark-read'].some(className => ev.target.closest(className))) { + return; + } + const roomId = $(this).attr('data-roomid'); + if (!ajaxify.currentPage.match(/^chats\//)) { + module.openChat(roomId); + } else { + ajaxify.go('user/' + app.user.userslug + '/chats/' + roomId); + } + }); - listEl.removeEventListener('click', onMarkReadClicked); - listEl.addEventListener('click', onMarkReadClicked); + listEl.removeEventListener('click', onMarkReadClicked); + listEl.addEventListener('click', onMarkReadClicked); - $('[component="chats/mark-all-read"]').off('click').on('click', function () { - socket.emit('modules.chats.markAllRead', function (err) { - if (err) { - return alerts.error(err); - } + $('[component="chats/mark-all-read"]').off('click').on('click', async function () { + await socket.emit('modules.chats.markAllRead'); + if (ajaxify.data.template.chats) { + $('[component="chat/nav-wrapper"] [data-roomid]').each((i, el) => { + module.markChatElUnread($(el), false); }); - }); + } }); }); }); @@ -143,30 +144,53 @@ define('chat', [ e.stopPropagation(); const chatEl = e.target.closest('[data-roomid]'); - const state = !chatEl.classList.contains('unread'); + module.toggleReadState(chatEl); + } + + module.toggleReadState = function (chatEl) { + const state = !chatEl.classList.contains('unread'); // this is the new state const roomId = chatEl.getAttribute('data-roomid'); api[state ? 'put' : 'del'](`/chats/${roomId}/state`, {}).catch((err) => { alerts.error(err); // Revert on failure - chatEl.classList[state ? 'remove' : 'add']('unread'); - chatEl.querySelector('.unread').classList[state ? 'add' : 'remove']('hidden'); - chatEl.querySelector('.read').classList[!state ? 'add' : 'remove']('hidden'); + module.markChatElUnread($(chatEl), !state); }); // Immediate feedback - chatEl.classList[state ? 'add' : 'remove']('unread'); - chatEl.querySelector('.unread').classList[!state ? 'add' : 'remove']('hidden'); - chatEl.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); - } + module.markChatElUnread($(chatEl), state); + }; + + module.isFromBlockedUser = function (fromUid) { + return app.user.blocks.includes(parseInt(fromUid, 10)); + }; + + module.isLookingAtRoom = function (roomId) { + return ajaxify.data.template.chats && parseInt(ajaxify.data.roomId, 10) === parseInt(roomId, 10); + }; + + module.markChatElUnread = function (roomEl, unread) { + if (roomEl.length > 0) { + roomEl.toggleClass('unread', unread); + const markEl = roomEl.find('.mark-read'); + if (markEl.length) { + markEl.find('.read').toggleClass('hidden', unread); + markEl.find('.unread').toggleClass('hidden', !unread); + } + } + }; module.onChatMessageReceived = function (data) { - if (!newMessage) { - newMessage = data.self === 0; + if (app.user.blocks.includes(parseInt(data.fromUid, 10))) { + return; } if (module.modalExists(data.roomId)) { + data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0; + if (!newMessage) { + newMessage = data.self === 0; + } data.message.self = data.self; - data.message.timestamp = Math.min(Date.now(), data.message.timetamp); + data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); addMessageToModal(data); } @@ -179,13 +203,13 @@ define('chat', [ require(['forum/chats/messages'], function (ChatsMessages) { // don't add if already added if (!modal.find('[data-mid="' + data.message.messageId + '"]').length) { - ChatsMessages.appendChatMessage(modal.find('.chat-content'), data.message); + ChatsMessages.appendChatMessage(modal.find('[component="chat/message/content"]'), data.message); } if (modal.is(':visible')) { taskbar.updateActive(modal.attr('data-uuid')); - if (ChatsMessages.isAtBottom(modal.find('.chat-content'))) { - ChatsMessages.scrollToBottom(modal.find('.chat-content')); + if (ChatsMessages.isAtBottom(modal.find('[component="chat/message/content"]'))) { + ChatsMessages.scrollToBottomAfterImageLoad(modal.find('[component="chat/message/content"]')); } } else if (!ajaxify.data.template.chats) { module.toggleNew(modal.attr('data-uuid'), true, true); @@ -208,9 +232,18 @@ define('chat', [ }; module.onRoomRename = function (data) { - const newTitle = $('
').html(data.newName).text(); const modal = module.getModal(data.roomId); - modal.find('[component="chat/room/name"]').text(newTitle); + const titleEl = modal.find('[component="chat/room/name"]'); + const icon = titleEl.attr('data-icon'); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + data.chatWithMessage + ); + } + + const newTitle = $('
').html(data.newName).text(); taskbar.update('chat', modal.attr('data-uuid'), { title: newTitle, }); @@ -230,17 +263,18 @@ define('chat', [ module.createModal = function (data, callback) { callback = callback || function () {}; require([ - 'scrollStop', 'forum/chats', 'forum/chats/messages', - ], function (scrollStop, Chats, ChatsMessages) { + 'scrollStop', 'forum/chats', 'forum/chats/messages', 'forum/chats/message-search', + ], function (scrollStop, Chats, ChatsMessages, messageSearch) { app.parseAndTranslate('chat', data, function (chatModal) { - if (module.modalExists(data.roomId)) { + const roomId = data.roomId; + if (module.modalExists(roomId)) { return callback(module.getModal(data.roomId)); } const uuid = utils.generateUUID(); let dragged = false; - chatModal.attr('id', 'chat-modal-' + data.roomId); - chatModal.attr('data-roomid', data.roomId); + chatModal.attr('id', 'chat-modal-' + roomId); + chatModal.attr('data-roomid', roomId); chatModal.attr('intervalId', 0); chatModal.attr('data-uuid', uuid); chatModal.css('position', 'fixed'); @@ -289,7 +323,7 @@ define('chat', [ components.get('chat/input').val(text); }); - ajaxify.go('user/' + app.user.userslug + '/chats/' + chatModal.attr('data-roomid')); + ajaxify.go(`user/${app.user.userslug}/chats/${roomId}`); module.close(uuid); } @@ -316,22 +350,23 @@ define('chat', [ chatModal.on('mousemove keypress click', function () { if (newMessage) { - api.del(`/chats/${data.roomId}/state`, {}); + api.del(`/chats/${roomId}/state`, {}); newMessage = false; } }); - Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), data.roomId); - Chats.addRenameHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="rename"]'), data.roomName); - Chats.addLeaveHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="leave"]')); - Chats.addSendHandlers(chatModal.attr('data-roomid'), chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); - Chats.addMemberHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="members"]')); + Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), roomId); + Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]')); + Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]')); + Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]')); + Chats.addSendHandlers(roomId, chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); + Chats.addManageHandler(roomId, chatModal.find('[data-action="manage"]')); - Chats.createAutoComplete(chatModal.attr('data-roomid'), chatModal.find('[component="chat/input"]')); - - Chats.addScrollHandler(chatModal.attr('data-roomid'), data.uid, chatModal.find('.chat-content')); - Chats.addScrollBottomHandler(chatModal.find('.chat-content')); + Chats.createAutoComplete(roomId, chatModal.find('[component="chat/input"]')); + Chats.addScrollHandler(roomId, data.uid, chatModal.find('[component="chat/message/content"]')); + Chats.addScrollBottomHandler(chatModal.find('[component="chat/message/content"]')); + Chats.addParentHandler(chatModal.find('[component="chat/message/content"]')); Chats.addCharactersLeftHandler(chatModal); Chats.addTextareaResizeHandler(chatModal); Chats.addIPHandler(chatModal); @@ -345,6 +380,8 @@ define('chat', [ }); ChatsMessages.addSocketListeners(); + messageSearch.init(roomId, chatModal); + Chats.addNotificationSettingHandler(roomId, chatModal); taskbar.push('chat', chatModal.attr('data-uuid'), { title: '[[modules:chat.chatting_with]] ' + (data.roomName || (data.users.length ? data.users[0].username : '')), @@ -381,10 +418,11 @@ define('chat', [ if (chatModal.attr('data-mobile')) { module.disableMobileBehaviour(chatModal); } + const roomId = chatModal.attr('data-roomid'); require(['forum/chats'], function (chats) { - chats.destroyAutoComplete(chatModal.attr('data-roomid')); + chats.destroyAutoComplete(roomId); }); - + socket.emit('modules.chats.leave', roomId); hooks.fire('action:chat.closed', { uuid: uuid, modal: chatModal, @@ -415,10 +453,11 @@ define('chat', [ const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]'); chatModal.removeClass('hide'); taskbar.updateActive(uuid); - ChatsMessages.scrollToBottom(chatModal.find('.chat-content')); + ChatsMessages.scrollToBottomAfterImageLoad(chatModal.find('.chat-content')); module.focusInput(chatModal); - api.del(`/chats/${chatModal.attr('data-roomid')}/state`, {}); - + const roomId = chatModal.attr('data-roomid'); + api.del(`/chats/${roomId}/state`, {}); + socket.emit('modules.chats.enter', roomId); const env = utils.findBootstrapEnvironment(); if (env === 'xs' || env === 'sm') { module.enableMobileBehaviour(chatModal); diff --git a/public/src/modules/helpers.common.js b/public/src/modules/helpers.common.js index 123b5eccc6..8121ad171d 100644 --- a/public/src/modules/helpers.common.js +++ b/public/src/modules/helpers.common.js @@ -29,7 +29,8 @@ module.exports = function (utils, Benchpress, relative_path) { generateWrote, isoTimeToLocaleString, shouldHideReplyContainer, - + humanReadableNumber, + formattedNumber, register, __escape: identity, }; @@ -352,6 +353,14 @@ module.exports = function (utils, Benchpress, relative_path) { return false; } + function humanReadableNumber(number, toFixed = 1) { + return utils.makeNumberHumanReadable(number, toFixed); + } + + function formattedNumber(number) { + return utils.addCommas(number); + } + function register() { Object.keys(helpers).forEach(function (helperName) { Benchpress.registerHelper(helperName, helpers[helperName]); diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js index 3795c00e23..fb4d537a45 100644 --- a/public/src/modules/iconSelect.js +++ b/public/src/modules/iconSelect.js @@ -2,6 +2,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { + const fontawesome_license = config.fontawesome.pro ? 'pro' : 'free'; const iconSelect = {}; const initialIcons = [ { id: 'nbb-none', label: 'None (NodeBB)', style: 'nodebb' }, @@ -222,16 +223,17 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { { id: 'address-book', label: 'Address Book (solid)', style: 'solid' }, ]; iconSelect.init = function (el, onModified) { - onModified = onModified || function () {}; - let selected = cleanFAClass(el.attr('class')); - + onModified = onModified || function () { }; + let selected = cleanFAClass(el[0].classList); $('#icons .selected').removeClass('selected'); - - if (selected) { + if (selected.icon) { try { - $('#icons .nbb-fa-icons .fa.' + selected).addClass('selected'); + $(`#icons .nbb-fa-icons ${selected.styles.length ? '.' + selected.styles.join('.') : ''}.${selected.icon}`).addClass('selected'); } catch (err) { - selected = ''; + selected = { + icon: '', + style: '', + }; } } @@ -250,26 +252,39 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { label: 'No Icon', className: 'btn-default', callback: function () { - el.removeClass(selected); + el.removeClass(selected.icon); + // eslint-disable-next-line no-restricted-syntax + for (const style of selected.styles) { + el.removeClass(style); + } el.val(''); el.attr('value', ''); - onModified(el, ''); + onModified(el, '', []); }, }, success: { label: 'Select', className: 'btn-primary', callback: function () { - const iconClass = $('.bootbox .selected').attr('class') || `fa fa-${$('.bootbox #fa-filter').val()}`; - const newIconClass = cleanFAClass(iconClass); - - if (newIconClass) { - el.removeClass(selected).addClass(newIconClass); - el.val(newIconClass); - el.attr('value', newIconClass); + const iconClass = $('.bootbox .selected')[0]?.classList || [`fa-${$('.bootbox #fa-filter').val()}`]; + const newIcon = cleanFAClass(iconClass); + if (newIcon.icon) { + el.removeClass(selected.icon).addClass(newIcon.icon); + // eslint-disable-next-line no-restricted-syntax + for (const style of selected.styles || []) { + el.removeClass(style); + } + // eslint-disable-next-line no-restricted-syntax + for (const style of newIcon.styles || []) { + el.addClass(style); + } + // Simple workaround for lack of style information in icons by just adding the style class to the value + const newValue = newIcon.icon + (newIcon.styles.length ? ' ' + newIcon.styles.join(' ') : ''); + el.val(newValue); + el.attr('value', newValue); } - onModified(el, newIconClass); + onModified(el, newIcon.icon, newIcon.styles); }, }, }, @@ -279,9 +294,9 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { const modalEl = $(this); const searchEl = modalEl.find('input'); - if (selected) { - modalEl.find('.' + selected).addClass('selected'); - searchEl.val(selected.replace('fa-', '')); + if (selected.icon) { + modalEl.find('.' + selected.icon).addClass('selected'); + searchEl.val(selected.icon.replace('fa-', '')); } }).modal('show'); @@ -298,8 +313,8 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { if (newSelection) { newSelection.addClass('selected'); } else if (searchEl.val().length === 0) { - if (selected) { - modalEl.find('.' + selected).addClass('selected'); + if (selected.icon) { + modalEl.find('.' + selected.icon).addClass('selected'); } } else { modalEl.find('i:visible').first().addClass('selected'); @@ -310,7 +325,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { searchEl.selectRange(0, searchEl.val().length); modalEl.find('.icon-container').on('click', 'i', function () { - searchEl.val(cleanFAClass($(this).attr('class')).replace('fa-', '')); + searchEl.val(cleanFAClass($(this)[0].classList).icon.replace('fa-', '')); changeSelection($(this)); }); const debouncedSearch = utils.debounce(async () => { @@ -323,7 +338,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { } icons.remove(); iconData.forEach((iconData) => { - iconContainer.append($(``)); + iconContainer.append($(``)); }); icons = modalEl.find('.nbb-fa-icons i'); changeSelection(); @@ -340,13 +355,54 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { }); }; - // turns "fa fa-2x fa-solid fa-heart" into "fa-heart" - function cleanFAClass(className) { - className = className.replace(/fa-(solid|regular|brands|light|thin|duotone|nodebb) /, ''); - const filterNames = ['fa-2x', 'fa-xl', 'fa', 'fa-']; - return className.split(' ') - .filter(c => !filterNames.includes(c)) - .filter(c => c && c.startsWith('fa-')).join(''); + const excludedClassList = [ + 'nodebb', + 'fw', + '\\d{1,2}?[xsl][smgl]', + 'rotate-(\\d+|horizontal|vertical|both|by)', + 'flip-(\\d+|horizontal|vertical|both)', + 'beat', + 'fade', + 'beat-fade', + 'bounce', + 'flip', + 'shake', + 'spin', + 'spin-pulse', + 'spin-reverse', + 'border', + 'pull-(left|right)', + 'stack(-\\dx)?', + 'inverse', + 'layers(-text)?(-counter)?', + 'ul', + 'li', + 'border', + 'swap-opacity', + 'sr-only(-focusable)?', + ]; + + const excludedClassRegex = RegExp(`\\bfa-(${excludedClassList.join('|')})\\b`, 'i'); + + const styleRegex = /fa-(solid|regular|brands|light|thin|duotone|sharp)/; + // turns 'fa fa-2x fa-solid fa-heart' into 'fa-heart' + function cleanFAClass(classList) { + const styles = []; + let icon; + // eslint-disable-next-line no-restricted-syntax + for (const className of classList) { + if (className.startsWith('fa-') && !excludedClassRegex.test(className)) { + if (styleRegex.test(className)) { + styles.push(className); + } else { + icon = className; + } + } + } + return { + icon, + styles, + }; } iconSelect.findIcons = async function (searchString) { @@ -357,26 +413,35 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { }, body: JSON.stringify({ query: `query { - search(version: "6.2.0", query: "${searchString}", first: 200) { + search(version: "${config.fontawesome.version}", query: "${searchString}", first: 200) { id, label, familyStylesByLicense { - free { - style + ${fontawesome_license} { + style, + family } } } - }`, + }`.replace(/(\n| {2,}|\t{2,})/g, ''), // very simple minification }), }); const response = await request.json(); const icons = response.data.search.filter(icon => icon.familyStylesByLicense.free.length > 0).flatMap((icon) => { const result = []; - icon.familyStylesByLicense.free.forEach((style) => { + icon.familyStylesByLicense[fontawesome_license].forEach((style) => { + let familyStyle = style.style; + if (style.family !== 'classic') { + familyStyle = `${style.family}-${familyStyle}`; + } + if (!config.fontawesome.styles.includes(familyStyle)) { + return; + } result.push({ id: icon.id, label: `${icon.label} (${style.style})`, style: style.style, + family: style.family, }); }); return result; diff --git a/public/src/modules/search.js b/public/src/modules/search.js index ebcc12dab0..566be43ab2 100644 --- a/public/src/modules/search.js +++ b/public/src/modules/search.js @@ -243,8 +243,7 @@ define('search', [ Search.query = function (data, callback) { callback = callback || function () {}; - ajaxify.go('search?' + createQueryString(data)); - callback(); + ajaxify.go('search?' + createQueryString(data), callback); }; Search.api = function (data, callback) { diff --git a/public/src/modules/topicList.js b/public/src/modules/topicList.js index 5d1ea52a62..f771eca47c 100644 --- a/public/src/modules/topicList.js +++ b/public/src/modules/topicList.js @@ -242,7 +242,6 @@ define('topicList', [ } html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:topics.loaded', { topics: topics, template: templateName }); callback(); }); diff --git a/public/src/modules/uploadHelpers.js b/public/src/modules/uploadHelpers.js index e532054288..ce6cb08476 100644 --- a/public/src/modules/uploadHelpers.js +++ b/public/src/modules/uploadHelpers.js @@ -160,7 +160,7 @@ define('uploadHelpers', ['alerts'], function (alerts) { if ((isImage && !app.user.privileges['upload:post:image']) || (!isImage && !app.user.privileges['upload:post:file'])) { return alerts.error('[[error:no-privileges]]'); } - if (files[i].size > parseInt(config.maximumFileSize, 10) * 1024) { + if (!app.user.isAdmin && files[i].size > parseInt(config.maximumFileSize, 10) * 1024) { options.uploadForm[0].reset(); return alerts.error('[[error:file-too-big, ' + config.maximumFileSize + ']]'); } diff --git a/public/src/sockets.js b/public/src/sockets.js index acd3ba3dbe..9e840ec513 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -159,15 +159,14 @@ app = window.app || {}; function onConnect() { if (!reconnecting) { hooks.fire('action:connected'); - } - - if (reconnecting) { + } else { const reconnectEl = $('#reconnect'); const reconnectAlert = $('#reconnect-alert'); reconnectEl.tooltip('dispose'); reconnectEl.html(''); - reconnectAlert.addClass('hide'); + reconnectAlert.removeClass('show'); + setTimeout(() => reconnectAlert.addClass('hide'), 100); reconnecting = false; reJoinCurrentRoom(); @@ -188,16 +187,24 @@ app = window.app || {}; app.currentRoom = ''; app.enterRoom(current); } + if (ajaxify.data.template.chats) { + if (ajaxify.data.roomId) { + socket.emit('modules.chats.enter', ajaxify.data.roomId); + } + if (ajaxify.data.publicRooms) { + socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); + } + } } function onReconnecting() { - reconnecting = true; const reconnectEl = $('#reconnect'); const reconnectAlert = $('#reconnect-alert'); if (!reconnectEl.hasClass('active')) { reconnectEl.html(''); reconnectAlert.removeClass('hide'); + setTimeout(() => reconnectAlert.addClass('show'), 100); } reconnectEl.addClass('active').removeClass('hide').tooltip({ @@ -207,8 +214,9 @@ app = window.app || {}; } function onDisconnect() { + reconnecting = true; setTimeout(function () { - if (socket.disconnected) { + if (!socket.connected) { onReconnecting(); } }, 2000); diff --git a/public/src/utils.common.js b/public/src/utils.common.js index f83b3924a2..5773fa1675 100644 --- a/public/src/utils.common.js +++ b/public/src/utils.common.js @@ -442,7 +442,7 @@ const utils = { makeNumberHumanReadable: function (num, toFixed = 1) { const n = parseInt(num, 10); if (!n) { - return num; + return String(num); } if (n > 999999) { return (n / 1000000).toFixed(toFixed) + 'm'; diff --git a/public/src/utils.js b/public/src/utils.js index 863b8f0c40..0c7f106fa5 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -16,18 +16,21 @@ utils.getLanguage = function () { utils.makeNumbersHumanReadable = function (elements) { + console.warn('[deprecated] utils.makeNumbersHumanReadable is deprecated! Use {humanReadableNumber(value)} helper directly in the template'); elements.each(function () { const $this = $(this); const toFixed = $this.attr('data-toFixed') || 1; - $this.html(utils.makeNumberHumanReadable($(this).attr('title'), toFixed)) + $this.html(utils.makeNumberHumanReadable($this.attr('title'), toFixed)) .removeClass('hidden'); }); }; utils.addCommasToNumbers = function (elements) { + console.warn('[deprecated] utils.addCommasToNumbers is deprecated! Use {formattedNumber(value)} helper directly in the template'); elements.each(function (index, element) { - $(element) - .html(utils.addCommas($(element).html())) + const $element = $(element); + $element + .html(utils.addCommas($element.html())) .removeClass('hidden'); }); }; diff --git a/public/vendor/fontawesome/.gitignore b/public/vendor/fontawesome/.gitignore deleted file mode 100644 index aaad45f3c8..0000000000 --- a/public/vendor/fontawesome/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -*.pyc -*.egg-info -*.db -*.db.old -*.swp -*.db-journal - -.coverage -.DS_Store -.installed.cfg - -.idea/* -.svn/* -src/website/static/* -src/website/media/* - -bin -build -cfcache -develop-eggs -dist -downloads -eggs -parts -tmp -.sass-cache - -src/website/settingslocal.py -stunnel.log \ No newline at end of file diff --git a/public/vendor/fontawesome/LICENSE.txt b/public/vendor/fontawesome/LICENSE.txt deleted file mode 100644 index cc557ece45..0000000000 --- a/public/vendor/fontawesome/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ -Fonticons, Inc. (https://fontawesome.com) - --------------------------------------------------------------------------------- - -Font Awesome Free License - -Font Awesome Free is free, open source, and GPL friendly. You can use it for -commercial projects, open source projects, or really almost whatever you want. -Full Font Awesome Free license: https://fontawesome.com/license/free. - --------------------------------------------------------------------------------- - -# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) - -The Font Awesome Free download is licensed under a Creative Commons -Attribution 4.0 International License and applies to all icons packaged -as SVG and JS file types. - --------------------------------------------------------------------------------- - -# Fonts: SIL OFL 1.1 License - -In the Font Awesome Free download, the SIL OFL license applies to all icons -packaged as web and desktop font files. - -Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com) -with Reserved Font Name: "Font Awesome". - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - -SIL OPEN FONT LICENSE -Version 1.1 - 26 February 2007 - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting — in part or in whole — any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - --------------------------------------------------------------------------------- - -# Code: MIT License (https://opensource.org/licenses/MIT) - -In the Font Awesome Free download, the MIT license applies to all non-font and -non-icon files. - -Copyright 2022 Fonticons, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in the -Software without restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------------------- - -# Attribution - -Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font -Awesome Free files already contain embedded comments with sufficient -attribution, so you shouldn't need to do anything additional when using these -files normally. - -We've kept attribution comments terse, so we ask that you do not actively work -to remove them from files, especially code. They're a great way for folks to -learn about Font Awesome. - --------------------------------------------------------------------------------- - -# Brand Icons - -All brand icons are trademarks of their respective owners. The use of these -trademarks does not indicate endorsement of the trademark holder by Font -Awesome, nor vice versa. **Please do not use brand logos for any purpose except -to represent the company, product, or service to which they refer.** diff --git a/public/vendor/fontawesome/attribution.js b/public/vendor/fontawesome/attribution.js deleted file mode 100644 index a659606c8d..0000000000 --- a/public/vendor/fontawesome/attribution.js +++ /dev/null @@ -1,3 +0,0 @@ -console.log(`Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com -License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -`) \ No newline at end of file diff --git a/public/vendor/fontawesome/scss/_animated.scss b/public/vendor/fontawesome/scss/_animated.scss deleted file mode 100644 index 93555b2f43..0000000000 --- a/public/vendor/fontawesome/scss/_animated.scss +++ /dev/null @@ -1,153 +0,0 @@ -// animating icons -// -------------------------- - -.#{$fa-css-prefix}-beat { - animation-name: #{$fa-css-prefix}-beat; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out); -} - -.#{$fa-css-prefix}-bounce { - animation-name: #{$fa-css-prefix}-bounce; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(0.280, 0.840, 0.420, 1)); -} - -.#{$fa-css-prefix}-fade { - animation-name: #{$fa-css-prefix}-fade; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1)); -} - -.#{$fa-css-prefix}-beat-fade { - animation-name: #{$fa-css-prefix}-beat-fade; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1)); -} - -.#{$fa-css-prefix}-flip { - animation-name: #{$fa-css-prefix}-flip; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out); -} - -.#{$fa-css-prefix}-shake { - animation-name: #{$fa-css-prefix}-shake; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear); -} - -.#{$fa-css-prefix}-spin { - animation-name: #{$fa-css-prefix}-spin; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 2s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear); -} - -.#{$fa-css-prefix}-spin-reverse { - --#{$fa-css-prefix}-animation-direction: reverse; -} - -.#{$fa-css-prefix}-pulse, -.#{$fa-css-prefix}-spin-pulse { - animation-name: #{$fa-css-prefix}-spin; - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, steps(8)); -} - -// if agent or operating system prefers reduced motion, disable animations -// see: https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/ -// see: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion -@media (prefers-reduced-motion: reduce) { - .#{$fa-css-prefix}-beat, - .#{$fa-css-prefix}-bounce, - .#{$fa-css-prefix}-fade, - .#{$fa-css-prefix}-beat-fade, - .#{$fa-css-prefix}-flip, - .#{$fa-css-prefix}-pulse, - .#{$fa-css-prefix}-shake, - .#{$fa-css-prefix}-spin, - .#{$fa-css-prefix}-spin-pulse { - animation-delay: -1ms; - animation-duration: 1ms; - animation-iteration-count: 1; - transition-delay: 0s; - transition-duration: 0s; - } -} - -@keyframes #{$fa-css-prefix}-beat { - 0%, 90% { transform: scale(1); } - 45% { transform: scale(var(--#{$fa-css-prefix}-beat-scale, 1.25)); } -} - -@keyframes #{$fa-css-prefix}-bounce { - 0% { transform: scale(1,1) translateY(0); } - 10% { transform: scale(var(--#{$fa-css-prefix}-bounce-start-scale-x, 1.1),var(--#{$fa-css-prefix}-bounce-start-scale-y, 0.9)) translateY(0); } - 30% { transform: scale(var(--#{$fa-css-prefix}-bounce-jump-scale-x, 0.9),var(--#{$fa-css-prefix}-bounce-jump-scale-y, 1.1)) translateY(var(--#{$fa-css-prefix}-bounce-height, -0.5em)); } - 50% { transform: scale(var(--#{$fa-css-prefix}-bounce-land-scale-x, 1.05),var(--#{$fa-css-prefix}-bounce-land-scale-y, 0.95)) translateY(0); } - 57% { transform: scale(1,1) translateY(var(--#{$fa-css-prefix}-bounce-rebound, -0.125em)); } - 64% { transform: scale(1,1) translateY(0); } - 100% { transform: scale(1,1) translateY(0); } -} - -@keyframes #{$fa-css-prefix}-fade { - 50% { opacity: var(--#{$fa-css-prefix}-fade-opacity, 0.4); } -} - -@keyframes #{$fa-css-prefix}-beat-fade { - 0%, 100% { - opacity: var(--#{$fa-css-prefix}-beat-fade-opacity, 0.4); - transform: scale(1); - } - 50% { - opacity: 1; - transform: scale(var(--#{$fa-css-prefix}-beat-fade-scale, 1.125)); - } -} - -@keyframes #{$fa-css-prefix}-flip { - 50% { - transform: rotate3d(var(--#{$fa-css-prefix}-flip-x, 0), var(--#{$fa-css-prefix}-flip-y, 1), var(--#{$fa-css-prefix}-flip-z, 0), var(--#{$fa-css-prefix}-flip-angle, -180deg)); - } -} - -@keyframes #{$fa-css-prefix}-shake { - 0% { transform: rotate(-15deg); } - 4% { transform: rotate(15deg); } - 8%, 24% { transform: rotate(-18deg); } - 12%, 28% { transform: rotate(18deg); } - 16% { transform: rotate(-22deg); } - 20% { transform: rotate(22deg); } - 32% { transform: rotate(-12deg); } - 36% { transform: rotate(12deg); } - 40%, 100% { transform: rotate(0deg); } -} - -@keyframes #{$fa-css-prefix}-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - diff --git a/public/vendor/fontawesome/scss/_bordered-pulled.scss b/public/vendor/fontawesome/scss/_bordered-pulled.scss deleted file mode 100644 index 9068253a74..0000000000 --- a/public/vendor/fontawesome/scss/_bordered-pulled.scss +++ /dev/null @@ -1,20 +0,0 @@ -// bordered + pulled icons -// ------------------------- - -.#{$fa-css-prefix}-border { - border-color: var(--#{$fa-css-prefix}-border-color, #{$fa-border-color}); - border-radius: var(--#{$fa-css-prefix}-border-radius, #{$fa-border-radius}); - border-style: var(--#{$fa-css-prefix}-border-style, #{$fa-border-style}); - border-width: var(--#{$fa-css-prefix}-border-width, #{$fa-border-width}); - padding: var(--#{$fa-css-prefix}-border-padding, #{$fa-border-padding}); -} - -.#{$fa-css-prefix}-pull-left { - float: left; - margin-right: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); -} - -.#{$fa-css-prefix}-pull-right { - float: right; - margin-left: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); -} diff --git a/public/vendor/fontawesome/scss/_core.scss b/public/vendor/fontawesome/scss/_core.scss deleted file mode 100644 index 1b2fd99205..0000000000 --- a/public/vendor/fontawesome/scss/_core.scss +++ /dev/null @@ -1,43 +0,0 @@ -// base icon class definition -// ------------------------- - -.#{$fa-css-prefix} { - font-family: var(--#{$fa-css-prefix}-style-family, '#{$fa-style-family}'); - font-weight: var(--#{$fa-css-prefix}-style, #{$fa-style}); -} - -.#{$fa-css-prefix}, -.#{$fa-css-prefix}-classic, -.#{$fa-css-prefix}-sharp, -.fas, -.#{$fa-css-prefix}-solid, -.far, -.#{$fa-css-prefix}-regular, -.fab, -.#{$fa-css-prefix}-brands { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: var(--#{$fa-css-prefix}-display, #{$fa-display}); - font-style: normal; - font-variant: normal; - line-height: 1; - text-rendering: auto; -} - -.fas, -.#{$fa-css-prefix}-classic, -.#{$fa-css-prefix}-solid, -.far, -.#{$fa-css-prefix}-regular { - font-family: 'Font Awesome 6 Free'; -} - -.fab, -.#{$fa-css-prefix}-brands { - font-family: 'Font Awesome 6 Brands'; -} - - -%fa-icon { - @include fa-icon; -} diff --git a/public/vendor/fontawesome/scss/_fixed-width.scss b/public/vendor/fontawesome/scss/_fixed-width.scss deleted file mode 100644 index 72342368af..0000000000 --- a/public/vendor/fontawesome/scss/_fixed-width.scss +++ /dev/null @@ -1,7 +0,0 @@ -// fixed-width icons -// ------------------------- - -.#{$fa-css-prefix}-fw { - text-align: center; - width: $fa-fw-width; -} diff --git a/public/vendor/fontawesome/scss/_functions.scss b/public/vendor/fontawesome/scss/_functions.scss deleted file mode 100644 index a17ffe87cc..0000000000 --- a/public/vendor/fontawesome/scss/_functions.scss +++ /dev/null @@ -1,57 +0,0 @@ -// functions -// -------------------------- - -// fa-content: convenience function used to set content property -@function fa-content($fa-var) { - @return unquote("\"#{ $fa-var }\""); -} - -// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap -// -// Licensed under: The MIT License (MIT) -// -// Copyright (c) 2011-2021 Twitter, Inc. -// Copyright (c) 2011-2021 The Bootstrap Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -@function fa-divide($dividend, $divisor, $precision: 10) { - $sign: if($dividend > 0 and $divisor > 0, 1, -1); - $dividend: abs($dividend); - $divisor: abs($divisor); - $quotient: 0; - $remainder: $dividend; - @if $dividend == 0 { - @return 0; - } - @if $divisor == 0 { - @error "Cannot divide by 0"; - } - @if $divisor == 1 { - @return $dividend; - } - @while $remainder >= $divisor { - $quotient: $quotient + 1; - $remainder: $remainder - $divisor; - } - @if $remainder > 0 and $precision > 0 { - $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1; - } - @return ($quotient + $remainder) * $sign; -} diff --git a/public/vendor/fontawesome/scss/_icons.scss b/public/vendor/fontawesome/scss/_icons.scss deleted file mode 100644 index 9e57e39cb3..0000000000 --- a/public/vendor/fontawesome/scss/_icons.scss +++ /dev/null @@ -1,9 +0,0 @@ -// specific icon class definition -// ------------------------- - -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen -readers do not read off random characters that represent icons */ - -@each $name, $icon in $fa-icons { - .#{$fa-css-prefix}-#{$name}::before { content: unquote("\"#{ $icon }\""); } -} diff --git a/public/vendor/fontawesome/scss/_larger.scss b/public/vendor/fontawesome/scss/_larger.scss deleted file mode 100644 index e88f4e54d0..0000000000 --- a/public/vendor/fontawesome/scss/_larger.scss +++ /dev/null @@ -1,24 +0,0 @@ -// Icon Sizes -// ------------------------- -@use "sass:math"; - -// makes the font 33% larger relative to the icon container -.#{$fa-css-prefix}-lg { - font-size: math.div(4em, 3); - line-height: math.div(3em, 4); - vertical-align: -.0667em; -} - -.#{$fa-css-prefix}-xs { - font-size: .75em; -} - -.#{$fa-css-prefix}-sm { - font-size: .875em; -} - -@for $i from 1 through 10 { - .#{$fa-css-prefix}-#{$i}x { - font-size: $i * 1em; - } -} diff --git a/public/vendor/fontawesome/scss/_list.scss b/public/vendor/fontawesome/scss/_list.scss deleted file mode 100644 index ced36e20a2..0000000000 --- a/public/vendor/fontawesome/scss/_list.scss +++ /dev/null @@ -1,18 +0,0 @@ -// icons in a list -// ------------------------- - -.#{$fa-css-prefix}-ul { - list-style-type: none; - margin-left: var(--#{$fa-css-prefix}-li-margin, #{$fa-li-margin}); - padding-left: 0; - - > li { position: relative; } -} - -.#{$fa-css-prefix}-li { - left: calc(var(--#{$fa-css-prefix}-li-width, #{$fa-li-width}) * -1); - position: absolute; - text-align: center; - width: var(--#{$fa-css-prefix}-li-width, #{$fa-li-width}); - line-height: inherit; -} diff --git a/public/vendor/fontawesome/scss/_mixins.scss b/public/vendor/fontawesome/scss/_mixins.scss deleted file mode 100644 index e06b69aa54..0000000000 --- a/public/vendor/fontawesome/scss/_mixins.scss +++ /dev/null @@ -1,75 +0,0 @@ -// mixins -// -------------------------- - -// base rendering for an icon -@mixin fa-icon { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - display: inline-block; - font-style: normal; - font-variant: normal; - font-weight: normal; - line-height: 1; -} - -// sets relative font-sizing and alignment (in _sizing) -@mixin fa-size ($font-size) { - font-size: fa-divide($font-size, $fa-size-scale-base) * 1em; // converts step in sizing scale into an em-based value that's relative to the scale's base - line-height: fa-divide(1, $font-size) * 1em; // sets the line-height of the icon back to that of it's parent - vertical-align: (fa-divide(6, $font-size) - fa-divide(3, 8)) * 1em; // vertically centers the icon taking into account the surrounding text's descender -} - -// only display content to screen readers -// see: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ -// see: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/ -@mixin fa-sr-only() { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} - -// use in conjunction with .sr-only to only display content when it's focused -@mixin fa-sr-only-focusable() { - &:not(:focus) { - @include fa-sr-only(); - } -} - -// sets a specific icon family to use alongside style + icon mixins - -// convenience mixins for declaring pseudo-elements by CSS variable, -// including all style-specific font properties, and both the ::before -// and ::after elements in the duotone case. -@mixin fa-icon-solid($fa-var) { - @extend %fa-icon; - @extend .fa-solid; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - -@mixin fa-icon-regular($fa-var) { - @extend %fa-icon; - @extend .fa-regular; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - -@mixin fa-icon-brands($fa-var) { - @extend %fa-icon; - @extend .fa-brands; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - diff --git a/public/vendor/fontawesome/scss/_rotated-flipped.scss b/public/vendor/fontawesome/scss/_rotated-flipped.scss deleted file mode 100644 index f27fabee40..0000000000 --- a/public/vendor/fontawesome/scss/_rotated-flipped.scss +++ /dev/null @@ -1,31 +0,0 @@ -// rotating + flipping icons -// ------------------------- - -.#{$fa-css-prefix}-rotate-90 { - transform: rotate(90deg); -} - -.#{$fa-css-prefix}-rotate-180 { - transform: rotate(180deg); -} - -.#{$fa-css-prefix}-rotate-270 { - transform: rotate(270deg); -} - -.#{$fa-css-prefix}-flip-horizontal { - transform: scale(-1, 1); -} - -.#{$fa-css-prefix}-flip-vertical { - transform: scale(1, -1); -} - -.#{$fa-css-prefix}-flip-both, -.#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical { - transform: scale(-1, -1); -} - -.#{$fa-css-prefix}-rotate-by { - transform: rotate(var(--#{$fa-css-prefix}-rotate-angle, none)); -} diff --git a/public/vendor/fontawesome/scss/_screen-reader.scss b/public/vendor/fontawesome/scss/_screen-reader.scss deleted file mode 100644 index 2beb887b49..0000000000 --- a/public/vendor/fontawesome/scss/_screen-reader.scss +++ /dev/null @@ -1,14 +0,0 @@ -// screen-reader utilities -// ------------------------- - -// only display content to screen readers -.sr-only, -.#{$fa-css-prefix}-sr-only { - @include fa-sr-only; -} - -// use in conjunction with .sr-only to only display content when it's focused -.sr-only-focusable, -.#{$fa-css-prefix}-sr-only-focusable { - @include fa-sr-only-focusable; -} diff --git a/public/vendor/fontawesome/scss/_shims.scss b/public/vendor/fontawesome/scss/_shims.scss deleted file mode 100644 index 7809aa6490..0000000000 --- a/public/vendor/fontawesome/scss/_shims.scss +++ /dev/null @@ -1,2042 +0,0 @@ -.#{$fa-css-prefix}.#{$fa-css-prefix}-glass:before { content: unquote("\"#{ $fa-var-martini-glass-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o:before { content: unquote("\"#{ $fa-var-envelope }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o:before { content: unquote("\"#{ $fa-var-star }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-remove:before { content: unquote("\"#{ $fa-var-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-close:before { content: unquote("\"#{ $fa-var-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gear:before { content: unquote("\"#{ $fa-var-gear }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o:before { content: unquote("\"#{ $fa-var-trash-can }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-home:before { content: unquote("\"#{ $fa-var-house }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o:before { content: unquote("\"#{ $fa-var-file }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o:before { content: unquote("\"#{ $fa-var-clock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down:before { content: unquote("\"#{ $fa-var-circle-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up:before { content: unquote("\"#{ $fa-var-circle-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o:before { content: unquote("\"#{ $fa-var-circle-play }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-repeat:before { content: unquote("\"#{ $fa-var-arrow-rotate-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-right:before { content: unquote("\"#{ $fa-var-arrow-rotate-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-refresh:before { content: unquote("\"#{ $fa-var-arrows-rotate }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt:before { content: unquote("\"#{ $fa-var-rectangle-list }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dedent:before { content: unquote("\"#{ $fa-var-outdent }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-video-camera:before { content: unquote("\"#{ $fa-var-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-photo { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-photo:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-image { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-image:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-marker:before { content: unquote("\"#{ $fa-var-location-dot }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o:before { content: unquote("\"#{ $fa-var-pen-to-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-edit { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-edit:before { content: unquote("\"#{ $fa-var-pen-to-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-share-square-o:before { content: unquote("\"#{ $fa-var-share-from-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o:before { content: unquote("\"#{ $fa-var-square-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows:before { content: unquote("\"#{ $fa-var-up-down-left-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o:before { content: unquote("\"#{ $fa-var-circle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o:before { content: unquote("\"#{ $fa-var-circle-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-forward:before { content: unquote("\"#{ $fa-var-share }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-expand:before { content: unquote("\"#{ $fa-var-up-right-and-down-left-from-center }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-compress:before { content: unquote("\"#{ $fa-var-down-left-and-up-right-to-center }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eye { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eye-slash { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-warning:before { content: unquote("\"#{ $fa-var-triangle-exclamation }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar:before { content: unquote("\"#{ $fa-var-calendar-days }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-v:before { content: unquote("\"#{ $fa-var-up-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-h:before { content: unquote("\"#{ $fa-var-left-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart:before { content: unquote("\"#{ $fa-var-chart-column }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart-o:before { content: unquote("\"#{ $fa-var-chart-column }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square:before { content: unquote("\"#{ $fa-var-square-twitter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square:before { content: unquote("\"#{ $fa-var-square-facebook }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gears:before { content: unquote("\"#{ $fa-var-gears }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up:before { content: unquote("\"#{ $fa-var-thumbs-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down:before { content: unquote("\"#{ $fa-var-thumbs-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o:before { content: unquote("\"#{ $fa-var-heart }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-out:before { content: unquote("\"#{ $fa-var-right-from-bracket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square:before { content: unquote("\"#{ $fa-var-linkedin }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumb-tack:before { content: unquote("\"#{ $fa-var-thumbtack }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link:before { content: unquote("\"#{ $fa-var-up-right-from-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-in:before { content: unquote("\"#{ $fa-var-right-to-bracket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square:before { content: unquote("\"#{ $fa-var-square-github }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o:before { content: unquote("\"#{ $fa-var-lemon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o:before { content: unquote("\"#{ $fa-var-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o:before { content: unquote("\"#{ $fa-var-bookmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook:before { content: unquote("\"#{ $fa-var-facebook-f }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f:before { content: unquote("\"#{ $fa-var-facebook-f }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-feed:before { content: unquote("\"#{ $fa-var-rss }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o:before { content: unquote("\"#{ $fa-var-hard-drive }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right:before { content: unquote("\"#{ $fa-var-hand-point-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left:before { content: unquote("\"#{ $fa-var-hand-point-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up:before { content: unquote("\"#{ $fa-var-hand-point-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down:before { content: unquote("\"#{ $fa-var-hand-point-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-globe:before { content: unquote("\"#{ $fa-var-earth-americas }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tasks:before { content: unquote("\"#{ $fa-var-bars-progress }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-alt:before { content: unquote("\"#{ $fa-var-maximize }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-group:before { content: unquote("\"#{ $fa-var-users }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chain:before { content: unquote("\"#{ $fa-var-link }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cut:before { content: unquote("\"#{ $fa-var-scissors }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o:before { content: unquote("\"#{ $fa-var-copy }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o:before { content: unquote("\"#{ $fa-var-floppy-disk }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-save { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-save:before { content: unquote("\"#{ $fa-var-floppy-disk }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-navicon:before { content: unquote("\"#{ $fa-var-bars }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reorder:before { content: unquote("\"#{ $fa-var-bars }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-magic:before { content: unquote("\"#{ $fa-var-wand-magic-sparkles }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square:before { content: unquote("\"#{ $fa-var-square-pinterest }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square:before { content: unquote("\"#{ $fa-var-square-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus:before { content: unquote("\"#{ $fa-var-google-plus-g }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-money:before { content: unquote("\"#{ $fa-var-money-bill-1 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unsorted:before { content: unquote("\"#{ $fa-var-sort }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-desc:before { content: unquote("\"#{ $fa-var-sort-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-asc:before { content: unquote("\"#{ $fa-var-sort-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin:before { content: unquote("\"#{ $fa-var-linkedin-in }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-left:before { content: unquote("\"#{ $fa-var-arrow-rotate-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-legal:before { content: unquote("\"#{ $fa-var-gavel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tachometer:before { content: unquote("\"#{ $fa-var-gauge-high }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dashboard:before { content: unquote("\"#{ $fa-var-gauge-high }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o:before { content: unquote("\"#{ $fa-var-comment }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o:before { content: unquote("\"#{ $fa-var-comments }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flash:before { content: unquote("\"#{ $fa-var-bolt }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clipboard:before { content: unquote("\"#{ $fa-var-paste }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o:before { content: unquote("\"#{ $fa-var-lightbulb }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-exchange:before { content: unquote("\"#{ $fa-var-right-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-download:before { content: unquote("\"#{ $fa-var-cloud-arrow-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-upload:before { content: unquote("\"#{ $fa-var-cloud-arrow-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o:before { content: unquote("\"#{ $fa-var-bell }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cutlery:before { content: unquote("\"#{ $fa-var-utensils }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o:before { content: unquote("\"#{ $fa-var-file-lines }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o:before { content: unquote("\"#{ $fa-var-building }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o:before { content: unquote("\"#{ $fa-var-hospital }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tablet:before { content: unquote("\"#{ $fa-var-tablet-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile:before { content: unquote("\"#{ $fa-var-mobile-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile-phone:before { content: unquote("\"#{ $fa-var-mobile-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o:before { content: unquote("\"#{ $fa-var-circle }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply:before { content: unquote("\"#{ $fa-var-reply }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o:before { content: unquote("\"#{ $fa-var-folder }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o:before { content: unquote("\"#{ $fa-var-folder-open }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o:before { content: unquote("\"#{ $fa-var-face-smile }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o:before { content: unquote("\"#{ $fa-var-face-frown }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o:before { content: unquote("\"#{ $fa-var-face-meh }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o:before { content: unquote("\"#{ $fa-var-keyboard }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o:before { content: unquote("\"#{ $fa-var-flag }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply-all:before { content: unquote("\"#{ $fa-var-reply-all }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-code-fork:before { content: unquote("\"#{ $fa-var-code-branch }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chain-broken:before { content: unquote("\"#{ $fa-var-link-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unlink:before { content: unquote("\"#{ $fa-var-link-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o:before { content: unquote("\"#{ $fa-var-calendar }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-maxcdn { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-html5 { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-css3 { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unlock-alt:before { content: unquote("\"#{ $fa-var-unlock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o:before { content: unquote("\"#{ $fa-var-square-minus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-level-up:before { content: unquote("\"#{ $fa-var-turn-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-level-down:before { content: unquote("\"#{ $fa-var-turn-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square:before { content: unquote("\"#{ $fa-var-square-pen }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link-square:before { content: unquote("\"#{ $fa-var-square-up-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-compass { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down:before { content: unquote("\"#{ $fa-var-square-caret-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down:before { content: unquote("\"#{ $fa-var-square-caret-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up:before { content: unquote("\"#{ $fa-var-square-caret-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up:before { content: unquote("\"#{ $fa-var-square-caret-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right:before { content: unquote("\"#{ $fa-var-square-caret-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right:before { content: unquote("\"#{ $fa-var-square-caret-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eur:before { content: unquote("\"#{ $fa-var-euro-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-euro:before { content: unquote("\"#{ $fa-var-euro-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gbp:before { content: unquote("\"#{ $fa-var-sterling-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-usd:before { content: unquote("\"#{ $fa-var-dollar-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dollar:before { content: unquote("\"#{ $fa-var-dollar-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-inr:before { content: unquote("\"#{ $fa-var-indian-rupee-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rupee:before { content: unquote("\"#{ $fa-var-indian-rupee-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-jpy:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cny:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rmb:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yen:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rub:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ruble:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rouble:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-krw:before { content: unquote("\"#{ $fa-var-won-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-won:before { content: unquote("\"#{ $fa-var-won-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-btc { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin:before { content: unquote("\"#{ $fa-var-btc }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text:before { content: unquote("\"#{ $fa-var-file-lines }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-asc:before { content: unquote("\"#{ $fa-var-arrow-down-a-z }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-desc:before { content: unquote("\"#{ $fa-var-arrow-down-z-a }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-asc:before { content: unquote("\"#{ $fa-var-arrow-down-short-wide }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-desc:before { content: unquote("\"#{ $fa-var-arrow-down-wide-short }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-asc:before { content: unquote("\"#{ $fa-var-arrow-down-1-9 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-desc:before { content: unquote("\"#{ $fa-var-arrow-down-9-1 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square:before { content: unquote("\"#{ $fa-var-square-youtube }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square:before { content: unquote("\"#{ $fa-var-square-xing }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play:before { content: unquote("\"#{ $fa-var-youtube }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dropbox { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-overflow { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-instagram { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flickr { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-adn { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square:before { content: unquote("\"#{ $fa-var-bitbucket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square:before { content: unquote("\"#{ $fa-var-square-tumblr }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-down:before { content: unquote("\"#{ $fa-var-down-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-up:before { content: unquote("\"#{ $fa-var-up-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-left:before { content: unquote("\"#{ $fa-var-left-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-right:before { content: unquote("\"#{ $fa-var-right-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-apple { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-windows { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-android { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linux { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dribbble { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-skype { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-foursquare { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trello { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gratipay { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip:before { content: unquote("\"#{ $fa-var-gratipay }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o:before { content: unquote("\"#{ $fa-var-sun }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o:before { content: unquote("\"#{ $fa-var-moon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vk { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-weibo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-renren { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pagelines { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-exchange { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right:before { content: unquote("\"#{ $fa-var-circle-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left:before { content: unquote("\"#{ $fa-var-circle-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left:before { content: unquote("\"#{ $fa-var-square-caret-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left:before { content: unquote("\"#{ $fa-var-square-caret-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o:before { content: unquote("\"#{ $fa-var-circle-dot }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square:before { content: unquote("\"#{ $fa-var-square-vimeo }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-try:before { content: unquote("\"#{ $fa-var-turkish-lira-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-turkish-lira:before { content: unquote("\"#{ $fa-var-turkish-lira-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o:before { content: unquote("\"#{ $fa-var-square-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-slack { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wordpress { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-openid { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-institution:before { content: unquote("\"#{ $fa-var-building-columns }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bank:before { content: unquote("\"#{ $fa-var-building-columns }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mortar-board:before { content: unquote("\"#{ $fa-var-graduation-cap }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yahoo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square:before { content: unquote("\"#{ $fa-var-square-reddit }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-delicious { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-digg { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-pp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drupal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-joomla { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square:before { content: unquote("\"#{ $fa-var-square-behance }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square:before { content: unquote("\"#{ $fa-var-square-steam }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-automobile:before { content: unquote("\"#{ $fa-var-car }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cab:before { content: unquote("\"#{ $fa-var-taxi }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-spotify { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-deviantart { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-soundcloud { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o:before { content: unquote("\"#{ $fa-var-file-pdf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o:before { content: unquote("\"#{ $fa-var-file-word }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o:before { content: unquote("\"#{ $fa-var-file-excel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o:before { content: unquote("\"#{ $fa-var-file-powerpoint }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o:before { content: unquote("\"#{ $fa-var-file-zipper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o:before { content: unquote("\"#{ $fa-var-file-zipper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o:before { content: unquote("\"#{ $fa-var-file-audio }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o:before { content: unquote("\"#{ $fa-var-file-audio }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o:before { content: unquote("\"#{ $fa-var-file-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o:before { content: unquote("\"#{ $fa-var-file-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o:before { content: unquote("\"#{ $fa-var-file-code }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vine { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-codepen { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-jsfiddle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-bouy:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-buoy:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-saver:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-support:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o-notch:before { content: unquote("\"#{ $fa-var-circle-notch }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rebel { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ra { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-ra:before { content: unquote("\"#{ $fa-var-rebel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance:before { content: unquote("\"#{ $fa-var-rebel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-empire { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ge { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-ge:before { content: unquote("\"#{ $fa-var-empire }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square:before { content: unquote("\"#{ $fa-var-square-git }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-git { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hacker-news { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square:before { content: unquote("\"#{ $fa-var-hacker-news }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square:before { content: unquote("\"#{ $fa-var-hacker-news }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tencent-weibo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-qq { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-weixin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat:before { content: unquote("\"#{ $fa-var-weixin }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-send:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin:before { content: unquote("\"#{ $fa-var-circle }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-header:before { content: unquote("\"#{ $fa-var-heading }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o:before { content: unquote("\"#{ $fa-var-futbol }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o:before { content: unquote("\"#{ $fa-var-futbol }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-slideshare { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitch { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yelp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o:before { content: unquote("\"#{ $fa-var-newspaper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-paypal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-wallet { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-visa { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-mastercard { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-discover { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-amex { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-paypal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-stripe { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o:before { content: unquote("\"#{ $fa-var-bell-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash:before { content: unquote("\"#{ $fa-var-trash-can }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-copyright { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eyedropper:before { content: unquote("\"#{ $fa-var-eye-dropper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-area-chart:before { content: unquote("\"#{ $fa-var-chart-area }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pie-chart:before { content: unquote("\"#{ $fa-var-chart-pie }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-line-chart:before { content: unquote("\"#{ $fa-var-chart-line }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square:before { content: unquote("\"#{ $fa-var-square-lastfm }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ioxhost { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-angellist { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc:before { content: unquote("\"#{ $fa-var-closed-captioning }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ils:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-shekel:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sheqel:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-buysellads { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-connectdevelop { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dashcube { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-forumbee { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-leanpub { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sellsy { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-shirtsinbulk { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-simplybuilt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-skyatlas { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond:before { content: unquote("\"#{ $fa-var-gem }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender:before { content: unquote("\"#{ $fa-var-mars-and-venus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-intersex:before { content: unquote("\"#{ $fa-var-mars-and-venus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender-alt:before { content: unquote("\"#{ $fa-var-transgender }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official:before { content: unquote("\"#{ $fa-var-facebook }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-p { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-whatsapp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hotel:before { content: unquote("\"#{ $fa-var-bed }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viacoin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-medium { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc:before { content: unquote("\"#{ $fa-var-y-combinator }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-optin-monster { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-opencart { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-expeditedssl { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-4:before { content: unquote("\"#{ $fa-var-battery-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery:before { content: unquote("\"#{ $fa-var-battery-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-3:before { content: unquote("\"#{ $fa-var-battery-three-quarters }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-2:before { content: unquote("\"#{ $fa-var-battery-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-1:before { content: unquote("\"#{ $fa-var-battery-quarter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-0:before { content: unquote("\"#{ $fa-var-battery-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-object-group { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-object-ungroup { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o:before { content: unquote("\"#{ $fa-var-note-sticky }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-jcb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-diners-club { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clone { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-o:before { content: unquote("\"#{ $fa-var-hourglass }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-1:before { content: unquote("\"#{ $fa-var-hourglass-start }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-2:before { content: unquote("\"#{ $fa-var-hourglass-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-3:before { content: unquote("\"#{ $fa-var-hourglass-end }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o:before { content: unquote("\"#{ $fa-var-hand-back-fist }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o:before { content: unquote("\"#{ $fa-var-hand-back-fist }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o:before { content: unquote("\"#{ $fa-var-hand }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o:before { content: unquote("\"#{ $fa-var-hand }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o:before { content: unquote("\"#{ $fa-var-hand-scissors }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o:before { content: unquote("\"#{ $fa-var-hand-lizard }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o:before { content: unquote("\"#{ $fa-var-hand-spock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o:before { content: unquote("\"#{ $fa-var-hand-pointer }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o:before { content: unquote("\"#{ $fa-var-hand-peace }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-registered { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-creative-commons { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gg { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gg-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square:before { content: unquote("\"#{ $fa-var-square-odnoklassniki }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-get-pocket { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wikipedia-w { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-safari { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chrome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-firefox { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-opera { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-internet-explorer { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-television:before { content: unquote("\"#{ $fa-var-tv }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-contao { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-500px { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-amazon { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o:before { content: unquote("\"#{ $fa-var-calendar-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o:before { content: unquote("\"#{ $fa-var-calendar-minus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o:before { content: unquote("\"#{ $fa-var-calendar-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o:before { content: unquote("\"#{ $fa-var-calendar-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o:before { content: unquote("\"#{ $fa-var-map }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting:before { content: unquote("\"#{ $fa-var-comment-dots }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o:before { content: unquote("\"#{ $fa-var-comment-dots }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-houzz { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo:before { content: unquote("\"#{ $fa-var-vimeo-v }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-black-tie { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fonticons { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-alien { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-edge { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card-alt:before { content: unquote("\"#{ $fa-var-credit-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-codiepie { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-modx { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fort-awesome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-usb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-product-hunt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mixcloud { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-scribd { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o:before { content: unquote("\"#{ $fa-var-circle-pause }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o:before { content: unquote("\"#{ $fa-var-circle-stop }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth-b { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gitlab { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpbeginner { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpforms { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envira { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt:before { content: unquote("\"#{ $fa-var-accessible-icon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o:before { content: unquote("\"#{ $fa-var-circle-question }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-volume-control-phone:before { content: unquote("\"#{ $fa-var-phone-volume }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-asl-interpreting:before { content: unquote("\"#{ $fa-var-hands-asl-interpreting }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-deafness:before { content: unquote("\"#{ $fa-var-ear-deaf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hard-of-hearing:before { content: unquote("\"#{ $fa-var-ear-deaf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-glide { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-glide-g { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-signing:before { content: unquote("\"#{ $fa-var-hands }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square:before { content: unquote("\"#{ $fa-var-square-viadeo }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost:before { content: unquote("\"#{ $fa-var-snapchat }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square:before { content: unquote("\"#{ $fa-var-square-snapchat }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-first-order { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yoast { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-themeisle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official:before { content: unquote("\"#{ $fa-var-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle:before { content: unquote("\"#{ $fa-var-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-font-awesome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fa { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-fa:before { content: unquote("\"#{ $fa-var-font-awesome }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o:before { content: unquote("\"#{ $fa-var-handshake }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o:before { content: unquote("\"#{ $fa-var-envelope-open }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linode { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o:before { content: unquote("\"#{ $fa-var-address-book }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o:before { content: unquote("\"#{ $fa-var-circle-user }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o:before { content: unquote("\"#{ $fa-var-user }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-badge { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-quora { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-free-code-camp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-telegram { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-4:before { content: unquote("\"#{ $fa-var-temperature-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer:before { content: unquote("\"#{ $fa-var-temperature-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-3:before { content: unquote("\"#{ $fa-var-temperature-three-quarters }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-2:before { content: unquote("\"#{ $fa-var-temperature-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-1:before { content: unquote("\"#{ $fa-var-temperature-quarter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-0:before { content: unquote("\"#{ $fa-var-temperature-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bathtub:before { content: unquote("\"#{ $fa-var-bath }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-s15:before { content: unquote("\"#{ $fa-var-bath }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-maximize { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-restore { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bandcamp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-grav { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-etsy { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-imdb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ravelry { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast:before { content: unquote("\"#{ $fa-var-sellcast }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o:before { content: unquote("\"#{ $fa-var-snowflake }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-superpowers { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpexplorer { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-meetup { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - diff --git a/public/vendor/fontawesome/scss/_sizing.scss b/public/vendor/fontawesome/scss/_sizing.scss deleted file mode 100644 index e171e7df4c..0000000000 --- a/public/vendor/fontawesome/scss/_sizing.scss +++ /dev/null @@ -1,16 +0,0 @@ -// sizing icons -// ------------------------- - -// literal magnification scale -@for $i from 1 through 10 { - .#{$fa-css-prefix}-#{$i}x { - font-size: $i * 1em; - } -} - -// step-based scale (with alignment) -@each $size, $value in $fa-sizes { - .#{$fa-css-prefix}-#{$size} { - @include fa-size($value); - } -} diff --git a/public/vendor/fontawesome/scss/_stacked.scss b/public/vendor/fontawesome/scss/_stacked.scss deleted file mode 100644 index d9a9d4e98f..0000000000 --- a/public/vendor/fontawesome/scss/_stacked.scss +++ /dev/null @@ -1,32 +0,0 @@ -// stacking icons -// ------------------------- - -.#{$fa-css-prefix}-stack { - display: inline-block; - height: 2em; - line-height: 2em; - position: relative; - vertical-align: $fa-stack-vertical-align; - width: $fa-stack-width; -} - -.#{$fa-css-prefix}-stack-1x, -.#{$fa-css-prefix}-stack-2x { - left: 0; - position: absolute; - text-align: center; - width: 100%; - z-index: var(--#{$fa-css-prefix}-stack-z-index, #{$fa-stack-z-index}); -} - -.#{$fa-css-prefix}-stack-1x { - line-height: inherit; -} - -.#{$fa-css-prefix}-stack-2x { - font-size: 2em; -} - -.#{$fa-css-prefix}-inverse { - color: var(--#{$fa-css-prefix}-inverse, #{$fa-inverse}); -} diff --git a/public/vendor/fontawesome/scss/_variables.scss b/public/vendor/fontawesome/scss/_variables.scss deleted file mode 100644 index e3a920deab..0000000000 --- a/public/vendor/fontawesome/scss/_variables.scss +++ /dev/null @@ -1,4951 +0,0 @@ -// variables -// -------------------------- - -$fa-css-prefix : fa !default; -$fa-style : 900 !default; -$fa-style-family : "Font Awesome 6 Free" !default; - -$fa-display : inline-block !default; - -$fa-fw-width : fa-divide(20em, 16) !default; -$fa-inverse : #fff !default; - -$fa-border-color : #eee !default; -$fa-border-padding : .2em .25em .15em !default; -$fa-border-radius : .1em !default; -$fa-border-style : solid !default; -$fa-border-width : .08em !default; - -$fa-size-scale-2xs : 10 !default; -$fa-size-scale-xs : 12 !default; -$fa-size-scale-sm : 14 !default; -$fa-size-scale-base : 16 !default; -$fa-size-scale-lg : 20 !default; -$fa-size-scale-xl : 24 !default; -$fa-size-scale-2xl : 32 !default; - -$fa-sizes: ( - "2xs" : $fa-size-scale-2xs, - "xs" : $fa-size-scale-xs, - "sm" : $fa-size-scale-sm, - "lg" : $fa-size-scale-lg, - "xl" : $fa-size-scale-xl, - "2xl" : $fa-size-scale-2xl -) !default; - -$fa-li-width : 2em !default; -$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default; - -$fa-pull-margin : .3em !default; - -$fa-primary-opacity : 1 !default; -$fa-secondary-opacity : .4 !default; - -$fa-stack-vertical-align: middle !default; -$fa-stack-width : ($fa-fw-width * 2) !default; -$fa-stack-z-index : auto !default; - -$fa-font-display : block !default; -$fa-font-path : "../webfonts" !default; - -$fa-var-0: \30; -$fa-var-1: \31; -$fa-var-2: \32; -$fa-var-3: \33; -$fa-var-4: \34; -$fa-var-5: \35; -$fa-var-6: \36; -$fa-var-7: \37; -$fa-var-8: \38; -$fa-var-9: \39; -$fa-var-fill-drip: \f576; -$fa-var-arrows-to-circle: \e4bd; -$fa-var-circle-chevron-right: \f138; -$fa-var-chevron-circle-right: \f138; -$fa-var-at: \40; -$fa-var-trash-can: \f2ed; -$fa-var-trash-alt: \f2ed; -$fa-var-text-height: \f034; -$fa-var-user-xmark: \f235; -$fa-var-user-times: \f235; -$fa-var-stethoscope: \f0f1; -$fa-var-message: \f27a; -$fa-var-comment-alt: \f27a; -$fa-var-info: \f129; -$fa-var-down-left-and-up-right-to-center: \f422; -$fa-var-compress-alt: \f422; -$fa-var-explosion: \e4e9; -$fa-var-file-lines: \f15c; -$fa-var-file-alt: \f15c; -$fa-var-file-text: \f15c; -$fa-var-wave-square: \f83e; -$fa-var-ring: \f70b; -$fa-var-building-un: \e4d9; -$fa-var-dice-three: \f527; -$fa-var-calendar-days: \f073; -$fa-var-calendar-alt: \f073; -$fa-var-anchor-circle-check: \e4aa; -$fa-var-building-circle-arrow-right: \e4d1; -$fa-var-volleyball: \f45f; -$fa-var-volleyball-ball: \f45f; -$fa-var-arrows-up-to-line: \e4c2; -$fa-var-sort-down: \f0dd; -$fa-var-sort-desc: \f0dd; -$fa-var-circle-minus: \f056; -$fa-var-minus-circle: \f056; -$fa-var-door-open: \f52b; -$fa-var-right-from-bracket: \f2f5; -$fa-var-sign-out-alt: \f2f5; -$fa-var-atom: \f5d2; -$fa-var-soap: \e06e; -$fa-var-icons: \f86d; -$fa-var-heart-music-camera-bolt: \f86d; -$fa-var-microphone-lines-slash: \f539; -$fa-var-microphone-alt-slash: \f539; -$fa-var-bridge-circle-check: \e4c9; -$fa-var-pump-medical: \e06a; -$fa-var-fingerprint: \f577; -$fa-var-hand-point-right: \f0a4; -$fa-var-magnifying-glass-location: \f689; -$fa-var-search-location: \f689; -$fa-var-forward-step: \f051; -$fa-var-step-forward: \f051; -$fa-var-face-smile-beam: \f5b8; -$fa-var-smile-beam: \f5b8; -$fa-var-flag-checkered: \f11e; -$fa-var-football: \f44e; -$fa-var-football-ball: \f44e; -$fa-var-school-circle-exclamation: \e56c; -$fa-var-crop: \f125; -$fa-var-angles-down: \f103; -$fa-var-angle-double-down: \f103; -$fa-var-users-rectangle: \e594; -$fa-var-people-roof: \e537; -$fa-var-people-line: \e534; -$fa-var-beer-mug-empty: \f0fc; -$fa-var-beer: \f0fc; -$fa-var-diagram-predecessor: \e477; -$fa-var-arrow-up-long: \f176; -$fa-var-long-arrow-up: \f176; -$fa-var-fire-flame-simple: \f46a; -$fa-var-burn: \f46a; -$fa-var-person: \f183; -$fa-var-male: \f183; -$fa-var-laptop: \f109; -$fa-var-file-csv: \f6dd; -$fa-var-menorah: \f676; -$fa-var-truck-plane: \e58f; -$fa-var-record-vinyl: \f8d9; -$fa-var-face-grin-stars: \f587; -$fa-var-grin-stars: \f587; -$fa-var-bong: \f55c; -$fa-var-spaghetti-monster-flying: \f67b; -$fa-var-pastafarianism: \f67b; -$fa-var-arrow-down-up-across-line: \e4af; -$fa-var-spoon: \f2e5; -$fa-var-utensil-spoon: \f2e5; -$fa-var-jar-wheat: \e517; -$fa-var-envelopes-bulk: \f674; -$fa-var-mail-bulk: \f674; -$fa-var-file-circle-exclamation: \e4eb; -$fa-var-circle-h: \f47e; -$fa-var-hospital-symbol: \f47e; -$fa-var-pager: \f815; -$fa-var-address-book: \f2b9; -$fa-var-contact-book: \f2b9; -$fa-var-strikethrough: \f0cc; -$fa-var-k: \4b; -$fa-var-landmark-flag: \e51c; -$fa-var-pencil: \f303; -$fa-var-pencil-alt: \f303; -$fa-var-backward: \f04a; -$fa-var-caret-right: \f0da; -$fa-var-comments: \f086; -$fa-var-paste: \f0ea; -$fa-var-file-clipboard: \f0ea; -$fa-var-code-pull-request: \e13c; -$fa-var-clipboard-list: \f46d; -$fa-var-truck-ramp-box: \f4de; -$fa-var-truck-loading: \f4de; -$fa-var-user-check: \f4fc; -$fa-var-vial-virus: \e597; -$fa-var-sheet-plastic: \e571; -$fa-var-blog: \f781; -$fa-var-user-ninja: \f504; -$fa-var-person-arrow-up-from-line: \e539; -$fa-var-scroll-torah: \f6a0; -$fa-var-torah: \f6a0; -$fa-var-broom-ball: \f458; -$fa-var-quidditch: \f458; -$fa-var-quidditch-broom-ball: \f458; -$fa-var-toggle-off: \f204; -$fa-var-box-archive: \f187; -$fa-var-archive: \f187; -$fa-var-person-drowning: \e545; -$fa-var-arrow-down-9-1: \f886; -$fa-var-sort-numeric-desc: \f886; -$fa-var-sort-numeric-down-alt: \f886; -$fa-var-face-grin-tongue-squint: \f58a; -$fa-var-grin-tongue-squint: \f58a; -$fa-var-spray-can: \f5bd; -$fa-var-truck-monster: \f63b; -$fa-var-w: \57; -$fa-var-earth-africa: \f57c; -$fa-var-globe-africa: \f57c; -$fa-var-rainbow: \f75b; -$fa-var-circle-notch: \f1ce; -$fa-var-tablet-screen-button: \f3fa; -$fa-var-tablet-alt: \f3fa; -$fa-var-paw: \f1b0; -$fa-var-cloud: \f0c2; -$fa-var-trowel-bricks: \e58a; -$fa-var-face-flushed: \f579; -$fa-var-flushed: \f579; -$fa-var-hospital-user: \f80d; -$fa-var-tent-arrow-left-right: \e57f; -$fa-var-gavel: \f0e3; -$fa-var-legal: \f0e3; -$fa-var-binoculars: \f1e5; -$fa-var-microphone-slash: \f131; -$fa-var-box-tissue: \e05b; -$fa-var-motorcycle: \f21c; -$fa-var-bell-concierge: \f562; -$fa-var-concierge-bell: \f562; -$fa-var-pen-ruler: \f5ae; -$fa-var-pencil-ruler: \f5ae; -$fa-var-people-arrows: \e068; -$fa-var-people-arrows-left-right: \e068; -$fa-var-mars-and-venus-burst: \e523; -$fa-var-square-caret-right: \f152; -$fa-var-caret-square-right: \f152; -$fa-var-scissors: \f0c4; -$fa-var-cut: \f0c4; -$fa-var-sun-plant-wilt: \e57a; -$fa-var-toilets-portable: \e584; -$fa-var-hockey-puck: \f453; -$fa-var-table: \f0ce; -$fa-var-magnifying-glass-arrow-right: \e521; -$fa-var-tachograph-digital: \f566; -$fa-var-digital-tachograph: \f566; -$fa-var-users-slash: \e073; -$fa-var-clover: \e139; -$fa-var-reply: \f3e5; -$fa-var-mail-reply: \f3e5; -$fa-var-star-and-crescent: \f699; -$fa-var-house-fire: \e50c; -$fa-var-square-minus: \f146; -$fa-var-minus-square: \f146; -$fa-var-helicopter: \f533; -$fa-var-compass: \f14e; -$fa-var-square-caret-down: \f150; -$fa-var-caret-square-down: \f150; -$fa-var-file-circle-question: \e4ef; -$fa-var-laptop-code: \f5fc; -$fa-var-swatchbook: \f5c3; -$fa-var-prescription-bottle: \f485; -$fa-var-bars: \f0c9; -$fa-var-navicon: \f0c9; -$fa-var-people-group: \e533; -$fa-var-hourglass-end: \f253; -$fa-var-hourglass-3: \f253; -$fa-var-heart-crack: \f7a9; -$fa-var-heart-broken: \f7a9; -$fa-var-square-up-right: \f360; -$fa-var-external-link-square-alt: \f360; -$fa-var-face-kiss-beam: \f597; -$fa-var-kiss-beam: \f597; -$fa-var-film: \f008; -$fa-var-ruler-horizontal: \f547; -$fa-var-people-robbery: \e536; -$fa-var-lightbulb: \f0eb; -$fa-var-caret-left: \f0d9; -$fa-var-circle-exclamation: \f06a; -$fa-var-exclamation-circle: \f06a; -$fa-var-school-circle-xmark: \e56d; -$fa-var-arrow-right-from-bracket: \f08b; -$fa-var-sign-out: \f08b; -$fa-var-circle-chevron-down: \f13a; -$fa-var-chevron-circle-down: \f13a; -$fa-var-unlock-keyhole: \f13e; -$fa-var-unlock-alt: \f13e; -$fa-var-cloud-showers-heavy: \f740; -$fa-var-headphones-simple: \f58f; -$fa-var-headphones-alt: \f58f; -$fa-var-sitemap: \f0e8; -$fa-var-circle-dollar-to-slot: \f4b9; -$fa-var-donate: \f4b9; -$fa-var-memory: \f538; -$fa-var-road-spikes: \e568; -$fa-var-fire-burner: \e4f1; -$fa-var-flag: \f024; -$fa-var-hanukiah: \f6e6; -$fa-var-feather: \f52d; -$fa-var-volume-low: \f027; -$fa-var-volume-down: \f027; -$fa-var-comment-slash: \f4b3; -$fa-var-cloud-sun-rain: \f743; -$fa-var-compress: \f066; -$fa-var-wheat-awn: \e2cd; -$fa-var-wheat-alt: \e2cd; -$fa-var-ankh: \f644; -$fa-var-hands-holding-child: \e4fa; -$fa-var-asterisk: \2a; -$fa-var-square-check: \f14a; -$fa-var-check-square: \f14a; -$fa-var-peseta-sign: \e221; -$fa-var-heading: \f1dc; -$fa-var-header: \f1dc; -$fa-var-ghost: \f6e2; -$fa-var-list: \f03a; -$fa-var-list-squares: \f03a; -$fa-var-square-phone-flip: \f87b; -$fa-var-phone-square-alt: \f87b; -$fa-var-cart-plus: \f217; -$fa-var-gamepad: \f11b; -$fa-var-circle-dot: \f192; -$fa-var-dot-circle: \f192; -$fa-var-face-dizzy: \f567; -$fa-var-dizzy: \f567; -$fa-var-egg: \f7fb; -$fa-var-house-medical-circle-xmark: \e513; -$fa-var-campground: \f6bb; -$fa-var-folder-plus: \f65e; -$fa-var-futbol: \f1e3; -$fa-var-futbol-ball: \f1e3; -$fa-var-soccer-ball: \f1e3; -$fa-var-paintbrush: \f1fc; -$fa-var-paint-brush: \f1fc; -$fa-var-lock: \f023; -$fa-var-gas-pump: \f52f; -$fa-var-hot-tub-person: \f593; -$fa-var-hot-tub: \f593; -$fa-var-map-location: \f59f; -$fa-var-map-marked: \f59f; -$fa-var-house-flood-water: \e50e; -$fa-var-tree: \f1bb; -$fa-var-bridge-lock: \e4cc; -$fa-var-sack-dollar: \f81d; -$fa-var-pen-to-square: \f044; -$fa-var-edit: \f044; -$fa-var-car-side: \f5e4; -$fa-var-share-nodes: \f1e0; -$fa-var-share-alt: \f1e0; -$fa-var-heart-circle-minus: \e4ff; -$fa-var-hourglass-half: \f252; -$fa-var-hourglass-2: \f252; -$fa-var-microscope: \f610; -$fa-var-sink: \e06d; -$fa-var-bag-shopping: \f290; -$fa-var-shopping-bag: \f290; -$fa-var-arrow-down-z-a: \f881; -$fa-var-sort-alpha-desc: \f881; -$fa-var-sort-alpha-down-alt: \f881; -$fa-var-mitten: \f7b5; -$fa-var-person-rays: \e54d; -$fa-var-users: \f0c0; -$fa-var-eye-slash: \f070; -$fa-var-flask-vial: \e4f3; -$fa-var-hand: \f256; -$fa-var-hand-paper: \f256; -$fa-var-om: \f679; -$fa-var-worm: \e599; -$fa-var-house-circle-xmark: \e50b; -$fa-var-plug: \f1e6; -$fa-var-chevron-up: \f077; -$fa-var-hand-spock: \f259; -$fa-var-stopwatch: \f2f2; -$fa-var-face-kiss: \f596; -$fa-var-kiss: \f596; -$fa-var-bridge-circle-xmark: \e4cb; -$fa-var-face-grin-tongue: \f589; -$fa-var-grin-tongue: \f589; -$fa-var-chess-bishop: \f43a; -$fa-var-face-grin-wink: \f58c; -$fa-var-grin-wink: \f58c; -$fa-var-ear-deaf: \f2a4; -$fa-var-deaf: \f2a4; -$fa-var-deafness: \f2a4; -$fa-var-hard-of-hearing: \f2a4; -$fa-var-road-circle-check: \e564; -$fa-var-dice-five: \f523; -$fa-var-square-rss: \f143; -$fa-var-rss-square: \f143; -$fa-var-land-mine-on: \e51b; -$fa-var-i-cursor: \f246; -$fa-var-stamp: \f5bf; -$fa-var-stairs: \e289; -$fa-var-i: \49; -$fa-var-hryvnia-sign: \f6f2; -$fa-var-hryvnia: \f6f2; -$fa-var-pills: \f484; -$fa-var-face-grin-wide: \f581; -$fa-var-grin-alt: \f581; -$fa-var-tooth: \f5c9; -$fa-var-v: \56; -$fa-var-bicycle: \f206; -$fa-var-staff-snake: \e579; -$fa-var-rod-asclepius: \e579; -$fa-var-rod-snake: \e579; -$fa-var-staff-aesculapius: \e579; -$fa-var-head-side-cough-slash: \e062; -$fa-var-truck-medical: \f0f9; -$fa-var-ambulance: \f0f9; -$fa-var-wheat-awn-circle-exclamation: \e598; -$fa-var-snowman: \f7d0; -$fa-var-mortar-pestle: \f5a7; -$fa-var-road-barrier: \e562; -$fa-var-school: \f549; -$fa-var-igloo: \f7ae; -$fa-var-joint: \f595; -$fa-var-angle-right: \f105; -$fa-var-horse: \f6f0; -$fa-var-q: \51; -$fa-var-g: \47; -$fa-var-notes-medical: \f481; -$fa-var-temperature-half: \f2c9; -$fa-var-temperature-2: \f2c9; -$fa-var-thermometer-2: \f2c9; -$fa-var-thermometer-half: \f2c9; -$fa-var-dong-sign: \e169; -$fa-var-capsules: \f46b; -$fa-var-poo-storm: \f75a; -$fa-var-poo-bolt: \f75a; -$fa-var-face-frown-open: \f57a; -$fa-var-frown-open: \f57a; -$fa-var-hand-point-up: \f0a6; -$fa-var-money-bill: \f0d6; -$fa-var-bookmark: \f02e; -$fa-var-align-justify: \f039; -$fa-var-umbrella-beach: \f5ca; -$fa-var-helmet-un: \e503; -$fa-var-bullseye: \f140; -$fa-var-bacon: \f7e5; -$fa-var-hand-point-down: \f0a7; -$fa-var-arrow-up-from-bracket: \e09a; -$fa-var-folder: \f07b; -$fa-var-folder-blank: \f07b; -$fa-var-file-waveform: \f478; -$fa-var-file-medical-alt: \f478; -$fa-var-radiation: \f7b9; -$fa-var-chart-simple: \e473; -$fa-var-mars-stroke: \f229; -$fa-var-vial: \f492; -$fa-var-gauge: \f624; -$fa-var-dashboard: \f624; -$fa-var-gauge-med: \f624; -$fa-var-tachometer-alt-average: \f624; -$fa-var-wand-magic-sparkles: \e2ca; -$fa-var-magic-wand-sparkles: \e2ca; -$fa-var-e: \45; -$fa-var-pen-clip: \f305; -$fa-var-pen-alt: \f305; -$fa-var-bridge-circle-exclamation: \e4ca; -$fa-var-user: \f007; -$fa-var-school-circle-check: \e56b; -$fa-var-dumpster: \f793; -$fa-var-van-shuttle: \f5b6; -$fa-var-shuttle-van: \f5b6; -$fa-var-building-user: \e4da; -$fa-var-square-caret-left: \f191; -$fa-var-caret-square-left: \f191; -$fa-var-highlighter: \f591; -$fa-var-key: \f084; -$fa-var-bullhorn: \f0a1; -$fa-var-globe: \f0ac; -$fa-var-synagogue: \f69b; -$fa-var-person-half-dress: \e548; -$fa-var-road-bridge: \e563; -$fa-var-location-arrow: \f124; -$fa-var-c: \43; -$fa-var-tablet-button: \f10a; -$fa-var-building-lock: \e4d6; -$fa-var-pizza-slice: \f818; -$fa-var-money-bill-wave: \f53a; -$fa-var-chart-area: \f1fe; -$fa-var-area-chart: \f1fe; -$fa-var-house-flag: \e50d; -$fa-var-person-circle-minus: \e540; -$fa-var-ban: \f05e; -$fa-var-cancel: \f05e; -$fa-var-camera-rotate: \e0d8; -$fa-var-spray-can-sparkles: \f5d0; -$fa-var-air-freshener: \f5d0; -$fa-var-star: \f005; -$fa-var-repeat: \f363; -$fa-var-cross: \f654; -$fa-var-box: \f466; -$fa-var-venus-mars: \f228; -$fa-var-arrow-pointer: \f245; -$fa-var-mouse-pointer: \f245; -$fa-var-maximize: \f31e; -$fa-var-expand-arrows-alt: \f31e; -$fa-var-charging-station: \f5e7; -$fa-var-shapes: \f61f; -$fa-var-triangle-circle-square: \f61f; -$fa-var-shuffle: \f074; -$fa-var-random: \f074; -$fa-var-person-running: \f70c; -$fa-var-running: \f70c; -$fa-var-mobile-retro: \e527; -$fa-var-grip-lines-vertical: \f7a5; -$fa-var-spider: \f717; -$fa-var-hands-bound: \e4f9; -$fa-var-file-invoice-dollar: \f571; -$fa-var-plane-circle-exclamation: \e556; -$fa-var-x-ray: \f497; -$fa-var-spell-check: \f891; -$fa-var-slash: \f715; -$fa-var-computer-mouse: \f8cc; -$fa-var-mouse: \f8cc; -$fa-var-arrow-right-to-bracket: \f090; -$fa-var-sign-in: \f090; -$fa-var-shop-slash: \e070; -$fa-var-store-alt-slash: \e070; -$fa-var-server: \f233; -$fa-var-virus-covid-slash: \e4a9; -$fa-var-shop-lock: \e4a5; -$fa-var-hourglass-start: \f251; -$fa-var-hourglass-1: \f251; -$fa-var-blender-phone: \f6b6; -$fa-var-building-wheat: \e4db; -$fa-var-person-breastfeeding: \e53a; -$fa-var-right-to-bracket: \f2f6; -$fa-var-sign-in-alt: \f2f6; -$fa-var-venus: \f221; -$fa-var-passport: \f5ab; -$fa-var-heart-pulse: \f21e; -$fa-var-heartbeat: \f21e; -$fa-var-people-carry-box: \f4ce; -$fa-var-people-carry: \f4ce; -$fa-var-temperature-high: \f769; -$fa-var-microchip: \f2db; -$fa-var-crown: \f521; -$fa-var-weight-hanging: \f5cd; -$fa-var-xmarks-lines: \e59a; -$fa-var-file-prescription: \f572; -$fa-var-weight-scale: \f496; -$fa-var-weight: \f496; -$fa-var-user-group: \f500; -$fa-var-user-friends: \f500; -$fa-var-arrow-up-a-z: \f15e; -$fa-var-sort-alpha-up: \f15e; -$fa-var-chess-knight: \f441; -$fa-var-face-laugh-squint: \f59b; -$fa-var-laugh-squint: \f59b; -$fa-var-wheelchair: \f193; -$fa-var-circle-arrow-up: \f0aa; -$fa-var-arrow-circle-up: \f0aa; -$fa-var-toggle-on: \f205; -$fa-var-person-walking: \f554; -$fa-var-walking: \f554; -$fa-var-l: \4c; -$fa-var-fire: \f06d; -$fa-var-bed-pulse: \f487; -$fa-var-procedures: \f487; -$fa-var-shuttle-space: \f197; -$fa-var-space-shuttle: \f197; -$fa-var-face-laugh: \f599; -$fa-var-laugh: \f599; -$fa-var-folder-open: \f07c; -$fa-var-heart-circle-plus: \e500; -$fa-var-code-fork: \e13b; -$fa-var-city: \f64f; -$fa-var-microphone-lines: \f3c9; -$fa-var-microphone-alt: \f3c9; -$fa-var-pepper-hot: \f816; -$fa-var-unlock: \f09c; -$fa-var-colon-sign: \e140; -$fa-var-headset: \f590; -$fa-var-store-slash: \e071; -$fa-var-road-circle-xmark: \e566; -$fa-var-user-minus: \f503; -$fa-var-mars-stroke-up: \f22a; -$fa-var-mars-stroke-v: \f22a; -$fa-var-champagne-glasses: \f79f; -$fa-var-glass-cheers: \f79f; -$fa-var-clipboard: \f328; -$fa-var-house-circle-exclamation: \e50a; -$fa-var-file-arrow-up: \f574; -$fa-var-file-upload: \f574; -$fa-var-wifi: \f1eb; -$fa-var-wifi-3: \f1eb; -$fa-var-wifi-strong: \f1eb; -$fa-var-bath: \f2cd; -$fa-var-bathtub: \f2cd; -$fa-var-underline: \f0cd; -$fa-var-user-pen: \f4ff; -$fa-var-user-edit: \f4ff; -$fa-var-signature: \f5b7; -$fa-var-stroopwafel: \f551; -$fa-var-bold: \f032; -$fa-var-anchor-lock: \e4ad; -$fa-var-building-ngo: \e4d7; -$fa-var-manat-sign: \e1d5; -$fa-var-not-equal: \f53e; -$fa-var-border-top-left: \f853; -$fa-var-border-style: \f853; -$fa-var-map-location-dot: \f5a0; -$fa-var-map-marked-alt: \f5a0; -$fa-var-jedi: \f669; -$fa-var-square-poll-vertical: \f681; -$fa-var-poll: \f681; -$fa-var-mug-hot: \f7b6; -$fa-var-car-battery: \f5df; -$fa-var-battery-car: \f5df; -$fa-var-gift: \f06b; -$fa-var-dice-two: \f528; -$fa-var-chess-queen: \f445; -$fa-var-glasses: \f530; -$fa-var-chess-board: \f43c; -$fa-var-building-circle-check: \e4d2; -$fa-var-person-chalkboard: \e53d; -$fa-var-mars-stroke-right: \f22b; -$fa-var-mars-stroke-h: \f22b; -$fa-var-hand-back-fist: \f255; -$fa-var-hand-rock: \f255; -$fa-var-square-caret-up: \f151; -$fa-var-caret-square-up: \f151; -$fa-var-cloud-showers-water: \e4e4; -$fa-var-chart-bar: \f080; -$fa-var-bar-chart: \f080; -$fa-var-hands-bubbles: \e05e; -$fa-var-hands-wash: \e05e; -$fa-var-less-than-equal: \f537; -$fa-var-train: \f238; -$fa-var-eye-low-vision: \f2a8; -$fa-var-low-vision: \f2a8; -$fa-var-crow: \f520; -$fa-var-sailboat: \e445; -$fa-var-window-restore: \f2d2; -$fa-var-square-plus: \f0fe; -$fa-var-plus-square: \f0fe; -$fa-var-torii-gate: \f6a1; -$fa-var-frog: \f52e; -$fa-var-bucket: \e4cf; -$fa-var-image: \f03e; -$fa-var-microphone: \f130; -$fa-var-cow: \f6c8; -$fa-var-caret-up: \f0d8; -$fa-var-screwdriver: \f54a; -$fa-var-folder-closed: \e185; -$fa-var-house-tsunami: \e515; -$fa-var-square-nfi: \e576; -$fa-var-arrow-up-from-ground-water: \e4b5; -$fa-var-martini-glass: \f57b; -$fa-var-glass-martini-alt: \f57b; -$fa-var-rotate-left: \f2ea; -$fa-var-rotate-back: \f2ea; -$fa-var-rotate-backward: \f2ea; -$fa-var-undo-alt: \f2ea; -$fa-var-table-columns: \f0db; -$fa-var-columns: \f0db; -$fa-var-lemon: \f094; -$fa-var-head-side-mask: \e063; -$fa-var-handshake: \f2b5; -$fa-var-gem: \f3a5; -$fa-var-dolly: \f472; -$fa-var-dolly-box: \f472; -$fa-var-smoking: \f48d; -$fa-var-minimize: \f78c; -$fa-var-compress-arrows-alt: \f78c; -$fa-var-monument: \f5a6; -$fa-var-snowplow: \f7d2; -$fa-var-angles-right: \f101; -$fa-var-angle-double-right: \f101; -$fa-var-cannabis: \f55f; -$fa-var-circle-play: \f144; -$fa-var-play-circle: \f144; -$fa-var-tablets: \f490; -$fa-var-ethernet: \f796; -$fa-var-euro-sign: \f153; -$fa-var-eur: \f153; -$fa-var-euro: \f153; -$fa-var-chair: \f6c0; -$fa-var-circle-check: \f058; -$fa-var-check-circle: \f058; -$fa-var-circle-stop: \f28d; -$fa-var-stop-circle: \f28d; -$fa-var-compass-drafting: \f568; -$fa-var-drafting-compass: \f568; -$fa-var-plate-wheat: \e55a; -$fa-var-icicles: \f7ad; -$fa-var-person-shelter: \e54f; -$fa-var-neuter: \f22c; -$fa-var-id-badge: \f2c1; -$fa-var-marker: \f5a1; -$fa-var-face-laugh-beam: \f59a; -$fa-var-laugh-beam: \f59a; -$fa-var-helicopter-symbol: \e502; -$fa-var-universal-access: \f29a; -$fa-var-circle-chevron-up: \f139; -$fa-var-chevron-circle-up: \f139; -$fa-var-lari-sign: \e1c8; -$fa-var-volcano: \f770; -$fa-var-person-walking-dashed-line-arrow-right: \e553; -$fa-var-sterling-sign: \f154; -$fa-var-gbp: \f154; -$fa-var-pound-sign: \f154; -$fa-var-viruses: \e076; -$fa-var-square-person-confined: \e577; -$fa-var-user-tie: \f508; -$fa-var-arrow-down-long: \f175; -$fa-var-long-arrow-down: \f175; -$fa-var-tent-arrow-down-to-line: \e57e; -$fa-var-certificate: \f0a3; -$fa-var-reply-all: \f122; -$fa-var-mail-reply-all: \f122; -$fa-var-suitcase: \f0f2; -$fa-var-person-skating: \f7c5; -$fa-var-skating: \f7c5; -$fa-var-filter-circle-dollar: \f662; -$fa-var-funnel-dollar: \f662; -$fa-var-camera-retro: \f083; -$fa-var-circle-arrow-down: \f0ab; -$fa-var-arrow-circle-down: \f0ab; -$fa-var-file-import: \f56f; -$fa-var-arrow-right-to-file: \f56f; -$fa-var-square-arrow-up-right: \f14c; -$fa-var-external-link-square: \f14c; -$fa-var-box-open: \f49e; -$fa-var-scroll: \f70e; -$fa-var-spa: \f5bb; -$fa-var-location-pin-lock: \e51f; -$fa-var-pause: \f04c; -$fa-var-hill-avalanche: \e507; -$fa-var-temperature-empty: \f2cb; -$fa-var-temperature-0: \f2cb; -$fa-var-thermometer-0: \f2cb; -$fa-var-thermometer-empty: \f2cb; -$fa-var-bomb: \f1e2; -$fa-var-registered: \f25d; -$fa-var-address-card: \f2bb; -$fa-var-contact-card: \f2bb; -$fa-var-vcard: \f2bb; -$fa-var-scale-unbalanced-flip: \f516; -$fa-var-balance-scale-right: \f516; -$fa-var-subscript: \f12c; -$fa-var-diamond-turn-right: \f5eb; -$fa-var-directions: \f5eb; -$fa-var-burst: \e4dc; -$fa-var-house-laptop: \e066; -$fa-var-laptop-house: \e066; -$fa-var-face-tired: \f5c8; -$fa-var-tired: \f5c8; -$fa-var-money-bills: \e1f3; -$fa-var-smog: \f75f; -$fa-var-crutch: \f7f7; -$fa-var-cloud-arrow-up: \f0ee; -$fa-var-cloud-upload: \f0ee; -$fa-var-cloud-upload-alt: \f0ee; -$fa-var-palette: \f53f; -$fa-var-arrows-turn-right: \e4c0; -$fa-var-vest: \e085; -$fa-var-ferry: \e4ea; -$fa-var-arrows-down-to-people: \e4b9; -$fa-var-seedling: \f4d8; -$fa-var-sprout: \f4d8; -$fa-var-left-right: \f337; -$fa-var-arrows-alt-h: \f337; -$fa-var-boxes-packing: \e4c7; -$fa-var-circle-arrow-left: \f0a8; -$fa-var-arrow-circle-left: \f0a8; -$fa-var-group-arrows-rotate: \e4f6; -$fa-var-bowl-food: \e4c6; -$fa-var-candy-cane: \f786; -$fa-var-arrow-down-wide-short: \f160; -$fa-var-sort-amount-asc: \f160; -$fa-var-sort-amount-down: \f160; -$fa-var-cloud-bolt: \f76c; -$fa-var-thunderstorm: \f76c; -$fa-var-text-slash: \f87d; -$fa-var-remove-format: \f87d; -$fa-var-face-smile-wink: \f4da; -$fa-var-smile-wink: \f4da; -$fa-var-file-word: \f1c2; -$fa-var-file-powerpoint: \f1c4; -$fa-var-arrows-left-right: \f07e; -$fa-var-arrows-h: \f07e; -$fa-var-house-lock: \e510; -$fa-var-cloud-arrow-down: \f0ed; -$fa-var-cloud-download: \f0ed; -$fa-var-cloud-download-alt: \f0ed; -$fa-var-children: \e4e1; -$fa-var-chalkboard: \f51b; -$fa-var-blackboard: \f51b; -$fa-var-user-large-slash: \f4fa; -$fa-var-user-alt-slash: \f4fa; -$fa-var-envelope-open: \f2b6; -$fa-var-handshake-simple-slash: \e05f; -$fa-var-handshake-alt-slash: \e05f; -$fa-var-mattress-pillow: \e525; -$fa-var-guarani-sign: \e19a; -$fa-var-arrows-rotate: \f021; -$fa-var-refresh: \f021; -$fa-var-sync: \f021; -$fa-var-fire-extinguisher: \f134; -$fa-var-cruzeiro-sign: \e152; -$fa-var-greater-than-equal: \f532; -$fa-var-shield-halved: \f3ed; -$fa-var-shield-alt: \f3ed; -$fa-var-book-atlas: \f558; -$fa-var-atlas: \f558; -$fa-var-virus: \e074; -$fa-var-envelope-circle-check: \e4e8; -$fa-var-layer-group: \f5fd; -$fa-var-arrows-to-dot: \e4be; -$fa-var-archway: \f557; -$fa-var-heart-circle-check: \e4fd; -$fa-var-house-chimney-crack: \f6f1; -$fa-var-house-damage: \f6f1; -$fa-var-file-zipper: \f1c6; -$fa-var-file-archive: \f1c6; -$fa-var-square: \f0c8; -$fa-var-martini-glass-empty: \f000; -$fa-var-glass-martini: \f000; -$fa-var-couch: \f4b8; -$fa-var-cedi-sign: \e0df; -$fa-var-italic: \f033; -$fa-var-church: \f51d; -$fa-var-comments-dollar: \f653; -$fa-var-democrat: \f747; -$fa-var-z: \5a; -$fa-var-person-skiing: \f7c9; -$fa-var-skiing: \f7c9; -$fa-var-road-lock: \e567; -$fa-var-a: \41; -$fa-var-temperature-arrow-down: \e03f; -$fa-var-temperature-down: \e03f; -$fa-var-feather-pointed: \f56b; -$fa-var-feather-alt: \f56b; -$fa-var-p: \50; -$fa-var-snowflake: \f2dc; -$fa-var-newspaper: \f1ea; -$fa-var-rectangle-ad: \f641; -$fa-var-ad: \f641; -$fa-var-circle-arrow-right: \f0a9; -$fa-var-arrow-circle-right: \f0a9; -$fa-var-filter-circle-xmark: \e17b; -$fa-var-locust: \e520; -$fa-var-sort: \f0dc; -$fa-var-unsorted: \f0dc; -$fa-var-list-ol: \f0cb; -$fa-var-list-1-2: \f0cb; -$fa-var-list-numeric: \f0cb; -$fa-var-person-dress-burst: \e544; -$fa-var-money-check-dollar: \f53d; -$fa-var-money-check-alt: \f53d; -$fa-var-vector-square: \f5cb; -$fa-var-bread-slice: \f7ec; -$fa-var-language: \f1ab; -$fa-var-face-kiss-wink-heart: \f598; -$fa-var-kiss-wink-heart: \f598; -$fa-var-filter: \f0b0; -$fa-var-question: \3f; -$fa-var-file-signature: \f573; -$fa-var-up-down-left-right: \f0b2; -$fa-var-arrows-alt: \f0b2; -$fa-var-house-chimney-user: \e065; -$fa-var-hand-holding-heart: \f4be; -$fa-var-puzzle-piece: \f12e; -$fa-var-money-check: \f53c; -$fa-var-star-half-stroke: \f5c0; -$fa-var-star-half-alt: \f5c0; -$fa-var-code: \f121; -$fa-var-whiskey-glass: \f7a0; -$fa-var-glass-whiskey: \f7a0; -$fa-var-building-circle-exclamation: \e4d3; -$fa-var-magnifying-glass-chart: \e522; -$fa-var-arrow-up-right-from-square: \f08e; -$fa-var-external-link: \f08e; -$fa-var-cubes-stacked: \e4e6; -$fa-var-won-sign: \f159; -$fa-var-krw: \f159; -$fa-var-won: \f159; -$fa-var-virus-covid: \e4a8; -$fa-var-austral-sign: \e0a9; -$fa-var-f: \46; -$fa-var-leaf: \f06c; -$fa-var-road: \f018; -$fa-var-taxi: \f1ba; -$fa-var-cab: \f1ba; -$fa-var-person-circle-plus: \e541; -$fa-var-chart-pie: \f200; -$fa-var-pie-chart: \f200; -$fa-var-bolt-lightning: \e0b7; -$fa-var-sack-xmark: \e56a; -$fa-var-file-excel: \f1c3; -$fa-var-file-contract: \f56c; -$fa-var-fish-fins: \e4f2; -$fa-var-building-flag: \e4d5; -$fa-var-face-grin-beam: \f582; -$fa-var-grin-beam: \f582; -$fa-var-object-ungroup: \f248; -$fa-var-poop: \f619; -$fa-var-location-pin: \f041; -$fa-var-map-marker: \f041; -$fa-var-kaaba: \f66b; -$fa-var-toilet-paper: \f71e; -$fa-var-helmet-safety: \f807; -$fa-var-hard-hat: \f807; -$fa-var-hat-hard: \f807; -$fa-var-eject: \f052; -$fa-var-circle-right: \f35a; -$fa-var-arrow-alt-circle-right: \f35a; -$fa-var-plane-circle-check: \e555; -$fa-var-face-rolling-eyes: \f5a5; -$fa-var-meh-rolling-eyes: \f5a5; -$fa-var-object-group: \f247; -$fa-var-chart-line: \f201; -$fa-var-line-chart: \f201; -$fa-var-mask-ventilator: \e524; -$fa-var-arrow-right: \f061; -$fa-var-signs-post: \f277; -$fa-var-map-signs: \f277; -$fa-var-cash-register: \f788; -$fa-var-person-circle-question: \e542; -$fa-var-h: \48; -$fa-var-tarp: \e57b; -$fa-var-screwdriver-wrench: \f7d9; -$fa-var-tools: \f7d9; -$fa-var-arrows-to-eye: \e4bf; -$fa-var-plug-circle-bolt: \e55b; -$fa-var-heart: \f004; -$fa-var-mars-and-venus: \f224; -$fa-var-house-user: \e1b0; -$fa-var-home-user: \e1b0; -$fa-var-dumpster-fire: \f794; -$fa-var-house-crack: \e3b1; -$fa-var-martini-glass-citrus: \f561; -$fa-var-cocktail: \f561; -$fa-var-face-surprise: \f5c2; -$fa-var-surprise: \f5c2; -$fa-var-bottle-water: \e4c5; -$fa-var-circle-pause: \f28b; -$fa-var-pause-circle: \f28b; -$fa-var-toilet-paper-slash: \e072; -$fa-var-apple-whole: \f5d1; -$fa-var-apple-alt: \f5d1; -$fa-var-kitchen-set: \e51a; -$fa-var-r: \52; -$fa-var-temperature-quarter: \f2ca; -$fa-var-temperature-1: \f2ca; -$fa-var-thermometer-1: \f2ca; -$fa-var-thermometer-quarter: \f2ca; -$fa-var-cube: \f1b2; -$fa-var-bitcoin-sign: \e0b4; -$fa-var-shield-dog: \e573; -$fa-var-solar-panel: \f5ba; -$fa-var-lock-open: \f3c1; -$fa-var-elevator: \e16d; -$fa-var-money-bill-transfer: \e528; -$fa-var-money-bill-trend-up: \e529; -$fa-var-house-flood-water-circle-arrow-right: \e50f; -$fa-var-square-poll-horizontal: \f682; -$fa-var-poll-h: \f682; -$fa-var-circle: \f111; -$fa-var-backward-fast: \f049; -$fa-var-fast-backward: \f049; -$fa-var-recycle: \f1b8; -$fa-var-user-astronaut: \f4fb; -$fa-var-plane-slash: \e069; -$fa-var-trademark: \f25c; -$fa-var-basketball: \f434; -$fa-var-basketball-ball: \f434; -$fa-var-satellite-dish: \f7c0; -$fa-var-circle-up: \f35b; -$fa-var-arrow-alt-circle-up: \f35b; -$fa-var-mobile-screen-button: \f3cd; -$fa-var-mobile-alt: \f3cd; -$fa-var-volume-high: \f028; -$fa-var-volume-up: \f028; -$fa-var-users-rays: \e593; -$fa-var-wallet: \f555; -$fa-var-clipboard-check: \f46c; -$fa-var-file-audio: \f1c7; -$fa-var-burger: \f805; -$fa-var-hamburger: \f805; -$fa-var-wrench: \f0ad; -$fa-var-bugs: \e4d0; -$fa-var-rupee-sign: \f156; -$fa-var-rupee: \f156; -$fa-var-file-image: \f1c5; -$fa-var-circle-question: \f059; -$fa-var-question-circle: \f059; -$fa-var-plane-departure: \f5b0; -$fa-var-handshake-slash: \e060; -$fa-var-book-bookmark: \e0bb; -$fa-var-code-branch: \f126; -$fa-var-hat-cowboy: \f8c0; -$fa-var-bridge: \e4c8; -$fa-var-phone-flip: \f879; -$fa-var-phone-alt: \f879; -$fa-var-truck-front: \e2b7; -$fa-var-cat: \f6be; -$fa-var-anchor-circle-exclamation: \e4ab; -$fa-var-truck-field: \e58d; -$fa-var-route: \f4d7; -$fa-var-clipboard-question: \e4e3; -$fa-var-panorama: \e209; -$fa-var-comment-medical: \f7f5; -$fa-var-teeth-open: \f62f; -$fa-var-file-circle-minus: \e4ed; -$fa-var-tags: \f02c; -$fa-var-wine-glass: \f4e3; -$fa-var-forward-fast: \f050; -$fa-var-fast-forward: \f050; -$fa-var-face-meh-blank: \f5a4; -$fa-var-meh-blank: \f5a4; -$fa-var-square-parking: \f540; -$fa-var-parking: \f540; -$fa-var-house-signal: \e012; -$fa-var-bars-progress: \f828; -$fa-var-tasks-alt: \f828; -$fa-var-faucet-drip: \e006; -$fa-var-cart-flatbed: \f474; -$fa-var-dolly-flatbed: \f474; -$fa-var-ban-smoking: \f54d; -$fa-var-smoking-ban: \f54d; -$fa-var-terminal: \f120; -$fa-var-mobile-button: \f10b; -$fa-var-house-medical-flag: \e514; -$fa-var-basket-shopping: \f291; -$fa-var-shopping-basket: \f291; -$fa-var-tape: \f4db; -$fa-var-bus-simple: \f55e; -$fa-var-bus-alt: \f55e; -$fa-var-eye: \f06e; -$fa-var-face-sad-cry: \f5b3; -$fa-var-sad-cry: \f5b3; -$fa-var-audio-description: \f29e; -$fa-var-person-military-to-person: \e54c; -$fa-var-file-shield: \e4f0; -$fa-var-user-slash: \f506; -$fa-var-pen: \f304; -$fa-var-tower-observation: \e586; -$fa-var-file-code: \f1c9; -$fa-var-signal: \f012; -$fa-var-signal-5: \f012; -$fa-var-signal-perfect: \f012; -$fa-var-bus: \f207; -$fa-var-heart-circle-xmark: \e501; -$fa-var-house-chimney: \e3af; -$fa-var-home-lg: \e3af; -$fa-var-window-maximize: \f2d0; -$fa-var-face-frown: \f119; -$fa-var-frown: \f119; -$fa-var-prescription: \f5b1; -$fa-var-shop: \f54f; -$fa-var-store-alt: \f54f; -$fa-var-floppy-disk: \f0c7; -$fa-var-save: \f0c7; -$fa-var-vihara: \f6a7; -$fa-var-scale-unbalanced: \f515; -$fa-var-balance-scale-left: \f515; -$fa-var-sort-up: \f0de; -$fa-var-sort-asc: \f0de; -$fa-var-comment-dots: \f4ad; -$fa-var-commenting: \f4ad; -$fa-var-plant-wilt: \e5aa; -$fa-var-diamond: \f219; -$fa-var-face-grin-squint: \f585; -$fa-var-grin-squint: \f585; -$fa-var-hand-holding-dollar: \f4c0; -$fa-var-hand-holding-usd: \f4c0; -$fa-var-bacterium: \e05a; -$fa-var-hand-pointer: \f25a; -$fa-var-drum-steelpan: \f56a; -$fa-var-hand-scissors: \f257; -$fa-var-hands-praying: \f684; -$fa-var-praying-hands: \f684; -$fa-var-arrow-rotate-right: \f01e; -$fa-var-arrow-right-rotate: \f01e; -$fa-var-arrow-rotate-forward: \f01e; -$fa-var-redo: \f01e; -$fa-var-biohazard: \f780; -$fa-var-location-crosshairs: \f601; -$fa-var-location: \f601; -$fa-var-mars-double: \f227; -$fa-var-child-dress: \e59c; -$fa-var-users-between-lines: \e591; -$fa-var-lungs-virus: \e067; -$fa-var-face-grin-tears: \f588; -$fa-var-grin-tears: \f588; -$fa-var-phone: \f095; -$fa-var-calendar-xmark: \f273; -$fa-var-calendar-times: \f273; -$fa-var-child-reaching: \e59d; -$fa-var-head-side-virus: \e064; -$fa-var-user-gear: \f4fe; -$fa-var-user-cog: \f4fe; -$fa-var-arrow-up-1-9: \f163; -$fa-var-sort-numeric-up: \f163; -$fa-var-door-closed: \f52a; -$fa-var-shield-virus: \e06c; -$fa-var-dice-six: \f526; -$fa-var-mosquito-net: \e52c; -$fa-var-bridge-water: \e4ce; -$fa-var-person-booth: \f756; -$fa-var-text-width: \f035; -$fa-var-hat-wizard: \f6e8; -$fa-var-pen-fancy: \f5ac; -$fa-var-person-digging: \f85e; -$fa-var-digging: \f85e; -$fa-var-trash: \f1f8; -$fa-var-gauge-simple: \f629; -$fa-var-gauge-simple-med: \f629; -$fa-var-tachometer-average: \f629; -$fa-var-book-medical: \f7e6; -$fa-var-poo: \f2fe; -$fa-var-quote-right: \f10e; -$fa-var-quote-right-alt: \f10e; -$fa-var-shirt: \f553; -$fa-var-t-shirt: \f553; -$fa-var-tshirt: \f553; -$fa-var-cubes: \f1b3; -$fa-var-divide: \f529; -$fa-var-tenge-sign: \f7d7; -$fa-var-tenge: \f7d7; -$fa-var-headphones: \f025; -$fa-var-hands-holding: \f4c2; -$fa-var-hands-clapping: \e1a8; -$fa-var-republican: \f75e; -$fa-var-arrow-left: \f060; -$fa-var-person-circle-xmark: \e543; -$fa-var-ruler: \f545; -$fa-var-align-left: \f036; -$fa-var-dice-d6: \f6d1; -$fa-var-restroom: \f7bd; -$fa-var-j: \4a; -$fa-var-users-viewfinder: \e595; -$fa-var-file-video: \f1c8; -$fa-var-up-right-from-square: \f35d; -$fa-var-external-link-alt: \f35d; -$fa-var-table-cells: \f00a; -$fa-var-th: \f00a; -$fa-var-file-pdf: \f1c1; -$fa-var-book-bible: \f647; -$fa-var-bible: \f647; -$fa-var-o: \4f; -$fa-var-suitcase-medical: \f0fa; -$fa-var-medkit: \f0fa; -$fa-var-user-secret: \f21b; -$fa-var-otter: \f700; -$fa-var-person-dress: \f182; -$fa-var-female: \f182; -$fa-var-comment-dollar: \f651; -$fa-var-business-time: \f64a; -$fa-var-briefcase-clock: \f64a; -$fa-var-table-cells-large: \f009; -$fa-var-th-large: \f009; -$fa-var-book-tanakh: \f827; -$fa-var-tanakh: \f827; -$fa-var-phone-volume: \f2a0; -$fa-var-volume-control-phone: \f2a0; -$fa-var-hat-cowboy-side: \f8c1; -$fa-var-clipboard-user: \f7f3; -$fa-var-child: \f1ae; -$fa-var-lira-sign: \f195; -$fa-var-satellite: \f7bf; -$fa-var-plane-lock: \e558; -$fa-var-tag: \f02b; -$fa-var-comment: \f075; -$fa-var-cake-candles: \f1fd; -$fa-var-birthday-cake: \f1fd; -$fa-var-cake: \f1fd; -$fa-var-envelope: \f0e0; -$fa-var-angles-up: \f102; -$fa-var-angle-double-up: \f102; -$fa-var-paperclip: \f0c6; -$fa-var-arrow-right-to-city: \e4b3; -$fa-var-ribbon: \f4d6; -$fa-var-lungs: \f604; -$fa-var-arrow-up-9-1: \f887; -$fa-var-sort-numeric-up-alt: \f887; -$fa-var-litecoin-sign: \e1d3; -$fa-var-border-none: \f850; -$fa-var-circle-nodes: \e4e2; -$fa-var-parachute-box: \f4cd; -$fa-var-indent: \f03c; -$fa-var-truck-field-un: \e58e; -$fa-var-hourglass: \f254; -$fa-var-hourglass-empty: \f254; -$fa-var-mountain: \f6fc; -$fa-var-user-doctor: \f0f0; -$fa-var-user-md: \f0f0; -$fa-var-circle-info: \f05a; -$fa-var-info-circle: \f05a; -$fa-var-cloud-meatball: \f73b; -$fa-var-camera: \f030; -$fa-var-camera-alt: \f030; -$fa-var-square-virus: \e578; -$fa-var-meteor: \f753; -$fa-var-car-on: \e4dd; -$fa-var-sleigh: \f7cc; -$fa-var-arrow-down-1-9: \f162; -$fa-var-sort-numeric-asc: \f162; -$fa-var-sort-numeric-down: \f162; -$fa-var-hand-holding-droplet: \f4c1; -$fa-var-hand-holding-water: \f4c1; -$fa-var-water: \f773; -$fa-var-calendar-check: \f274; -$fa-var-braille: \f2a1; -$fa-var-prescription-bottle-medical: \f486; -$fa-var-prescription-bottle-alt: \f486; -$fa-var-landmark: \f66f; -$fa-var-truck: \f0d1; -$fa-var-crosshairs: \f05b; -$fa-var-person-cane: \e53c; -$fa-var-tent: \e57d; -$fa-var-vest-patches: \e086; -$fa-var-check-double: \f560; -$fa-var-arrow-down-a-z: \f15d; -$fa-var-sort-alpha-asc: \f15d; -$fa-var-sort-alpha-down: \f15d; -$fa-var-money-bill-wheat: \e52a; -$fa-var-cookie: \f563; -$fa-var-arrow-rotate-left: \f0e2; -$fa-var-arrow-left-rotate: \f0e2; -$fa-var-arrow-rotate-back: \f0e2; -$fa-var-arrow-rotate-backward: \f0e2; -$fa-var-undo: \f0e2; -$fa-var-hard-drive: \f0a0; -$fa-var-hdd: \f0a0; -$fa-var-face-grin-squint-tears: \f586; -$fa-var-grin-squint-tears: \f586; -$fa-var-dumbbell: \f44b; -$fa-var-rectangle-list: \f022; -$fa-var-list-alt: \f022; -$fa-var-tarp-droplet: \e57c; -$fa-var-house-medical-circle-check: \e511; -$fa-var-person-skiing-nordic: \f7ca; -$fa-var-skiing-nordic: \f7ca; -$fa-var-calendar-plus: \f271; -$fa-var-plane-arrival: \f5af; -$fa-var-circle-left: \f359; -$fa-var-arrow-alt-circle-left: \f359; -$fa-var-train-subway: \f239; -$fa-var-subway: \f239; -$fa-var-chart-gantt: \e0e4; -$fa-var-indian-rupee-sign: \e1bc; -$fa-var-indian-rupee: \e1bc; -$fa-var-inr: \e1bc; -$fa-var-crop-simple: \f565; -$fa-var-crop-alt: \f565; -$fa-var-money-bill-1: \f3d1; -$fa-var-money-bill-alt: \f3d1; -$fa-var-left-long: \f30a; -$fa-var-long-arrow-alt-left: \f30a; -$fa-var-dna: \f471; -$fa-var-virus-slash: \e075; -$fa-var-minus: \f068; -$fa-var-subtract: \f068; -$fa-var-child-rifle: \e4e0; -$fa-var-chess: \f439; -$fa-var-arrow-left-long: \f177; -$fa-var-long-arrow-left: \f177; -$fa-var-plug-circle-check: \e55c; -$fa-var-street-view: \f21d; -$fa-var-franc-sign: \e18f; -$fa-var-volume-off: \f026; -$fa-var-hands-asl-interpreting: \f2a3; -$fa-var-american-sign-language-interpreting: \f2a3; -$fa-var-asl-interpreting: \f2a3; -$fa-var-hands-american-sign-language-interpreting: \f2a3; -$fa-var-gear: \f013; -$fa-var-cog: \f013; -$fa-var-droplet-slash: \f5c7; -$fa-var-tint-slash: \f5c7; -$fa-var-mosque: \f678; -$fa-var-mosquito: \e52b; -$fa-var-star-of-david: \f69a; -$fa-var-person-military-rifle: \e54b; -$fa-var-cart-shopping: \f07a; -$fa-var-shopping-cart: \f07a; -$fa-var-vials: \f493; -$fa-var-plug-circle-plus: \e55f; -$fa-var-place-of-worship: \f67f; -$fa-var-grip-vertical: \f58e; -$fa-var-arrow-turn-up: \f148; -$fa-var-level-up: \f148; -$fa-var-u: \55; -$fa-var-square-root-variable: \f698; -$fa-var-square-root-alt: \f698; -$fa-var-clock: \f017; -$fa-var-clock-four: \f017; -$fa-var-backward-step: \f048; -$fa-var-step-backward: \f048; -$fa-var-pallet: \f482; -$fa-var-faucet: \e005; -$fa-var-baseball-bat-ball: \f432; -$fa-var-s: \53; -$fa-var-timeline: \e29c; -$fa-var-keyboard: \f11c; -$fa-var-caret-down: \f0d7; -$fa-var-house-chimney-medical: \f7f2; -$fa-var-clinic-medical: \f7f2; -$fa-var-temperature-three-quarters: \f2c8; -$fa-var-temperature-3: \f2c8; -$fa-var-thermometer-3: \f2c8; -$fa-var-thermometer-three-quarters: \f2c8; -$fa-var-mobile-screen: \f3cf; -$fa-var-mobile-android-alt: \f3cf; -$fa-var-plane-up: \e22d; -$fa-var-piggy-bank: \f4d3; -$fa-var-battery-half: \f242; -$fa-var-battery-3: \f242; -$fa-var-mountain-city: \e52e; -$fa-var-coins: \f51e; -$fa-var-khanda: \f66d; -$fa-var-sliders: \f1de; -$fa-var-sliders-h: \f1de; -$fa-var-folder-tree: \f802; -$fa-var-network-wired: \f6ff; -$fa-var-map-pin: \f276; -$fa-var-hamsa: \f665; -$fa-var-cent-sign: \e3f5; -$fa-var-flask: \f0c3; -$fa-var-person-pregnant: \e31e; -$fa-var-wand-sparkles: \f72b; -$fa-var-ellipsis-vertical: \f142; -$fa-var-ellipsis-v: \f142; -$fa-var-ticket: \f145; -$fa-var-power-off: \f011; -$fa-var-right-long: \f30b; -$fa-var-long-arrow-alt-right: \f30b; -$fa-var-flag-usa: \f74d; -$fa-var-laptop-file: \e51d; -$fa-var-tty: \f1e4; -$fa-var-teletype: \f1e4; -$fa-var-diagram-next: \e476; -$fa-var-person-rifle: \e54e; -$fa-var-house-medical-circle-exclamation: \e512; -$fa-var-closed-captioning: \f20a; -$fa-var-person-hiking: \f6ec; -$fa-var-hiking: \f6ec; -$fa-var-venus-double: \f226; -$fa-var-images: \f302; -$fa-var-calculator: \f1ec; -$fa-var-people-pulling: \e535; -$fa-var-n: \4e; -$fa-var-cable-car: \f7da; -$fa-var-tram: \f7da; -$fa-var-cloud-rain: \f73d; -$fa-var-building-circle-xmark: \e4d4; -$fa-var-ship: \f21a; -$fa-var-arrows-down-to-line: \e4b8; -$fa-var-download: \f019; -$fa-var-face-grin: \f580; -$fa-var-grin: \f580; -$fa-var-delete-left: \f55a; -$fa-var-backspace: \f55a; -$fa-var-eye-dropper: \f1fb; -$fa-var-eye-dropper-empty: \f1fb; -$fa-var-eyedropper: \f1fb; -$fa-var-file-circle-check: \e5a0; -$fa-var-forward: \f04e; -$fa-var-mobile: \f3ce; -$fa-var-mobile-android: \f3ce; -$fa-var-mobile-phone: \f3ce; -$fa-var-face-meh: \f11a; -$fa-var-meh: \f11a; -$fa-var-align-center: \f037; -$fa-var-book-skull: \f6b7; -$fa-var-book-dead: \f6b7; -$fa-var-id-card: \f2c2; -$fa-var-drivers-license: \f2c2; -$fa-var-outdent: \f03b; -$fa-var-dedent: \f03b; -$fa-var-heart-circle-exclamation: \e4fe; -$fa-var-house: \f015; -$fa-var-home: \f015; -$fa-var-home-alt: \f015; -$fa-var-home-lg-alt: \f015; -$fa-var-calendar-week: \f784; -$fa-var-laptop-medical: \f812; -$fa-var-b: \42; -$fa-var-file-medical: \f477; -$fa-var-dice-one: \f525; -$fa-var-kiwi-bird: \f535; -$fa-var-arrow-right-arrow-left: \f0ec; -$fa-var-exchange: \f0ec; -$fa-var-rotate-right: \f2f9; -$fa-var-redo-alt: \f2f9; -$fa-var-rotate-forward: \f2f9; -$fa-var-utensils: \f2e7; -$fa-var-cutlery: \f2e7; -$fa-var-arrow-up-wide-short: \f161; -$fa-var-sort-amount-up: \f161; -$fa-var-mill-sign: \e1ed; -$fa-var-bowl-rice: \e2eb; -$fa-var-skull: \f54c; -$fa-var-tower-broadcast: \f519; -$fa-var-broadcast-tower: \f519; -$fa-var-truck-pickup: \f63c; -$fa-var-up-long: \f30c; -$fa-var-long-arrow-alt-up: \f30c; -$fa-var-stop: \f04d; -$fa-var-code-merge: \f387; -$fa-var-upload: \f093; -$fa-var-hurricane: \f751; -$fa-var-mound: \e52d; -$fa-var-toilet-portable: \e583; -$fa-var-compact-disc: \f51f; -$fa-var-file-arrow-down: \f56d; -$fa-var-file-download: \f56d; -$fa-var-caravan: \f8ff; -$fa-var-shield-cat: \e572; -$fa-var-bolt: \f0e7; -$fa-var-zap: \f0e7; -$fa-var-glass-water: \e4f4; -$fa-var-oil-well: \e532; -$fa-var-vault: \e2c5; -$fa-var-mars: \f222; -$fa-var-toilet: \f7d8; -$fa-var-plane-circle-xmark: \e557; -$fa-var-yen-sign: \f157; -$fa-var-cny: \f157; -$fa-var-jpy: \f157; -$fa-var-rmb: \f157; -$fa-var-yen: \f157; -$fa-var-ruble-sign: \f158; -$fa-var-rouble: \f158; -$fa-var-rub: \f158; -$fa-var-ruble: \f158; -$fa-var-sun: \f185; -$fa-var-guitar: \f7a6; -$fa-var-face-laugh-wink: \f59c; -$fa-var-laugh-wink: \f59c; -$fa-var-horse-head: \f7ab; -$fa-var-bore-hole: \e4c3; -$fa-var-industry: \f275; -$fa-var-circle-down: \f358; -$fa-var-arrow-alt-circle-down: \f358; -$fa-var-arrows-turn-to-dots: \e4c1; -$fa-var-florin-sign: \e184; -$fa-var-arrow-down-short-wide: \f884; -$fa-var-sort-amount-desc: \f884; -$fa-var-sort-amount-down-alt: \f884; -$fa-var-less-than: \3c; -$fa-var-angle-down: \f107; -$fa-var-car-tunnel: \e4de; -$fa-var-head-side-cough: \e061; -$fa-var-grip-lines: \f7a4; -$fa-var-thumbs-down: \f165; -$fa-var-user-lock: \f502; -$fa-var-arrow-right-long: \f178; -$fa-var-long-arrow-right: \f178; -$fa-var-anchor-circle-xmark: \e4ac; -$fa-var-ellipsis: \f141; -$fa-var-ellipsis-h: \f141; -$fa-var-chess-pawn: \f443; -$fa-var-kit-medical: \f479; -$fa-var-first-aid: \f479; -$fa-var-person-through-window: \e5a9; -$fa-var-toolbox: \f552; -$fa-var-hands-holding-circle: \e4fb; -$fa-var-bug: \f188; -$fa-var-credit-card: \f09d; -$fa-var-credit-card-alt: \f09d; -$fa-var-car: \f1b9; -$fa-var-automobile: \f1b9; -$fa-var-hand-holding-hand: \e4f7; -$fa-var-book-open-reader: \f5da; -$fa-var-book-reader: \f5da; -$fa-var-mountain-sun: \e52f; -$fa-var-arrows-left-right-to-line: \e4ba; -$fa-var-dice-d20: \f6cf; -$fa-var-truck-droplet: \e58c; -$fa-var-file-circle-xmark: \e5a1; -$fa-var-temperature-arrow-up: \e040; -$fa-var-temperature-up: \e040; -$fa-var-medal: \f5a2; -$fa-var-bed: \f236; -$fa-var-square-h: \f0fd; -$fa-var-h-square: \f0fd; -$fa-var-podcast: \f2ce; -$fa-var-temperature-full: \f2c7; -$fa-var-temperature-4: \f2c7; -$fa-var-thermometer-4: \f2c7; -$fa-var-thermometer-full: \f2c7; -$fa-var-bell: \f0f3; -$fa-var-superscript: \f12b; -$fa-var-plug-circle-xmark: \e560; -$fa-var-star-of-life: \f621; -$fa-var-phone-slash: \f3dd; -$fa-var-paint-roller: \f5aa; -$fa-var-handshake-angle: \f4c4; -$fa-var-hands-helping: \f4c4; -$fa-var-location-dot: \f3c5; -$fa-var-map-marker-alt: \f3c5; -$fa-var-file: \f15b; -$fa-var-greater-than: \3e; -$fa-var-person-swimming: \f5c4; -$fa-var-swimmer: \f5c4; -$fa-var-arrow-down: \f063; -$fa-var-droplet: \f043; -$fa-var-tint: \f043; -$fa-var-eraser: \f12d; -$fa-var-earth-americas: \f57d; -$fa-var-earth: \f57d; -$fa-var-earth-america: \f57d; -$fa-var-globe-americas: \f57d; -$fa-var-person-burst: \e53b; -$fa-var-dove: \f4ba; -$fa-var-battery-empty: \f244; -$fa-var-battery-0: \f244; -$fa-var-socks: \f696; -$fa-var-inbox: \f01c; -$fa-var-section: \e447; -$fa-var-gauge-high: \f625; -$fa-var-tachometer-alt: \f625; -$fa-var-tachometer-alt-fast: \f625; -$fa-var-envelope-open-text: \f658; -$fa-var-hospital: \f0f8; -$fa-var-hospital-alt: \f0f8; -$fa-var-hospital-wide: \f0f8; -$fa-var-wine-bottle: \f72f; -$fa-var-chess-rook: \f447; -$fa-var-bars-staggered: \f550; -$fa-var-reorder: \f550; -$fa-var-stream: \f550; -$fa-var-dharmachakra: \f655; -$fa-var-hotdog: \f80f; -$fa-var-person-walking-with-cane: \f29d; -$fa-var-blind: \f29d; -$fa-var-drum: \f569; -$fa-var-ice-cream: \f810; -$fa-var-heart-circle-bolt: \e4fc; -$fa-var-fax: \f1ac; -$fa-var-paragraph: \f1dd; -$fa-var-check-to-slot: \f772; -$fa-var-vote-yea: \f772; -$fa-var-star-half: \f089; -$fa-var-boxes-stacked: \f468; -$fa-var-boxes: \f468; -$fa-var-boxes-alt: \f468; -$fa-var-link: \f0c1; -$fa-var-chain: \f0c1; -$fa-var-ear-listen: \f2a2; -$fa-var-assistive-listening-systems: \f2a2; -$fa-var-tree-city: \e587; -$fa-var-play: \f04b; -$fa-var-font: \f031; -$fa-var-rupiah-sign: \e23d; -$fa-var-magnifying-glass: \f002; -$fa-var-search: \f002; -$fa-var-table-tennis-paddle-ball: \f45d; -$fa-var-ping-pong-paddle-ball: \f45d; -$fa-var-table-tennis: \f45d; -$fa-var-person-dots-from-line: \f470; -$fa-var-diagnoses: \f470; -$fa-var-trash-can-arrow-up: \f82a; -$fa-var-trash-restore-alt: \f82a; -$fa-var-naira-sign: \e1f6; -$fa-var-cart-arrow-down: \f218; -$fa-var-walkie-talkie: \f8ef; -$fa-var-file-pen: \f31c; -$fa-var-file-edit: \f31c; -$fa-var-receipt: \f543; -$fa-var-square-pen: \f14b; -$fa-var-pen-square: \f14b; -$fa-var-pencil-square: \f14b; -$fa-var-suitcase-rolling: \f5c1; -$fa-var-person-circle-exclamation: \e53f; -$fa-var-chevron-down: \f078; -$fa-var-battery-full: \f240; -$fa-var-battery: \f240; -$fa-var-battery-5: \f240; -$fa-var-skull-crossbones: \f714; -$fa-var-code-compare: \e13a; -$fa-var-list-ul: \f0ca; -$fa-var-list-dots: \f0ca; -$fa-var-school-lock: \e56f; -$fa-var-tower-cell: \e585; -$fa-var-down-long: \f309; -$fa-var-long-arrow-alt-down: \f309; -$fa-var-ranking-star: \e561; -$fa-var-chess-king: \f43f; -$fa-var-person-harassing: \e549; -$fa-var-brazilian-real-sign: \e46c; -$fa-var-landmark-dome: \f752; -$fa-var-landmark-alt: \f752; -$fa-var-arrow-up: \f062; -$fa-var-tv: \f26c; -$fa-var-television: \f26c; -$fa-var-tv-alt: \f26c; -$fa-var-shrimp: \e448; -$fa-var-list-check: \f0ae; -$fa-var-tasks: \f0ae; -$fa-var-jug-detergent: \e519; -$fa-var-circle-user: \f2bd; -$fa-var-user-circle: \f2bd; -$fa-var-user-shield: \f505; -$fa-var-wind: \f72e; -$fa-var-car-burst: \f5e1; -$fa-var-car-crash: \f5e1; -$fa-var-y: \59; -$fa-var-person-snowboarding: \f7ce; -$fa-var-snowboarding: \f7ce; -$fa-var-truck-fast: \f48b; -$fa-var-shipping-fast: \f48b; -$fa-var-fish: \f578; -$fa-var-user-graduate: \f501; -$fa-var-circle-half-stroke: \f042; -$fa-var-adjust: \f042; -$fa-var-clapperboard: \e131; -$fa-var-circle-radiation: \f7ba; -$fa-var-radiation-alt: \f7ba; -$fa-var-baseball: \f433; -$fa-var-baseball-ball: \f433; -$fa-var-jet-fighter-up: \e518; -$fa-var-diagram-project: \f542; -$fa-var-project-diagram: \f542; -$fa-var-copy: \f0c5; -$fa-var-volume-xmark: \f6a9; -$fa-var-volume-mute: \f6a9; -$fa-var-volume-times: \f6a9; -$fa-var-hand-sparkles: \e05d; -$fa-var-grip: \f58d; -$fa-var-grip-horizontal: \f58d; -$fa-var-share-from-square: \f14d; -$fa-var-share-square: \f14d; -$fa-var-gun: \e19b; -$fa-var-square-phone: \f098; -$fa-var-phone-square: \f098; -$fa-var-plus: \2b; -$fa-var-add: \2b; -$fa-var-expand: \f065; -$fa-var-computer: \e4e5; -$fa-var-xmark: \f00d; -$fa-var-close: \f00d; -$fa-var-multiply: \f00d; -$fa-var-remove: \f00d; -$fa-var-times: \f00d; -$fa-var-arrows-up-down-left-right: \f047; -$fa-var-arrows: \f047; -$fa-var-chalkboard-user: \f51c; -$fa-var-chalkboard-teacher: \f51c; -$fa-var-peso-sign: \e222; -$fa-var-building-shield: \e4d8; -$fa-var-baby: \f77c; -$fa-var-users-line: \e592; -$fa-var-quote-left: \f10d; -$fa-var-quote-left-alt: \f10d; -$fa-var-tractor: \f722; -$fa-var-trash-arrow-up: \f829; -$fa-var-trash-restore: \f829; -$fa-var-arrow-down-up-lock: \e4b0; -$fa-var-lines-leaning: \e51e; -$fa-var-ruler-combined: \f546; -$fa-var-copyright: \f1f9; -$fa-var-equals: \3d; -$fa-var-blender: \f517; -$fa-var-teeth: \f62e; -$fa-var-shekel-sign: \f20b; -$fa-var-ils: \f20b; -$fa-var-shekel: \f20b; -$fa-var-sheqel: \f20b; -$fa-var-sheqel-sign: \f20b; -$fa-var-map: \f279; -$fa-var-rocket: \f135; -$fa-var-photo-film: \f87c; -$fa-var-photo-video: \f87c; -$fa-var-folder-minus: \f65d; -$fa-var-store: \f54e; -$fa-var-arrow-trend-up: \e098; -$fa-var-plug-circle-minus: \e55e; -$fa-var-sign-hanging: \f4d9; -$fa-var-sign: \f4d9; -$fa-var-bezier-curve: \f55b; -$fa-var-bell-slash: \f1f6; -$fa-var-tablet: \f3fb; -$fa-var-tablet-android: \f3fb; -$fa-var-school-flag: \e56e; -$fa-var-fill: \f575; -$fa-var-angle-up: \f106; -$fa-var-drumstick-bite: \f6d7; -$fa-var-holly-berry: \f7aa; -$fa-var-chevron-left: \f053; -$fa-var-bacteria: \e059; -$fa-var-hand-lizard: \f258; -$fa-var-disease: \f7fa; -$fa-var-briefcase-medical: \f469; -$fa-var-genderless: \f22d; -$fa-var-chevron-right: \f054; -$fa-var-retweet: \f079; -$fa-var-car-rear: \f5de; -$fa-var-car-alt: \f5de; -$fa-var-pump-soap: \e06b; -$fa-var-video-slash: \f4e2; -$fa-var-battery-quarter: \f243; -$fa-var-battery-2: \f243; -$fa-var-radio: \f8d7; -$fa-var-baby-carriage: \f77d; -$fa-var-carriage-baby: \f77d; -$fa-var-traffic-light: \f637; -$fa-var-thermometer: \f491; -$fa-var-vr-cardboard: \f729; -$fa-var-hand-middle-finger: \f806; -$fa-var-percent: \25; -$fa-var-percentage: \25; -$fa-var-truck-moving: \f4df; -$fa-var-glass-water-droplet: \e4f5; -$fa-var-display: \e163; -$fa-var-face-smile: \f118; -$fa-var-smile: \f118; -$fa-var-thumbtack: \f08d; -$fa-var-thumb-tack: \f08d; -$fa-var-trophy: \f091; -$fa-var-person-praying: \f683; -$fa-var-pray: \f683; -$fa-var-hammer: \f6e3; -$fa-var-hand-peace: \f25b; -$fa-var-rotate: \f2f1; -$fa-var-sync-alt: \f2f1; -$fa-var-spinner: \f110; -$fa-var-robot: \f544; -$fa-var-peace: \f67c; -$fa-var-gears: \f085; -$fa-var-cogs: \f085; -$fa-var-warehouse: \f494; -$fa-var-arrow-up-right-dots: \e4b7; -$fa-var-splotch: \f5bc; -$fa-var-face-grin-hearts: \f584; -$fa-var-grin-hearts: \f584; -$fa-var-dice-four: \f524; -$fa-var-sim-card: \f7c4; -$fa-var-transgender: \f225; -$fa-var-transgender-alt: \f225; -$fa-var-mercury: \f223; -$fa-var-arrow-turn-down: \f149; -$fa-var-level-down: \f149; -$fa-var-person-falling-burst: \e547; -$fa-var-award: \f559; -$fa-var-ticket-simple: \f3ff; -$fa-var-ticket-alt: \f3ff; -$fa-var-building: \f1ad; -$fa-var-angles-left: \f100; -$fa-var-angle-double-left: \f100; -$fa-var-qrcode: \f029; -$fa-var-clock-rotate-left: \f1da; -$fa-var-history: \f1da; -$fa-var-face-grin-beam-sweat: \f583; -$fa-var-grin-beam-sweat: \f583; -$fa-var-file-export: \f56e; -$fa-var-arrow-right-from-file: \f56e; -$fa-var-shield: \f132; -$fa-var-shield-blank: \f132; -$fa-var-arrow-up-short-wide: \f885; -$fa-var-sort-amount-up-alt: \f885; -$fa-var-house-medical: \e3b2; -$fa-var-golf-ball-tee: \f450; -$fa-var-golf-ball: \f450; -$fa-var-circle-chevron-left: \f137; -$fa-var-chevron-circle-left: \f137; -$fa-var-house-chimney-window: \e00d; -$fa-var-pen-nib: \f5ad; -$fa-var-tent-arrow-turn-left: \e580; -$fa-var-tents: \e582; -$fa-var-wand-magic: \f0d0; -$fa-var-magic: \f0d0; -$fa-var-dog: \f6d3; -$fa-var-carrot: \f787; -$fa-var-moon: \f186; -$fa-var-wine-glass-empty: \f5ce; -$fa-var-wine-glass-alt: \f5ce; -$fa-var-cheese: \f7ef; -$fa-var-yin-yang: \f6ad; -$fa-var-music: \f001; -$fa-var-code-commit: \f386; -$fa-var-temperature-low: \f76b; -$fa-var-person-biking: \f84a; -$fa-var-biking: \f84a; -$fa-var-broom: \f51a; -$fa-var-shield-heart: \e574; -$fa-var-gopuram: \f664; -$fa-var-earth-oceania: \e47b; -$fa-var-globe-oceania: \e47b; -$fa-var-square-xmark: \f2d3; -$fa-var-times-square: \f2d3; -$fa-var-xmark-square: \f2d3; -$fa-var-hashtag: \23; -$fa-var-up-right-and-down-left-from-center: \f424; -$fa-var-expand-alt: \f424; -$fa-var-oil-can: \f613; -$fa-var-t: \54; -$fa-var-hippo: \f6ed; -$fa-var-chart-column: \e0e3; -$fa-var-infinity: \f534; -$fa-var-vial-circle-check: \e596; -$fa-var-person-arrow-down-to-line: \e538; -$fa-var-voicemail: \f897; -$fa-var-fan: \f863; -$fa-var-person-walking-luggage: \e554; -$fa-var-up-down: \f338; -$fa-var-arrows-alt-v: \f338; -$fa-var-cloud-moon-rain: \f73c; -$fa-var-calendar: \f133; -$fa-var-trailer: \e041; -$fa-var-bahai: \f666; -$fa-var-haykal: \f666; -$fa-var-sd-card: \f7c2; -$fa-var-dragon: \f6d5; -$fa-var-shoe-prints: \f54b; -$fa-var-circle-plus: \f055; -$fa-var-plus-circle: \f055; -$fa-var-face-grin-tongue-wink: \f58b; -$fa-var-grin-tongue-wink: \f58b; -$fa-var-hand-holding: \f4bd; -$fa-var-plug-circle-exclamation: \e55d; -$fa-var-link-slash: \f127; -$fa-var-chain-broken: \f127; -$fa-var-chain-slash: \f127; -$fa-var-unlink: \f127; -$fa-var-clone: \f24d; -$fa-var-person-walking-arrow-loop-left: \e551; -$fa-var-arrow-up-z-a: \f882; -$fa-var-sort-alpha-up-alt: \f882; -$fa-var-fire-flame-curved: \f7e4; -$fa-var-fire-alt: \f7e4; -$fa-var-tornado: \f76f; -$fa-var-file-circle-plus: \e494; -$fa-var-book-quran: \f687; -$fa-var-quran: \f687; -$fa-var-anchor: \f13d; -$fa-var-border-all: \f84c; -$fa-var-face-angry: \f556; -$fa-var-angry: \f556; -$fa-var-cookie-bite: \f564; -$fa-var-arrow-trend-down: \e097; -$fa-var-rss: \f09e; -$fa-var-feed: \f09e; -$fa-var-draw-polygon: \f5ee; -$fa-var-scale-balanced: \f24e; -$fa-var-balance-scale: \f24e; -$fa-var-gauge-simple-high: \f62a; -$fa-var-tachometer: \f62a; -$fa-var-tachometer-fast: \f62a; -$fa-var-shower: \f2cc; -$fa-var-desktop: \f390; -$fa-var-desktop-alt: \f390; -$fa-var-m: \4d; -$fa-var-table-list: \f00b; -$fa-var-th-list: \f00b; -$fa-var-comment-sms: \f7cd; -$fa-var-sms: \f7cd; -$fa-var-book: \f02d; -$fa-var-user-plus: \f234; -$fa-var-check: \f00c; -$fa-var-battery-three-quarters: \f241; -$fa-var-battery-4: \f241; -$fa-var-house-circle-check: \e509; -$fa-var-angle-left: \f104; -$fa-var-diagram-successor: \e47a; -$fa-var-truck-arrow-right: \e58b; -$fa-var-arrows-split-up-and-left: \e4bc; -$fa-var-hand-fist: \f6de; -$fa-var-fist-raised: \f6de; -$fa-var-cloud-moon: \f6c3; -$fa-var-briefcase: \f0b1; -$fa-var-person-falling: \e546; -$fa-var-image-portrait: \f3e0; -$fa-var-portrait: \f3e0; -$fa-var-user-tag: \f507; -$fa-var-rug: \e569; -$fa-var-earth-europe: \f7a2; -$fa-var-globe-europe: \f7a2; -$fa-var-cart-flatbed-suitcase: \f59d; -$fa-var-luggage-cart: \f59d; -$fa-var-rectangle-xmark: \f410; -$fa-var-rectangle-times: \f410; -$fa-var-times-rectangle: \f410; -$fa-var-window-close: \f410; -$fa-var-baht-sign: \e0ac; -$fa-var-book-open: \f518; -$fa-var-book-journal-whills: \f66a; -$fa-var-journal-whills: \f66a; -$fa-var-handcuffs: \e4f8; -$fa-var-triangle-exclamation: \f071; -$fa-var-exclamation-triangle: \f071; -$fa-var-warning: \f071; -$fa-var-database: \f1c0; -$fa-var-share: \f064; -$fa-var-arrow-turn-right: \f064; -$fa-var-mail-forward: \f064; -$fa-var-bottle-droplet: \e4c4; -$fa-var-mask-face: \e1d7; -$fa-var-hill-rockslide: \e508; -$fa-var-right-left: \f362; -$fa-var-exchange-alt: \f362; -$fa-var-paper-plane: \f1d8; -$fa-var-road-circle-exclamation: \e565; -$fa-var-dungeon: \f6d9; -$fa-var-align-right: \f038; -$fa-var-money-bill-1-wave: \f53b; -$fa-var-money-bill-wave-alt: \f53b; -$fa-var-life-ring: \f1cd; -$fa-var-hands: \f2a7; -$fa-var-sign-language: \f2a7; -$fa-var-signing: \f2a7; -$fa-var-calendar-day: \f783; -$fa-var-water-ladder: \f5c5; -$fa-var-ladder-water: \f5c5; -$fa-var-swimming-pool: \f5c5; -$fa-var-arrows-up-down: \f07d; -$fa-var-arrows-v: \f07d; -$fa-var-face-grimace: \f57f; -$fa-var-grimace: \f57f; -$fa-var-wheelchair-move: \e2ce; -$fa-var-wheelchair-alt: \e2ce; -$fa-var-turn-down: \f3be; -$fa-var-level-down-alt: \f3be; -$fa-var-person-walking-arrow-right: \e552; -$fa-var-square-envelope: \f199; -$fa-var-envelope-square: \f199; -$fa-var-dice: \f522; -$fa-var-bowling-ball: \f436; -$fa-var-brain: \f5dc; -$fa-var-bandage: \f462; -$fa-var-band-aid: \f462; -$fa-var-calendar-minus: \f272; -$fa-var-circle-xmark: \f057; -$fa-var-times-circle: \f057; -$fa-var-xmark-circle: \f057; -$fa-var-gifts: \f79c; -$fa-var-hotel: \f594; -$fa-var-earth-asia: \f57e; -$fa-var-globe-asia: \f57e; -$fa-var-id-card-clip: \f47f; -$fa-var-id-card-alt: \f47f; -$fa-var-magnifying-glass-plus: \f00e; -$fa-var-search-plus: \f00e; -$fa-var-thumbs-up: \f164; -$fa-var-user-clock: \f4fd; -$fa-var-hand-dots: \f461; -$fa-var-allergies: \f461; -$fa-var-file-invoice: \f570; -$fa-var-window-minimize: \f2d1; -$fa-var-mug-saucer: \f0f4; -$fa-var-coffee: \f0f4; -$fa-var-brush: \f55d; -$fa-var-mask: \f6fa; -$fa-var-magnifying-glass-minus: \f010; -$fa-var-search-minus: \f010; -$fa-var-ruler-vertical: \f548; -$fa-var-user-large: \f406; -$fa-var-user-alt: \f406; -$fa-var-train-tram: \e5b4; -$fa-var-user-nurse: \f82f; -$fa-var-syringe: \f48e; -$fa-var-cloud-sun: \f6c4; -$fa-var-stopwatch-20: \e06f; -$fa-var-square-full: \f45c; -$fa-var-magnet: \f076; -$fa-var-jar: \e516; -$fa-var-note-sticky: \f249; -$fa-var-sticky-note: \f249; -$fa-var-bug-slash: \e490; -$fa-var-arrow-up-from-water-pump: \e4b6; -$fa-var-bone: \f5d7; -$fa-var-user-injured: \f728; -$fa-var-face-sad-tear: \f5b4; -$fa-var-sad-tear: \f5b4; -$fa-var-plane: \f072; -$fa-var-tent-arrows-down: \e581; -$fa-var-exclamation: \21; -$fa-var-arrows-spin: \e4bb; -$fa-var-print: \f02f; -$fa-var-turkish-lira-sign: \e2bb; -$fa-var-try: \e2bb; -$fa-var-turkish-lira: \e2bb; -$fa-var-dollar-sign: \24; -$fa-var-dollar: \24; -$fa-var-usd: \24; -$fa-var-x: \58; -$fa-var-magnifying-glass-dollar: \f688; -$fa-var-search-dollar: \f688; -$fa-var-users-gear: \f509; -$fa-var-users-cog: \f509; -$fa-var-person-military-pointing: \e54a; -$fa-var-building-columns: \f19c; -$fa-var-bank: \f19c; -$fa-var-institution: \f19c; -$fa-var-museum: \f19c; -$fa-var-university: \f19c; -$fa-var-umbrella: \f0e9; -$fa-var-trowel: \e589; -$fa-var-d: \44; -$fa-var-stapler: \e5af; -$fa-var-masks-theater: \f630; -$fa-var-theater-masks: \f630; -$fa-var-kip-sign: \e1c4; -$fa-var-hand-point-left: \f0a5; -$fa-var-handshake-simple: \f4c6; -$fa-var-handshake-alt: \f4c6; -$fa-var-jet-fighter: \f0fb; -$fa-var-fighter-jet: \f0fb; -$fa-var-square-share-nodes: \f1e1; -$fa-var-share-alt-square: \f1e1; -$fa-var-barcode: \f02a; -$fa-var-plus-minus: \e43c; -$fa-var-video: \f03d; -$fa-var-video-camera: \f03d; -$fa-var-graduation-cap: \f19d; -$fa-var-mortar-board: \f19d; -$fa-var-hand-holding-medical: \e05c; -$fa-var-person-circle-check: \e53e; -$fa-var-turn-up: \f3bf; -$fa-var-level-up-alt: \f3bf; - -$fa-var-monero: \f3d0; -$fa-var-hooli: \f427; -$fa-var-yelp: \f1e9; -$fa-var-cc-visa: \f1f0; -$fa-var-lastfm: \f202; -$fa-var-shopware: \f5b5; -$fa-var-creative-commons-nc: \f4e8; -$fa-var-aws: \f375; -$fa-var-redhat: \f7bc; -$fa-var-yoast: \f2b1; -$fa-var-cloudflare: \e07d; -$fa-var-ups: \f7e0; -$fa-var-wpexplorer: \f2de; -$fa-var-dyalog: \f399; -$fa-var-bity: \f37a; -$fa-var-stackpath: \f842; -$fa-var-buysellads: \f20d; -$fa-var-first-order: \f2b0; -$fa-var-modx: \f285; -$fa-var-guilded: \e07e; -$fa-var-vnv: \f40b; -$fa-var-square-js: \f3b9; -$fa-var-js-square: \f3b9; -$fa-var-microsoft: \f3ca; -$fa-var-qq: \f1d6; -$fa-var-orcid: \f8d2; -$fa-var-java: \f4e4; -$fa-var-invision: \f7b0; -$fa-var-creative-commons-pd-alt: \f4ed; -$fa-var-centercode: \f380; -$fa-var-glide-g: \f2a6; -$fa-var-drupal: \f1a9; -$fa-var-hire-a-helper: \f3b0; -$fa-var-creative-commons-by: \f4e7; -$fa-var-unity: \e049; -$fa-var-whmcs: \f40d; -$fa-var-rocketchat: \f3e8; -$fa-var-vk: \f189; -$fa-var-untappd: \f405; -$fa-var-mailchimp: \f59e; -$fa-var-css3-alt: \f38b; -$fa-var-square-reddit: \f1a2; -$fa-var-reddit-square: \f1a2; -$fa-var-vimeo-v: \f27d; -$fa-var-contao: \f26d; -$fa-var-square-font-awesome: \e5ad; -$fa-var-deskpro: \f38f; -$fa-var-sistrix: \f3ee; -$fa-var-square-instagram: \e055; -$fa-var-instagram-square: \e055; -$fa-var-battle-net: \f835; -$fa-var-the-red-yeti: \f69d; -$fa-var-square-hacker-news: \f3af; -$fa-var-hacker-news-square: \f3af; -$fa-var-edge: \f282; -$fa-var-napster: \f3d2; -$fa-var-square-snapchat: \f2ad; -$fa-var-snapchat-square: \f2ad; -$fa-var-google-plus-g: \f0d5; -$fa-var-artstation: \f77a; -$fa-var-markdown: \f60f; -$fa-var-sourcetree: \f7d3; -$fa-var-google-plus: \f2b3; -$fa-var-diaspora: \f791; -$fa-var-foursquare: \f180; -$fa-var-stack-overflow: \f16c; -$fa-var-github-alt: \f113; -$fa-var-phoenix-squadron: \f511; -$fa-var-pagelines: \f18c; -$fa-var-algolia: \f36c; -$fa-var-red-river: \f3e3; -$fa-var-creative-commons-sa: \f4ef; -$fa-var-safari: \f267; -$fa-var-google: \f1a0; -$fa-var-square-font-awesome-stroke: \f35c; -$fa-var-font-awesome-alt: \f35c; -$fa-var-atlassian: \f77b; -$fa-var-linkedin-in: \f0e1; -$fa-var-digital-ocean: \f391; -$fa-var-nimblr: \f5a8; -$fa-var-chromecast: \f838; -$fa-var-evernote: \f839; -$fa-var-hacker-news: \f1d4; -$fa-var-creative-commons-sampling: \f4f0; -$fa-var-adversal: \f36a; -$fa-var-creative-commons: \f25e; -$fa-var-watchman-monitoring: \e087; -$fa-var-fonticons: \f280; -$fa-var-weixin: \f1d7; -$fa-var-shirtsinbulk: \f214; -$fa-var-codepen: \f1cb; -$fa-var-git-alt: \f841; -$fa-var-lyft: \f3c3; -$fa-var-rev: \f5b2; -$fa-var-windows: \f17a; -$fa-var-wizards-of-the-coast: \f730; -$fa-var-square-viadeo: \f2aa; -$fa-var-viadeo-square: \f2aa; -$fa-var-meetup: \f2e0; -$fa-var-centos: \f789; -$fa-var-adn: \f170; -$fa-var-cloudsmith: \f384; -$fa-var-pied-piper-alt: \f1a8; -$fa-var-square-dribbble: \f397; -$fa-var-dribbble-square: \f397; -$fa-var-codiepie: \f284; -$fa-var-node: \f419; -$fa-var-mix: \f3cb; -$fa-var-steam: \f1b6; -$fa-var-cc-apple-pay: \f416; -$fa-var-scribd: \f28a; -$fa-var-openid: \f19b; -$fa-var-instalod: \e081; -$fa-var-expeditedssl: \f23e; -$fa-var-sellcast: \f2da; -$fa-var-square-twitter: \f081; -$fa-var-twitter-square: \f081; -$fa-var-r-project: \f4f7; -$fa-var-delicious: \f1a5; -$fa-var-freebsd: \f3a4; -$fa-var-vuejs: \f41f; -$fa-var-accusoft: \f369; -$fa-var-ioxhost: \f208; -$fa-var-fonticons-fi: \f3a2; -$fa-var-app-store: \f36f; -$fa-var-cc-mastercard: \f1f1; -$fa-var-itunes-note: \f3b5; -$fa-var-golang: \e40f; -$fa-var-kickstarter: \f3bb; -$fa-var-grav: \f2d6; -$fa-var-weibo: \f18a; -$fa-var-uncharted: \e084; -$fa-var-firstdraft: \f3a1; -$fa-var-square-youtube: \f431; -$fa-var-youtube-square: \f431; -$fa-var-wikipedia-w: \f266; -$fa-var-wpressr: \f3e4; -$fa-var-rendact: \f3e4; -$fa-var-angellist: \f209; -$fa-var-galactic-republic: \f50c; -$fa-var-nfc-directional: \e530; -$fa-var-skype: \f17e; -$fa-var-joget: \f3b7; -$fa-var-fedora: \f798; -$fa-var-stripe-s: \f42a; -$fa-var-meta: \e49b; -$fa-var-laravel: \f3bd; -$fa-var-hotjar: \f3b1; -$fa-var-bluetooth-b: \f294; -$fa-var-sticker-mule: \f3f7; -$fa-var-creative-commons-zero: \f4f3; -$fa-var-hips: \f452; -$fa-var-behance: \f1b4; -$fa-var-reddit: \f1a1; -$fa-var-discord: \f392; -$fa-var-chrome: \f268; -$fa-var-app-store-ios: \f370; -$fa-var-cc-discover: \f1f2; -$fa-var-wpbeginner: \f297; -$fa-var-confluence: \f78d; -$fa-var-mdb: \f8ca; -$fa-var-dochub: \f394; -$fa-var-accessible-icon: \f368; -$fa-var-ebay: \f4f4; -$fa-var-amazon: \f270; -$fa-var-unsplash: \e07c; -$fa-var-yarn: \f7e3; -$fa-var-square-steam: \f1b7; -$fa-var-steam-square: \f1b7; -$fa-var-500px: \f26e; -$fa-var-square-vimeo: \f194; -$fa-var-vimeo-square: \f194; -$fa-var-asymmetrik: \f372; -$fa-var-font-awesome: \f2b4; -$fa-var-font-awesome-flag: \f2b4; -$fa-var-font-awesome-logo-full: \f2b4; -$fa-var-gratipay: \f184; -$fa-var-apple: \f179; -$fa-var-hive: \e07f; -$fa-var-gitkraken: \f3a6; -$fa-var-keybase: \f4f5; -$fa-var-apple-pay: \f415; -$fa-var-padlet: \e4a0; -$fa-var-amazon-pay: \f42c; -$fa-var-square-github: \f092; -$fa-var-github-square: \f092; -$fa-var-stumbleupon: \f1a4; -$fa-var-fedex: \f797; -$fa-var-phoenix-framework: \f3dc; -$fa-var-shopify: \e057; -$fa-var-neos: \f612; -$fa-var-hackerrank: \f5f7; -$fa-var-researchgate: \f4f8; -$fa-var-swift: \f8e1; -$fa-var-angular: \f420; -$fa-var-speakap: \f3f3; -$fa-var-angrycreative: \f36e; -$fa-var-y-combinator: \f23b; -$fa-var-empire: \f1d1; -$fa-var-envira: \f299; -$fa-var-square-gitlab: \e5ae; -$fa-var-gitlab-square: \e5ae; -$fa-var-studiovinari: \f3f8; -$fa-var-pied-piper: \f2ae; -$fa-var-wordpress: \f19a; -$fa-var-product-hunt: \f288; -$fa-var-firefox: \f269; -$fa-var-linode: \f2b8; -$fa-var-goodreads: \f3a8; -$fa-var-square-odnoklassniki: \f264; -$fa-var-odnoklassniki-square: \f264; -$fa-var-jsfiddle: \f1cc; -$fa-var-sith: \f512; -$fa-var-themeisle: \f2b2; -$fa-var-page4: \f3d7; -$fa-var-hashnode: \e499; -$fa-var-react: \f41b; -$fa-var-cc-paypal: \f1f4; -$fa-var-squarespace: \f5be; -$fa-var-cc-stripe: \f1f5; -$fa-var-creative-commons-share: \f4f2; -$fa-var-bitcoin: \f379; -$fa-var-keycdn: \f3ba; -$fa-var-opera: \f26a; -$fa-var-itch-io: \f83a; -$fa-var-umbraco: \f8e8; -$fa-var-galactic-senate: \f50d; -$fa-var-ubuntu: \f7df; -$fa-var-draft2digital: \f396; -$fa-var-stripe: \f429; -$fa-var-houzz: \f27c; -$fa-var-gg: \f260; -$fa-var-dhl: \f790; -$fa-var-square-pinterest: \f0d3; -$fa-var-pinterest-square: \f0d3; -$fa-var-xing: \f168; -$fa-var-blackberry: \f37b; -$fa-var-creative-commons-pd: \f4ec; -$fa-var-playstation: \f3df; -$fa-var-quinscape: \f459; -$fa-var-less: \f41d; -$fa-var-blogger-b: \f37d; -$fa-var-opencart: \f23d; -$fa-var-vine: \f1ca; -$fa-var-paypal: \f1ed; -$fa-var-gitlab: \f296; -$fa-var-typo3: \f42b; -$fa-var-reddit-alien: \f281; -$fa-var-yahoo: \f19e; -$fa-var-dailymotion: \e052; -$fa-var-affiliatetheme: \f36b; -$fa-var-pied-piper-pp: \f1a7; -$fa-var-bootstrap: \f836; -$fa-var-odnoklassniki: \f263; -$fa-var-nfc-symbol: \e531; -$fa-var-ethereum: \f42e; -$fa-var-speaker-deck: \f83c; -$fa-var-creative-commons-nc-eu: \f4e9; -$fa-var-patreon: \f3d9; -$fa-var-avianex: \f374; -$fa-var-ello: \f5f1; -$fa-var-gofore: \f3a7; -$fa-var-bimobject: \f378; -$fa-var-facebook-f: \f39e; -$fa-var-square-google-plus: \f0d4; -$fa-var-google-plus-square: \f0d4; -$fa-var-mandalorian: \f50f; -$fa-var-first-order-alt: \f50a; -$fa-var-osi: \f41a; -$fa-var-google-wallet: \f1ee; -$fa-var-d-and-d-beyond: \f6ca; -$fa-var-periscope: \f3da; -$fa-var-fulcrum: \f50b; -$fa-var-cloudscale: \f383; -$fa-var-forumbee: \f211; -$fa-var-mizuni: \f3cc; -$fa-var-schlix: \f3ea; -$fa-var-square-xing: \f169; -$fa-var-xing-square: \f169; -$fa-var-bandcamp: \f2d5; -$fa-var-wpforms: \f298; -$fa-var-cloudversify: \f385; -$fa-var-usps: \f7e1; -$fa-var-megaport: \f5a3; -$fa-var-magento: \f3c4; -$fa-var-spotify: \f1bc; -$fa-var-optin-monster: \f23c; -$fa-var-fly: \f417; -$fa-var-aviato: \f421; -$fa-var-itunes: \f3b4; -$fa-var-cuttlefish: \f38c; -$fa-var-blogger: \f37c; -$fa-var-flickr: \f16e; -$fa-var-viber: \f409; -$fa-var-soundcloud: \f1be; -$fa-var-digg: \f1a6; -$fa-var-tencent-weibo: \f1d5; -$fa-var-symfony: \f83d; -$fa-var-maxcdn: \f136; -$fa-var-etsy: \f2d7; -$fa-var-facebook-messenger: \f39f; -$fa-var-audible: \f373; -$fa-var-think-peaks: \f731; -$fa-var-bilibili: \e3d9; -$fa-var-erlang: \f39d; -$fa-var-cotton-bureau: \f89e; -$fa-var-dashcube: \f210; -$fa-var-42-group: \e080; -$fa-var-innosoft: \e080; -$fa-var-stack-exchange: \f18d; -$fa-var-elementor: \f430; -$fa-var-square-pied-piper: \e01e; -$fa-var-pied-piper-square: \e01e; -$fa-var-creative-commons-nd: \f4eb; -$fa-var-palfed: \f3d8; -$fa-var-superpowers: \f2dd; -$fa-var-resolving: \f3e7; -$fa-var-xbox: \f412; -$fa-var-searchengin: \f3eb; -$fa-var-tiktok: \e07b; -$fa-var-square-facebook: \f082; -$fa-var-facebook-square: \f082; -$fa-var-renren: \f18b; -$fa-var-linux: \f17c; -$fa-var-glide: \f2a5; -$fa-var-linkedin: \f08c; -$fa-var-hubspot: \f3b2; -$fa-var-deploydog: \f38e; -$fa-var-twitch: \f1e8; -$fa-var-ravelry: \f2d9; -$fa-var-mixer: \e056; -$fa-var-square-lastfm: \f203; -$fa-var-lastfm-square: \f203; -$fa-var-vimeo: \f40a; -$fa-var-mendeley: \f7b3; -$fa-var-uniregistry: \f404; -$fa-var-figma: \f799; -$fa-var-creative-commons-remix: \f4ee; -$fa-var-cc-amazon-pay: \f42d; -$fa-var-dropbox: \f16b; -$fa-var-instagram: \f16d; -$fa-var-cmplid: \e360; -$fa-var-facebook: \f09a; -$fa-var-gripfire: \f3ac; -$fa-var-jedi-order: \f50e; -$fa-var-uikit: \f403; -$fa-var-fort-awesome-alt: \f3a3; -$fa-var-phabricator: \f3db; -$fa-var-ussunnah: \f407; -$fa-var-earlybirds: \f39a; -$fa-var-trade-federation: \f513; -$fa-var-autoprefixer: \f41c; -$fa-var-whatsapp: \f232; -$fa-var-slideshare: \f1e7; -$fa-var-google-play: \f3ab; -$fa-var-viadeo: \f2a9; -$fa-var-line: \f3c0; -$fa-var-google-drive: \f3aa; -$fa-var-servicestack: \f3ec; -$fa-var-simplybuilt: \f215; -$fa-var-bitbucket: \f171; -$fa-var-imdb: \f2d8; -$fa-var-deezer: \e077; -$fa-var-raspberry-pi: \f7bb; -$fa-var-jira: \f7b1; -$fa-var-docker: \f395; -$fa-var-screenpal: \e570; -$fa-var-bluetooth: \f293; -$fa-var-gitter: \f426; -$fa-var-d-and-d: \f38d; -$fa-var-microblog: \e01a; -$fa-var-cc-diners-club: \f24c; -$fa-var-gg-circle: \f261; -$fa-var-pied-piper-hat: \f4e5; -$fa-var-kickstarter-k: \f3bc; -$fa-var-yandex: \f413; -$fa-var-readme: \f4d5; -$fa-var-html5: \f13b; -$fa-var-sellsy: \f213; -$fa-var-sass: \f41e; -$fa-var-wirsindhandwerk: \e2d0; -$fa-var-wsh: \e2d0; -$fa-var-buromobelexperte: \f37f; -$fa-var-salesforce: \f83b; -$fa-var-octopus-deploy: \e082; -$fa-var-medapps: \f3c6; -$fa-var-ns8: \f3d5; -$fa-var-pinterest-p: \f231; -$fa-var-apper: \f371; -$fa-var-fort-awesome: \f286; -$fa-var-waze: \f83f; -$fa-var-cc-jcb: \f24b; -$fa-var-snapchat: \f2ab; -$fa-var-snapchat-ghost: \f2ab; -$fa-var-fantasy-flight-games: \f6dc; -$fa-var-rust: \e07a; -$fa-var-wix: \f5cf; -$fa-var-square-behance: \f1b5; -$fa-var-behance-square: \f1b5; -$fa-var-supple: \f3f9; -$fa-var-rebel: \f1d0; -$fa-var-css3: \f13c; -$fa-var-staylinked: \f3f5; -$fa-var-kaggle: \f5fa; -$fa-var-space-awesome: \e5ac; -$fa-var-deviantart: \f1bd; -$fa-var-cpanel: \f388; -$fa-var-goodreads-g: \f3a9; -$fa-var-square-git: \f1d2; -$fa-var-git-square: \f1d2; -$fa-var-square-tumblr: \f174; -$fa-var-tumblr-square: \f174; -$fa-var-trello: \f181; -$fa-var-creative-commons-nc-jp: \f4ea; -$fa-var-get-pocket: \f265; -$fa-var-perbyte: \e083; -$fa-var-grunt: \f3ad; -$fa-var-weebly: \f5cc; -$fa-var-connectdevelop: \f20e; -$fa-var-leanpub: \f212; -$fa-var-black-tie: \f27e; -$fa-var-themeco: \f5c6; -$fa-var-python: \f3e2; -$fa-var-android: \f17b; -$fa-var-bots: \e340; -$fa-var-free-code-camp: \f2c5; -$fa-var-hornbill: \f592; -$fa-var-js: \f3b8; -$fa-var-ideal: \e013; -$fa-var-git: \f1d3; -$fa-var-dev: \f6cc; -$fa-var-sketch: \f7c6; -$fa-var-yandex-international: \f414; -$fa-var-cc-amex: \f1f3; -$fa-var-uber: \f402; -$fa-var-github: \f09b; -$fa-var-php: \f457; -$fa-var-alipay: \f642; -$fa-var-youtube: \f167; -$fa-var-skyatlas: \f216; -$fa-var-firefox-browser: \e007; -$fa-var-replyd: \f3e6; -$fa-var-suse: \f7d6; -$fa-var-jenkins: \f3b6; -$fa-var-twitter: \f099; -$fa-var-rockrms: \f3e9; -$fa-var-pinterest: \f0d2; -$fa-var-buffer: \f837; -$fa-var-npm: \f3d4; -$fa-var-yammer: \f840; -$fa-var-btc: \f15a; -$fa-var-dribbble: \f17d; -$fa-var-stumbleupon-circle: \f1a3; -$fa-var-internet-explorer: \f26b; -$fa-var-telegram: \f2c6; -$fa-var-telegram-plane: \f2c6; -$fa-var-old-republic: \f510; -$fa-var-square-whatsapp: \f40c; -$fa-var-whatsapp-square: \f40c; -$fa-var-node-js: \f3d3; -$fa-var-edge-legacy: \e078; -$fa-var-slack: \f198; -$fa-var-slack-hash: \f198; -$fa-var-medrt: \f3c8; -$fa-var-usb: \f287; -$fa-var-tumblr: \f173; -$fa-var-vaadin: \f408; -$fa-var-quora: \f2c4; -$fa-var-reacteurope: \f75d; -$fa-var-medium: \f23a; -$fa-var-medium-m: \f23a; -$fa-var-amilia: \f36d; -$fa-var-mixcloud: \f289; -$fa-var-flipboard: \f44d; -$fa-var-viacoin: \f237; -$fa-var-critical-role: \f6c9; -$fa-var-sitrox: \e44a; -$fa-var-discourse: \f393; -$fa-var-joomla: \f1aa; -$fa-var-mastodon: \f4f6; -$fa-var-airbnb: \f834; -$fa-var-wolf-pack-battalion: \f514; -$fa-var-buy-n-large: \f8a6; -$fa-var-gulp: \f3ae; -$fa-var-creative-commons-sampling-plus: \f4f1; -$fa-var-strava: \f428; -$fa-var-ember: \f423; -$fa-var-canadian-maple-leaf: \f785; -$fa-var-teamspeak: \f4f9; -$fa-var-pushed: \f3e1; -$fa-var-wordpress-simple: \f411; -$fa-var-nutritionix: \f3d6; -$fa-var-wodu: \e088; -$fa-var-google-pay: \e079; -$fa-var-intercom: \f7af; -$fa-var-zhihu: \f63f; -$fa-var-korvue: \f42f; -$fa-var-pix: \e43a; -$fa-var-steam-symbol: \f3f6; - -$fa-icons: ( - "0": $fa-var-0, - "1": $fa-var-1, - "2": $fa-var-2, - "3": $fa-var-3, - "4": $fa-var-4, - "5": $fa-var-5, - "6": $fa-var-6, - "7": $fa-var-7, - "8": $fa-var-8, - "9": $fa-var-9, - "fill-drip": $fa-var-fill-drip, - "arrows-to-circle": $fa-var-arrows-to-circle, - "circle-chevron-right": $fa-var-circle-chevron-right, - "chevron-circle-right": $fa-var-chevron-circle-right, - "at": $fa-var-at, - "trash-can": $fa-var-trash-can, - "trash-alt": $fa-var-trash-alt, - "text-height": $fa-var-text-height, - "user-xmark": $fa-var-user-xmark, - "user-times": $fa-var-user-times, - "stethoscope": $fa-var-stethoscope, - "message": $fa-var-message, - "comment-alt": $fa-var-comment-alt, - "info": $fa-var-info, - "down-left-and-up-right-to-center": $fa-var-down-left-and-up-right-to-center, - "compress-alt": $fa-var-compress-alt, - "explosion": $fa-var-explosion, - "file-lines": $fa-var-file-lines, - "file-alt": $fa-var-file-alt, - "file-text": $fa-var-file-text, - "wave-square": $fa-var-wave-square, - "ring": $fa-var-ring, - "building-un": $fa-var-building-un, - "dice-three": $fa-var-dice-three, - "calendar-days": $fa-var-calendar-days, - "calendar-alt": $fa-var-calendar-alt, - "anchor-circle-check": $fa-var-anchor-circle-check, - "building-circle-arrow-right": $fa-var-building-circle-arrow-right, - "volleyball": $fa-var-volleyball, - "volleyball-ball": $fa-var-volleyball-ball, - "arrows-up-to-line": $fa-var-arrows-up-to-line, - "sort-down": $fa-var-sort-down, - "sort-desc": $fa-var-sort-desc, - "circle-minus": $fa-var-circle-minus, - "minus-circle": $fa-var-minus-circle, - "door-open": $fa-var-door-open, - "right-from-bracket": $fa-var-right-from-bracket, - "sign-out-alt": $fa-var-sign-out-alt, - "atom": $fa-var-atom, - "soap": $fa-var-soap, - "icons": $fa-var-icons, - "heart-music-camera-bolt": $fa-var-heart-music-camera-bolt, - "microphone-lines-slash": $fa-var-microphone-lines-slash, - "microphone-alt-slash": $fa-var-microphone-alt-slash, - "bridge-circle-check": $fa-var-bridge-circle-check, - "pump-medical": $fa-var-pump-medical, - "fingerprint": $fa-var-fingerprint, - "hand-point-right": $fa-var-hand-point-right, - "magnifying-glass-location": $fa-var-magnifying-glass-location, - "search-location": $fa-var-search-location, - "forward-step": $fa-var-forward-step, - "step-forward": $fa-var-step-forward, - "face-smile-beam": $fa-var-face-smile-beam, - "smile-beam": $fa-var-smile-beam, - "flag-checkered": $fa-var-flag-checkered, - "football": $fa-var-football, - "football-ball": $fa-var-football-ball, - "school-circle-exclamation": $fa-var-school-circle-exclamation, - "crop": $fa-var-crop, - "angles-down": $fa-var-angles-down, - "angle-double-down": $fa-var-angle-double-down, - "users-rectangle": $fa-var-users-rectangle, - "people-roof": $fa-var-people-roof, - "people-line": $fa-var-people-line, - "beer-mug-empty": $fa-var-beer-mug-empty, - "beer": $fa-var-beer, - "diagram-predecessor": $fa-var-diagram-predecessor, - "arrow-up-long": $fa-var-arrow-up-long, - "long-arrow-up": $fa-var-long-arrow-up, - "fire-flame-simple": $fa-var-fire-flame-simple, - "burn": $fa-var-burn, - "person": $fa-var-person, - "male": $fa-var-male, - "laptop": $fa-var-laptop, - "file-csv": $fa-var-file-csv, - "menorah": $fa-var-menorah, - "truck-plane": $fa-var-truck-plane, - "record-vinyl": $fa-var-record-vinyl, - "face-grin-stars": $fa-var-face-grin-stars, - "grin-stars": $fa-var-grin-stars, - "bong": $fa-var-bong, - "spaghetti-monster-flying": $fa-var-spaghetti-monster-flying, - "pastafarianism": $fa-var-pastafarianism, - "arrow-down-up-across-line": $fa-var-arrow-down-up-across-line, - "spoon": $fa-var-spoon, - "utensil-spoon": $fa-var-utensil-spoon, - "jar-wheat": $fa-var-jar-wheat, - "envelopes-bulk": $fa-var-envelopes-bulk, - "mail-bulk": $fa-var-mail-bulk, - "file-circle-exclamation": $fa-var-file-circle-exclamation, - "circle-h": $fa-var-circle-h, - "hospital-symbol": $fa-var-hospital-symbol, - "pager": $fa-var-pager, - "address-book": $fa-var-address-book, - "contact-book": $fa-var-contact-book, - "strikethrough": $fa-var-strikethrough, - "k": $fa-var-k, - "landmark-flag": $fa-var-landmark-flag, - "pencil": $fa-var-pencil, - "pencil-alt": $fa-var-pencil-alt, - "backward": $fa-var-backward, - "caret-right": $fa-var-caret-right, - "comments": $fa-var-comments, - "paste": $fa-var-paste, - "file-clipboard": $fa-var-file-clipboard, - "code-pull-request": $fa-var-code-pull-request, - "clipboard-list": $fa-var-clipboard-list, - "truck-ramp-box": $fa-var-truck-ramp-box, - "truck-loading": $fa-var-truck-loading, - "user-check": $fa-var-user-check, - "vial-virus": $fa-var-vial-virus, - "sheet-plastic": $fa-var-sheet-plastic, - "blog": $fa-var-blog, - "user-ninja": $fa-var-user-ninja, - "person-arrow-up-from-line": $fa-var-person-arrow-up-from-line, - "scroll-torah": $fa-var-scroll-torah, - "torah": $fa-var-torah, - "broom-ball": $fa-var-broom-ball, - "quidditch": $fa-var-quidditch, - "quidditch-broom-ball": $fa-var-quidditch-broom-ball, - "toggle-off": $fa-var-toggle-off, - "box-archive": $fa-var-box-archive, - "archive": $fa-var-archive, - "person-drowning": $fa-var-person-drowning, - "arrow-down-9-1": $fa-var-arrow-down-9-1, - "sort-numeric-desc": $fa-var-sort-numeric-desc, - "sort-numeric-down-alt": $fa-var-sort-numeric-down-alt, - "face-grin-tongue-squint": $fa-var-face-grin-tongue-squint, - "grin-tongue-squint": $fa-var-grin-tongue-squint, - "spray-can": $fa-var-spray-can, - "truck-monster": $fa-var-truck-monster, - "w": $fa-var-w, - "earth-africa": $fa-var-earth-africa, - "globe-africa": $fa-var-globe-africa, - "rainbow": $fa-var-rainbow, - "circle-notch": $fa-var-circle-notch, - "tablet-screen-button": $fa-var-tablet-screen-button, - "tablet-alt": $fa-var-tablet-alt, - "paw": $fa-var-paw, - "cloud": $fa-var-cloud, - "trowel-bricks": $fa-var-trowel-bricks, - "face-flushed": $fa-var-face-flushed, - "flushed": $fa-var-flushed, - "hospital-user": $fa-var-hospital-user, - "tent-arrow-left-right": $fa-var-tent-arrow-left-right, - "gavel": $fa-var-gavel, - "legal": $fa-var-legal, - "binoculars": $fa-var-binoculars, - "microphone-slash": $fa-var-microphone-slash, - "box-tissue": $fa-var-box-tissue, - "motorcycle": $fa-var-motorcycle, - "bell-concierge": $fa-var-bell-concierge, - "concierge-bell": $fa-var-concierge-bell, - "pen-ruler": $fa-var-pen-ruler, - "pencil-ruler": $fa-var-pencil-ruler, - "people-arrows": $fa-var-people-arrows, - "people-arrows-left-right": $fa-var-people-arrows-left-right, - "mars-and-venus-burst": $fa-var-mars-and-venus-burst, - "square-caret-right": $fa-var-square-caret-right, - "caret-square-right": $fa-var-caret-square-right, - "scissors": $fa-var-scissors, - "cut": $fa-var-cut, - "sun-plant-wilt": $fa-var-sun-plant-wilt, - "toilets-portable": $fa-var-toilets-portable, - "hockey-puck": $fa-var-hockey-puck, - "table": $fa-var-table, - "magnifying-glass-arrow-right": $fa-var-magnifying-glass-arrow-right, - "tachograph-digital": $fa-var-tachograph-digital, - "digital-tachograph": $fa-var-digital-tachograph, - "users-slash": $fa-var-users-slash, - "clover": $fa-var-clover, - "reply": $fa-var-reply, - "mail-reply": $fa-var-mail-reply, - "star-and-crescent": $fa-var-star-and-crescent, - "house-fire": $fa-var-house-fire, - "square-minus": $fa-var-square-minus, - "minus-square": $fa-var-minus-square, - "helicopter": $fa-var-helicopter, - "compass": $fa-var-compass, - "square-caret-down": $fa-var-square-caret-down, - "caret-square-down": $fa-var-caret-square-down, - "file-circle-question": $fa-var-file-circle-question, - "laptop-code": $fa-var-laptop-code, - "swatchbook": $fa-var-swatchbook, - "prescription-bottle": $fa-var-prescription-bottle, - "bars": $fa-var-bars, - "navicon": $fa-var-navicon, - "people-group": $fa-var-people-group, - "hourglass-end": $fa-var-hourglass-end, - "hourglass-3": $fa-var-hourglass-3, - "heart-crack": $fa-var-heart-crack, - "heart-broken": $fa-var-heart-broken, - "square-up-right": $fa-var-square-up-right, - "external-link-square-alt": $fa-var-external-link-square-alt, - "face-kiss-beam": $fa-var-face-kiss-beam, - "kiss-beam": $fa-var-kiss-beam, - "film": $fa-var-film, - "ruler-horizontal": $fa-var-ruler-horizontal, - "people-robbery": $fa-var-people-robbery, - "lightbulb": $fa-var-lightbulb, - "caret-left": $fa-var-caret-left, - "circle-exclamation": $fa-var-circle-exclamation, - "exclamation-circle": $fa-var-exclamation-circle, - "school-circle-xmark": $fa-var-school-circle-xmark, - "arrow-right-from-bracket": $fa-var-arrow-right-from-bracket, - "sign-out": $fa-var-sign-out, - "circle-chevron-down": $fa-var-circle-chevron-down, - "chevron-circle-down": $fa-var-chevron-circle-down, - "unlock-keyhole": $fa-var-unlock-keyhole, - "unlock-alt": $fa-var-unlock-alt, - "cloud-showers-heavy": $fa-var-cloud-showers-heavy, - "headphones-simple": $fa-var-headphones-simple, - "headphones-alt": $fa-var-headphones-alt, - "sitemap": $fa-var-sitemap, - "circle-dollar-to-slot": $fa-var-circle-dollar-to-slot, - "donate": $fa-var-donate, - "memory": $fa-var-memory, - "road-spikes": $fa-var-road-spikes, - "fire-burner": $fa-var-fire-burner, - "flag": $fa-var-flag, - "hanukiah": $fa-var-hanukiah, - "feather": $fa-var-feather, - "volume-low": $fa-var-volume-low, - "volume-down": $fa-var-volume-down, - "comment-slash": $fa-var-comment-slash, - "cloud-sun-rain": $fa-var-cloud-sun-rain, - "compress": $fa-var-compress, - "wheat-awn": $fa-var-wheat-awn, - "wheat-alt": $fa-var-wheat-alt, - "ankh": $fa-var-ankh, - "hands-holding-child": $fa-var-hands-holding-child, - "asterisk": $fa-var-asterisk, - "square-check": $fa-var-square-check, - "check-square": $fa-var-check-square, - "peseta-sign": $fa-var-peseta-sign, - "heading": $fa-var-heading, - "header": $fa-var-header, - "ghost": $fa-var-ghost, - "list": $fa-var-list, - "list-squares": $fa-var-list-squares, - "square-phone-flip": $fa-var-square-phone-flip, - "phone-square-alt": $fa-var-phone-square-alt, - "cart-plus": $fa-var-cart-plus, - "gamepad": $fa-var-gamepad, - "circle-dot": $fa-var-circle-dot, - "dot-circle": $fa-var-dot-circle, - "face-dizzy": $fa-var-face-dizzy, - "dizzy": $fa-var-dizzy, - "egg": $fa-var-egg, - "house-medical-circle-xmark": $fa-var-house-medical-circle-xmark, - "campground": $fa-var-campground, - "folder-plus": $fa-var-folder-plus, - "futbol": $fa-var-futbol, - "futbol-ball": $fa-var-futbol-ball, - "soccer-ball": $fa-var-soccer-ball, - "paintbrush": $fa-var-paintbrush, - "paint-brush": $fa-var-paint-brush, - "lock": $fa-var-lock, - "gas-pump": $fa-var-gas-pump, - "hot-tub-person": $fa-var-hot-tub-person, - "hot-tub": $fa-var-hot-tub, - "map-location": $fa-var-map-location, - "map-marked": $fa-var-map-marked, - "house-flood-water": $fa-var-house-flood-water, - "tree": $fa-var-tree, - "bridge-lock": $fa-var-bridge-lock, - "sack-dollar": $fa-var-sack-dollar, - "pen-to-square": $fa-var-pen-to-square, - "edit": $fa-var-edit, - "car-side": $fa-var-car-side, - "share-nodes": $fa-var-share-nodes, - "share-alt": $fa-var-share-alt, - "heart-circle-minus": $fa-var-heart-circle-minus, - "hourglass-half": $fa-var-hourglass-half, - "hourglass-2": $fa-var-hourglass-2, - "microscope": $fa-var-microscope, - "sink": $fa-var-sink, - "bag-shopping": $fa-var-bag-shopping, - "shopping-bag": $fa-var-shopping-bag, - "arrow-down-z-a": $fa-var-arrow-down-z-a, - "sort-alpha-desc": $fa-var-sort-alpha-desc, - "sort-alpha-down-alt": $fa-var-sort-alpha-down-alt, - "mitten": $fa-var-mitten, - "person-rays": $fa-var-person-rays, - "users": $fa-var-users, - "eye-slash": $fa-var-eye-slash, - "flask-vial": $fa-var-flask-vial, - "hand": $fa-var-hand, - "hand-paper": $fa-var-hand-paper, - "om": $fa-var-om, - "worm": $fa-var-worm, - "house-circle-xmark": $fa-var-house-circle-xmark, - "plug": $fa-var-plug, - "chevron-up": $fa-var-chevron-up, - "hand-spock": $fa-var-hand-spock, - "stopwatch": $fa-var-stopwatch, - "face-kiss": $fa-var-face-kiss, - "kiss": $fa-var-kiss, - "bridge-circle-xmark": $fa-var-bridge-circle-xmark, - "face-grin-tongue": $fa-var-face-grin-tongue, - "grin-tongue": $fa-var-grin-tongue, - "chess-bishop": $fa-var-chess-bishop, - "face-grin-wink": $fa-var-face-grin-wink, - "grin-wink": $fa-var-grin-wink, - "ear-deaf": $fa-var-ear-deaf, - "deaf": $fa-var-deaf, - "deafness": $fa-var-deafness, - "hard-of-hearing": $fa-var-hard-of-hearing, - "road-circle-check": $fa-var-road-circle-check, - "dice-five": $fa-var-dice-five, - "square-rss": $fa-var-square-rss, - "rss-square": $fa-var-rss-square, - "land-mine-on": $fa-var-land-mine-on, - "i-cursor": $fa-var-i-cursor, - "stamp": $fa-var-stamp, - "stairs": $fa-var-stairs, - "i": $fa-var-i, - "hryvnia-sign": $fa-var-hryvnia-sign, - "hryvnia": $fa-var-hryvnia, - "pills": $fa-var-pills, - "face-grin-wide": $fa-var-face-grin-wide, - "grin-alt": $fa-var-grin-alt, - "tooth": $fa-var-tooth, - "v": $fa-var-v, - "bicycle": $fa-var-bicycle, - "staff-snake": $fa-var-staff-snake, - "rod-asclepius": $fa-var-rod-asclepius, - "rod-snake": $fa-var-rod-snake, - "staff-aesculapius": $fa-var-staff-aesculapius, - "head-side-cough-slash": $fa-var-head-side-cough-slash, - "truck-medical": $fa-var-truck-medical, - "ambulance": $fa-var-ambulance, - "wheat-awn-circle-exclamation": $fa-var-wheat-awn-circle-exclamation, - "snowman": $fa-var-snowman, - "mortar-pestle": $fa-var-mortar-pestle, - "road-barrier": $fa-var-road-barrier, - "school": $fa-var-school, - "igloo": $fa-var-igloo, - "joint": $fa-var-joint, - "angle-right": $fa-var-angle-right, - "horse": $fa-var-horse, - "q": $fa-var-q, - "g": $fa-var-g, - "notes-medical": $fa-var-notes-medical, - "temperature-half": $fa-var-temperature-half, - "temperature-2": $fa-var-temperature-2, - "thermometer-2": $fa-var-thermometer-2, - "thermometer-half": $fa-var-thermometer-half, - "dong-sign": $fa-var-dong-sign, - "capsules": $fa-var-capsules, - "poo-storm": $fa-var-poo-storm, - "poo-bolt": $fa-var-poo-bolt, - "face-frown-open": $fa-var-face-frown-open, - "frown-open": $fa-var-frown-open, - "hand-point-up": $fa-var-hand-point-up, - "money-bill": $fa-var-money-bill, - "bookmark": $fa-var-bookmark, - "align-justify": $fa-var-align-justify, - "umbrella-beach": $fa-var-umbrella-beach, - "helmet-un": $fa-var-helmet-un, - "bullseye": $fa-var-bullseye, - "bacon": $fa-var-bacon, - "hand-point-down": $fa-var-hand-point-down, - "arrow-up-from-bracket": $fa-var-arrow-up-from-bracket, - "folder": $fa-var-folder, - "folder-blank": $fa-var-folder-blank, - "file-waveform": $fa-var-file-waveform, - "file-medical-alt": $fa-var-file-medical-alt, - "radiation": $fa-var-radiation, - "chart-simple": $fa-var-chart-simple, - "mars-stroke": $fa-var-mars-stroke, - "vial": $fa-var-vial, - "gauge": $fa-var-gauge, - "dashboard": $fa-var-dashboard, - "gauge-med": $fa-var-gauge-med, - "tachometer-alt-average": $fa-var-tachometer-alt-average, - "wand-magic-sparkles": $fa-var-wand-magic-sparkles, - "magic-wand-sparkles": $fa-var-magic-wand-sparkles, - "e": $fa-var-e, - "pen-clip": $fa-var-pen-clip, - "pen-alt": $fa-var-pen-alt, - "bridge-circle-exclamation": $fa-var-bridge-circle-exclamation, - "user": $fa-var-user, - "school-circle-check": $fa-var-school-circle-check, - "dumpster": $fa-var-dumpster, - "van-shuttle": $fa-var-van-shuttle, - "shuttle-van": $fa-var-shuttle-van, - "building-user": $fa-var-building-user, - "square-caret-left": $fa-var-square-caret-left, - "caret-square-left": $fa-var-caret-square-left, - "highlighter": $fa-var-highlighter, - "key": $fa-var-key, - "bullhorn": $fa-var-bullhorn, - "globe": $fa-var-globe, - "synagogue": $fa-var-synagogue, - "person-half-dress": $fa-var-person-half-dress, - "road-bridge": $fa-var-road-bridge, - "location-arrow": $fa-var-location-arrow, - "c": $fa-var-c, - "tablet-button": $fa-var-tablet-button, - "building-lock": $fa-var-building-lock, - "pizza-slice": $fa-var-pizza-slice, - "money-bill-wave": $fa-var-money-bill-wave, - "chart-area": $fa-var-chart-area, - "area-chart": $fa-var-area-chart, - "house-flag": $fa-var-house-flag, - "person-circle-minus": $fa-var-person-circle-minus, - "ban": $fa-var-ban, - "cancel": $fa-var-cancel, - "camera-rotate": $fa-var-camera-rotate, - "spray-can-sparkles": $fa-var-spray-can-sparkles, - "air-freshener": $fa-var-air-freshener, - "star": $fa-var-star, - "repeat": $fa-var-repeat, - "cross": $fa-var-cross, - "box": $fa-var-box, - "venus-mars": $fa-var-venus-mars, - "arrow-pointer": $fa-var-arrow-pointer, - "mouse-pointer": $fa-var-mouse-pointer, - "maximize": $fa-var-maximize, - "expand-arrows-alt": $fa-var-expand-arrows-alt, - "charging-station": $fa-var-charging-station, - "shapes": $fa-var-shapes, - "triangle-circle-square": $fa-var-triangle-circle-square, - "shuffle": $fa-var-shuffle, - "random": $fa-var-random, - "person-running": $fa-var-person-running, - "running": $fa-var-running, - "mobile-retro": $fa-var-mobile-retro, - "grip-lines-vertical": $fa-var-grip-lines-vertical, - "spider": $fa-var-spider, - "hands-bound": $fa-var-hands-bound, - "file-invoice-dollar": $fa-var-file-invoice-dollar, - "plane-circle-exclamation": $fa-var-plane-circle-exclamation, - "x-ray": $fa-var-x-ray, - "spell-check": $fa-var-spell-check, - "slash": $fa-var-slash, - "computer-mouse": $fa-var-computer-mouse, - "mouse": $fa-var-mouse, - "arrow-right-to-bracket": $fa-var-arrow-right-to-bracket, - "sign-in": $fa-var-sign-in, - "shop-slash": $fa-var-shop-slash, - "store-alt-slash": $fa-var-store-alt-slash, - "server": $fa-var-server, - "virus-covid-slash": $fa-var-virus-covid-slash, - "shop-lock": $fa-var-shop-lock, - "hourglass-start": $fa-var-hourglass-start, - "hourglass-1": $fa-var-hourglass-1, - "blender-phone": $fa-var-blender-phone, - "building-wheat": $fa-var-building-wheat, - "person-breastfeeding": $fa-var-person-breastfeeding, - "right-to-bracket": $fa-var-right-to-bracket, - "sign-in-alt": $fa-var-sign-in-alt, - "venus": $fa-var-venus, - "passport": $fa-var-passport, - "heart-pulse": $fa-var-heart-pulse, - "heartbeat": $fa-var-heartbeat, - "people-carry-box": $fa-var-people-carry-box, - "people-carry": $fa-var-people-carry, - "temperature-high": $fa-var-temperature-high, - "microchip": $fa-var-microchip, - "crown": $fa-var-crown, - "weight-hanging": $fa-var-weight-hanging, - "xmarks-lines": $fa-var-xmarks-lines, - "file-prescription": $fa-var-file-prescription, - "weight-scale": $fa-var-weight-scale, - "weight": $fa-var-weight, - "user-group": $fa-var-user-group, - "user-friends": $fa-var-user-friends, - "arrow-up-a-z": $fa-var-arrow-up-a-z, - "sort-alpha-up": $fa-var-sort-alpha-up, - "chess-knight": $fa-var-chess-knight, - "face-laugh-squint": $fa-var-face-laugh-squint, - "laugh-squint": $fa-var-laugh-squint, - "wheelchair": $fa-var-wheelchair, - "circle-arrow-up": $fa-var-circle-arrow-up, - "arrow-circle-up": $fa-var-arrow-circle-up, - "toggle-on": $fa-var-toggle-on, - "person-walking": $fa-var-person-walking, - "walking": $fa-var-walking, - "l": $fa-var-l, - "fire": $fa-var-fire, - "bed-pulse": $fa-var-bed-pulse, - "procedures": $fa-var-procedures, - "shuttle-space": $fa-var-shuttle-space, - "space-shuttle": $fa-var-space-shuttle, - "face-laugh": $fa-var-face-laugh, - "laugh": $fa-var-laugh, - "folder-open": $fa-var-folder-open, - "heart-circle-plus": $fa-var-heart-circle-plus, - "code-fork": $fa-var-code-fork, - "city": $fa-var-city, - "microphone-lines": $fa-var-microphone-lines, - "microphone-alt": $fa-var-microphone-alt, - "pepper-hot": $fa-var-pepper-hot, - "unlock": $fa-var-unlock, - "colon-sign": $fa-var-colon-sign, - "headset": $fa-var-headset, - "store-slash": $fa-var-store-slash, - "road-circle-xmark": $fa-var-road-circle-xmark, - "user-minus": $fa-var-user-minus, - "mars-stroke-up": $fa-var-mars-stroke-up, - "mars-stroke-v": $fa-var-mars-stroke-v, - "champagne-glasses": $fa-var-champagne-glasses, - "glass-cheers": $fa-var-glass-cheers, - "clipboard": $fa-var-clipboard, - "house-circle-exclamation": $fa-var-house-circle-exclamation, - "file-arrow-up": $fa-var-file-arrow-up, - "file-upload": $fa-var-file-upload, - "wifi": $fa-var-wifi, - "wifi-3": $fa-var-wifi-3, - "wifi-strong": $fa-var-wifi-strong, - "bath": $fa-var-bath, - "bathtub": $fa-var-bathtub, - "underline": $fa-var-underline, - "user-pen": $fa-var-user-pen, - "user-edit": $fa-var-user-edit, - "signature": $fa-var-signature, - "stroopwafel": $fa-var-stroopwafel, - "bold": $fa-var-bold, - "anchor-lock": $fa-var-anchor-lock, - "building-ngo": $fa-var-building-ngo, - "manat-sign": $fa-var-manat-sign, - "not-equal": $fa-var-not-equal, - "border-top-left": $fa-var-border-top-left, - "border-style": $fa-var-border-style, - "map-location-dot": $fa-var-map-location-dot, - "map-marked-alt": $fa-var-map-marked-alt, - "jedi": $fa-var-jedi, - "square-poll-vertical": $fa-var-square-poll-vertical, - "poll": $fa-var-poll, - "mug-hot": $fa-var-mug-hot, - "car-battery": $fa-var-car-battery, - "battery-car": $fa-var-battery-car, - "gift": $fa-var-gift, - "dice-two": $fa-var-dice-two, - "chess-queen": $fa-var-chess-queen, - "glasses": $fa-var-glasses, - "chess-board": $fa-var-chess-board, - "building-circle-check": $fa-var-building-circle-check, - "person-chalkboard": $fa-var-person-chalkboard, - "mars-stroke-right": $fa-var-mars-stroke-right, - "mars-stroke-h": $fa-var-mars-stroke-h, - "hand-back-fist": $fa-var-hand-back-fist, - "hand-rock": $fa-var-hand-rock, - "square-caret-up": $fa-var-square-caret-up, - "caret-square-up": $fa-var-caret-square-up, - "cloud-showers-water": $fa-var-cloud-showers-water, - "chart-bar": $fa-var-chart-bar, - "bar-chart": $fa-var-bar-chart, - "hands-bubbles": $fa-var-hands-bubbles, - "hands-wash": $fa-var-hands-wash, - "less-than-equal": $fa-var-less-than-equal, - "train": $fa-var-train, - "eye-low-vision": $fa-var-eye-low-vision, - "low-vision": $fa-var-low-vision, - "crow": $fa-var-crow, - "sailboat": $fa-var-sailboat, - "window-restore": $fa-var-window-restore, - "square-plus": $fa-var-square-plus, - "plus-square": $fa-var-plus-square, - "torii-gate": $fa-var-torii-gate, - "frog": $fa-var-frog, - "bucket": $fa-var-bucket, - "image": $fa-var-image, - "microphone": $fa-var-microphone, - "cow": $fa-var-cow, - "caret-up": $fa-var-caret-up, - "screwdriver": $fa-var-screwdriver, - "folder-closed": $fa-var-folder-closed, - "house-tsunami": $fa-var-house-tsunami, - "square-nfi": $fa-var-square-nfi, - "arrow-up-from-ground-water": $fa-var-arrow-up-from-ground-water, - "martini-glass": $fa-var-martini-glass, - "glass-martini-alt": $fa-var-glass-martini-alt, - "rotate-left": $fa-var-rotate-left, - "rotate-back": $fa-var-rotate-back, - "rotate-backward": $fa-var-rotate-backward, - "undo-alt": $fa-var-undo-alt, - "table-columns": $fa-var-table-columns, - "columns": $fa-var-columns, - "lemon": $fa-var-lemon, - "head-side-mask": $fa-var-head-side-mask, - "handshake": $fa-var-handshake, - "gem": $fa-var-gem, - "dolly": $fa-var-dolly, - "dolly-box": $fa-var-dolly-box, - "smoking": $fa-var-smoking, - "minimize": $fa-var-minimize, - "compress-arrows-alt": $fa-var-compress-arrows-alt, - "monument": $fa-var-monument, - "snowplow": $fa-var-snowplow, - "angles-right": $fa-var-angles-right, - "angle-double-right": $fa-var-angle-double-right, - "cannabis": $fa-var-cannabis, - "circle-play": $fa-var-circle-play, - "play-circle": $fa-var-play-circle, - "tablets": $fa-var-tablets, - "ethernet": $fa-var-ethernet, - "euro-sign": $fa-var-euro-sign, - "eur": $fa-var-eur, - "euro": $fa-var-euro, - "chair": $fa-var-chair, - "circle-check": $fa-var-circle-check, - "check-circle": $fa-var-check-circle, - "circle-stop": $fa-var-circle-stop, - "stop-circle": $fa-var-stop-circle, - "compass-drafting": $fa-var-compass-drafting, - "drafting-compass": $fa-var-drafting-compass, - "plate-wheat": $fa-var-plate-wheat, - "icicles": $fa-var-icicles, - "person-shelter": $fa-var-person-shelter, - "neuter": $fa-var-neuter, - "id-badge": $fa-var-id-badge, - "marker": $fa-var-marker, - "face-laugh-beam": $fa-var-face-laugh-beam, - "laugh-beam": $fa-var-laugh-beam, - "helicopter-symbol": $fa-var-helicopter-symbol, - "universal-access": $fa-var-universal-access, - "circle-chevron-up": $fa-var-circle-chevron-up, - "chevron-circle-up": $fa-var-chevron-circle-up, - "lari-sign": $fa-var-lari-sign, - "volcano": $fa-var-volcano, - "person-walking-dashed-line-arrow-right": $fa-var-person-walking-dashed-line-arrow-right, - "sterling-sign": $fa-var-sterling-sign, - "gbp": $fa-var-gbp, - "pound-sign": $fa-var-pound-sign, - "viruses": $fa-var-viruses, - "square-person-confined": $fa-var-square-person-confined, - "user-tie": $fa-var-user-tie, - "arrow-down-long": $fa-var-arrow-down-long, - "long-arrow-down": $fa-var-long-arrow-down, - "tent-arrow-down-to-line": $fa-var-tent-arrow-down-to-line, - "certificate": $fa-var-certificate, - "reply-all": $fa-var-reply-all, - "mail-reply-all": $fa-var-mail-reply-all, - "suitcase": $fa-var-suitcase, - "person-skating": $fa-var-person-skating, - "skating": $fa-var-skating, - "filter-circle-dollar": $fa-var-filter-circle-dollar, - "funnel-dollar": $fa-var-funnel-dollar, - "camera-retro": $fa-var-camera-retro, - "circle-arrow-down": $fa-var-circle-arrow-down, - "arrow-circle-down": $fa-var-arrow-circle-down, - "file-import": $fa-var-file-import, - "arrow-right-to-file": $fa-var-arrow-right-to-file, - "square-arrow-up-right": $fa-var-square-arrow-up-right, - "external-link-square": $fa-var-external-link-square, - "box-open": $fa-var-box-open, - "scroll": $fa-var-scroll, - "spa": $fa-var-spa, - "location-pin-lock": $fa-var-location-pin-lock, - "pause": $fa-var-pause, - "hill-avalanche": $fa-var-hill-avalanche, - "temperature-empty": $fa-var-temperature-empty, - "temperature-0": $fa-var-temperature-0, - "thermometer-0": $fa-var-thermometer-0, - "thermometer-empty": $fa-var-thermometer-empty, - "bomb": $fa-var-bomb, - "registered": $fa-var-registered, - "address-card": $fa-var-address-card, - "contact-card": $fa-var-contact-card, - "vcard": $fa-var-vcard, - "scale-unbalanced-flip": $fa-var-scale-unbalanced-flip, - "balance-scale-right": $fa-var-balance-scale-right, - "subscript": $fa-var-subscript, - "diamond-turn-right": $fa-var-diamond-turn-right, - "directions": $fa-var-directions, - "burst": $fa-var-burst, - "house-laptop": $fa-var-house-laptop, - "laptop-house": $fa-var-laptop-house, - "face-tired": $fa-var-face-tired, - "tired": $fa-var-tired, - "money-bills": $fa-var-money-bills, - "smog": $fa-var-smog, - "crutch": $fa-var-crutch, - "cloud-arrow-up": $fa-var-cloud-arrow-up, - "cloud-upload": $fa-var-cloud-upload, - "cloud-upload-alt": $fa-var-cloud-upload-alt, - "palette": $fa-var-palette, - "arrows-turn-right": $fa-var-arrows-turn-right, - "vest": $fa-var-vest, - "ferry": $fa-var-ferry, - "arrows-down-to-people": $fa-var-arrows-down-to-people, - "seedling": $fa-var-seedling, - "sprout": $fa-var-sprout, - "left-right": $fa-var-left-right, - "arrows-alt-h": $fa-var-arrows-alt-h, - "boxes-packing": $fa-var-boxes-packing, - "circle-arrow-left": $fa-var-circle-arrow-left, - "arrow-circle-left": $fa-var-arrow-circle-left, - "group-arrows-rotate": $fa-var-group-arrows-rotate, - "bowl-food": $fa-var-bowl-food, - "candy-cane": $fa-var-candy-cane, - "arrow-down-wide-short": $fa-var-arrow-down-wide-short, - "sort-amount-asc": $fa-var-sort-amount-asc, - "sort-amount-down": $fa-var-sort-amount-down, - "cloud-bolt": $fa-var-cloud-bolt, - "thunderstorm": $fa-var-thunderstorm, - "text-slash": $fa-var-text-slash, - "remove-format": $fa-var-remove-format, - "face-smile-wink": $fa-var-face-smile-wink, - "smile-wink": $fa-var-smile-wink, - "file-word": $fa-var-file-word, - "file-powerpoint": $fa-var-file-powerpoint, - "arrows-left-right": $fa-var-arrows-left-right, - "arrows-h": $fa-var-arrows-h, - "house-lock": $fa-var-house-lock, - "cloud-arrow-down": $fa-var-cloud-arrow-down, - "cloud-download": $fa-var-cloud-download, - "cloud-download-alt": $fa-var-cloud-download-alt, - "children": $fa-var-children, - "chalkboard": $fa-var-chalkboard, - "blackboard": $fa-var-blackboard, - "user-large-slash": $fa-var-user-large-slash, - "user-alt-slash": $fa-var-user-alt-slash, - "envelope-open": $fa-var-envelope-open, - "handshake-simple-slash": $fa-var-handshake-simple-slash, - "handshake-alt-slash": $fa-var-handshake-alt-slash, - "mattress-pillow": $fa-var-mattress-pillow, - "guarani-sign": $fa-var-guarani-sign, - "arrows-rotate": $fa-var-arrows-rotate, - "refresh": $fa-var-refresh, - "sync": $fa-var-sync, - "fire-extinguisher": $fa-var-fire-extinguisher, - "cruzeiro-sign": $fa-var-cruzeiro-sign, - "greater-than-equal": $fa-var-greater-than-equal, - "shield-halved": $fa-var-shield-halved, - "shield-alt": $fa-var-shield-alt, - "book-atlas": $fa-var-book-atlas, - "atlas": $fa-var-atlas, - "virus": $fa-var-virus, - "envelope-circle-check": $fa-var-envelope-circle-check, - "layer-group": $fa-var-layer-group, - "arrows-to-dot": $fa-var-arrows-to-dot, - "archway": $fa-var-archway, - "heart-circle-check": $fa-var-heart-circle-check, - "house-chimney-crack": $fa-var-house-chimney-crack, - "house-damage": $fa-var-house-damage, - "file-zipper": $fa-var-file-zipper, - "file-archive": $fa-var-file-archive, - "square": $fa-var-square, - "martini-glass-empty": $fa-var-martini-glass-empty, - "glass-martini": $fa-var-glass-martini, - "couch": $fa-var-couch, - "cedi-sign": $fa-var-cedi-sign, - "italic": $fa-var-italic, - "church": $fa-var-church, - "comments-dollar": $fa-var-comments-dollar, - "democrat": $fa-var-democrat, - "z": $fa-var-z, - "person-skiing": $fa-var-person-skiing, - "skiing": $fa-var-skiing, - "road-lock": $fa-var-road-lock, - "a": $fa-var-a, - "temperature-arrow-down": $fa-var-temperature-arrow-down, - "temperature-down": $fa-var-temperature-down, - "feather-pointed": $fa-var-feather-pointed, - "feather-alt": $fa-var-feather-alt, - "p": $fa-var-p, - "snowflake": $fa-var-snowflake, - "newspaper": $fa-var-newspaper, - "rectangle-ad": $fa-var-rectangle-ad, - "ad": $fa-var-ad, - "circle-arrow-right": $fa-var-circle-arrow-right, - "arrow-circle-right": $fa-var-arrow-circle-right, - "filter-circle-xmark": $fa-var-filter-circle-xmark, - "locust": $fa-var-locust, - "sort": $fa-var-sort, - "unsorted": $fa-var-unsorted, - "list-ol": $fa-var-list-ol, - "list-1-2": $fa-var-list-1-2, - "list-numeric": $fa-var-list-numeric, - "person-dress-burst": $fa-var-person-dress-burst, - "money-check-dollar": $fa-var-money-check-dollar, - "money-check-alt": $fa-var-money-check-alt, - "vector-square": $fa-var-vector-square, - "bread-slice": $fa-var-bread-slice, - "language": $fa-var-language, - "face-kiss-wink-heart": $fa-var-face-kiss-wink-heart, - "kiss-wink-heart": $fa-var-kiss-wink-heart, - "filter": $fa-var-filter, - "question": $fa-var-question, - "file-signature": $fa-var-file-signature, - "up-down-left-right": $fa-var-up-down-left-right, - "arrows-alt": $fa-var-arrows-alt, - "house-chimney-user": $fa-var-house-chimney-user, - "hand-holding-heart": $fa-var-hand-holding-heart, - "puzzle-piece": $fa-var-puzzle-piece, - "money-check": $fa-var-money-check, - "star-half-stroke": $fa-var-star-half-stroke, - "star-half-alt": $fa-var-star-half-alt, - "code": $fa-var-code, - "whiskey-glass": $fa-var-whiskey-glass, - "glass-whiskey": $fa-var-glass-whiskey, - "building-circle-exclamation": $fa-var-building-circle-exclamation, - "magnifying-glass-chart": $fa-var-magnifying-glass-chart, - "arrow-up-right-from-square": $fa-var-arrow-up-right-from-square, - "external-link": $fa-var-external-link, - "cubes-stacked": $fa-var-cubes-stacked, - "won-sign": $fa-var-won-sign, - "krw": $fa-var-krw, - "won": $fa-var-won, - "virus-covid": $fa-var-virus-covid, - "austral-sign": $fa-var-austral-sign, - "f": $fa-var-f, - "leaf": $fa-var-leaf, - "road": $fa-var-road, - "taxi": $fa-var-taxi, - "cab": $fa-var-cab, - "person-circle-plus": $fa-var-person-circle-plus, - "chart-pie": $fa-var-chart-pie, - "pie-chart": $fa-var-pie-chart, - "bolt-lightning": $fa-var-bolt-lightning, - "sack-xmark": $fa-var-sack-xmark, - "file-excel": $fa-var-file-excel, - "file-contract": $fa-var-file-contract, - "fish-fins": $fa-var-fish-fins, - "building-flag": $fa-var-building-flag, - "face-grin-beam": $fa-var-face-grin-beam, - "grin-beam": $fa-var-grin-beam, - "object-ungroup": $fa-var-object-ungroup, - "poop": $fa-var-poop, - "location-pin": $fa-var-location-pin, - "map-marker": $fa-var-map-marker, - "kaaba": $fa-var-kaaba, - "toilet-paper": $fa-var-toilet-paper, - "helmet-safety": $fa-var-helmet-safety, - "hard-hat": $fa-var-hard-hat, - "hat-hard": $fa-var-hat-hard, - "eject": $fa-var-eject, - "circle-right": $fa-var-circle-right, - "arrow-alt-circle-right": $fa-var-arrow-alt-circle-right, - "plane-circle-check": $fa-var-plane-circle-check, - "face-rolling-eyes": $fa-var-face-rolling-eyes, - "meh-rolling-eyes": $fa-var-meh-rolling-eyes, - "object-group": $fa-var-object-group, - "chart-line": $fa-var-chart-line, - "line-chart": $fa-var-line-chart, - "mask-ventilator": $fa-var-mask-ventilator, - "arrow-right": $fa-var-arrow-right, - "signs-post": $fa-var-signs-post, - "map-signs": $fa-var-map-signs, - "cash-register": $fa-var-cash-register, - "person-circle-question": $fa-var-person-circle-question, - "h": $fa-var-h, - "tarp": $fa-var-tarp, - "screwdriver-wrench": $fa-var-screwdriver-wrench, - "tools": $fa-var-tools, - "arrows-to-eye": $fa-var-arrows-to-eye, - "plug-circle-bolt": $fa-var-plug-circle-bolt, - "heart": $fa-var-heart, - "mars-and-venus": $fa-var-mars-and-venus, - "house-user": $fa-var-house-user, - "home-user": $fa-var-home-user, - "dumpster-fire": $fa-var-dumpster-fire, - "house-crack": $fa-var-house-crack, - "martini-glass-citrus": $fa-var-martini-glass-citrus, - "cocktail": $fa-var-cocktail, - "face-surprise": $fa-var-face-surprise, - "surprise": $fa-var-surprise, - "bottle-water": $fa-var-bottle-water, - "circle-pause": $fa-var-circle-pause, - "pause-circle": $fa-var-pause-circle, - "toilet-paper-slash": $fa-var-toilet-paper-slash, - "apple-whole": $fa-var-apple-whole, - "apple-alt": $fa-var-apple-alt, - "kitchen-set": $fa-var-kitchen-set, - "r": $fa-var-r, - "temperature-quarter": $fa-var-temperature-quarter, - "temperature-1": $fa-var-temperature-1, - "thermometer-1": $fa-var-thermometer-1, - "thermometer-quarter": $fa-var-thermometer-quarter, - "cube": $fa-var-cube, - "bitcoin-sign": $fa-var-bitcoin-sign, - "shield-dog": $fa-var-shield-dog, - "solar-panel": $fa-var-solar-panel, - "lock-open": $fa-var-lock-open, - "elevator": $fa-var-elevator, - "money-bill-transfer": $fa-var-money-bill-transfer, - "money-bill-trend-up": $fa-var-money-bill-trend-up, - "house-flood-water-circle-arrow-right": $fa-var-house-flood-water-circle-arrow-right, - "square-poll-horizontal": $fa-var-square-poll-horizontal, - "poll-h": $fa-var-poll-h, - "circle": $fa-var-circle, - "backward-fast": $fa-var-backward-fast, - "fast-backward": $fa-var-fast-backward, - "recycle": $fa-var-recycle, - "user-astronaut": $fa-var-user-astronaut, - "plane-slash": $fa-var-plane-slash, - "trademark": $fa-var-trademark, - "basketball": $fa-var-basketball, - "basketball-ball": $fa-var-basketball-ball, - "satellite-dish": $fa-var-satellite-dish, - "circle-up": $fa-var-circle-up, - "arrow-alt-circle-up": $fa-var-arrow-alt-circle-up, - "mobile-screen-button": $fa-var-mobile-screen-button, - "mobile-alt": $fa-var-mobile-alt, - "volume-high": $fa-var-volume-high, - "volume-up": $fa-var-volume-up, - "users-rays": $fa-var-users-rays, - "wallet": $fa-var-wallet, - "clipboard-check": $fa-var-clipboard-check, - "file-audio": $fa-var-file-audio, - "burger": $fa-var-burger, - "hamburger": $fa-var-hamburger, - "wrench": $fa-var-wrench, - "bugs": $fa-var-bugs, - "rupee-sign": $fa-var-rupee-sign, - "rupee": $fa-var-rupee, - "file-image": $fa-var-file-image, - "circle-question": $fa-var-circle-question, - "question-circle": $fa-var-question-circle, - "plane-departure": $fa-var-plane-departure, - "handshake-slash": $fa-var-handshake-slash, - "book-bookmark": $fa-var-book-bookmark, - "code-branch": $fa-var-code-branch, - "hat-cowboy": $fa-var-hat-cowboy, - "bridge": $fa-var-bridge, - "phone-flip": $fa-var-phone-flip, - "phone-alt": $fa-var-phone-alt, - "truck-front": $fa-var-truck-front, - "cat": $fa-var-cat, - "anchor-circle-exclamation": $fa-var-anchor-circle-exclamation, - "truck-field": $fa-var-truck-field, - "route": $fa-var-route, - "clipboard-question": $fa-var-clipboard-question, - "panorama": $fa-var-panorama, - "comment-medical": $fa-var-comment-medical, - "teeth-open": $fa-var-teeth-open, - "file-circle-minus": $fa-var-file-circle-minus, - "tags": $fa-var-tags, - "wine-glass": $fa-var-wine-glass, - "forward-fast": $fa-var-forward-fast, - "fast-forward": $fa-var-fast-forward, - "face-meh-blank": $fa-var-face-meh-blank, - "meh-blank": $fa-var-meh-blank, - "square-parking": $fa-var-square-parking, - "parking": $fa-var-parking, - "house-signal": $fa-var-house-signal, - "bars-progress": $fa-var-bars-progress, - "tasks-alt": $fa-var-tasks-alt, - "faucet-drip": $fa-var-faucet-drip, - "cart-flatbed": $fa-var-cart-flatbed, - "dolly-flatbed": $fa-var-dolly-flatbed, - "ban-smoking": $fa-var-ban-smoking, - "smoking-ban": $fa-var-smoking-ban, - "terminal": $fa-var-terminal, - "mobile-button": $fa-var-mobile-button, - "house-medical-flag": $fa-var-house-medical-flag, - "basket-shopping": $fa-var-basket-shopping, - "shopping-basket": $fa-var-shopping-basket, - "tape": $fa-var-tape, - "bus-simple": $fa-var-bus-simple, - "bus-alt": $fa-var-bus-alt, - "eye": $fa-var-eye, - "face-sad-cry": $fa-var-face-sad-cry, - "sad-cry": $fa-var-sad-cry, - "audio-description": $fa-var-audio-description, - "person-military-to-person": $fa-var-person-military-to-person, - "file-shield": $fa-var-file-shield, - "user-slash": $fa-var-user-slash, - "pen": $fa-var-pen, - "tower-observation": $fa-var-tower-observation, - "file-code": $fa-var-file-code, - "signal": $fa-var-signal, - "signal-5": $fa-var-signal-5, - "signal-perfect": $fa-var-signal-perfect, - "bus": $fa-var-bus, - "heart-circle-xmark": $fa-var-heart-circle-xmark, - "house-chimney": $fa-var-house-chimney, - "home-lg": $fa-var-home-lg, - "window-maximize": $fa-var-window-maximize, - "face-frown": $fa-var-face-frown, - "frown": $fa-var-frown, - "prescription": $fa-var-prescription, - "shop": $fa-var-shop, - "store-alt": $fa-var-store-alt, - "floppy-disk": $fa-var-floppy-disk, - "save": $fa-var-save, - "vihara": $fa-var-vihara, - "scale-unbalanced": $fa-var-scale-unbalanced, - "balance-scale-left": $fa-var-balance-scale-left, - "sort-up": $fa-var-sort-up, - "sort-asc": $fa-var-sort-asc, - "comment-dots": $fa-var-comment-dots, - "commenting": $fa-var-commenting, - "plant-wilt": $fa-var-plant-wilt, - "diamond": $fa-var-diamond, - "face-grin-squint": $fa-var-face-grin-squint, - "grin-squint": $fa-var-grin-squint, - "hand-holding-dollar": $fa-var-hand-holding-dollar, - "hand-holding-usd": $fa-var-hand-holding-usd, - "bacterium": $fa-var-bacterium, - "hand-pointer": $fa-var-hand-pointer, - "drum-steelpan": $fa-var-drum-steelpan, - "hand-scissors": $fa-var-hand-scissors, - "hands-praying": $fa-var-hands-praying, - "praying-hands": $fa-var-praying-hands, - "arrow-rotate-right": $fa-var-arrow-rotate-right, - "arrow-right-rotate": $fa-var-arrow-right-rotate, - "arrow-rotate-forward": $fa-var-arrow-rotate-forward, - "redo": $fa-var-redo, - "biohazard": $fa-var-biohazard, - "location-crosshairs": $fa-var-location-crosshairs, - "location": $fa-var-location, - "mars-double": $fa-var-mars-double, - "child-dress": $fa-var-child-dress, - "users-between-lines": $fa-var-users-between-lines, - "lungs-virus": $fa-var-lungs-virus, - "face-grin-tears": $fa-var-face-grin-tears, - "grin-tears": $fa-var-grin-tears, - "phone": $fa-var-phone, - "calendar-xmark": $fa-var-calendar-xmark, - "calendar-times": $fa-var-calendar-times, - "child-reaching": $fa-var-child-reaching, - "head-side-virus": $fa-var-head-side-virus, - "user-gear": $fa-var-user-gear, - "user-cog": $fa-var-user-cog, - "arrow-up-1-9": $fa-var-arrow-up-1-9, - "sort-numeric-up": $fa-var-sort-numeric-up, - "door-closed": $fa-var-door-closed, - "shield-virus": $fa-var-shield-virus, - "dice-six": $fa-var-dice-six, - "mosquito-net": $fa-var-mosquito-net, - "bridge-water": $fa-var-bridge-water, - "person-booth": $fa-var-person-booth, - "text-width": $fa-var-text-width, - "hat-wizard": $fa-var-hat-wizard, - "pen-fancy": $fa-var-pen-fancy, - "person-digging": $fa-var-person-digging, - "digging": $fa-var-digging, - "trash": $fa-var-trash, - "gauge-simple": $fa-var-gauge-simple, - "gauge-simple-med": $fa-var-gauge-simple-med, - "tachometer-average": $fa-var-tachometer-average, - "book-medical": $fa-var-book-medical, - "poo": $fa-var-poo, - "quote-right": $fa-var-quote-right, - "quote-right-alt": $fa-var-quote-right-alt, - "shirt": $fa-var-shirt, - "t-shirt": $fa-var-t-shirt, - "tshirt": $fa-var-tshirt, - "cubes": $fa-var-cubes, - "divide": $fa-var-divide, - "tenge-sign": $fa-var-tenge-sign, - "tenge": $fa-var-tenge, - "headphones": $fa-var-headphones, - "hands-holding": $fa-var-hands-holding, - "hands-clapping": $fa-var-hands-clapping, - "republican": $fa-var-republican, - "arrow-left": $fa-var-arrow-left, - "person-circle-xmark": $fa-var-person-circle-xmark, - "ruler": $fa-var-ruler, - "align-left": $fa-var-align-left, - "dice-d6": $fa-var-dice-d6, - "restroom": $fa-var-restroom, - "j": $fa-var-j, - "users-viewfinder": $fa-var-users-viewfinder, - "file-video": $fa-var-file-video, - "up-right-from-square": $fa-var-up-right-from-square, - "external-link-alt": $fa-var-external-link-alt, - "table-cells": $fa-var-table-cells, - "th": $fa-var-th, - "file-pdf": $fa-var-file-pdf, - "book-bible": $fa-var-book-bible, - "bible": $fa-var-bible, - "o": $fa-var-o, - "suitcase-medical": $fa-var-suitcase-medical, - "medkit": $fa-var-medkit, - "user-secret": $fa-var-user-secret, - "otter": $fa-var-otter, - "person-dress": $fa-var-person-dress, - "female": $fa-var-female, - "comment-dollar": $fa-var-comment-dollar, - "business-time": $fa-var-business-time, - "briefcase-clock": $fa-var-briefcase-clock, - "table-cells-large": $fa-var-table-cells-large, - "th-large": $fa-var-th-large, - "book-tanakh": $fa-var-book-tanakh, - "tanakh": $fa-var-tanakh, - "phone-volume": $fa-var-phone-volume, - "volume-control-phone": $fa-var-volume-control-phone, - "hat-cowboy-side": $fa-var-hat-cowboy-side, - "clipboard-user": $fa-var-clipboard-user, - "child": $fa-var-child, - "lira-sign": $fa-var-lira-sign, - "satellite": $fa-var-satellite, - "plane-lock": $fa-var-plane-lock, - "tag": $fa-var-tag, - "comment": $fa-var-comment, - "cake-candles": $fa-var-cake-candles, - "birthday-cake": $fa-var-birthday-cake, - "cake": $fa-var-cake, - "envelope": $fa-var-envelope, - "angles-up": $fa-var-angles-up, - "angle-double-up": $fa-var-angle-double-up, - "paperclip": $fa-var-paperclip, - "arrow-right-to-city": $fa-var-arrow-right-to-city, - "ribbon": $fa-var-ribbon, - "lungs": $fa-var-lungs, - "arrow-up-9-1": $fa-var-arrow-up-9-1, - "sort-numeric-up-alt": $fa-var-sort-numeric-up-alt, - "litecoin-sign": $fa-var-litecoin-sign, - "border-none": $fa-var-border-none, - "circle-nodes": $fa-var-circle-nodes, - "parachute-box": $fa-var-parachute-box, - "indent": $fa-var-indent, - "truck-field-un": $fa-var-truck-field-un, - "hourglass": $fa-var-hourglass, - "hourglass-empty": $fa-var-hourglass-empty, - "mountain": $fa-var-mountain, - "user-doctor": $fa-var-user-doctor, - "user-md": $fa-var-user-md, - "circle-info": $fa-var-circle-info, - "info-circle": $fa-var-info-circle, - "cloud-meatball": $fa-var-cloud-meatball, - "camera": $fa-var-camera, - "camera-alt": $fa-var-camera-alt, - "square-virus": $fa-var-square-virus, - "meteor": $fa-var-meteor, - "car-on": $fa-var-car-on, - "sleigh": $fa-var-sleigh, - "arrow-down-1-9": $fa-var-arrow-down-1-9, - "sort-numeric-asc": $fa-var-sort-numeric-asc, - "sort-numeric-down": $fa-var-sort-numeric-down, - "hand-holding-droplet": $fa-var-hand-holding-droplet, - "hand-holding-water": $fa-var-hand-holding-water, - "water": $fa-var-water, - "calendar-check": $fa-var-calendar-check, - "braille": $fa-var-braille, - "prescription-bottle-medical": $fa-var-prescription-bottle-medical, - "prescription-bottle-alt": $fa-var-prescription-bottle-alt, - "landmark": $fa-var-landmark, - "truck": $fa-var-truck, - "crosshairs": $fa-var-crosshairs, - "person-cane": $fa-var-person-cane, - "tent": $fa-var-tent, - "vest-patches": $fa-var-vest-patches, - "check-double": $fa-var-check-double, - "arrow-down-a-z": $fa-var-arrow-down-a-z, - "sort-alpha-asc": $fa-var-sort-alpha-asc, - "sort-alpha-down": $fa-var-sort-alpha-down, - "money-bill-wheat": $fa-var-money-bill-wheat, - "cookie": $fa-var-cookie, - "arrow-rotate-left": $fa-var-arrow-rotate-left, - "arrow-left-rotate": $fa-var-arrow-left-rotate, - "arrow-rotate-back": $fa-var-arrow-rotate-back, - "arrow-rotate-backward": $fa-var-arrow-rotate-backward, - "undo": $fa-var-undo, - "hard-drive": $fa-var-hard-drive, - "hdd": $fa-var-hdd, - "face-grin-squint-tears": $fa-var-face-grin-squint-tears, - "grin-squint-tears": $fa-var-grin-squint-tears, - "dumbbell": $fa-var-dumbbell, - "rectangle-list": $fa-var-rectangle-list, - "list-alt": $fa-var-list-alt, - "tarp-droplet": $fa-var-tarp-droplet, - "house-medical-circle-check": $fa-var-house-medical-circle-check, - "person-skiing-nordic": $fa-var-person-skiing-nordic, - "skiing-nordic": $fa-var-skiing-nordic, - "calendar-plus": $fa-var-calendar-plus, - "plane-arrival": $fa-var-plane-arrival, - "circle-left": $fa-var-circle-left, - "arrow-alt-circle-left": $fa-var-arrow-alt-circle-left, - "train-subway": $fa-var-train-subway, - "subway": $fa-var-subway, - "chart-gantt": $fa-var-chart-gantt, - "indian-rupee-sign": $fa-var-indian-rupee-sign, - "indian-rupee": $fa-var-indian-rupee, - "inr": $fa-var-inr, - "crop-simple": $fa-var-crop-simple, - "crop-alt": $fa-var-crop-alt, - "money-bill-1": $fa-var-money-bill-1, - "money-bill-alt": $fa-var-money-bill-alt, - "left-long": $fa-var-left-long, - "long-arrow-alt-left": $fa-var-long-arrow-alt-left, - "dna": $fa-var-dna, - "virus-slash": $fa-var-virus-slash, - "minus": $fa-var-minus, - "subtract": $fa-var-subtract, - "child-rifle": $fa-var-child-rifle, - "chess": $fa-var-chess, - "arrow-left-long": $fa-var-arrow-left-long, - "long-arrow-left": $fa-var-long-arrow-left, - "plug-circle-check": $fa-var-plug-circle-check, - "street-view": $fa-var-street-view, - "franc-sign": $fa-var-franc-sign, - "volume-off": $fa-var-volume-off, - "hands-asl-interpreting": $fa-var-hands-asl-interpreting, - "american-sign-language-interpreting": $fa-var-american-sign-language-interpreting, - "asl-interpreting": $fa-var-asl-interpreting, - "hands-american-sign-language-interpreting": $fa-var-hands-american-sign-language-interpreting, - "gear": $fa-var-gear, - "cog": $fa-var-cog, - "droplet-slash": $fa-var-droplet-slash, - "tint-slash": $fa-var-tint-slash, - "mosque": $fa-var-mosque, - "mosquito": $fa-var-mosquito, - "star-of-david": $fa-var-star-of-david, - "person-military-rifle": $fa-var-person-military-rifle, - "cart-shopping": $fa-var-cart-shopping, - "shopping-cart": $fa-var-shopping-cart, - "vials": $fa-var-vials, - "plug-circle-plus": $fa-var-plug-circle-plus, - "place-of-worship": $fa-var-place-of-worship, - "grip-vertical": $fa-var-grip-vertical, - "arrow-turn-up": $fa-var-arrow-turn-up, - "level-up": $fa-var-level-up, - "u": $fa-var-u, - "square-root-variable": $fa-var-square-root-variable, - "square-root-alt": $fa-var-square-root-alt, - "clock": $fa-var-clock, - "clock-four": $fa-var-clock-four, - "backward-step": $fa-var-backward-step, - "step-backward": $fa-var-step-backward, - "pallet": $fa-var-pallet, - "faucet": $fa-var-faucet, - "baseball-bat-ball": $fa-var-baseball-bat-ball, - "s": $fa-var-s, - "timeline": $fa-var-timeline, - "keyboard": $fa-var-keyboard, - "caret-down": $fa-var-caret-down, - "house-chimney-medical": $fa-var-house-chimney-medical, - "clinic-medical": $fa-var-clinic-medical, - "temperature-three-quarters": $fa-var-temperature-three-quarters, - "temperature-3": $fa-var-temperature-3, - "thermometer-3": $fa-var-thermometer-3, - "thermometer-three-quarters": $fa-var-thermometer-three-quarters, - "mobile-screen": $fa-var-mobile-screen, - "mobile-android-alt": $fa-var-mobile-android-alt, - "plane-up": $fa-var-plane-up, - "piggy-bank": $fa-var-piggy-bank, - "battery-half": $fa-var-battery-half, - "battery-3": $fa-var-battery-3, - "mountain-city": $fa-var-mountain-city, - "coins": $fa-var-coins, - "khanda": $fa-var-khanda, - "sliders": $fa-var-sliders, - "sliders-h": $fa-var-sliders-h, - "folder-tree": $fa-var-folder-tree, - "network-wired": $fa-var-network-wired, - "map-pin": $fa-var-map-pin, - "hamsa": $fa-var-hamsa, - "cent-sign": $fa-var-cent-sign, - "flask": $fa-var-flask, - "person-pregnant": $fa-var-person-pregnant, - "wand-sparkles": $fa-var-wand-sparkles, - "ellipsis-vertical": $fa-var-ellipsis-vertical, - "ellipsis-v": $fa-var-ellipsis-v, - "ticket": $fa-var-ticket, - "power-off": $fa-var-power-off, - "right-long": $fa-var-right-long, - "long-arrow-alt-right": $fa-var-long-arrow-alt-right, - "flag-usa": $fa-var-flag-usa, - "laptop-file": $fa-var-laptop-file, - "tty": $fa-var-tty, - "teletype": $fa-var-teletype, - "diagram-next": $fa-var-diagram-next, - "person-rifle": $fa-var-person-rifle, - "house-medical-circle-exclamation": $fa-var-house-medical-circle-exclamation, - "closed-captioning": $fa-var-closed-captioning, - "person-hiking": $fa-var-person-hiking, - "hiking": $fa-var-hiking, - "venus-double": $fa-var-venus-double, - "images": $fa-var-images, - "calculator": $fa-var-calculator, - "people-pulling": $fa-var-people-pulling, - "n": $fa-var-n, - "cable-car": $fa-var-cable-car, - "tram": $fa-var-tram, - "cloud-rain": $fa-var-cloud-rain, - "building-circle-xmark": $fa-var-building-circle-xmark, - "ship": $fa-var-ship, - "arrows-down-to-line": $fa-var-arrows-down-to-line, - "download": $fa-var-download, - "face-grin": $fa-var-face-grin, - "grin": $fa-var-grin, - "delete-left": $fa-var-delete-left, - "backspace": $fa-var-backspace, - "eye-dropper": $fa-var-eye-dropper, - "eye-dropper-empty": $fa-var-eye-dropper-empty, - "eyedropper": $fa-var-eyedropper, - "file-circle-check": $fa-var-file-circle-check, - "forward": $fa-var-forward, - "mobile": $fa-var-mobile, - "mobile-android": $fa-var-mobile-android, - "mobile-phone": $fa-var-mobile-phone, - "face-meh": $fa-var-face-meh, - "meh": $fa-var-meh, - "align-center": $fa-var-align-center, - "book-skull": $fa-var-book-skull, - "book-dead": $fa-var-book-dead, - "id-card": $fa-var-id-card, - "drivers-license": $fa-var-drivers-license, - "outdent": $fa-var-outdent, - "dedent": $fa-var-dedent, - "heart-circle-exclamation": $fa-var-heart-circle-exclamation, - "house": $fa-var-house, - "home": $fa-var-home, - "home-alt": $fa-var-home-alt, - "home-lg-alt": $fa-var-home-lg-alt, - "calendar-week": $fa-var-calendar-week, - "laptop-medical": $fa-var-laptop-medical, - "b": $fa-var-b, - "file-medical": $fa-var-file-medical, - "dice-one": $fa-var-dice-one, - "kiwi-bird": $fa-var-kiwi-bird, - "arrow-right-arrow-left": $fa-var-arrow-right-arrow-left, - "exchange": $fa-var-exchange, - "rotate-right": $fa-var-rotate-right, - "redo-alt": $fa-var-redo-alt, - "rotate-forward": $fa-var-rotate-forward, - "utensils": $fa-var-utensils, - "cutlery": $fa-var-cutlery, - "arrow-up-wide-short": $fa-var-arrow-up-wide-short, - "sort-amount-up": $fa-var-sort-amount-up, - "mill-sign": $fa-var-mill-sign, - "bowl-rice": $fa-var-bowl-rice, - "skull": $fa-var-skull, - "tower-broadcast": $fa-var-tower-broadcast, - "broadcast-tower": $fa-var-broadcast-tower, - "truck-pickup": $fa-var-truck-pickup, - "up-long": $fa-var-up-long, - "long-arrow-alt-up": $fa-var-long-arrow-alt-up, - "stop": $fa-var-stop, - "code-merge": $fa-var-code-merge, - "upload": $fa-var-upload, - "hurricane": $fa-var-hurricane, - "mound": $fa-var-mound, - "toilet-portable": $fa-var-toilet-portable, - "compact-disc": $fa-var-compact-disc, - "file-arrow-down": $fa-var-file-arrow-down, - "file-download": $fa-var-file-download, - "caravan": $fa-var-caravan, - "shield-cat": $fa-var-shield-cat, - "bolt": $fa-var-bolt, - "zap": $fa-var-zap, - "glass-water": $fa-var-glass-water, - "oil-well": $fa-var-oil-well, - "vault": $fa-var-vault, - "mars": $fa-var-mars, - "toilet": $fa-var-toilet, - "plane-circle-xmark": $fa-var-plane-circle-xmark, - "yen-sign": $fa-var-yen-sign, - "cny": $fa-var-cny, - "jpy": $fa-var-jpy, - "rmb": $fa-var-rmb, - "yen": $fa-var-yen, - "ruble-sign": $fa-var-ruble-sign, - "rouble": $fa-var-rouble, - "rub": $fa-var-rub, - "ruble": $fa-var-ruble, - "sun": $fa-var-sun, - "guitar": $fa-var-guitar, - "face-laugh-wink": $fa-var-face-laugh-wink, - "laugh-wink": $fa-var-laugh-wink, - "horse-head": $fa-var-horse-head, - "bore-hole": $fa-var-bore-hole, - "industry": $fa-var-industry, - "circle-down": $fa-var-circle-down, - "arrow-alt-circle-down": $fa-var-arrow-alt-circle-down, - "arrows-turn-to-dots": $fa-var-arrows-turn-to-dots, - "florin-sign": $fa-var-florin-sign, - "arrow-down-short-wide": $fa-var-arrow-down-short-wide, - "sort-amount-desc": $fa-var-sort-amount-desc, - "sort-amount-down-alt": $fa-var-sort-amount-down-alt, - "less-than": $fa-var-less-than, - "angle-down": $fa-var-angle-down, - "car-tunnel": $fa-var-car-tunnel, - "head-side-cough": $fa-var-head-side-cough, - "grip-lines": $fa-var-grip-lines, - "thumbs-down": $fa-var-thumbs-down, - "user-lock": $fa-var-user-lock, - "arrow-right-long": $fa-var-arrow-right-long, - "long-arrow-right": $fa-var-long-arrow-right, - "anchor-circle-xmark": $fa-var-anchor-circle-xmark, - "ellipsis": $fa-var-ellipsis, - "ellipsis-h": $fa-var-ellipsis-h, - "chess-pawn": $fa-var-chess-pawn, - "kit-medical": $fa-var-kit-medical, - "first-aid": $fa-var-first-aid, - "person-through-window": $fa-var-person-through-window, - "toolbox": $fa-var-toolbox, - "hands-holding-circle": $fa-var-hands-holding-circle, - "bug": $fa-var-bug, - "credit-card": $fa-var-credit-card, - "credit-card-alt": $fa-var-credit-card-alt, - "car": $fa-var-car, - "automobile": $fa-var-automobile, - "hand-holding-hand": $fa-var-hand-holding-hand, - "book-open-reader": $fa-var-book-open-reader, - "book-reader": $fa-var-book-reader, - "mountain-sun": $fa-var-mountain-sun, - "arrows-left-right-to-line": $fa-var-arrows-left-right-to-line, - "dice-d20": $fa-var-dice-d20, - "truck-droplet": $fa-var-truck-droplet, - "file-circle-xmark": $fa-var-file-circle-xmark, - "temperature-arrow-up": $fa-var-temperature-arrow-up, - "temperature-up": $fa-var-temperature-up, - "medal": $fa-var-medal, - "bed": $fa-var-bed, - "square-h": $fa-var-square-h, - "h-square": $fa-var-h-square, - "podcast": $fa-var-podcast, - "temperature-full": $fa-var-temperature-full, - "temperature-4": $fa-var-temperature-4, - "thermometer-4": $fa-var-thermometer-4, - "thermometer-full": $fa-var-thermometer-full, - "bell": $fa-var-bell, - "superscript": $fa-var-superscript, - "plug-circle-xmark": $fa-var-plug-circle-xmark, - "star-of-life": $fa-var-star-of-life, - "phone-slash": $fa-var-phone-slash, - "paint-roller": $fa-var-paint-roller, - "handshake-angle": $fa-var-handshake-angle, - "hands-helping": $fa-var-hands-helping, - "location-dot": $fa-var-location-dot, - "map-marker-alt": $fa-var-map-marker-alt, - "file": $fa-var-file, - "greater-than": $fa-var-greater-than, - "person-swimming": $fa-var-person-swimming, - "swimmer": $fa-var-swimmer, - "arrow-down": $fa-var-arrow-down, - "droplet": $fa-var-droplet, - "tint": $fa-var-tint, - "eraser": $fa-var-eraser, - "earth-americas": $fa-var-earth-americas, - "earth": $fa-var-earth, - "earth-america": $fa-var-earth-america, - "globe-americas": $fa-var-globe-americas, - "person-burst": $fa-var-person-burst, - "dove": $fa-var-dove, - "battery-empty": $fa-var-battery-empty, - "battery-0": $fa-var-battery-0, - "socks": $fa-var-socks, - "inbox": $fa-var-inbox, - "section": $fa-var-section, - "gauge-high": $fa-var-gauge-high, - "tachometer-alt": $fa-var-tachometer-alt, - "tachometer-alt-fast": $fa-var-tachometer-alt-fast, - "envelope-open-text": $fa-var-envelope-open-text, - "hospital": $fa-var-hospital, - "hospital-alt": $fa-var-hospital-alt, - "hospital-wide": $fa-var-hospital-wide, - "wine-bottle": $fa-var-wine-bottle, - "chess-rook": $fa-var-chess-rook, - "bars-staggered": $fa-var-bars-staggered, - "reorder": $fa-var-reorder, - "stream": $fa-var-stream, - "dharmachakra": $fa-var-dharmachakra, - "hotdog": $fa-var-hotdog, - "person-walking-with-cane": $fa-var-person-walking-with-cane, - "blind": $fa-var-blind, - "drum": $fa-var-drum, - "ice-cream": $fa-var-ice-cream, - "heart-circle-bolt": $fa-var-heart-circle-bolt, - "fax": $fa-var-fax, - "paragraph": $fa-var-paragraph, - "check-to-slot": $fa-var-check-to-slot, - "vote-yea": $fa-var-vote-yea, - "star-half": $fa-var-star-half, - "boxes-stacked": $fa-var-boxes-stacked, - "boxes": $fa-var-boxes, - "boxes-alt": $fa-var-boxes-alt, - "link": $fa-var-link, - "chain": $fa-var-chain, - "ear-listen": $fa-var-ear-listen, - "assistive-listening-systems": $fa-var-assistive-listening-systems, - "tree-city": $fa-var-tree-city, - "play": $fa-var-play, - "font": $fa-var-font, - "rupiah-sign": $fa-var-rupiah-sign, - "magnifying-glass": $fa-var-magnifying-glass, - "search": $fa-var-search, - "table-tennis-paddle-ball": $fa-var-table-tennis-paddle-ball, - "ping-pong-paddle-ball": $fa-var-ping-pong-paddle-ball, - "table-tennis": $fa-var-table-tennis, - "person-dots-from-line": $fa-var-person-dots-from-line, - "diagnoses": $fa-var-diagnoses, - "trash-can-arrow-up": $fa-var-trash-can-arrow-up, - "trash-restore-alt": $fa-var-trash-restore-alt, - "naira-sign": $fa-var-naira-sign, - "cart-arrow-down": $fa-var-cart-arrow-down, - "walkie-talkie": $fa-var-walkie-talkie, - "file-pen": $fa-var-file-pen, - "file-edit": $fa-var-file-edit, - "receipt": $fa-var-receipt, - "square-pen": $fa-var-square-pen, - "pen-square": $fa-var-pen-square, - "pencil-square": $fa-var-pencil-square, - "suitcase-rolling": $fa-var-suitcase-rolling, - "person-circle-exclamation": $fa-var-person-circle-exclamation, - "chevron-down": $fa-var-chevron-down, - "battery-full": $fa-var-battery-full, - "battery": $fa-var-battery, - "battery-5": $fa-var-battery-5, - "skull-crossbones": $fa-var-skull-crossbones, - "code-compare": $fa-var-code-compare, - "list-ul": $fa-var-list-ul, - "list-dots": $fa-var-list-dots, - "school-lock": $fa-var-school-lock, - "tower-cell": $fa-var-tower-cell, - "down-long": $fa-var-down-long, - "long-arrow-alt-down": $fa-var-long-arrow-alt-down, - "ranking-star": $fa-var-ranking-star, - "chess-king": $fa-var-chess-king, - "person-harassing": $fa-var-person-harassing, - "brazilian-real-sign": $fa-var-brazilian-real-sign, - "landmark-dome": $fa-var-landmark-dome, - "landmark-alt": $fa-var-landmark-alt, - "arrow-up": $fa-var-arrow-up, - "tv": $fa-var-tv, - "television": $fa-var-television, - "tv-alt": $fa-var-tv-alt, - "shrimp": $fa-var-shrimp, - "list-check": $fa-var-list-check, - "tasks": $fa-var-tasks, - "jug-detergent": $fa-var-jug-detergent, - "circle-user": $fa-var-circle-user, - "user-circle": $fa-var-user-circle, - "user-shield": $fa-var-user-shield, - "wind": $fa-var-wind, - "car-burst": $fa-var-car-burst, - "car-crash": $fa-var-car-crash, - "y": $fa-var-y, - "person-snowboarding": $fa-var-person-snowboarding, - "snowboarding": $fa-var-snowboarding, - "truck-fast": $fa-var-truck-fast, - "shipping-fast": $fa-var-shipping-fast, - "fish": $fa-var-fish, - "user-graduate": $fa-var-user-graduate, - "circle-half-stroke": $fa-var-circle-half-stroke, - "adjust": $fa-var-adjust, - "clapperboard": $fa-var-clapperboard, - "circle-radiation": $fa-var-circle-radiation, - "radiation-alt": $fa-var-radiation-alt, - "baseball": $fa-var-baseball, - "baseball-ball": $fa-var-baseball-ball, - "jet-fighter-up": $fa-var-jet-fighter-up, - "diagram-project": $fa-var-diagram-project, - "project-diagram": $fa-var-project-diagram, - "copy": $fa-var-copy, - "volume-xmark": $fa-var-volume-xmark, - "volume-mute": $fa-var-volume-mute, - "volume-times": $fa-var-volume-times, - "hand-sparkles": $fa-var-hand-sparkles, - "grip": $fa-var-grip, - "grip-horizontal": $fa-var-grip-horizontal, - "share-from-square": $fa-var-share-from-square, - "share-square": $fa-var-share-square, - "gun": $fa-var-gun, - "square-phone": $fa-var-square-phone, - "phone-square": $fa-var-phone-square, - "plus": $fa-var-plus, - "add": $fa-var-add, - "expand": $fa-var-expand, - "computer": $fa-var-computer, - "xmark": $fa-var-xmark, - "close": $fa-var-close, - "multiply": $fa-var-multiply, - "remove": $fa-var-remove, - "times": $fa-var-times, - "arrows-up-down-left-right": $fa-var-arrows-up-down-left-right, - "arrows": $fa-var-arrows, - "chalkboard-user": $fa-var-chalkboard-user, - "chalkboard-teacher": $fa-var-chalkboard-teacher, - "peso-sign": $fa-var-peso-sign, - "building-shield": $fa-var-building-shield, - "baby": $fa-var-baby, - "users-line": $fa-var-users-line, - "quote-left": $fa-var-quote-left, - "quote-left-alt": $fa-var-quote-left-alt, - "tractor": $fa-var-tractor, - "trash-arrow-up": $fa-var-trash-arrow-up, - "trash-restore": $fa-var-trash-restore, - "arrow-down-up-lock": $fa-var-arrow-down-up-lock, - "lines-leaning": $fa-var-lines-leaning, - "ruler-combined": $fa-var-ruler-combined, - "copyright": $fa-var-copyright, - "equals": $fa-var-equals, - "blender": $fa-var-blender, - "teeth": $fa-var-teeth, - "shekel-sign": $fa-var-shekel-sign, - "ils": $fa-var-ils, - "shekel": $fa-var-shekel, - "sheqel": $fa-var-sheqel, - "sheqel-sign": $fa-var-sheqel-sign, - "map": $fa-var-map, - "rocket": $fa-var-rocket, - "photo-film": $fa-var-photo-film, - "photo-video": $fa-var-photo-video, - "folder-minus": $fa-var-folder-minus, - "store": $fa-var-store, - "arrow-trend-up": $fa-var-arrow-trend-up, - "plug-circle-minus": $fa-var-plug-circle-minus, - "sign-hanging": $fa-var-sign-hanging, - "sign": $fa-var-sign, - "bezier-curve": $fa-var-bezier-curve, - "bell-slash": $fa-var-bell-slash, - "tablet": $fa-var-tablet, - "tablet-android": $fa-var-tablet-android, - "school-flag": $fa-var-school-flag, - "fill": $fa-var-fill, - "angle-up": $fa-var-angle-up, - "drumstick-bite": $fa-var-drumstick-bite, - "holly-berry": $fa-var-holly-berry, - "chevron-left": $fa-var-chevron-left, - "bacteria": $fa-var-bacteria, - "hand-lizard": $fa-var-hand-lizard, - "disease": $fa-var-disease, - "briefcase-medical": $fa-var-briefcase-medical, - "genderless": $fa-var-genderless, - "chevron-right": $fa-var-chevron-right, - "retweet": $fa-var-retweet, - "car-rear": $fa-var-car-rear, - "car-alt": $fa-var-car-alt, - "pump-soap": $fa-var-pump-soap, - "video-slash": $fa-var-video-slash, - "battery-quarter": $fa-var-battery-quarter, - "battery-2": $fa-var-battery-2, - "radio": $fa-var-radio, - "baby-carriage": $fa-var-baby-carriage, - "carriage-baby": $fa-var-carriage-baby, - "traffic-light": $fa-var-traffic-light, - "thermometer": $fa-var-thermometer, - "vr-cardboard": $fa-var-vr-cardboard, - "hand-middle-finger": $fa-var-hand-middle-finger, - "percent": $fa-var-percent, - "percentage": $fa-var-percentage, - "truck-moving": $fa-var-truck-moving, - "glass-water-droplet": $fa-var-glass-water-droplet, - "display": $fa-var-display, - "face-smile": $fa-var-face-smile, - "smile": $fa-var-smile, - "thumbtack": $fa-var-thumbtack, - "thumb-tack": $fa-var-thumb-tack, - "trophy": $fa-var-trophy, - "person-praying": $fa-var-person-praying, - "pray": $fa-var-pray, - "hammer": $fa-var-hammer, - "hand-peace": $fa-var-hand-peace, - "rotate": $fa-var-rotate, - "sync-alt": $fa-var-sync-alt, - "spinner": $fa-var-spinner, - "robot": $fa-var-robot, - "peace": $fa-var-peace, - "gears": $fa-var-gears, - "cogs": $fa-var-cogs, - "warehouse": $fa-var-warehouse, - "arrow-up-right-dots": $fa-var-arrow-up-right-dots, - "splotch": $fa-var-splotch, - "face-grin-hearts": $fa-var-face-grin-hearts, - "grin-hearts": $fa-var-grin-hearts, - "dice-four": $fa-var-dice-four, - "sim-card": $fa-var-sim-card, - "transgender": $fa-var-transgender, - "transgender-alt": $fa-var-transgender-alt, - "mercury": $fa-var-mercury, - "arrow-turn-down": $fa-var-arrow-turn-down, - "level-down": $fa-var-level-down, - "person-falling-burst": $fa-var-person-falling-burst, - "award": $fa-var-award, - "ticket-simple": $fa-var-ticket-simple, - "ticket-alt": $fa-var-ticket-alt, - "building": $fa-var-building, - "angles-left": $fa-var-angles-left, - "angle-double-left": $fa-var-angle-double-left, - "qrcode": $fa-var-qrcode, - "clock-rotate-left": $fa-var-clock-rotate-left, - "history": $fa-var-history, - "face-grin-beam-sweat": $fa-var-face-grin-beam-sweat, - "grin-beam-sweat": $fa-var-grin-beam-sweat, - "file-export": $fa-var-file-export, - "arrow-right-from-file": $fa-var-arrow-right-from-file, - "shield": $fa-var-shield, - "shield-blank": $fa-var-shield-blank, - "arrow-up-short-wide": $fa-var-arrow-up-short-wide, - "sort-amount-up-alt": $fa-var-sort-amount-up-alt, - "house-medical": $fa-var-house-medical, - "golf-ball-tee": $fa-var-golf-ball-tee, - "golf-ball": $fa-var-golf-ball, - "circle-chevron-left": $fa-var-circle-chevron-left, - "chevron-circle-left": $fa-var-chevron-circle-left, - "house-chimney-window": $fa-var-house-chimney-window, - "pen-nib": $fa-var-pen-nib, - "tent-arrow-turn-left": $fa-var-tent-arrow-turn-left, - "tents": $fa-var-tents, - "wand-magic": $fa-var-wand-magic, - "magic": $fa-var-magic, - "dog": $fa-var-dog, - "carrot": $fa-var-carrot, - "moon": $fa-var-moon, - "wine-glass-empty": $fa-var-wine-glass-empty, - "wine-glass-alt": $fa-var-wine-glass-alt, - "cheese": $fa-var-cheese, - "yin-yang": $fa-var-yin-yang, - "music": $fa-var-music, - "code-commit": $fa-var-code-commit, - "temperature-low": $fa-var-temperature-low, - "person-biking": $fa-var-person-biking, - "biking": $fa-var-biking, - "broom": $fa-var-broom, - "shield-heart": $fa-var-shield-heart, - "gopuram": $fa-var-gopuram, - "earth-oceania": $fa-var-earth-oceania, - "globe-oceania": $fa-var-globe-oceania, - "square-xmark": $fa-var-square-xmark, - "times-square": $fa-var-times-square, - "xmark-square": $fa-var-xmark-square, - "hashtag": $fa-var-hashtag, - "up-right-and-down-left-from-center": $fa-var-up-right-and-down-left-from-center, - "expand-alt": $fa-var-expand-alt, - "oil-can": $fa-var-oil-can, - "t": $fa-var-t, - "hippo": $fa-var-hippo, - "chart-column": $fa-var-chart-column, - "infinity": $fa-var-infinity, - "vial-circle-check": $fa-var-vial-circle-check, - "person-arrow-down-to-line": $fa-var-person-arrow-down-to-line, - "voicemail": $fa-var-voicemail, - "fan": $fa-var-fan, - "person-walking-luggage": $fa-var-person-walking-luggage, - "up-down": $fa-var-up-down, - "arrows-alt-v": $fa-var-arrows-alt-v, - "cloud-moon-rain": $fa-var-cloud-moon-rain, - "calendar": $fa-var-calendar, - "trailer": $fa-var-trailer, - "bahai": $fa-var-bahai, - "haykal": $fa-var-haykal, - "sd-card": $fa-var-sd-card, - "dragon": $fa-var-dragon, - "shoe-prints": $fa-var-shoe-prints, - "circle-plus": $fa-var-circle-plus, - "plus-circle": $fa-var-plus-circle, - "face-grin-tongue-wink": $fa-var-face-grin-tongue-wink, - "grin-tongue-wink": $fa-var-grin-tongue-wink, - "hand-holding": $fa-var-hand-holding, - "plug-circle-exclamation": $fa-var-plug-circle-exclamation, - "link-slash": $fa-var-link-slash, - "chain-broken": $fa-var-chain-broken, - "chain-slash": $fa-var-chain-slash, - "unlink": $fa-var-unlink, - "clone": $fa-var-clone, - "person-walking-arrow-loop-left": $fa-var-person-walking-arrow-loop-left, - "arrow-up-z-a": $fa-var-arrow-up-z-a, - "sort-alpha-up-alt": $fa-var-sort-alpha-up-alt, - "fire-flame-curved": $fa-var-fire-flame-curved, - "fire-alt": $fa-var-fire-alt, - "tornado": $fa-var-tornado, - "file-circle-plus": $fa-var-file-circle-plus, - "book-quran": $fa-var-book-quran, - "quran": $fa-var-quran, - "anchor": $fa-var-anchor, - "border-all": $fa-var-border-all, - "face-angry": $fa-var-face-angry, - "angry": $fa-var-angry, - "cookie-bite": $fa-var-cookie-bite, - "arrow-trend-down": $fa-var-arrow-trend-down, - "rss": $fa-var-rss, - "feed": $fa-var-feed, - "draw-polygon": $fa-var-draw-polygon, - "scale-balanced": $fa-var-scale-balanced, - "balance-scale": $fa-var-balance-scale, - "gauge-simple-high": $fa-var-gauge-simple-high, - "tachometer": $fa-var-tachometer, - "tachometer-fast": $fa-var-tachometer-fast, - "shower": $fa-var-shower, - "desktop": $fa-var-desktop, - "desktop-alt": $fa-var-desktop-alt, - "m": $fa-var-m, - "table-list": $fa-var-table-list, - "th-list": $fa-var-th-list, - "comment-sms": $fa-var-comment-sms, - "sms": $fa-var-sms, - "book": $fa-var-book, - "user-plus": $fa-var-user-plus, - "check": $fa-var-check, - "battery-three-quarters": $fa-var-battery-three-quarters, - "battery-4": $fa-var-battery-4, - "house-circle-check": $fa-var-house-circle-check, - "angle-left": $fa-var-angle-left, - "diagram-successor": $fa-var-diagram-successor, - "truck-arrow-right": $fa-var-truck-arrow-right, - "arrows-split-up-and-left": $fa-var-arrows-split-up-and-left, - "hand-fist": $fa-var-hand-fist, - "fist-raised": $fa-var-fist-raised, - "cloud-moon": $fa-var-cloud-moon, - "briefcase": $fa-var-briefcase, - "person-falling": $fa-var-person-falling, - "image-portrait": $fa-var-image-portrait, - "portrait": $fa-var-portrait, - "user-tag": $fa-var-user-tag, - "rug": $fa-var-rug, - "earth-europe": $fa-var-earth-europe, - "globe-europe": $fa-var-globe-europe, - "cart-flatbed-suitcase": $fa-var-cart-flatbed-suitcase, - "luggage-cart": $fa-var-luggage-cart, - "rectangle-xmark": $fa-var-rectangle-xmark, - "rectangle-times": $fa-var-rectangle-times, - "times-rectangle": $fa-var-times-rectangle, - "window-close": $fa-var-window-close, - "baht-sign": $fa-var-baht-sign, - "book-open": $fa-var-book-open, - "book-journal-whills": $fa-var-book-journal-whills, - "journal-whills": $fa-var-journal-whills, - "handcuffs": $fa-var-handcuffs, - "triangle-exclamation": $fa-var-triangle-exclamation, - "exclamation-triangle": $fa-var-exclamation-triangle, - "warning": $fa-var-warning, - "database": $fa-var-database, - "share": $fa-var-share, - "arrow-turn-right": $fa-var-arrow-turn-right, - "mail-forward": $fa-var-mail-forward, - "bottle-droplet": $fa-var-bottle-droplet, - "mask-face": $fa-var-mask-face, - "hill-rockslide": $fa-var-hill-rockslide, - "right-left": $fa-var-right-left, - "exchange-alt": $fa-var-exchange-alt, - "paper-plane": $fa-var-paper-plane, - "road-circle-exclamation": $fa-var-road-circle-exclamation, - "dungeon": $fa-var-dungeon, - "align-right": $fa-var-align-right, - "money-bill-1-wave": $fa-var-money-bill-1-wave, - "money-bill-wave-alt": $fa-var-money-bill-wave-alt, - "life-ring": $fa-var-life-ring, - "hands": $fa-var-hands, - "sign-language": $fa-var-sign-language, - "signing": $fa-var-signing, - "calendar-day": $fa-var-calendar-day, - "water-ladder": $fa-var-water-ladder, - "ladder-water": $fa-var-ladder-water, - "swimming-pool": $fa-var-swimming-pool, - "arrows-up-down": $fa-var-arrows-up-down, - "arrows-v": $fa-var-arrows-v, - "face-grimace": $fa-var-face-grimace, - "grimace": $fa-var-grimace, - "wheelchair-move": $fa-var-wheelchair-move, - "wheelchair-alt": $fa-var-wheelchair-alt, - "turn-down": $fa-var-turn-down, - "level-down-alt": $fa-var-level-down-alt, - "person-walking-arrow-right": $fa-var-person-walking-arrow-right, - "square-envelope": $fa-var-square-envelope, - "envelope-square": $fa-var-envelope-square, - "dice": $fa-var-dice, - "bowling-ball": $fa-var-bowling-ball, - "brain": $fa-var-brain, - "bandage": $fa-var-bandage, - "band-aid": $fa-var-band-aid, - "calendar-minus": $fa-var-calendar-minus, - "circle-xmark": $fa-var-circle-xmark, - "times-circle": $fa-var-times-circle, - "xmark-circle": $fa-var-xmark-circle, - "gifts": $fa-var-gifts, - "hotel": $fa-var-hotel, - "earth-asia": $fa-var-earth-asia, - "globe-asia": $fa-var-globe-asia, - "id-card-clip": $fa-var-id-card-clip, - "id-card-alt": $fa-var-id-card-alt, - "magnifying-glass-plus": $fa-var-magnifying-glass-plus, - "search-plus": $fa-var-search-plus, - "thumbs-up": $fa-var-thumbs-up, - "user-clock": $fa-var-user-clock, - "hand-dots": $fa-var-hand-dots, - "allergies": $fa-var-allergies, - "file-invoice": $fa-var-file-invoice, - "window-minimize": $fa-var-window-minimize, - "mug-saucer": $fa-var-mug-saucer, - "coffee": $fa-var-coffee, - "brush": $fa-var-brush, - "mask": $fa-var-mask, - "magnifying-glass-minus": $fa-var-magnifying-glass-minus, - "search-minus": $fa-var-search-minus, - "ruler-vertical": $fa-var-ruler-vertical, - "user-large": $fa-var-user-large, - "user-alt": $fa-var-user-alt, - "train-tram": $fa-var-train-tram, - "user-nurse": $fa-var-user-nurse, - "syringe": $fa-var-syringe, - "cloud-sun": $fa-var-cloud-sun, - "stopwatch-20": $fa-var-stopwatch-20, - "square-full": $fa-var-square-full, - "magnet": $fa-var-magnet, - "jar": $fa-var-jar, - "note-sticky": $fa-var-note-sticky, - "sticky-note": $fa-var-sticky-note, - "bug-slash": $fa-var-bug-slash, - "arrow-up-from-water-pump": $fa-var-arrow-up-from-water-pump, - "bone": $fa-var-bone, - "user-injured": $fa-var-user-injured, - "face-sad-tear": $fa-var-face-sad-tear, - "sad-tear": $fa-var-sad-tear, - "plane": $fa-var-plane, - "tent-arrows-down": $fa-var-tent-arrows-down, - "exclamation": $fa-var-exclamation, - "arrows-spin": $fa-var-arrows-spin, - "print": $fa-var-print, - "turkish-lira-sign": $fa-var-turkish-lira-sign, - "try": $fa-var-try, - "turkish-lira": $fa-var-turkish-lira, - "dollar-sign": $fa-var-dollar-sign, - "dollar": $fa-var-dollar, - "usd": $fa-var-usd, - "x": $fa-var-x, - "magnifying-glass-dollar": $fa-var-magnifying-glass-dollar, - "search-dollar": $fa-var-search-dollar, - "users-gear": $fa-var-users-gear, - "users-cog": $fa-var-users-cog, - "person-military-pointing": $fa-var-person-military-pointing, - "building-columns": $fa-var-building-columns, - "bank": $fa-var-bank, - "institution": $fa-var-institution, - "museum": $fa-var-museum, - "university": $fa-var-university, - "umbrella": $fa-var-umbrella, - "trowel": $fa-var-trowel, - "d": $fa-var-d, - "stapler": $fa-var-stapler, - "masks-theater": $fa-var-masks-theater, - "theater-masks": $fa-var-theater-masks, - "kip-sign": $fa-var-kip-sign, - "hand-point-left": $fa-var-hand-point-left, - "handshake-simple": $fa-var-handshake-simple, - "handshake-alt": $fa-var-handshake-alt, - "jet-fighter": $fa-var-jet-fighter, - "fighter-jet": $fa-var-fighter-jet, - "square-share-nodes": $fa-var-square-share-nodes, - "share-alt-square": $fa-var-share-alt-square, - "barcode": $fa-var-barcode, - "plus-minus": $fa-var-plus-minus, - "video": $fa-var-video, - "video-camera": $fa-var-video-camera, - "graduation-cap": $fa-var-graduation-cap, - "mortar-board": $fa-var-mortar-board, - "hand-holding-medical": $fa-var-hand-holding-medical, - "person-circle-check": $fa-var-person-circle-check, - "turn-up": $fa-var-turn-up, - "level-up-alt": $fa-var-level-up-alt, -); - -$fa-brand-icons: ( - "monero": $fa-var-monero, - "hooli": $fa-var-hooli, - "yelp": $fa-var-yelp, - "cc-visa": $fa-var-cc-visa, - "lastfm": $fa-var-lastfm, - "shopware": $fa-var-shopware, - "creative-commons-nc": $fa-var-creative-commons-nc, - "aws": $fa-var-aws, - "redhat": $fa-var-redhat, - "yoast": $fa-var-yoast, - "cloudflare": $fa-var-cloudflare, - "ups": $fa-var-ups, - "wpexplorer": $fa-var-wpexplorer, - "dyalog": $fa-var-dyalog, - "bity": $fa-var-bity, - "stackpath": $fa-var-stackpath, - "buysellads": $fa-var-buysellads, - "first-order": $fa-var-first-order, - "modx": $fa-var-modx, - "guilded": $fa-var-guilded, - "vnv": $fa-var-vnv, - "square-js": $fa-var-square-js, - "js-square": $fa-var-js-square, - "microsoft": $fa-var-microsoft, - "qq": $fa-var-qq, - "orcid": $fa-var-orcid, - "java": $fa-var-java, - "invision": $fa-var-invision, - "creative-commons-pd-alt": $fa-var-creative-commons-pd-alt, - "centercode": $fa-var-centercode, - "glide-g": $fa-var-glide-g, - "drupal": $fa-var-drupal, - "hire-a-helper": $fa-var-hire-a-helper, - "creative-commons-by": $fa-var-creative-commons-by, - "unity": $fa-var-unity, - "whmcs": $fa-var-whmcs, - "rocketchat": $fa-var-rocketchat, - "vk": $fa-var-vk, - "untappd": $fa-var-untappd, - "mailchimp": $fa-var-mailchimp, - "css3-alt": $fa-var-css3-alt, - "square-reddit": $fa-var-square-reddit, - "reddit-square": $fa-var-reddit-square, - "vimeo-v": $fa-var-vimeo-v, - "contao": $fa-var-contao, - "square-font-awesome": $fa-var-square-font-awesome, - "deskpro": $fa-var-deskpro, - "sistrix": $fa-var-sistrix, - "square-instagram": $fa-var-square-instagram, - "instagram-square": $fa-var-instagram-square, - "battle-net": $fa-var-battle-net, - "the-red-yeti": $fa-var-the-red-yeti, - "square-hacker-news": $fa-var-square-hacker-news, - "hacker-news-square": $fa-var-hacker-news-square, - "edge": $fa-var-edge, - "napster": $fa-var-napster, - "square-snapchat": $fa-var-square-snapchat, - "snapchat-square": $fa-var-snapchat-square, - "google-plus-g": $fa-var-google-plus-g, - "artstation": $fa-var-artstation, - "markdown": $fa-var-markdown, - "sourcetree": $fa-var-sourcetree, - "google-plus": $fa-var-google-plus, - "diaspora": $fa-var-diaspora, - "foursquare": $fa-var-foursquare, - "stack-overflow": $fa-var-stack-overflow, - "github-alt": $fa-var-github-alt, - "phoenix-squadron": $fa-var-phoenix-squadron, - "pagelines": $fa-var-pagelines, - "algolia": $fa-var-algolia, - "red-river": $fa-var-red-river, - "creative-commons-sa": $fa-var-creative-commons-sa, - "safari": $fa-var-safari, - "google": $fa-var-google, - "square-font-awesome-stroke": $fa-var-square-font-awesome-stroke, - "font-awesome-alt": $fa-var-font-awesome-alt, - "atlassian": $fa-var-atlassian, - "linkedin-in": $fa-var-linkedin-in, - "digital-ocean": $fa-var-digital-ocean, - "nimblr": $fa-var-nimblr, - "chromecast": $fa-var-chromecast, - "evernote": $fa-var-evernote, - "hacker-news": $fa-var-hacker-news, - "creative-commons-sampling": $fa-var-creative-commons-sampling, - "adversal": $fa-var-adversal, - "creative-commons": $fa-var-creative-commons, - "watchman-monitoring": $fa-var-watchman-monitoring, - "fonticons": $fa-var-fonticons, - "weixin": $fa-var-weixin, - "shirtsinbulk": $fa-var-shirtsinbulk, - "codepen": $fa-var-codepen, - "git-alt": $fa-var-git-alt, - "lyft": $fa-var-lyft, - "rev": $fa-var-rev, - "windows": $fa-var-windows, - "wizards-of-the-coast": $fa-var-wizards-of-the-coast, - "square-viadeo": $fa-var-square-viadeo, - "viadeo-square": $fa-var-viadeo-square, - "meetup": $fa-var-meetup, - "centos": $fa-var-centos, - "adn": $fa-var-adn, - "cloudsmith": $fa-var-cloudsmith, - "pied-piper-alt": $fa-var-pied-piper-alt, - "square-dribbble": $fa-var-square-dribbble, - "dribbble-square": $fa-var-dribbble-square, - "codiepie": $fa-var-codiepie, - "node": $fa-var-node, - "mix": $fa-var-mix, - "steam": $fa-var-steam, - "cc-apple-pay": $fa-var-cc-apple-pay, - "scribd": $fa-var-scribd, - "openid": $fa-var-openid, - "instalod": $fa-var-instalod, - "expeditedssl": $fa-var-expeditedssl, - "sellcast": $fa-var-sellcast, - "square-twitter": $fa-var-square-twitter, - "twitter-square": $fa-var-twitter-square, - "r-project": $fa-var-r-project, - "delicious": $fa-var-delicious, - "freebsd": $fa-var-freebsd, - "vuejs": $fa-var-vuejs, - "accusoft": $fa-var-accusoft, - "ioxhost": $fa-var-ioxhost, - "fonticons-fi": $fa-var-fonticons-fi, - "app-store": $fa-var-app-store, - "cc-mastercard": $fa-var-cc-mastercard, - "itunes-note": $fa-var-itunes-note, - "golang": $fa-var-golang, - "kickstarter": $fa-var-kickstarter, - "grav": $fa-var-grav, - "weibo": $fa-var-weibo, - "uncharted": $fa-var-uncharted, - "firstdraft": $fa-var-firstdraft, - "square-youtube": $fa-var-square-youtube, - "youtube-square": $fa-var-youtube-square, - "wikipedia-w": $fa-var-wikipedia-w, - "wpressr": $fa-var-wpressr, - "rendact": $fa-var-rendact, - "angellist": $fa-var-angellist, - "galactic-republic": $fa-var-galactic-republic, - "nfc-directional": $fa-var-nfc-directional, - "skype": $fa-var-skype, - "joget": $fa-var-joget, - "fedora": $fa-var-fedora, - "stripe-s": $fa-var-stripe-s, - "meta": $fa-var-meta, - "laravel": $fa-var-laravel, - "hotjar": $fa-var-hotjar, - "bluetooth-b": $fa-var-bluetooth-b, - "sticker-mule": $fa-var-sticker-mule, - "creative-commons-zero": $fa-var-creative-commons-zero, - "hips": $fa-var-hips, - "behance": $fa-var-behance, - "reddit": $fa-var-reddit, - "discord": $fa-var-discord, - "chrome": $fa-var-chrome, - "app-store-ios": $fa-var-app-store-ios, - "cc-discover": $fa-var-cc-discover, - "wpbeginner": $fa-var-wpbeginner, - "confluence": $fa-var-confluence, - "mdb": $fa-var-mdb, - "dochub": $fa-var-dochub, - "accessible-icon": $fa-var-accessible-icon, - "ebay": $fa-var-ebay, - "amazon": $fa-var-amazon, - "unsplash": $fa-var-unsplash, - "yarn": $fa-var-yarn, - "square-steam": $fa-var-square-steam, - "steam-square": $fa-var-steam-square, - "500px": $fa-var-500px, - "square-vimeo": $fa-var-square-vimeo, - "vimeo-square": $fa-var-vimeo-square, - "asymmetrik": $fa-var-asymmetrik, - "font-awesome": $fa-var-font-awesome, - "font-awesome-flag": $fa-var-font-awesome-flag, - "font-awesome-logo-full": $fa-var-font-awesome-logo-full, - "gratipay": $fa-var-gratipay, - "apple": $fa-var-apple, - "hive": $fa-var-hive, - "gitkraken": $fa-var-gitkraken, - "keybase": $fa-var-keybase, - "apple-pay": $fa-var-apple-pay, - "padlet": $fa-var-padlet, - "amazon-pay": $fa-var-amazon-pay, - "square-github": $fa-var-square-github, - "github-square": $fa-var-github-square, - "stumbleupon": $fa-var-stumbleupon, - "fedex": $fa-var-fedex, - "phoenix-framework": $fa-var-phoenix-framework, - "shopify": $fa-var-shopify, - "neos": $fa-var-neos, - "hackerrank": $fa-var-hackerrank, - "researchgate": $fa-var-researchgate, - "swift": $fa-var-swift, - "angular": $fa-var-angular, - "speakap": $fa-var-speakap, - "angrycreative": $fa-var-angrycreative, - "y-combinator": $fa-var-y-combinator, - "empire": $fa-var-empire, - "envira": $fa-var-envira, - "square-gitlab": $fa-var-square-gitlab, - "gitlab-square": $fa-var-gitlab-square, - "studiovinari": $fa-var-studiovinari, - "pied-piper": $fa-var-pied-piper, - "wordpress": $fa-var-wordpress, - "product-hunt": $fa-var-product-hunt, - "firefox": $fa-var-firefox, - "linode": $fa-var-linode, - "goodreads": $fa-var-goodreads, - "square-odnoklassniki": $fa-var-square-odnoklassniki, - "odnoklassniki-square": $fa-var-odnoklassniki-square, - "jsfiddle": $fa-var-jsfiddle, - "sith": $fa-var-sith, - "themeisle": $fa-var-themeisle, - "page4": $fa-var-page4, - "hashnode": $fa-var-hashnode, - "react": $fa-var-react, - "cc-paypal": $fa-var-cc-paypal, - "squarespace": $fa-var-squarespace, - "cc-stripe": $fa-var-cc-stripe, - "creative-commons-share": $fa-var-creative-commons-share, - "bitcoin": $fa-var-bitcoin, - "keycdn": $fa-var-keycdn, - "opera": $fa-var-opera, - "itch-io": $fa-var-itch-io, - "umbraco": $fa-var-umbraco, - "galactic-senate": $fa-var-galactic-senate, - "ubuntu": $fa-var-ubuntu, - "draft2digital": $fa-var-draft2digital, - "stripe": $fa-var-stripe, - "houzz": $fa-var-houzz, - "gg": $fa-var-gg, - "dhl": $fa-var-dhl, - "square-pinterest": $fa-var-square-pinterest, - "pinterest-square": $fa-var-pinterest-square, - "xing": $fa-var-xing, - "blackberry": $fa-var-blackberry, - "creative-commons-pd": $fa-var-creative-commons-pd, - "playstation": $fa-var-playstation, - "quinscape": $fa-var-quinscape, - "less": $fa-var-less, - "blogger-b": $fa-var-blogger-b, - "opencart": $fa-var-opencart, - "vine": $fa-var-vine, - "paypal": $fa-var-paypal, - "gitlab": $fa-var-gitlab, - "typo3": $fa-var-typo3, - "reddit-alien": $fa-var-reddit-alien, - "yahoo": $fa-var-yahoo, - "dailymotion": $fa-var-dailymotion, - "affiliatetheme": $fa-var-affiliatetheme, - "pied-piper-pp": $fa-var-pied-piper-pp, - "bootstrap": $fa-var-bootstrap, - "odnoklassniki": $fa-var-odnoklassniki, - "nfc-symbol": $fa-var-nfc-symbol, - "ethereum": $fa-var-ethereum, - "speaker-deck": $fa-var-speaker-deck, - "creative-commons-nc-eu": $fa-var-creative-commons-nc-eu, - "patreon": $fa-var-patreon, - "avianex": $fa-var-avianex, - "ello": $fa-var-ello, - "gofore": $fa-var-gofore, - "bimobject": $fa-var-bimobject, - "facebook-f": $fa-var-facebook-f, - "square-google-plus": $fa-var-square-google-plus, - "google-plus-square": $fa-var-google-plus-square, - "mandalorian": $fa-var-mandalorian, - "first-order-alt": $fa-var-first-order-alt, - "osi": $fa-var-osi, - "google-wallet": $fa-var-google-wallet, - "d-and-d-beyond": $fa-var-d-and-d-beyond, - "periscope": $fa-var-periscope, - "fulcrum": $fa-var-fulcrum, - "cloudscale": $fa-var-cloudscale, - "forumbee": $fa-var-forumbee, - "mizuni": $fa-var-mizuni, - "schlix": $fa-var-schlix, - "square-xing": $fa-var-square-xing, - "xing-square": $fa-var-xing-square, - "bandcamp": $fa-var-bandcamp, - "wpforms": $fa-var-wpforms, - "cloudversify": $fa-var-cloudversify, - "usps": $fa-var-usps, - "megaport": $fa-var-megaport, - "magento": $fa-var-magento, - "spotify": $fa-var-spotify, - "optin-monster": $fa-var-optin-monster, - "fly": $fa-var-fly, - "aviato": $fa-var-aviato, - "itunes": $fa-var-itunes, - "cuttlefish": $fa-var-cuttlefish, - "blogger": $fa-var-blogger, - "flickr": $fa-var-flickr, - "viber": $fa-var-viber, - "soundcloud": $fa-var-soundcloud, - "digg": $fa-var-digg, - "tencent-weibo": $fa-var-tencent-weibo, - "symfony": $fa-var-symfony, - "maxcdn": $fa-var-maxcdn, - "etsy": $fa-var-etsy, - "facebook-messenger": $fa-var-facebook-messenger, - "audible": $fa-var-audible, - "think-peaks": $fa-var-think-peaks, - "bilibili": $fa-var-bilibili, - "erlang": $fa-var-erlang, - "cotton-bureau": $fa-var-cotton-bureau, - "dashcube": $fa-var-dashcube, - "42-group": $fa-var-42-group, - "innosoft": $fa-var-innosoft, - "stack-exchange": $fa-var-stack-exchange, - "elementor": $fa-var-elementor, - "square-pied-piper": $fa-var-square-pied-piper, - "pied-piper-square": $fa-var-pied-piper-square, - "creative-commons-nd": $fa-var-creative-commons-nd, - "palfed": $fa-var-palfed, - "superpowers": $fa-var-superpowers, - "resolving": $fa-var-resolving, - "xbox": $fa-var-xbox, - "searchengin": $fa-var-searchengin, - "tiktok": $fa-var-tiktok, - "square-facebook": $fa-var-square-facebook, - "facebook-square": $fa-var-facebook-square, - "renren": $fa-var-renren, - "linux": $fa-var-linux, - "glide": $fa-var-glide, - "linkedin": $fa-var-linkedin, - "hubspot": $fa-var-hubspot, - "deploydog": $fa-var-deploydog, - "twitch": $fa-var-twitch, - "ravelry": $fa-var-ravelry, - "mixer": $fa-var-mixer, - "square-lastfm": $fa-var-square-lastfm, - "lastfm-square": $fa-var-lastfm-square, - "vimeo": $fa-var-vimeo, - "mendeley": $fa-var-mendeley, - "uniregistry": $fa-var-uniregistry, - "figma": $fa-var-figma, - "creative-commons-remix": $fa-var-creative-commons-remix, - "cc-amazon-pay": $fa-var-cc-amazon-pay, - "dropbox": $fa-var-dropbox, - "instagram": $fa-var-instagram, - "cmplid": $fa-var-cmplid, - "facebook": $fa-var-facebook, - "gripfire": $fa-var-gripfire, - "jedi-order": $fa-var-jedi-order, - "uikit": $fa-var-uikit, - "fort-awesome-alt": $fa-var-fort-awesome-alt, - "phabricator": $fa-var-phabricator, - "ussunnah": $fa-var-ussunnah, - "earlybirds": $fa-var-earlybirds, - "trade-federation": $fa-var-trade-federation, - "autoprefixer": $fa-var-autoprefixer, - "whatsapp": $fa-var-whatsapp, - "slideshare": $fa-var-slideshare, - "google-play": $fa-var-google-play, - "viadeo": $fa-var-viadeo, - "line": $fa-var-line, - "google-drive": $fa-var-google-drive, - "servicestack": $fa-var-servicestack, - "simplybuilt": $fa-var-simplybuilt, - "bitbucket": $fa-var-bitbucket, - "imdb": $fa-var-imdb, - "deezer": $fa-var-deezer, - "raspberry-pi": $fa-var-raspberry-pi, - "jira": $fa-var-jira, - "docker": $fa-var-docker, - "screenpal": $fa-var-screenpal, - "bluetooth": $fa-var-bluetooth, - "gitter": $fa-var-gitter, - "d-and-d": $fa-var-d-and-d, - "microblog": $fa-var-microblog, - "cc-diners-club": $fa-var-cc-diners-club, - "gg-circle": $fa-var-gg-circle, - "pied-piper-hat": $fa-var-pied-piper-hat, - "kickstarter-k": $fa-var-kickstarter-k, - "yandex": $fa-var-yandex, - "readme": $fa-var-readme, - "html5": $fa-var-html5, - "sellsy": $fa-var-sellsy, - "sass": $fa-var-sass, - "wirsindhandwerk": $fa-var-wirsindhandwerk, - "wsh": $fa-var-wsh, - "buromobelexperte": $fa-var-buromobelexperte, - "salesforce": $fa-var-salesforce, - "octopus-deploy": $fa-var-octopus-deploy, - "medapps": $fa-var-medapps, - "ns8": $fa-var-ns8, - "pinterest-p": $fa-var-pinterest-p, - "apper": $fa-var-apper, - "fort-awesome": $fa-var-fort-awesome, - "waze": $fa-var-waze, - "cc-jcb": $fa-var-cc-jcb, - "snapchat": $fa-var-snapchat, - "snapchat-ghost": $fa-var-snapchat-ghost, - "fantasy-flight-games": $fa-var-fantasy-flight-games, - "rust": $fa-var-rust, - "wix": $fa-var-wix, - "square-behance": $fa-var-square-behance, - "behance-square": $fa-var-behance-square, - "supple": $fa-var-supple, - "rebel": $fa-var-rebel, - "css3": $fa-var-css3, - "staylinked": $fa-var-staylinked, - "kaggle": $fa-var-kaggle, - "space-awesome": $fa-var-space-awesome, - "deviantart": $fa-var-deviantart, - "cpanel": $fa-var-cpanel, - "goodreads-g": $fa-var-goodreads-g, - "square-git": $fa-var-square-git, - "git-square": $fa-var-git-square, - "square-tumblr": $fa-var-square-tumblr, - "tumblr-square": $fa-var-tumblr-square, - "trello": $fa-var-trello, - "creative-commons-nc-jp": $fa-var-creative-commons-nc-jp, - "get-pocket": $fa-var-get-pocket, - "perbyte": $fa-var-perbyte, - "grunt": $fa-var-grunt, - "weebly": $fa-var-weebly, - "connectdevelop": $fa-var-connectdevelop, - "leanpub": $fa-var-leanpub, - "black-tie": $fa-var-black-tie, - "themeco": $fa-var-themeco, - "python": $fa-var-python, - "android": $fa-var-android, - "bots": $fa-var-bots, - "free-code-camp": $fa-var-free-code-camp, - "hornbill": $fa-var-hornbill, - "js": $fa-var-js, - "ideal": $fa-var-ideal, - "git": $fa-var-git, - "dev": $fa-var-dev, - "sketch": $fa-var-sketch, - "yandex-international": $fa-var-yandex-international, - "cc-amex": $fa-var-cc-amex, - "uber": $fa-var-uber, - "github": $fa-var-github, - "php": $fa-var-php, - "alipay": $fa-var-alipay, - "youtube": $fa-var-youtube, - "skyatlas": $fa-var-skyatlas, - "firefox-browser": $fa-var-firefox-browser, - "replyd": $fa-var-replyd, - "suse": $fa-var-suse, - "jenkins": $fa-var-jenkins, - "twitter": $fa-var-twitter, - "rockrms": $fa-var-rockrms, - "pinterest": $fa-var-pinterest, - "buffer": $fa-var-buffer, - "npm": $fa-var-npm, - "yammer": $fa-var-yammer, - "btc": $fa-var-btc, - "dribbble": $fa-var-dribbble, - "stumbleupon-circle": $fa-var-stumbleupon-circle, - "internet-explorer": $fa-var-internet-explorer, - "telegram": $fa-var-telegram, - "telegram-plane": $fa-var-telegram-plane, - "old-republic": $fa-var-old-republic, - "square-whatsapp": $fa-var-square-whatsapp, - "whatsapp-square": $fa-var-whatsapp-square, - "node-js": $fa-var-node-js, - "edge-legacy": $fa-var-edge-legacy, - "slack": $fa-var-slack, - "slack-hash": $fa-var-slack-hash, - "medrt": $fa-var-medrt, - "usb": $fa-var-usb, - "tumblr": $fa-var-tumblr, - "vaadin": $fa-var-vaadin, - "quora": $fa-var-quora, - "reacteurope": $fa-var-reacteurope, - "medium": $fa-var-medium, - "medium-m": $fa-var-medium-m, - "amilia": $fa-var-amilia, - "mixcloud": $fa-var-mixcloud, - "flipboard": $fa-var-flipboard, - "viacoin": $fa-var-viacoin, - "critical-role": $fa-var-critical-role, - "sitrox": $fa-var-sitrox, - "discourse": $fa-var-discourse, - "joomla": $fa-var-joomla, - "mastodon": $fa-var-mastodon, - "airbnb": $fa-var-airbnb, - "wolf-pack-battalion": $fa-var-wolf-pack-battalion, - "buy-n-large": $fa-var-buy-n-large, - "gulp": $fa-var-gulp, - "creative-commons-sampling-plus": $fa-var-creative-commons-sampling-plus, - "strava": $fa-var-strava, - "ember": $fa-var-ember, - "canadian-maple-leaf": $fa-var-canadian-maple-leaf, - "teamspeak": $fa-var-teamspeak, - "pushed": $fa-var-pushed, - "wordpress-simple": $fa-var-wordpress-simple, - "nutritionix": $fa-var-nutritionix, - "wodu": $fa-var-wodu, - "google-pay": $fa-var-google-pay, - "intercom": $fa-var-intercom, - "zhihu": $fa-var-zhihu, - "korvue": $fa-var-korvue, - "pix": $fa-var-pix, - "steam-symbol": $fa-var-steam-symbol, -); diff --git a/public/vendor/fontawesome/scss/brands.scss b/public/vendor/fontawesome/scss/brands.scss deleted file mode 100644 index 617535bba8..0000000000 --- a/public/vendor/fontawesome/scss/brands.scss +++ /dev/null @@ -1,30 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-brands: 'Font Awesome 6 Brands'; - --#{$fa-css-prefix}-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; -} - -@font-face { - font-family: 'Font Awesome 6 Brands'; - font-style: normal; - font-weight: 400; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'), - url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype'); -} - -.fab, -.#{$fa-css-prefix}-brands { - font-weight: 400; -} - -@each $name, $icon in $fa-brand-icons { - .#{$fa-css-prefix}-#{$name}:before { content: unquote("\"#{ $icon }\""); } -} diff --git a/public/vendor/fontawesome/scss/fontawesome.scss b/public/vendor/fontawesome/scss/fontawesome.scss deleted file mode 100644 index c14ee94283..0000000000 --- a/public/vendor/fontawesome/scss/fontawesome.scss +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -// Font Awesome core compile (Web Fonts-based) -// ------------------------- - -@import 'functions'; -@import 'variables'; -@import 'mixins'; -@import 'core'; -@import 'sizing'; -@import 'fixed-width'; -@import 'list'; -@import 'bordered-pulled'; -@import 'animated'; -@import 'rotated-flipped'; -@import 'stacked'; -@import 'icons'; -@import 'screen-reader'; diff --git a/public/vendor/fontawesome/scss/regular.scss b/public/vendor/fontawesome/scss/regular.scss deleted file mode 100644 index 0985c48df0..0000000000 --- a/public/vendor/fontawesome/scss/regular.scss +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }'; - --#{$fa-css-prefix}-font-regular: normal 400 1em/1 '#{ $fa-style-family }'; -} - -@font-face { - font-family: 'Font Awesome 6 Free'; - font-style: normal; - font-weight: 400; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'), - url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'); -} - -.far, -.#{$fa-css-prefix}-regular { - font-weight: 400; -} diff --git a/public/vendor/fontawesome/scss/solid.scss b/public/vendor/fontawesome/scss/solid.scss deleted file mode 100644 index 9b90120033..0000000000 --- a/public/vendor/fontawesome/scss/solid.scss +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }'; - --#{$fa-css-prefix}-font-solid: normal 900 1em/1 '#{ $fa-style-family }'; -} - -@font-face { - font-family: 'Font Awesome 6 Free'; - font-style: normal; - font-weight: 900; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'), - url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'); -} - -.fas, -.#{$fa-css-prefix}-solid { - font-weight: 900; -} diff --git a/public/vendor/fontawesome/scss/v4-shims.scss b/public/vendor/fontawesome/scss/v4-shims.scss deleted file mode 100644 index 2e267770a9..0000000000 --- a/public/vendor/fontawesome/scss/v4-shims.scss +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -// V4 shims compile (Web Fonts-based) -// ------------------------- - -@import 'functions'; -@import 'variables'; -@import 'shims'; diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf deleted file mode 100644 index 502f3621e7..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.woff2 deleted file mode 100644 index d801b51f66..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.woff2 and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.ttf deleted file mode 100644 index e0abe2710f..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.ttf and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.woff2 deleted file mode 100644 index d736e4b24c..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.woff2 and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf deleted file mode 100644 index 13c9489771..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 deleted file mode 100644 index 3516fdbe33..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf deleted file mode 100644 index dc2981941d..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf and /dev/null differ diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 deleted file mode 100644 index 28d46b15ac..0000000000 Binary files a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 and /dev/null differ diff --git a/src/api/chats.js b/src/api/chats.js index 2e7fe6dfd7..cf7bc6c7ee 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -2,10 +2,10 @@ const validator = require('validator'); +const db = require('../database'); const user = require('../user'); const meta = require('../meta'); const messaging = require('../messaging'); -const notifications = require('../notifications'); const plugins = require('../plugins'); const privileges = require('../privileges'); @@ -39,12 +39,30 @@ chatsAPI.create = async function (caller, data) { if (!data) { throw new Error('[[error:invalid-data]]'); } + + const isPublic = data.type === 'public'; + const isAdmin = await user.isAdministrator(caller.uid); + if (isPublic && !isAdmin) { + throw new Error('[[error:no-privileges]]'); + } + if (!data.uids || !Array.isArray(data.uids)) { throw new Error(`[[error:wrong-parameter-type, uids, ${typeof data.uids}, Array]]`); } + if (!isPublic && !data.uids.length) { + throw new Error('[[error:no-users-selected]]'); + } + if (isPublic && (!Array.isArray(data.groups) || !data.groups.length)) { + throw new Error('[[error:no-groups-selected]]'); + } + + data.notificationSetting = isPublic ? + messaging.notificationSettings.ATMENTION : + messaging.notificationSettings.ALLMESSAGES; + await Promise.all(data.uids.map(async uid => messaging.canMessageUser(caller.uid, uid))); - const roomId = await messaging.newRoom(caller.uid, data.uids); + const roomId = await messaging.newRoom(caller.uid, data); return await messaging.getRoomData(roomId); }; @@ -69,6 +87,7 @@ chatsAPI.post = async (caller, data) => { uid: caller.uid, roomId: data.roomId, content: data.message, + toMid: data.toMid, timestamp: Date.now(), ip: caller.ip, }); @@ -78,18 +97,53 @@ chatsAPI.post = async (caller, data) => { return message; }; +chatsAPI.update = async (caller, data) => { + if (!data || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + if (data.hasOwnProperty('name')) { + if (!data.name && data.name !== '') { + throw new Error('[[error:invalid-data]]'); + } + await messaging.renameRoom(caller.uid, data.roomId, data.name); + } + const [roomData, isAdmin] = await Promise.all([ + messaging.getRoomData(data.roomId), + user.isAdministrator(caller.uid), + ]); + if (!roomData) { + throw new Error('[[error:invalid-data]]'); + } + if (data.hasOwnProperty('groups')) { + if (roomData.public && isAdmin) { + await db.setObjectField(`chat:room:${data.roomId}`, 'groups', JSON.stringify(data.groups)); + } + } + if (data.hasOwnProperty('notificationSetting') && isAdmin) { + await db.setObjectField(`chat:room:${data.roomId}`, 'notificationSetting', data.notificationSetting); + } + const loadedRoom = await messaging.loadRoom(caller.uid, { + roomId: data.roomId, + }); + if (data.hasOwnProperty('name')) { + const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); + if (ioRoom) { + ioRoom.emit('event:chats.roomRename', { + roomId: data.roomId, + newName: validator.escape(String(data.name)), + chatWithMessage: loadedRoom.chatWithMessage, + }); + } + } + return loadedRoom; +}; + chatsAPI.rename = async (caller, data) => { if (!data || !data.roomId || !data.name) { throw new Error('[[error:invalid-data]]'); } - await messaging.renameRoom(caller.uid, data.roomId, data.name); - const uids = await messaging.getUidsInRoom(data.roomId, 0, -1); - const eventData = { roomId: data.roomId, newName: validator.escape(String(data.name)) }; - - socketHelpers.emitToUids('event:chats.roomRename', eventData, uids); - return messaging.loadRoom(caller.uid, { - roomId: data.roomId, - }); + return await chatsAPI.update(caller, data); }; chatsAPI.mark = async (caller, data) => { @@ -102,37 +156,33 @@ chatsAPI.mark = async (caller, data) => { } else { await messaging.markRead(caller.uid, roomId); socketHelpers.emitToUids('event:chats.markedAsRead', { roomId: roomId }, [caller.uid]); - - const uidsInRoom = await messaging.getUidsInRoom(roomId, 0, -1); - if (!uidsInRoom.includes(String(caller.uid))) { - return; - } - - // Mark notification read - const nids = uidsInRoom.filter(uid => parseInt(uid, 10) !== caller.uid) - .map(uid => `chat_${uid}_${roomId}`); - - await notifications.markReadMultiple(nids, caller.uid); - await user.notifications.pushCount(caller.uid); } socketHelpers.emitToUids('event:chats.mark', { roomId, state }, [caller.uid]); messaging.pushUnreadCount(caller.uid); - - return messaging.loadRoom(caller.uid, { roomId }); }; chatsAPI.users = async (caller, data) => { - const [isOwner, isUserInRoom, users] = await Promise.all([ + const start = data.hasOwnProperty('start') ? data.start : 0; + const stop = start + 39; + const io = require('../socket.io'); + const [isOwner, isUserInRoom, users, isAdmin, onlineUids] = await Promise.all([ messaging.isRoomOwner(caller.uid, data.roomId), messaging.isUserInRoom(caller.uid, data.roomId), - messaging.getUsersInRoom(data.roomId, 0, -1), + messaging.getUsersInRoomFromSet( + `chat:room:${data.roomId}:uids:online`, data.roomId, start, stop, true + ), + user.isAdministrator(caller.uid), + io.getUidsInRoom(`chat_room_${data.roomId}`), ]); if (!isUserInRoom) { throw new Error('[[error:no-privileges]]'); } users.forEach((user) => { - user.canKick = (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)) && isOwner; + const isSelf = parseInt(user.uid, 10) === parseInt(caller.uid, 10); + user.canKick = isOwner && !isSelf; + user.canToggleOwner = (isAdmin || isOwner) && !isSelf; + user.online = parseInt(user.uid, 10) === parseInt(caller.uid, 10) || onlineUids.includes(String(user.uid)); }); return { users }; }; @@ -145,10 +195,13 @@ chatsAPI.invite = async (caller, data) => { if (!data || !data.roomId) { throw new Error('[[error:invalid-data]]'); } - + const roomData = await messaging.getRoomData(data.roomId); + if (!roomData) { + throw new Error('[[error:invalid-data]]'); + } const userCount = await messaging.getUserCountInRoom(data.roomId); const maxUsers = meta.config.maximumUsersInChatRoom; - if (maxUsers && userCount >= maxUsers) { + if (!roomData.public && maxUsers && userCount >= maxUsers) { throw new Error('[[error:cant-add-more-users-to-chat-room]]'); } @@ -175,10 +228,11 @@ chatsAPI.kick = async (caller, data) => { // Additional checks if kicking vs leaving if (data.uids.length === 1 && parseInt(data.uids[0], 10) === caller.uid) { await messaging.leaveRoom([caller.uid], data.roomId); + await socketHelpers.removeSocketsFromRoomByUids([caller.uid], data.roomId); return []; } await messaging.removeUsersFromRoom(caller.uid, data.uids, data.roomId); - + await socketHelpers.removeSocketsFromRoomByUids(data.uids, data.roomId); delete data.uids; return chatsAPI.users(caller, data); }; diff --git a/src/api/utils.js b/src/api/utils.js index 4597bed42b..67e496a5f5 100644 --- a/src/api/utils.js +++ b/src/api/utils.js @@ -94,9 +94,11 @@ utils.tokens.roll = async (token) => { const updates = [ db.rename(`token:${token}`, `token:${newToken}`), - db.sortedSetRemove(`tokens:createtime`, token), - db.sortedSetRemove(`tokens:uid`, token), - db.sortedSetRemove(`tokens:lastSeen`, token), + db.sortedSetsRemove([ + `tokens:createtime`, + `tokens:uid`, + `tokens:lastSeen`, + ], token), db.sortedSetAdd(`tokens:createtime`, createTime, newToken), db.sortedSetAdd(`tokens:uid`, uid, newToken), ]; @@ -113,9 +115,11 @@ utils.tokens.roll = async (token) => { utils.tokens.delete = async (token) => { await Promise.all([ db.delete(`token:${token}`), - db.sortedSetRemove(`tokens:createtime`, token), - db.sortedSetRemove(`tokens:uid`, token), - db.sortedSetRemove(`tokens:lastSeen`, token), + db.sortedSetsRemove([ + `tokens:createtime`, + `tokens:uid`, + `tokens:lastSeen`, + ], token), ]); }; diff --git a/src/batch.js b/src/batch.js index 8442def721..edc4038055 100644 --- a/src/batch.js +++ b/src/batch.js @@ -23,6 +23,7 @@ exports.processSortedSet = async function (setKey, process, options) { } options.batch = options.batch || DEFAULT_BATCH_SIZE; + options.reverse = options.reverse || false; // use the fast path if possible if (db.processSortedSet && typeof options.doneIf !== 'function' && !utils.isNumber(options.alwaysStartAt)) { @@ -38,21 +39,21 @@ exports.processSortedSet = async function (setKey, process, options) { if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); } - + const method = options.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'; + let iteration = 1; while (true) { /* eslint-disable no-await-in-loop */ - const ids = await db[`getSortedSetRange${options.withScores ? 'WithScores' : ''}`](setKey, start, stop); + const ids = await db[`${method}${options.withScores ? 'WithScores' : ''}`](setKey, start, stop); if (!ids.length || options.doneIf(start, stop, ids)) { return; } - await process(ids); - - start += utils.isNumber(options.alwaysStartAt) ? options.alwaysStartAt : options.batch; - stop = start + options.batch - 1; - - if (options.interval) { + if (iteration > 1 && options.interval) { await sleep(options.interval); } + await process(ids); + iteration += 1; + start += utils.isNumber(options.alwaysStartAt) ? options.alwaysStartAt : options.batch; + stop = start + options.batch - 1; } }; @@ -71,21 +72,20 @@ exports.processArray = async function (array, process, options) { if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); } - + let iteration = 1; while (true) { const currentBatch = array.slice(start, start + batch); if (!currentBatch.length) { return; } - + if (iteration > 1 && options.interval) { + await sleep(options.interval); + } await process(currentBatch); start += batch; - - if (options.interval) { - await sleep(options.interval); - } + iteration += 1; } }; diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js index 02c9b404cc..221e1f5fae 100644 --- a/src/controllers/accounts/chats.js +++ b/src/controllers/accounts/chats.js @@ -1,5 +1,6 @@ 'use strict'; +const db = require('../../database'); const messaging = require('../../messaging'); const meta = require('../../meta'); const user = require('../../user'); @@ -21,35 +22,45 @@ chatsController.get = async function (req, res, next) { if (!canChat) { return next(new Error('[[error:no-privileges]]')); } - const recentChats = await messaging.getRecentChats(req.uid, uid, 0, 29); - if (!recentChats) { - return next(); + + const payload = { + title: '[[pages:chats]]', + uid: uid, + userslug: req.params.userslug, + }; + const isSwitch = res.locals.isAPI && parseInt(req.query.switch, 10) === 1; + if (!isSwitch) { + const [recentChats, publicRooms, privateRoomCount] = await Promise.all([ + messaging.getRecentChats(req.uid, uid, 0, 29), + messaging.getPublicRooms(req.uid, uid), + db.sortedSetCard(`uid:${uid}:chat:rooms`), + ]); + if (!recentChats) { + return next(); + } + payload.rooms = recentChats.rooms; + payload.nextStart = recentChats.nextStart; + payload.publicRooms = publicRooms; + payload.privateRoomCount = privateRoomCount; } if (!req.params.roomid) { - return res.render('chats', { - rooms: recentChats.rooms, - uid: uid, - userslug: req.params.userslug, - nextStart: recentChats.nextStart, - allowed: true, - title: '[[pages:chats]]', - }); + return res.render('chats', payload); } + const room = await messaging.loadRoom(req.uid, { uid: uid, roomId: req.params.roomid }); if (!room) { return next(); } - room.rooms = recentChats.rooms; - room.nextStart = recentChats.nextStart; room.title = room.roomName || room.usernames || '[[pages:chats]]'; - room.uid = uid; - room.userslug = req.params.userslug; - + room.bodyClasses = ['chat-loaded']; room.canViewInfo = await privileges.global.can('view:users:info', uid); - res.render('chats', room); + res.render('chats', { + ...payload, + ...room, + }); }; chatsController.redirectToChat = async function (req, res, next) { diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index d2737ee314..1ef9756784 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -93,7 +93,7 @@ async function getPosts(callerUid, userData, setSuffix) { user.isModerator(callerUid, cids), privileges.categories.isUserAllowedTo('topics:schedule', cids, callerUid), ]); - const cidToIsMod = _.zipObject(cids, isModOfCids); + const isModOfCid = _.zipObject(cids, isModOfCids); const cidToCanSchedule = _.zipObject(cids, canSchedule); do { @@ -111,8 +111,12 @@ async function getPosts(callerUid, userData, setSuffix) { })); const p = await posts.getPostSummaryByPids(pids, callerUid, { stripTags: false }); postData.push(...p.filter( - p => p && p.topic && (isAdmin || cidToIsMod[p.topic.cid] || - (p.topic.scheduled && cidToCanSchedule[p.topic.cid]) || (!p.deleted && !p.topic.deleted)) + p => p && p.topic && ( + isAdmin || + isModOfCid[p.topic.cid] || + (p.topic.scheduled && cidToCanSchedule[p.topic.cid]) || + (!p.deleted && !p.topic.deleted) + ) )); } start += count; diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js index 597f8ff55e..852adee41c 100644 --- a/src/controllers/admin/categories.js +++ b/src/controllers/admin/categories.js @@ -134,12 +134,14 @@ async function buildBreadcrumbs(categoryData, url) { categoriesController.buildBreadCrumbs = buildBreadcrumbs; categoriesController.getAnalytics = async function (req, res) { - const [name, analyticsData] = await Promise.all([ + const [name, analyticsData, selectedData] = await Promise.all([ categories.getCategoryField(req.params.category_id, 'name'), analytics.getCategoryAnalytics(req.params.category_id), + helpers.getSelectedCategory(req.params.category_id), ]); res.render('admin/manage/category-analytics', { name: name, analytics: analyticsData, + selectedCategory: selectedData.selectedCategory, }); }; diff --git a/src/controllers/api.js b/src/controllers/api.js index e0f23206f9..7aebe9c3e3 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -10,6 +10,7 @@ const plugins = require('../plugins'); const translator = require('../translator'); const languages = require('../languages'); const { generateToken } = require('../middleware/csrf'); +const utils = require('../utils'); const apiController = module.exports; @@ -19,6 +20,9 @@ const asset_base_url = nconf.get('asset_base_url'); const socketioTransports = nconf.get('socket.io:transports') || ['polling', 'websocket']; const socketioOrigins = nconf.get('socket.io:origins'); const websocketAddress = nconf.get('socket.io:address') || ''; +const fontawesome_pro = nconf.get('fontawesome:pro') || false; +const fontawesome_styles = utils.getFontawesomeStyles(); +const fontawesome_version = utils.getFontawesomeVersion(); apiController.loadConfig = async function (req) { const config = { @@ -86,6 +90,11 @@ apiController.loadConfig = async function (req) { iconBackgrounds: await user.getIconBackgrounds(req.uid), emailPrompt: meta.config.emailPrompt, useragent: req.useragent, + fontawesome: { + pro: fontawesome_pro, + styles: fontawesome_styles, + version: fontawesome_version, + }, }; let settings = config; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index dcd9aa371f..08515f1124 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -102,6 +102,8 @@ authenticationController.register = async function (req, res) { user.isPasswordValid(userData.password); + await plugins.hooks.fire('filter:password.check', { password: userData.password, uid: 0, userData: userData }); + res.locals.processLogin = true; // set it to false in plugin if you wish to just register only await plugins.hooks.fire('filter:register.check', { req: req, res: res, userData: userData }); @@ -210,7 +212,7 @@ authenticationController.registerComplete = async function (req, res) { }; authenticationController.registerAbort = async (req, res) => { - if (req.uid) { + if (req.uid && req.session.registration) { // Email is the only cancelable interstitial delete req.session.registration.updateEmail; diff --git a/src/controllers/composer.js b/src/controllers/composer.js index 9475fbdba5..bc1e4283c3 100644 --- a/src/controllers/composer.js +++ b/src/controllers/composer.js @@ -46,6 +46,7 @@ exports.post = async function (req, res) { req: req, timestamp: Date.now(), content: body.content, + handle: body.handle, fromQueue: false, }; req.body.noscript = 'true'; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index ad63672e56..fd3a3b9966 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -209,8 +209,8 @@ async function addTags(topicData, req, res, currentPage) { description = utils.stripHTMLTags(utils.decodeHTMLEntities(postAtIndex.content)); } - if (description.length > 255) { - description = `${description.slice(0, 255)}...`; + if (description.length > 160) { + description = `${description.slice(0, 157)}...`; } description = description.replace(/\n/g, ' '); diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 46871ca076..d5105d25f1 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -163,8 +163,8 @@ uploadsController.uploadFile = async function (uid, uploadedFile) { if (!uploadedFile) { throw new Error('[[error:invalid-file]]'); } - - if (uploadedFile.size > meta.config.maximumFileSize * 1024) { + const isAdmin = await user.isAdministrator(uid); + if (!isAdmin && uploadedFile.size > meta.config.maximumFileSize * 1024) { throw new Error(`[[error:file-too-big, ${meta.config.maximumFileSize}]]`); } diff --git a/src/controllers/users.js b/src/controllers/users.js index 7506a8c8d3..2f697c4b9c 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -61,7 +61,6 @@ usersController.getOnlineUsers = async function (req, res) { } userData.anonymousUserCount = guests + hiddenCount; - userData.timeagoCutoff = 1; await render(req, res, userData); }; diff --git a/src/controllers/write/admin.js b/src/controllers/write/admin.js index b7ba39db10..84d25ac300 100644 --- a/src/controllers/write/admin.js +++ b/src/controllers/write/admin.js @@ -2,6 +2,8 @@ const api = require('../../api'); const helpers = require('../helpers'); +const messaging = require('../../messaging'); +const events = require('../../events'); const Admin = module.exports; @@ -29,6 +31,19 @@ Admin.getAnalyticsData = async (req, res) => { })); }; +Admin.chats = {}; + +Admin.chats.deleteRoom = async (req, res) => { + await messaging.deleteRooms([req.params.roomId]); + + events.log({ + type: 'chat-room-deleted', + uid: req.uid, + ip: req.ip, + }); + helpers.formatApiResponse(200, res); +}; + Admin.generateToken = async (req, res) => { const { uid, description } = req.body; const token = await api.utils.tokens.generate({ uid, description }); diff --git a/src/controllers/write/chats.js b/src/controllers/write/chats.js index fe7900a50a..f6b9378836 100644 --- a/src/controllers/write/chats.js +++ b/src/controllers/write/chats.js @@ -33,12 +33,21 @@ Chats.get = async (req, res) => { Chats.post = async (req, res) => { const messageObj = await api.chats.post(req, { message: req.body.message, + toMid: req.body.toMid, roomId: req.params.roomId, }); helpers.formatApiResponse(200, res, messageObj); }; +Chats.update = async (req, res) => { + const payload = { ...req.body }; + payload.roomId = req.params.roomId; + const roomObj = await api.chats.update(req, payload); + + helpers.formatApiResponse(200, res, roomObj); +}; + Chats.rename = async (req, res) => { const roomObj = await api.chats.rename(req, { name: req.body.name, @@ -50,17 +59,18 @@ Chats.rename = async (req, res) => { Chats.mark = async (req, res) => { const state = req.method === 'PUT' ? 1 : 0; - const roomObj = await api.chats.mark(req, { + await api.chats.mark(req, { roomId: req.params.roomId, state, }); - helpers.formatApiResponse(200, res, roomObj); + helpers.formatApiResponse(200, res); }; Chats.users = async (req, res) => { const { roomId } = req.params; - const users = await api.chats.users(req, { roomId }); + const start = parseInt(req.query.start, 10) || 0; + const users = await api.chats.users(req, { roomId, start }); helpers.formatApiResponse(200, res, users); }; diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index ec9cfa051b..699d63cc4e 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -26,7 +26,8 @@ module.exports = function (module) { await module.client.collection('objects').updateOne({ _key: key }, { $set: writeData }, { upsert: true }); } } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, data); return await module.setObject(key, data); } throw err; @@ -61,7 +62,8 @@ module.exports = function (module) { await bulk.execute(); } } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, data); return await module.setObjectBulk(data); } throw err; @@ -255,7 +257,8 @@ module.exports = function (module) { // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, field, value); return await module.incrObjectFieldBy(key, field, value); } throw err; diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index c4b9615c9e..42051bc2a4 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -51,7 +51,8 @@ module.exports = function (module) { try { await bulk.execute(); } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, keys, value); return await module.setsAdd(keys, value); } throw err; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index d5db6c3451..9dbf947b1a 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -84,7 +84,9 @@ module.exports = function (module) { let result = []; async function doQuery(_key, fields, skip, limit) { - return await module.client.collection('objects').find({ ...query, ...{ _key: _key } }, { projection: fields }) + return await module.client.collection('objects').find({ + ...query, ...{ _key: _key }, + }, { projection: fields }) .sort({ score: sort }) .skip(skip) .limit(limit) @@ -441,7 +443,8 @@ module.exports = function (module) { // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, increment, value); return await module.sortedSetIncrBy(key, increment, value); } throw err; @@ -560,12 +563,12 @@ module.exports = function (module) { let done = false; const ids = []; const project = { _id: 0, _key: 0 }; - + const sort = options.reverse ? -1 : 1; if (!options.withScores) { project.score = 0; } const cursor = await module.client.collection('objects').find({ _key: setKey }, { projection: project }) - .sort({ score: 1 }) + .sort({ score: sort }) .batchSize(options.batch); if (processFn && processFn.constructor && processFn.constructor.name !== 'AsyncFunction') { diff --git a/src/database/mongo/sorted/add.js b/src/database/mongo/sorted/add.js index 13ee427c23..bc3a8bc8ec 100644 --- a/src/database/mongo/sorted/add.js +++ b/src/database/mongo/sorted/add.js @@ -19,7 +19,8 @@ module.exports = function (module) { try { await module.client.collection('objects').updateOne({ _key: key, value: value }, { $set: { score: parseFloat(score) } }, { upsert: true }); } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, score, value); return await module.sortedSetAdd(key, score, value); } throw err; diff --git a/src/database/postgres/sorted.js b/src/database/postgres/sorted.js index 2ed679b683..70e66af314 100644 --- a/src/database/postgres/sorted.js +++ b/src/database/postgres/sorted.js @@ -664,6 +664,7 @@ SELECT z."value", module.processSortedSet = async function (setKey, process, options) { const client = await module.pool.connect(); const batchSize = (options || {}).batch || 100; + const sort = options.reverse ? 'DESC' : 'ASC'; const cursor = client.query(new Cursor(` SELECT z."value", z."score" FROM "legacy_object_live" o @@ -671,7 +672,7 @@ SELECT z."value", z."score" ON o."_key" = z."_key" AND o."type" = z."type" WHERE o."_key" = $1::TEXT - ORDER BY z."score" ASC, z."value" ASC`, [setKey])); + ORDER BY z."score" ${sort}, z."value" ${sort}`, [setKey])); if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); diff --git a/src/database/redis/main.js b/src/database/redis/main.js index c2e030b42c..8b79afb07c 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -26,7 +26,7 @@ module.exports = function (module) { module.scan = async function (params) { let cursor = '0'; let returnData = []; - const seen = {}; + const seen = Object.create(null); do { /* eslint-disable no-await-in-loop */ const res = await module.client.scan(cursor, 'MATCH', params.match, 'COUNT', 10000); diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 6a38b5eced..07a30bab05 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -310,7 +310,7 @@ module.exports = function (module) { const returnData = []; let done = false; - const seen = {}; + const seen = Object.create(null); do { /* eslint-disable no-await-in-loop */ const res = await module.client.zscan(params.key, cursor, 'MATCH', params.match, 'COUNT', 5000); diff --git a/src/events.js b/src/events.js index 637f53acf6..7329aa486e 100644 --- a/src/events.js +++ b/src/events.js @@ -75,6 +75,7 @@ events.types = [ 'export:uploads', 'account-locked', 'getUsersCSV', + 'chat-room-deleted', // To add new types from plugins, just Array.push() to this array ]; @@ -100,13 +101,17 @@ events.log = async function (data) { events.getEvents = async function (filter, start, stop, from, to) { // from/to optional if (from === undefined) { - from = 0; + from = '-inf'; } if (to === undefined) { - to = Date.now(); + to = '+inf'; } - const eids = await db.getSortedSetRevRangeByScore(`events:time${filter ? `:${filter}` : ''}`, start, stop - start + 1, to, from); + const eids = await db.getSortedSetRevRangeByScore(`events:time${filter ? `:${filter}` : ''}`, start, stop === -1 ? -1 : stop - start + 1, to, from); + return await events.getEventsByEventIds(eids); +}; + +events.getEventsByEventIds = async (eids) => { let eventsData = await db.getObjects(eids.map(eid => `event:${eid}`)); eventsData = eventsData.filter(Boolean); await addUserData(eventsData, 'uid', 'user'); diff --git a/src/flags.js b/src/flags.js index 904f1f71dc..1c9dd3a5e1 100644 --- a/src/flags.js +++ b/src/flags.js @@ -680,6 +680,11 @@ Flags.update = async function (flagId, uid, changeset) { return allowed; }; + async function rescindNotifications(match) { + const nids = await db.getSortedSetScan({ key: 'notifications', match: `${match}*` }); + return notifications.rescind(nids); + } + // Retrieve existing flag data to compare for history-saving/reference purposes const tasks = []; for (const prop of Object.keys(changeset)) { @@ -692,10 +697,10 @@ Flags.update = async function (flagId, uid, changeset) { tasks.push(db.sortedSetAdd(`flags:byState:${changeset[prop]}`, now, flagId)); tasks.push(db.sortedSetRemove(`flags:byState:${current[prop]}`, flagId)); if (changeset[prop] === 'resolved' && meta.config['flags:actionOnResolve'] === 'rescind') { - tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`)); + tasks.push(rescindNotifications(`flag:${current.type}:${current.targetId}`)); } if (changeset[prop] === 'rejected' && meta.config['flags:actionOnReject'] === 'rescind') { - tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`)); + tasks.push(rescindNotifications(`flag:${current.type}:${current.targetId}`)); } } } else if (prop === 'assignee') { @@ -844,7 +849,7 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) { bodyLong: await plugins.hooks.fire('filter:parse.raw', String(flagObj.description || '')), pid: flagObj.targetId, path: `/flags/${flagObj.flagId}`, - nid: `flag:post:${flagObj.targetId}`, + nid: `flag:post:${flagObj.targetId}:${uid}`, from: uid, mergeId: `notifications:user_flagged_post_in|${flagObj.targetId}`, topicTitle: title, @@ -857,7 +862,7 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) { bodyShort: `[[notifications:user_flagged_user, ${displayname}, ${targetDisplayname}]]`, bodyLong: await plugins.hooks.fire('filter:parse.raw', String(flagObj.description || '')), path: `/flags/${flagObj.flagId}`, - nid: `flag:user:${flagObj.targetId}`, + nid: `flag:user:${flagObj.targetId}:${uid}`, from: uid, mergeId: `notifications:user_flagged_user|${flagObj.targetId}`, }); diff --git a/src/groups/invite.js b/src/groups/invite.js index ddb244cd0a..0683994801 100644 --- a/src/groups/invite.js +++ b/src/groups/invite.js @@ -45,6 +45,7 @@ module.exports = function (Groups) { bodyShort: `[[groups:membership.accept.notification_title, ${groupName}]]`, nid: `group:${groupName}:uid:${uid}:invite-accepted`, path: `/groups/${slugify(groupName)}`, + icon: 'fa-users', }); await notifications.push(notification, [uid]); }; @@ -68,6 +69,7 @@ module.exports = function (Groups) { bodyLong: '', nid: `group:${groupName}:uid:${uid}:invite`, path: `/groups/${slugify(groupName)}`, + icon: 'fa-users', }))); await Promise.all(uids.map((uid, index) => notifications.push(notificationData[index], uid))); diff --git a/src/groups/leave.js b/src/groups/leave.js index 14bfb2558c..32495232c9 100644 --- a/src/groups/leave.js +++ b/src/groups/leave.js @@ -1,9 +1,12 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../database'); const user = require('../user'); const plugins = require('../plugins'); const cache = require('../cache'); +const messaging = require('../messaging'); module.exports = function (Groups) { Groups.leave = async function (groupNames, uid) { @@ -53,7 +56,10 @@ module.exports = function (Groups) { await Promise.all(promises); - await clearGroupTitleIfSet(groupsToLeave, uid); + await Promise.all([ + clearGroupTitleIfSet(groupsToLeave, uid), + leavePublicRooms(groupsToLeave, uid), + ]); plugins.hooks.fire('action:group.leave', { groupNames: groupsToLeave, @@ -61,6 +67,20 @@ module.exports = function (Groups) { }); }; + async function leavePublicRooms(groupNames, uid) { + const allRoomIds = await messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); + const allRoomData = await messaging.getRoomsData(allRoomIds); + const roomData = allRoomData.filter( + room => room && room.groups.some(group => groupNames.includes(group)) + ); + const isMemberOfAny = _.zipObject( + roomData.map(r => r.roomId), + await Promise.all(roomData.map(r => Groups.isMemberOfAny(uid, r.groups))) + ); + const roomIds = roomData.filter(r => isMemberOfAny[r.roomId]).map(r => r.roomId); + await messaging.leaveRooms(uid, roomIds); + } + async function clearGroupTitleIfSet(groupNames, uid) { groupNames = groupNames.filter(groupName => groupName !== 'registered-users' && !Groups.isPrivilegeGroup(groupName)); if (!groupNames.length) { diff --git a/src/groups/membership.js b/src/groups/membership.js index 66af1c1ed1..aa25719652 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -97,7 +97,7 @@ module.exports = function (Groups) { } Groups.isMemberOfAny = async function (uid, groups) { - if (!groups.length) { + if (!Array.isArray(groups) || !groups.length) { return false; } const isMembers = await Groups.isMemberOfGroups(uid, groups); diff --git a/src/groups/update.js b/src/groups/update.js index 56b541df27..ced53ef04e 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -189,6 +189,7 @@ module.exports = function (Groups) { await updateNavigationItems(oldName, newName); await updateWidgets(oldName, newName); await updateConfig(oldName, newName); + await updateChatRooms(oldName, newName); await db.setObject(`group:${oldName}`, { name: newName, slug: slugify(newName) }); await db.deleteObjectField('groupslug:groupname', group.slug); await db.setObjectField('groupslug:groupname', slugify(newName), newName); @@ -286,4 +287,18 @@ module.exports = function (Groups) { await meta.configs.set('groupsExemptFromMaintenanceMode', meta.config.groupsExemptFromMaintenanceMode); } } + + async function updateChatRooms(oldName, newName) { + const messaging = require('../messaging'); + const roomIds = await db.getSortedSetRange('chat:rooms:public', 0, -1); + const roomData = await messaging.getRoomsData(roomIds); + const bulkSet = []; + roomData.forEach((room) => { + if (room && room.public && Array.isArray(room.groups) && room.groups.includes(oldName)) { + room.groups.splice(room.groups.indexOf(oldName), 1, newName); + bulkSet.push([`chat:room:${room.roomId}`, { groups: JSON.stringify(room.groups) }]); + } + }); + await db.setObjectBulk(bulkSet); + } }; diff --git a/src/messaging/create.js b/src/messaging/create.js index d78a0afe4c..81da98d0d6 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -1,9 +1,12 @@ 'use strict'; +const _ = require('lodash'); + const meta = require('../meta'); const plugins = require('../plugins'); const db = require('../database'); const user = require('../user'); +const utils = require('../utils'); module.exports = function (Messaging) { Messaging.sendMessage = async (data) => { @@ -34,16 +37,29 @@ module.exports = function (Messaging) { }; Messaging.addMessage = async (data) => { + const { uid, roomId } = data; + const roomData = await Messaging.getRoomData(roomId); + if (!roomData) { + throw new Error('[[error:no-room]]'); + } + if (data.toMid && !utils.isNumber(data.toMid)) { + throw new Error('[[error:invalid-mid]]'); + } const mid = await db.incrObjectField('global', 'nextMid'); const timestamp = data.timestamp || Date.now(); let message = { + mid: mid, content: String(data.content), timestamp: timestamp, - fromuid: data.uid, - roomId: data.roomId, - deleted: 0, - system: data.system || 0, + fromuid: uid, + roomId: roomId, }; + if (data.toMid) { + message.toMid = data.toMid; + } + if (data.system) { + message.system = data.system; + } if (data.ip) { message.ip = data.ip; @@ -51,25 +67,38 @@ module.exports = function (Messaging) { message = await plugins.hooks.fire('filter:messaging.save', message); await db.setObject(`message:${mid}`, message); - const isNewSet = await Messaging.isNewSet(data.uid, data.roomId, timestamp); - let uids = await db.getSortedSetRange(`chat:room:${data.roomId}:uids`, 0, -1); - uids = await user.blocks.filterUids(data.uid, uids); + const isNewSet = await Messaging.isNewSet(uid, roomId, timestamp); - await Promise.all([ - Messaging.addRoomToUsers(data.roomId, uids, timestamp), - Messaging.addMessageToUsers(data.roomId, uids, mid, timestamp), - Messaging.markUnread(uids.filter(uid => uid !== String(data.uid)), data.roomId), - ]); + const tasks = [ + Messaging.addMessageToRoom(roomId, mid, timestamp), + Messaging.markRead(uid, roomId), + db.sortedSetAdd('messages:mid', timestamp, mid), + db.incrObjectField('global', 'messageCount'), + ]; + if (data.toMid) { + tasks.push(db.sortedSetAdd(`mid:${data.toMid}:replies`, timestamp, mid)); + } + if (roomData.public) { + tasks.push( + db.sortedSetAdd('chat:rooms:public:lastpost', timestamp, roomId) + ); + } else { + let uids = await Messaging.getUidsInRoom(roomId, 0, -1); + uids = await user.blocks.filterUids(uid, uids); + tasks.push( + Messaging.addRoomToUsers(roomId, uids, timestamp), + Messaging.markUnread(uids.filter(uid => uid !== String(data.uid)), roomId), + ); + } + await Promise.all(tasks); - const messages = await Messaging.getMessagesData([mid], data.uid, data.roomId, true); + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); if (!messages || !messages[0]) { return null; } messages[0].newSet = isNewSet; - messages[0].mid = mid; - messages[0].roomId = data.roomId; - plugins.hooks.fire('action:messaging.save', { message: messages[0], data: data }); + plugins.hooks.fire('action:messaging.save', { message: message, data: data }); return messages[0]; }; @@ -87,16 +116,11 @@ module.exports = function (Messaging) { if (!uids.length) { return; } - - const keys = uids.map(uid => `uid:${uid}:chat:rooms`); + const keys = _.uniq(uids).map(uid => `uid:${uid}:chat:rooms`); await db.sortedSetsAdd(keys, timestamp, roomId); }; - Messaging.addMessageToUsers = async (roomId, uids, mid, timestamp) => { - if (!uids.length) { - return; - } - const keys = uids.map(uid => `uid:${uid}:chat:room:${roomId}:mids`); - await db.sortedSetsAdd(keys, timestamp, mid); + Messaging.addMessageToRoom = async (roomId, mid, timestamp) => { + await db.sortedSetAdd(`chat:room:${roomId}:mids`, timestamp, mid); }; }; diff --git a/src/messaging/data.js b/src/messaging/data.js index 085081d8ec..94d9c37e8c 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -1,5 +1,6 @@ 'use strict'; +const _ = require('lodash'); const validator = require('validator'); const db = require('../database'); @@ -7,7 +8,7 @@ const user = require('../user'); const utils = require('../utils'); const plugins = require('../plugins'); -const intFields = ['timestamp', 'edited', 'fromuid', 'roomId', 'deleted', 'system']; +const intFields = ['mid', 'timestamp', 'edited', 'fromuid', 'roomId', 'deleted', 'system']; module.exports = function (Messaging) { Messaging.newMessageCutoff = 1000 * 60 * 3; @@ -71,22 +72,9 @@ module.exports = function (Messaging) { message.newSet = false; message.roomId = String(message.roomId || roomId); - message.deleted = !!message.deleted; - message.system = !!message.system; }); - messages = await Promise.all(messages.map(async (message) => { - if (message.system) { - message.content = validator.escape(String(message.content)); - message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(message.content)); - return message; - } - - const result = await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew); - message.content = result; - message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(result)); - return message; - })); + await parseMessages(messages, uid, roomId, isNew); if (messages.length > 1) { // Add a spacer in between messages with time gaps between them @@ -100,7 +88,7 @@ module.exports = function (Messaging) { message.newSet = true; } else if (index > 0 && messages[index - 1].system) { message.newSet = true; - } else if (index === 0) { + } else if (index === 0 || message.toMid) { message.newSet = true; } @@ -108,14 +96,14 @@ module.exports = function (Messaging) { }); } else if (messages.length === 1) { // For single messages, we don't know the context, so look up the previous message and compare - const key = `uid:${uid}:chat:room:${roomId}:mids`; + const key = `chat:room:${roomId}:mids`; const index = await db.sortedSetRank(key, messages[0].messageId); if (index > 0) { const mid = await db.getSortedSetRange(key, index - 1, index - 1); const fields = await Messaging.getMessageFields(mid, ['fromuid', 'timestamp']); if ((messages[0].timestamp > fields.timestamp + Messaging.newMessageCutoff) || (messages[0].fromuid !== fields.fromuid) || - messages[0].system) { + messages[0].system || messages[0].toMid) { // If it's been 5 minutes, this is a new set of messages messages[0].newSet = true; } @@ -124,6 +112,8 @@ module.exports = function (Messaging) { } } + await addParentMessages(messages, uid, roomId); + const data = await plugins.hooks.fire('filter:messaging.getMessages', { messages: messages, uid: uid, @@ -134,6 +124,64 @@ module.exports = function (Messaging) { return data && data.messages; }; + + async function addParentMessages(messages, uid, roomId) { + let parentMids = messages.map(msg => (msg && msg.hasOwnProperty('toMid') ? parseInt(msg.toMid, 10) : null)).filter(Boolean); + + if (!parentMids.length) { + return; + } + parentMids = _.uniq(parentMids); + const parentMessages = await Messaging.getMessagesFields(parentMids, [ + 'fromuid', 'content', 'timestamp', 'deleted', + ]); + const parentUids = _.uniq(parentMessages.map(msg => msg && msg.fromuid)); + const usersMap = _.zipObject( + parentUids, + await user.getUsersFields(parentUids, ['uid', 'username', 'userslug', 'picture']) + ); + + await Promise.all(parentMessages.map(async (parentMsg) => { + if (parentMsg.deleted && parentMsg.fromuid !== parseInt(uid, 10)) { + parentMsg.content = `

[[modules:chat.message-deleted]]

`; + return; + } + const foundMsg = messages.find(msg => parseInt(msg.mid, 10) === parseInt(parentMsg.mid, 10)); + if (foundMsg) { + parentMsg.content = foundMsg.content; + return; + } + parentMsg.content = await parseMessage(parentMsg, uid, roomId, false); + })); + + const parents = {}; + parentMessages.forEach((msg, i) => { + if (usersMap[msg.fromuid]) { + msg.user = usersMap[msg.fromuid]; + parents[parentMids[i]] = msg; + } + }); + + messages.forEach((msg) => { + if (parents[msg.toMid]) { + msg.parent = parents[msg.toMid]; + msg.parent.mid = msg.toMid; + } + }); + } + + async function parseMessages(messages, uid, roomId, isNew) { + await Promise.all(messages.map(async (message) => { + message.content = await parseMessage(message, uid, roomId, isNew); + })); + } + async function parseMessage(message, uid, roomId, isNew) { + if (message.system) { + return validator.escape(String(message.content)); + } + + return await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew); + } }; async function modifyMessage(message, fields, mid) { diff --git a/src/messaging/delete.js b/src/messaging/delete.js index 341bafda6b..1c16ceddc1 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -1,6 +1,7 @@ 'use strict'; const sockets = require('../socket.io'); +const plugins = require('../plugins'); module.exports = function (Messaging) { Messaging.deleteMessage = async (mid, uid) => await doDeleteRestore(mid, 1, uid); @@ -8,26 +9,23 @@ module.exports = function (Messaging) { async function doDeleteRestore(mid, state, uid) { const field = state ? 'deleted' : 'restored'; - const { deleted, roomId } = await Messaging.getMessageFields(mid, ['deleted', 'roomId']); - if (deleted === state) { + const msgData = await Messaging.getMessageFields(mid, [ + 'mid', 'fromuid', 'deleted', 'roomId', 'content', 'system', + ]); + if (msgData.deleted === state) { throw new Error(`[[error:chat-${field}-already]]`); } await Messaging.setMessageField(mid, 'deleted', state); - - const [uids, messages] = await Promise.all([ - Messaging.getUidsInRoom(roomId, 0, -1), - Messaging.getMessagesData([mid], uid, roomId, true), - ]); - - uids.forEach((_uid) => { - if (parseInt(_uid, 10) !== parseInt(uid, 10)) { - if (state === 1) { - sockets.in(`uid_${_uid}`).emit('event:chats.delete', mid); - } else if (state === 0) { - sockets.in(`uid_${_uid}`).emit('event:chats.restore', messages[0]); - } - } - }); + msgData.deleted = state; + const ioRoom = sockets.in(`chat_room_${msgData.roomId}`); + if (state === 1 && ioRoom) { + ioRoom.emit('event:chats.delete', mid); + plugins.hooks.fire('action:messaging.delete', { message: msgData }); + } else if (state === 0 && ioRoom) { + const messages = await Messaging.getMessagesData([mid], uid, msgData.roomId, true); + ioRoom.emit('event:chats.restore', messages[0]); + plugins.hooks.fire('action:messaging.restore', { message: msgData }); + } } }; diff --git a/src/messaging/edit.js b/src/messaging/edit.js index 85cad068ab..438d43685a 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -27,15 +27,12 @@ module.exports = function (Messaging) { await Messaging.setMessageFields(mid, payload); // Propagate this change to users in the room - const [uids, messages] = await Promise.all([ - Messaging.getUidsInRoom(roomId, 0, -1), - Messaging.getMessagesData([mid], uid, roomId, true), - ]); - - uids.forEach((uid) => { - sockets.in(`uid_${uid}`).emit('event:chats.edit', { - messages: messages, - }); + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); + sockets.in(`chat_room_${roomId}`).emit('event:chats.edit', { + messages: messages, + }); + plugins.hooks.fire('action:messaging.edit', { + message: { ...messages[0], content: payload.content }, }); }; diff --git a/src/messaging/index.js b/src/messaging/index.js index e532043a12..5199345720 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -1,15 +1,17 @@ 'use strict'; - +const _ = require('lodash'); const validator = require('validator'); const nconf = require('nconf'); const db = require('../database'); const user = require('../user'); +const groups = require('../groups'); const privileges = require('../privileges'); const plugins = require('../plugins'); const meta = require('../meta'); const utils = require('../utils'); const translator = require('../translator'); +const cache = require('../cache'); const relative_path = nconf.get('relative_path'); @@ -23,41 +25,58 @@ require('./rooms')(Messaging); require('./unread')(Messaging); require('./notifications')(Messaging); +Messaging.notificationSettings = Object.create(null); +Messaging.notificationSettings.NONE = 1; +Messaging.notificationSettings.ATMENTION = 2; +Messaging.notificationSettings.ALLMESSAGES = 3; + Messaging.messageExists = async mid => db.exists(`message:${mid}`); Messaging.getMessages = async (params) => { + const { callerUid, uid, roomId } = params; const isNew = params.isNew || false; const start = params.hasOwnProperty('start') ? params.start : 0; const stop = parseInt(start, 10) + ((params.count || 50) - 1); - const indices = {}; - const ok = await canGet('filter:messaging.canGetMessages', params.callerUid, params.uid); + const ok = await canGet('filter:messaging.canGetMessages', callerUid, uid); if (!ok) { return; } - - const mids = await db.getSortedSetRevRange(`uid:${params.uid}:chat:room:${params.roomId}:mids`, start, stop); + const mids = await getMessageIds(roomId, uid, start, stop); if (!mids.length) { return []; } + const indices = {}; mids.forEach((mid, index) => { indices[mid] = start + index; }); mids.reverse(); - const messageData = await Messaging.getMessagesData(mids, params.uid, params.roomId, isNew); - messageData.forEach((messageData) => { - messageData.index = indices[messageData.messageId.toString()]; - messageData.isOwner = messageData.fromuid === parseInt(params.uid, 10); - if (messageData.deleted && !messageData.isOwner) { - messageData.content = '[[modules:chat.message-deleted]]'; - messageData.cleanedContent = messageData.content; + const messageData = await Messaging.getMessagesData(mids, uid, roomId, isNew); + messageData.forEach((msg) => { + msg.index = indices[msg.messageId.toString()]; + msg.isOwner = msg.fromuid === parseInt(uid, 10); + if (msg.deleted && !msg.isOwner) { + msg.content = `

[[modules:chat.message-deleted]]

`; } }); return messageData; }; +async function getMessageIds(roomId, uid, start, stop) { + const isPublic = await db.getObjectField(`chat:room:${roomId}`, 'public'); + if (parseInt(isPublic, 10) === 1) { + return await db.getSortedSetRevRange( + `chat:room:${roomId}:mids`, start, stop, + ); + } + const userjoinTimestamp = await db.sortedSetScore(`chat:room:${roomId}:uids`, uid); + return await db.getSortedSetRevRangeByScore( + `chat:room:${roomId}:mids`, start, stop - start + 1, '+inf', userjoinTimestamp + ); +} + async function canGet(hook, callerUid, uid) { const data = await plugins.hooks.fire(hook, { callerUid: callerUid, @@ -85,7 +104,7 @@ Messaging.parse = async (message, fromuid, uid, roomId, isNew) => { }; Messaging.isNewSet = async (uid, roomId, timestamp) => { - const setKey = `uid:${uid}:chat:room:${roomId}:mids`; + const setKey = `chat:room:${roomId}:mids`; const messages = await db.getSortedSetRevRangeWithScores(setKey, 0, 0); if (messages && messages.length) { return parseInt(timestamp, 10) > parseInt(messages[0].score, 10) + Messaging.newMessageCutoff; @@ -93,6 +112,61 @@ Messaging.isNewSet = async (uid, roomId, timestamp) => { return true; }; +Messaging.getPublicRoomIdsFromSet = async function (set) { + const cacheKey = `${set}:all`; + let allRoomIds = cache.get(cacheKey); + if (allRoomIds === undefined) { + allRoomIds = await db.getSortedSetRange(set, 0, -1); + cache.set(cacheKey, allRoomIds); + } + return allRoomIds.slice(); +}; + +Messaging.getPublicRooms = async (callerUid, uid) => { + const ok = await canGet('filter:messaging.canGetPublicChats', callerUid, uid); + if (!ok) { + return null; + } + + const allRoomIds = await Messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); + const allRoomData = await Messaging.getRoomsData(allRoomIds); + const checks = await Promise.all( + allRoomData.map( + room => room && ( + !Array.isArray(room.groups) || + !room.groups.length || + groups.isMemberOfAny(uid, room && room.groups) + ) + ) + ); + + const roomData = allRoomData.filter((room, idx) => room && checks[idx]); + const roomIds = roomData.map(r => r.roomId); + const userReadTimestamps = await db.getObjectFields( + `uid:${uid}:chat:rooms:read`, + roomIds, + ); + + const maxUnread = 50; + const unreadCounts = await Promise.all(roomIds.map(async (roomId) => { + const cutoff = userReadTimestamps[roomId] || '-inf'; + const unreadMids = await db.getSortedSetRangeByScore( + `chat:room:${roomId}:mids`, 0, maxUnread + 1, cutoff, '+inf' + ); + return unreadMids.length; + })); + + roomData.forEach((r, idx) => { + const count = unreadCounts[idx]; + r.unreadCountText = count > maxUnread ? `${maxUnread}+` : String(count); + r.unreadCount = count; + r.unread = count > 0; + r.icon = Messaging.getRoomIcon(r); + }); + + return roomData; +}; + Messaging.getRecentChats = async (callerUid, uid, start, stop) => { const ok = await canGet('filter:messaging.canGetRecentChats', callerUid, uid); if (!ok) { @@ -100,15 +174,29 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { } const roomIds = await db.getSortedSetRevRange(`uid:${uid}:chat:rooms`, start, stop); + + async function getUsers(roomIds) { + const arrayOfUids = await Promise.all( + roomIds.map(roomId => Messaging.getUidsInRoom(roomId, 0, 9)) + ); + const uniqUids = _.uniq(_.flatten(arrayOfUids)).filter( + _uid => _uid && parseInt(_uid, 10) !== parseInt(uid, 10) + ); + const uidToUser = _.zipObject( + uniqUids, + await user.getUsersFields(uniqUids, [ + 'uid', 'username', 'userslug', 'picture', 'status', 'lastonline', + ]) + ); + return arrayOfUids.map(uids => uids.map(uid => uidToUser[uid])); + } + const results = await utils.promiseParallel({ roomData: Messaging.getRoomsData(roomIds), unread: db.isSortedSetMembers(`uid:${uid}:chat:rooms:unread`, roomIds), - users: Promise.all(roomIds.map(async (roomId) => { - let uids = await db.getSortedSetRevRange(`chat:room:${roomId}:uids`, 0, 9); - uids = uids.filter(_uid => _uid && parseInt(_uid, 10) !== parseInt(uid, 10)); - return await user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline']); - })), - teasers: Promise.all(roomIds.map(async roomId => Messaging.getTeaser(uid, roomId))), + users: getUsers(roomIds), + teasers: Messaging.getTeasers(uid, roomIds), + settings: user.getSettings(uid), }); await Promise.all(results.roomData.map(async (room, index) => { @@ -125,8 +213,8 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); room.users = room.users.filter(user => user && parseInt(user.uid, 10)); room.lastUser = room.users[0]; - room.usernames = Messaging.generateUsernames(room.users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(room.users, uid); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, results.settings.userLang); } })); @@ -140,21 +228,21 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); }; -Messaging.generateUsernames = function (users, excludeUid) { - users = users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); +Messaging.generateUsernames = function (room, excludeUid) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); const usernames = users.map(u => u.username); if (users.length > 3) { return translator.compile( 'modules:chat.usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } return usernames.join(', '); }; -Messaging.generateChatWithMessage = async function (users, excludeUid) { - users = users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); +Messaging.generateChatWithMessage = async function (room, callerUid, userLang) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== callerUid); const usernames = users.map(u => `${u.username}`); let compiled = ''; if (!users.length) { @@ -164,7 +252,7 @@ Messaging.generateChatWithMessage = async function (users, excludeUid) { compiled = translator.compile( 'modules:chat.chat-with-usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } else { compiled = translator.compile( @@ -172,31 +260,48 @@ Messaging.generateChatWithMessage = async function (users, excludeUid) { usernames.join(', '), ); } - return utils.decodeHTMLEntities(await translator.translate(compiled)); + return utils.decodeHTMLEntities(await translator.translate(compiled, userLang)); }; Messaging.getTeaser = async (uid, roomId) => { - const mid = await Messaging.getLatestUndeletedMessage(uid, roomId); - if (!mid) { - return null; - } - const teaser = await Messaging.getMessageFields(mid, ['fromuid', 'content', 'timestamp']); - if (!teaser.fromuid) { - return null; - } - const blocked = await user.blocks.is(teaser.fromuid, uid); - if (blocked) { - return null; - } + const teasers = await Messaging.getTeasers(uid, [roomId]); + return teasers[0]; +}; - teaser.user = await user.getUserFields(teaser.fromuid, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline']); - if (teaser.content) { - teaser.content = utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content)); - teaser.content = validator.escape(String(teaser.content)); - } +Messaging.getTeasers = async (uid, roomIds) => { + const mids = await Promise.all( + roomIds.map(roomId => Messaging.getLatestUndeletedMessage(uid, roomId)) + ); + const [teasers, blockedUids] = await Promise.all([ + Messaging.getMessagesFields(mids, ['fromuid', 'content', 'timestamp']), + user.blocks.list(uid), + ]); + const uids = _.uniq( + teasers.map(t => t && t.fromuid).filter(uid => uid && !blockedUids.includes(uid)) + ); - const payload = await plugins.hooks.fire('filter:messaging.getTeaser', { teaser: teaser }); - return payload.teaser; + const userMap = _.zipObject( + uids, + await user.getUsersFields(uids, [ + 'uid', 'username', 'userslug', 'picture', 'status', 'lastonline', + ]) + ); + + return await Promise.all(roomIds.map(async (roomId, idx) => { + const teaser = teasers[idx]; + if (!teaser || !teaser.fromuid) { + return null; + } + if (userMap[teaser.fromuid]) { + teaser.user = userMap[teaser.fromuid]; + } + teaser.content = validator.escape( + String(utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content))) + ); + teaser.roomId = roomId; + const payload = await plugins.hooks.fire('filter:messaging.getTeaser', { teaser: teaser }); + return payload.teaser; + })); }; Messaging.getLatestUndeletedMessage = async (uid, roomId) => { @@ -207,7 +312,7 @@ Messaging.getLatestUndeletedMessage = async (uid, roomId) => { while (!done) { /* eslint-disable no-await-in-loop */ - mids = await db.getSortedSetRevRange(`uid:${uid}:chat:room:${roomId}:mids`, index, index); + mids = await getMessageIds(roomId, uid, index, index); if (mids.length) { const states = await Messaging.getMessageFields(mids[0], ['deleted', 'system']); done = !states.deleted && !states.system; @@ -337,8 +442,16 @@ Messaging.canViewMessage = async (mids, roomId, uid) => { mids = [mids]; single = true; } + const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; + const [midTimestamps, userTimestamp] = await Promise.all([ + db.sortedSetScores(`chat:room:${roomId}:mids`, mids), + db.sortedSetScore(`chat:room:${roomId}:uids`, uid), + ]); + + const canView = midTimestamps.map( + midTimestamp => !!(midTimestamp && userTimestamp && (isPublic || userTimestamp <= midTimestamp)) + ); - const canView = await db.isSortedSetMembers(`uid:${uid}:chat:room:${roomId}:mids`, mids); return single ? canView.pop() : canView; }; diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 6913c2d415..2295dcd58a 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -2,39 +2,77 @@ const winston = require('winston'); -const user = require('../user'); +const batch = require('../batch'); +const db = require('../database'); const notifications = require('../notifications'); -const sockets = require('../socket.io'); +const user = require('../user'); +const io = require('../socket.io'); const plugins = require('../plugins'); const meta = require('../meta'); module.exports = function (Messaging) { - Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser + // Only used to notify a user of a new chat message + Messaging.notifyQueue = {}; + + Messaging.setUserNotificationSetting = async (uid, roomId, value) => { + if (parseInt(value, 10) === -1) { + // go back to default + return await db.deleteObjectField(`chat:room:${roomId}:notification:settings`, uid); + } + await db.setObjectField(`chat:room:${roomId}:notification:settings`, uid, parseInt(value, 10)); + }; + + Messaging.getUidsNotificationSetting = async (uids, roomId) => { + const [settings, roomData] = await Promise.all([ + db.getObjectFields(`chat:room:${roomId}:notification:settings`, uids), + Messaging.getRoomData(roomId, ['notificationSetting']), + ]); + return uids.map(uid => parseInt(settings[uid] || roomData.notificationSetting, 10)); + }; + + Messaging.markRoomNotificationsRead = async (uid, roomId) => { + const chatNids = await db.getSortedSetScan({ + key: `uid:${uid}:notifications:unread`, + match: `chat_${roomId}_*`, + }); + if (chatNids.length) { + await notifications.markReadMultiple(chatNids, uid); + await user.notifications.pushCount(uid); + } + }; Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { - let uids = await Messaging.getUidsInRoom(roomId, 0, -1); - uids = await user.blocks.filterUids(fromUid, uids); + const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; let data = { roomId: roomId, fromUid: fromUid, message: messageObj, - uids: uids, + public: isPublic, }; data = await plugins.hooks.fire('filter:messaging.notify', data); - if (!data || !data.uids || !data.uids.length) { + if (!data) { return; } - uids = data.uids; - uids.forEach((uid) => { - data.self = parseInt(uid, 10) === parseInt(fromUid, 10) ? 1 : 0; - Messaging.pushUnreadCount(uid); - sockets.in(`uid_${uid}`).emit('event:chats.receive', data); - }); + // delivers full message to all online users in roomId + io.in(`chat_room_${roomId}`).emit('event:chats.receive', data); + + const unreadData = { roomId, fromUid, public: isPublic }; + if (isPublic && !messageObj.system) { + // delivers unread public msg to all online users on the chats page + io.in(`chat_room_public_${roomId}`).emit('event:chats.public.unread', unreadData); + } if (messageObj.system) { return; } + + // push unread count only for private rooms + if (!isPublic) { + const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`); + Messaging.pushUnreadCount(uids, unreadData); + } + // Delayed notifications let queueObj = Messaging.notifyQueue[`${fromUid}:${roomId}`]; if (queueObj) { @@ -49,35 +87,50 @@ module.exports = function (Messaging) { queueObj.timeout = setTimeout(async () => { try { - await sendNotifications(fromUid, uids, roomId, queueObj.message); + await sendNotification(fromUid, roomId, queueObj.message); + delete Messaging.notifyQueue[`${fromUid}:${roomId}`]; } catch (err) { winston.error(`[messaging/notifications] Unabled to send notification\n${err.stack}`); } }, meta.config.notificationSendDelay * 1000); }; - async function sendNotifications(fromuid, uids, roomId, messageObj) { - const hasRead = await Messaging.hasRead(uids, roomId); - uids = uids.filter((uid, index) => !hasRead[index] && parseInt(fromuid, 10) !== parseInt(uid, 10)); - if (!uids.length) { - delete Messaging.notifyQueue[`${fromuid}:${roomId}`]; - return; - } + async function sendNotification(fromUid, roomId, messageObj) { + fromUid = parseInt(fromUid, 10); - const { displayname } = messageObj.fromUser; - - const isGroupChat = await Messaging.isGroupChat(roomId); - const notification = await notifications.create({ - type: isGroupChat ? 'new-group-chat' : 'new-chat', - subject: `[[email:notif.chat.subject, ${displayname}]]`, - bodyShort: `[[notifications:new_message_from, ${displayname}]]`, - bodyLong: messageObj.content, - nid: `chat_${fromuid}_${roomId}`, - from: fromuid, - path: `/chats/${messageObj.roomId}`, + const [settings, roomData] = await Promise.all([ + db.getObject(`chat:room:${roomId}:notification:settings`), + Messaging.getRoomData(roomId, ['notificationSetting']), + ]); + const roomDefault = roomData.notificationSetting; + const uidsToNotify = []; + const { ALLMESSAGES } = Messaging.notificationSettings; + await batch.processSortedSet(`chat:room:${roomId}:uids:online`, async (uids) => { + uids = uids.filter( + uid => (parseInt((settings && settings[uid]) || roomDefault, 10) === ALLMESSAGES) && + fromUid !== parseInt(uid, 10) + ); + const hasRead = await Messaging.hasRead(uids, roomId); + uidsToNotify.push(...uids.filter((uid, index) => !hasRead[index])); + }, { + reverse: true, + batch: 500, + interval: 100, }); - delete Messaging.notifyQueue[`${fromuid}:${roomId}`]; - notifications.push(notification, uids); + if (uidsToNotify.length) { + const { displayname } = messageObj.fromUser; + const isGroupChat = await Messaging.isGroupChat(roomId); + const notification = await notifications.create({ + type: isGroupChat ? 'new-group-chat' : 'new-chat', + subject: `[[email:notif.chat.subject, ${displayname}]]`, + bodyShort: `[[notifications:new_message_from, ${displayname}]]`, + bodyLong: messageObj.content, + nid: `chat_${roomId}_${fromUid}`, + from: fromUid, + path: `/chats/${messageObj.roomId}`, + }); + await notifications.push(notification, uidsToNotify); + } } }; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 49646d394a..5428489f42 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -1,71 +1,221 @@ 'use strict'; +const _ = require('lodash'); const validator = require('validator'); +const winston = require('winston'); const db = require('../database'); const user = require('../user'); +const groups = require('../groups'); const plugins = require('../plugins'); const privileges = require('../privileges'); const meta = require('../meta'); +const io = require('../socket.io'); +const cache = require('../cache'); +const cacheCreate = require('../cacheCreate'); + +const roomUidCache = cacheCreate({ + name: 'chat:room:uids', + max: 500, + ttl: 0, +}); + +const intFields = [ + 'roomId', 'timestamp', 'userCount', +]; module.exports = function (Messaging) { - Messaging.getRoomData = async (roomId) => { - const data = await db.getObject(`chat:room:${roomId}`); - if (!data) { - throw new Error('[[error:no-chat-room]]'); - } - - modifyRoomData([data]); - return data; + Messaging.getRoomData = async (roomId, fields = []) => { + const roomData = await Messaging.getRoomsData([roomId], fields); + return roomData[0]; }; - Messaging.getRoomsData = async (roomIds) => { - const roomData = await db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`)); - modifyRoomData(roomData); + Messaging.getRoomsData = async (roomIds, fields = []) => { + if (fields.includes('notificationSetting') && !fields.includes('public')) { + fields.push('public'); + } + const roomData = await db.getObjects( + roomIds.map(roomId => `chat:room:${roomId}`), + fields + ); + modifyRoomData(roomData, fields); return roomData; }; - function modifyRoomData(rooms) { + function modifyRoomData(rooms, fields) { rooms.forEach((data) => { if (data) { - data.roomName = data.roomName || ''; - data.roomName = validator.escape(String(data.roomName)); + db.parseIntFields(data, intFields, fields); + data.roomName = validator.escape(String(data.roomName || '')); + data.public = parseInt(data.public, 10) === 1; if (data.hasOwnProperty('groupChat')) { data.groupChat = parseInt(data.groupChat, 10) === 1; } + + if (!fields.length || fields.includes('notificationSetting')) { + data.notificationSetting = data.notificationSetting || + ( + data.public ? + Messaging.notificationSettings.ATMENTION : + Messaging.notificationSettings.ALLMESSAGES + ); + } + + if (data.hasOwnProperty('groups') || !fields.length || fields.includes('groups')) { + try { + data.groups = JSON.parse(data.groups || '[]'); + } catch (err) { + winston.error(err.stack); + data.groups = []; + } + } } }); } - Messaging.newRoom = async (uid, toUids) => { + Messaging.newRoom = async (uid, data) => { + // backwards compat. remove in 4.x + if (Array.isArray(data)) { // old usage second param used to be toUids + data = { uids: data }; + } + if (data.hasOwnProperty('roomName')) { + checkRoomName(data.roomName); + } + const now = Date.now(); const roomId = await db.incrObjectField('global', 'nextChatRoomId'); const room = { - owner: uid, roomId: roomId, + timestamp: now, + notificationSetting: data.notificationSetting, }; + if (data.hasOwnProperty('roomName') && data.roomName) { + room.roomName = String(data.roomName).trim(); + } + if (Array.isArray(data.groups) && data.groups.length) { + room.groups = JSON.stringify(data.groups); + } + const isPublic = data.type === 'public'; + if (isPublic) { + room.public = 1; + } + await Promise.all([ db.setObject(`chat:room:${roomId}`, room), - db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid), + db.sortedSetAdd('chat:rooms', now, roomId), + db.sortedSetAdd(`chat:room:${roomId}:owners`, now, uid), + db.sortedSetsAdd([ + `chat:room:${roomId}:uids`, + `chat:room:${roomId}:uids:online`, + ], now, uid), ]); + await Promise.all([ - Messaging.addUsersToRoom(uid, toUids, roomId), - Messaging.addRoomToUsers(roomId, [uid].concat(toUids), now), + Messaging.addUsersToRoom(uid, data.uids, roomId), + isPublic ? + db.sortedSetAddBulk([ + ['chat:rooms:public', now, roomId], + ['chat:rooms:public:order', roomId, roomId], + ]) : + Messaging.addRoomToUsers(roomId, [uid].concat(data.uids), now), ]); - // chat owner should also get the user-join system message - await Messaging.addSystemMessage('user-join', uid, roomId); + + cache.del([ + 'chat:rooms:public:all', + 'chat:rooms:public:order:all', + ]); + + if (!isPublic) { + // chat owner should also get the user-join system message + await Messaging.addSystemMessage('user-join', uid, roomId); + } return roomId; }; - Messaging.isUserInRoom = async (uid, roomId) => { - const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid); - const data = await plugins.hooks.fire('filter:messaging.isUserInRoom', { uid: uid, roomId: roomId, inRoom: inRoom }); - return data.inRoom; + Messaging.deleteRooms = async (roomIds) => { + if (!roomIds) { + throw new Error('[[error:invalid-data]]'); + } + + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + } + + await Promise.all(roomIds.map(async (roomId) => { + const uids = await db.getSortedSetMembers(`chat:room:${roomId}:uids`); + const keys = uids + .map(uid => `uid:${uid}:chat:rooms`) + .concat(uids.map(uid => `uid:${uid}:chat:rooms:unread`)); + + await db.sortedSetsRemove(keys, roomId); + })); + await Promise.all([ + db.deleteAll([ + ...roomIds.map(id => `chat:room:${id}`), + ...roomIds.map(id => `chat:room:${id}:uids`), + ...roomIds.map(id => `chat:room:${id}:owners`), + ...roomIds.map(id => `chat:room:${id}:uids:online`), + ...roomIds.map(id => `chat:room:${id}:notification:settings`), + ]), + db.sortedSetRemove([ + 'chat:rooms', + 'chat:rooms:public', + 'chat:rooms:public:order', + 'chat:rooms:public:lastpost', + ], roomIds), + ]); + cache.del([ + 'chat:rooms:public:all', + 'chat:rooms:public:order:all', + ]); }; - Messaging.roomExists = async roomId => db.exists(`chat:room:${roomId}:uids`); + Messaging.isUserInRoom = async (uid, roomIds) => { + let single = false; + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + single = true; + } + const inRooms = await db.isMemberOfSortedSets( + roomIds.map(id => `chat:room:${id}:uids`), + uid + ); + + const data = await Promise.all(roomIds.map(async (roomId, idx) => { + const data = await plugins.hooks.fire('filter:messaging.isUserInRoom', { + uid: uid, + roomId: roomId, + inRoom: inRooms[idx], + }); + return data.inRoom; + })); + return single ? data.pop() : data; + }; + + Messaging.isUsersInRoom = async (uids, roomId) => { + let single = false; + if (!Array.isArray(uids)) { + uids = [uids]; + single = true; + } + + const inRooms = await db.isSortedSetMembers( + `chat:room:${roomId}:uids`, + uids, + ); + + const data = await plugins.hooks.fire('filter:messaging.isUsersInRoom', { + uids: uids, + roomId: roomId, + inRooms: inRooms, + }); + + return single ? data.inRooms.pop() : data.inRooms; + }; + + Messaging.roomExists = async roomId => db.exists(`chat:room:${roomId}`); Messaging.getUserCountInRoom = async roomId => db.sortedSetCard(`chat:room:${roomId}:uids`); @@ -74,17 +224,33 @@ module.exports = function (Messaging) { if (!isArray) { uids = [uids]; } - const owner = await db.getObjectField(`chat:room:${roomId}`, 'owner'); - const isOwners = uids.map(uid => parseInt(uid, 10) === parseInt(owner, 10)); + const isOwners = await db.isSortedSetMembers(`chat:room:${roomId}:owners`, uids); const result = await Promise.all(isOwners.map(async (isOwner, index) => { - const payload = await plugins.hooks.fire('filter:messaging.isRoomOwner', { uid: uids[index], roomId, owner, isOwner }); + const payload = await plugins.hooks.fire('filter:messaging.isRoomOwner', { uid: uids[index], roomId, isOwner }); return payload.isOwner; })); return isArray ? result : result[0]; }; + Messaging.toggleOwner = async (uid, roomId) => { + if (!(parseInt(uid, 10) > 0) || !roomId) { + return; + } + const isOwner = await Messaging.isRoomOwner(uid, roomId); + if (isOwner) { + await db.sortedSetRemove(`chat:room:${roomId}:owners`, uid); + } else { + await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), uid); + } + }; + + Messaging.isRoomPublic = async function (roomId) { + return parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; + }; + Messaging.addUsersToRoom = async function (uid, uids, roomId) { + uids = _.uniq(uids); const inRoom = await Messaging.isUserInRoom(uid, roomId); const payload = await plugins.hooks.fire('filter:messaging.addUsersToRoom', { uid, uids, roomId, inRoom }); @@ -92,13 +258,20 @@ module.exports = function (Messaging) { throw new Error('[[error:cant-add-users-to-chat-room]]'); } - const now = Date.now(); - const timestamps = payload.uids.map(() => now); - await db.sortedSetAdd(`chat:room:${payload.roomId}:uids`, timestamps, payload.uids); - await updateGroupChatField([payload.roomId]); - await Promise.all(payload.uids.map(uid => Messaging.addSystemMessage('user-join', uid, payload.roomId))); + await addUidsToRoom(payload.uids, roomId); }; + async function addUidsToRoom(uids, roomId) { + const now = Date.now(); + const timestamps = uids.map(() => now); + await Promise.all([ + db.sortedSetAdd(`chat:room:${roomId}:uids`, timestamps, uids), + db.sortedSetAdd(`chat:room:${roomId}:uids:online`, timestamps, uids), + ]); + await updateUserCount([roomId]); + await Promise.all(uids.map(uid => Messaging.addSystemMessage('user-join', uid, roomId))); + } + Messaging.removeUsersFromRoom = async (uid, uids, roomId) => { const [isOwner, userCount] = await Promise.all([ Messaging.isRoomOwner(uid, roomId), @@ -117,14 +290,16 @@ module.exports = function (Messaging) { return (await Messaging.getRoomData(roomId)).groupChat; }; - async function updateGroupChatField(roomIds) { + async function updateUserCount(roomIds) { const userCounts = await db.sortedSetsCard(roomIds.map(roomId => `chat:room:${roomId}:uids`)); + const countMap = _.zipObject(roomIds, userCounts); const groupChats = roomIds.filter((roomId, index) => userCounts[index] > 2); const privateChats = roomIds.filter((roomId, index) => userCounts[index] <= 2); await db.setObjectBulk([ - ...groupChats.map(id => [`chat:room:${id}`, { groupChat: 1 }]), - ...privateChats.map(id => [`chat:room:${id}`, { groupChat: 0 }]), + ...groupChats.map(id => [`chat:room:${id}`, { groupChat: 1, userCount: countMap[id] }]), + ...privateChats.map(id => [`chat:room:${id}`, { groupChat: 0, userCount: countMap[id] }]), ]); + roomUidCache.del(roomIds.map(id => `chat:room:${id}:users`)); } Messaging.leaveRoom = async (uids, roomId) => { @@ -136,20 +311,28 @@ module.exports = function (Messaging) { .concat(uids.map(uid => `uid:${uid}:chat:rooms:unread`)); await Promise.all([ - db.sortedSetRemove(`chat:room:${roomId}:uids`, uids), + db.sortedSetRemove([ + `chat:room:${roomId}:uids`, + `chat:room:${roomId}:owners`, + `chat:room:${roomId}:uids:online`, + ], uids), db.sortedSetsRemove(keys, roomId), ]); await Promise.all(uids.map(uid => Messaging.addSystemMessage('user-leave', uid, roomId))); await updateOwner(roomId); - await updateGroupChatField([roomId]); + await updateUserCount([roomId]); }; Messaging.leaveRooms = async (uid, roomIds) => { const isInRoom = await Promise.all(roomIds.map(roomId => Messaging.isUserInRoom(uid, roomId))); roomIds = roomIds.filter((roomId, index) => isInRoom[index]); - const roomKeys = roomIds.map(roomId => `chat:room:${roomId}:uids`); + const roomKeys = [ + ...roomIds.map(roomId => `chat:room:${roomId}:uids`), + ...roomIds.map(roomId => `chat:room:${roomId}:owners`), + ...roomIds.map(roomId => `chat:room:${roomId}:uids:online`), + ]; await Promise.all([ db.sortedSetsRemove(roomKeys, uid), db.sortedSetRemove([ @@ -162,38 +345,64 @@ module.exports = function (Messaging) { roomIds.map(roomId => updateOwner(roomId)) .concat(roomIds.map(roomId => Messaging.addSystemMessage('user-leave', uid, roomId))) ); - await updateGroupChatField(roomIds); + await updateUserCount(roomIds); }; async function updateOwner(roomId) { - const uids = await db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, 0); - const newOwner = uids[0] || 0; - await db.setObjectField(`chat:room:${roomId}`, 'owner', newOwner); + let nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:owners`, 0, 0); + if (!nextOwner.length) { + // no owners left grab next user + nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, 0); + const newOwner = nextOwner[0] || 0; + if (parseInt(newOwner, 10) > 0) { + await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), newOwner); + } + } } - Messaging.getUidsInRoom = async (roomId, start, stop) => db.getSortedSetRevRange(`chat:room:${roomId}:uids`, start, stop); + Messaging.getAllUidsInRoomFromSet = async function (set) { + const cacheKey = `${set}:all`; + let uids = roomUidCache.get(cacheKey); + if (uids !== undefined) { + return uids; + } + uids = await Messaging.getUidsInRoomFromSet(set, 0, -1); + roomUidCache.set(cacheKey, uids); + return uids; + }; - Messaging.getUsersInRoom = async (roomId, start, stop) => { - const uids = await Messaging.getUidsInRoom(roomId, start, stop); + Messaging.getUidsInRoomFromSet = async (set, start, stop, reverse = false) => db[ + reverse ? 'getSortedSetRevRange' : 'getSortedSetRange' + ](set, start, stop); + + Messaging.getUidsInRoom = async (roomId, start, stop, reverse = false) => db[ + reverse ? 'getSortedSetRevRange' : 'getSortedSetRange' + ](`chat:room:${roomId}:uids`, start, stop); + + Messaging.getUsersInRoom = async (roomId, start, stop, reverse = false) => { + const users = await Messaging.getUsersInRoomFromSet( + `chat:room:${roomId}:uids`, roomId, start, stop, reverse + ); + return users; + }; + + Messaging.getUsersInRoomFromSet = async (set, roomId, start, stop, reverse = false) => { + const uids = await Messaging.getUidsInRoomFromSet(set, start, stop, reverse); const [users, isOwners] = await Promise.all([ user.getUsersFields(uids, ['uid', 'username', 'picture', 'status']), Messaging.isRoomOwner(uids, roomId), ]); return users.map((user, index) => { + user.index = start + index; user.isOwner = isOwners[index]; return user; }); }; Messaging.renameRoom = async function (uid, roomId, newName) { - if (!newName) { - throw new Error('[[error:invalid-data]]'); - } - newName = newName.trim(); - if (newName.length > 75) { - throw new Error('[[error:chat-room-name-too-long]]'); - } + newName = String(newName).trim(); + checkRoomName(newName); const payload = await plugins.hooks.fire('filter:chat.renameRoom', { uid: uid, @@ -214,6 +423,15 @@ module.exports = function (Messaging) { }); }; + function checkRoomName(roomName) { + if (!roomName && roomName !== '') { + throw new Error('[[error:invalid-room-name]]'); + } + if (roomName.length > meta.config.maximumChatRoomNameLength) { + throw new Error(`[[error:chat-room-name-too-long, ${meta.config.maximumChatRoomNameLength}]]`); + } + } + Messaging.canReply = async (roomId, uid) => { const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid); const data = await plugins.hooks.fire('filter:messaging.canReply', { uid: uid, roomId: roomId, inRoom: inRoom, canReply: inRoom }); @@ -221,42 +439,112 @@ module.exports = function (Messaging) { }; Messaging.loadRoom = async (uid, data) => { - const canChat = await privileges.global.can('chat', uid); + const { roomId } = data; + const [room, inRoom, canChat, isAdmin, isGlobalMod] = await Promise.all([ + Messaging.getRoomData(roomId), + Messaging.isUserInRoom(uid, roomId), + privileges.global.can('chat', uid), + user.isAdministrator(uid), + user.isGlobalModerator(uid), + ]); + if (!canChat) { throw new Error('[[error:no-privileges]]'); } - const inRoom = await Messaging.isUserInRoom(uid, data.roomId); - if (!inRoom) { + if (!room || + (!room.public && !inRoom) || + (room.public && ( + Array.isArray(room.groups) && room.groups.length && !(await groups.isMemberOfAny(uid, room.groups))) + ) + ) { return null; } - const [room, canReply, users, messages, isAdminOrGlobalMod, isOwner] = await Promise.all([ - Messaging.getRoomData(data.roomId), - Messaging.canReply(data.roomId, uid), - Messaging.getUsersInRoom(data.roomId, 0, -1), + // add user to public room onload + if (room.public && !inRoom) { + await addUidsToRoom([uid], roomId); + room.userCount += 1; + } else if (inRoom) { + await db.sortedSetAdd(`chat:room:${roomId}:uids:online`, Date.now(), uid); + } + + async function getNotificationOptions() { + const userSetting = await db.getObjectField(`chat:room:${roomId}:notification:settings`, uid); + const roomDefault = room.notificationSetting; + const currentSetting = userSetting || roomDefault; + const labels = { + [Messaging.notificationSettings.NONE]: { label: '[[modules:chat.notification-setting-none]]', icon: 'fa-ban' }, + [Messaging.notificationSettings.ATMENTION]: { label: '[[modules:chat.notification-setting-at-mention-only]]', icon: 'fa-at' }, + [Messaging.notificationSettings.ALLMESSAGES]: { label: '[[modules:chat.notification-setting-all-messages]]', icon: 'fa-comment-o' }, + }; + const options = [ + { + label: '[[modules:chat.notification-setting-room-default]]', + subLabel: labels[roomDefault].label || '', + icon: labels[roomDefault].icon, + value: -1, + selected: userSetting === null, + }, + ]; + Object.keys(labels).forEach((key) => { + options.push({ + label: labels[key].label, + icon: labels[key].icon, + value: key, + selected: parseInt(userSetting, 10) === parseInt(key, 10), + }); + }); + return { options, selectedIcon: labels[currentSetting].icon }; + } + + const [canReply, users, messages, settings, isOwner, onlineUids, notifOptions] = await Promise.all([ + Messaging.canReply(roomId, uid), + Messaging.getUsersInRoomFromSet(`chat:room:${roomId}:uids:online`, roomId, 0, 39, true), Messaging.getMessages({ callerUid: uid, uid: data.uid || uid, - roomId: data.roomId, + roomId: roomId, isNew: false, }), - user.isAdminOrGlobalMod(uid), - Messaging.isRoomOwner(uid, data.roomId), + user.getSettings(uid), + Messaging.isRoomOwner(uid, roomId), + io.getUidsInRoom(`chat_room_${roomId}`), + getNotificationOptions(), + Messaging.markRoomNotificationsRead(uid, roomId), ]); + users.forEach((user) => { + if (user) { + user.online = parseInt(user.uid, 10) === parseInt(uid, 10) || onlineUids.includes(String(user.uid)); + } + }); + room.messages = messages; room.isOwner = isOwner; - room.users = users.filter(user => user && parseInt(user.uid, 10) && parseInt(user.uid, 10) !== parseInt(uid, 10)); + room.users = users; room.canReply = canReply; room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : users.length > 2; - room.usernames = Messaging.generateUsernames(users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid); + room.icon = Messaging.getRoomIcon(room); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, settings.userLang); room.maximumUsersInChatRoom = meta.config.maximumUsersInChatRoom; room.maximumChatMessageLength = meta.config.maximumChatMessageLength; room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; - room.isAdminOrGlobalMod = isAdminOrGlobalMod; + room.isAdminOrGlobalMod = isAdmin || isGlobalMod; + room.isAdmin = isAdmin; + room.notificationOptions = notifOptions.options; + room.notificationOptionsIcon = notifOptions.selectedIcon; const payload = await plugins.hooks.fire('filter:messaging.loadRoom', { uid, data, room }); return payload.room; }; + + const globalUserGroups = [ + 'registered-users', 'verified-users', 'unverified-users', 'banned-users', + ]; + + Messaging.getRoomIcon = function (roomData) { + const hasGroups = Array.isArray(roomData.groups) && roomData.groups.length; + return !hasGroups || roomData.groups.some(group => globalUserGroups.includes(group)) ? 'fa-hashtag' : 'fa-lock'; + }; }; diff --git a/src/messaging/unread.js b/src/messaging/unread.js index 3a31595070..6144def618 100644 --- a/src/messaging/unread.js +++ b/src/messaging/unread.js @@ -1,30 +1,57 @@ 'use strict'; const db = require('../database'); -const sockets = require('../socket.io'); +const io = require('../socket.io'); module.exports = function (Messaging) { Messaging.getUnreadCount = async (uid) => { - if (parseInt(uid, 10) <= 0) { + if (!(parseInt(uid, 10) > 0)) { return 0; } return await db.sortedSetCard(`uid:${uid}:chat:rooms:unread`); }; - Messaging.pushUnreadCount = async (uid) => { - if (parseInt(uid, 10) <= 0) { + Messaging.pushUnreadCount = async (uids, data = null) => { + if (!Array.isArray(uids)) { + uids = [uids]; + } + uids = uids.filter(uid => parseInt(uid, 10) > 0); + if (!uids.length) { return; } - const unreadCount = await Messaging.getUnreadCount(uid); - sockets.in(`uid_${uid}`).emit('event:unread.updateChatCount', unreadCount); + uids.forEach((uid) => { + io.in(`uid_${uid}`).emit('event:unread.updateChatCount', data); + }); }; Messaging.markRead = async (uid, roomId) => { - await db.sortedSetRemove(`uid:${uid}:chat:rooms:unread`, roomId); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:chat:rooms:unread`, roomId), + db.setObjectField(`uid:${uid}:chat:rooms:read`, roomId, Date.now()), + ]); }; Messaging.hasRead = async (uids, roomId) => { + if (!uids.length) { + return []; + } + const roomData = await Messaging.getRoomData(roomId); + if (!roomData) { + return uids.map(() => false); + } + if (roomData.public) { + const [userTimestamps, mids] = await Promise.all([ + db.getObjectsFields(uids.map(uid => `uid:${uid}:chat:rooms:read`), [roomId]), + db.getSortedSetRevRangeWithScores(`chat:room:${roomId}:mids`, 0, 0), + ]); + const lastMsgTimestamp = mids[0] ? mids[0].score : 0; + return uids.map( + (uid, index) => !userTimestamps[index] || + !userTimestamps[index][roomId] || + parseInt(userTimestamps[index][roomId], 10) > lastMsgTimestamp + ); + } const isMembers = await db.isMemberOfSortedSets( uids.map(uid => `uid:${uid}:chat:rooms:unread`), roomId @@ -42,6 +69,6 @@ module.exports = function (Messaging) { return; } const keys = uids.map(uid => `uid:${uid}:chat:rooms:unread`); - return await db.sortedSetsAdd(keys, Date.now(), roomId); + await db.sortedSetsAdd(keys, Date.now(), roomId); }; }; diff --git a/src/meta/aliases.js b/src/meta/aliases.js index d5eb42aa89..068080ed72 100644 --- a/src/meta/aliases.js +++ b/src/meta/aliases.js @@ -13,9 +13,9 @@ const aliases = { 'clientcss', 'clientscss', 'clientstyles', 'clientstyle', ], 'admin control panel styles': [ - 'admincss', 'adminless', 'adminstyles', 'adminstyle', 'acpcss', 'acpless', 'acpstyles', 'acpstyle', + 'admincss', 'adminscss', 'adminstyles', 'adminstyle', 'acpcss', 'acpscss', 'acpstyles', 'acpstyle', ], - styles: ['css', 'less', 'style'], + styles: ['css', 'scss', 'style'], templates: ['tpl'], languages: ['lang', 'i18n'], }; diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index 8e3bc7b1f7..6fa3761bbb 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -38,54 +38,69 @@ Blacklist.save = async function (rules) { pubsub.publish('blacklist:reload'); }; +Blacklist.addRule = async function (rule) { + const { valid } = Blacklist.validate(rule); + if (!valid.length) { + throw new Error('[[error:invalid-rule]]'); + } + let rules = await Blacklist.get(); + rules = `${rules}\n${valid[0]}`; + await Blacklist.save(rules); +}; + Blacklist.get = async function () { const data = await db.getObject('ip-blacklist-rules'); return data && data.rules; }; Blacklist.test = async function (clientIp) { - // Some handy test addresses - // clientIp = '2001:db8:85a3:0:0:8a2e:370:7334'; // IPv6 - // clientIp = '127.0.15.1'; // IPv4 - // clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail if (!clientIp) { return; } clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp; - let addr; - try { - addr = ipaddr.parse(clientIp); - } catch (err) { - winston.error(`[meta/blacklist] Error parsing client IP : ${clientIp}`); - throw err; + if (!validator.isIP(clientIp)) { + throw new Error('[[error:invalid-ip]]'); } - if ( - !Blacklist._rules.ipv4.includes(clientIp) && // not explicitly specified in ipv4 list - !Blacklist._rules.ipv6.includes(clientIp) && // not explicitly specified in ipv6 list - !Blacklist._rules.cidr.some((subnet) => { + const rules = Blacklist._rules; + function checkCidrRange(clientIP) { + if (!rules.cidr.length) { + return false; + } + let addr; + try { + addr = ipaddr.parse(clientIP); + } catch (err) { + winston.error(`[meta/blacklist] Error parsing client IP : ${clientIp}`); + throw err; + } + return rules.cidr.some((subnet) => { const cidr = ipaddr.parseCIDR(subnet); if (addr.kind() !== cidr[0].kind()) { return false; } return addr.match(cidr); - }) // not in a blacklisted IPv4 or IPv6 cidr range - ) { - try { - // To return test failure, pass back an error in callback - await plugins.hooks.fire('filter:blacklist.test', { ip: clientIp }); - } catch (err) { - analytics.increment('blacklist'); - throw err; - } - } else { + }); + } + + if (rules.ipv4.includes(clientIp) || + rules.ipv6.includes(clientIp) || + checkCidrRange(clientIp)) { const err = new Error('[[error:blacklisted-ip]]'); err.code = 'blacklisted-ip'; analytics.increment('blacklist'); throw err; } + + try { + // To return test failure, throw an error in hook + await plugins.hooks.fire('filter:blacklist.test', { ip: clientIp }); + } catch (err) { + analytics.increment('blacklist'); + throw err; + } }; Blacklist.validate = function (rules) { @@ -160,12 +175,4 @@ Blacklist.validate = function (rules) { }; }; -Blacklist.addRule = async function (rule) { - const { valid } = Blacklist.validate(rule); - if (!valid.length) { - throw new Error('[[error:invalid-rule]]'); - } - let rules = await Blacklist.get(); - rules = `${rules}\n${valid[0]}`; - await Blacklist.save(rules); -}; + diff --git a/src/meta/css.js b/src/meta/css.js index 6298cfc44a..5b665f6d43 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -5,11 +5,13 @@ const winston = require('winston'); const nconf = require('nconf'); const fs = require('fs'); const path = require('path'); +const { mkdirp } = require('mkdirp'); const plugins = require('../plugins'); const db = require('../database'); const file = require('../file'); const minifier = require('./minifier'); +const utils = require('../utils'); const CSS = module.exports; @@ -35,7 +37,8 @@ const buildImports = { '@import "admin/overrides";', '@import "bootstrap/scss/bootstrap";', '@import "mixins";', - '@import "fontawesome";', + '@import "fontawesome/loader";', + getFontawesomeStyle(), '@import "@adactive/bootstrap-tagsinput/src/bootstrap-tagsinput";', '@import "generics";', '@import "responsive-utilities";', @@ -73,6 +76,7 @@ function boostrapImport(themeData) { // bs files '@import "bootstrap/scss/variables";', + '@import "bootstrap/scss/variables-dark";', '@import "bootstrap/scss/maps";', '@import "bootstrap/scss/mixins";', '@import "bootstrap/scss/utilities";', @@ -119,7 +123,9 @@ function boostrapImport(themeData) { '@import "bootstrap/scss/utilities/api";', // scss-docs-end import-stack - '@import "fontawesome";', + '@import "fontawesome/loader";', + getFontawesomeStyle(), + '@import "mixins";', // core mixins '@import "generics";', '@import "client";', // core page styles @@ -128,6 +134,26 @@ function boostrapImport(themeData) { ].join('\n'); } + +function getFontawesomeStyle() { + const styles = utils.getFontawesomeStyles(); + return styles.map(style => `@import "fontawesome/style-${style}";`).join('\n'); +} + +async function copyFontAwesomeFiles() { + await mkdirp(path.join(__dirname, '../../build/public/fontawesome/webfonts')); + const fonts = await fs.promises.opendir(path.join(utils.getFontawesomePath(), '/webfonts')); + const copyOperations = []; + for await (const file of fonts) { + if (file.isFile() && file.name.match(/\.(woff2|ttf|eot)?$/)) { // there shouldn't be any legacy eot files, but just in case we'll allow it + copyOperations.push( + fs.promises.copyFile(path.join(fonts.path, file.name), path.join(__dirname, '../../build/public/fontawesome/webfonts/', file.name)) + ); + } + } + await Promise.all(copyOperations); +} + async function filterMissingFiles(filepaths) { const exists = await Promise.all( filepaths.map(async (filepath) => { @@ -175,7 +201,8 @@ async function getBundleMetadata(target) { const paths = [ path.join(__dirname, '../../node_modules'), path.join(__dirname, '../../public/scss'), - path.join(__dirname, '../../public/vendor/fontawesome/scss'), + path.join(__dirname, '../../public/fontawesome/scss'), + path.join(utils.getFontawesomePath(), 'scss'), ]; // Skin support @@ -256,13 +283,12 @@ CSS.getSkinSwitcherOptions = async function (uid) { }); return skins; } - - return { + return await plugins.hooks.fire('filter:meta.css.getSkinSwitcherOptions', { default: defaultSkins, custom: customSkins.map(s => ({ ...s, selected: s.value === userSettings.bootswatchSkin })), light: parseSkins(lightSkins), dark: parseSkins(darkSkins), - }; + }); }; CSS.getCustomSkins = async function (opts = {}) { @@ -313,6 +339,7 @@ CSS.buildBundle = async function (target, fork) { await Promise.all([ fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}.css`), ltr.code), fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}-rtl.css`), rtl.code), + copyFontAwesomeFiles(), ]); return [ltr.code, rtl.code]; }; diff --git a/src/middleware/assert.js b/src/middleware/assert.js index f91fde93f4..553114f870 100644 --- a/src/middleware/assert.js +++ b/src/middleware/assert.js @@ -113,8 +113,8 @@ Assert.room = helpers.try(async (req, res, next) => { } const [exists, inRoom] = await Promise.all([ - await messaging.roomExists(req.params.roomId), - await messaging.isUserInRoom(req.uid, req.params.roomId), + messaging.roomExists(req.params.roomId), + messaging.isUserInRoom(req.uid, req.params.roomId), ]); if (!exists) { diff --git a/src/middleware/helpers.js b/src/middleware/helpers.js index dde0c3b749..de2669bd84 100644 --- a/src/middleware/helpers.js +++ b/src/middleware/helpers.js @@ -41,16 +41,20 @@ helpers.buildBodyClass = function (req, res, templateData = {}) { p = validator.escape(String(p)); parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`; }); - - if (templateData.template) { - parts.push(`template-${templateData.template.name.split('/').join('-')}`); + const { template } = templateData; + if (template) { + parts.push(`template-${template.name.split('/').join('-')}`); } - if (templateData.template && templateData.template.topic) { + if (template && template.topic) { parts.push(`page-topic-category-${templateData.category.cid}`); parts.push(`page-topic-category-${slugify(templateData.category.name)}`); } + if (template && template.chats && templateData.roomId) { + parts.push(`page-user-chats-${templateData.roomId}`); + } + if (Array.isArray(templateData.breadcrumbs)) { templateData.breadcrumbs.forEach((crumb) => { if (crumb && crumb.hasOwnProperty('cid')) { diff --git a/src/middleware/index.js b/src/middleware/index.js index f3c42d11d6..80a5f568c6 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -6,6 +6,7 @@ const validator = require('validator'); const nconf = require('nconf'); const toobusy = require('toobusy-js'); const util = require('util'); +const multipart = require('connect-multiparty'); const { csrfSynchronisedProtection } = require('./csrf'); const plugins = require('../plugins'); @@ -27,6 +28,7 @@ const delayCache = cacheCreate({ ttl: 1000 * 60, max: 200, }); +const multipartMiddleware = multipart(); const middleware = module.exports; @@ -284,3 +286,14 @@ middleware.checkRequired = function (fields, req, res, next) { controllers.helpers.formatApiResponse(400, res, new Error(`[[error:required-parameters-missing, ${missing.join(' ')}]]`)); }; + +middleware.handleMultipart = (req, res, next) => { + // Applies multipart handler on applicable content-type + const { 'content-type': contentType } = req.headers; + + if (contentType && !contentType.startsWith('multipart/form-data')) { + return next(); + } + + multipartMiddleware(req, res, next); +}; diff --git a/src/middleware/render.js b/src/middleware/render.js index 3bbf6a6887..6b1181d3af 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -169,6 +169,7 @@ module.exports = function (middleware) { isGlobalMod: user.isGlobalModerator(req.uid), isModerator: user.isModeratorOfAnyCategory(req.uid), privileges: privileges.global.get(req.uid), + blocks: user.blocks.list(req.uid), user: user.getUserData(req.uid), isEmailConfirmSent: req.uid <= 0 ? false : await user.email.isValidationPending(req.uid), languageDirection: translator.translate('[[language:dir]]', res.locals.config.userLang), @@ -190,6 +191,7 @@ module.exports = function (middleware) { results.user.isGlobalMod = results.isGlobalMod; results.user.isMod = !!results.isModerator; results.user.privileges = results.privileges; + results.user.blocks = results.blocks; results.user.timeagoCode = results.timeagoCode; results.user[results.user.status] = true; results.user.lastRoomId = results.roomIds.length ? results.roomIds[0] : null; diff --git a/src/notifications.js b/src/notifications.js index b484129d5c..b4a8aeff63 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -159,7 +159,7 @@ Notifications.push = async function (notification, uids) { winston.error(err.stack); } }); - }, 1000); + }, 500); }; async function pushToUids(uids, notification) { diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 58f8c85f96..68d0ee2768 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -233,7 +233,7 @@ async function fireStaticHook(hook, hookList, params) { try { // eslint-disable-next-line - await timeout(hookFn(params), 5000, 'timeout'); + await timeout(hookFn(params), 10000, 'timeout'); } catch (err) { if (err && err.message === 'timeout') { winston.warn(`[plugins] Callback timed out, hook '${hook}' in plugin '${hookObj.id}'`); diff --git a/src/posts/delete.js b/src/posts/delete.js index fb285b5128..66c8269334 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -116,7 +116,9 @@ module.exports = function (Posts) { const topicPostCountTasks = []; const topicTasks = []; const zsetIncrBulk = []; + const tids = []; for (const [tid, posts] of Object.entries(postsByTopic)) { + tids.push(tid); incrObjectBulk.push([`topic:${tid}`, { postcount: -posts.length }]); if (posts.length && posts[0]) { const topicData = posts[0].topic; @@ -142,6 +144,14 @@ module.exports = function (Posts) { user.updatePostCount(_.uniq(postData.map(p => p.uid))), notifications.rescind(...postData.map(p => `new_post:tid:${p.tid}:pid:${p.pid}:uid:${p.uid}`)), ]); + const tidPosterZsets = tids.map(tid => `tid:${tid}:posters`); + await db.sortedSetsRemoveRangeByScore(tidPosterZsets, '-inf', 0); + const posterCounts = await db.sortedSetsCard(tidPosterZsets); + await db.setObjectBulk( + tids.map((tid, idx) => ( + [`topic:${tid}`, { postercount: posterCounts[idx] || 0 }] + )) + ); } async function deleteFromCategoryRecentPosts(postData) { diff --git a/src/posts/queue.js b/src/posts/queue.js index 7cfdb462d8..2c485fb11e 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -38,6 +38,11 @@ module.exports = function (Posts) { postData.forEach((postData, index) => { if (postData) { postData.user = userData[index]; + if (postData.user.uid === 0 && postData.data.handle) { + postData.user.username = validator.escape(String(postData.data.handle)); + postData.user.displayname = postData.user.username; + postData.user.fullname = postData.user.username; + } postData.data.rawContent = validator.escape(String(postData.data.content)); postData.data.title = validator.escape(String(postData.data.title || '')); } diff --git a/src/posts/user.js b/src/posts/user.js index 960e4960a6..4d9ab4d21e 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -206,6 +206,9 @@ module.exports = function (Posts) { await async.eachOf(postsByUser, async (posts, uid) => { await db.sortedSetIncrBy(`tid:${tid}:posters`, -posts.length, uid); }); + await db.sortedSetsRemoveRangeByScore([`tid:${tid}:posters`], '-inf', 0); + const posterCount = await db.sortedSetCard(`tid:${tid}:posters`); + await topics.setTopicField(tid, 'postercount', posterCount); }); } diff --git a/src/prestart.js b/src/prestart.js index bda51ad9e5..7a84a0a958 100644 --- a/src/prestart.js +++ b/src/prestart.js @@ -58,6 +58,10 @@ function loadConfig(configFile) { isCluster: false, isPrimary: true, jobsDisabled: false, + fontawesome: { + pro: false, + styles: '*', + }, }); // Explicitly cast as Bool, loader.js passes in isCluster as string 'true'/'false' diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 8d5bee679e..e24ff064b9 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -45,8 +45,7 @@ Auth.getLoginStrategies = function () { }; Auth.verifyToken = async function (token, done) { - const tokens = await api.utils.tokens.list(); - const tokenObj = tokens.filter((t => t.token === token)).pop(); + const tokenObj = await api.utils.tokens.get(token); const uid = tokenObj ? tokenObj.uid : undefined; if (uid !== undefined) { diff --git a/src/routes/helpers.js b/src/routes/helpers.js index 834ecfabfe..aff46467ec 100644 --- a/src/routes/helpers.js +++ b/src/routes/helpers.js @@ -16,6 +16,7 @@ helpers.setupPageRoute = function (...args) { } middlewares = [ + middleware.applyBlacklist, middleware.authenticateRequest, middleware.maintenanceMode, middleware.registrationComplete, @@ -53,11 +54,13 @@ helpers.setupApiRoute = function (...args) { const controller = args[args.length - 1]; middlewares = [ + middleware.applyBlacklist, middleware.authenticateRequest, middleware.maintenanceMode, middleware.registrationComplete, middleware.pluginHooks, middleware.logApiUsage, + middleware.handleMultipart, ...middlewares, ]; diff --git a/src/routes/write/admin.js b/src/routes/write/admin.js index 2571b8dd01..593e9ce123 100644 --- a/src/routes/write/admin.js +++ b/src/routes/write/admin.js @@ -15,6 +15,8 @@ module.exports = function () { setupApiRoute(router, 'get', '/analytics', [...middlewares], controllers.write.admin.getAnalyticsKeys); setupApiRoute(router, 'get', '/analytics/:set', [...middlewares], controllers.write.admin.getAnalyticsData); + setupApiRoute(router, 'delete', '/chats/:roomId', [...middlewares, middleware.assert.room], controllers.write.admin.chats.deleteRoom); + setupApiRoute(router, 'post', '/tokens', [...middlewares], controllers.write.admin.generateToken); setupApiRoute(router, 'get', '/tokens/:token', [...middlewares], controllers.write.admin.getToken); setupApiRoute(router, 'put', '/tokens/:token', [...middlewares], controllers.write.admin.updateToken); diff --git a/src/routes/write/chats.js b/src/routes/write/chats.js index a92db701f7..3334cb377f 100644 --- a/src/routes/write/chats.js +++ b/src/routes/write/chats.js @@ -16,8 +16,7 @@ module.exports = function () { setupApiRoute(router, 'head', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.exists); setupApiRoute(router, 'get', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.get); setupApiRoute(router, 'post', '/:roomId', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['message'])], controllers.write.chats.post); - setupApiRoute(router, 'put', '/:roomId', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['name'])], controllers.write.chats.rename); - // no route for room deletion, noted here just in case... + setupApiRoute(router, 'put', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.update); setupApiRoute(router, 'put', '/:roomId/state', [...middlewares, middleware.assert.room], controllers.write.chats.mark); setupApiRoute(router, 'delete', '/:roomId/state', [...middlewares, middleware.assert.room], controllers.write.chats.mark); diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 21165713db..e5efe90482 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -8,6 +8,7 @@ const events = require('../events'); const db = require('../database'); const privileges = require('../privileges'); const websockets = require('./index'); +const batch = require('../batch'); const index = require('./index'); const getAdminSearchDict = require('../admin/search').getDictionary; @@ -117,4 +118,12 @@ SocketAdmin.getServerTime = function (socket, data, callback) { }); }; +SocketAdmin.clearSearchHistory = async function () { + const keys = await db.scan({ match: 'searches:*' }); + await batch.processArray(keys, db.deleteAll, { + batch: 500, + interval: 0, + }); +}; + require('../promisify')(SocketAdmin); diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index 4aafe9fbf6..c426d0c7d6 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -1,61 +1,26 @@ 'use strict'; -const os = require('os'); -const nconf = require('nconf'); - const topics = require('../../topics'); -const pubsub = require('../../pubsub'); -const utils = require('../../utils'); +const io = require('..'); -const stats = {}; const totals = {}; const SocketRooms = module.exports; -SocketRooms.stats = stats; SocketRooms.totals = totals; -pubsub.on('sync:stats:start', () => { - const stats = SocketRooms.getLocalStats(); - pubsub.publish('sync:stats:end', { - stats: stats, - id: `${os.hostname()}:${nconf.get('port')}`, - }); -}); - -pubsub.on('sync:stats:end', (data) => { - stats[data.id] = data.stats; -}); - -pubsub.on('sync:stats:guests', (eventId) => { - const Sockets = require('../index'); - const guestCount = Sockets.getCountInRoom('online_guests'); - pubsub.publish(eventId, guestCount); -}); - -SocketRooms.getTotalGuestCount = function (callback) { - let count = 0; - const eventId = `sync:stats:guests:end:${utils.generateUUID()}`; - pubsub.on(eventId, (guestCount) => { - count += guestCount; - }); - - pubsub.publish('sync:stats:guests', eventId); - - setTimeout(() => { - pubsub.removeAllListeners(eventId); - callback(null, count); - }, 100); +SocketRooms.getTotalGuestCount = async function () { + const s = await io.in('online_guests').fetchSockets(); + return s.length; }; - SocketRooms.getAll = async function () { - pubsub.publish('sync:stats:start'); + const sockets = await io.server.fetchSockets(); totals.onlineGuestCount = 0; totals.onlineRegisteredCount = 0; - totals.socketCount = 0; - totals.topics = {}; + totals.socketCount = sockets.length; + totals.topTenTopics = []; totals.users = { categories: 0, recent: 0, @@ -63,30 +28,39 @@ SocketRooms.getAll = async function () { topics: 0, category: 0, }; - - for (const instance of Object.values(stats)) { - totals.onlineGuestCount += instance.onlineGuestCount; - totals.onlineRegisteredCount += instance.onlineRegisteredCount; - totals.socketCount += instance.socketCount; - totals.users.categories += instance.users.categories; - totals.users.recent += instance.users.recent; - totals.users.unread += instance.users.unread; - totals.users.topics += instance.users.topics; - totals.users.category += instance.users.category; - - instance.topics.forEach((topic) => { - totals.topics[topic.tid] = totals.topics[topic.tid] || { count: 0, tid: topic.tid }; - totals.topics[topic.tid].count += topic.count; - }); + const userRooms = {}; + const topicData = {}; + for (const s of sockets) { + for (const key of s.rooms) { + if (key === 'online_guests') { + totals.onlineGuestCount += 1; + } else if (key === 'categories') { + totals.users.categories += 1; + } else if (key === 'recent_topics') { + totals.users.recent += 1; + } else if (key === 'unread_topics') { + totals.users.unread += 1; + } else if (key.startsWith('uid_')) { + userRooms[key] = 1; + } else if (key.startsWith('category_')) { + totals.users.category += 1; + } else { + const tid = key.match(/^topic_(\d+)/); + if (tid) { + totals.users.topics += 1; + topicData[tid[1]] = topicData[tid[1]] || { count: 0 }; + topicData[tid[1]].count += 1; + } + } + } } + totals.onlineRegisteredCount = Object.keys(userRooms).length; let topTenTopics = []; - Object.keys(totals.topics).forEach((tid) => { - topTenTopics.push({ tid: tid, count: totals.topics[tid].count || 0 }); + Object.keys(topicData).forEach((tid) => { + topTenTopics.push({ tid: tid, count: topicData[tid].count }); }); - topTenTopics = topTenTopics.sort((a, b) => b.count - a.count).slice(0, 10); - const topTenTids = topTenTopics.map(topic => topic.tid); const titles = await topics.getTopicsFields(topTenTids, ['title']); @@ -94,6 +68,7 @@ SocketRooms.getAll = async function () { topic.title = titles[index].title; return topic; }); + return totals; }; diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index afe47e4d82..6c5e0c5b28 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -8,6 +8,7 @@ const groups = require('../../groups'); const user = require('../../user'); const events = require('../../events'); const translator = require('../../translator'); +const utils = require('../../utils'); const sockets = require('..'); const User = module.exports; @@ -146,6 +147,21 @@ User.loadGroups = async function (socket, uids) { return { users: userData }; }; +User.setReputation = async function (socket, data) { + if (!data || !Array.isArray(data.uids) || !utils.isNumber(data.value)) { + throw new Error('[[error:invalid-data]]'); + } + + await Promise.all([ + db.setObjectBulk( + data.uids.map(uid => ([`user:${uid}`, { reputation: parseInt(data.value, 10) }])) + ), + db.sortedSetAddBulk( + data.uids.map(uid => (['users:reputation', data.value, uid])) + ), + ]); +}; + User.exportUsersCSV = async function (socket) { await events.log({ type: 'exportUsersCSV', diff --git a/src/socket.io/blacklist.js b/src/socket.io/blacklist.js index c38220f9ff..af7678a17d 100644 --- a/src/socket.io/blacklist.js +++ b/src/socket.io/blacklist.js @@ -24,6 +24,10 @@ async function blacklist(socket, method, rule) { if (!isAdminOrGlobalMod) { throw new Error('[[error:no-privileges]]'); } + if (socket.ip && rule.includes(socket.ip)) { + throw new Error('[[error:cant-blacklist-self-ip]]'); + } + await meta.blacklist[method](rule); await events.log({ type: `ip-blacklist-${method}`, diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 0a90698115..169e207b0d 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -148,7 +148,7 @@ SocketCategories.isModerator = async function (socket, cid) { }; SocketCategories.loadMoreSubCategories = async function (socket, data) { - if (!data || !data.cid || !(parseInt(data.start, 10) > 0)) { + if (!data || !data.cid || !(parseInt(data.start, 10) >= 0)) { throw new Error('[[error:invalid-data]]'); } const allowed = await privileges.categories.can('read', data.cid, socket.uid); diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 969a0c07e8..d34eec366e 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -65,6 +65,17 @@ SocketGroups.loadMoreMembers = async (socket, data) => { }; }; +SocketGroups.getChatGroups = async (socket) => { + const isAdmin = await user.isAdministrator(socket.uid); + if (!isAdmin) { + throw new Error('[[error:no-privileges]]'); + } + const allGroups = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); + const groupsList = allGroups.filter(g => !groups.ephemeralGroups.includes(g.name)); + groupsList.sort((a, b) => b.system - a.system); + return groupsList.map(g => ({ name: g.name, displayName: g.displayName })); +}; + async function canSearchMembers(uid, groupName) { const [isHidden, isMember, hasAdminPrivilege, isGlobalMod, viewGroups] = await Promise.all([ groups.isHidden(groupName), diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 4dd3a31dd4..36b3384d24 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -196,4 +196,19 @@ SocketHelpers.emitToUids = async function (event, data, uids) { uids.forEach(toUid => websockets.in(`uid_${toUid}`).emit(event, data)); }; +SocketHelpers.removeSocketsFromRoomByUids = async function (uids, roomId) { + const sockets = _.flatten( + await Promise.all(uids.map(uid => websockets.in(`uid_${uid}`).fetchSockets())) + ); + + for (const s of sockets) { + if (s.rooms.has(`chat_room_${roomId}`)) { + websockets.in(s.id).socketsLeave(`chat_room_${roomId}`); + } + if (s.rooms.has(`chat_room_public_${roomId}`)) { + websockets.in(s.id).socketsLeave(`chat_room_public_${roomId}`); + } + } +}; + require('../promisify')(SocketHelpers); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index b540cbc15f..c128cc414c 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -12,6 +12,7 @@ const user = require('../user'); const logger = require('../logger'); const plugins = require('../plugins'); const ratelimit = require('../middleware/ratelimit'); +const blacklist = require('../meta/blacklist'); const Namespaces = Object.create(null); @@ -178,6 +179,7 @@ async function onMessage(socket, payload) { return socket.disconnect(); } + await blacklist.test(socket.ip); await checkMaintenance(socket); await validateSession(socket, '[[error:revalidate-failure]]'); @@ -292,6 +294,26 @@ Sockets.getCountInRoom = function (room) { return roomMap ? roomMap.size : 0; }; +// works across multiple nodes +Sockets.getUidsInRoom = async function (room) { + if (!Sockets.server) { + return []; + } + const ioRoom = Sockets.server.in(room); + const uids = {}; + if (ioRoom) { + const sockets = await ioRoom.fetchSockets(); + for (const s of sockets) { + for (const r of s.rooms) { + if (r.startsWith('uid_')) { + uids[r.split('_').pop()] = 1; + } + } + } + } + return Object.keys(uids); +}; + Sockets.warnDeprecated = (socket, replacement) => { if (socket.previousEvents && socket.emit) { socket.emit('event:deprecated_call', { diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index 68230bd6f0..e62ae0e356 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -4,9 +4,8 @@ const user = require('../user'); const topics = require('../topics'); -const SocketMeta = { - rooms: {}, -}; +const SocketMeta = module.exports; +SocketMeta.rooms = {}; SocketMeta.reconnected = function (socket, data, callback) { callback = callback || function () {}; @@ -19,13 +18,13 @@ SocketMeta.reconnected = function (socket, data, callback) { /* Rooms */ -SocketMeta.rooms.enter = function (socket, data, callback) { +SocketMeta.rooms.enter = async function (socket, data) { if (!socket.uid) { - return callback(); + return; } if (!data) { - return callback(new Error('[[error:invalid-data]]')); + throw new Error('[[error:invalid-data]]'); } if (data.enter) { @@ -33,7 +32,11 @@ SocketMeta.rooms.enter = function (socket, data, callback) { } if (data.enter && data.enter.startsWith('uid_') && data.enter !== `uid_${socket.uid}`) { - return callback(new Error('[[error:not-allowed]]')); + throw new Error('[[error:not-allowed]]'); + } + + if (data.enter && data.enter.startsWith('chat_')) { + throw new Error('[[error:not-allowed]]'); } leaveCurrentRoom(socket); @@ -42,15 +45,13 @@ SocketMeta.rooms.enter = function (socket, data, callback) { socket.join(data.enter); socket.currentRoom = data.enter; } - callback(); }; -SocketMeta.rooms.leaveCurrent = function (socket, data, callback) { +SocketMeta.rooms.leaveCurrent = async function (socket) { if (!socket.uid || !socket.currentRoom) { - return callback(); + return; } leaveCurrentRoom(socket); - callback(); }; function leaveCurrentRoom(socket) { @@ -60,4 +61,4 @@ function leaveCurrentRoom(socket) { } } -module.exports = SocketMeta; +require('../promisify')(SocketMeta); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 679a2516ec..0595e1b59f 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -1,10 +1,14 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../database'); const Messaging = require('../messaging'); const utils = require('../utils'); const user = require('../user'); +const plugins = require('../plugins'); const privileges = require('../privileges'); +const groups = require('../groups'); const SocketModules = module.exports; @@ -18,13 +22,13 @@ SocketModules.chats.getRaw = async function (socket, data) { throw new Error('[[error:invalid-data]]'); } const roomId = await Messaging.getMessageField(data.mid, 'roomId'); - const [isAdmin, hasMessage, inRoom] = await Promise.all([ + const [isAdmin, canViewMessage, inRoom] = await Promise.all([ user.isAdministrator(socket.uid), - db.isSortedSetMember(`uid:${socket.uid}:chat:room:${roomId}:mids`, data.mid), + Messaging.canViewMessage(data.mid, roomId, socket.uid), Messaging.isUserInRoom(socket.uid, roomId), ]); - if (!isAdmin && (!inRoom || !hasMessage)) { + if (!isAdmin && (!inRoom || !canViewMessage)) { throw new Error('[[error:not-allowed]]'); } @@ -70,4 +74,181 @@ SocketModules.chats.getIP = async function (socket, mid) { return await Messaging.getMessageField(mid, 'ip'); }; +SocketModules.chats.getUnreadCount = async function (socket) { + return await Messaging.getUnreadCount(socket.uid); +}; + +SocketModules.chats.enter = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'join'); +}; + +SocketModules.chats.leave = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'leave'); +}; + +SocketModules.chats.enterPublic = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'join', 'chat_room_public'); +}; + +SocketModules.chats.leavePublic = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'leave', 'chat_room_public'); +}; + +async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { + if (!(socket.uid > 0)) { + throw new Error('[[error:not-allowed]]'); + } + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + } + if (roomIds.length) { + const [isAdmin, inRooms, roomData] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, roomIds), + Messaging.getRoomsData(roomIds, ['public', 'groups']), + ]); + + await Promise.all(roomIds.map(async (roomId, idx) => { + const isPublic = roomData[idx] && roomData[idx].public; + const roomGroups = roomData[idx] && roomData[idx].groups; + + if (isAdmin || + ( + inRooms[idx] && + (!isPublic || !roomGroups.length || await groups.isMemberOfAny(socket.uid, roomGroups)) + ) + ) { + socket[method](`${prefix}_${roomId}`); + } + })); + } +} + +SocketModules.chats.sortPublicRooms = async function (socket, data) { + if (!data || !Array.isArray(data.scores) || !Array.isArray(data.roomIds)) { + throw new Error('[[error:invalid-data]]'); + } + const isAdmin = await user.isAdministrator(socket.uid); + if (!isAdmin) { + throw new Error('[[error:no-privileges]]'); + } + await db.sortedSetAdd(`chat:rooms:public:order`, data.scores, data.roomIds); + require('../cache').del(`chat:rooms:public:order:all`); +}; + +SocketModules.chats.searchMembers = async function (socket, data) { + if (!data || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + const [isAdmin, inRoom, isRoomOwner] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, data.roomId), + Messaging.isRoomOwner(socket.uid, data.roomId), + ]); + + if (!isAdmin && !inRoom) { + throw new Error('[[error:no-privileges]]'); + } + + const results = await user.search({ + query: data.username, + paginate: false, + hardCap: -1, + }); + + const { users } = results; + const foundUids = users.map(user => user && user.uid); + const isUidInRoom = _.zipObject( + foundUids, + await Messaging.isUsersInRoom(foundUids, data.roomId) + ); + + const roomUsers = users.filter(user => isUidInRoom[user.uid]); + const isOwners = await Messaging.isRoomOwner(roomUsers.map(u => u.uid), data.roomId); + + roomUsers.forEach((user, index) => { + if (user) { + user.isOwner = isOwners[index]; + user.canKick = isRoomOwner && (parseInt(user.uid, 10) !== parseInt(socket.uid, 10)); + } + }); + + roomUsers.sort((a, b) => { + if (a.isOwner && !b.isOwner) { + return -1; + } else if (!a.isOwner && b.isOwner) { + return 1; + } + return 0; + }); + return { users: roomUsers }; +}; + +SocketModules.chats.toggleOwner = async (socket, data) => { + if (!data || !data.uid || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + const [isAdmin, inRoom, isRoomOwner] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, data.roomId), + Messaging.isRoomOwner(socket.uid, data.roomId), + ]); + if (!isAdmin && (!inRoom || !isRoomOwner)) { + throw new Error('[[error:no-privileges]]'); + } + + await Messaging.toggleOwner(data.uid, data.roomId); +}; + +SocketModules.chats.setNotificationSetting = async (socket, data) => { + if (!data || !utils.isNumber(data.value) || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + const inRoom = await Messaging.isUserInRoom(socket.uid, data.roomId); + if (!inRoom) { + throw new Error('[[error:no-privileges]]'); + } + + await Messaging.setUserNotificationSetting(socket.uid, data.roomId, data.value); +}; + +SocketModules.chats.searchMessages = async (socket, data) => { + if (!data || !utils.isNumber(data.roomId) || !data.content) { + throw new Error('[[error:invalid-data]]'); + } + const [roomData, inRoom] = await Promise.all([ + Messaging.getRoomData(data.roomId), + Messaging.isUserInRoom(socket.uid, data.roomId), + ]); + + if (!roomData) { + throw new Error('[[error:no-room]]'); + } + if (!inRoom) { + throw new Error('[[error:no-privileges]]'); + } + const { ids } = await plugins.hooks.fire('filter:messaging.searchMessages', { + content: data.content, + roomId: [data.roomId], + uid: [data.uid], + matchWords: 'any', + ids: [], + }); + + let userjoinTimestamp = 0; + if (!roomData.public) { + userjoinTimestamp = await db.sortedSetScore(`chat:room:${data.roomId}:uids`, socket.uid); + } + const messageData = await Messaging.getMessagesData(ids, socket.uid, data.roomId, false); + messageData.forEach((msg) => { + if (msg) { + msg.newSet = true; + } + }); + + return messageData.filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp); +}; + require('../promisify')(SocketModules); diff --git a/src/socket.io/posts/votes.js b/src/socket.io/posts/votes.js index 0ecd8196ef..4c971efd82 100644 --- a/src/socket.io/posts/votes.js +++ b/src/socket.io/posts/votes.js @@ -1,5 +1,7 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../../database'); const user = require('../../user'); const posts = require('../../posts'); @@ -39,23 +41,47 @@ module.exports = function (SocketPosts) { if (!Array.isArray(pids)) { throw new Error('[[error:invalid-data]]'); } - const data = await posts.getUpvotedUidsByPids(pids); + + const [cids, data, isAdmin] = await Promise.all([ + posts.getCidsByPids(pids), + posts.getUpvotedUidsByPids(pids), + privileges.users.isAdministrator(socket.uid), + ]); + + if (!isAdmin) { + const isAllowed = await privileges.categories.isUserAllowedTo( + 'topics:read', _.uniq(cids), socket.uid + ); + if (isAllowed.includes(false)) { + throw new Error('[[error:no-privileges]]'); + } + } + if (!data.length) { return []; } - - const result = await Promise.all(data.map(async (uids) => { + const cutoff = 6; + const sliced = data.map((uids) => { let otherCount = 0; - if (uids.length > 6) { - otherCount = uids.length - 5; - uids = uids.slice(0, 5); + if (uids.length > cutoff) { + otherCount = uids.length - (cutoff - 1); + uids = uids.slice(0, cutoff - 1); } - const usernames = await user.getUsernamesByUids(uids); return { - otherCount: otherCount, - usernames: usernames, + otherCount, + uids, }; - })); + }); + + const uniqUids = _.uniq(_.flatten(sliced.map(d => d.uids))); + const usernameMap = _.zipObject(uniqUids, await user.getUsernamesByUids(uniqUids)); + const result = sliced.map( + data => ({ + otherCount: data.otherCount, + cutoff: cutoff, + usernames: data.uids.map(uid => usernameMap[uid]), + }) + ); return result; }; }; diff --git a/src/topics/create.js b/src/topics/create.js index 5d631cce27..f962b21ddf 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -80,23 +80,26 @@ module.exports = function (Topics) { data = await plugins.hooks.fire('filter:topic.post', data); const { uid } = data; - data.title = String(data.title).trim(); - data.tags = data.tags || []; - data.content = String(data.content || '').trimEnd(); - - Topics.checkTitle(data.title); - await Topics.validateTags(data.tags, data.cid, uid); - data.tags = await Topics.filterTags(data.tags, data.cid); - if (!data.fromQueue) { - Topics.checkContent(data.content); - } - - const [categoryExists, canCreate, canTag] = await Promise.all([ + const [categoryExists, canCreate, canTag, isAdmin] = await Promise.all([ categories.exists(data.cid), privileges.categories.can('topics:create', data.cid, uid), privileges.categories.can('topics:tag', data.cid, uid), + privileges.users.isAdministrator(uid), ]); + data.title = String(data.title).trim(); + data.tags = data.tags || []; + data.content = String(data.content || '').trimEnd(); + if (!isAdmin) { + Topics.checkTitle(data.title); + } + + await Topics.validateTags(data.tags, data.cid, uid); + data.tags = await Topics.filterTags(data.tags, data.cid); + if (!data.fromQueue && !isAdmin) { + Topics.checkContent(data.content); + } + if (!categoryExists) { throw new Error('[[error:no-category]]'); } @@ -159,7 +162,10 @@ module.exports = function (Topics) { const { tid } = data; const { uid } = data; - const topicData = await Topics.getTopicData(tid); + const [topicData, isAdmin] = await Promise.all([ + Topics.getTopicData(tid), + privileges.users.isAdministrator(uid), + ]); await canReply(data, topicData); @@ -168,7 +174,7 @@ module.exports = function (Topics) { await guestHandleValid(data); data.content = String(data.content || '').trimEnd(); - if (!data.fromQueue) { + if (!data.fromQueue && !isAdmin) { await user.isReadyToPost(uid, data.cid); Topics.checkContent(data.content); } diff --git a/src/topics/posts.js b/src/topics/posts.js index 438844d753..1d1b95af2b 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -189,14 +189,18 @@ module.exports = function (Topics) { const usersMap = _.zipObject(parentUids, userData); const parents = {}; parentPosts.forEach((post, i) => { - parents[parentPids[i]] = { - username: usersMap[post.uid].username, - displayname: usersMap[post.uid].displayname, - }; + if (usersMap[post.uid]) { + parents[parentPids[i]] = { + username: usersMap[post.uid].username, + displayname: usersMap[post.uid].displayname, + }; + } }); postData.forEach((post) => { - post.parent = parents[post.toPid]; + if (parents[post.toPid]) { + post.parent = parents[post.toPid]; + } }); }; diff --git a/src/topics/sorted.js b/src/topics/sorted.js index 7899a2f8d0..a1d809fb48 100644 --- a/src/topics/sorted.js +++ b/src/topics/sorted.js @@ -112,7 +112,9 @@ module.exports = function (Topics) { if (params.term === 'alltime' && !params.cids && !params.tags.length && params.filter !== 'watched' && !params.floatPinned) { return tids; } - const topicData = await Topics.getTopicsFields(tids, ['tid', 'lastposttime', 'upvotes', 'downvotes', 'postcount', 'pinned']); + const topicData = await Topics.getTopicsFields(tids, [ + 'tid', 'lastposttime', 'upvotes', 'downvotes', 'postcount', 'pinned', + ]); const sortMap = { recent: sortRecent, old: sortOld, diff --git a/src/upgrades/3.3.0/chat_message_mids.js b/src/upgrades/3.3.0/chat_message_mids.js new file mode 100644 index 0000000000..d7f349ae98 --- /dev/null +++ b/src/upgrades/3.3.0/chat_message_mids.js @@ -0,0 +1,46 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + +module.exports = { + name: 'Set mid on message objects and create messages:mid', + timestamp: Date.UTC(2023, 6, 27), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard(`chat:rooms`); + await batch.processSortedSet(`chat:rooms`, async (roomIds) => { + progress.incr(roomIds.length); + await Promise.all(roomIds.map(async (roomId) => { + await batch.processSortedSet(`chat:room:${roomId}:mids`, async (mids) => { + let messageData = await db.getObjects(mids.map(mid => `message:${mid}`)); + messageData.forEach((m, idx) => { + if (m) { + m.mid = parseInt(mids[idx], 10); + } + }); + messageData = messageData.filter(Boolean); + + const bulkSet = messageData.map( + msg => [`message:${msg.mid}`, { mid: msg.mid }] + ); + + await db.setObjectBulk(bulkSet); + await db.sortedSetAdd( + 'messages:mid', + messageData.map(msg => msg.timestamp), + messageData.map(msg => msg.mid) + ); + }, { + batch: 500, + }); + })); + }, { + batch: 500, + }); + const count = await db.sortedSetCard(`messages:mid`); + await db.setObjectField('global', 'messageCount', count); + }, +}; diff --git a/src/upgrades/3.3.0/chat_room_online_zset.js b/src/upgrades/3.3.0/chat_room_online_zset.js new file mode 100644 index 0000000000..0a57076fa0 --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_online_zset.js @@ -0,0 +1,32 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Create chat:room:uids:online zset', + timestamp: Date.UTC(2023, 6, 14), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard('chat:rooms'); + + await batch.processSortedSet('chat:rooms', async (roomIds) => { + progress.incr(roomIds.length); + const arrayOfUids = await db.getSortedSetsMembersWithScores(roomIds.map(roomId => `chat:room:${roomId}:uids`)); + + const bulkAdd = []; + arrayOfUids.forEach((uids, idx) => { + const roomId = roomIds[idx]; + uids.forEach((uid) => { + bulkAdd.push([`chat:room:${roomId}:uids:online`, uid.score, uid.value]); + }); + }); + await db.sortedSetAddBulk(bulkAdd); + }, { + batch: 500, + }); + }, +}; diff --git a/src/upgrades/3.3.0/chat_room_owners.js b/src/upgrades/3.3.0/chat_room_owners.js new file mode 100644 index 0000000000..9824091e39 --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_owners.js @@ -0,0 +1,44 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Create chat:room::owners zset', + timestamp: Date.UTC(2023, 6, 17), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard('chat:rooms'); + const users = await db.getSortedSetRangeWithScores(`users:joindate`, 0, 0); + const timestamp = users.length ? users[0].score : Date.now(); + + await batch.processSortedSet('chat:rooms', async (roomIds) => { + progress.incr(roomIds.length); + const roomData = await db.getObjects( + roomIds.map(id => `chat:room:${id}`) + ); + + const arrayOfUids = await Promise.all( + roomIds.map(roomId => db.getSortedSetRangeWithScores(`chat:room:${roomId}:uids`, 0, 0)) + ); + + const bulkAdd = []; + roomData.forEach((room, idx) => { + if (room && room.roomId && room.owner) { + // if room doesn't have timestamp for some reason use the first user timestamp + room.timestamp = room.timestamp || ( + arrayOfUids[idx].length ? (arrayOfUids[idx][0].score || timestamp) : timestamp + ); + bulkAdd.push([`chat:room:${room.roomId}:owners`, room.timestamp, room.owner]); + } + }); + + await db.sortedSetAddBulk(bulkAdd); + }, { + batch: 500, + }); + }, +}; diff --git a/src/upgrades/3.3.0/chat_room_refactor.js b/src/upgrades/3.3.0/chat_room_refactor.js new file mode 100644 index 0000000000..7c008a9764 --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_refactor.js @@ -0,0 +1,66 @@ +'use strict'; + + +const _ = require('lodash'); + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Update chat messages to add roomId field', + timestamp: Date.UTC(2023, 6, 2), + method: async function () { + const { progress } = this; + + const nextChatRoomId = await db.getObjectField('global', 'nextChatRoomId'); + const allRoomIds = []; + for (let i = 1; i <= nextChatRoomId; i++) { + allRoomIds.push(i); + } + progress.total = allRoomIds.length; + await batch.processArray(allRoomIds, async (roomIds) => { + progress.incr(roomIds.length); + const [arrayOfUids, arrayOfRoomData] = await Promise.all([ + db.getSortedSetsMembers(roomIds.map(roomId => `chat:room:${roomId}:uids`)), + db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`)), + ]); + + await Promise.all(roomIds.map(async (roomId, index) => { + const uids = arrayOfUids[index]; + const roomData = arrayOfRoomData[index]; + if (!uids.length && !roomData) { + return; + } + if (roomData && roomData.owner && !uids.includes(String(roomData.owner))) { + uids.push(roomData.owner); + } + const userKeys = uids.map(uid => `uid:${uid}:chat:room:${roomId}:mids`); + const mids = await db.getSortedSetsMembers(userKeys); + const uniqMids = _.uniq(_.flatten(mids)); + let messageData = await db.getObjects(uniqMids.map(mid => `message:${mid}`)); + messageData.forEach((m, idx) => { + if (m) { + m.mid = parseInt(uniqMids[idx], 10); + } + }); + messageData = messageData.filter(Boolean); + + const bulkSet = messageData.map( + msg => [`message:${msg.mid}`, { roomId: roomId }] + ); + + await db.setObjectBulk(bulkSet); + await db.setObjectField(`chat:room:${roomId}`, 'userCount', uids.length); + await db.sortedSetAdd( + `chat:room:${roomId}:mids`, + messageData.map(m => m.timestamp), + messageData.map(m => m.mid), + ); + await db.deleteAll(userKeys); + })); + }, { + batch: 500, + }); + }, +}; diff --git a/src/upgrades/3.3.0/save_rooms_zset.js b/src/upgrades/3.3.0/save_rooms_zset.js new file mode 100644 index 0000000000..9c75362a50 --- /dev/null +++ b/src/upgrades/3.3.0/save_rooms_zset.js @@ -0,0 +1,42 @@ +'use strict'; + +const db = require('../../database'); +const batch = require('../../batch'); + +module.exports = { + name: 'Store list of chat rooms', + timestamp: Date.UTC(2023, 6, 3), + method: async function () { + const { progress } = this; + const lastRoomId = await db.getObjectField('global', 'nextChatRoomId'); + const allRoomIds = []; + for (let x = 1; x <= lastRoomId; x++) { + allRoomIds.push(x); + } + const users = await db.getSortedSetRangeWithScores(`users:joindate`, 0, 0); + const timestamp = users.length ? users[0].score : Date.now(); + progress.total = allRoomIds.length; + + await batch.processArray(allRoomIds, async (roomIds) => { + progress.incr(roomIds.length); + const keys = roomIds.map(id => `chat:room:${id}`); + const exists = await db.exists(keys); + roomIds = roomIds.filter((_, idx) => exists[idx]); + // get timestamp from uids, if no users use the timestamp of first user + const arrayOfUids = await Promise.all( + roomIds.map(roomId => db.getSortedSetRangeWithScores(`chat:room:${roomId}:uids`, 0, 0)) + ); + + const timestamps = roomIds.map( + (id, idx) => (arrayOfUids[idx].length ? (arrayOfUids[idx][0].score || timestamp) : timestamp) + ); + + await db.sortedSetAdd('chat:rooms', timestamps, roomIds); + await db.setObjectBulk( + roomIds.map((id, idx) => ([`chat:room:${id}`, { timestamp: timestamps[idx] }])) + ); + }, { + batch: 500, + }); + }, +}; diff --git a/src/user/delete.js b/src/user/delete.js index 4cc574c4ff..1362df1621 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -116,7 +116,9 @@ module.exports = function (User) { `user:${uid}:emails`, `uid:${uid}:topics`, `uid:${uid}:posts`, `uid:${uid}:chats`, `uid:${uid}:chats:unread`, - `uid:${uid}:chat:rooms`, `uid:${uid}:chat:rooms:unread`, + `uid:${uid}:chat:rooms`, + `uid:${uid}:chat:rooms:unread`, + `uid:${uid}:chat:rooms:read`, `uid:${uid}:upvote`, `uid:${uid}:downvote`, `uid:${uid}:flag:pids`, `uid:${uid}:sessions`, `uid:${uid}:sessionUUID:sessionId`, @@ -168,13 +170,10 @@ module.exports = function (User) { } async function deleteChats(uid) { - const roomIds = await db.getSortedSetRange(`uid:${uid}:chat:rooms`, 0, -1); - const userKeys = roomIds.map(roomId => `uid:${uid}:chat:room:${roomId}:mids`); - - await Promise.all([ - messaging.leaveRooms(uid, roomIds), - db.deleteAll(userKeys), - ]); + const roomIds = await db.getSortedSetRange([ + `uid:${uid}:chat:rooms`, `chat:rooms:public`, + ], 0, -1); + await messaging.leaveRooms(uid, roomIds); } async function deleteUserIps(uid) { diff --git a/src/user/digest.js b/src/user/digest.js index d45cf8e576..b07f54d1c3 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -8,6 +8,7 @@ const batch = require('../batch'); const meta = require('../meta'); const user = require('./index'); const topics = require('../topics'); +const messaging = require('../messaging'); const plugins = require('../plugins'); const emailer = require('../emailer'); const utils = require('../utils'); @@ -94,13 +95,16 @@ Digest.send = async function (data) { return; } await Promise.all(userData.map(async (userObj) => { - const [notifications, topics] = await Promise.all([ + const [publicRooms, notifications, topics] = await Promise.all([ + getUnreadPublicRooms(userObj.uid), user.notifications.getUnreadInterval(userObj.uid, data.interval), getTermTopics(data.interval, userObj.uid), ]); const unreadNotifs = notifications.filter(Boolean); - // If there are no notifications and no new topics, don't bother sending a digest - if (!unreadNotifs.length && !topics.top.length && !topics.popular.length && !topics.recent.length) { + // If there are no notifications and no new topics and no unread chats, don't bother sending a digest + if (!unreadNotifs.length && + !topics.top.length && !topics.popular.length && !topics.recent.length && + !publicRooms.length) { return; } @@ -120,6 +124,7 @@ Digest.send = async function (data) { username: userObj.username, userslug: userObj.userslug, notifications: unreadNotifs, + publicRooms: publicRooms, recent: topics.recent, topTopics: topics.top, popularTopics: topics.popular, @@ -212,3 +217,8 @@ async function getTermTopics(term, uid) { }); return { top, popular, recent }; } + +async function getUnreadPublicRooms(uid) { + const publicRooms = await messaging.getPublicRooms(uid, uid); + return publicRooms.filter(r => r && r.unread); +} diff --git a/src/user/interstitials.js b/src/user/interstitials.js index cbb82ba9f7..fbdb63f9ab 100644 --- a/src/user/interstitials.js +++ b/src/user/interstitials.js @@ -28,8 +28,8 @@ Interstitials.email = async (data) => { return data; } - const [isAdminOrGlobalMod, hasPassword, hasPending] = await Promise.all([ - user.isAdminOrGlobalMod(data.req.uid), + const [canManageUsers, hasPassword, hasPending] = await Promise.all([ + privileges.admin.can('admin:users', data.req.uid), user.hasPassword(data.userData.uid), user.email.isValidationPending(data.userData.uid), ]); @@ -44,7 +44,12 @@ Interstitials.email = async (data) => { data: { email, requireEmailAddress: meta.config.requireEmailAddress, - issuePasswordChallenge: !!data.userData.uid && hasPassword, + issuePasswordChallenge: + hasPassword && + ( + (canManageUsers && data.userData.uid === data.req.uid) || // admin changing own email + (!canManageUsers && !!data.userData.uid) // non-admins changing own email + ), hasPending, }, callback: async (userData, formData) => { @@ -68,7 +73,7 @@ Interstitials.email = async (data) => { }), ]); - if (!isAdminOrGlobalMod && !isPasswordCorrect) { + if (!canManageUsers && !isPasswordCorrect) { await sleep(2000); } @@ -87,7 +92,7 @@ Interstitials.email = async (data) => { } // Admins editing will auto-confirm, unless editing their own email - if (isAdminOrGlobalMod && userData.uid !== data.req.uid) { + if (canManageUsers && userData.uid !== data.req.uid) { if (!await user.email.available(formData.email)) { throw new Error('[[error:email-taken]]'); } @@ -115,7 +120,7 @@ Interstitials.email = async (data) => { throw new Error('[[error:invalid-email]]'); } - if (current.length && (!hasPassword || (hasPassword && isPasswordCorrect) || isAdminOrGlobalMod)) { + if (current.length && (!hasPassword || (hasPassword && isPasswordCorrect) || canManageUsers)) { // User or admin explicitly clearing their email await user.email.remove(userData.uid, isSelf ? data.req.session.id : null); } diff --git a/src/user/jobs/export-profile.js b/src/user/jobs/export-profile.js index 49c18550ca..27177d112d 100644 --- a/src/user/jobs/export-profile.js +++ b/src/user/jobs/export-profile.js @@ -89,7 +89,7 @@ process.on('message', async (msg) => { async function getRoomMessages(uid, roomId) { const batch = require('../../batch'); let data = []; - await batch.processSortedSet(`uid:${uid}:chat:room:${roomId}:mids`, async (mids) => { + await batch.processSortedSet(`chat:room:${roomId}:mids`, async (mids) => { const messageData = await db.getObjects(mids.map(mid => `message:${mid}`)); data = data.concat( messageData diff --git a/src/user/profile.js b/src/user/profile.js index 09c4814410..8daba09758 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -310,6 +310,8 @@ module.exports = function (User) { throw new Error('[[user:change_password_error_privileges]]'); } + await plugins.hooks.fire('filter:password.check', { password: data.newPassword, uid: data.uid }); + if (isSelf && hasPassword) { const correct = await User.isPasswordCorrect(data.uid, data.currentPassword, data.ip); if (!correct) { diff --git a/src/user/reset.js b/src/user/reset.js index 557a83285c..9a6d6330ff 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -12,6 +12,7 @@ const db = require('../database'); const meta = require('../meta'); const emailer = require('../emailer'); const Password = require('../password'); +const plugins = require('../plugins'); const UserReset = module.exports; @@ -92,8 +93,11 @@ UserReset.commit = async function (code, password) { } const userData = await db.getObjectFields( `user:${uid}`, - ['password', 'passwordExpiry', 'password:shaWrapped'] + ['password', 'passwordExpiry', 'password:shaWrapped', 'username'] ); + + await plugins.hooks.fire('filter:password.check', { password: password, uid }); + const ok = await Password.compare(password, userData.password, !!parseInt(userData['password:shaWrapped'], 10)); if (ok) { throw new Error('[[error:reset-same-password]]'); diff --git a/src/utils.js b/src/utils.js index 2d0d2e7b9c..fb59865f69 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,6 +1,8 @@ 'use strict'; const crypto = require('crypto'); +const nconf = require('nconf'); +const path = require('node:path'); process.profile = function (operation, start) { console.log('%s took %d milliseconds', operation, process.elapsedTimeSince(start)); @@ -38,4 +40,36 @@ utils.getSass = function () { } }; +utils.getFontawesomePath = function () { + let packageName = '@fortawesome/fontawesome-free'; + if (nconf.get('fontawesome:pro') === true) { + packageName = '@fortawesome/fontawesome-pro'; + } + const pathToMainFile = require.resolve(packageName); + // main file will be in `js/fontawesome.js` - we need to go up two directories to get to the root of the package + const fontawesomePath = path.dirname(path.dirname(pathToMainFile)); + return fontawesomePath; +}; + +utils.getFontawesomeStyles = function () { + let styles = nconf.get('fontawesome:styles') || '*'; + // "*" is a special case, it means all styles, spread is used to support both string and array (["*"]) + if ([...styles][0] === '*') { + styles = ['solid', 'brands', 'regular']; + if (nconf.get('fontawesome:pro')) { + styles.push('light', 'thin', 'sharp', 'duotone'); + } + } + if (!Array.isArray(styles)) { + styles = [styles]; + } + return styles; +}; + +utils.getFontawesomeVersion = function () { + const fontawesomePath = utils.getFontawesomePath(); + const packageJson = require(path.join(fontawesomePath, 'package.json')); + return packageJson.version; +}; + module.exports = utils; diff --git a/src/views/admin/advanced/database.tpl b/src/views/admin/advanced/database.tpl index 4e10d868d7..cdcf2a65ab 100644 --- a/src/views/admin/advanced/database.tpl +++ b/src/views/admin/advanced/database.tpl @@ -13,10 +13,10 @@
[[admin/advanced/database:mongo.version]] {mongo.version}

-
[[admin/advanced/database:uptime-seconds]] {mongo.uptime}
+
[[admin/advanced/database:uptime-seconds]] {formattedNumber(mongo.uptime)}
[[admin/advanced/database:mongo.storage-engine]] {mongo.storageEngine}
-
[[admin/advanced/database:mongo.collections]] {mongo.collections}
-
[[admin/advanced/database:mongo.objects]] {mongo.objects}
+
[[admin/advanced/database:mongo.collections]] {formattedNumber(mongo.collections)}
+
[[admin/advanced/database:mongo.objects]] {formattedNumber(mongo.objects)}
[[admin/advanced/database:mongo.avg-object-size]] [[admin/advanced/database:x-b, {mongo.avgObjSize}]]

[[admin/advanced/database:mongo.data-size]] [[admin/advanced/database:x-gb, {mongo.dataSize}]]
@@ -47,23 +47,23 @@
[[admin/advanced/database:redis.version]] {redis.redis_version}

-
[[admin/advanced/database:uptime-seconds]] {redis.uptime_in_seconds}
+
[[admin/advanced/database:uptime-seconds]] {formattedNumber(redis.uptime_in_seconds)}
[[admin/advanced/database:uptime-days]] {redis.uptime_in_days}

-
[[admin/advanced/database:redis.keys]] {redis.keys}
-
[[admin/advanced/database:redis.expires]] {redis.expires}
-
[[admin/advanced/database:redis.avg-ttl]] {redis.avg_ttl}
-
[[admin/advanced/database:redis.connected-clients]] {redis.connected_clients}
-
[[admin/advanced/database:redis.connected-slaves]] {redis.connected_slaves}
+
[[admin/advanced/database:redis.keys]] {formattedNumber(redis.keys)}
+
[[admin/advanced/database:redis.expires]] {formattedNumber(redis.expires)}
+
[[admin/advanced/database:redis.avg-ttl]] {formattedNumber(redis.avg_ttl)}
+
[[admin/advanced/database:redis.connected-clients]] {formattedNumber(redis.connected_clients)}
+
[[admin/advanced/database:redis.connected-slaves]] {formattedNumber(redis.connected_slaves)}
[[admin/advanced/database:redis.blocked-clients]] {redis.blocked_clients}

[[admin/advanced/database:redis.used-memory]] [[admin/advanced/database:x-gb, {redis.used_memory_human}]]
[[admin/advanced/database:redis.memory-frag-ratio]] {redis.mem_fragmentation_ratio}

-
[[admin/advanced/database:redis.total-connections-recieved]] {redis.total_connections_received}
-
[[admin/advanced/database:redis.total-commands-processed]] {redis.total_commands_processed}
-
[[admin/advanced/database:redis.iops]] {redis.instantaneous_ops_per_sec}
+
[[admin/advanced/database:redis.total-connections-recieved]] {formattedNumber(redis.total_connections_received)}
+
[[admin/advanced/database:redis.total-commands-processed]] {formattedNumber(redis.total_commands_processed)}
+
[[admin/advanced/database:redis.iops]] {formattedNumber(redis.instantaneous_ops_per_sec)}
[[admin/advanced/database:redis.iinput]] [[admin/advanced/database:x-mb, {redis.instantaneous_input}]]
[[admin/advanced/database:redis.ioutput]] [[admin/advanced/database:x-mb, {redis.instantaneous_output}]]
@@ -71,8 +71,8 @@
[[admin/advanced/database:redis.total-output]] [[admin/advanced/database:x-gb, {redis.total_net_output}]]

-
[[admin/advanced/database:redis.keyspace-hits]] {redis.keyspace_hits}
-
[[admin/advanced/database:redis.keyspace-misses]] {redis.keyspace_misses}
+
[[admin/advanced/database:redis.keyspace-hits]] {formattedNumber(redis.keyspace_hits)}
+
[[admin/advanced/database:redis.keyspace-misses]] {formattedNumber(redis.keyspace_misses)}
@@ -87,7 +87,7 @@
[[admin/advanced/database:postgres.version]] {postgres.version}

-
[[admin/advanced/database:uptime-seconds]] {postgres.uptime}
+
[[admin/advanced/database:uptime-seconds]] {formattedNumber(postgres.uptime)}
diff --git a/src/views/admin/dashboard.tpl b/src/views/admin/dashboard.tpl index 6858038257..5f5de432cd 100644 --- a/src/views/admin/dashboard.tpl +++ b/src/views/admin/dashboard.tpl @@ -10,7 +10,7 @@
-
    +
    • () [[admin/dashboard:registered]]
    • () [[admin/dashboard:guest]]
    @@ -25,7 +25,7 @@
    -
      +
      • () [[admin/dashboard:reading-posts]]
      • () [[admin/dashboard:on-categories]]
      • () [[admin/dashboard:browsing-topics]]
      • @@ -42,7 +42,7 @@
        -
          +
        @@ -83,7 +83,15 @@ [[admin/dashboard:maintenance-mode]] - [[admin/dashboard:realtime-chart-updates]] OFF +
        + + +
        + +
        + + +
        {{{ end }}}
        [[admin/dashboard:notices]]
        diff --git a/src/views/admin/dashboard/searches.tpl b/src/views/admin/dashboard/searches.tpl index 27bf1ca11d..c669c4eda4 100644 --- a/src/views/admin/dashboard/searches.tpl +++ b/src/views/admin/dashboard/searches.tpl @@ -1,20 +1,21 @@
        - -
        -
        - - -
        -
        - - -
        -
        - -
        -
        - +
        +
        +
        + + +
        +
        + + +
        +
        + +
        +
        + +
        diff --git a/src/views/admin/development/info.tpl b/src/views/admin/development/info.tpl index aec2347985..7440729fab 100644 --- a/src/views/admin/development/info.tpl +++ b/src/views/admin/development/info.tpl @@ -12,7 +12,6 @@ - @@ -31,7 +30,6 @@ {{{if info.nodebb.isPrimary}}}{{{else}}}{{{end}}} / {{{if info.nodebb.runJobs}}}{{{else}}}{{{end}}} - - - + + diff --git a/src/views/admin/partials/categories/copy-settings.tpl b/src/views/admin/partials/categories/copy-settings.tpl index b17b4264c7..73ebb27f0c 100644 --- a/src/views/admin/partials/categories/copy-settings.tpl +++ b/src/views/admin/partials/categories/copy-settings.tpl @@ -1,7 +1,7 @@
        -
        \ No newline at end of file diff --git a/src/views/admin/partials/categories/create.tpl b/src/views/admin/partials/categories/create.tpl index b4c7e759c8..2158cab43f 100644 --- a/src/views/admin/partials/categories/create.tpl +++ b/src/views/admin/partials/categories/create.tpl @@ -16,14 +16,14 @@
        - +
        - +
        \ No newline at end of file diff --git a/src/views/admin/partials/dashboard/graph.tpl b/src/views/admin/partials/dashboard/graph.tpl index 7292e78baf..91ed736238 100644 --- a/src/views/admin/partials/dashboard/graph.tpl +++ b/src/views/admin/partials/dashboard/graph.tpl @@ -4,8 +4,8 @@ [[admin/dashboard:forum-traffic]]
        - - + +
        diff --git a/src/views/admin/partials/dashboard/stats.tpl b/src/views/admin/partials/dashboard/stats.tpl index b28e0ee9f6..abd4f9cd31 100644 --- a/src/views/admin/partials/dashboard/stats.tpl +++ b/src/views/admin/partials/dashboard/stats.tpl @@ -27,19 +27,19 @@ {{{ end }}} - - + + - - + + - - + + - + {{{ end }}} diff --git a/src/views/admin/partials/groups/memberlist.tpl b/src/views/admin/partials/groups/memberlist.tpl index e2807ac2d2..6881b3667c 100644 --- a/src/views/admin/partials/groups/memberlist.tpl +++ b/src/views/admin/partials/groups/memberlist.tpl @@ -10,8 +10,8 @@ -
        -
        [[admin/development/info:host]] [[admin/development/info:primary]][[admin/development/info:pid]] [[admin/development/info:nodejs]] [[admin/development/info:online]] [[admin/development/info:git]]{info.process.pid} {info.process.version} {info.stats.onlineRegisteredCount} / diff --git a/src/views/admin/development/logger.tpl b/src/views/admin/development/logger.tpl index 4f7eedb610..393f227997 100644 --- a/src/views/admin/development/logger.tpl +++ b/src/views/admin/development/logger.tpl @@ -20,13 +20,13 @@
        - - + +
        - - + +
        diff --git a/src/views/admin/footer.tpl b/src/views/admin/footer.tpl index 73ed1fb492..00c307ba55 100644 --- a/src/views/admin/footer.tpl +++ b/src/views/admin/footer.tpl @@ -5,9 +5,9 @@ {{{ if !isSpider }}}
        -
        - -

        [[global:reconnecting-message, {config.siteTitle}]]

        +
        + +

        [[global:reconnecting-message, {config.siteTitle}]]

        diff --git a/src/views/admin/header.tpl b/src/views/admin/header.tpl index fdc655b44b..e2f7725123 100644 --- a/src/views/admin/header.tpl +++ b/src/views/admin/header.tpl @@ -1,5 +1,5 @@ - + {title} @@ -15,6 +15,10 @@ flags: {}, inAdmin: true }; + const theme = localStorage.getItem('data-bs-theme'); + if (theme && theme === 'dark') { + document.documentElement.setAttribute('data-bs-theme', 'dark'); + } diff --git a/src/views/admin/manage/category-analytics.tpl b/src/views/admin/manage/category-analytics.tpl index 523e79cdfc..18ca7666c0 100644 --- a/src/views/admin/manage/category-analytics.tpl +++ b/src/views/admin/manage/category-analytics.tpl @@ -1,55 +1,61 @@ - - [[admin/manage/categories:analytics.back]] - -
        [[admin/manage/categories:analytics.title, {name}]]
        -
        +
        -
        -
        -
        -
        -
        -

        - -

        -
        - +
        +
        +

        [[admin/manage/categories:analytics.title, {name}]]

        +
        -
        -
        -
        -
        -

        -

        + +
        +
        +
        +
        +
        +
        +

        + +

        +
        + +
        +
        +
        +
        +
        +
        +

        + +

        +
        +
        -
        -
        -
        -
        -
        -
        -
        -

        +

        +
        +
        +
        +
        +

        -

        +

        +
        +
        -
        -
        -
        -
        -
        -
        -

        +

        +
        +
        +
        +

        -

        +

        +
        +
        -
        \ No newline at end of file diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index 4c34df4730..fb2afcedec 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -78,16 +78,16 @@
        - - + +
        {{{ if postQueueEnabled }}}
        - - + +
        {{{ end }}} @@ -99,7 +99,7 @@
        -
        +
        diff --git a/src/views/admin/manage/tags.tpl b/src/views/admin/manage/tags.tpl index edeff453c6..00c4260f41 100644 --- a/src/views/admin/manage/tags.tpl +++ b/src/views/admin/manage/tags.tpl @@ -21,7 +21,7 @@
        -
        +
        [[admin/manage/tags:description]]
        diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl index b87faf0ea9..23127a9876 100644 --- a/src/views/admin/manage/users.tpl +++ b/src/views/admin/manage/users.tpl @@ -45,6 +45,7 @@
      • [[admin/manage/users:password-reset-email]]
      • [[admin/manage/users:force-password-reset]]
      • [[admin/manage/users:manage-groups]]
      • +
      • [[admin/manage/users:set-reputation]]
      • [[admin/manage/users:ban]]
      • [[admin/manage/users:temp-ban]]
      • @@ -151,8 +152,8 @@
        {{{ end }}}
        {users.postcount}{users.reputation}{formattedNumber(users.postcount)}{formattedNumber(users.reputation)} {{{ if users.flags }}}{users.flags}{{{ else }}}0{{{ end }}} {./yesterday}{./today}{formattedNumber(./yesterday)}{formattedNumber(./today)} {./dayIncrease}%{./lastweek}{./thisweek}{formattedNumber(./lastweek)}{formattedNumber(./thisweek)} {./weekIncrease}%{./lastmonth}{./thismonth}{formattedNumber(./lastmonth)}{formattedNumber(./thismonth)} {./monthIncrease}%{./alltime}{formattedNumber(./alltime)}
        +
        +
        {{{ each group.members }}} diff --git a/src/views/admin/partials/navigation.tpl b/src/views/admin/partials/navigation.tpl index c73e8007af..8c89f6a702 100644 --- a/src/views/admin/partials/navigation.tpl +++ b/src/views/admin/partials/navigation.tpl @@ -53,6 +53,8 @@ [[admin/menu:manage/uploads]][[admin/menu:manage/digest]]
        +
        [[pages:moderator-tools]]
        + [[admin/menu:manage/flagged-content]] [[admin/menu:manage/post-queue]] [[admin/menu:manage/ip-blacklist]] {{{ end }}} diff --git a/src/views/admin/partials/offcanvas.tpl b/src/views/admin/partials/offcanvas.tpl index f4651a74e6..20688bd1ab 100644 --- a/src/views/admin/partials/offcanvas.tpl +++ b/src/views/admin/partials/offcanvas.tpl @@ -1,4 +1,4 @@ -
        +
        diff --git a/src/views/admin/partials/privileges/global.tpl b/src/views/admin/partials/privileges/global.tpl index 614b3635a8..37953ba2dc 100644 --- a/src/views/admin/partials/privileges/global.tpl +++ b/src/views/admin/partials/privileges/global.tpl @@ -94,18 +94,15 @@ {{{ each privileges.users }}}
        - + {function.spawnPrivilegeStates, privileges.users.username, ../privileges} diff --git a/src/views/admin/partials/sidebar-left.tpl b/src/views/admin/partials/sidebar-left.tpl index d56029d806..3a336101a6 100644 --- a/src/views/admin/partials/sidebar-left.tpl +++ b/src/views/admin/partials/sidebar-left.tpl @@ -1,4 +1,4 @@ - {{{ each tokens }}} - - + - {{{ end }}} + {{{ if publicRooms.length }}} + + + + {{{ end }}} {{{ if topTopics.length }}}
        - {{{ if ./picture }}} - - {{{ else }}} -
        {../icon:text}
        - {{{ end }}} -
        + {buildAvatar(privileges.users, "24px", true)} {{{ if privileges.users.banned }}} {{{ end }}} {privileges.users.username} + +
        +
        {./token} @@ -76,7 +76,7 @@ + diff --git a/src/views/admin/settings/chat.tpl b/src/views/admin/settings/chat.tpl index 18e073e2ec..62fbd3c199 100644 --- a/src/views/admin/settings/chat.tpl +++ b/src/views/admin/settings/chat.tpl @@ -9,14 +9,14 @@
        - +
        - +

        [[admin/settings/chat:disable-editing-help]]

        @@ -31,6 +31,11 @@ +
        + + +
        +
        diff --git a/src/views/admin/settings/cookies.tpl b/src/views/admin/settings/cookies.tpl index 56d3abb832..e7c5fa6e70 100644 --- a/src/views/admin/settings/cookies.tpl +++ b/src/views/admin/settings/cookies.tpl @@ -8,7 +8,7 @@
        - +
        diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index bf3d79ded3..7092fab2be 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -181,8 +181,8 @@
        - - + +
        diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index 26fcf37a27..2d3f960007 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -6,15 +6,15 @@
        [[admin/settings/group:general]]
        - - + +

        [[admin/settings/group:private-groups.help]]

        [[admin/settings/group:private-groups.warning]]

        - - + +

        [[admin/settings/group:allow-multiple-badges-help]]

        diff --git a/src/views/admin/settings/navigation.tpl b/src/views/admin/settings/navigation.tpl index 2d071be170..431b052361 100644 --- a/src/views/admin/settings/navigation.tpl +++ b/src/views/admin/settings/navigation.tpl @@ -14,7 +14,7 @@
        - - + +
        @@ -218,8 +218,8 @@
        - - + +

        [[admin/settings/guest:handles.enabled-help]] @@ -227,14 +227,14 @@

        - - + +
        - - + +
        @@ -244,33 +244,33 @@
        [[admin/settings/user:default-user-settings]]
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        @@ -285,13 +285,13 @@
        - - + +
        - - + +
        diff --git a/src/views/admin/settings/web-crawler.tpl b/src/views/admin/settings/web-crawler.tpl index 8cdcd67702..ebb51d728d 100644 --- a/src/views/admin/settings/web-crawler.tpl +++ b/src/views/admin/settings/web-crawler.tpl @@ -16,13 +16,13 @@
        [[admin/settings/web-crawler:sitemap-feed-settings]]
        - - + +
        - - + +
        diff --git a/src/views/emails/digest.tpl b/src/views/emails/digest.tpl index b6d827187c..cd278d6c6f 100644 --- a/src/views/emails/digest.tpl +++ b/src/views/emails/digest.tpl @@ -43,6 +43,26 @@
        +

        [[email:digest.unread-rooms]]

        + +
        diff --git a/src/views/modals/create-room.tpl b/src/views/modals/create-room.tpl new file mode 100644 index 0000000000..a4b47c85a0 --- /dev/null +++ b/src/views/modals/create-room.tpl @@ -0,0 +1,46 @@ +
        +
        + + +
        + +
        + + +
        + + {{{ if user.isAdmin }}} + + + + {{{ end }}} +
        \ No newline at end of file diff --git a/src/views/modals/manage-room.tpl b/src/views/modals/manage-room.tpl index de9ac4f331..0469897464 100644 --- a/src/views/modals/manage-room.tpl +++ b/src/views/modals/manage-room.tpl @@ -1,11 +1,40 @@ -
        - +
        + +

        [[modules:chat.add-user-help]]


        -
          + + +
          • [[modules:chat.retrieving-users]]
          + + {{{ if user.isAdmin }}} +
          +
          + + +
          + + {{{ if room.public }}} + + + + + {{{ end }}} +
          + +
          + {{{ end }}}
        \ No newline at end of file diff --git a/src/views/modals/temporary-ban.tpl b/src/views/modals/temporary-ban.tpl index 19b1047fed..d84bc28331 100644 --- a/src/views/modals/temporary-ban.tpl +++ b/src/views/modals/temporary-ban.tpl @@ -15,12 +15,12 @@
        - - + +
        - - + +
        diff --git a/src/views/modals/temporary-mute.tpl b/src/views/modals/temporary-mute.tpl index 87fab1890e..0025a909ee 100644 --- a/src/views/modals/temporary-mute.tpl +++ b/src/views/modals/temporary-mute.tpl @@ -6,12 +6,12 @@
        - - + +
        - - + +
        diff --git a/src/views/partials/chats/manage-room-users.tpl b/src/views/partials/chats/manage-room-users.tpl index f8808587bd..8489cbb15b 100644 --- a/src/views/partials/chats/manage-room-users.tpl +++ b/src/views/partials/chats/manage-room-users.tpl @@ -1,7 +1,17 @@ {{{ each users }}} -
      • - {{{ if ./canKick }}}{{{ end }}} - {buildAvatar(users, "24px", true)} - {../username} {{{ if ./isOwner }}}{{{ end }}} +
      • +
        + {buildAvatar(users, "24px", true)} + {./username} +
        +
        + {{{ if ./canToggleOwner }}} + + {{{ end }}} + + {{{ if ./canKick }}} + + {{{ end }}} +
      • {{{ end }}} \ No newline at end of file diff --git a/src/views/partials/gdpr_consent.tpl b/src/views/partials/gdpr_consent.tpl index be376b554d..f127f00260 100644 --- a/src/views/partials/gdpr_consent.tpl +++ b/src/views/partials/gdpr_consent.tpl @@ -17,6 +17,6 @@
        - +
        \ No newline at end of file diff --git a/src/views/partials/reconnect-alert.tpl b/src/views/partials/reconnect-alert.tpl new file mode 100644 index 0000000000..90ab679fde --- /dev/null +++ b/src/views/partials/reconnect-alert.tpl @@ -0,0 +1,4 @@ +
        + +

        [[global:reconnecting-message, {config.siteTitle}]]

        +
        \ No newline at end of file diff --git a/src/views/reset_code.tpl b/src/views/reset_code.tpl index 2365d7614c..ab3e58fc90 100644 --- a/src/views/reset_code.tpl +++ b/src/views/reset_code.tpl @@ -1,42 +1,42 @@ -{{{ if valid }}} -
        - {{{ if displayExpiryNotice }}} -
        - [[reset_password:password_expired]] +
        + {{{ if valid }}} +
        + {{{ if displayExpiryNotice }}} +
        + [[reset_password:password_expired]] +
        + {{{ end }}} + + +
        +
        + +
        +
        +
        + +
        +
        + +
        +
        + {{{ else }}} +
        +
        + [[reset_password:wrong_reset_code.title]] +
        +
        +

        [[reset_password:wrong_reset_code.message]]

        +
        {{{ end }}} - - -
        -
        - -
        -
        -
        - -
        -
        -
        - -
        -
        -
        -{{{ else }}} -
        -
        - [[reset_password:wrong_reset_code.title]] -
        -
        -

        [[reset_password:wrong_reset_code.message]]

        -
        -
        -{{{ end }}} \ No newline at end of file +
        \ No newline at end of file diff --git a/test/api.js b/test/api.js index 6eddd17f52..6723cd3f5e 100644 --- a/test/api.js +++ b/test/api.js @@ -281,7 +281,7 @@ describe('API', async () => { await flags.create('post', 2, unprivUid, 'sample reasons', Date.now()); // for testing flag notes (since flag 1 deleted) // Create a new chat room - await messaging.newRoom(1, [2]); + await messaging.newRoom(1, { uids: [2] }); // Create an empty file to test DELETE /files and thumb deletion fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.txt'), 'w')); diff --git a/test/blacklist.js b/test/blacklist.js index f682ccd16c..068882b8c8 100644 --- a/test/blacklist.js +++ b/test/blacklist.js @@ -59,10 +59,24 @@ describe('blacklist', () => { }); }); + it('should fail ip test against blacklist with port', (done) => { + blacklist.test('1.1.1.1:4567', (err) => { + assert.equal(err.message, '[[error:blacklisted-ip]]'); + done(); + }); + }); + it('should pass ip test and not crash with ipv6 address', (done) => { blacklist.test('2001:db8:85a3:0:0:8a2e:370:7334', (err) => { assert.ifError(err); done(); }); }); + + it('should fail ip test due to cidr', (done) => { + blacklist.test('192.168.100.1', (err) => { + assert.equal(err.message, '[[error:blacklisted-ip]]'); + done(); + }); + }); }); diff --git a/test/database/sorted.js b/test/database/sorted.js index e77314689b..36d4534a91 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -64,6 +64,7 @@ describe('Sorted Set methods', () => { match: '*b{', limit: 2, }); + assert.strictEqual(data.length, 2); assert(data.includes('aaab{')); assert(data.includes('bbcb{')); }); @@ -73,8 +74,8 @@ describe('Sorted Set methods', () => { const data = await db.getSortedSetScan({ key: 'scanzset4', match: 'b*', - limit: 2, }); + assert.strictEqual(data.length, 2); assert(data.includes('bbbb')); assert(data.includes('bbcb')); }); @@ -85,7 +86,7 @@ describe('Sorted Set methods', () => { key: 'scanzset5', match: '*db', }); - assert.equal(data.length, 2); + assert.strictEqual(data.length, 2); assert(data.includes('ddb')); assert(data.includes('adb')); }); diff --git a/test/flags.js b/test/flags.js index 50f9c5543c..2912346519 100644 --- a/test/flags.js +++ b/test/flags.js @@ -514,40 +514,40 @@ describe('Flags', () => { it('should rescind notification if flag is resolved', async () => { let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'resolved', }); userNotifs = await User.notifications.getAll(adminUid); - assert(!userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(!userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); }); it('should rescind notification if flag is rejected', async () => { let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'rejected', }); userNotifs = await User.notifications.getAll(adminUid); - assert(!userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(!userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); }); it('should do nothing if flag is resolved but ACP action is not "rescind"', async () => { Meta.config['flags:actionOnResolve'] = ''; let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'resolved', }); userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); delete Meta.config['flags:actionOnResolve']; }); @@ -556,14 +556,14 @@ describe('Flags', () => { Meta.config['flags:actionOnReject'] = ''; let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'rejected', }); userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); delete Meta.config['flags:actionOnReject']; }); diff --git a/test/messaging.js b/test/messaging.js index 45ed034bc3..1501f28e17 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -154,7 +154,7 @@ describe('Messaging Library', () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'foo'); const { messages } = body.response; assert.equal(messages.length, 2); - assert.strictEqual(messages[0].system, true); + assert.strictEqual(messages[0].system, 1); assert.strictEqual(messages[0].content, 'user-join'); const { statusCode, body: body2 } = await callv3API('put', `/chats/${roomId}/messages/${messages[0].messageId}`, { @@ -226,15 +226,14 @@ describe('Messaging Library', () => { await callv3API('delete', `/chats/${roomId}/users/${mocks.users.baz.uid}`, {}, 'baz'); const isUserInRoom = await Messaging.isUserInRoom(mocks.users.baz.uid, roomId); assert.equal(isUserInRoom, false); - const data = await Messaging.getRoomData(roomId); - assert.equal(data.owner, mocks.users.foo.uid); + assert(await Messaging.isRoomOwner(mocks.users.foo.uid, roomId)); }); it('should send a user-leave system message when a user leaves the chat room', async () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'foo'); const { messages } = body.response; const message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-leave'); }); @@ -245,12 +244,12 @@ describe('Messaging Library', () => { assert.equal(messages.length, 4); let message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-leave'); // The message before should still be a user-join message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-join'); }); @@ -263,8 +262,7 @@ describe('Messaging Library', () => { await callv3API('delete', `/chats/${body.response.roomId}/users/${mocks.users.herp.uid}`, {}, 'herp'); - const data = await Messaging.getRoomData(body.response.roomId); - assert.equal(data.owner, mocks.users.foo.uid); + assert(await Messaging.isRoomOwner(mocks.users.foo.uid, roomId)); }); it('should change owner if owner is deleted', async () => { @@ -284,8 +282,7 @@ describe('Messaging Library', () => { }, }); await User.deleteAccount(sender); - const data = await Messaging.getRoomData(response.roomId); - assert.equal(data.owner, receiver); + assert(await Messaging.isRoomOwner(receiver, response.roomId)); }); it('should fail to remove user from room', async () => { @@ -345,7 +342,7 @@ describe('Messaging Library', () => { assert(messageData.fromUser); assert(messageData.roomId, roomId); const raw = - await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: messageData.mid }); + await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: messageData.messageId }); assert.equal(raw, 'first chat message'); }); @@ -378,7 +375,7 @@ describe('Messaging Library', () => { assert(myRoomId); try { - await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.baz.uid }, { mid: 200 }); + await socketModules.chats.getRaw({ uid: mocks.users.baz.uid }, { mid: 200 }); } catch (err) { assert(err); assert.equal(err.message, '[[error:not-allowed]]'); @@ -386,7 +383,7 @@ describe('Messaging Library', () => { ({ body } = await callv3API('post', `/chats/${myRoomId}`, { roomId: myRoomId, message: 'admin will see this' }, 'baz')); const message = body.response; - const raw = await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: message.mid }); + const raw = await socketModules.chats.getRaw({ uid: mocks.users.foo.uid }, { mid: message.messageId }); assert.equal(raw, 'admin will see this'); }); @@ -407,7 +404,7 @@ describe('Messaging Library', () => { assert(data.unread[0]); const notification = data.unread[0]; assert.strictEqual(notification.bodyShort, 'New message from foo'); - assert.strictEqual(notification.nid, `chat_${mocks.users.foo.uid}_${roomId}`); + assert.strictEqual(notification.nid, `chat_${roomId}_${mocks.users.foo.uid}`); assert.strictEqual(notification.path, `${nconf.get('relative_path')}/chats/${roomId}`); }); @@ -455,11 +452,8 @@ describe('Messaging Library', () => { }); it('should fail to rename room with invalid data', async () => { - let { body } = await callv3API('put', `/chats/${roomId}`, { name: null }, 'foo'); + const { body } = await callv3API('put', `/chats/${roomId}`, { name: null }, 'foo'); assert.strictEqual(body.status.message, await translator.translate('[[error:invalid-data]]')); - - ({ body } = await callv3API('put', `/chats/${roomId}`, {}, 'foo')); - assert.strictEqual(body.status.message, await translator.translate('[[error:required-parameters-missing, name]]')); }); it('should rename room', async () => { @@ -472,7 +466,7 @@ describe('Messaging Library', () => { const { messages } = body.response; const message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'room-rename, new room name'); }); @@ -563,9 +557,9 @@ describe('Messaging Library', () => { before(async () => { await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.baz.uid] }, 'foo'); let { body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'first chat message' }, 'foo'); - mid = body.response.mid; + mid = body.response.messageId; ({ body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message' }, 'baz')); - mid2 = body.response.mid; + mid2 = body.response.messageId; }); after(async () => { @@ -639,8 +633,7 @@ describe('Messaging Library', () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'herp'); const { messages } = body.response; messages.forEach((msg) => { - assert(!msg.deleted || msg.content === '[[modules:chat.message-deleted]]', msg.content); - assert(!msg.deleted || msg.cleanedContent, '[[modules:chat.message-deleted]]', msg.content); + assert(!msg.deleted || msg.content === '

        [[modules:chat.message-deleted]]

        ', msg.content); }); }); diff --git a/test/posts.js b/test/posts.js index 866fc3b529..8b3cc947e2 100644 --- a/test/posts.js +++ b/test/posts.js @@ -114,7 +114,7 @@ describe('Post\'s', () => { await posts.changeOwner([pid1, pid2], newUid); - assert.deepStrictEqual(await db.sortedSetScores(`tid:${postResult.topicData.tid}:posters`, [oldUid, newUid]), [0, 2]); + assert.deepStrictEqual(await db.sortedSetScores(`tid:${postResult.topicData.tid}:posters`, [oldUid, newUid]), [null, 2]); assert.deepStrictEqual(await posts.isOwner([pid1, pid2], oldUid), [false, false]); assert.deepStrictEqual(await posts.isOwner([pid1, pid2], newUid), [true, true]); @@ -130,6 +130,8 @@ describe('Post\'s', () => { assert.strictEqual(await topics.isOwner(postResult.topicData.tid, oldUid), false); assert.strictEqual(await topics.isOwner(postResult.topicData.tid, newUid), true); + + assert.strictEqual(await topics.getTopicField(postResult.topicData.tid, 'postercount'), 1); }); it('should fail to change owner if new owner does not exist', async () => { @@ -214,6 +216,14 @@ describe('Post\'s', () => { }); }); + it('should fail to get upvoters if user does not have read privilege', async () => { + await privileges.categories.rescind(['groups:topics:read'], cid, 'guests'); + await assert.rejects(socketPosts.getUpvoters({ uid: 0 }, [postData.pid]), { + message: '[[error:no-privileges]]', + }); + await privileges.categories.give(['groups:topics:read'], cid, 'guests'); + }); + it('should unvote a post', async () => { const result = await apiPosts.unvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }); assert.equal(result.post.upvotes, 0); diff --git a/test/socket.io.js b/test/socket.io.js index b7fcaff935..54568b47e0 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -371,7 +371,7 @@ describe('socket.io', () => { assert(data.hasOwnProperty('onlineGuestCount')); assert(data.hasOwnProperty('onlineRegisteredCount')); assert(data.hasOwnProperty('socketCount')); - assert(data.hasOwnProperty('topics')); + assert(data.hasOwnProperty('topTenTopics')); assert(data.hasOwnProperty('users')); done(); }); diff --git a/test/topics.js b/test/topics.js index 0febc38699..07af567b25 100644 --- a/test/topics.js +++ b/test/topics.js @@ -106,14 +106,14 @@ describe('Topic\'s', () => { }); it('should fail to create new topic with empty title', (done) => { - topics.post({ uid: topic.userId, title: '', content: topic.content, cid: topic.categoryId }, (err) => { + topics.post({ uid: fooUid, title: '', content: topic.content, cid: topic.categoryId }, (err) => { assert.ok(err); done(); }); }); it('should fail to create new topic with empty content', (done) => { - topics.post({ uid: topic.userId, title: topic.title, content: '', cid: topic.categoryId }, (err) => { + topics.post({ uid: fooUid, title: topic.title, content: '', cid: topic.categoryId }, (err) => { assert.ok(err); done(); }); @@ -304,7 +304,7 @@ describe('Topic\'s', () => { }); it('should fail to create new reply with empty content', (done) => { - topics.reply({ uid: topic.userId, content: '', tid: newTopic.tid }, (err) => { + topics.reply({ uid: fooUid, content: '', tid: newTopic.tid }, (err) => { assert.strictEqual(err.message, '[[error:content-too-short, 8]]'); done(); }); diff --git a/test/user.js b/test/user.js index 066f6f13ae..660d35b805 100644 --- a/test/user.js +++ b/test/user.js @@ -574,7 +574,7 @@ describe('User', () => { const socketModules = require('../src/socket.io/modules'); const uid1 = await User.create({ username: 'chatuserdelete1' }); const uid2 = await User.create({ username: 'chatuserdelete2' }); - const roomId = await messaging.newRoom(uid1, [uid2]); + const roomId = await messaging.newRoom(uid1, { uids: [uid2] }); await messaging.addMessage({ uid: uid1, content: 'hello', diff --git a/test/utils.js b/test/utils.js index b0a6afcfb9..b47ff80224 100644 --- a/test/utils.js +++ b/test/utils.js @@ -238,7 +238,7 @@ describe('Utility Methods', () => { }); it('should make number human readable', (done) => { - assert.equal(utils.makeNumberHumanReadable(null), null); + assert.equal(utils.makeNumberHumanReadable(null), 'null'); done(); });