diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1410efb7c5..ca5ca430ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,612 @@
+#### v1.17.0 (2021-04-22)
+
+##### Breaking Changes
+
+* add additional flag hooks [breaking] (00a68a95)
+* remove deprecated `User.emailConfirm` [breaking] (fb84c785)
+* remove deprecated plugin hook `filter:privileges:isUserAllowedTo` [breaking] (5a775e09)
+* remove deprecated plugin hook methods [breaking] (d41de481)
+* more removals of thumb specific backwards-compatibility [breaking] (cc0d562e)
+* remove deprecated `filter:admin/header.build` hook [breaking] (5f9f241e)
+* remove deprecated v2 style responses for thumbs upload route [breaking] (84dfdfe6)
+* remove deprecated getObject routes [breaking] (2ad0d0d0)
+* remove 'filters' and 'categories' from flag details API return [breaking] (8b72479f)
+* filtering logic of flags [breaking] (1603566b)
+* feature flag for auto-resolving a user's flags on ban [breaking] (6b1c97db)
+* allow interstitial callbacks to be async functions [breaking] (280285cd)
+
+##### Chores
+
+* **deps:**
+ * update dependency jsdom to v16.5.3 (0f249aa7)
+ * update dependency eslint to v7.24.0 (60c0c16f)
+ * update dependency husky to v6 (f155f326)
+ * update commitlint monorepo to v12.1.1 (b4d01388)
+ * update dependency jsdom to v16.5.2 (5e2e7a58)
+ * update dependency eslint to v7.23.0 (d600cd94)
+ * update dependency husky to v5.2.0 (77f551a4)
+ * update dependency jsdom to v16.5.1 (28ed579b)
+ * update dependency eslint to v7.22.0 (775c3b91)
+ * update dependency mocha to v8.3.2 (3ce731d8)
+ * update dependency jsdom to v16.5.0 (fd926d61)
+ * update dependency mocha to v8.3.1 (651c629f)
+ * update dependency husky to v5.1.3 (8791b44e)
+ * update dependency husky to v5.1.2 (5f061b94)
+ * update commitlint monorepo to v12 (42f7cd52)
+ * update dependency eslint to v7.21.0 (59518437)
+ * update dependency husky to v5.1.1 (2551295c)
+ * update dependency husky to v5.1.0 (dc06fe22)
+ * update dependency eslint to v7.20.0 (9ec0b2ed)
+ * update dependency mocha to v8.3.0 (73f07958)
+ * update dependency husky to v5 (d89ccf26)
+ * update dependency lint-staged to v10.5.4 (030ecffa)
+ * update dependency eslint to v7.19.0 (3696a199)
+* incrementing version number - v1.17.0-beta.5 (42c4f963)
+* fix indent (6406e527)
+* benchpress 2.4.1 (3403635c)
+* remove log (a1ee1a2a)
+* incrementing version number - v1.17.0-beta.4 (91992240)
+* bump composer-default (289bfc0b)
+* up themes (d14ba1f4)
+* remove node 10 (8d3ec234)
+* bump composer-default to 6.5.20 (33fbfdfe)
+* incrementing version number - v1.17.0-beta.3 (6e8b1bb9)
+* add multiparty dep (ef3ec96a)
+* incrementing version number - v1.17.0-beta.2 (0c1945dc)
+* incrementing version number - v1.17.0-beta.1 (31872aac)
+* bump composer (30954789)
+* bump deps (#9335) (b9fd2c87)
+* incrementing version number - v1.17.0-beta.0 (b61257ef)
+* incrementing version number - v1.16.3-beta.0 (477157cc)
+* extra console.log (1ae8dda8)
+* up composer (1c9acef6)
+* eslint max-len (cc9d6fd0)
+* eslint no-restricted-syntax (5c2f0f05)
+* eslint prefer-rest-params, prefer-spread (115d19e2)
+* eslint prefer-destructuring (23f212a4)
+* eslint object-curly-newline (8d1462ff)
+* eslint function-paren-newline (62869bae)
+* eslint no-var, vars-on-top (dab3b235)
+* eslint prefer-arrow-callback (b56d9e12)
+* eslint prefer-template (707b55b6)
+* eslint import/newline-after-import (4ee0f145)
+* eslint no-script-url (9f6a682c)
+* eslint no-bitwise (dad01e30)
+* eslint rules matching existing styles (58528d1a)
+* fallbacks (74be1a59)
+* deprecation notices for plugins using plugin old hook methods (3052256d)
+* add deprecation notice in comments for ajaxify.loadExtraScripts (8b09292e)
+* incrementing version number - v1.16.2 (ea7f8381)
+* update changelog for v1.16.2 (d3883d4b)
+
+##### Documentation Changes
+
+* fixed typo (e7550673)
+* added comment re: #9305 (65c57c73)
+* update deprecation-removal version for plugin hook helper methods in 1.18.0 (15ba0abb)
+
+##### New Features
+
+* lang strings (9b71b087)
+* rate limit file uploads (a9978fcf)
+* filter flags by username #8489 (#9451) (8faa6e45)
+* roll session identifier on login, as security best practice (697ed3bf)
+* allow different slugs (4494728c)
+* remove sort again (fd3bc605)
+* update hook (f65d2162)
+* add reverse of recent to getSortedTopics (05f22361)
+* allow exists methods to work with arrays and single id (285aa365)
+* pass all data to filter:category.get (d16b45fd)
+* add action:posts.loaded (dbb59228)
+* rescheduling (editing ST) (#9445) (aa0137b1)
+* upgrade sharp (#9442) (f7f46e7c)
+* optional urlMethod param for loginStrategies (9e1f72a4)
+* add hooks to language loading (#9426) (344575dd)
+* doggy.gif (b06f0ea2)
+* allow adding sorted-list items from forms outside of modal (a3e95e79)
+* scheduled topics (#9399) (077330b7)
+* show link if category is a link (a94d9651)
+* make info page full width (dd12c83f)
+* allow optional fields argument on db.getObject(s) (#9385) (4327a09d)
+* closes #9380, add category filtering and topic tools to tag page (668508cc)
+* allow sync function (#9379) (34b9aaed)
+* allow filter functions that return promises or the data directly (e6c52cf2)
+* add resolve flag to post tools (52082e12)
+* hide revert button in ACP > Privileges until privileges change (4cbd13fd)
+* bring back static hook timeout (46270f9f)
+* upgrade connect-mongo, closes https://github.com/NodeBB/NodeBB/pull/9367 (3c60ccfd)
+* pass interstital errors to individual partials as well as to registerComplete (f71cb0e4)
+* add filter:plugins.firehook (5eb3132d)
+* copy default favicon if it doesn't exist (754283d3)
+* add missing translation keys (17184bfa)
+* allow missing (or non-array) middlewares argument in route helper methods (4b545085)
+* pass modified params, only affects filter hooks (e74df539)
+* add back topic id input (696c4895)
+* expose username validation logic to user lib, new hook `filter:username.check` (bfd512b9)
+* add $.deserialize to client side (e5133a78)
+* allow for settings.save/settings.load on client side (66196d2c)
+* remove promise-pollyfil (902a88c2)
+* category privilege API routes (c1b3079d)
+* change uploadCroppedPicture to use updateProfile as well (0af9d26f)
+* use updateProfile for picture change (a598abcd)
+* allow payload to be passed to emailer test method (1155b0c4)
+* add uid of user who created flag to action:flags.create (069ac60f)
+* new client-side hook `filter:api.options` to allow plugins to modify api requests (7d391d47)
+* keep notifs for one month, load 50 notifications instead of 30 (02f08111)
+* also pass in uid to `filter:email.prepare` (86b0c57d)
+* new hook `filter:email.prepare` (27ea3dcb)
+* new hook static:email.send (bf90d158)
+* show time info for upgrade scripts (14a6c349)
+* add dashboard sub-pages to ACP menu (73dc64d9)
+* recent logins sessions table in dashbaord subpage (2f89b0d7)
+* topics dashboard details subpage (e1ed514b)
+* update user list in dashboard/users on graph update (c57c7703)
+* show list of recent users in dashboard/users (cc938224)
+* req.query parsing and dynamically loading data instead (6fdcae73)
+* new hooks for notifications get/getCount (079a13d4)
+* allow hook unregistration, and temporary page-based hooks (d0136074)
+* report login statistics from analytics data, instead of its own zset (16d3c457)
+* track login sessions for admin dashboard reporting (9a9f366d)
+* track successful logins in analytics (504fd107)
+* pass user picture object into change_picture_modal (c96fd3b1)
+* add logout to invalid session (beb14273)
+* category search test (a592ebd1)
+* pass post object to filter:post.tools (ed3d9dcb)
+* allow defining a list of system tags (0e07f3c9)
+* add category search test, #9307 (bbaaead0)
+* add tag filter to getSortedTopics (9ce6f8ad)
+* ability to re-order topic thumbnails (7223074f)
+* add close button to topic thumbnail modal (db027170)
+* #9304, add category/topic/username to post queue notification emails (0738dae8)
+* add failing test for list append/prepend with list (#9303) (8f0386d9)
+* link to post-queue from topic event (a4b4a556)
+* post-queue topic event (8fd78ce5)
+* add post-queue cache (3f35fd33)
+* newsletter opt-in/out in UCP, closes #21 (3c7cd9a6)
+* load user posts/topics via xhr on infinitescroll (35954734)
+* #9294, put new categories at top (4b2bf12f)
+* add invalid event name to error message (670cde78)
+* new notifications load/loaded hooks on client side (7edc8f45)
+* pass req.session into buildReqObject (a6fa351b)
+* new hook `action:login.continue` (4f976390)
+* banned-users group (53e0d4d2)
+* #9109, ability to delete a post's diffs (eb642f40)
+* add .delete() method to api module (501441b7)
+* doc add description (cc560ca3)
+* add doc for query param (ed11e171)
+* #9234, add pagination to /api/recent/posts/:term? (fffdc4e0)
+* allow sorted-lists on multiple pages (d5d24594)
+* #9232, add profile picture into exported zip (f6cd2862)
+* new hook `filter:login.override`, deprecate `action:auth.overrideLogin` (b820d234)
+* guard password fields in login/register against accidental caps lock (4bb3b032)
+* ability to search categories, #8813 (34c42c6f)
+* restore action:script.load, allow modifying loaded module via static:script.init (05be1c66)
+* async/await redis connection (fdfbc902)
+* async/await psql connection (33bf1b0e)
+* add group name to csv event (672959c1)
+* **user:** icon background selector in change picture modal (95502124)
+* **remountable-routes:**
+ * allow category and account routes to be remounted (9021f071)
+ * allow /admin and /post to be remountable (f01af62b)
+* **topic-events:**
+ * topic events GET route in write API (dc84559d)
+ * server-side tests for topic events (449c379d)
+ * clear out topic events when a topic is purged (0d4a3775)
+ * client-side handling on topic event log (8e93bf73)
+ * handle newest_to_oldest sort in topic events, WIP (882e6a15)
+ * generic css for timeline-event (2293a07a)
+ * support for uids in topic event payloads (611d1f87)
+ * work in progress topic events logic and client-side implementation (ab2e1ecb)
+* **hooks:**
+ * update action:ajaxify.end to use new hooks module (1d775721)
+ * client-side hooks module (01c9b184)
+
+##### Bug Fixes
+
+* regress. rescheduling shouldn't add to sets that pinning removed… (#9477) (8b79c7f1)
+* logic is hard (4dd38446)
+* run in series (bc0ca61c)
+* wrong variable for cache (2e9efc0e)
+* accidentally committed this (13fa983e)
+* tests (eb240c90)
+* eslint (fa0c92a7)
+* use req.ip instead, since guests can upload as well (ea22cd30)
+* #9492, keep query params on redirect (36f119a9)
+* stripTags for editing sorted list items as well (93598982)
+* #9487, session data gathered during a session is lost upon login (1fee6a70)
+* failure on session reroll 🍣 test (f4c5050a)
+* registration interstitials not handling promise rejections properly (e845c34b)
+* stripHTMLTags for sorted list entries (75073c0e)
+* restore original behavior for up/downvoting when logged out (e50408b4)
+* let recent replies respect oldest/newest sort settings (60eed8d8)
+* #9483, fix events count display (6907837f)
+* escape flag reason (161081e9)
+* copy change on plugin activate to instruct admins to rebuild as well as restart (95d5359c)
+* updateCategoryTagsCount (2dc3283f)
+* #9473 (#9476) (036f935f)
+* #9474, load hooks on page load (1af34b43)
+* spec (d09cdc04)
+* #9466, don't call leaveRoom in maintenance mode (f32ea173)
+* exempt ST from being del/res via last main posts (#9468) (a0dd9080)
+* #9462, on install copy default favicon (784600d9)
+* #9463 (c5ae8a70)
+* #9465 (4041e786)
+* #9450 express session saved even if saveUninitialized explicitly passed in (9c52fd2e)
+* acp crash (cb53a64c)
+* #9447, include query params in previousUrl (536591f8)
+* thumb count not updated when uploading multiple thumbs at a time (1ad1787e)
+* change email button stays disabled if user submitted an invalid email (01f63e5d)
+* use app.logout() to clear session after deleting user (cfdef77b)
+* ./nodebb help with commander@7 (#9434) (2a03012e)
+* hide titleRaw for deleted topics as well (edf80cfb)
+* #9410, fix post queue (c5dda64f)
+* privilege tables (9052db93)
+* #9420, paginate after loading notifications (67b09cba)
+* hooks for alert animate, no more fadein/fadeout for reconnect alert (d9e20290)
+* #9414, use posts:view_deleted (e42b152f)
+* preserve order when changing parent (2ceda70a)
+* #9411 (3c4e93a3)
+* #9412 (cef58d1d)
+* #9406, update flag post tools (93c595d9)
+* typo in switch..case (d8ff9851)
+* #9404, show signatures if the target user has signature privilege (801570e4)
+* selector (ee69c1f8)
+* sorting when filtering by uid (75553b24)
+* allow local (and overridden) login strategies to pass Error objects back (98b72ca5)
+* category search not using uid (6aa60b63)
+* inf scroll with subfolder install (262e059f)
+* flicker on dashboard (2041b808)
+* #9398, crash on post flag (90d64fe1)
+* #9395, pass all data from client to Topics.reply (#9396) (a8f7b244)
+* lint (4ac38ab2)
+* #9394, fix guest handles (eb360351)
+* #9387, don't try to load undefined images (03e30634)
+* #9389, allow admins to add themselves to private groups (5c59354c)
+* #9386, add missing translation string (482641e3)
+* #9383, don't show deleted topic titles in inf scroll (e789fe8d)
+* #9378, crash on verifyToken if API Token settings not saved (null case error) (cc489708)
+* closes #9382, fix digest topic links (35700d16)
+* spec (1e1127bd)
+* regression from filter hook change (53f67ff3)
+* crash if unreadTopics is undefined (617f4730)
+* dont crash if login el doesnt exist (f45c0aab)
+* regression via c1b3079d93fb4c49ba62a4be5279b7bff8e5a54d (2a939aad)
+* change notification updateCount to use client-side hooks (84725130)
+* tests (39b0e0fb)
+* #9370, show correct teaser index if sorting is newest to oldest (9382fc6d)
+* don't copy if src doesn't exist (ebccc794)
+* #9362 best not to check file exists on every page load; copying favicon to uploads/system folder instead (771a8955)
+* #9362 (ad565495)
+* regression where login redirect for admin routes didn't go to local=1 (678e8f0f)
+* lint (f4f61b92)
+* if no in passed use "titles" to match header search (e787e6ea)
+* add back middleware.authenticateOrGuest (166d65a1)
+* request authentication called twice in account routes (e3b2c00d)
+* #9354, don't close quicksearch results if mouse is down on them (8a4c361e)
+* #9339, only log email errors once per digest, notification push (3aa26c4d)
+* winston.info (3f42d40c)
+* #9351 bad logic when inserting rows to privilege tables, also a missing tfoot :foot: (c5e25788)
+* app.parseAndTranslate to always return promise (c2650169)
+* bug where fallback window trigger was not firing if there were no hook listeners attached (1e579428)
+* bad assignment (c8b78654)
+* #9348 incorrect redirect via connect-ensure-login (fbe9215b)
+* bug where loginSeconds setting was ignored for local login (f806befd)
+* remove old dep (b58bacaf)
+* notif pruning (2737f653)
+* notification prune test (ca817631)
+* user icon text overflow in some cases (2b7d0b5a)
+* use components for toggleNavbar instead (114e3a1e)
+* allow interstitial callbacks to be functional (no cb required) (9bf94ad5)
+* don't publish before pubClient is connected (cdf5d18f)
+* remove unused async (48f1e265)
+* in setupPageRoute helper, buildHeader after plugin hooks have fired (984c9dd9)
+* timeago missing on table update (655e2c67)
+* wrong qs param, allow string to be passed to util.getDaysArray (f8e1a74c)
+* wrong call to sortedSetAdd (dbe5f702)
+* session not persisting to database in some scenarios (020f0b83)
+* allow hidden inputs in user settings page (beaac0a1)
+* use root context if buildAvatar context is undefined (b4c0b32b)
+* use bootbox module (fa91525a)
+* #9307, use _.flatten (25c8f026)
+* awaiting res.render in send404 controller > > A plugin wanted to use `response:rotuer.page` to 404 a specific page on some condition. res.render returns early in send404 and so must be awaited otherwise multiple responses will be sent (2fef4627)
+* do not overwrite `config.port` from URL, if it's already set (34096b73)
+* switch back to getSortedSetRange (8686fbfa)
+* settings v3 (91734a64)
+* another topic thumb test fix (782bef5e)
+* thumbs.associate logic fix + tests (7ebb6d30)
+* missing awaits, possible test fix (7665adf7)
+* #9301, dont call sitemapstream if there are no entries in categories/pages/topics.xml (9a6cf3d9)
+* properly incase its the same path (807b0d43)
+* numThumbs count on associate (76bcc0c9)
+* missing cache deletion calls for post-queue cache (1490b32d)
+* use of removed URL to get post data (36e8d251)
+* init topic events from webserver.js (b81508c4)
+* check null topics (b753c69c)
+* guard against null topics (58cd797e)
+* tests, new categories go to top now (fc90f32e)
+* #9292, messageobj.content already parsed (c953b1b3)
+* clear category cache on copy parent (765db86d)
+* delete category cache key on category create (ed3e9ce2)
+* typo (c61cc37b)
+* wait for event.log to finish before killing process (a5fa212f)
+* tests, only generate csrf_token on 404 gets (b6493f89)
+* #9287, generate csrf_token on 404 (94f72d60)
+* do not blindly escape a notification's bodyLong (783786cf)
+* pass jquery object in to action:notifications.loaded hook (16610b2d)
+* #9275, (0cca6893)
+* don't use global bootbox obj (cfa0d423)
+* remove console.log (550cd995)
+* move service worker back to relative_path/service-worker.js (fca17cb7)
+* spec (ab0ef442)
+* markread selector (a4878a5b)
+* position when scrolling up (3090a2ae)
+* cache key collision (e40af441)
+* tests breakage due to 67e3fb64981fe2310b17515e1f18c32021a5e983 (5c21c33e)
+* register returnTo logic to match login route (67e3fb64)
+* tests (492cbc62)
+* posts.uploads.sync dissociates uploaded thumbs of the main pid (f79aeef8)
+* update grammar on unban text (68da1c55)
+* privileges page - tweak icon position and width, group name wrapping (c729adeb)
+* autofocus on search field in ACP > Manage > Plugins (4af9c2fc)
+* openapi test specs (cabec378)
+* include admins (7c9674de)
+* include admins, limit to category mods, correct privilege name (eaf9d2e4)
+* http 200 test for api routes (bd583963)
+* invalid API call when unfollowing a user (58655e9a)
+* example (833c73e8)
+* #9127, scope service worker to relative_path for the forum (#9239) (2bc74cff)
+* update docs (4c12e0aa)
+* broken test after sorted-lists logic change (d6f60f45)
+* clear all locks on restart (9834f72f)
+* `action:admin.settingsLoaded` to use new hooks lib (5131eb6b)
+* crash on firing action hook that had no listeners registered (b0f5d5a5)
+* bug where `action:settings.sorted-list.loaded` fired early (1a04ec64)
+* regression where `filter:settings.set` no longer received sorted-lists (a8be6fb8)
+* #9231, fix redis pubsub connection (5bc1f5b4)
+* don't translate message on every ajaxify (a29dd21d)
+* tests (05c53394)
+* improper override of req.body.username in login logic (74199220)
+* full settings hash not passed through to action:settings.set (473d5f4a)
+* #9223, don't overwrite stmp settings (a5bf9779)
+* multiple sorted-lists do not save to the correct set (4029ec37)
+* pass module name to `static:script.init`, +comments (f8bf9e99)
+* handle delete and update for categories:name zset (e8429f50)
+* tests remove old routes (faeb6373)
+* removed object routes (d41ce873)
+* removed methods (647d3ba8)
+* incorrect return for Thumbs.get() if thumbs were disabled (7b090c58)
+* script failure if client-side page script does not exist (7da1b43f)
+* bug where `action:ajaxify.end` was never called if there were no init scripts (faf59603)
+* update js concatenation logic to bundle scripts.rjs into minfile regardless of build environment (8ff07bc1)
+* #7125, allow list for page route, configurable via plugin hook (f975063b)
+* error on flag list if no flag filters were saved in session (942d9247)
+* mod cid filter accidentally saved in session (35c92d0c)
+* more tests for #9217 (ce7c74b2)
+* tests for #9217 (f2a5cd0b)
+* missing return for #9217 (27cae0d5)
+* #9217, render 400 error page on bad access to /register (b2b1450e)
+* redis check compat tests (78896fc6)
+* registration completion overriding returnTo if it was already set (a186ea0f)
+* add missing user delete event types (5c1b7429)
+* missing option for user-deleteAccount on ACP Events page (1c420602)
+* **deps:**
+ * update dependency html-to-text to v7.1.1 (427e4f47)
+ * update dependency redis to v3.1.2 (35a4d0be)
+ * update dependency validator to v13.6.0 (e3d5d8d7)
+ * update dependency nodebb-plugin-composer-default to v6.5.27 (1b846271)
+ * update dependency redis to v3.1.1 (286a63e3)
+ * update dependency nodebb-theme-persona to v11.0.17 (51d58ce6)
+ * update dependency nodebb-theme-vanilla to v12.0.7 (16a1ba57)
+ * update dependency postcss to v8.2.10 (31cec2de)
+ * update dependency nodebb-plugin-mentions to v2.13.9 (fe087806)
+ * update dependency mongodb to v3.6.6 (#9467) (4264b236)
+ * update dependency sharp to v0.28.1 (34cbc9e2)
+ * update dependency nodebb-theme-persona to v11.0.16 (a8330b6d)
+ * update dependency nodebb-theme-vanilla to v12.0.6 (c02310b8)
+ * update dependency nodebb-theme-persona to v11.0.15 (316c71d7)
+ * update socket.io packages to v4.0.1 (e7776f8d)
+ * update dependency redis to v3.1.0 (fd9ff334)
+ * update dependency nodebb-plugin-composer-default to v6.5.26 (#9446) (8d9afbc6)
+ * update dependency postcss to v8.2.9 (6f51c460)
+ * update dependency nodebb-theme-persona to v11.0.14 (#9443) (fecfcd81)
+ * update dependency nodebb-theme-persona to v11.0.13 (#9437) (e5cc6e40)
+ * update dependency nodebb-theme-slick to v1.4.6 (dfdb0050)
+ * update dependency nodebb-theme-persona to v11.0.11 (27de58f2)
+ * update dependency benchpressjs to v2.4.3 (382f75bc)
+ * update dependency nodebb-plugin-composer-default to v6.5.25 (24236718)
+ * update dependency nodebb-theme-vanilla to v12.0.5 (89973d80)
+ * update dependency nodebb-plugin-composer-default to v6.5.24 (dec34446)
+ * update dependency nodebb-theme-persona to v11.0.10 (f78b4ba6)
+ * update dependency nodebb-plugin-composer-default to v6.5.23 (#9422) (e35d0741)
+ * update dependency nodebb-theme-persona to v11.0.8 (124cb9d9)
+ * update dependency benchpressjs to v2.4.2 (1dddcb49)
+ * update dependency nodebb-plugin-mentions to v2.13.8 (d511216c)
+ * update dependency connect-mongo to v4.4.1 (29ff5bb9)
+ * update dependency nodebb-theme-persona to v11.0.7 (c5734063)
+ * update dependency nodebb-theme-vanilla to v12.0.4 (#9409) (870e6c2c)
+ * update dependency nodebb-theme-slick to v1.4.5 (#9408) (24be8642)
+ * update dependency nodebb-theme-persona to v11.0.6 (#9407) (b50739c1)
+ * update dependency nodebb-plugin-spam-be-gone to v0.7.9 (#9405) (9359cae9)
+ * update dependency nodebb-theme-persona to v11.0.5 (47b2b97f)
+ * update dependency nodebb-plugin-composer-default to v6.5.21 (#9401) (2f70ac5a)
+ * update dependency mongodb to v3.6.5 (fcd887fd)
+ * update dependency nodebb-plugin-composer-default to v6.5.19 (#9391) (1631f159)
+ * update dependency nodebb-plugin-composer-default to v6.5.17 (#9384) (8d401760)
+ * update dependency nodebb-theme-persona to v11.0.3 (27facadb)
+ * update dependency socket.io-redis to v6.1.0 (adaddde6)
+ * update dependency nodebb-plugin-composer-default to v6.5.16 (a98e92b4)
+ * update dependency nodebb-plugin-markdown to v8.12.7 (#9371) (56b0bfd5)
+ * update dependency nodebb-theme-vanilla to v12.0.2 (#9369) (8923d34c)
+ * update dependency nodebb-theme-persona to v11.0.2 (#9368) (fa71c483)
+ * update socket.io packages to v4 (#9363) (13f3c504)
+ * update dependency postcss to v8.2.8 (680cf5ef)
+ * update dependency nodebb-theme-persona to v10.5.17 (2645bf55)
+ * update dependency connect-mongo to v4.3.1 (59459074)
+ * update dependency connect-mongo to v4.3.0 (f388086a)
+ * update dependency autoprefixer to v10.2.5 (4f4cdacc)
+ * update dependency postcss to v8.2.7 (72db3754)
+ * update dependency nodebb-plugin-composer-default to v6.5.13 (017af7cb)
+ * update dependency jquery to v3.6.0 (dd6082a0)
+ * update dependency connect-mongo to v4.2.2 (ec0912cc)
+ * update dependency nodebb-plugin-spam-be-gone to v0.7.8 (#9337) (536bae70)
+ * update dependency nodebb-plugin-composer-default to v6.5.12 (2674de01)
+ * update socket.io packages to v3.1.2 (510eb1f9)
+ * update dependency nodebb-theme-persona to v10.5.16 (217d3afd)
+ * update dependency nodebb-plugin-emoji-android to v2.0.5 (e8209341)
+ * update dependency sharp to v0.27.2 (c5231f10)
+ * update dependency nodebb-theme-vanilla to v11.4.5 (8596dcc4)
+ * update dependency nodebb-theme-persona to v10.5.15 (753ab0a0)
+ * update dependency nodebb-theme-persona to v10.5.14 (ed503b80)
+ * update dependency nodebb-theme-persona to v10.5.12 (ddd8fa31)
+ * update dependency benchpressjs to v2.4.1 (4ee3a8e8)
+ * update dependency nodebb-theme-persona to v10.5.10 (7f8fd4b0)
+ * update dependency nodebb-theme-persona to v10.5.9 (5dd748c6)
+ * require xregexp 5.0.1 (86e911ba)
+ * update dependency xregexp to v5 (513cd1c3)
+ * update dependency nodebb-theme-persona to v10.5.8 (54b4dc1d)
+ * update dependency postcss to v8.2.6 (4d92af5a)
+ * update dependency nodebb-theme-persona to v10.5.7 (#9288) (c2459fd5)
+ * update dependency nodebb-plugin-composer-default to v6.5.10 (b312725f)
+ * update dependency nodebb-theme-persona to v10.5.6 (4599144f)
+ * update dependency nodebb-widget-essentials to v5.0.3 (#9284) (eb9f058f)
+ * update dependency nodebb-plugin-composer-default to v6.5.9 (6e14014b)
+ * update dependency nodebb-plugin-composer-default to v6.5.8 (674a31d1)
+ * update dependency nodebb-theme-slick to v1.4.3 (#9278) (d3923585)
+ * update dependency nodebb-theme-vanilla to v11.4.4 (#9279) (1f28e8c3)
+ * update dependency nodebb-theme-persona to v10.5.5 (#9277) (a7b46adc)
+ * update dependency connect-redis to v5.1.0 (#9276) (83a0b6b8)
+ * update dependency nodebb-theme-persona to v10.5.4 (#9270) (dc145284)
+ * update dependency nodebb-theme-vanilla to v11.4.3 (#9272) (2fda6774)
+ * update dependency nodebb-theme-slick to v1.4.2 (2b12905d)
+ * update dependency nodebb-theme-lavender to v5.2.1 (fb2f1143)
+ * update dependency nodebb-theme-slick to v1.4.1 (#9262) (2cfab367)
+ * update socket.io packages to v3.1.1 (#9253) (2147d386)
+ * update dependency postcss to v8.2.5 (1fa0d4f4)
+ * update dependency nodebb-plugin-emoji-android to v2.0.1 (42e365d9)
+ * update dependency nodebb-plugin-markdown to v8.12.6 (4fd6027b)
+ * update dependency nodebb-plugin-mentions to v2.13.7 (8a2fe3d9)
+ * update dependency nodebb-theme-vanilla to v11.4.2 (2326e9a6)
+ * update dependency nodebb-theme-persona to v10.5.3 (9245ffaf)
+ * update dependency nodebb-plugin-dbsearch to v4.2.0 (389690c3)
+ * update dependency nodebb-plugin-composer-default to v6.5.7 (13e12c95)
+ * update dependency json2csv to v5.0.6 (0aa8e03f)
+ * bump theme deps for #9244 (44019e28)
+ * update dependency mongodb to v3.6.4 (56e4e56b)
+ * update dependency nodebb-theme-persona to v10.5.1 (04411449)
+ * update dependency nodebb-theme-vanilla to v11.4.0 (#9238) (897d29ec)
+ * update dependency nodebb-theme-slick to v1.4.0 (#9237) (8e2deab4)
+ * update dependency nodebb-theme-persona to v10.5.0 (#9236) (4f842a79)
+ * update dependency nodebb-theme-lavender to v5.2.0 (47fd1634)
+ * update dependency nodebb-plugin-dbsearch to v4.1.3 (1e10ebfb)
+ * update dependency nodebb-plugin-composer-default to v6.5.6 (0e2b329b)
+ * update dependency autoprefixer to v10.2.4 (6c3b1fde)
+ * update dependency nodebb-plugin-markdown to v8.12.5 (05901fcd)
+ * update dependency nodebb-theme-persona to v10.4.1 (a9b3fb37)
+ * update dependency sharp to v0.27.1 (a90773a6)
+ * bump persona to get timeline style (ca14c0e2)
+ * update dependency postcss to v8.2.4 (5b2f0be0)
+ * update dependency autoprefixer to v10.2.3 (d99cb1cf)
+ * update dependency postcss-clean to v1.2.0 (4232d97b)
+* **#9315:** api v3 post, put, del JSON (0d59fe3d)
+* **remountable-routes:**
+ * more fixes to remountable routes (9d17f397)
+ * bug with user routes remounting to itself (bc68e990)
+* **#9252:** pass site domain to nodemailer (#9254) (5e5d37c3)
+* **topic-events:**
+ * topicEvents.init() test (aa8b84bb)
+ * repeated invocations of Posts.addTopicEvents caused dupes to be added to DOM (df2fdd56)
+* **hooks:**
+ * bug where hook firing would fail if there were no listeners (efff8e2a)
+ * fallback handling for core invocations of hooks.fire (412d2858)
+
+##### Other Changes
+
+* schema docs for new ACP dashboard subpage routes (0804d547)
+
+##### Performance Improvements
+
+* increase batch size for notifs, run parallel (728ac5ff)
+* faster category tags upgrade script (0dad568c)
+* use setObjectBulk (95033ef7)
+* make upgrade script faster (a07509f7)
+* make upgrade script faster (0959b124)
+* cache base_url (cf4002bc)
+* single call to get digest topics, dont send duplicate topics (5ce28207)
+* single db call to add all uids (90d5c9da)
+* make digests a little bit faster (0185ea1b)
+* only load thumbs for topics that actually have thumbs (7eebcbdb)
+
+##### Refactors
+
+* make debug handler async (1db8920b)
+* widgets (#9471) (397baf02)
+* style, no need to convert length to string (d00268c9)
+* deprecate action:script.load, use filter:script.load instead (d1685600)
+* remove uncessary check (f316c4d4)
+* remove async.each/reduce from hooks for better stack traces (d05d7091)
+* use hooks.fire (0d3979ef)
+* fix variable name (1982edfd)
+* account edit logic and template, closes #9364 (98bf4064)
+* automatically authenticate all requests setup through route helpers (#9357) (7da061f0)
+* async listen testSocket (0021c601)
+* remove startsWith/endsWith (48bc23c0)
+* app.parseAndTranslate to return promise if no callback passed (b5a6a314)
+* privileges, export modules directly (#9325) (293b7c26)
+* have Graph.init and Graph.update return promises (3fa2e3ce)
+* abstract out some client side dashboard code into modules, analytics subpages for users, topics, and logins (f561799f)
+* move picture change client-side logic to its own rjs module (28f6931e)
+* remove dupe code (5286f208)
+* thumbs.associate accepts both relative path and url in path arg (3e6640ef)
+* move post queue retrival code to posts.getQueuedPosts (36f20211)
+* call topic events init from within file itself (6074a0fb)
+* improvements (970bd06f)
+* update dom after diff deletion better (a2a7557c)
+* removed 3 lines (4447a64e)
+* use Map to track sorted lists in Settings.set() (65de2e76)
+* **user:** all plugins to change list of icon background colours (fbccf6e2)
+* **remountable-routes:**
+ * rename `src/routes/accounts.js` to `src/routes/user.js` to better match the route prefix (1f28713f)
+ * allow certain route prefixes to be mounted elsewhere (92758ec5)
+* **topic-events:**
+ * expose addTopicEvents method in topic posts lib (9559fad8)
+ * break out some logic in events.get into local modifyEvent method (cec3fc93)
+ * fire topic event logging in topics/tools instead, pass uid into payload (425eca14)
+* **hooks:**
+ * deprecate `action:script.load` client-side hook (8e5687a4)
+ * better error handling (e7bd038d)
+
+##### Reverts
+
+* revert tag sort (f9df6431)
+* change toPid truthy (56523aa1)
+* bring back backwards compat (a1c01446)
+
+##### Code Style Changes
+
+* eslint (b5ce8d25)
+* **remountable-routes:** abstract removable routes code to a separate local fn (16c1d6e9)
+
+##### Tests
+
+* remove logs (435067aa)
+* clear cache between runs, require middleware later in helpers (2ea468da)
+* log (d15e2710)
+* remove equals (354e0a82)
+* test times (2f401d7d)
+* log (80ef1082)
+* added test for session id reroll on login (a3a7ab3a)
+* add missing test (8ef38cb2)
+* double filter test (70a653d0)
+* admin/manage/users tests (0e67ab01)
+* fix spec for topic thumbs (4c078084)
+* added missing properties to topicObject (1d9ade4c)
+* added missing test file (b31f6dd2)
+* topic reordering tests (ad54b174)
+* additional tests for topic thumbs (50664487)
+* added more topic thumbnail tests (28b30134)
+* post diff deletion tests (72b050b4)
+* **user:** added additional tests for icon background colour (d3a9e76a)
+
#### v1.16.2 (2021-01-21)
##### Breaking Changes
diff --git a/install/package.json b/install/package.json
index 9f493a639c..3cb383970c 100644
--- a/install/package.json
+++ b/install/package.json
@@ -49,7 +49,7 @@
"connect-mongo": "4.4.1",
"connect-multiparty": "^2.2.0",
"connect-pg-simple": "^6.2.1",
- "connect-redis": "5.1.0",
+ "connect-redis": "5.2.0",
"cookie-parser": "^1.4.5",
"cron": "^1.8.2",
"cropperjs": "^1.5.11",
@@ -78,25 +78,25 @@
"material-design-lite": "^1.3.0",
"mime": "^2.5.2",
"mkdirp": "^1.0.4",
- "mongodb": "3.6.6",
+ "mongodb": "3.6.8",
"morgan": "^1.10.0",
"mousetrap": "^1.6.5",
"multiparty": "4.2.2",
"@nodebb/bootswatch": "3.4.2",
"nconf": "^0.11.2",
- "nodebb-plugin-composer-default": "6.5.27",
- "nodebb-plugin-dbsearch": "4.2.0",
+ "nodebb-plugin-composer-default": "6.5.29",
+ "nodebb-plugin-dbsearch": "5.0.2",
"nodebb-plugin-emoji": "^3.5.0",
"nodebb-plugin-emoji-android": "2.0.5",
- "nodebb-plugin-markdown": "8.12.7",
- "nodebb-plugin-mentions": "2.13.9",
+ "nodebb-plugin-markdown": "8.12.10",
+ "nodebb-plugin-mentions": "2.13.11",
"nodebb-plugin-spam-be-gone": "0.7.9",
"nodebb-rewards-essentials": "0.1.4",
"nodebb-theme-lavender": "5.2.1",
- "nodebb-theme-persona": "11.0.17",
- "nodebb-theme-slick": "1.4.6",
- "nodebb-theme-vanilla": "12.0.7",
- "nodebb-widget-essentials": "5.0.3",
+ "nodebb-theme-persona": "11.0.20",
+ "nodebb-theme-slick": "1.4.7",
+ "nodebb-theme-vanilla": "12.0.8",
+ "nodebb-widget-essentials": "5.0.4",
"nodemailer": "^6.5.0",
"nprogress": "0.2.0",
"passport": "^0.4.1",
@@ -104,10 +104,10 @@
"passport-local": "1.0.0",
"pg": "^8.5.1",
"pg-cursor": "^2.5.2",
- "postcss": "8.2.10",
+ "postcss": "8.3.0",
"postcss-clean": "1.2.0",
"prompt": "^1.1.0",
- "redis": "3.1.2",
+ "ioredis": "4.27.3",
"request": "2.88.2",
"request-promise-native": "^1.0.9",
"requirejs": "2.3.6",
@@ -116,17 +116,17 @@
"sanitize-html": "^2.3.2",
"semver": "^7.3.4",
"serve-favicon": "^2.5.0",
- "sharp": "0.28.1",
- "sitemap": "^6.4.0",
+ "sharp": "0.28.3",
+ "sitemap": "^7.0.0",
"slideout": "1.0.1",
- "socket.io": "4.0.1",
+ "socket.io": "4.1.2",
"socket.io-adapter-cluster": "^1.0.1",
- "socket.io-client": "4.0.1",
- "socket.io-redis": "6.1.0",
+ "socket.io-client": "4.1.2",
+ "@socket.io/redis-adapter": "7.0.0",
"sortablejs": "1.13.0",
"spdx-license-list": "^6.4.0",
"spider-detector": "2.0.0",
- "textcomplete": "^0.17.1",
+ "textcomplete": "^0.18.0",
"textcomplete.contenteditable": "^0.1.1",
"timeago": "^1.6.7",
"tinycon": "0.6.8",
@@ -142,18 +142,18 @@
},
"devDependencies": {
"@apidevtools/swagger-parser": "10.0.2",
- "@commitlint/cli": "12.1.1",
- "@commitlint/config-angular": "12.1.1",
+ "@commitlint/cli": "12.1.4",
+ "@commitlint/config-angular": "12.1.4",
"coveralls": "3.1.0",
- "eslint": "7.24.0",
+ "eslint": "7.27.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-plugin-import": "2.22.1",
- "grunt": "1.3.0",
+ "grunt": "1.4.1",
"grunt-contrib-watch": "1.1.0",
"husky": "6.0.0",
- "jsdom": "16.5.3",
- "lint-staged": "10.5.4",
- "mocha": "8.3.2",
+ "jsdom": "16.6.0",
+ "lint-staged": "11.0.0",
+ "mocha": "8.4.0",
"mocha-lcov-reporter": "1.3.0",
"mockdate": "3.0.5",
"nyc": "15.1.0",
@@ -182,4 +182,4 @@
"url": "https://github.com/barisusakli"
}
]
-}
\ No newline at end of file
+}
diff --git a/public/language/ar/admin/manage/categories.json b/public/language/ar/admin/manage/categories.json
index 89bde1d9d0..9139872a6d 100644
--- a/public/language/ar/admin/manage/categories.json
+++ b/public/language/ar/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/ar/error.json b/public/language/ar/error.json
index ae71364c67..2be4c10ea7 100644
--- a/public/language/ar/error.json
+++ b/public/language/ar/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "لا يمكنك طرد نفسك من المجموعة.",
"no-users-selected": "لا يوجد مستخدم محدد.",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "يبدو أن فترة التسجيل لم تعد قائمة او هي غير مطابقة مع الخادم. يرجى إعادة تحميل هذه الصفحة.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json
index 80677aeb4f..5b20ece2b1 100644
--- a/public/language/ar/notifications.json
+++ b/public/language/ar/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "تم التحقق من عنوان البريد الإلكتروني",
"email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.",
"email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.",
diff --git a/public/language/ar/success.json b/public/language/ar/success.json
index 6b2670dc00..57b7def037 100644
--- a/public/language/ar/success.json
+++ b/public/language/ar/success.json
@@ -1,7 +1,7 @@
{
"success": "نجاح",
"topic-post": "لقد تمت الإضافة بنجاح.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "تم تسجيل الدخول بنجاح",
"settings-saved": "تم حفظ التغييرات!"
}
\ No newline at end of file
diff --git a/public/language/bg/admin/manage/categories.json b/public/language/bg/admin/manage/categories.json
index 7b8ed29fb3..a024272dc9 100644
--- a/public/language/bg/admin/manage/categories.json
+++ b/public/language/bg/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Анализи",
"view-category": "Преглед на категорията",
"set-order": "Запазване на реда",
+ "set-order-help": "Задаването на позиция за категорията ще я премести на желаното място и ще промени местата на другите категории, ако е необходимо. Най-малкият възможен номер е 1, което ще постави категорията най-отгоре.",
"select-category": "Изберете категория",
"set-parent-category": "Задайте базова категория",
diff --git a/public/language/bg/error.json b/public/language/bg/error.json
index f99e87accc..636545912e 100644
--- a/public/language/bg/error.json
+++ b/public/language/bg/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Не можете да изритате себе си от групата",
"no-users-selected": "Няма избран(и) потребител(и)",
"invalid-home-page-route": "Грешен път към началната страница",
- "invalid-session": "Несъответствие в сесията",
- "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла или не съответства на сървъра. Моля, опреснете страницата.",
+ "invalid-session": "Изтекла сесия",
+ "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла. Моля, опреснете страницата.",
+ "session-mismatch": "Несъответствие в сесията",
+ "session-mismatch-text": "Изглежда сесията Ви на вписване вече не съответства на сървъра. Моля, опреснете страницата.",
"no-topics-selected": "Няма избрани теми!",
"cant-move-to-same-topic": "Публикацията не може да бъде преместена в същата тема!",
"cant-move-topic-to-same-category": "Темата не може да бъде преместена в същата категория!",
diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json
index 86d2b8c7e8..5a13ffa0a1 100644
--- a/public/language/bg/notifications.json
+++ b/public/language/bg/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "Публикациите на %1 са изнесени, щракнете за сваляне",
"uploads-exported": "Качванията на %1 са изнесени, щракнете за сваляне",
"users-csv-exported": "Потребителите са изнесени във формат „csv“, щракнете за сваляне",
+ "post-queue-accepted": "Вашата публикация, която чакаше в опашката, беше приета. Натиснете тук, за да я видите.",
+ "post-queue-rejected": "Вашата публикация, която чакаше в опашката, беше отхвърлена.",
"email-confirmed": "Е-пощата беше потвърдена",
"email-confirmed-message": "Благодарим Ви, че потвърдихте е-пощата си. Акаунтът Ви е вече напълно активиран.",
"email-confirm-error-message": "Възникна проблем при потвърждаването на е-пощата Ви. Може кодът да е грешен или давността му да е изтекла.",
diff --git a/public/language/bg/success.json b/public/language/bg/success.json
index 28725d2552..6319fc1cc0 100644
--- a/public/language/bg/success.json
+++ b/public/language/bg/success.json
@@ -1,7 +1,7 @@
{
"success": "Готово",
"topic-post": "Вие публикувахте успешно.",
- "post-queued": "Публикацията Ви е добавена в опашката за одобрение.",
+ "post-queued": "Публикацията Ви е поставена в опашка за одобрение. Ще получите известие, когато тя бъде одобрена или отхвърлена.",
"authentication-successful": "Успешно удостоверяване",
"settings-saved": "Настройките са запазени!"
}
\ No newline at end of file
diff --git a/public/language/bn/admin/manage/categories.json b/public/language/bn/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/bn/admin/manage/categories.json
+++ b/public/language/bn/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/bn/error.json b/public/language/bn/error.json
index 97d34f7fa7..c9577d2149 100644
--- a/public/language/bn/error.json
+++ b/public/language/bn/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json
index 661d4909d2..0650db9e2d 100644
--- a/public/language/bn/notifications.json
+++ b/public/language/bn/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "ইমেইল নিশ্চিত করা হয়েছে",
"email-confirmed-message": "আপনার ইমেইল যাচাই করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টটি এখন সম্পূর্ণরূপে সক্রিয়।",
"email-confirm-error-message": "আপনার ইমেল ঠিকানার বৈধতা যাচাইয়ে একটি সমস্যা হয়েছে। সম্ভবত কোডটি ভুল ছিল অথবা কোডের মেয়াদ শেষ হয়ে গিয়েছে।",
diff --git a/public/language/bn/success.json b/public/language/bn/success.json
index c94040eeb1..7e8f468f6a 100644
--- a/public/language/bn/success.json
+++ b/public/language/bn/success.json
@@ -1,7 +1,7 @@
{
"success": "সফল হয়েছে",
"topic-post": "আপনি সফলভাবে পোষ্ট করেছেন। ",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "অথেন্টিকেশন সফল হয়েছে",
"settings-saved": "সেটিংস সেভ করা হয়েছে। "
}
\ No newline at end of file
diff --git a/public/language/bn/uploads.json b/public/language/bn/uploads.json
index 651a839876..fa1a858dcb 100644
--- a/public/language/bn/uploads.json
+++ b/public/language/bn/uploads.json
@@ -1,6 +1,6 @@
{
- "uploading-file": "Uploading the file...",
- "select-file-to-upload": "Select a file to upload!",
+ "uploading-file": "ফাইল পাঠানো হচ্ছে...",
+ "select-file-to-upload": "পাঠানোর জন্য নথি নির্বাচন",
"upload-success": "File uploaded successfully!",
"maximum-file-size": "Maximum %1 kb",
"no-uploads-found": "No uploads found",
diff --git a/public/language/cs/admin/manage/categories.json b/public/language/cs/admin/manage/categories.json
index ecd5d09438..7d7719e51c 100644
--- a/public/language/cs/admin/manage/categories.json
+++ b/public/language/cs/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytika",
"view-category": "Zobrazit kategorii",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Vyberte kategorii",
"set-parent-category": "Nastavit nadřazenou kategorii",
diff --git a/public/language/cs/error.json b/public/language/cs/error.json
index cd143ef070..60628f1984 100644
--- a/public/language/cs/error.json
+++ b/public/language/cs/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Nemůžete vyhodit sami sebe ze skupiny",
"no-users-selected": "Žádný uživatel/é nebyl/y vybrán/i",
"invalid-home-page-route": "Neplatná cesta k domovské stránkce",
- "invalid-session": "Nesoulad v relacích",
- "invalid-session-text": "Zdá se, že vše relace s přihlášením již není aktivní nebo již neodpovídá s relací na serveru. Obnovte prosím tuto stránku.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Žádná vybraná témata.",
"cant-move-to-same-topic": "Není možné přesunout příspěvek do stejného tématu!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json
index 35c65485c5..8eab980947 100644
--- a/public/language/cs/notifications.json
+++ b/public/language/cs/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "E-mail potvrzen",
"email-confirmed-message": "Děkujeme za ověření vaší e-mailové adresy. Váš účet je nyní aktivní.",
"email-confirm-error-message": "Nastal problém s ověřením vaší e-mailové adresy. Kód je pravděpodobně neplatný nebo jeho platnost vypršela.",
diff --git a/public/language/cs/success.json b/public/language/cs/success.json
index 656ed305ef..b1f996e509 100644
--- a/public/language/cs/success.json
+++ b/public/language/cs/success.json
@@ -1,7 +1,7 @@
{
"success": "Úspěšné",
"topic-post": "Příspěvek úspěšně přidán.",
- "post-queued": "Váš příspěvek byl přidán do fronty na schválení.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Úspěšné přihlášení",
"settings-saved": "Nastavení byla uložena."
}
\ No newline at end of file
diff --git a/public/language/da/admin/manage/categories.json b/public/language/da/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/da/admin/manage/categories.json
+++ b/public/language/da/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/da/error.json b/public/language/da/error.json
index 2bebe430cc..b7d49e2f18 100644
--- a/public/language/da/error.json
+++ b/public/language/da/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json
index 4c6ad68139..e0ddf2362c 100644
--- a/public/language/da/notifications.json
+++ b/public/language/da/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email bekræftet",
"email-confirmed-message": "Tak fordi du validerede din email. Din konto er nu fuldt ud aktiveret.",
"email-confirm-error-message": "Der var et problem med valideringen af din emailadresse. Bekræftelses koden var muligvis forkert eller udløbet.",
diff --git a/public/language/da/success.json b/public/language/da/success.json
index 67e8fb02f5..b024945606 100644
--- a/public/language/da/success.json
+++ b/public/language/da/success.json
@@ -1,7 +1,7 @@
{
"success": "Udført",
"topic-post": "Du har indsendt et indlæg.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Du blev autentificeret",
"settings-saved": "Indstillinger gemt!"
}
\ No newline at end of file
diff --git a/public/language/de/admin/manage/categories.json b/public/language/de/admin/manage/categories.json
index 2709567719..63c6de56ea 100644
--- a/public/language/de/admin/manage/categories.json
+++ b/public/language/de/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Kategorie auswählen",
"set-parent-category": "Übergeordnete Kategorie festlegen",
diff --git a/public/language/de/error.json b/public/language/de/error.json
index d72d636de8..a383a75396 100644
--- a/public/language/de/error.json
+++ b/public/language/de/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Du kannst dich nicht selber aus der Gruppe entfernen.",
"no-users-selected": "Kein(e) Benutzer ausgewählt",
"invalid-home-page-route": "Ungültiger Startseitenpfad",
- "invalid-session": "Sitzungsdiskrepanz",
- "invalid-session-text": "Es scheint als wäre deine Login-Sitzung nicht mehr aktiv oder sie passt nicht mehr mit der des Servers. Bitte aktualisiere diese Seite.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Keine Beiträge ausgewählt!",
"cant-move-to-same-topic": "Du kannst den Beitrag nicht in das selbe Thema schieben!",
"cant-move-topic-to-same-category": "Das Thema kann nicht zur selben Kategorie verschoben werden!",
diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json
index 030c0ed80b..c70f4679f4 100644
--- a/public/language/de/notifications.json
+++ b/public/language/de/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 Posts exportiert, klicke zum downloaden",
"uploads-exported": "%1 Uploads exportiert, klicke zum downloaden",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "E-Mail bestätigt",
"email-confirmed-message": "Vielen Dank für Ihre E-Mail-Validierung. Ihr Konto ist nun vollständig aktiviert.",
"email-confirm-error-message": "Es gab ein Problem bei der Validierung Ihrer E-Mail-Adresse. Möglicherweise ist der Code ungültig oder abgelaufen.",
diff --git a/public/language/de/success.json b/public/language/de/success.json
index a944624fc6..2ef0331ba0 100644
--- a/public/language/de/success.json
+++ b/public/language/de/success.json
@@ -1,7 +1,7 @@
{
"success": "Fertig",
"topic-post": "Beitrag erfolgreich erstellt.",
- "post-queued": "Dein Beitrag wurde zur Genehmigung eingereicht",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Authentifizierung erfolgreich!",
"settings-saved": "Einstellungen gespeichert!"
}
\ No newline at end of file
diff --git a/public/language/el/admin/manage/categories.json b/public/language/el/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/el/admin/manage/categories.json
+++ b/public/language/el/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/el/error.json b/public/language/el/error.json
index 2610f43acb..7d1bd35e85 100644
--- a/public/language/el/error.json
+++ b/public/language/el/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json
index 5779866aed..78e1d7b6ba 100644
--- a/public/language/el/notifications.json
+++ b/public/language/el/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email Confirmed",
"email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
"email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.",
diff --git a/public/language/el/success.json b/public/language/el/success.json
index df56b7ec5f..89a804572f 100644
--- a/public/language/el/success.json
+++ b/public/language/el/success.json
@@ -1,7 +1,7 @@
{
"success": "Επιτυχία",
"topic-post": "Δημοσίευσες με επιτυχία.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Επιτυχής Ταυτοποίηση",
"settings-saved": "Οι επιλογές αποθηκεύτηκαν!"
}
\ No newline at end of file
diff --git a/public/language/en-GB/admin/manage/categories.json b/public/language/en-GB/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/en-GB/admin/manage/categories.json
+++ b/public/language/en-GB/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json
index 2a849f7c5c..2f0f89458b 100644
--- a/public/language/en-GB/error.json
+++ b/public/language/en-GB/error.json
@@ -206,8 +206,11 @@
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
diff --git a/public/language/en-GB/notifications.json b/public/language/en-GB/notifications.json
index 0ec141d742..33014b5c80 100644
--- a/public/language/en-GB/notifications.json
+++ b/public/language/en-GB/notifications.json
@@ -51,6 +51,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email Confirmed",
"email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/en-GB/success.json b/public/language/en-GB/success.json
index 17093d3efe..6923dd3b8a 100644
--- a/public/language/en-GB/success.json
+++ b/public/language/en-GB/success.json
@@ -1,7 +1,7 @@
{
"success": "Success",
"topic-post": "You have successfully posted.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Authentication Successful",
"settings-saved": "Settings saved!"
}
\ No newline at end of file
diff --git a/public/language/en-US/admin/manage/categories.json b/public/language/en-US/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/en-US/admin/manage/categories.json
+++ b/public/language/en-US/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json
index d1635c8723..4ebeaecde0 100644
--- a/public/language/en-US/error.json
+++ b/public/language/en-US/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/en-US/notifications.json b/public/language/en-US/notifications.json
index 14bc2e046e..a3816674e2 100644
--- a/public/language/en-US/notifications.json
+++ b/public/language/en-US/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email Confirmed",
"email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
"email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.",
diff --git a/public/language/en-US/success.json b/public/language/en-US/success.json
index 231f17a160..7fa5550915 100644
--- a/public/language/en-US/success.json
+++ b/public/language/en-US/success.json
@@ -1,7 +1,7 @@
{
"success": "Success",
"topic-post": "You have successfully posted.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Authentication Successful",
"settings-saved": "Settings saved!"
}
\ No newline at end of file
diff --git a/public/language/en-x-pirate/admin/manage/categories.json b/public/language/en-x-pirate/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/en-x-pirate/admin/manage/categories.json
+++ b/public/language/en-x-pirate/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json
index d1635c8723..4ebeaecde0 100644
--- a/public/language/en-x-pirate/error.json
+++ b/public/language/en-x-pirate/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/en-x-pirate/notifications.json b/public/language/en-x-pirate/notifications.json
index fe394df25a..79e4693058 100644
--- a/public/language/en-x-pirate/notifications.json
+++ b/public/language/en-x-pirate/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email Confirmed",
"email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
"email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.",
diff --git a/public/language/en-x-pirate/success.json b/public/language/en-x-pirate/success.json
index 231f17a160..7fa5550915 100644
--- a/public/language/en-x-pirate/success.json
+++ b/public/language/en-x-pirate/success.json
@@ -1,7 +1,7 @@
{
"success": "Success",
"topic-post": "You have successfully posted.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Authentication Successful",
"settings-saved": "Settings saved!"
}
\ No newline at end of file
diff --git a/public/language/es/admin/manage/categories.json b/public/language/es/admin/manage/categories.json
index 22bb6256e7..977744d05e 100644
--- a/public/language/es/admin/manage/categories.json
+++ b/public/language/es/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Seleccionar Categoría",
"set-parent-category": "Fijar Categoría Superior",
diff --git a/public/language/es/error.json b/public/language/es/error.json
index f52907cf73..3a5b111245 100644
--- a/public/language/es/error.json
+++ b/public/language/es/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "No te puedes expulsar a ti mismo del grupo",
"no-users-selected": "Ningun usuario(s) seleccionado",
"invalid-home-page-route": "Ruta de página de inicio invalida",
- "invalid-session": "No concuerdan los datos de sesión",
- "invalid-session-text": "Parece que su sesión ha expirado o no concuerda con el servidor. Por favor vuelva a cargar la página.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "¡No se han seleccionado temas!",
"cant-move-to-same-topic": "¡No puedes mover el mensaje al mismo tema!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json
index 5fc224c511..a519882961 100644
--- a/public/language/es/notifications.json
+++ b/public/language/es/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Correo electrónico confirmado",
"email-confirmed-message": "Gracias por validar tu correo electrónico. Tu cuenta ya está completamente activa.",
"email-confirm-error-message": "Hubo un problema al validar tu cuenta de correo electrónico. Quizá el código era erróneo o expiró...",
diff --git a/public/language/es/success.json b/public/language/es/success.json
index aad794e5a2..80dbf11c21 100644
--- a/public/language/es/success.json
+++ b/public/language/es/success.json
@@ -1,7 +1,7 @@
{
"success": "¡Éxito!",
"topic-post": "Mensaje publicado satisfactoriamente.",
- "post-queued": "Tu post está en cola para su aprobación.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Identificado satisfactoriamente",
"settings-saved": "¡Ajustes guardados satisfactoriamente!"
}
\ No newline at end of file
diff --git a/public/language/es/tags.json b/public/language/es/tags.json
index ddea2905c6..c61d272cde 100644
--- a/public/language/es/tags.json
+++ b/public/language/es/tags.json
@@ -4,5 +4,5 @@
"enter_tags_here": "Introduce aquí las etiquetas, entre %1 y %2 caracteres cada una.",
"enter_tags_here_short": "Introduzca las etiquetas...",
"no_tags": "Aún no hay etiquetas.",
- "select_tags": "Select Tags"
+ "select_tags": "Seleccionar Etiquetas"
}
\ No newline at end of file
diff --git a/public/language/es/topic.json b/public/language/es/topic.json
index e08c2ca404..b92af3daf6 100644
--- a/public/language/es/topic.json
+++ b/public/language/es/topic.json
@@ -1,6 +1,6 @@
{
"topic": "Tema",
- "title": "Title",
+ "title": "Título",
"no_topics_found": "¡No se encontraron temas!",
"no_posts_found": "¡No se encontraron publicaciones!",
"post_is_deleted": "¡Esta publicación está eliminada!",
@@ -31,18 +31,18 @@
"locked": "Cerrado",
"pinned": "Fijo",
"pinned-with-expiry": "Pinned until %1",
- "scheduled": "Scheduled",
+ "scheduled": "Programado",
"moved": "Movido",
"moved-from": "Moved from %1",
"copy-ip": "Copiar IP",
"ban-ip": "Banear IP",
"view-history": "Editar Historial",
- "locked-by": "Locked by",
- "unlocked-by": "Unlocked by",
+ "locked-by": "Bloqueado por",
+ "unlocked-by": "Desbloqueado por",
"pinned-by": "Pinned by",
"unpinned-by": "Unpinned by",
- "deleted-by": "Deleted by",
- "restored-by": "Restored by",
+ "deleted-by": "Borrado por",
+ "restored-by": "Restaurado por",
"queued-by": "Post queued for approval →",
"bookmark_instructions": "Haz click aquí para volver a tu último mensaje leído en este tema",
"flag-post": "Flag this post",
diff --git a/public/language/et/admin/manage/categories.json b/public/language/et/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/et/admin/manage/categories.json
+++ b/public/language/et/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/et/error.json b/public/language/et/error.json
index a8226a57ad..3c101a3a41 100644
--- a/public/language/et/error.json
+++ b/public/language/et/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Sa ei saa ennast ära visata gruppist",
"no-users-selected": "Ühtki kasutajat pole valitud",
"invalid-home-page-route": "Vigane avalehe suunamine",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json
index 51d15b1a6a..516c72ac26 100644
--- a/public/language/et/notifications.json
+++ b/public/language/et/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Emaili aadress kinnitatud",
"email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja on nüüd täielikult aktiveeritud.",
"email-confirm-error-message": "Emaili aadressi kinnitamisel tekkis viga. Võibolla kinnituskood oli vale või aegunud.",
diff --git a/public/language/et/success.json b/public/language/et/success.json
index be9cc4d9e6..1d897c8083 100644
--- a/public/language/et/success.json
+++ b/public/language/et/success.json
@@ -1,7 +1,7 @@
{
"success": "Õnnestus",
"topic-post": "Edukalt postitatud.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Sisse logimine õnnestus!",
"settings-saved": "Seaded salvestatud!"
}
\ No newline at end of file
diff --git a/public/language/fa-IR/admin/manage/categories.json b/public/language/fa-IR/admin/manage/categories.json
index 29558b95b5..8cc20c9205 100644
--- a/public/language/fa-IR/admin/manage/categories.json
+++ b/public/language/fa-IR/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json
index 6cc73559e2..b19cf7b242 100644
--- a/public/language/fa-IR/error.json
+++ b/public/language/fa-IR/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "شما نمی توانید خودتان را از گروه کیک کنید",
"no-users-selected": "هیچ کاربر(های) انتخاب نشده",
"invalid-home-page-route": "مسیر صفحه اصلی نامعتبر است",
- "invalid-session": "عدم تطابق جلسه",
- "invalid-session-text": "به نظر میرسد این جلسه برای ورود دیگر فعال نیست و یا با سرور هماهنگ نیست. لطفا این صفحه را رفرش کنید.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "هیچ موضوعی انتخاب نشده است !",
"cant-move-to-same-topic": "نمی توان پست یک موضوع را به همان موضوع انتقال داد !",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/fa-IR/notifications.json b/public/language/fa-IR/notifications.json
index 2d16080363..7fa8c2622a 100644
--- a/public/language/fa-IR/notifications.json
+++ b/public/language/fa-IR/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "ایمیل تایید شد",
"email-confirmed-message": "بابت تایید ایمیلتان سپاسگزاریم. حساب کاربری شما اکنون به صورت کامل فعال شده است.",
"email-confirm-error-message": "خطایی در تایید آدرس ایمیل شما پیش آمده است. ممکن است کد نامعتبر و یا منقضی شده باشد.",
diff --git a/public/language/fa-IR/success.json b/public/language/fa-IR/success.json
index 9ca802250a..7544893c44 100644
--- a/public/language/fa-IR/success.json
+++ b/public/language/fa-IR/success.json
@@ -1,7 +1,7 @@
{
"success": "موفقیتآمیز",
"topic-post": "پست شما باموفقیت فرستاده شد.",
- "post-queued": "پست شما برای تأیید در صف قرار گرفت.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "اعتبارسنجی موفق",
"settings-saved": "تنظیمات ذخیره شد."
}
\ No newline at end of file
diff --git a/public/language/fi/admin/manage/categories.json b/public/language/fi/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/fi/admin/manage/categories.json
+++ b/public/language/fi/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/fi/error.json b/public/language/fi/error.json
index d6ba3838a4..970f45c3ea 100644
--- a/public/language/fi/error.json
+++ b/public/language/fi/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Ei aiheita valittuna",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json
index 4083fcd37c..da64260a2b 100644
--- a/public/language/fi/notifications.json
+++ b/public/language/fi/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Sähköpostiosoite vahvistettu",
"email-confirmed-message": "Kiitos sähköpostiosoitteesi vahvistamisesta. Käyttäjätilisi on nyt täysin aktivoitu.",
"email-confirm-error-message": "Ongelma sähköpostiosoitteen vahvistamisessa. Ehkäpä koodi oli virheellinen tai vanhentunut.",
diff --git a/public/language/fi/success.json b/public/language/fi/success.json
index b782e7e9a5..02864d93ff 100644
--- a/public/language/fi/success.json
+++ b/public/language/fi/success.json
@@ -1,7 +1,7 @@
{
"success": "Onnistui",
"topic-post": "Viestin lähettäminen onnistui.",
- "post-queued": "Viestisi on jonossa odottamassa hyväksyntää",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Tunnistautuminen onnistui",
"settings-saved": "Asetukset tallennettu!"
}
\ No newline at end of file
diff --git a/public/language/fr/admin/manage/categories.json b/public/language/fr/admin/manage/categories.json
index 52f0441c6e..39f68b7f6d 100644
--- a/public/language/fr/admin/manage/categories.json
+++ b/public/language/fr/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Statistiques",
"view-category": "Voir la catégorie",
"set-order": "Définir l'ordre",
+ "set-order-help": "Configuration des catégories. Vous pouvez déplacer vos catégories dans l'ordre que vous le souhaitez. La commande minimum est de 1, ce qui place la catégorie au sommet.",
"select-category": "Sélectionner une catégorie",
"set-parent-category": "Définissez une catégorie parente",
diff --git a/public/language/fr/admin/settings/uploads.json b/public/language/fr/admin/settings/uploads.json
index f6f979382e..dbba8cae6b 100644
--- a/public/language/fr/admin/settings/uploads.json
+++ b/public/language/fr/admin/settings/uploads.json
@@ -21,9 +21,9 @@
"topic-thumb-size": "Miniature du sujet",
"allowed-file-extensions": "Extensions de fichier autorisés",
"allowed-file-extensions-help": "Entrer une liste d’extensions de fichier séparés par une virgule (ex : pdf,xls,doc). Une liste vide signifie que toutes les extensions sont autorisées.",
- "upload-limit-threshold": "Rate limit user uploads to:",
- "upload-limit-threshold-per-minute": "Per %1 Minute",
- "upload-limit-threshold-per-minutes": "Per %1 Minutes",
+ "upload-limit-threshold": "Limite d'envoi de fichiers par utilisateurs:",
+ "upload-limit-threshold-per-minute": "Par %1 Minute",
+ "upload-limit-threshold-per-minutes": "Par %1 Minutes",
"profile-avatars": "Avatar",
"allow-profile-image-uploads": "Autoriser les utilisateurs à télécharger des avatars",
"convert-profile-image-png": "Convertir les avatars téléchargés au format PNG",
diff --git a/public/language/fr/error.json b/public/language/fr/error.json
index ac4198d4cd..741fff28d7 100644
--- a/public/language/fr/error.json
+++ b/public/language/fr/error.json
@@ -89,7 +89,7 @@
"file-too-big": "La taille maximale autorisée pour un fichier est de %1 ko. Veuillez envoyer un fichier plus petit.",
"guest-upload-disabled": "L'envoi de fichiers a été désactivé pour les invités",
"cors-error": "Impossible d'envoyer l'image en raison d'une erreur de configuration CORS",
- "upload-ratelimit-reached": "You have uploaded too many files at one time. Please try again later.",
+ "upload-ratelimit-reached": "Vous avez envoyé trop de fichiers à la fois. Veuillez réessayer plus tard.",
"scheduling-to-past": "Veuillez sélectionner une date ultérieure.",
"invalid-schedule-date": "Veuillez saisir une date et une heure valide.",
"cant-pin-scheduled": "Les sujets planifiés ne peuvent pas être (dé)épinglés.",
@@ -174,8 +174,10 @@
"cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe",
"no-users-selected": "Aucun utilisateur sélectionné",
"invalid-home-page-route": "Chemin vers la page d'accueil invalide",
- "invalid-session": "Session interrompue",
- "invalid-session-text": "Il semble que votre session ne soit plus active, ou que le serveur ne la reconnaisse plus. Merci de rafraichir cette page.",
+ "invalid-session": "Session Invalide",
+ "invalid-session-text": "Il semblerait que votre session de connexion ne soit plus active. Merci de rafraîchir cette page.",
+ "session-mismatch": "Session Interrompue",
+ "session-mismatch-text": "Il semble que votre session ne soit plus active, ou que le serveur ne la reconnaisse plus. Merci de rafraîchir cette page.",
"no-topics-selected": "Aucun sujet sélectionné !",
"cant-move-to-same-topic": "Impossible de déplacer le message dans le même sujet !",
"cant-move-topic-to-same-category": "Impossible de déplacer le sujet dans la même catégorie !",
diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json
index ab11735341..7f38bf7b7f 100644
--- a/public/language/fr/notifications.json
+++ b/public/language/fr/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 messages exportés, cliquez pour les télécharger",
"uploads-exported": "%1 envois exportés, cliquez pour les télécharger",
"users-csv-exported": "Utilisateurs exportés en CSV, cliquez pour télécharger",
+ "post-queue-accepted": "Votre message a été accepté. Cliquez ici pour voir votre message.",
+ "post-queue-rejected": "Votre message a été rejeté.",
"email-confirmed": "Email vérifié",
"email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.",
"email-confirm-error-message": "Il y a un un problème dans la vérification de votre adresse email. Le code est peut être invalide ou a expiré.",
diff --git a/public/language/fr/success.json b/public/language/fr/success.json
index 11894dcd3f..33e50aadfa 100644
--- a/public/language/fr/success.json
+++ b/public/language/fr/success.json
@@ -1,7 +1,7 @@
{
"success": "Terminé",
"topic-post": "Le message a bien été envoyé.",
- "post-queued": "Votre message est en attente d'approbation.",
+ "post-queued": "Votre message est en attente d'approbation. Vous recevrez une notification lorsqu'il sera accepté ou rejeté.",
"authentication-successful": "Authentification réussie",
"settings-saved": "Paramètres enregistrés !"
}
\ No newline at end of file
diff --git a/public/language/gl/admin/manage/categories.json b/public/language/gl/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/gl/admin/manage/categories.json
+++ b/public/language/gl/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/gl/error.json b/public/language/gl/error.json
index cf247b6cac..4a84d894f4 100644
--- a/public/language/gl/error.json
+++ b/public/language/gl/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Non te podes expulsar a ti mesmo do grupo",
"no-users-selected": "Ningún usuario seleccionado",
"invalid-home-page-route": "Ruta de páxina de inicio inválida",
- "invalid-session": "Non concordan os datos da sesión",
- "invalid-session-text": "Parece que a súa sesión expirou ou non concorda co servidor. Por favor, recarge a páxina.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json
index 5f3ceb4af1..0243fac65f 100644
--- a/public/language/gl/notifications.json
+++ b/public/language/gl/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Correo confirmado",
"email-confirmed-message": "Grazas por validar o teu correo. A túa conta agora está activada.",
"email-confirm-error-message": "Houbo un problema validando o teu correo. Poida que o código fose inválido ou expirase. ",
diff --git a/public/language/gl/success.json b/public/language/gl/success.json
index c98888b604..ab75efd29b 100644
--- a/public/language/gl/success.json
+++ b/public/language/gl/success.json
@@ -1,7 +1,7 @@
{
"success": "Éxito",
"topic-post": "Publicaches con éxito.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Autenticación exitosa",
"settings-saved": "Configuración gardada!"
}
\ No newline at end of file
diff --git a/public/language/he/admin/advanced/database.json b/public/language/he/admin/advanced/database.json
index a17b7832d1..b18bbe3f6a 100644
--- a/public/language/he/admin/advanced/database.json
+++ b/public/language/he/admin/advanced/database.json
@@ -21,8 +21,8 @@
"mongo.bytes-in": "ביטים נכנסים",
"mongo.bytes-out": "ביטים יוצאים",
"mongo.num-requests": "מספר בקשות",
- "mongo.raw-info": "מידע לא מעובד מMongoDB",
- "mongo.unauthorized": "NodeBB לא הצליחה לקבל את המידע הדרוש מMongoDB. אנא בדוק שלמשתמש יש הרשאת clusterMonitor לadmin database.",
+ "mongo.raw-info": "מידע לא מעובד מ-MongoDB",
+ "mongo.unauthorized": "NodeBB לא הצליחה לקבל את המידע הדרוש מ-MongoDB. אנא בדוק שלמשתמש יש הרשאת clusterMonitor ל-admin database.",
"redis": "Redis",
"redis.version": "גרסת Redis",
@@ -37,8 +37,8 @@
"redis.total-connections-recieved": "סך כל החיבורים שהתקבלו",
"redis.total-commands-processed": "סך כל הפקודות שעובדו",
"redis.iops": "אפשרויות מידיות לשניה",
- "redis.iinput": "Instantaneous Input Per Second",
- "redis.ioutput": "Instantaneous Output Per Second",
+ "redis.iinput": "קלט מיידי לשנייה",
+ "redis.ioutput": "פלט מיידי לשנייה",
"redis.total-input": "סך הכל מידע נכנס",
"redis.total-output": "סך הכל מידע יוצא",
diff --git a/public/language/he/admin/manage/categories.json b/public/language/he/admin/manage/categories.json
index fe1a4a5b94..fcc8cf1483 100644
--- a/public/language/he/admin/manage/categories.json
+++ b/public/language/he/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "נתח",
"view-category": "הצג קטגוריה",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "בחר קטגוריה",
"set-parent-category": "הגדר קטגוריית אב",
diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json
index 60af5a6eb1..c4d31c775d 100644
--- a/public/language/he/admin/menu.json
+++ b/public/language/he/admin/menu.json
@@ -1,9 +1,9 @@
{
- "section-dashboard": "Dashboards",
- "dashboard/overview": "Overview",
- "dashboard/logins": "Logins",
- "dashboard/users": "Users",
- "dashboard/topics": "Topics",
+ "section-dashboard": "לוח מחוונים",
+ "dashboard/overview": "סקירה כללית",
+ "dashboard/logins": "כניסות",
+ "dashboard/users": "משתמשים",
+ "dashboard/topics": "נושאים",
"section-general": "כללי",
"section-manage": "ניהול",
diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json
index 0557595e9c..1d1a13ee20 100644
--- a/public/language/he/admin/settings/user.json
+++ b/public/language/he/admin/settings/user.json
@@ -16,25 +16,25 @@
"allow-account-deletion": "אפשר מחיקת חשבונות",
"hide-fullname": "החבא שם מלא ממשתמשים",
"hide-email": "החבא כתובת מייל ממשתמשים",
- "show-fullname-as-displayname": "Show user's full name as their display name if available",
+ "show-fullname-as-displayname": "הצג את השם המלא של המשתמש כשם התצוגה שלו אם הוא זמין",
"themes": "ערכות נושא",
"disable-user-skins": "אל תאפשר למשתמשים לבחור ערכת נושא",
- "account-protection": "Account Protection",
- "admin-relogin-duration": "Admin relogin duration (minutes)",
- "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable",
- "login-attempts": "Login attempts per hour",
- "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time",
- "lockout-duration": "Account Lockout Duration (minutes)",
- "login-days": "Days to remember user login sessions",
- "password-expiry-days": "Force password reset after a set number of days",
- "session-time": "Session Time",
- "session-time-days": "Days",
- "session-time-seconds": "Seconds",
+ "account-protection": "הגנת חשבון",
+ "admin-relogin-duration": "משך חיבור של מנהל מערכת (דקות)",
+ "admin-relogin-duration-help": "לאחר פרק זמן מוגדר של גישה למקטע הניהול ידרוש כניסה מחדש, הגדר ל- 0 על-מנת להפוך ללא זמין",
+ "login-attempts": "נסיונות כניסה לשעה",
+ "login-attempts-help": "אם ניסיונות כניסה ל user's חורג מסף זה, החשבון יינעל לפרק זמן שנקבע מראש",
+ "lockout-duration": "משך נעילת חשבון (דקות)",
+ "login-days": "ימים לזכירת התחברות כניסה של משתמשים",
+ "password-expiry-days": "כפיית איפוס סיסמה לאחר מספר ימים מוגדר",
+ "session-time": "זמן סשן",
+ "session-time-days": "ימים",
+ "session-time-seconds": "שניות",
"session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.",
"online-cutoff": "Minutes after user is considered inactive",
- "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.",
- "registration": "User Registration",
- "registration-type": "סוג השרמה",
+ "online-cutoff-help": "אם משתמש אינו מבצע פעולות במשך זמן זה, הוא נחשב כלא פעיל ואינו מקבל עדכונים בזמן אמת.",
+ "registration": "רישום משתמש",
+ "registration-type": "סוג הרשמה",
"registration-approval-type": "סוג אישור הרשמה",
"registration-type.normal": "רגיל",
"registration-type.admin-approval": "אישור מנהל",
@@ -44,14 +44,14 @@
"registration-type.disabled": "בטל הרשמה",
"registration-type.help": "רגיל - משתמשים יכולים להירשם על ידי שימוש בדף /register.
\nהזמנה בלבד - משתמשים אחרים יכולים להזמין משתמשים מדף המשתמש.
\nהזמנת מנהל בלבד - רק מנהלים יכולים להזמין משתמשים אחרים מדף המשתמש ודף ההנהלת משתמשים.
\nבטל הרשמה - לא ניתן להירשם.
ד",
"registration-approval-type.help": "רגיל - משתמשים נרשמים באופן מיידי.
\nאישור מנהל - משתמשים אשר נרשמו מוכנים לתוך רשימת אישור למנהלים.
\nאישור מנהל לכתובות IP - רגיל למשתמשים חדשים, אישור מנהל לכתובות IP אשר כבר מקושר אליהם חשבון.
",
- "registration-queue-auto-approve-time": "Automatic Approval Time",
- "registration-queue-auto-approve-time-help": "Hours before user is approved automatically. 0 to disable.",
- "registration-queue-show-average-time": "Show users average time it takes to approve a new user",
+ "registration-queue-auto-approve-time": "זמן אישור אוטומטי",
+ "registration-queue-auto-approve-time-help": "שעות לפני שהמשתמש מאושר באופן אוטומטי. רשום 0 על-מנת להשבית.",
+ "registration-queue-show-average-time": "הצג למשתמשים זמן ממוצע שנדרש על-מנת לאשר משתמש חדש",
"registration.max-invites": "מרב ההזמנות למשתמש",
"max-invites": "מרב ההזמנות למשתמש",
"max-invites-help": "0 בשביל לבטל הגבלה. מנהלים מקבלים אינסוף הזמנות
תקף רק ל-\"הזמנה בלבד\"",
"invite-expiration": "תוקף ההזמנה",
- "invite-expiration-help": "הזמנות יפוגו ב# ימים.",
+ "invite-expiration-help": "הזמנות יפוגו ב-# ימים.",
"min-username-length": "Minimum Username Length",
"max-username-length": "Maximum Username Length",
"min-password-length": "Minimum Password Length",
diff --git a/public/language/he/error.json b/public/language/he/error.json
index eeefe47316..db5de54d2c 100644
--- a/public/language/he/error.json
+++ b/public/language/he/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "אינך יכול להסיר את עצמך מהקבוצה",
"no-users-selected": "לא נבחרו משתמשים",
"invalid-home-page-route": "כתובת דף הבית הינה שגויה",
- "invalid-session": "מושב לא תואם",
- "invalid-session-text": "נראה שסשן ההתחברות שלך כבר לא פעיל. אנא טען מחדש את העמוד.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "לא נבחרו נושאים!",
"cant-move-to-same-topic": "אתה לא יכול להעביר פוסט לאותו נושא!",
"cant-move-topic-to-same-category": "לא ניתן להעביר נושא לאותה קטגוריה!",
diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json
index b79ec05b08..76392360ae 100644
--- a/public/language/he/notifications.json
+++ b/public/language/he/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 פוסטים יוצאו, לחץ כדי להוריד.",
"uploads-exported": "%1 העלאות יוצאו, לחץ כדי להוריד.",
"users-csv-exported": "משתמשים יוצאו כ-csv, לחץ כאן להורדה.",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "כתובת המייל אושרה",
"email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.",
"email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.",
diff --git a/public/language/he/success.json b/public/language/he/success.json
index da04fbee46..c658ec97f0 100644
--- a/public/language/he/success.json
+++ b/public/language/he/success.json
@@ -1,7 +1,7 @@
{
"success": "הצלחה",
"topic-post": "העלת פוסט בהצלחה.",
- "post-queued": "הפוסט שלך ממתין לאישור.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "הנתונים אומתו בהצלחה",
"settings-saved": "הנתונים נשמרו!"
}
\ No newline at end of file
diff --git a/public/language/hr/admin/manage/categories.json b/public/language/hr/admin/manage/categories.json
index 0ec362b08c..6108057152 100644
--- a/public/language/hr/admin/manage/categories.json
+++ b/public/language/hr/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Odabri kategoriju",
"set-parent-category": "Postavi roditeljsku kategoriju ",
diff --git a/public/language/hr/error.json b/public/language/hr/error.json
index 3e6978ea21..8c940ea4fe 100644
--- a/public/language/hr/error.json
+++ b/public/language/hr/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Ne možete sebe izbaciti iz grupe",
"no-users-selected": "Korisnici nisu odabrani",
"invalid-home-page-route": "Netočna putanja naslovnice",
- "invalid-session": "Pogreška sesije",
- "invalid-session-text": "Vaša sesija nije više aktivna ili se više ne poklapa sa serverom. Molimo osvježite stranicu.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/hr/notifications.json b/public/language/hr/notifications.json
index 0db4e82c4f..35d05ab336 100644
--- a/public/language/hr/notifications.json
+++ b/public/language/hr/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email potvrđen",
"email-confirmed-message": "Hvala na potvrdi emaila. Vaš račun je sada aktivan.",
"email-confirm-error-message": "Nastao je problem pri potvrdi Vaše email adrese. Provjerite kod ili zatražite novi.",
diff --git a/public/language/hr/success.json b/public/language/hr/success.json
index 5427792de5..d00c3087ef 100644
--- a/public/language/hr/success.json
+++ b/public/language/hr/success.json
@@ -1,7 +1,7 @@
{
"success": "Uspijeh",
"topic-post": "Uspješna objava",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Autentifikacija uspješna",
"settings-saved": "Postavke spremljene!"
}
\ No newline at end of file
diff --git a/public/language/hu/admin/extend/plugins.json b/public/language/hu/admin/extend/plugins.json
index a7ddbad1e9..18f559a666 100644
--- a/public/language/hu/admin/extend/plugins.json
+++ b/public/language/hu/admin/extend/plugins.json
@@ -39,7 +39,7 @@
"alert.upgraded": "Beépülő frissítve",
"alert.installed": "Beépülő telepítve",
"alert.uninstalled": "Beépülő eltávolítva",
- "alert.activate-success": "Please rebuild and restart your NodeBB to fully activate this plugin",
+ "alert.activate-success": "Kérlek építsd újra és indítsd újra a NodeBB-t, hogy teljesen engedélyezd ezt a beépülőt",
"alert.deactivate-success": "A beépülő sikeresen deaktiválva",
"alert.upgrade-success": "A beépülő teljes frissítéséhez kérlek építsd újra majd indítsd újra a NodeBB-t.",
"alert.install-success": "A beépülő sikeresen telepítve, kérlek aktiváld.",
diff --git a/public/language/hu/admin/manage/categories.json b/public/language/hu/admin/manage/categories.json
index 2de62865d9..42b11ebd47 100644
--- a/public/language/hu/admin/manage/categories.json
+++ b/public/language/hu/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analitika",
"view-category": "Kategória megtekintése",
"set-order": "Sorrend beállítása",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Kategória kiválasztása",
"set-parent-category": "Szülő kategória beállítása",
diff --git a/public/language/hu/admin/settings/uploads.json b/public/language/hu/admin/settings/uploads.json
index 297f2f79b4..d3f3633e10 100644
--- a/public/language/hu/admin/settings/uploads.json
+++ b/public/language/hu/admin/settings/uploads.json
@@ -21,9 +21,9 @@
"topic-thumb-size": "Témakörkép mérete",
"allowed-file-extensions": "Megengedett fájlkiterjesztések",
"allowed-file-extensions-help": "Itt adj meg fájlkiterjesztési listát, vesszővel elválasztva (pl. pdf,xls,doc). Az üres lista azt jelenti, hogy minden kiterjesztés megengedett.",
- "upload-limit-threshold": "Rate limit user uploads to:",
- "upload-limit-threshold-per-minute": "Per %1 Minute",
- "upload-limit-threshold-per-minutes": "Per %1 Minutes",
+ "upload-limit-threshold": "Felhasználó limit feltöltésekre:",
+ "upload-limit-threshold-per-minute": "%1 percenként",
+ "upload-limit-threshold-per-minutes": "%1 percenként",
"profile-avatars": "Profil avatárok",
"allow-profile-image-uploads": "Profilképek feltöltésének engedélyezése a felhasználók számára",
"convert-profile-image-png": "Profilkép feltöltések átkonvertálása PNG-be",
diff --git a/public/language/hu/error.json b/public/language/hu/error.json
index 79706377e8..c3158a29c2 100644
--- a/public/language/hu/error.json
+++ b/public/language/hu/error.json
@@ -89,7 +89,7 @@
"file-too-big": "A maximális megengedett fájl méret %1 kB - kérlek kisebb méretű fájlt tölts fel",
"guest-upload-disabled": "Vendég általi feltöltés kikapcsolva",
"cors-error": "Nem sikerült a kép feltöltés a rosszul konfigurált CORS miatt",
- "upload-ratelimit-reached": "You have uploaded too many files at one time. Please try again later.",
+ "upload-ratelimit-reached": "Egyszerre túl sok fájlt töltöttél fel. Kérlek próbáld újra később.",
"scheduling-to-past": "Kérlek adj meg egy jövőbeli időpontot.",
"invalid-schedule-date": "Kérlek valós dátumot és időt adj meg.",
"cant-pin-scheduled": "Időzített témakörök rögzítése nem oldható fel.",
@@ -174,8 +174,10 @@
"cant-kick-self": "Nem rúghatod ki magad a csoportból",
"no-users-selected": "Nincs felhasználó kiválasztva",
"invalid-home-page-route": "Érvénytelen főoldal elérési útvonal",
- "invalid-session": "Eltérő munkamenet",
- "invalid-session-text": "A bejelentkezés munkamenete már nem aktív vagy már nem illik össze a szerverrel. Kérlek frissítsd az oldalt.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Nincs témakör kiválasztva",
"cant-move-to-same-topic": "Nem mozgathatsz hozzászólást azonos témakörbe!",
"cant-move-topic-to-same-category": "Nem mozgathatod a témakört azonos kategóriába!",
diff --git a/public/language/hu/flags.json b/public/language/hu/flags.json
index e2121af042..0c475a5ede 100644
--- a/public/language/hu/flags.json
+++ b/public/language/hu/flags.json
@@ -27,7 +27,7 @@
"filter-cid-all": "Minden kategória",
"apply-filters": "Szűrők alkalmazása",
"more-filters": "Több szűrő",
- "fewer-filters": "Fewer Filters",
+ "fewer-filters": "Kevesebb szűrő",
"quick-actions": "Gyors akciók",
"flagged-user": "Megjelölt felhasználó",
diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json
index 84910426bb..db470c45cc 100644
--- a/public/language/hu/notifications.json
+++ b/public/language/hu/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "A Users csv exportálva, kattints ide a letöltéshez",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "E-mail megerősítve",
"email-confirmed-message": "Köszönjük az e-mail címed megerősítését. A fiókod mostantól teljesen aktiválva van.",
"email-confirm-error-message": "Probléma lépett fel az e-mail címed megerősítésekor. Talán a kód érvénytelen volt vagy lejárt.",
diff --git a/public/language/hu/success.json b/public/language/hu/success.json
index f7cdaaeb19..5a2d590191 100644
--- a/public/language/hu/success.json
+++ b/public/language/hu/success.json
@@ -1,7 +1,7 @@
{
"success": "Sikeres",
"topic-post": "Sikeres hozzászólás.",
- "post-queued": "A hozzászólásod jóváhagyásra vár.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Sikeres hitelesítés",
"settings-saved": "Beállítások mentve!"
}
\ No newline at end of file
diff --git a/public/language/id/admin/manage/categories.json b/public/language/id/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/id/admin/manage/categories.json
+++ b/public/language/id/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/id/error.json b/public/language/id/error.json
index 57c474cd37..e81972811c 100644
--- a/public/language/id/error.json
+++ b/public/language/id/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json
index a4b823d82b..069a285f8b 100644
--- a/public/language/id/notifications.json
+++ b/public/language/id/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email telah Dikonfirmasi",
"email-confirmed-message": "Terimakasih telah melakukan validasi email. Akunmu saat ini telah aktif sepenuhnya.",
"email-confirm-error-message": "Terjadi masalah saat melakukan validasi emailmu. Mungkin terjadi kesalahan kode atau waktu habis.",
diff --git a/public/language/id/success.json b/public/language/id/success.json
index e73e61b7ff..266e5e27ad 100644
--- a/public/language/id/success.json
+++ b/public/language/id/success.json
@@ -1,7 +1,7 @@
{
"success": "Sukses",
"topic-post": "Kamu berhasil melakukan posting.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Otentikasi Sukses",
"settings-saved": "Pengaturan disimpan!"
}
\ No newline at end of file
diff --git a/public/language/it/admin/manage/categories.json b/public/language/it/admin/manage/categories.json
index 9664c1bc23..5166ed1b90 100644
--- a/public/language/it/admin/manage/categories.json
+++ b/public/language/it/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analitica",
"view-category": "Visualizza categoria",
"set-order": "Imposta ordine",
+ "set-order-help": "L'impostazione dell'ordine della categoria sposterà questa categoria in quell'ordine e aggiornerà l'ordine delle altre categorie, se necessario. L'ordine minimo è 1 che mette la categoria in cima.",
"select-category": "Seleziona Categoria",
"set-parent-category": "Imposta la Categoria Padre",
diff --git a/public/language/it/error.json b/public/language/it/error.json
index f2300f1783..70619300a5 100644
--- a/public/language/it/error.json
+++ b/public/language/it/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Non puoi espellerti dal gruppo",
"no-users-selected": "Nessun utente selezionato",
"invalid-home-page-route": "Percorso della pagina iniziale non valido",
- "invalid-session": "Discrepanza della sessione",
- "invalid-session-text": "Sembra che la tua sessione non sia più attiva, oppure non corrisponde con il server. Per favore ricarica la pagina.",
+ "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.",
+ "session-mismatch": "Mancata corrispondenza della sessione",
+ "session-mismatch-text": "Sembra che la tua sessione di accesso non corrisponda più al server. Si prega di aggiornare questa pagina.",
"no-topics-selected": "Nessuna discussione selezionata!",
"cant-move-to-same-topic": "Non puoi spostare il post nella stessa discussione!",
"cant-move-topic-to-same-category": "Non si può spostare la discussione nella stessa categoria!",
diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json
index d263fd1cb7..c6f6de144d 100644
--- a/public/language/it/notifications.json
+++ b/public/language/it/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 post esportati, clicca per scaricare",
"uploads-exported": "%1 caricamenti esportati, clicca per scaricare",
"users-csv-exported": "Utenti esportati in CSV, clicca per scaricare",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Il tuo post in coda è stato rifiutato.",
"email-confirmed": "Email Confermata",
"email-confirmed-message": "Grazie per aver validato la tua email. Il tuo account è ora completamente attivato.",
"email-confirm-error-message": "C'è stato un problema nella validazione del tuo indirizzo email. Potrebbe essere il codice non valido o scaduto.",
diff --git a/public/language/it/success.json b/public/language/it/success.json
index f75ae41f5a..d5d2534894 100644
--- a/public/language/it/success.json
+++ b/public/language/it/success.json
@@ -1,7 +1,7 @@
{
"success": "Riuscito",
"topic-post": "Hai postato correttamente.",
- "post-queued": "Il tuo post è in attesa di approvazione.",
+ "post-queued": "Il tuo post è in coda per l'approvazione. Riceverai una notifica quando sarà accettato o rifiutato.",
"authentication-successful": "Autenticazione Riuscita",
"settings-saved": "Impostazioni salvate!"
}
\ No newline at end of file
diff --git a/public/language/ja/admin/manage/categories.json b/public/language/ja/admin/manage/categories.json
index 2e5f25ff97..388c342602 100644
--- a/public/language/ja/admin/manage/categories.json
+++ b/public/language/ja/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "カテゴリを選択",
"set-parent-category": "親カテゴリとして設定",
diff --git a/public/language/ja/error.json b/public/language/ja/error.json
index 466281e762..c217b344a7 100644
--- a/public/language/ja/error.json
+++ b/public/language/ja/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "あなたは、グループから自分自身をキックすることが出来ません",
"no-users-selected": "ユーザー(s)が選択されていません",
"invalid-home-page-route": "ホームページのルートが無効",
- "invalid-session": "セッションの不一致",
- "invalid-session-text": "ログインセッションの期限切れ、またはサーバーとの未接続が長すぎると思われます。このページを更新してみてください。",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "スレッドが選択されていません!!",
"cant-move-to-same-topic": "同じスレッドに投稿を移動することはできません!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json
index 07b5857a37..1815a37f9e 100644
--- a/public/language/ja/notifications.json
+++ b/public/language/ja/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Eメールが確認されました",
"email-confirmed-message": "メールアドレス検証をして頂き、ありがとうございます。あなたのアカウントは完全にアクティブになりました。",
"email-confirm-error-message": "あなたのEメールアドレス検証に問題があります。コードが無効か、期限切れです。",
diff --git a/public/language/ja/success.json b/public/language/ja/success.json
index 44a88b9bd1..ad6f53e5ae 100644
--- a/public/language/ja/success.json
+++ b/public/language/ja/success.json
@@ -1,7 +1,7 @@
{
"success": "成功しました",
"topic-post": "投稿に成功しました",
- "post-queued": "あなたの投稿は承認待ちです。",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "認証に成功しました",
"settings-saved": "設定を保存しました。"
}
\ No newline at end of file
diff --git a/public/language/ko/admin/extend/plugins.json b/public/language/ko/admin/extend/plugins.json
index 2f9e6006fe..aea2277f7e 100644
--- a/public/language/ko/admin/extend/plugins.json
+++ b/public/language/ko/admin/extend/plugins.json
@@ -39,7 +39,7 @@
"alert.upgraded": "플러그인 업그레이드 완료",
"alert.installed": "플러그인 설치 완료",
"alert.uninstalled": "플러그인 제거 완료",
- "alert.activate-success": "Please rebuild and restart your NodeBB to fully activate this plugin",
+ "alert.activate-success": "해당 플러그인을 완벽하게 활성화하기 위해 NodeBB를 리빌드하고 다시 시작해주세요.",
"alert.deactivate-success": "플러그인이 성공적으로 비활성화됐습니다.",
"alert.upgrade-success": "이 플러그인을 업그레이드 하려면 NodeBB를 리빌드하고 다시 시작해주세요.",
"alert.install-success": "플러그인이 성공적으로 설치됐습니다. 플러그인을 활성화 해주세요.",
diff --git a/public/language/ko/admin/manage/categories.json b/public/language/ko/admin/manage/categories.json
index 383856822a..692d1ee508 100644
--- a/public/language/ko/admin/manage/categories.json
+++ b/public/language/ko/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "애널리틱스",
"view-category": "카테고리 보기",
"set-order": "순서 설정",
+ "set-order-help": "카테고리의 순서를 설정하면 해당 위치로 순서가 변경되며 다른 카테고리의 순서도 함께 변경됩니다. 최소 설정값은 1이며 최상단에 위치됩니다.",
"select-category": "카테고리 선택",
"set-parent-category": "상위 카테고리 설정",
diff --git a/public/language/ko/admin/settings/uploads.json b/public/language/ko/admin/settings/uploads.json
index fdd297a6ca..9c589448e9 100644
--- a/public/language/ko/admin/settings/uploads.json
+++ b/public/language/ko/admin/settings/uploads.json
@@ -21,9 +21,9 @@
"topic-thumb-size": "화제 썸네일 크기",
"allowed-file-extensions": "사용 가능한 파일 확장자",
"allowed-file-extensions-help": "파일 확장자 목록을 콤마(,) 로 구분지어 입력해주세요.(예: pdf, xls, doc) 빈칸으로 남기면 모든 확장자를 허용합니다. ",
- "upload-limit-threshold": "Rate limit user uploads to:",
- "upload-limit-threshold-per-minute": "Per %1 Minute",
- "upload-limit-threshold-per-minutes": "Per %1 Minutes",
+ "upload-limit-threshold": "업로드 속도 제한:",
+ "upload-limit-threshold-per-minute": "%1분 기준",
+ "upload-limit-threshold-per-minutes": "%1분 기준",
"profile-avatars": "프로필 사진",
"allow-profile-image-uploads": "사용자들이 프로필 사진 업로드 하는것을 허용",
"convert-profile-image-png": "업로드 된 프로필 사진 확장자를 PNG로 변환",
diff --git a/public/language/ko/error.json b/public/language/ko/error.json
index 111e01cc83..cc71f95327 100644
--- a/public/language/ko/error.json
+++ b/public/language/ko/error.json
@@ -89,7 +89,7 @@
"file-too-big": "업로드 가능한 파일크기는 최대 %1 KB 입니다. 파일의 용량을 줄이거나 압축을 활용하세요.",
"guest-upload-disabled": "비회원의 파일 업로드는 제한되어 있습니다.",
"cors-error": "잘못 구성된 CORS로 인해 이미지를 업로드 할 수 없습니다.",
- "upload-ratelimit-reached": "You have uploaded too many files at one time. Please try again later.",
+ "upload-ratelimit-reached": "한 번에 너무 많은 파일을 업로드하셨습니다. 나중에 다시 시도해주세요.",
"scheduling-to-past": "내일 이후의 날짜를 선택해주세요.",
"invalid-schedule-date": "적합한 형식의 날짜와 시간을 입력해주세요.",
"cant-pin-scheduled": "예약된 화제는 상단에 고정(해제)할 수 없습니다.",
@@ -174,8 +174,10 @@
"cant-kick-self": "스스로 이 그룹을 탈퇴할 수 없습니다.",
"no-users-selected": "선택된 사용자가 없습니다.",
"invalid-home-page-route": "올바르지 않은 홈페이지 경로입니다. ",
- "invalid-session": "일치하지 않는 세션입니다.",
- "invalid-session-text": "로그인 세션이 비활성화 되었거나 서버와 일치하지 않습니다. 페이지를 새로고침 해주세요.",
+ "invalid-session": "세션 오류",
+ "invalid-session-text": "로그인 세션이 종료됐습니다. 페이지를 새로고침 해주세요.",
+ "session-mismatch": "세션 불일치",
+ "session-mismatch-text": "로그인 세션이 서버와 일치하지 않습니다. 페이지를 새로고침 해주세요.",
"no-topics-selected": "선택된 화제가 없습니다!",
"cant-move-to-same-topic": "동일한 화제로 포스트를 이동할 수 없습니다!",
"cant-move-topic-to-same-category": "동일한 카테고리로 화제를 이동할 수 없습니다!",
diff --git a/public/language/ko/flags.json b/public/language/ko/flags.json
index aa7e0b7a31..df0854692f 100644
--- a/public/language/ko/flags.json
+++ b/public/language/ko/flags.json
@@ -26,8 +26,8 @@
"filter-quick-mine": "나에게 배정된 신고",
"filter-cid-all": "모든 카테고리",
"apply-filters": "필터 적용",
- "more-filters": "필터 추가",
- "fewer-filters": "Fewer Filters",
+ "more-filters": "더 많은 필터",
+ "fewer-filters": "기본 필터",
"quick-actions": "빠른 신고",
"flagged-user": "신고된 사용자",
diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json
index a274341cf0..7634e08858 100644
--- a/public/language/ko/notifications.json
+++ b/public/language/ko/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1의 포스트 내보내기 완료, 클릭해서 다운로드 ",
"uploads-exported": "%1의 업로드 내보내기 완료, 클릭해서 다운로드 ",
"users-csv-exported": "사용자 csv 내보내기 완료, 클릭해서 다운로드",
+ "post-queue-accepted": "게시 대기 중인 게시물이 승인되었습니다. 여기를 눌러 포스트를 확인할 수 있습니다.",
+ "post-queue-rejected": "게시 대기 중인 게시물이 거절되었습니다.",
"email-confirmed": "이메일 인증이 완료되었습니다.",
"email-confirmed-message": "이메일을 인증해주셔서 감사합니다. 계정이 완전히 활성화되었습니다.",
"email-confirm-error-message": "이메일 주소를 인증하지 못했습니다. 코드가 올바르지 않거나 만료되었을 수 있습니다.",
diff --git a/public/language/ko/success.json b/public/language/ko/success.json
index 0bf47a388c..a627bcb5af 100644
--- a/public/language/ko/success.json
+++ b/public/language/ko/success.json
@@ -1,7 +1,7 @@
{
"success": "성공",
"topic-post": "성공적으로 작성했습니다.",
- "post-queued": "글이 승인 대기 중입니다.",
+ "post-queued": "포스트가 게시 대기열에 등록되었습니다. 승인 혹은 거절될 경우 알림이 전송됩니다.",
"authentication-successful": "인증에 성공했습니다.",
"settings-saved": "설정이 저장되었습니다!"
}
\ No newline at end of file
diff --git a/public/language/lt/admin/manage/categories.json b/public/language/lt/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/lt/admin/manage/categories.json
+++ b/public/language/lt/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/lt/error.json b/public/language/lt/error.json
index 1a0e0bfe86..93cf27e543 100644
--- a/public/language/lt/error.json
+++ b/public/language/lt/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Negalite išmesti savęs iš grupės",
"no-users-selected": "Nepasirinktas joks vartotojas",
"invalid-home-page-route": "Blogas kelias į pagrindinį puslapį",
- "invalid-session": "Sesijų Nesutapimas",
- "invalid-session-text": "Panašu, jog jūsų prisijungimo sesija nebeaktyvi arba nesutampa su serverio. Prašome perkrauti puslapį.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Nepasirinkta jokia tema!",
"cant-move-to-same-topic": "Negalima perkelti įrašo į tą pačią temą!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json
index 3177907282..3ab7f45e3c 100644
--- a/public/language/lt/notifications.json
+++ b/public/language/lt/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "El. paštas patvirtintas",
"email-confirmed-message": "Dėkojame už el. pašto patvirtinimą. Jūsų paskyra pilnai aktyvuota.",
"email-confirm-error-message": "Įvyko klaida mėginant patvirtinti Jūsų el. pašto adresą. Galbūt kodas yra neteisingas, arba nebegalioajantis.",
diff --git a/public/language/lt/success.json b/public/language/lt/success.json
index 91c9e63dba..818476c6a5 100644
--- a/public/language/lt/success.json
+++ b/public/language/lt/success.json
@@ -1,7 +1,7 @@
{
"success": "Pavyko",
"topic-post": "Sėkmingai parašėte pranešimą",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Autentifikacija sėkminga",
"settings-saved": "Nustatymai išsaugoti!"
}
\ No newline at end of file
diff --git a/public/language/lv/admin/manage/categories.json b/public/language/lv/admin/manage/categories.json
index a08912e4b7..050b03d33a 100644
--- a/public/language/lv/admin/manage/categories.json
+++ b/public/language/lv/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Atlasīt kategoriju",
"set-parent-category": "Iestatīt virskategoriju",
diff --git a/public/language/lv/error.json b/public/language/lv/error.json
index f10ffee6ca..d54a6c46af 100644
--- a/public/language/lv/error.json
+++ b/public/language/lv/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Nevar sevi izslēgt no grupas",
"no-users-selected": "Nav atlasīts neviens lietotājs(-i)",
"invalid-home-page-route": "Nederīgs sākumlapas ceļš",
- "invalid-session": "Sesijas nesakrīt",
- "invalid-session-text": "Izskatās, ka Tava sesija vairs nav aktīva vai vairs nesakrīt ar serveri. Lūdzu, atsvaidzināt šo lapu.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Nav atlasīts neviens temats",
"cant-move-to-same-topic": "Nevar pārnest uz savu pašu tematu!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/lv/notifications.json b/public/language/lv/notifications.json
index 40601196ef..9f7d4b78af 100644
--- a/public/language/lv/notifications.json
+++ b/public/language/lv/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "E-pasta adrese ir apstiprināta",
"email-confirmed-message": "Paldies, ka apstiprināji e-pasta adresi. Tavs konts tagad ir pilnībā aktivizēts.",
"email-confirm-error-message": "Tavā e-pasta adreses apstiprināšanā radās problēma. Iespējams, kods ir nederīgs vai ir beidzies derīguma termiņš.",
diff --git a/public/language/lv/success.json b/public/language/lv/success.json
index 9c9cd08e74..e44895da00 100644
--- a/public/language/lv/success.json
+++ b/public/language/lv/success.json
@@ -1,7 +1,7 @@
{
"success": "Veiksme",
"topic-post": "Veiksmīgi publicēts.",
- "post-queued": "Tavs raksts gaida apstiprināšanu.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Veiksmīgi autentificējies",
"settings-saved": "Iestatījumi saglabāti!"
}
\ No newline at end of file
diff --git a/public/language/ms/admin/manage/categories.json b/public/language/ms/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/ms/admin/manage/categories.json
+++ b/public/language/ms/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/ms/error.json b/public/language/ms/error.json
index ee09559819..c9eeead36f 100644
--- a/public/language/ms/error.json
+++ b/public/language/ms/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route",
- "invalid-session": "Session Mismatch",
- "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json
index 89031d7e50..996299be13 100644
--- a/public/language/ms/notifications.json
+++ b/public/language/ms/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Emel Disahkan",
"email-confirmed-message": "Terima kasih kerana mengesahkan emel anda. Akaun anda telah diaktifkan sepenuhnya.",
"email-confirm-error-message": "Berlaku masalah semasa mengesahkan emel anda. Mungkin kod tidak sah atau tamat tempoh.",
diff --git a/public/language/ms/success.json b/public/language/ms/success.json
index bde8980ba9..e58458ce99 100644
--- a/public/language/ms/success.json
+++ b/public/language/ms/success.json
@@ -1,7 +1,7 @@
{
"success": "Berjaya",
"topic-post": "Kiriman anda berjaya dihantar.",
- "post-queued": "Your post is queued for approval.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Pengesahan Berjaya",
"settings-saved": "Tetapan disimpan!"
}
\ No newline at end of file
diff --git a/public/language/nb/admin/admin.json b/public/language/nb/admin/admin.json
index 1c96a5c8cc..3c2646fa79 100644
--- a/public/language/nb/admin/admin.json
+++ b/public/language/nb/admin/admin.json
@@ -1,7 +1,7 @@
{
- "alert.confirm-rebuild-and-restart": "Are you sure you wish to rebuild and restart NodeBB?",
+ "alert.confirm-rebuild-and-restart": "Er du sikker på at du vil gjenoppbygge og restarte NodeBB?",
"alert.confirm-restart": "Er du sikker på at du ønsker å restarte NoddeBB?",
- "acp-title": "%1 | NodeBB Admin Control Panel",
- "settings-header-contents": "Contents"
+ "acp-title": "%1 | NodeBB Admin Kontrollpanel",
+ "settings-header-contents": "Innhold"
}
\ No newline at end of file
diff --git a/public/language/nb/admin/advanced/logs.json b/public/language/nb/admin/advanced/logs.json
index b9de400e1c..ba29274563 100644
--- a/public/language/nb/admin/advanced/logs.json
+++ b/public/language/nb/admin/advanced/logs.json
@@ -1,7 +1,7 @@
{
- "logs": "Logs",
- "control-panel": "Logs Control Panel",
- "reload": "Reload Logs",
- "clear": "Clear Logs",
- "clear-success": "Logs Cleared!"
+ "logs": "Logger",
+ "control-panel": "Kontrollpanel for logg",
+ "reload": "Last inn logg på nytt",
+ "clear": "Tøm logg",
+ "clear-success": "Logg er tømt!"
}
\ No newline at end of file
diff --git a/public/language/nb/admin/appearance/themes.json b/public/language/nb/admin/appearance/themes.json
index 597830f379..fcb509e365 100644
--- a/public/language/nb/admin/appearance/themes.json
+++ b/public/language/nb/admin/appearance/themes.json
@@ -1,11 +1,11 @@
{
"checking-for-installed": "Checking for installed themes...",
- "homepage": "Homepage",
- "select-theme": "Select Theme",
- "current-theme": "Current Theme",
- "no-themes": "No installed themes found",
- "revert-confirm": "Are you sure you wish to restore the default NodeBB theme?",
- "theme-changed": "Theme Changed",
- "revert-success": "You have successfully reverted your NodeBB back to it's default theme.",
- "restart-to-activate": "Please rebuild and restart your NodeBB to fully activate this theme."
+ "homepage": "Hjemmeside",
+ "select-theme": "Velg tema",
+ "current-theme": "Nåværende tema",
+ "no-themes": "Ingen installerte temaer funnet",
+ "revert-confirm": "Er du sikker på at du vil gjenopprette standard NodeBB-tema?",
+ "theme-changed": "Tema endret",
+ "revert-success": "Du har tilbakestilt NodeBB til standardtemaet.",
+ "restart-to-activate": "Vennligst bygg og start NodeBB for å aktivere dette temaet fullt ut."
}
\ No newline at end of file
diff --git a/public/language/nb/admin/dashboard.json b/public/language/nb/admin/dashboard.json
index 0de31d4917..2f744a1182 100644
--- a/public/language/nb/admin/dashboard.json
+++ b/public/language/nb/admin/dashboard.json
@@ -63,11 +63,11 @@
"user-presence": "User Presence",
"on-categories": "On categories list",
"reading-posts": "Reading posts",
- "browsing-topics": "Browsing topics",
+ "browsing-topics": "Blar i tråder",
"recent": "Recent",
"unread": "Unread",
- "high-presence-topics": "High Presence Topics",
+ "high-presence-topics": "Høyt synlige tråder",
"graphs.page-views": "Page Views",
"graphs.page-views-registered": "Page Views Registered",
diff --git a/public/language/nb/admin/manage/categories.json b/public/language/nb/admin/manage/categories.json
index db353a8ce2..28d2bc5d4d 100644
--- a/public/language/nb/admin/manage/categories.json
+++ b/public/language/nb/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
@@ -65,14 +66,14 @@
"analytics.title": "Analytics for \"%1\" category",
"analytics.pageviews-hourly": "Figure 1 – Hourly page views for this category",
"analytics.pageviews-daily": "Figure 2 – Daily page views for this category",
- "analytics.topics-daily": "Figure 3 – Daily topics created in this category",
+ "analytics.topics-daily": "Figur 3 – Daglige tråder publisert i denne kategorien",
"analytics.posts-daily": "Figure 4 – Daily posts made in this category",
"alert.created": "Created",
"alert.create-success": "Category successfully created!",
"alert.none-active": "You have no active categories.",
"alert.create": "Create a Category",
- "alert.confirm-purge": "
Do you really want to purge this category \"%1\"?
Purging a category will remove all topics and posts, and delete the category from the database. If you want to remove a category temporarily, you'll want to \"disable\" the category instead.
", + "alert.confirm-purge": "Vil du virkelig renske kategorien \"%1\"?
Rensking av en kategori vil fjerne alle tråder og innlegg, og slette kategorien fra databasen. Hvis du vil fjerne en kategori midlertidig, vil du \"deaktivere\" kategorien i stedet.
", "alert.purge-success": "Category purged!", "alert.copy-success": "Settings Copied!", "alert.set-parent-category": "Set Parent Category", diff --git a/public/language/nb/admin/manage/tags.json b/public/language/nb/admin/manage/tags.json index 3976ea97d7..21b333056d 100644 --- a/public/language/nb/admin/manage/tags.json +++ b/public/language/nb/admin/manage/tags.json @@ -1,5 +1,5 @@ { - "none": "Your forum does not have any topics with tags yet.", + "none": "Forumet ditt har ingen tråder med emneord.", "bg-color": "Background Colour", "text-color": "Text Colour", "create-modify": "Create & Modify Tags", diff --git a/public/language/nb/admin/manage/users.json b/public/language/nb/admin/manage/users.json index 76488baeb7..7798e70d73 100644 --- a/public/language/nb/admin/manage/users.json +++ b/public/language/nb/admin/manage/users.json @@ -88,7 +88,7 @@ "alerts.validate-email-success": "Emails validated", "alerts.validate-force-password-reset-success": "User(s) passwords have been reset and their existing sessions have been revoked.", "alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?", - "alerts.confirm-delete": "Warning!Do you really want to delete user(s)?
This action is not reversible! Only the user account will be deleted, their posts and topics will remain.
", + "alerts.confirm-delete": "Advarsel!Vil du virkelig slette bruker(e)?
Denne handlingen kan ikke angres! Kun brukerkontoen vil bli slettet, deres innlegg og tråder påvirkes ikke.
", "alerts.delete-success": "User(s) Deleted!", "alerts.confirm-delete-content": "Warning!Do you really want to delete these user(s) content?
This action is not reversible! The users' accounts will remain, but their posts and topics will be deleted.
", "alerts.delete-content-success": "User(s) Content Deleted!", diff --git a/public/language/nb/admin/settings/guest.json b/public/language/nb/admin/settings/guest.json index 75d44f37e4..ab416c7889 100644 --- a/public/language/nb/admin/settings/guest.json +++ b/public/language/nb/admin/settings/guest.json @@ -1,7 +1,7 @@ { - "settings": "Settings", + "settings": "Innstillinger ", "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", - "reply-notifications.enabled": "Allow guests to generate reply notifications" + "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", + "reply-notifications.enabled": "La gjestene generere varsler på svar" } \ No newline at end of file diff --git a/public/language/nb/admin/settings/pagination.json b/public/language/nb/admin/settings/pagination.json index 3bf306b2f9..2fb3343b1d 100644 --- a/public/language/nb/admin/settings/pagination.json +++ b/public/language/nb/admin/settings/pagination.json @@ -1,12 +1,12 @@ { "pagination": "Pagination Settings", - "enable": "Paginate topics and posts instead of using infinite scroll.", + "enable": "Paginer tråder og innlegg istedet for å bruke uendelig scrolling.", "posts": "Post Pagination", - "topics": "Topic Pagination", + "topics": "Trådpaginering", "posts-per-page": "Posts per Page", "max-posts-per-page": "Maximum posts per page", "categories": "Category Pagination", - "topics-per-page": "Topics per Page", + "topics-per-page": "Tråder per side", "max-topics-per-page": "Maximum topics per page", "categories-per-page": "Categories per page" } \ No newline at end of file diff --git a/public/language/nb/admin/settings/post.json b/public/language/nb/admin/settings/post.json index 27493aafbd..f2b9a5e674 100644 --- a/public/language/nb/admin/settings/post.json +++ b/public/language/nb/admin/settings/post.json @@ -5,7 +5,7 @@ "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", "sorting.most-posts": "Most Posts", - "sorting.topic-default": "Default Topic Sorting", + "sorting.topic-default": "Standard trådsortering", "length": "Post Length", "post-queue": "Post Queue", "restrictions": "Posting Restrictions", @@ -22,7 +22,7 @@ "restrictions.seconds-before-new": "Seconds before a new user can make their first post", "restrictions.seconds-edit-after": "Number of seconds a post remains editable (set to 0 to disable)", "restrictions.seconds-delete-after": "Number of seconds a post remains deletable (set to 0 to disable)", - "restrictions.replies-no-delete": "Number of replies after users are disallowed to delete their own topics (set to 0 to disable)", + "restrictions.replies-no-delete": "Antall svar i tråd før bruker ikke lenger får lov til å slette egen tråd (sett til 0 for å deaktivere)", "restrictions.min-title-length": "Minimum Title Length", "restrictions.max-title-length": "Maximum Title Length", "restrictions.min-post-length": "Minimum Post Length", @@ -42,7 +42,7 @@ "teaser.first": "First", "unread": "Unread Settings", "unread.cutoff": "Unread cutoff days", - "unread.min-track-last": "Minimum posts in topic before tracking last read", + "unread.min-track-last": "Minimum antall innlegg i tråd før registrering av sist lest", "recent": "Recent Settings", "recent.max-topics": "Maximum topics on /recent", "recent.categoryFilter.disable": "Disable filtering of topics in ignored categories on the /recent page", @@ -52,7 +52,7 @@ "signature.no-images": "Disable images in signatures", "signature.max-length": "Maximum Signature Length", "composer": "Composer Settings", - "composer-help": "The following settings govern the functionality and/or appearance of the post composer shown\n\t\t\t\tto users when they create new topics, or reply to existing topics.", + "composer-help": "Følgende innstillinger styrer funksjonaliteten og/ eller utseendet til skriveverktøyet vist\n\t\t\t\ttil brukere når de lager nye tråder, eller svarer på eksisterende tråder.", "composer.show-help": "Show \"Help\" tab", "composer.enable-plugin-help": "Allow plugins to add content to the help tab", "composer.custom-help": "Custom Help Text", diff --git a/public/language/nb/admin/settings/tags.json b/public/language/nb/admin/settings/tags.json index 080010f6f0..57c22ae822 100644 --- a/public/language/nb/admin/settings/tags.json +++ b/public/language/nb/admin/settings/tags.json @@ -3,10 +3,10 @@ "link-to-manage": "Manage Tags", "system-tags": "System Tags", "system-tags-help": "Only privileged users will be able to use these tags.", - "min-per-topic": "Minimum Tags per Topic", - "max-per-topic": "Maximum Tags per Topic", + "min-per-topic": "Minimalt antall emneord per tråd", + "max-per-topic": "Maksimalt antall emneord per tråd", "min-length": "Minimum Tag Length", "max-length": "Maximum Tag Length", - "related-topics": "Related Topics", - "max-related-topics": "Maximum related topics to display (if supported by theme)" + "related-topics": "Relaterte tråder", + "max-related-topics": "Maks antall relaterte tråder å vise (hvis støttet av tema)" } \ No newline at end of file diff --git a/public/language/nb/admin/settings/user.json b/public/language/nb/admin/settings/user.json index 48be13b75e..37f0b6fdfe 100644 --- a/public/language/nb/admin/settings/user.json +++ b/public/language/nb/admin/settings/user.json @@ -1,84 +1,84 @@ { - "authentication": "Authentication", - "require-email-confirmation": "Require Email Confirmation", - "email-confirm-interval": "User may not resend a confirmation email until", - "email-confirm-email2": "minutes have elapsed", - "allow-login-with": "Allow login with", - "allow-login-with.username-email": "Username or Email", - "allow-login-with.username": "Username Only", - "allow-login-with.email": "Email Only", - "account-settings": "Account Settings", - "gdpr_enabled": "Enable GDPR consent collection", - "gdpr_enabled_help": "When enabled, all new registrants will be required to explicitly give consent for data collection and usage under the General Data Protection Regulation (GDPR). Note: Enabling GDPR does not force pre-existing users to provide consent. To do so, you will need to install the GDPR plugin.", - "disable-username-changes": "Disable username changes", - "disable-email-changes": "Disable email changes", - "disable-password-changes": "Disable password changes", - "allow-account-deletion": "Allow account deletion", - "hide-fullname": "Hide fullname from users", - "hide-email": "Hide email from users", - "show-fullname-as-displayname": "Show user's full name as their display name if available", - "themes": "Themes", - "disable-user-skins": "Prevent users from choosing a custom skin", - "account-protection": "Account Protection", - "admin-relogin-duration": "Admin relogin duration (minutes)", - "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", - "login-attempts": "Login attempts per hour", - "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", - "lockout-duration": "Account Lockout Duration (minutes)", - "login-days": "Days to remember user login sessions", - "password-expiry-days": "Force password reset after a set number of days", - "session-time": "Session Time", - "session-time-days": "Days", - "session-time-seconds": "Seconds", - "session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no seconds value we fall back to days. If there is no days value we default to 14 days.", - "online-cutoff": "Minutes after user is considered inactive", - "online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.", - "registration": "User Registration", - "registration-type": "Registration Type", - "registration-approval-type": "Registration Approval Type", + "authentication": "Autentisering ", + "require-email-confirmation": "Krever bekreftelse via e-post", + "email-confirm-interval": "Brukeren kan ikke sende en bekreftelses-e-post på nytt før", + "email-confirm-email2": "minutter har gått", + "allow-login-with": "Tillat innlogging med", + "allow-login-with.username-email": "Brukernavn eller e-post", + "allow-login-with.username": "Kun brukernavn", + "allow-login-with.email": "Kun e-post", + "account-settings": "Kontoinnstillinger ", + "gdpr_enabled": "Aktiver innhenting av GDPR-samtykke", + "gdpr_enabled_help": "Når aktivert, vil alle nye registranter være pålagt å eksplisitt gi samtykke til datainnsamling og behandling under Personvernforordningen (GDPR). Merk: Aktivering av GDPR tvinger ikke eksisterende brukere til å gi samtykke. For å gjøre dette, må du installere GDPR-programutvidelse. ", + "disable-username-changes": "Deaktiver endringer for brukernavn", + "disable-email-changes": "Deaktiver endringer for e-post", + "disable-password-changes": "Deaktiver endringer for passord", + "allow-account-deletion": "Tillat kontosletting ", + "hide-fullname": "Skjul fullt navn for andre brukere", + "hide-email": "Skjul e-post for brukere", + "show-fullname-as-displayname": "Vis brukerens fulle navn som navn ved visning hvis tilgjengelig", + "themes": "Temaer", + "disable-user-skins": "Forhindre brukere fra å velge en tilpasset skin", + "account-protection": "Kontobeskyttelse", + "admin-relogin-duration": "Innloggingstid for administrator (minutter)", + "admin-relogin-duration-help": "Etter en angitt tid for å få tilgang til administrasjon-delen, vil det kreve pålogging på nytt, sett til 0 for å deaktivere", + "login-attempts": "Innloggingsforsøk per time", + "login-attempts-help": "Hvis påloggingsforsøk til brukerens konto overskrider denne terskelen, vil brukerkontoen bli låst i en forhåndskonfigurert tid", + "lockout-duration": "Varighet på kontosperring (minutter)", + "login-days": "Dager å huske brukerinnloggingsøkter på", + "password-expiry-days": "Tving passordtilbakestillingen etter angitt antall dager", + "session-time": "Tidssesjon ", + "session-time-days": "Dager", + "session-time-seconds": "Sekunder", + "session-time-help": "Disse verdiene brukes for å følge med på hvor lenge en bruker er logget inn når de sjekker "Remember Me" ved pålogging. Merk at kun en av disse verdiene brukes. Hvis det ikke er sekundverdi bruker vi dager. Hvis det ikke er noen verdier for dager faller verdien tilbake til 14 dager.", + "online-cutoff": "Minutter etter at bruker er ansett som inaktiv ", + "online-cutoff-help": "Hvis brukeren ikke utfører noen handlinger for den bestemte varigheten, anses de som inaktive, og de mottar ikke sanntidsoppdateringer.", + "registration": "Brukerregistrering", + "registration-type": "Registreringstype", + "registration-approval-type": "Registrering godkjenningstype", "registration-type.normal": "Normal", - "registration-type.admin-approval": "Admin Approval", - "registration-type.admin-approval-ip": "Admin Approval for IPs", - "registration-type.invite-only": "Invite Only", - "registration-type.admin-invite-only": "Admin Invite Only", - "registration-type.disabled": "No registration", - "registration-type.help": "Normal - Users can register from the /register page.192.168.100.0/22).",
"hint-2": "You can add in comments by starting lines with the # symbol.",
@@ -15,5 +15,5 @@
"analytics.blacklist-hourly": "Figure 1 – Blacklist hits per hour",
"analytics.blacklist-daily": "Figure 2 – Blacklist hits per day",
- "ip-banned": "IP banned"
+ "ip-banned": "IP er utestengt"
}
\ No newline at end of file
diff --git a/public/language/nb/login.json b/public/language/nb/login.json
index 0622fd53e9..ef7d3a0926 100644
--- a/public/language/nb/login.json
+++ b/public/language/nb/login.json
@@ -5,7 +5,7 @@
"remember_me": "Husk meg?",
"forgot_password": "Glemt passord?",
"alternative_logins": "Alternativ innlogging",
- "failed_login_attempt": "Login Unsuccessful",
+ "failed_login_attempt": "Innlogging misslyktes",
"login_successful": "Du har blitt logget inn!",
"dont_have_account": "Har du ikke en konto?",
"logged-out-due-to-inactivity": "You have been logged out of the Admin Control Panel due to inactivity",
diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json
index c6de7300ac..02bf041915 100644
--- a/public/language/nb/modules.json
+++ b/public/language/nb/modules.json
@@ -1,7 +1,7 @@
{
- "chat.chatting_with": "Chat with",
+ "chat.chatting_with": "Chat med",
"chat.placeholder": "Skriv chat-melding her, trykk enter for å sende",
- "chat.scroll-up-alert": "You are looking at older messages, click here to go to most recent message.",
+ "chat.scroll-up-alert": "Du ser på eldre meldinger, klikk her for å gå til siste melding",
"chat.send": "Send",
"chat.no_active": "Du har ingen aktive chatter.",
"chat.user_typing": "%1 skriver ...",
@@ -13,18 +13,18 @@
"chat.recent-chats": "Nylige chatter",
"chat.contacts": "Kontakter",
"chat.message-history": "Meldingshistorikk",
- "chat.message-deleted": "Message Deleted",
- "chat.options": "Chat options",
- "chat.pop-out": "Pop-out chat",
- "chat.minimize": "Minimize",
+ "chat.message-deleted": "Melding slettet",
+ "chat.options": "Alternativer for chatt",
+ "chat.pop-out": "Pop-out chatt",
+ "chat.minimize": "Mimimer",
"chat.maximize": "Maksimer",
"chat.seven_days": "7 dager",
"chat.thirty_days": "30 dager",
"chat.three_months": "3 måneder",
- "chat.delete_message_confirm": "Are you sure you wish to delete this message?",
- "chat.retrieving-users": "Retrieving users...",
+ "chat.delete_message_confirm": "Er du sikker på at du vil slette denne meldingen?",
+ "chat.retrieving-users": "Henter brukere ...",
"chat.manage-room": "Manage Chat Room",
- "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.",
+ "chat.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.rename-room": "Rename Room",
"chat.rename-placeholder": "Enter your room name here",
@@ -58,13 +58,13 @@
"composer.upload-picture": "Upload Image",
"composer.upload-file": "Upload File",
"composer.zen_mode": "Zen Mode",
- "composer.select_category": "Select a category",
+ "composer.select_category": "Velg en kategori",
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
"composer.schedule-for": "Schedule topic for",
"composer.schedule-date": "Date",
"composer.schedule-time": "Time",
"composer.cancel-scheduling": "Cancel Scheduling",
- "composer.set-schedule-date": "Set Date",
+ "composer.set-schedule-date": "Angitt dato",
"bootbox.ok": "OK",
"bootbox.cancel": "Avbryt",
"bootbox.confirm": "Bekreft",
@@ -74,7 +74,7 @@
"thumbs.modal.title": "Manage topic thumbnails",
"thumbs.modal.no-thumbs": "No thumbnails found.",
"thumbs.modal.resize-note": "Note: This forum is configured to resize topic thumbnails down to a maximum width of %1px",
- "thumbs.modal.add": "Add thumbnail",
- "thumbs.modal.remove": "Remove thumbnail",
- "thumbs.modal.confirm-remove": "Are you sure you want to remove this thumbnail?"
+ "thumbs.modal.add": "Legg til miniatyrbilde",
+ "thumbs.modal.remove": "Fjern miniatyrbilde ",
+ "thumbs.modal.confirm-remove": "Er du sikker på at du vil fjerne dette miniatyrbilde? "
}
\ No newline at end of file
diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json
index bdcca81501..15ec6a34b4 100644
--- a/public/language/nb/notifications.json
+++ b/public/language/nb/notifications.json
@@ -5,68 +5,70 @@
"mark_all_read": "Merk alle varsler som lest",
"back_to_home": "Tilbake til %1",
"outgoing_link": "Utgående link",
- "outgoing_link_message": "You are now leaving %1",
+ "outgoing_link_message": "Du forlater nå %1",
"continue_to": "Fortsett til %1",
"return_to": "Gå tilbake til %1",
- "new_notification": "You have a new notification",
+ "new_notification": "Du har en ny varsling",
"you_have_unread_notifications": "Du har uleste varsler.",
- "all": "All",
- "topics": "Topics",
- "replies": "Replies",
- "chat": "Chats",
- "follows": "Follows",
- "upvote": "Upvotes",
- "new-flags": "New Flags",
- "my-flags": "Flags assigned to me",
- "bans": "Bans",
+ "all": "Alle",
+ "topics": "Emner",
+ "replies": "Svar",
+ "chat": "Samtaler",
+ "follows": "Følger",
+ "upvote": "Oppstemmer",
+ "new-flags": "Nye flagg",
+ "my-flags": "Flagg som er tildelt til meg",
+ "bans": "Forbud",
"new_message_from": "Ny melding fra %1",
"upvoted_your_post_in": "%1 har stemt opp innlegget ditt i %2.",
- "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
- "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
- "moved_your_post": "%1 has moved your post to %2",
- "moved_your_topic": "%1 has moved %2",
+ "upvoted_your_post_in_dual": "%1 og 2% har stemt opp innlegget ditt i %3.",
+ "upvoted_your_post_in_multiple": "%1 og 2% har stemt opp innlegget ditt i %3.",
+ "moved_your_post": "%1 har flyttet innlegget ditt til %2.",
+ "moved_your_topic": "%1 har flyttet %2",
"user_flagged_post_in": "%1 har flagget et innlegg i %2",
"user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
- "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
- "user_flagged_user": "%1 flagged a user profile (%2)",
- "user_flagged_user_dual": "%1 and %2 flagged a user profile (%3)",
- "user_flagged_user_multiple": "%1 and %2 others flagged a user profile (%3)",
+ "user_flagged_post_in_multiple": "%1 og %2 har flagget et innlegg i %3",
+ "user_flagged_user": "%1 flagget en brukerprofil (%2)",
+ "user_flagged_user_dual": "%1 og 2% har flagget en brukerprofil (%3)",
+ "user_flagged_user_multiple": "%1 og %2 andre flagget en brukerprofil (%3)",
"user_posted_to": "%1 har skrevet et svar til: %2",
- "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
- "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
- "user_posted_topic": "%1 har skrevet et nytt emne: %2",
- "user_edited_post": "%1 has edited a post in %2",
+ "user_posted_to_dual": "%1 og 2% har svart på innlegget ditt i %3.",
+ "user_posted_to_multiple": "%1 og 2% andre har svart på %3",
+ "user_posted_topic": "%1 har skrevet en ny tråd: %2",
+ "user_edited_post": "%1 har redigert ett innlegg i %2",
"user_started_following_you": "%1 begynte å følge deg.",
- "user_started_following_you_dual": "%1 and %2 started following you.",
- "user_started_following_you_multiple": "%1 and %2 others started following you.",
+ "user_started_following_you_dual": "%1 og 2% har begynt å følge deg. ",
+ "user_started_following_you_multiple": "%1 og %2 andre begynte å følge deg.",
"new_register": "%1 sendte en forespørsel om registrering",
- "new_register_multiple": "There are %1 registration requests awaiting review.",
- "flag_assigned_to_you": "Flag %1 has been assigned to you",
- "post_awaiting_review": "Post awaiting review",
- "profile-exported": "%1 profile exported, click to download",
- "posts-exported": "%1 posts exported, click to download",
- "uploads-exported": "%1 uploads exported, click to download",
- "users-csv-exported": "Users csv exported, click to download",
+ "new_register_multiple": " Det er %1 registreringsforespørsler som venter på deg.",
+ "flag_assigned_to_you": "Flag %1 har blitt tildelt deg",
+ "post_awaiting_review": "Innlegg avventer anmeldelse",
+ "profile-exported": "%1 profil eksportert, klikk for å laste ned",
+ "posts-exported": "%1 innlegg eksportert, klikk for å laste ned",
+ "uploads-exported": "%1 opplastninger eksportert, klikk for å laste ned",
+ "users-csv-exported": "Bruker csv eksportert, klikk for å laste ned",
+ "post-queue-accepted": "Innlegget ditt i køen er godtatt. Klikk her for å se innlegget ditt.",
+ "post-queue-rejected": "Innlegget dit i køen har blitt avvist",
"email-confirmed": "E-post bekreftet",
"email-confirmed-message": "Takk for at du har validert din e-post. Kontoen din er nå fullstendig aktivert.",
"email-confirm-error-message": "Det oppsto et problem under valdiering av din e-post. Koden kan ha vært ugyldig eller ha utløpt.",
"email-confirm-sent": "Bekreftelsesepost sendt.",
- "none": "None",
- "notification_only": "Notification Only",
- "email_only": "Email Only",
- "notification_and_email": "Notification & Email",
- "notificationType_upvote": "When someone upvotes your post",
- "notificationType_new-topic": "When someone you follow posts a topic",
- "notificationType_new-reply": "When a new reply is posted in a topic you are watching",
- "notificationType_post-edit": "When a post is edited in a topic you are watching",
- "notificationType_follow": "When someone starts following you",
- "notificationType_new-chat": "When you receive a chat message",
- "notificationType_new-group-chat": "When you receive a group chat message",
- "notificationType_group-invite": "When you receive a group invite",
- "notificationType_group-leave": "When a user leaves your group",
- "notificationType_group-request-membership": "When someone requests to join a group you own",
- "notificationType_new-register": "When someone gets added to registration queue",
- "notificationType_post-queue": "When a new post is queued",
- "notificationType_new-post-flag": "When a post is flagged",
- "notificationType_new-user-flag": "When a user is flagged"
+ "none": "Ingen",
+ "notification_only": "Kun notifikasjon ",
+ "email_only": "Kun e-post",
+ "notification_and_email": "Notifikasjon og e-post ",
+ "notificationType_upvote": "Når noen stemmer opp innlegget ditt",
+ "notificationType_new-topic": "Når noen du følger følger legger ut et emne",
+ "notificationType_new-reply": "Når et nytt svar er lagt ut i et emne du overvåker",
+ "notificationType_post-edit": "Når et innlegg er redigert i et emne du overvåker",
+ "notificationType_follow": "Når noen starter å følge deg",
+ "notificationType_new-chat": "Når du mottar en melding i chatt",
+ "notificationType_new-group-chat": "Når du mottar en gruppemelding i chatt",
+ "notificationType_group-invite": "Når du får tilsendt en gruppeinvitasjon ",
+ "notificationType_group-leave": "Når en bruker forlater gruppen din",
+ "notificationType_group-request-membership": "Når noen sender en forespørsel om å bli med i en gruppe du eier",
+ "notificationType_new-register": "Når noen blir lag til i kø for å registrere",
+ "notificationType_post-queue": "Når et nytt innlegg er satt i kø ",
+ "notificationType_new-post-flag": "Når ett nytt innlegg er flagget",
+ "notificationType_new-user-flag": "Når en bruker er flagget"
}
\ No newline at end of file
diff --git a/public/language/nb/pages.json b/public/language/nb/pages.json
index 6030f98c83..40081fd02d 100644
--- a/public/language/nb/pages.json
+++ b/public/language/nb/pages.json
@@ -6,26 +6,26 @@
"popular-month": "Populære emner denne måneden",
"popular-alltime": "Mest populære emner for all tid",
"recent": "Nylige emner",
- "top-day": "Top voted topics today",
- "top-week": "Top voted topics this week",
- "top-month": "Top voted topics this month",
- "top-alltime": "Top Voted Topics",
- "moderator-tools": "Moderator Tools",
- "flagged-content": "Flagged Content",
- "ip-blacklist": "IP Blacklist",
- "post-queue": "Post Queue",
+ "top-day": "Dagens emne med fleste stemmer",
+ "top-week": "Emne med flest stemmer denne uken",
+ "top-month": "Emne med flest stemme denne måneden ",
+ "top-alltime": "Emner med flest stemmer",
+ "moderator-tools": "Moderatorverktøy",
+ "flagged-content": "Flagget innhold",
+ "ip-blacklist": "IP Svarteliste",
+ "post-queue": "Innleggskø",
"users/online": "Påloggede Brukere",
"users/latest": "Nyeste Brukere",
"users/sort-posts": "Brukere med flest innlegg",
"users/sort-reputation": "Brukere med best rykte",
- "users/banned": "Banned Users",
- "users/most-flags": "Most flagged users",
+ "users/banned": "Utestengte brukere",
+ "users/most-flags": "Brukere som er mest flagget ",
"users/search": "Brukersøk",
"notifications": "Varsler",
"tags": "Emneord",
- "tag": "Topics tagged under "%1"",
+ "tag": "Tråder tagget under "%1"",
"register": "Registrer en konto",
- "registration-complete": "Registration complete",
+ "registration-complete": "Registrering er fullført",
"login": "Logg inn på kontoen din",
"reset": "Tilbakestill passordet ditt",
"categories": "Kategorier",
@@ -33,32 +33,32 @@
"group": "%1 gruppe",
"chats": "Samtaler",
"chat": "Samtale med %1",
- "flags": "Flags",
- "flag-details": "Flag %1 Details",
+ "flags": "Flagg",
+ "flag-details": "Flagg %1 Detaljer",
"account/edit": "Endrer \"%1\"",
- "account/edit/password": "Editing password of \"%1\"",
- "account/edit/username": "Editing username of \"%1\"",
- "account/edit/email": "Editing email of \"%1\"",
- "account/info": "Account Info",
+ "account/edit/password": "Redigeringspassord for \"%1\"",
+ "account/edit/username": "Rediger brukernavnet til \"%1\"",
+ "account/edit/email": "Rediger e-post for \"%1\"",
+ "account/info": "Informasjon om brukerkonto ",
"account/following": "Personer %1 følger",
"account/followers": "Personer som følger %1",
"account/posts": "Innlegg opprettet av %1",
- "account/latest-posts": "Latest posts made by %1",
+ "account/latest-posts": "Seneste innlegg skrevet av %1",
"account/topics": "Emner opprettet av %1",
"account/groups": "%1 sine grupper",
- "account/watched_categories": "%1's Watched Categories",
- "account/bookmarks": "%1's Bookmarked Posts",
+ "account/watched_categories": "%1's overvåkede kategorier",
+ "account/bookmarks": "%1's bokmerkede innlegg",
"account/settings": "Brukerinnstillinger",
"account/watched": "Innlegg overvåket av %1",
- "account/ignored": "Topics ignored by %1",
- "account/upvoted": "Posts upvoted by %1",
- "account/downvoted": "Posts downvoted by %1",
- "account/best": "Best posts made by %1",
- "account/blocks": "Blocked users for %1",
- "account/uploads": "Uploads by %1",
- "account/sessions": "Login Sessions",
- "confirm": "Email Confirmed",
+ "account/ignored": "Emner ignorert av %1",
+ "account/upvoted": "Innlegg stemt opp av %1",
+ "account/downvoted": "Innlegg nedstemt av %1",
+ "account/best": "Beste innlegg skrevet av %1",
+ "account/blocks": "Blokkerte brukere for % 1",
+ "account/uploads": "Opplastninger av %1",
+ "account/sessions": "Påloggingsøkter",
+ "confirm": "E-post bekreftet",
"maintenance.text": "%1 er for tiden under vedlikehold. Kom tilbake en annen gang.",
"maintenance.messageIntro": "I tillegg har administratoren skrevet denne meldingen:",
- "throttled.text": "%1 is currently unavailable due to excessive load. Please come back another time."
+ "throttled.text": "% 1 er for øyeblikket ikke tilgjengelig på grunn av overdreven belastning. Kom tilbake en annen gang."
}
\ No newline at end of file
diff --git a/public/language/nb/post-queue.json b/public/language/nb/post-queue.json
index bfaa367870..b4d3610009 100644
--- a/public/language/nb/post-queue.json
+++ b/public/language/nb/post-queue.json
@@ -1,18 +1,18 @@
{
- "post-queue": "Post Queue",
+ "post-queue": "Innleggskø",
"description": "There are no posts in the post queue. Uma nova versão (v%1) foi lançada. Considere atualizar o seu NodeBB.
", "prerelease-upgrade-available": "Esta é uma versão de pré-lançamento desatualizada do NodeBB. Uma nova versão (v%1) foi lançada. Considere atualizar o seu NodeBB.
", "prerelease-warning": "Esta é uma versão de pré-lançamento do NodeBB. Bugs inesperados podem ocorrer.
", - "fallback-emailer-not-found": "Fallback emailer not found!", + "fallback-emailer-not-found": "Emailer substituto não encontrado!", "running-in-development": "O fórum está sendo executado em modo de desenvolvedor. O fórum pode estar sujeito a potenciais vulnerabilidades; por favor, entre em contato com o seu administrador de sistemas.", "latest-lookup-failed": "Falha ao procurar a versão mais recente disponível do NodeBB
", @@ -79,10 +79,10 @@ "last-restarted-by": "Última vez reiniciado por", "no-users-browsing": "Nenhum usuário navegando", - "back-to-dashboard": "Back to Dashboard", - "details.no-users": "No users have joined within the selected timeframe", - "details.no-topics": "No topics have been posted within the selected timeframe", - "details.no-logins": "No logins have been recorded within the selected timeframe", - "details.logins-static": "NodeBB only saves session data for %1 days, and so this table below will only show the most recently active sessions", - "details.logins-login-time": "Login Time" + "back-to-dashboard": "De volta ao Painel", + "details.no-users": "Nenhum usuário ingressou dentro do período de tempo selecionado", + "details.no-topics": "Nenhum tópico foi postado dentro do período de tempo selecionado", + "details.no-logins": "Nenhum login foi registrado dentro do período de tempo selecionado", + "details.logins-static": "O NodeBB só salva os dados da sessão por %1 dias, então esta tabela abaixo mostrará apenas as sessões ativas mais recentemente", + "details.logins-login-time": "Hora de Login" } diff --git a/public/language/pt-BR/admin/development/info.json b/public/language/pt-BR/admin/development/info.json index fb17421447..cb67c31ed3 100644 --- a/public/language/pt-BR/admin/development/info.json +++ b/public/language/pt-BR/admin/development/info.json @@ -1,5 +1,5 @@ { - "you-are-on": "You are on %1:%2", + "you-are-on": "Você está em %1:%2", "ip": "IP %1", "nodes-responded": "%1 nodes respondidos dentro de %2ms!", "host": "host", diff --git a/public/language/pt-BR/admin/extend/plugins.json b/public/language/pt-BR/admin/extend/plugins.json index f9e3609e06..4ed999a60a 100644 --- a/public/language/pt-BR/admin/extend/plugins.json +++ b/public/language/pt-BR/admin/extend/plugins.json @@ -39,7 +39,7 @@ "alert.upgraded": "Plugin Atualizado", "alert.installed": "Plugin Instalado", "alert.uninstalled": "Plugin Desinstalado", - "alert.activate-success": "Please rebuild and restart your NodeBB to fully activate this plugin", + "alert.activate-success": "Por favor, reconstrua e reinicie o seu NodeBB para ativar totalmente este plugin", "alert.deactivate-success": "Plugin desativado com sucesso", "alert.upgrade-success": "Por favor, recompile e reinicie seu NodeBB para atualizar totalmente este plugin.", "alert.install-success": "Plugin instalado com sucesso, por favor ative o plugin.", diff --git a/public/language/pt-BR/admin/extend/widgets.json b/public/language/pt-BR/admin/extend/widgets.json index bc22f12488..f9930d4a39 100644 --- a/public/language/pt-BR/admin/extend/widgets.json +++ b/public/language/pt-BR/admin/extend/widgets.json @@ -1,7 +1,7 @@ { "available": "Widgets Disponíveis", "explanation": "Escolha um widget do menu de dropdown e então arraste e solte numa área de widget do template à esquerda.", - "none-installed": "No widgets found! Activate the widget essentials plugin in the plugins control panel.", + "none-installed": "Nenhum widget encontrado! Ative o plug-in de widgets básicos no painel de controle de plugins.", "clone-from": "Copiar widgets de", "containers.available": "Contêineres Disponíveis", "containers.explanation": "Arrastar e soltar em cima de qualquer widget ativo", @@ -20,11 +20,11 @@ "error.select-clone": "Por favor, selecione a página a ser copiada", - "title": "Title", - "title.placeholder": "Title (only shown on some containers)", - "container": "Container", - "container.placeholder": "Drag and drop a container or enter HTML here.", - "show-to-groups": "Show to groups", - "hide-from-groups": "Hide from groups", - "hide-on-mobile": "Hide on mobile" + "title": "Título", + "title.placeholder": "Título (mostrado apenas em alguns contêineres)", + "container": "Contêiner", + "container.placeholder": "Arraste e solte um contêiner ou insira HTML aqui.", + "show-to-groups": "Mostrar para grupos", + "hide-from-groups": "Esconder dos grupos", + "hide-on-mobile": "Esconder no móvel" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/manage/categories.json b/public/language/pt-BR/admin/manage/categories.json index 8f82d94c7a..8d8b38f147 100644 --- a/public/language/pt-BR/admin/manage/categories.json +++ b/public/language/pt-BR/admin/manage/categories.json @@ -10,16 +10,16 @@ "custom-class": "Classe Personalizada", "num-recent-replies": "# de Respostas Recentes", "ext-link": "Link Externo", - "subcategories-per-page": "Subcategories per page", + "subcategories-per-page": "Subcategorias por página", "is-section": "Trate esta categoria como uma seção", - "post-queue": "Post queue", - "tag-whitelist": "Tag Whitelist", + "post-queue": "Fila de posts", + "tag-whitelist": "Lista Branca de Tags", "upload-image": "Enviar Imagem", "delete-image": "Remover", "category-image": "Imagem da Categoria", "parent-category": "Categoria-Mãe", "optional-parent-category": "(Opcional) Categoria-Mãe", - "top-level": "Top Level", + "top-level": "Nível Superior", "parent-category-none": "(Nenhum)", "copy-parent": "Copiar Mãe", "copy-settings": "Copiar Configurações De", @@ -31,8 +31,9 @@ "disable": "Desativar", "edit": "Editar", "analytics": "Analytics", - "view-category": "View category", - "set-order": "Set order", + "view-category": "Ver categoria", + "set-order": "Definir ordem", + "set-order-help": "Definir a ordem da categoria moverá esta categoria para aquela ordem e atualizará a ordem das outras categorias conforme necessário. A ordem mínima é 1, o que coloca a categoria no topo.", "select-category": "Selecionar Categoria", "set-parent-category": "Definir Categoria-Mãe", @@ -49,8 +50,8 @@ "privileges.no-users": "Sem privilégios para usuários específicos nesta categoria.", "privileges.section-group": "Grupo", "privileges.group-private": "Este grupo é privado", - "privileges.inheritance-exception": "This group does not inherit privileges from registered-users group", - "privileges.banned-user-inheritance": "Banned users inherit privileges from banned-users group", + "privileges.inheritance-exception": "Este grupo não herda privilégios do grupo registered-users", + "privileges.banned-user-inheritance": "Usuários banidos herdam privilégios do grupo banned-users", "privileges.search-group": "Adicionar Grupo", "privileges.copy-to-children": "Copiar para Filhos", "privileges.copy-from-category": "Copiar da Categoria", @@ -83,9 +84,9 @@ "alert.user-search": "Procure por um usuário aqui...", "alert.find-group": "Encontre um Grupo", "alert.group-search": "Pesquise por um grupo aqui...", - "alert.not-enough-whitelisted-tags": "Whitelisted tags are less than minimum tags, you need to create more whitelisted tags!", + "alert.not-enough-whitelisted-tags": "As tags na lista de permissões são em menor número do que as tags mínimas, você precisa criar mais tags na lista de permissões!", "collapse-all": "Esconder todos", "expand-all": "Expandir todos", "disable-on-create": "Desativar ao criar", - "no-matches": "No matches" + "no-matches": "Nada encontrado" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/manage/digest.json b/public/language/pt-BR/admin/manage/digest.json index 8f3661698a..c62371c550 100644 --- a/public/language/pt-BR/admin/manage/digest.json +++ b/public/language/pt-BR/admin/manage/digest.json @@ -1,21 +1,21 @@ { - "lead": "A listing of digest delivery stats and times is displayed below.", - "disclaimer": "Please be advised that email delivery is not guaranteed, due to the nature of email technology. Many variables factor into whether an email sent to the recipient server is ultimately delivered into the user's inbox, including server reputation, blacklisted IP addresses, and whether DKIM/SPF/DMARC is configured.", - "disclaimer-continued": "A successful delivery means the message was sent successfully by NodeBB and acknowledged by the recipient server. It does not mean the email landed in the inbox. For best results, we recommend using a third-party email delivery service such as SendGrid.", + "lead": "Uma lista de estatísticas e tempos de entrega de resumo é exibida abaixo.", + "disclaimer": "Informamos que a entrega de e-mail não é garantida, devido à natureza da tecnologia de e-mail. Muitos fatores variáveis determinam se um e-mail enviado ao servidor do destinatário é entregue na caixa de entrada do usuário, incluindo reputação do servidor, endereços IP na lista negra e se DKIM/SPF/DMARC está configurado.", + "disclaimer-continued": "Uma entrega bem-sucedida significa que a mensagem foi enviada com sucesso pelo NodeBB e confirmada pelo servidor do destinatário. Isso não significa que o e-mail foi parar na caixa de entrada. Para obter melhores resultados, recomendamos o uso de um serviço de entrega de e-mail de terceiros, como o SendGrid.", - "user": "User", - "subscription": "Subscription Type", - "last-delivery": "Last successful delivery", - "default": "System default", - "default-help": "System default means the user has not explicitly overridden the global forum setting for digests, which is currently: "%1"", - "resend": "Resend Digest", - "resend-all-confirm": "Are you sure you wish to manually execute this digest run?", - "resent-single": "Manual digest resend completed", - "resent-day": "Daily digest resent", - "resent-week": "Weekly digest resent", - "resent-month": "Monthly digest resent", - "null": "Never", - "manual-run": "Manual digest run:", + "user": "Usuário", + "subscription": "Tipo de Inscrição", + "last-delivery": "Última entrega bem sucedida", + "default": "Padrão do sistema", + "default-help": "Padrão do sistema significa que o usuário não substituiu explicitamente a configuração global do fórum para resumos, a qual atualmente é: \"%1\"", + "resend": "Reenviar Resumo", + "resend-all-confirm": "Tem certeza de que deseja executar manualmente esta execução de resumo?", + "resent-single": "Reenvio manual de resumos concluído", + "resent-day": "Resumo diário reenviado", + "resent-week": "Resumo semanal reenviado", + "resent-month": "Resumo mensal reenviado", + "null": "Nunca", + "manual-run": "Execução de resumo manual:", - "no-delivery-data": "No delivery data found" + "no-delivery-data": "Nenhum dado de entrega encontrado" } diff --git a/public/language/pt-BR/admin/manage/groups.json b/public/language/pt-BR/admin/manage/groups.json index 2ebae71be2..07b24ad3a6 100644 --- a/public/language/pt-BR/admin/manage/groups.json +++ b/public/language/pt-BR/admin/manage/groups.json @@ -8,8 +8,8 @@ "hidden": "Oculto", "private": "Privado", "edit": "Editar", - "delete": "Delete", - "privileges": "Privileges", + "delete": "Excluir", + "privileges": "Privilégios", "download-csv": "CSV", "search-placeholder": "Procurar", "create": "Criar Grupo", @@ -28,8 +28,8 @@ "edit.show-badge": "Mostrar Insígnia", "edit.private-details": "Se ativado, entrar em grupos requer a aprovação do dono do grupo.", "edit.private-override": "Aviso: grupos privados estão desabilitados no sistema, o que sobrepõe esta opção.", - "edit.disable-join": "Disable join requests", - "edit.disable-leave": "Disallow users from leaving the group", + "edit.disable-join": "Desativar pedidos de adesão", + "edit.disable-leave": "Impedir que usuários saiam do grupo", "edit.hidden": "Oculto", "edit.hidden-details": "Se ligado, o grupo não será encontrado nas listagens de grupos, e os usuários terão de ser convidados manualmente", "edit.add-user": "Adicionar Usuário ao Grupo", diff --git a/public/language/pt-BR/admin/manage/privileges.json b/public/language/pt-BR/admin/manage/privileges.json index 3b0c46efb7..9d3c7afd38 100644 --- a/public/language/pt-BR/admin/manage/privileges.json +++ b/public/language/pt-BR/admin/manage/privileges.json @@ -1,16 +1,16 @@ { "global": "Global", "admin": "Admin", - "group-privileges": "Group Privileges", - "user-privileges": "User Privileges", - "edit-privileges": "Edit Privileges", - "select-clear-all": "Select/Clear All", + "group-privileges": "Privilégios do Grupo", + "user-privileges": "Privilégios do Usuário", + "edit-privileges": "Editar Privilégios", + "select-clear-all": "Selecionar/Limpar Tudo", "chat": "Conversar", "upload-images": "Enviar Imagens", "upload-files": "Enviar Arquivos", "signature": "Assinatura", "ban": "Banir", - "invite": "Invite", + "invite": "Convidar", "search-content": "Pesquisar Conteúdo", "search-users": "Pesquisar Usuários", "search-tags": "Pesquisar Tags", @@ -19,13 +19,13 @@ "view-groups": "Ver Grupos", "allow-local-login": "Login Local", "allow-group-creation": "Criar Grupo", - "view-users-info": "View Users Info", + "view-users-info": "Ver Informações dos Usuários", "find-category": "Encontrar Categoria", "access-category": "Acessar Categoria", "access-topics": "Acessar Tópicos", "create-topics": "Criar Tópicos", "reply-to-topics": "Responder aos Tópicos", - "schedule-topics": "Schedule Topics", + "schedule-topics": "Agendar Tópicos", "tag-topics": "Definir tag em tópicos", "edit-posts": "Editar Posts", "view-edit-history": "Ver Histórico de Edição", @@ -36,25 +36,25 @@ "delete-topics": "Deletar Tópicos", "purge": "Purgar", "moderate": "Moderar", - "admin-dashboard": "Dashboard", - "admin-categories": "Categories", - "admin-privileges": "Privileges", - "admin-users": "Users", - "admin-admins-mods": "Admins & Mods", - "admin-groups": "Groups", + "admin-dashboard": "Painel", + "admin-categories": "Categorias", + "admin-privileges": "Privilégios", + "admin-users": "Usuários", + "admin-admins-mods": "Admins e Moderadores", + "admin-groups": "Grupos", "admin-tags": "Tags", - "admin-settings": "Settings", + "admin-settings": "Configurações", - "alert.confirm-moderate": "Are you sure you wish to grant the moderation privilege to this user group? This group is public, and any users can join at will.", - "alert.confirm-admins-mods": "Are you sure you wish to grant the "Admins & Mods" privilege to this user/group? Users with this privilege are able to promote and demote other users into privileged positions, including super administrator", - "alert.confirm-save": "Please confirm your intention to save these privileges", - "alert.saved": "Privilege changes saved and applied", - "alert.confirm-discard": "Are you sure you wish to discard your privilege changes?", - "alert.discarded": "Privilege changes discarded", - "alert.confirm-copyToAll": "Are you sure you wish to apply this privilege set to all categories?", - "alert.confirm-copyToAllGroup": "Are you sure you wish to apply this group's privilege set to all categories?", - "alert.confirm-copyToChildren": "Are you sure you wish to apply this privilege set to all descendant (child) categories?", - "alert.confirm-copyToChildrenGroup": "Are you sure you wish to apply this group's privilege set to all descendant (child) categories?", - "alert.no-undo": "This action cannot be undone.", - "alert.admin-warning": "Administrators implicitly get all privileges" + "alert.confirm-moderate": "Tem certeza de que deseja conceder o privilégio de moderação a este grupo de usuários? Este grupo é público e qualquer usuário pode entrar à vontade.", + "alert.confirm-admins-mods": "Tem certeza de que deseja conceder o privilégio de 'Administradores e Mods' a este usuário/grupo? Os usuários com este privilégio podem promover e rebaixar outros usuários a posições privilegiadas, incluindo superadministrador", + "alert.confirm-save": "Por favor, confirme a sua intenção de salvar estes privilégios", + "alert.saved": "Alterações de privilégio salvas e aplicadas", + "alert.confirm-discard": "Você tem certeza que quer descartar suas mudanças nos privilégios?", + "alert.discarded": "Mudanças de privilégio descartadas", + "alert.confirm-copyToAll": "Tem certeza de que deseja aplicar este conjunto de privilégios a todas as categorias?", + "alert.confirm-copyToAllGroup": "Tem certeza de que deseja aplicar o conjunto de privilégios deste grupo a todas as categorias?", + "alert.confirm-copyToChildren": "Tem certeza de que deseja aplicar este conjunto de privilégios a todas as categorias descendentes (filhos)?", + "alert.confirm-copyToChildrenGroup": "Tem certeza de que deseja aplicar o conjunto de privilégios deste grupo a todas as categorias descendentes (filhos)?", + "alert.no-undo": "Esta ação não pode ser desfeita.", + "alert.admin-warning": "Os administradores obtêm implicitamente todos os privilégios" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/manage/tags.json b/public/language/pt-BR/admin/manage/tags.json index 4e1111bae4..70964c7e09 100644 --- a/public/language/pt-BR/admin/manage/tags.json +++ b/public/language/pt-BR/admin/manage/tags.json @@ -3,17 +3,17 @@ "bg-color": "Cor de Fundo", "text-color": "Cor do Text", "create-modify": "Criar & Modificar Tags", - "description": "Select tags by clicking or dragging, useCTRL to select multiple tags.",
+ "description": "Selecione as tags clicando ou arrastando, use CTRL para selecionar várias tags.",
"create": "Criar Tag",
"modify": "Modificar Tags",
"rename": "Renomear Tags",
"delete": "Excluir Tags Selecionadas",
"search": "Pesquisar por tags...",
- "settings": "Tags Settings",
+ "settings": "Configurações de Tags",
"name": "Nome da Tag",
- "alerts.editing": "Editing tag(s)",
+ "alerts.editing": "Editando tag(s)",
"alerts.confirm-delete": "Você deseja excluir as tags selecionadas?",
"alerts.update-success": "Tag Atualizada!",
- "reset-colors": "Reset colors"
+ "reset-colors": "Redefinir cores"
}
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/manage/users.json b/public/language/pt-BR/admin/manage/users.json
index 2d301cb0a2..d4b8931069 100644
--- a/public/language/pt-BR/admin/manage/users.json
+++ b/public/language/pt-BR/admin/manage/users.json
@@ -12,17 +12,17 @@
"unban": "Desbanir Usuário(s)",
"reset-lockout": "Excluir Bloqueio",
"reset-flags": "Resetar Sinalizações",
- "delete": "Delete User(s)",
- "delete-content": "Delete User(s) Content",
- "purge": "Delete User(s) and Content",
+ "delete": "Excluir Usuário(s)",
+ "delete-content": "Excluir Conteúdo do(s) Usuário(s)",
+ "purge": "Excluir Usuário(s) e Conteúdo",
"download-csv": "Baixar CSV",
- "manage-groups": "Manage Groups",
- "add-group": "Add Group",
+ "manage-groups": "Gerenciar Grupos",
+ "add-group": "Adicionar Grupo",
"invite": "Convidar",
"new": "Novo Usuário",
- "filter-by": "Filter by",
+ "filter-by": "Filtrar por",
"pills.unvalidated": "Não Validado",
- "pills.validated": "Validated",
+ "pills.validated": "Validado",
"pills.banned": "Banido",
"50-per-page": "50 por página",
@@ -88,11 +88,11 @@
"alerts.validate-email-success": "E-mails validados",
"alerts.validate-force-password-reset-success": "A senha do(s) usuário(s) foi redefinida e as suas sessões existentes foram revogadas.",
"alerts.password-reset-confirm": "Você quer enviar e-mail(s) de redefinição de senha para este(s) usuário(s)?",
- "alerts.confirm-delete": "Warning!Do you really want to delete user(s)?
This action is not reversible! Only the user account will be deleted, their posts and topics will remain.
", + "alerts.confirm-delete": "Aviso!Você realmente quer deletar usuário(s)?
Esta ação não é reversível! Apenas a conta do usuário será excluída, suas postagens e tópicos permanecerão.
", "alerts.delete-success": "Usuário(s) Deletados!", - "alerts.confirm-delete-content": "Warning!Do you really want to delete these user(s) content?
This action is not reversible! The users' accounts will remain, but their posts and topics will be deleted.
", - "alerts.delete-content-success": "User(s) Content Deleted!", - "alerts.confirm-purge": "Warning!Do you really want to delete user(s) and their content?
This action is not reversible! All user data and content will be erased!
", + "alerts.confirm-delete-content": "Aviso!Você realmente deseja excluir o conteúdo destes usuários?
Esta ação não é reversível! As contão permanecerão, mas seus posts e tópicos serão excluídos.
", + "alerts.delete-content-success": "Conteúdo do(s) Usuário(s) Excluído!", + "alerts.confirm-purge": "Aviso!Você realmente quer excluir usuário(s) e seu conteúdo?
Essa ação não é reversível! Todos os dados e conteúdo dos usuários serão apagados!
", "alerts.create": "Criar Usuário", "alerts.button-create": "Criar", "alerts.button-cancel": "Cancelar", @@ -102,7 +102,7 @@ "alerts.prompt-email": "E-mails:", "alerts.email-sent-to": "Um e-mail de convite foi enviado para %1", - "alerts.x-users-found": "%1 user(s) found, (%2 seconds)", - "export-users-started": "Exporting users as csv, this might take a while. You will receive a notification when it is complete.", - "export-users-completed": "Users exported as csv, click here to download." + "alerts.x-users-found": "%1 usuário(s) encontrados, (%2 segundos)", + "export-users-started": "Exportando usuários como csv, isso pode demorar um pouco. Você receberá uma notificação quando isso for concluído.", + "export-users-completed": "Usuários exportados como csv, clique aqui para fazer o download." } \ No newline at end of file diff --git a/public/language/pt-BR/admin/menu.json b/public/language/pt-BR/admin/menu.json index 837ada6f17..df133d872f 100644 --- a/public/language/pt-BR/admin/menu.json +++ b/public/language/pt-BR/admin/menu.json @@ -1,9 +1,9 @@ { - "section-dashboard": "Dashboards", - "dashboard/overview": "Overview", + "section-dashboard": "Painéis", + "dashboard/overview": "Visão Geral", "dashboard/logins": "Logins", - "dashboard/users": "Users", - "dashboard/topics": "Topics", + "dashboard/users": "Usuários", + "dashboard/topics": "Tópicos", "section-general": "Geral", "section-manage": "Administrar", @@ -17,26 +17,26 @@ "manage/groups": "Grupos", "manage/ip-blacklist": "Lista Negra de IPs", "manage/uploads": "Uploads", - "manage/digest": "Digests", + "manage/digest": "Resumos", "section-settings": "Configurações", "settings/general": "Geral", - "settings/homepage": "Home Page", - "settings/navigation": "Navigation", - "settings/reputation": "Reputation & Flags", + "settings/homepage": "Página Inicial", + "settings/navigation": "Navegação", + "settings/reputation": "Reputação & Sinalizações", "settings/email": "E-mail", - "settings/user": "Users", - "settings/group": "Groups", + "settings/user": "Usuários", + "settings/group": "Grupos", "settings/guest": "Visitantes", "settings/uploads": "Uploads", - "settings/languages": "Languages", + "settings/languages": "Idiomas", "settings/post": "Posts", "settings/chat": "Chats", "settings/pagination": "Paginação", "settings/tags": "Tags", "settings/notifications": "Notificações", - "settings/api": "API Access", - "settings/sounds": "Sounds", + "settings/api": "Acesso a API", + "settings/sounds": "Sons", "settings/social": "Social", "settings/cookies": "Cookies", "settings/web-crawler": "Motores de Busca", @@ -75,7 +75,7 @@ "logout": "Sair da Conta", "view-forum": "Ver Fórum", - "search.placeholder": "Press "/" to search for settings", + "search.placeholder": "Pressione \"/\" para pesquisar por configurações", "search.no-results": "Sem resultados...", "search.search-forum": "Pesquisar o fórum por ", "search.keep-typing": "Digite para ver mais resultados...", diff --git a/public/language/pt-BR/admin/settings/advanced.json b/public/language/pt-BR/admin/settings/advanced.json index 9443dd64ad..6439ba1147 100644 --- a/public/language/pt-BR/admin/settings/advanced.json +++ b/public/language/pt-BR/admin/settings/advanced.json @@ -5,8 +5,8 @@ "maintenance-mode.message": "Mensagem de Manutenção", "headers": "Cabeçalhos", "headers.allow-from": "Defina ALLOW-FROM para Colocar o NodeBB em um iFrame", - "headers.csp-frame-ancestors": "Set Content-Security-Policy frame-ancestors header to Place NodeBB in an iFrame", - "headers.csp-frame-ancestors-help": "'none', 'self'(default) or list of URIs to allow.", + "headers.csp-frame-ancestors": "Define o cabeçalho de Content-Security-Policy frame-ancestors para Colocar o NodeBB em um iFrame", + "headers.csp-frame-ancestors-help": "'none', 'self' (padrão) ou lista de URIs a permitir.", "headers.powered-by": "Personalizar o cabeçalho de \"Powered By\" enviado pelo NodeBB", "headers.acao": "Access-Control-Allow-Origin", "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression", @@ -22,22 +22,22 @@ "hsts.preload": "Permitir pré-carregamento do cabeçalho do HSTS", "hsts.help": "Se habilitado, um cabeçalho de HSTS será enviado para este site. Você pode selecionar tanto quais subdomínios deseja incluir, como quais serão as flags de pré-carregamento no seu cabeçalho. Se estiver em dúvida, você pode deixar esta opção desmarcada. Mais informações", "traffic-management": "Administração de Tráfego", - "traffic.help": "NodeBB uses a module that automatically denies requests in high-traffic situations. You can tune these settings here, although the defaults are a good starting point.", + "traffic.help": "NodeBB usa um módulo que automaticamente nega requisições em situações de alto tráfego. Você pode ajustar estas configurações aqui, apesar de que os padrões são um bom ponto de partida.", "traffic.enable": "Ativar a Administração de Tráfego", "traffic.event-lag": "Limite do Lag do Loop de Eventos (em milisegundos)", "traffic.event-lag-help": "Abaixar este valor diminui o tempo de espera para o carregamentos de página, mas irá também mostrar a mensagem de \"carga excessiva\" para mais usuários. (É necessário reiniciar)", "traffic.lag-check-interval": "Intervalo de Checagem (em milisegundos)", "traffic.lag-check-interval-help": "Diminuir esse valor faz com que o NodeBB fique mais sensível a picos de carga, mas também pode fazer com que a verificação fique muito sensível. (É necessário reiniciar)", - "sockets.settings": "WebSocket Settings", - "sockets.max-attempts": "Max Reconnection Attempts", - "sockets.default-placeholder": "Default: %1", - "sockets.delay": "Reconnection Delay", + "sockets.settings": "Configurações de WebSocket", + "sockets.max-attempts": "Máx. Tentativas de Reconexão", + "sockets.default-placeholder": "Padrão: %1", + "sockets.delay": "Espera de Reconexão", - "analytics.settings": "Analytics Settings", - "analytics.max-cache": "Analytics Cache Max Value", - "analytics.max-cache-help": "On high-traffic installs, the cache could be exhausted continuously if there are more concurrent active users than the Max Cache value. (Restart required)", - "compression.settings": "Compression Settings", - "compression.enable": "Enable Compression", - "compression.help": "This setting enables gzip compression. For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level. You can enable it here for testing purposes." + "analytics.settings": "Configurações de Analytics", + "analytics.max-cache": "Valor Máx. do Cache de Analytics", + "analytics.max-cache-help": "Em instalações de alto tráfego, o cache pode ser exaurido continuamente se houver mais usuários ativos simultâneos do que o valor Max Cache. (É necessário reiniciar)", + "compression.settings": "Configurções de Compressão", + "compression.enable": "Habilitar Compreesão", + "compression.help": "Esta configuração ativa a compactação gzip. Para um site de alto tráfego em produção, a melhor maneira de implementar a compactação é implementá-la em um nível de proxy reverso. Você pode habilitá-lo aqui para fins de teste." } \ No newline at end of file diff --git a/public/language/pt-BR/admin/settings/api.json b/public/language/pt-BR/admin/settings/api.json index 50892925f3..a7427d4aeb 100644 --- a/public/language/pt-BR/admin/settings/api.json +++ b/public/language/pt-BR/admin/settings/api.json @@ -1,16 +1,16 @@ { "tokens": "Tokens", - "settings": "Settings", - "lead-text": "From this page you can configure access to the Write API in NodeBB.", - "intro": "By default, the Write API authenticates users based on their session cookie, but NodeBB also supports Bearer authentication via tokens generated via this page.", - "docs": "Click here to access the full API specification", + "settings": "Configurações", + "lead-text": "Nesta página, você pode configurar o acesso à API de Escrita no NodeBB.", + "intro": "Por padrão, a API de Escrita autentica os usuários com base em seu cookie de \nsessão, mas o NodeBB também oferece suporte à autenticação Bearer por\n meio de tokens gerados por meio desta página.", + "docs": "Clique aqui para acessar a especificação completa da API", - "require-https": "Require API usage via HTTPS only", - "require-https-caveat": "Note: Some installations involving load balancers may proxy their requests to NodeBB using HTTP, in which case this option should remain disabled.", + "require-https": "Exigir uso da API apenas via HTTPS", + "require-https-caveat": "Nota: Algumas instalações que envolvem balanceadores de carga podem fazer proxy de suas solicitações para NodeBB usando HTTP, caso em que esta opção deve permanecer desabilitada.", - "uid": "User ID", - "uid-help-text": "Specify a User ID to associate with this token. If the user ID is0, it will be considered a master token, which can assume the identity of other users based on the _uid parameter",
- "description": "Description",
- "no-description": "No description specified.",
- "token-on-save": "Token will be generated once form is saved"
+ "uid": "ID do Usuário",
+ "uid-help-text": "Especifique um ID de usuário para associar a este token. Se o ID do usuário for0, ele será considerada uma token master, que pode assumir a identidade de outros usuários com base no parâmetro _uid",
+ "description": "Descrição",
+ "no-description": "Nenhuma descrição especificada.",
+ "token-on-save": "O token será gerado assim que o formulário for salvo"
}
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/settings/chat.json b/public/language/pt-BR/admin/settings/chat.json
index 8e06b1fd64..710c1e29c4 100644
--- a/public/language/pt-BR/admin/settings/chat.json
+++ b/public/language/pt-BR/admin/settings/chat.json
@@ -6,7 +6,7 @@
"max-length": "Tamanho máximo das mensagens de chat",
"max-room-size": "Número máximo de usuários nas salas de chat",
"delay": "Tempo entre mensagens de chat em milisegundos",
- "notification-delay": "Notification delay for chat messages. (0 for no delay)",
+ "notification-delay": "Tempo de espera para notificação de mensagens de bate-papo. (0 para não esperar)",
"restrictions.seconds-edit-after": "Número de segundos que uma mensagem de chat permanecerá editável. (0 desligado)",
"restrictions.seconds-delete-after": "Número de segundos que uma mensagem de chat permanecerá deletável. (0 desligado)"
}
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/settings/cookies.json b/public/language/pt-BR/admin/settings/cookies.json
index c8c77ff6af..a59e7b91f0 100644
--- a/public/language/pt-BR/admin/settings/cookies.json
+++ b/public/language/pt-BR/admin/settings/cookies.json
@@ -8,6 +8,6 @@
"consent.blank-localised-default": "Deixar em branco para utilizar os padrões de localidade do NodeBB",
"settings": "Configurações",
"cookie-domain": "Domínio da sessão de cookie",
- "max-user-sessions": "Max active sessions per user",
+ "max-user-sessions": "Máximo de sessões ativas por usuário",
"blank-default": "Deixe em branco para o valor padrão"
}
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/settings/email.json b/public/language/pt-BR/admin/settings/email.json
index 6d233e6dfd..3997f2502f 100644
--- a/public/language/pt-BR/admin/settings/email.json
+++ b/public/language/pt-BR/admin/settings/email.json
@@ -22,8 +22,8 @@
"smtp-transport.username": "Nome de usuário",
"smtp-transport.username-help": "Para o serviço do Gmail, entre com o endereço de e-mail completo aqui, principalmente se você estiver usando um domínio administrado pelo Google Apps.",
"smtp-transport.password": "Senha",
- "smtp-transport.pool": "Enable pooled connections",
- "smtp-transport.pool-help": "Pooling connections prevents NodeBB from creating a new connection for every email. This option only applies if SMTP Transport is enabled.",
+ "smtp-transport.pool": "Habilitar conexões em pool",
+ "smtp-transport.pool-help": "O pool de conexões evita que o NodeBB crie uma nova conexão para cada e-mail. Esta opção se aplica apenas se o Transporte SMTP estiver habilitado.",
"template": "Editar Modelo do E-mail",
"template.select": "Escolher Modelo do E-mail",
@@ -32,10 +32,10 @@
"testing.select": "Escolher Modelo do E-mail",
"testing.send": "Enviar E-mail de Teste",
"testing.send-help": "O e-mail de teste será enviado para o seu endereço de e-mail.",
- "subscriptions": "Email Digests",
- "subscriptions.disable": "Disable email digests",
+ "subscriptions": "Resumos por Email",
+ "subscriptions.disable": "Desabilitar resumos por email",
"subscriptions.hour": "Hora de Envio dos Resumos",
"subscriptions.hour-help": "Por favor, entre um número representando a hora para enviar os resumos agendados via e-mail (por exemplo: 0 para meia-noite, 17 para 5:00pm). Tenha em mente que esta é a hora de acordo com o servidor e pode não combinar exatamente com o relógio do seu sistema.30, ou um mês). Defina como 0 para sempre mostrar datas, deixe em branco para sempre mostrar horários relativos.",
- "timestamp.necro-threshold": "Necro Threshold (in days)",
- "timestamp.necro-threshold-help": "A message will be shown between posts if the time between them is longer than the necro threshold. (Default: 7, or one week). Set to 0 to disable.",
- "timestamp.topic-views-interval": "Increment topic views interval (in minutes)",
- "timestamp.topic-views-interval-help": "Topic views will only increment once every X minutes as defined by this setting.",
+ "timestamp.necro-threshold": "Limiar para Necro (em dias)",
+ "timestamp.necro-threshold-help": "Uma mensagem será exibida entre as postagens se o tempo entre elas for maior do que o limite necro. (Padrão: 7, ou uma semana). Defina como 0 para desativar.",
+ "timestamp.topic-views-interval": "Intervalo de incrementação de visualizações do tópico (em minutos)",
+ "timestamp.topic-views-interval-help": "As visualizações de tópico serão incrementadas apenas uma vez a cada X minutos, conforme definido por esta configuração.",
"teaser": "Post de Propaganda",
"teaser.last-post": "Último – Exibir o último post, incluindo o post original, se não houver respostas",
"teaser.last-reply": "Último – Exibir a última resposta, ou um marcador \"Sem respostas\" se não houver respostas",
@@ -44,7 +44,7 @@
"unread.cutoff": "Data de corte de não-lidos",
"unread.min-track-last": "Mínimo de posts no tópico antes de rastrear o último lido",
"recent": "Configurações Recentes",
- "recent.max-topics": "Maximum topics on /recent",
+ "recent.max-topics": "Máximo de tópicos em /recent",
"recent.categoryFilter.disable": "Desailitar filtragem de tópicos em categorias ignoradas na página /recente",
"signature": "Configurações de Assinatura",
"signature.disable": "Desabilitar assinaturas",
diff --git a/public/language/pt-BR/admin/settings/reputation.json b/public/language/pt-BR/admin/settings/reputation.json
index 3e568926e9..899ee2bc3d 100644
--- a/public/language/pt-BR/admin/settings/reputation.json
+++ b/public/language/pt-BR/admin/settings/reputation.json
@@ -5,8 +5,8 @@
"votes-are-public": "Todos os Votos São Públicos",
"thresholds": "Limites às atividades",
"min-rep-downvote": "Reputação mínima para votar negativamente em posts",
- "downvotes-per-day": "Downvotes per day (set to 0 for unlimited downvotes)",
- "downvotes-per-user-per-day": "Downvotes per user per day (set to 0 for unlimited downvotes)",
+ "downvotes-per-day": "Votos negativos por dia (definido como 0 para votos negativos ilimitados)",
+ "downvotes-per-user-per-day": "Votos negativos por usuário por dia (definido como 0 para votos negativos ilimitados)",
"min-rep-flag": "Reputação mínima para sinalizar posts",
"min-rep-website": "Reputação mínima para adicionar \"Website\" ao perfil do usuário",
"min-rep-aboutme": "Reputação mínima para adicionar \"Sobre mim\" ao perfil do usuário",
@@ -14,9 +14,9 @@
"min-rep-profile-picture": "Reputação mínima para adicionar \"Foto do Perfil\" ao perfil do usuário",
"min-rep-cover-picture": "Reputação mínima para adicionar \"Foto de Capa\" ao perfil do usuário",
- "flags": "Flag Settings",
- "flags.limit-per-target": "Maximum number of times something can be flagged",
- "flags.limit-per-target-placeholder": "Default: 0",
- "flags.limit-per-target-help": "When a post or user is flagged multiple times, each additional flag is considered a "report" and added to the original flag. Set this option to a number other than zero to limit the number of reports an item can receive.",
- "flags.auto-resolve-on-ban": "Automatically resolve all of a user's tickets when they are banned"
+ "flags": "Configurações de Sinalização",
+ "flags.limit-per-target": "Número máximo de vezes que algo pode ser sinalizado",
+ "flags.limit-per-target-placeholder": "Padrão: 0",
+ "flags.limit-per-target-help": "Quando uma postagem ou usuário é sinalizado várias vezes, cada sinalizador adicional é considerado uma 'reportagem' e adicionado ao sinalizador original. Defina esta opção com um número diferente de zero para limitar o número de relatórios que um item pode receber.",
+ "flags.auto-resolve-on-ban": "Resolver automaticamente todos os tickets de um usuário quando eles são banidos"
}
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/settings/tags.json b/public/language/pt-BR/admin/settings/tags.json
index c08d3c7628..f44e8ba6b3 100644
--- a/public/language/pt-BR/admin/settings/tags.json
+++ b/public/language/pt-BR/admin/settings/tags.json
@@ -1,8 +1,8 @@
{
"tag": "Configurações de Tag",
- "link-to-manage": "Manage Tags",
- "system-tags": "System Tags",
- "system-tags-help": "Only privileged users will be able to use these tags.",
+ "link-to-manage": "Gerenciar Tags",
+ "system-tags": "Tags do Sistema",
+ "system-tags-help": "Apenas usuários privilegiados poderão usar essas tags.",
"min-per-topic": "Mínimo de Tags por Tópico",
"max-per-topic": "Máximo de Tags por Tópico",
"min-length": "Tamanho Mínimo das Tags",
diff --git a/public/language/pt-BR/admin/settings/uploads.json b/public/language/pt-BR/admin/settings/uploads.json
index 07c5602541..e8b9b7728b 100644
--- a/public/language/pt-BR/admin/settings/uploads.json
+++ b/public/language/pt-BR/admin/settings/uploads.json
@@ -21,9 +21,9 @@
"topic-thumb-size": "Tamanho da Miniatura de Tópico",
"allowed-file-extensions": "Extensões de Arquivo Permitidas",
"allowed-file-extensions-help": "Digite uma lista, separada por vírgulas, de extensões de arquivos aqui (por exemplo: pdf,xls,doc). Uma lista vazia significa que todas as extensões são permitidas.",
- "upload-limit-threshold": "Rate limit user uploads to:",
- "upload-limit-threshold-per-minute": "Per %1 Minute",
- "upload-limit-threshold-per-minutes": "Per %1 Minutes",
+ "upload-limit-threshold": "Limitar a taxa de uploads de usuários para:",
+ "upload-limit-threshold-per-minute": "A Cada %1 Minuto",
+ "upload-limit-threshold-per-minutes": "A Cada %1 Minutos",
"profile-avatars": "Avatares de Perfil",
"allow-profile-image-uploads": "Permitir usuários de enviar imagens de perfil",
"convert-profile-image-png": "Converter imagens de perfil enviadas para PNG",
diff --git a/public/language/pt-BR/admin/settings/user.json b/public/language/pt-BR/admin/settings/user.json
index 1af9f279f2..bb44efa13a 100644
--- a/public/language/pt-BR/admin/settings/user.json
+++ b/public/language/pt-BR/admin/settings/user.json
@@ -9,14 +9,14 @@
"allow-login-with.email": "Apenas E-mail",
"account-settings": "Configurações de Conta",
"gdpr_enabled": "Ativar coleta de consentimento do GDPR",
- "gdpr_enabled_help": "When enabled, all new registrants will be required to explicitly give consent for data collection and usage under the General Data Protection Regulation (GDPR). Note: Enabling GDPR does not force pre-existing users to provide consent. To do so, you will need to install the GDPR plugin.",
+ "gdpr_enabled_help": "Quando ativado, todos os novos registrantes serão obrigados a dar consentimento explícito para a coleta de dados e uso sob o General Data Protection Regulation (GDPR). Nota: Ativar o GDPR não força usuários pré-existentes a fornecer consentimento. Para fazer isso, você precisará instalar o plug-in GDPR.",
"disable-username-changes": "Desabilitar mudança de nome de usuário",
"disable-email-changes": "Desabilitar mudanças de e-mail",
"disable-password-changes": "Desabilitar mudanças de senha",
"allow-account-deletion": "Permitir exclusão de conta",
"hide-fullname": "Esconder nome completo de outros usuários",
"hide-email": "Esconder e-mail de outros usuários",
- "show-fullname-as-displayname": "Show user's full name as their display name if available",
+ "show-fullname-as-displayname": "Mostrar o nome completo do usuário como nome de exibição, se disponível",
"themes": "Temas",
"disable-user-skins": "Impedir usuários de escolherem um tema diferente",
"account-protection": "Proteção de Conta",
@@ -44,9 +44,9 @@
"registration-type.disabled": "Desativar registros",
"registration-type.help": "Normal - Usuários podem se registrar pela página /register.192.168.100.0/22).",
- "hint-2": "You can add in comments by starting lines with the # symbol.",
+ "lead": "Овде конфигуришите своју црну листу IP-а.",
+ "description": "Забрана корисничког налога некад није довољно средство за одвраћање. Понекад је ограничавање приступа форуму одређеној IP адреси или низу IP адреса најбољи начин да се форум заштити. У овим сценаријима можете додати проблематичне IP адресе или читаве CIDR блокове на ову црну листу и биће им онемогућено да се пријаве или региструју нови налог.",
+ "active-rules": "Активна правила",
+ "validate": "Потврдите црну листу",
+ "apply": "Примени црну листу",
+ "hints": "Савети за синтаксу",
+ "hint-1": "Дефинишите једну IP адресу по реду. Можете додати IP блокове све док следе формат CIDR (нпр. 192.168.100.0/22).",
+ "hint-2": "У коментаре можете додавати почетне редове са симболом #.",
- "validate.x-valid": "%1 out of %2 rule(s) valid.",
- "validate.x-invalid": "The following %1 rules are invalid:",
+ "validate.x-valid": "%1 од %2 правила важеће.",
+ "validate.x-invalid": "Следећа правила (укупно %1) су неважећа:",
- "alerts.applied-success": "Blacklist Applied",
+ "alerts.applied-success": "Црна листа је примењена",
- "analytics.blacklist-hourly": "Figure 1 – Blacklist hits per hour",
- "analytics.blacklist-daily": "Figure 2 – Blacklist hits per day",
- "ip-banned": "IP banned"
+ "analytics.blacklist-hourly": "Figure 1 – број посета са црне листе на сат",
+ "analytics.blacklist-daily": "Figure 1 – број посета са црне листе на дан",
+ "ip-banned": "IP је забрањен"
}
\ No newline at end of file
diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json
index e21484c7c7..c0ee49386e 100644
--- a/public/language/sr/notifications.json
+++ b/public/language/sr/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 порука извезено, кликните за преузимање",
"uploads-exported": "%1 отпремања извезено, кликните за преузимање",
"users-csv-exported": "Кориснички csv извезен, кликните за преузимање",
+ "post-queue-accepted": "Ваша порука на чекању је прихваћена. Кликните овде да бисте видели своју поруку.",
+ "post-queue-rejected": "Ваша порука на чекању је одбијена.",
"email-confirmed": "Е-пошта је потврђена.",
"email-confirmed-message": "Хвала на овери ваше е-поште. Ваш налог је сада у потпуности активан.",
"email-confirm-error-message": "Дошло је до проблема са овером ваше е-поште. Можда је код неисправан или је истекао.",
diff --git a/public/language/sr/success.json b/public/language/sr/success.json
index bbf415b6ac..d47cdfbaf3 100644
--- a/public/language/sr/success.json
+++ b/public/language/sr/success.json
@@ -1,7 +1,7 @@
{
"success": "Успешно",
"topic-post": "Успешно сте послали поруку.",
- "post-queued": "Ваша порука је стављена у ред за одобрење.",
+ "post-queued": "Ваша порука је на чекању за одобрење. Добићете обавештење када буде прихваћена или одбијена.",
"authentication-successful": "Успешна аутентификација",
"settings-saved": "Подешавања су сачувана!"
}
\ No newline at end of file
diff --git a/public/language/sv/admin/manage/categories.json b/public/language/sv/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/sv/admin/manage/categories.json
+++ b/public/language/sv/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/sv/error.json b/public/language/sv/error.json
index d2c79f791a..c7b7cde67f 100644
--- a/public/language/sv/error.json
+++ b/public/language/sv/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Du kan inte sparka ut dig själv från gruppen",
"no-users-selected": "Ingen användare vald(a)",
"invalid-home-page-route": "Ogiltig sidsökväg",
- "invalid-session": "Session fel",
- "invalid-session-text": "Det ser ut som din inloggningssession inte längre är aktiv eller inte längre överensstämmer med servern. Uppdatera denna sida.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Inga ämnen valda!",
"cant-move-to-same-topic": "Kan inte flytta inlägg till samma ämne!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json
index aa1eaa9c34..7a426b7d4b 100644
--- a/public/language/sv/notifications.json
+++ b/public/language/sv/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "E-post bekräftad",
"email-confirmed-message": "Tack för att du bekräftat din e-postadress. Ditt konto är nu fullt ut aktiverat.",
"email-confirm-error-message": "Det uppstod ett problem med bekräftelsen av din e-postadress. Kanske var koden felaktig eller ogiltig.",
diff --git a/public/language/sv/success.json b/public/language/sv/success.json
index 939069385e..d938c2c9f7 100644
--- a/public/language/sv/success.json
+++ b/public/language/sv/success.json
@@ -1,7 +1,7 @@
{
"success": "Lyckat",
"topic-post": "Du har nu gjort ett inlägg.",
- "post-queued": "Ditt inlägg väntar nu på att bli godkänt.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Autentisering lyckades",
"settings-saved": "Inställningarna sparades."
}
\ No newline at end of file
diff --git a/public/language/th/admin/manage/categories.json b/public/language/th/admin/manage/categories.json
index db353a8ce2..ed5462e9be 100644
--- a/public/language/th/admin/manage/categories.json
+++ b/public/language/th/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
diff --git a/public/language/th/error.json b/public/language/th/error.json
index b663761c04..660b50f93c 100644
--- a/public/language/th/error.json
+++ b/public/language/th/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "คุณไม่สามารถเตะตัวเองออกจากกลุ่มได้",
"no-users-selected": "ไม่มีผู้ใช้ที่เลือก",
"invalid-home-page-route": "เส้นทางไปหน้าแรกผิดพลาด",
- "invalid-session": "เซสชั่นไม่ถูกต้อง",
- "invalid-session-text": "เหมือนกับว่าการเข้าสู่ระบบของคุณไม่ได้มีอยู่ในระบบ หรือไม่ก็ไม่ได้รับการตอบกลับจากเซิร์ฟเวอร์ กรุณารีเฟรชหน้าเว็บนี้",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "No topics selected!",
"cant-move-to-same-topic": "Can't move post to same topic!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json
index 8c8f538a2a..adc174ff2b 100644
--- a/public/language/th/notifications.json
+++ b/public/language/th/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Email ได้รับการยืนยันแล้ว",
"email-confirmed-message": "ขอบคุณที่ยืนยัน Email ของคุณ บัญชีของคุณสามารถใช้งานได้แล้ว",
"email-confirm-error-message": "มีปัญหาในการยืนยัน Email ของคุณ บางทีรหัสไม่ถูกต้องหรือหมดอายุแล้ว",
diff --git a/public/language/th/success.json b/public/language/th/success.json
index 3173db70a8..7751c7b027 100644
--- a/public/language/th/success.json
+++ b/public/language/th/success.json
@@ -1,7 +1,7 @@
{
"success": "สำเร็จ",
"topic-post": "คุณลงข้อความสำเร็จแล้ว",
- "post-queued": "โพสของคุณกำลังรอการอนุมัติ",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "การระบุตัวตนสำเร็จแล้ว",
"settings-saved": "การตั้งค่าได้ถูกบันทึกแล้ว"
}
\ No newline at end of file
diff --git a/public/language/tr/admin/manage/categories.json b/public/language/tr/admin/manage/categories.json
index 12e5a42de0..5d09d269e6 100644
--- a/public/language/tr/admin/manage/categories.json
+++ b/public/language/tr/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analiz",
"view-category": "Kategori Görüntüle",
"set-order": "Bir sıra ayarla",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Kategori Seç",
"set-parent-category": "Ana Kategori Ayarla",
diff --git a/public/language/tr/admin/settings/advanced.json b/public/language/tr/admin/settings/advanced.json
index 7cdf04e608..d8432101d4 100644
--- a/public/language/tr/admin/settings/advanced.json
+++ b/public/language/tr/admin/settings/advanced.json
@@ -6,7 +6,7 @@
"headers": "Başlıklar",
"headers.allow-from": "NodeBB'yi bir iFrame'e yerleştirmek için ALLOW-FROM'u ayarla",
"headers.csp-frame-ancestors": "NodeBB'yi bir iFrame'e yerleştirmek için Content-Security-Policy frame-ancestors başlığını ayarla",
- "headers.csp-frame-ancestors-help": "'none', 'self'(default) or list of URIs to allow.",
+ "headers.csp-frame-ancestors-help": "\"yok\", \"iç\" (varsayılan) veya izin verilecek URI'lerin listesi.",
"headers.powered-by": "NodeBB tarafından gönderilen \"Powered By\" başlığını özelleştirin",
"headers.acao": "Erişim-Kontrolü-Kaynak-İzni",
"headers.acao-regex": "Erişim-Kontrolü-Kaynak-İzni Düzenli İfade",
@@ -36,8 +36,8 @@
"analytics.settings": "Analitik Ayarlar",
"analytics.max-cache": "Analitik Önbellek Maksimum Değeri",
- "analytics.max-cache-help": "On high-traffic installs, the cache could be exhausted continuously if there are more concurrent active users than the Max Cache value. (Restart required)",
+ "analytics.max-cache-help": "Yüksek trafikli zamanlarda, Maksimum Önbellek değerinden daha fazla eşzamanlı etkin kullanıcı varsa önbellek sürekli olarak tüketilebilir. (Yeniden başlatmak gerekir)",
"compression.settings": "Sıkıştırma Ayarları",
"compression.enable": "Sıkıştırmayı Aktifleştir",
- "compression.help": "This setting enables gzip compression. For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level. You can enable it here for testing purposes."
+ "compression.help": "Bu ayar gzip sıkıştırmasını etkinleştirir. Üretimdeki yüksek trafiğe sahip bir web sitesi için sıkıştırmayı uygulamaya koymanın en iyi yolu ters proxy düzeyinden uygulamaktır. Test amacıyla buradan etkinleştirebilirsiniz."
}
\ No newline at end of file
diff --git a/public/language/tr/admin/settings/api.json b/public/language/tr/admin/settings/api.json
index 4cf4394504..1f1f40a6b5 100644
--- a/public/language/tr/admin/settings/api.json
+++ b/public/language/tr/admin/settings/api.json
@@ -2,14 +2,14 @@
"tokens": "Jetonlar (Tokens)",
"settings": "Ayarlar",
"lead-text": "Bu sayfadan NodeBB'deki \"Write API\"e erişimi yapılandırabilirsiniz.",
- "intro": "By default, the Write API authenticates users based on their session cookie, but NodeBB also supports Bearer authentication via tokens generated via this page.",
+ "intro": "Varsayılan olarak, Yazma API'si kullanıcıların kimliklerini oturum tanımlama bilgileri temelinde doğrular, ancak NodeBB ayrıca bu sayfa aracılığıyla oluşturulan belirteçler aracılığıyla Taşıyıcı kimlik doğrulamasını da destekler.",
"docs": "Tüm API özeliklerine erişmek için buraya tıklayın. ",
"require-https": "API kullanımı için HTTPS kısıtlaması gerektir",
- "require-https-caveat": "Note: Some installations involving load balancers may proxy their requests to NodeBB using HTTP, in which case this option should remain disabled.",
+ "require-https-caveat": "Not: Yük dengeleyicilerini içeren bazı kurulumlar, isteklerini HTTP kullanarak NodeBB'ye proxy uygulayabilir, bu durumda bu seçenek devre dışı kalmalıdır.",
"uid": "Kullanıcı ID",
- "uid-help-text": "Specify a User ID to associate with this token. If the user ID is 0, it will be considered a master token, which can assume the identity of other users based on the _uid parameter",
+ "uid-help-text": "Bu jetonla ilişkilendirilecek bir Kullanıcı Kimliği belirtin. Kullanıcı kimliği 0 ise, diğer kullanıcıların kimliğini _uid parametresine göre üstlenebilen bir ana simge olarak kabul edilir.",
"description": "Açıklama",
"no-description": "Hiçbir açıklama belirtilmemiş.",
"token-on-save": "Form kaydedildikten sonra bir jeton oluşturulacak"
diff --git a/public/language/tr/error.json b/public/language/tr/error.json
index 43809043b5..d565877c83 100644
--- a/public/language/tr/error.json
+++ b/public/language/tr/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Kendinizi gruptan atamazsınız.",
"no-users-selected": "Seçili kullanıcı(lar) bulunamadı",
"invalid-home-page-route": "Geçersiz anasayfa yolu",
- "invalid-session": "Oturum Uyuşmazlığı",
- "invalid-session-text": "Senin giriş oturumun pek aktif gözükmüyor, ya da sunucu ile eşleşmiyor. Lütfen sayfayı yenileyiniz.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Hiçbir başlık seçilmedi!",
"cant-move-to-same-topic": "İletiyi aynı başlığa taşıyamazsın!",
"cant-move-topic-to-same-category": "Başlığı bulunduğu kategoriye taşıyamazsınız!",
diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json
index 1160f55cc4..73ed0560ef 100644
--- a/public/language/tr/notifications.json
+++ b/public/language/tr/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 iletileri hazırlandı, indirmek için tıklayınız",
"uploads-exported": "%1 yüklemeleri hazırlandı, indirmek için tıklayınız",
"users-csv-exported": "Kullanıcılar csv hazırlandı, indirmek için tıklayınız",
+ "post-queue-accepted": "Sıradaki gönderiniz kabul edildi. Gönderinizi görmek için burayı tıklayın.",
+ "post-queue-rejected": "Sıraya alınmış gönderiniz reddedildi.",
"email-confirmed": "E-posta onaylandı",
"email-confirmed-message": "E-postanızı onayladığınız için teşekkürler. Hesabınız tamamen aktif edildi.",
"email-confirm-error-message": "E-posta adresinizi onaylarken bir hata oluştu. Kodunuz geçersiz ya da eski olabilir.",
diff --git a/public/language/tr/success.json b/public/language/tr/success.json
index 0e16198149..d474f90a92 100644
--- a/public/language/tr/success.json
+++ b/public/language/tr/success.json
@@ -1,7 +1,7 @@
{
"success": "Başarılı",
"topic-post": "Başarıyla gönderim yaptınız.",
- "post-queued": "İletiniz onay için sıraya alındı.",
+ "post-queued": "Gönderiniz onay için sıraya alındı. Kabul edildiğinde veya reddedildiğinde bir bildirim alacaksınız.",
"authentication-successful": "Doğrulama Başarılı",
"settings-saved": "Ayarlar kaydedildi!"
}
\ No newline at end of file
diff --git a/public/language/uk/admin/manage/categories.json b/public/language/uk/admin/manage/categories.json
index 771588b319..6198af0464 100644
--- a/public/language/uk/admin/manage/categories.json
+++ b/public/language/uk/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
+ "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Вибрати категорію",
"set-parent-category": "Встановити батьківську категорію",
diff --git a/public/language/uk/error.json b/public/language/uk/error.json
index 47841172fd..106f6a9bef 100644
--- a/public/language/uk/error.json
+++ b/public/language/uk/error.json
@@ -174,8 +174,10 @@
"cant-kick-self": "Ви не можете вигнати самі себе з групи",
"no-users-selected": "Не вибрано жодного користувача",
"invalid-home-page-route": "Невірний шлях на головну",
- "invalid-session": "Сесія не існує",
- "invalid-session-text": "Здається, що ваша сесія більше неактивна або розійшлася з серверною. Оновіть, будь ласка, цю сторінку.",
+ "invalid-session": "Invalid Session",
+ "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
+ "session-mismatch": "Session Mismatch",
+ "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"no-topics-selected": "Не вибрано жодної теми!",
"cant-move-to-same-topic": "Ви не можете перемістити пост до тієї ж самої теми!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
diff --git a/public/language/uk/notifications.json b/public/language/uk/notifications.json
index 81db999a59..b5b72f459f 100644
--- a/public/language/uk/notifications.json
+++ b/public/language/uk/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 posts exported, click to download",
"uploads-exported": "%1 uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
+ "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
+ "post-queue-rejected": "Your queued post has been rejected.",
"email-confirmed": "Електронну пошту підтверджено",
"email-confirmed-message": "Дякуємо за підтвердження електронної пошти. Ваш акаунт тепер повністю активовано.",
"email-confirm-error-message": "При перевірці вашої електронної пошти сталася проблема. Можливо код був недійсним або простроченим.",
diff --git a/public/language/uk/success.json b/public/language/uk/success.json
index df20ad7bdf..e6f239a285 100644
--- a/public/language/uk/success.json
+++ b/public/language/uk/success.json
@@ -1,7 +1,7 @@
{
"success": "Успіх",
"topic-post": "Публікацію успішно створено.",
- "post-queued": "Ваш пост поставлений в чергу на схвалення.",
+ "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"authentication-successful": "Аутентифікація успішна",
"settings-saved": "Налаштування збережені!"
}
\ No newline at end of file
diff --git a/public/language/vi/admin/manage/categories.json b/public/language/vi/admin/manage/categories.json
index 833b2ffc2f..391eecb2f5 100644
--- a/public/language/vi/admin/manage/categories.json
+++ b/public/language/vi/admin/manage/categories.json
@@ -33,6 +33,7 @@
"analytics": "Phân tích",
"view-category": "Xem chuyên mục",
"set-order": "Đặt thứ tự",
+ "set-order-help": "Đặt thứ tự của danh mục sẽ chuyển danh mục này sang thứ tự đó và cập nhật thứ tự của các danh mục khác khi cần thiết. Thứ tự tối thiểu là 1 đặt danh mục ở trên cùng.",
"select-category": "Chọn Chuyên Mục",
"set-parent-category": "Đặt Chuyên Mục Chính",
diff --git a/public/language/vi/error.json b/public/language/vi/error.json
index 7a92cd3901..a6819cce3a 100644
--- a/public/language/vi/error.json
+++ b/public/language/vi/error.json
@@ -174,8 +174,10 @@
"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",
"invalid-home-page-route": "Đường dẫn trang chủ không hợp lệ",
- "invalid-session": "Không Khớp Phiên",
- "invalid-session-text": "Có vẻ như phiên đăng nhập của bạn không hoạt động, hoặc không đúng với thông tin trên máy chủ. Vui lòng tải lại trang này",
+ "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.",
+ "session-mismatch": "Phiên Không Khớp",
+ "session-mismatch-text": "Có vẻ như phiên đăng nhập của bạn không còn khớp với máy chủ. Vui lòng làm mới trang này.",
"no-topics-selected": "Không có chủ đề nào đang được chọn!",
"cant-move-to-same-topic": "Bạn không thể di chuyển bài viết vào cùng chủ đề hiện tại!",
"cant-move-topic-to-same-category": "Không thể di chuyển chủ đề sang cùng chuyên mục!",
diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json
index 3c5755694e..3fbf9c8f69 100644
--- a/public/language/vi/modules.json
+++ b/public/language/vi/modules.json
@@ -1,6 +1,6 @@
{
"chat.chatting_with": "Trò chuyện với",
- "chat.placeholder": "Nhập tin nhắn ở đây, nhấn enter để gửi",
+ "chat.placeholder": "Nhập tin nhắn trò chuyện ở đây, nhấn enter để gửi",
"chat.scroll-up-alert": "Bạn đang xem các tin nhắn cũ hơn, nhấp vào đây để chuyển đến tin nhắn gần đây nhất.",
"chat.send": "Gửi",
"chat.no_active": "Bạn không có cuộc trò chuyện đang hoạt động nào.",
diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json
index e1478d87d4..6a6ed2cbbb 100644
--- a/public/language/vi/notifications.json
+++ b/public/language/vi/notifications.json
@@ -47,6 +47,8 @@
"posts-exported": "%1 đã xuất bài viết, nhấn tải xuống",
"uploads-exported": "%1 đã xuất tải lên, nhấn tải xuống",
"users-csv-exported": "Đã xuất csv người dùng, nhấp để tải xuống",
+ "post-queue-accepted": "Bài đăng trong hàng đợi của bạn đã được chấp nhận. Nhấn vào đây để xem bài viết của bạn.",
+ "post-queue-rejected": "Bài đăng trong hàng đợi của bạn đã bị từ chối",
"email-confirmed": "Đã Xác Nhận Email",
"email-confirmed-message": "Cảm ơn bạn đã xác nhận địa chỉ email của bạn. Tài khoản của bạn đã được kích hoạt đầy đủ.",
"email-confirm-error-message": "Đã có lỗi khi xác nhận địa chỉ email. Có thể đoạn mã không đúng hoặc đã hết hạn.",
diff --git a/public/language/vi/success.json b/public/language/vi/success.json
index 7f37c5fa4c..f4034365f8 100644
--- a/public/language/vi/success.json
+++ b/public/language/vi/success.json
@@ -1,7 +1,7 @@
{
"success": "Thành công",
"topic-post": "Bạn đã đăng bài thành công",
- "post-queued": "Bài đăng của bạn được chờ xét duyệt.",
+ "post-queued": "Bài đăng của bạn được xếp hàng để phê duyệt. Bạn sẽ nhận được thông báo khi nó được chấp nhận hoặc bị từ chối.",
"authentication-successful": "Xác thực thành công",
"settings-saved": "Đã lưu thiết lập"
}
\ 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 9cf1dd41b7..427fdb412a 100644
--- a/public/language/zh-CN/admin/dashboard.json
+++ b/public/language/zh-CN/admin/dashboard.json
@@ -2,7 +2,7 @@
"forum-traffic": "论坛流量",
"page-views": "页面浏览量",
"unique-visitors": "单一访客",
- "logins": "Logins",
+ "logins": "登录",
"new-users": "新用户",
"posts": "发帖",
"topics": "主题",
@@ -30,7 +30,7 @@
"upgrade-available": "新的版本 (v%1) 已经发布。建议您 升级 NodeBB。
", "prerelease-upgrade-available": "这是一个已经过期的预发布版本的 NodeBB,新的版本 (v%1) 已经发布。建议您 升级 NodeBB。
", "prerelease-warning": "正在使用测试版 NodeBB。可能会出现意外的 Bug。
", - "fallback-emailer-not-found": "Fallback emailer not found!", + "fallback-emailer-not-found": "找不到备用邮箱", "running-in-development": "论坛正处于开发模式,这可能使其暴露于潜在的危险之中;请联系您的系统管理员。", "latest-lookup-failed": "无法查找 NodeBB 的最新可用版本
", @@ -79,10 +79,10 @@ "last-restarted-by": "上次重启管理员/时间", "no-users-browsing": "没有用户正在浏览", - "back-to-dashboard": "Back to Dashboard", - "details.no-users": "No users have joined within the selected timeframe", - "details.no-topics": "No topics have been posted within the selected timeframe", - "details.no-logins": "No logins have been recorded within the selected timeframe", - "details.logins-static": "NodeBB only saves session data for %1 days, and so this table below will only show the most recently active sessions", - "details.logins-login-time": "Login Time" + "back-to-dashboard": "返回控制面板", + "details.no-users": "选定的时间内没有用户加入", + "details.no-topics": "选定的时间内没有发布主题", + "details.no-logins": "选定的时间内没有登录记录", + "details.logins-static": "NodeBB只保留%1天登录数据,下列表格显示最近活动的登录。", + "details.logins-login-time": "登录时间" } diff --git a/public/language/zh-CN/admin/extend/plugins.json b/public/language/zh-CN/admin/extend/plugins.json index c69c28021d..27e29a407f 100644 --- a/public/language/zh-CN/admin/extend/plugins.json +++ b/public/language/zh-CN/admin/extend/plugins.json @@ -39,7 +39,7 @@ "alert.upgraded": "插件已升级", "alert.installed": "插件已安装", "alert.uninstalled": "插件已卸载", - "alert.activate-success": "Please rebuild and restart your NodeBB to fully activate this plugin", + "alert.activate-success": "请重新编译和启动NodeBB以激活此插件", "alert.deactivate-success": "插件停用成功", "alert.upgrade-success": "请部署并重启您的 NodeBB 来完成更新此插件。", "alert.install-success": "插件安装成功,请启用插件。", diff --git a/public/language/zh-CN/admin/manage/categories.json b/public/language/zh-CN/admin/manage/categories.json index a4e8536ede..febfc938ed 100644 --- a/public/language/zh-CN/admin/manage/categories.json +++ b/public/language/zh-CN/admin/manage/categories.json @@ -33,6 +33,7 @@ "analytics": "分析", "view-category": "查看版块", "set-order": "Set order", + "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.", "select-category": "选择版块", "set-parent-category": "设置父版块", diff --git a/public/language/zh-CN/admin/manage/privileges.json b/public/language/zh-CN/admin/manage/privileges.json index 638395ebd4..d924b77dd4 100644 --- a/public/language/zh-CN/admin/manage/privileges.json +++ b/public/language/zh-CN/admin/manage/privileges.json @@ -4,13 +4,13 @@ "group-privileges": "群组权限", "user-privileges": "用户权限", "edit-privileges": "编辑权限", - "select-clear-all": "Select/Clear All", + "select-clear-all": "选择/清除 全部", "chat": "对话", "upload-images": "上传图片", "upload-files": "上传文件", "signature": "签名档", "ban": "封禁", - "invite": "Invite", + "invite": "邀请", "search-content": "搜索内容", "search-users": "搜索用户", "search-tags": "搜索话题", @@ -41,8 +41,8 @@ "admin-privileges": "权限", "admin-users": "用户", "admin-admins-mods": "Admins & Mods", - "admin-groups": "Groups", - "admin-tags": "Tags", + "admin-groups": "群组", + "admin-tags": "话题", "admin-settings": "设置", "alert.confirm-moderate": "您确定要将审核权限授予此用户组吗?此用户组是公开的,任何用户都可以随意加入。", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index 4c35f7f5b0..81a5194eb9 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -174,8 +174,10 @@ "cant-kick-self": "您不能把自己踢出群组", "no-users-selected": "尚未选择用户", "invalid-home-page-route": "无效的首页路径", - "invalid-session": "Session 无法匹配", - "invalid-session-text": "您的登入状态已经失效,或者是与服务器信息不匹配。请刷新此页面。", + "invalid-session": "Invalid Session", + "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", + "session-mismatch": "Session Mismatch", + "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.", "no-topics-selected": "没有主题被选中!", "cant-move-to-same-topic": "无法将帖子移动到相同的主题中!", "cant-move-topic-to-same-category": "无法将主题移动到相同的版块!", diff --git a/public/language/zh-CN/notifications.json b/public/language/zh-CN/notifications.json index ac864191f6..335b8d5f1b 100644 --- a/public/language/zh-CN/notifications.json +++ b/public/language/zh-CN/notifications.json @@ -47,6 +47,8 @@ "posts-exported": "%1帖子已导出,点击下载", "uploads-exported": "%1上传已导出,点击下载", "users-csv-exported": "Users csv exported, click to download", + "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.", + "post-queue-rejected": "Your queued post has been rejected.", "email-confirmed": "电子邮箱已确认", "email-confirmed-message": "感谢您验证您的电子邮箱。您的帐户现已完全激活。", "email-confirm-error-message": "验证的您电子邮箱地址时出现了问题。可能是因为验证码无效或已过期。", diff --git a/public/language/zh-CN/post-queue.json b/public/language/zh-CN/post-queue.json index a63312d82b..721af42702 100644 --- a/public/language/zh-CN/post-queue.json +++ b/public/language/zh-CN/post-queue.json @@ -8,11 +8,11 @@ "content": "内容", "posted": "发布", "reply-to": "回复\"%1\"", - "content-editable": "Click on content to edit", - "category-editable": "Click on category to edit", - "title-editable": "Click on title to edit", - "reply": "Reply", - "topic": "Topic", - "accept": "Accept", - "reject": "Reject" + "content-editable": "点击内容开始编辑", + "category-editable": "点击版块开始编辑", + "title-editable": "点击标题开始编辑", + "reply": "回复", + "topic": "主题", + "accept": "接受", + "reject": "拒绝" } \ No newline at end of file diff --git a/public/language/zh-CN/success.json b/public/language/zh-CN/success.json index 0b0f706dec..951863f0a6 100644 --- a/public/language/zh-CN/success.json +++ b/public/language/zh-CN/success.json @@ -1,7 +1,7 @@ { "success": "成功", "topic-post": "您已成功发布。", - "post-queued": "您的帖子正在等待审核。", + "post-queued": "你的帖子正在等待批准。帖子被批准或者拒绝的时候,你会收到一个通知。", "authentication-successful": "验证成功", "settings-saved": "设置已保存!" } \ No newline at end of file diff --git a/public/language/zh-CN/user.json b/public/language/zh-CN/user.json index be98b84f01..01df3bc8b7 100644 --- a/public/language/zh-CN/user.json +++ b/public/language/zh-CN/user.json @@ -84,7 +84,7 @@ "remove_cover_picture_confirm": "您确定要移除封面图片吗?", "crop_picture": "剪裁图片", "upload_cropped_picture": "剪裁并上传", - "avatar-background-colour": "Avatar background colour", + "avatar-background-colour": "头像背景颜色", "settings": "设置", "show_email": "显示我的电子邮箱", "show_fullname": "显示我的全名", @@ -124,7 +124,7 @@ "open_links_in_new_tab": "在新标签打开外部链接", "enable_topic_searching": "启用主题内搜索", "topic_search_help": "如果启用此项,主题内搜索会替代浏览器默认的页面搜索,您将可以在整个主题内搜索,而不仅仅只搜索页面上展现的内容。", - "update_url_with_post_index": "Update url with post index while browsing topics", + "update_url_with_post_index": "浏览主题是更新链接和索引", "scroll_to_my_post": "在提交回复之后显示新回复", "follow_topics_you_reply_to": "关注您回复过的主题", "follow_topics_you_create": "关注您创建的主题", @@ -136,7 +136,7 @@ "homepage": "首页", "homepage_description": "选择一个页面作为论坛的首页,否则设置为 ‘空’ 使用默认首页。", "custom_route": "自定义首页路由", - "custom_route_help": "Enter a route name here, without any preceding slash (e.g. \"recent\" or \"category/2/general-discussion\")", + "custom_route_help": "输入路由名称,前面不需要斜杠 ( 例如, \"recent\" 或 \"category/2/general-discussion\" )", "sso.title": "单点登录服务", "sso.associated": "已关联到", "sso.not-associated": "点击这里来关联", diff --git a/public/language/zh-CN/users.json b/public/language/zh-CN/users.json index 6cdac0c1cc..9b1f392eb8 100644 --- a/public/language/zh-CN/users.json +++ b/public/language/zh-CN/users.json @@ -11,7 +11,7 @@ "online-only": "只看在线", "invite": "邀请注册", "prompt-email": "邮件:", - "groups-to-join": "Groups to be joined when invite is accepted:", + "groups-to-join": "邀请接受时要加入的群组:", "invitation-email-sent": "已发送邀请给 %1", "user_list": "用户列表", "recent_topics": "最新主题", diff --git a/public/language/zh-TW/admin/manage/categories.json b/public/language/zh-TW/admin/manage/categories.json index 6ff8e3121d..6f79081a24 100644 --- a/public/language/zh-TW/admin/manage/categories.json +++ b/public/language/zh-TW/admin/manage/categories.json @@ -33,6 +33,7 @@ "analytics": "Analytics", "view-category": "View category", "set-order": "Set order", + "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.", "select-category": "選擇版面", "set-parent-category": "設置上層版面", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index c20cdbd407..0fa4215f22 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -174,8 +174,10 @@ "cant-kick-self": "您不能把自己踢出群組", "no-users-selected": "尚未選擇使用者", "invalid-home-page-route": "無效的首頁路徑", - "invalid-session": "無效 Session", - "invalid-session-text": "您的登入狀態已經失效,或者是與伺服器資訊不一致。請重載此頁面。", + "invalid-session": "Invalid Session", + "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", + "session-mismatch": "Session Mismatch", + "session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.", "no-topics-selected": "沒有主題被選中!", "cant-move-to-same-topic": "無法將貼文移動到相同的主題中!", "cant-move-topic-to-same-category": "Can't move topic to the same category!", diff --git a/public/language/zh-TW/notifications.json b/public/language/zh-TW/notifications.json index 8951ca9a2a..d8b721e037 100644 --- a/public/language/zh-TW/notifications.json +++ b/public/language/zh-TW/notifications.json @@ -47,6 +47,8 @@ "posts-exported": "%1 posts exported, click to download", "uploads-exported": "%1 uploads exported, click to download", "users-csv-exported": "Users csv exported, click to download", + "post-queue-accepted": "Your queued post has been accepted. Click here to see your post.", + "post-queue-rejected": "Your queued post has been rejected.", "email-confirmed": "電子信箱已確認", "email-confirmed-message": "感謝您驗證您的電子信箱。您的帳戶現已完全啟用。", "email-confirm-error-message": "驗證的您電子信箱地址時出現了問題。可能是因為驗證碼無效或已過期。", diff --git a/public/language/zh-TW/success.json b/public/language/zh-TW/success.json index d5b8b0089d..759e67120d 100644 --- a/public/language/zh-TW/success.json +++ b/public/language/zh-TW/success.json @@ -1,7 +1,7 @@ { "success": "成功", "topic-post": "您已成功發佈。", - "post-queued": "您的貼文正在等待審核。", + "post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.", "authentication-successful": "驗證成功", "settings-saved": "設定已儲存!" } \ No newline at end of file diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml index 0058822c63..6605079d47 100644 --- a/public/openapi/read.yaml +++ b/public/openapi/read.yaml @@ -13,7 +13,7 @@ info: ## Shortcomings - The Read API is named because its primary use is by NodeBB itself when navigating between pages. Therefore, the routes almost universally always follow the same path as actual pages on NodeBB itself. There are also a small number of non-`GET` routes, which doesn't necessarily make sense in a Read API. These will be merged into the Write API in time. + The Read API is named because its primary use is by NodeBB itself when navigating between pages. Therefore, the routes almost universally always follow the same path as actual pages on NodeBB itself. There are also a small number of non-`GET` routes, which do not make sense in a Read API. These will be merged into the Write API in time. ## Authentication @@ -21,14 +21,23 @@ info: ### Cookie Authentication - This default authentication behaviour of this API is via cookie jar to find a valid session. A valid login session is required for API calls that pertain to operations involving a logged-in user. For example, `/api/unread` is a route showing unread topics, and is not accessible by guest users. + By default, the API will attempt to find a valid session in the browser's cookies. A valid login session is required for API calls that pertain to operations involving a logged-in user. For example, `/api/unread` is a route showing unread topics, and is not accessible by guest users. + + Most data transfer utilities like cURL will allow you to construct something like a cookie, to be sent alongside the request, to function much like a browser cookie. This should work with the API. ### Bearer Authentication - Both the Read API and Write API offers bearer authentication, as administered through the administration panel. + Both the Read API and Write API offer bearer authentication, as administered through the administration panel. - * For NodeBB v1.x, this is provided by [`nodebb-plugin-write-api`](https://github.com/NodeBB/nodebb-plugin-write-api). The Write API plugin needs to be installed before authentication via bearer token is enabled on routes provided by the Read API. - * For NodeBB v2.x+ (in development), the Write API is available in core, and bearer authentication is available out-of-the-box + * Up until v1.14.3, this is provided by [`nodebb-plugin-write-api`](https://github.com/NodeBB/nodebb-plugin-write-api). The Write API plugin needs to be installed before authentication via bearer token is enabled on routes provided by the Read API. + * From NodeBB v1.15.0 onwards, the Write API is available in core, and bearer authentication is available out-of-the-box + + In both cases, a bearer token is issued in the NodeBB admin panel in order to grant access to the API. + + There are two types of tokens: + * A *user token* is associated with a specific uid, and all calls made are made in the name of that user + * A *master token* is not associated with any specific uid, though a `_uid` parameter is required in the request, and then all calls are made in the name of *that* user. + This is the only difference between the two tokens. A master token with `_uid` set to a non-administrator will not allow you to make administrative calls. tags: - name: home description: Routes used at the forum index only diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index b7d1363e1d..8bf652c3d8 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -15,6 +15,10 @@ info: Years prior to this determination, many users of NodeBB had asked for a RESTful API to call against NodeBB, which led to the creation of [`nodebb-plugin-write-api`](https://github.com/NodeBB/nodebb-plugin-write-api). In tandem with the above decision, the Write API was merged into NodeBB core in late 2020. v3 of the Write API (this document) achieves rough feature parity with v2 of the Write API plugin. + + # Authentication + + Please see the ["Authentication" section under the Read API](../read/#section/Overview/Authentication) for more information on how to authenticate against this API in order to make calls. version: 1.15.0 contact: email: support@nodebb.org diff --git a/public/src/admin/manage/categories.js b/public/src/admin/manage/categories.js index d077ad9d39..c6d1307a4d 100644 --- a/public/src/admin/manage/categories.js +++ b/public/src/admin/manage/categories.js @@ -49,7 +49,7 @@ define('admin/manage/categories', [ var order = $(this).attr('data-order'); var modal = bootbox.dialog({ title: '[[admin/manage/categories:set-order]]', - message: '', + message: '[[admin/manage/categories:set-order-help]]
', show: true, buttons: { save: { diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index af52676726..883c0f12a7 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -473,10 +473,11 @@ $(document).ready(function () { var href = $this.attr('href'); var internalLink = utils.isInternalURI(this, window.location, config.relative_path); + const rootAndPath = new RegExp(`^${rootUrl}${config.relative_path}/?`); var process = function () { if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) { if (internalLink) { - var pathname = this.href.replace(rootUrl + config.relative_path + '/', ''); + var pathname = this.href.replace(rootAndPath, ''); // Special handling for urls with hashes if (window.location.pathname === this.pathname && this.hash.length) { diff --git a/public/src/app.js b/public/src/app.js index aa3e9f6088..eacfb7e2ee 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -181,9 +181,9 @@ app.cacheBuster = null; app.alertError = function (message, timeout) { message = (message && message.message) || message; - if (message === '[[error:invalid-session]]') { - app.handleInvalidSession(); - app.logout(false); + if (message === '[[error:revalidate-failure]]') { + socket.disconnect(); + app.reconnect(); return; } @@ -197,14 +197,27 @@ app.cacheBuster = null; }; app.handleInvalidSession = function () { + socket.disconnect(); + app.logout(false); + bootbox.alert({ + title: '[[error:invalid-session]]', + message: '[[error:invalid-session-text]]', + closeButton: false, + callback: function () { + window.location.reload(); + }, + }); + }; + + app.handleSessionMismatch = () => { if (app.flags._login || app.flags._logout) { return; } socket.disconnect(); bootbox.alert({ - title: '[[error:invalid-session]]', - message: '[[error:invalid-session-text]]', + title: '[[error:session-mismatch]]', + message: '[[error:session-mismatch-text]]', closeButton: false, callback: function () { window.location.reload(); @@ -799,7 +812,8 @@ app.cacheBuster = null; }; function registerServiceWorker() { - if ('serviceWorker' in navigator) { + // Do not register for Safari browsers + if (!ajaxify.data._locals.useragent.isSafari && 'serviceWorker' in navigator) { navigator.serviceWorker.register(config.relative_path + '/service-worker.js', { scope: config.relative_path + '/' }) .then(function () { console.info('ServiceWorker registration succeeded.'); diff --git a/public/src/client/account/edit/username.js b/public/src/client/account/edit/username.js index 350ce38bd3..076da3e452 100644 --- a/public/src/client/account/edit/username.js +++ b/public/src/client/account/edit/username.js @@ -27,7 +27,6 @@ define('forum/account/edit/username', [ btn.addClass('disabled').find('i').removeClass('hide'); api.put('/users/' + userData.uid, userData).then((response) => { - btn.removeClass('disabled').find('i').addClass('hide'); var userslug = slugify(userData.username); if (userData.username && userslug && parseInt(userData.uid, 10) === parseInt(app.user.uid, 10)) { $('[component="header/profilelink"]').attr('href', config.relative_path + '/user/' + userslug); @@ -38,7 +37,10 @@ define('forum/account/edit/username', [ } ajaxify.go('user/' + userslug + '/edit'); - }).catch(app.alertError); + }).catch(app.alertError) + .finally(() => { + btn.removeClass('disabled').find('i').addClass('hide'); + }); return false; }); diff --git a/public/src/client/infinitescroll.js b/public/src/client/infinitescroll.js index 0ada79cd04..2f66ce91a8 100644 --- a/public/src/client/infinitescroll.js +++ b/public/src/client/infinitescroll.js @@ -10,15 +10,20 @@ define('forum/infinitescroll', function () { var scrollTimeout = 0; scroll.init = function (el, cb) { + const $body = $('body'); if (typeof el === 'function') { callback = el; - container = $('body'); + container = $body; } else { callback = cb; - container = el || $('body'); + container = el || $body; } previousScrollTop = $(window).scrollTop(); $(window).off('scroll', startScrollTimeout).on('scroll', startScrollTimeout); + + if ($body.height() <= $(window).height()) { + callback(1); + } }; function startScrollTimeout() { diff --git a/public/src/sockets.js b/public/src/sockets.js index 5c27f979d7..6c4c4b62c3 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -70,13 +70,18 @@ socket = window.socket; .find('p') .translateText('[[error:socket-reconnect-failed]]') .one('click', app.reconnect); + + $(window).one('focus', app.reconnect); }); socket.on('checkSession', function (uid) { if (parseInt(uid, 10) !== parseInt(app.user.uid, 10)) { - app.handleInvalidSession(); + app.handleSessionMismatch(); } }); + socket.on('event:invalid_session', () => { + app.handleInvalidSession(); + }); socket.on('setHostname', function (hostname) { app.upstreamHost = hostname; diff --git a/public/src/utils.js b/public/src/utils.js index 56b4c46573..fa9864ac5c 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -469,7 +469,9 @@ makeNumbersHumanReadable: function (elements) { elements.each(function () { - $(this).html(utils.makeNumberHumanReadable($(this).attr('title'))); + $(this) + .html(utils.makeNumberHumanReadable($(this).attr('title'))) + .removeClass('hidden'); }); }, @@ -488,7 +490,9 @@ addCommasToNumbers: function (elements) { elements.each(function (index, element) { - $(element).html(utils.addCommas($(element).html())); + $(element) + .html(utils.addCommas($(element).html())) + .removeClass('hidden'); }); }, diff --git a/src/api/helpers.js b/src/api/helpers.js index 27481318e9..82a379ae40 100644 --- a/src/api/helpers.js +++ b/src/api/helpers.js @@ -20,7 +20,7 @@ exports.setDefaultPostData = function (reqOrSocket, data) { // creates a slimmed down version of the request object exports.buildReqObject = (req, payload) => { req = req || {}; - const headers = req.headers || {}; + const headers = req.headers || (req.request && req.request.headers) || {}; const encrypted = req.connection ? !!req.connection.encrypted : false; let { host } = headers; const referer = headers.referer || ''; diff --git a/src/categories/create.js b/src/categories/create.js index 93121dc8b9..b5068ff0dc 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -170,6 +170,11 @@ module.exports = function (Categories) { if (copyParent) { destination.parentCid = source.parentCid || 0; } + await plugins.hooks.fire('filter:categories.copySettingsFrom', { + source: source, + destination: destination, + copyParent: copyParent, + }); await db.setObject(`category:${toCid}`, destination); diff --git a/src/cli/package-install.js b/src/cli/package-install.js index 4f391c18c1..caad43162a 100644 --- a/src/cli/package-install.js +++ b/src/cli/package-install.js @@ -66,7 +66,7 @@ function installAll() { } } } catch (e) { - // ignore + console.error(e); } try { cproc.execSync(command + (prod ? ' --production' : ''), { diff --git a/src/cli/upgrade-plugins.js b/src/cli/upgrade-plugins.js index 8ec46f7a62..b6cd6ac2a7 100644 --- a/src/cli/upgrade-plugins.js +++ b/src/cli/upgrade-plugins.js @@ -1,13 +1,13 @@ 'use strict'; -const async = require('async'); const prompt = require('prompt'); -const request = require('request'); +const request = require('request-promise-native'); const cproc = require('child_process'); const semver = require('semver'); const fs = require('fs'); const path = require('path'); const nconf = require('nconf'); +const util = require('util'); const { paths, pluginNamePattern } = require('../constants'); @@ -22,190 +22,142 @@ if (process.platform === 'win32') { packageManagerExecutable += '.cmd'; } -function getModuleVersions(modules, callback) { +async function getModuleVersions(modules) { const versionHash = {}; - - async.eachLimit(modules, 50, (module, next) => { - fs.readFile(path.join(paths.nodeModules, module, 'package.json'), { encoding: 'utf-8' }, (err, pkg) => { - if (err) { - return next(err); - } - - try { - pkg = JSON.parse(pkg); - versionHash[module] = pkg.version; - next(); - } catch (err) { - next(err); - } - }); - }, (err) => { - callback(err, versionHash); - }); -} - -function getInstalledPlugins(callback) { - async.parallel({ - files: async.apply(fs.readdir, paths.nodeModules), - deps: async.apply(fs.readFile, paths.currentPackage, { encoding: 'utf-8' }), - bundled: async.apply(fs.readFile, paths.installPackage, { encoding: 'utf-8' }), - }, (err, payload) => { - if (err) { - return callback(err); - } - - payload.files = payload.files.filter(file => pluginNamePattern.test(file)); - - try { - payload.deps = Object.keys(JSON.parse(payload.deps).dependencies); - payload.bundled = Object.keys(JSON.parse(payload.bundled).dependencies); - } catch (err) { - return callback(err); - } - - payload.bundled = payload.bundled.filter(pkgName => pluginNamePattern.test(pkgName)); - payload.deps = payload.deps.filter(pkgName => pluginNamePattern.test(pkgName)); - - // Whittle down deps to send back only extraneously installed plugins/themes/etc - const checklist = payload.deps.filter((pkgName) => { - if (payload.bundled.includes(pkgName)) { - return false; - } - - // Ignore git repositories - try { - fs.accessSync(path.join(paths.nodeModules, pkgName, '.git')); - return false; - } catch (e) { - return true; - } - }); - - getModuleVersions(checklist, callback); - }); -} - -function getCurrentVersion(callback) { - fs.readFile(paths.installPackage, { encoding: 'utf-8' }, (err, pkg) => { - if (err) { - return callback(err); - } - - try { + const batch = require('../batch'); + await batch.processArray(modules, async (moduleNames) => { + await Promise.all(moduleNames.map(async (module) => { + let pkg = await fs.promises.readFile( + path.join(paths.nodeModules, module, 'package.json'), { encoding: 'utf-8' } + ); pkg = JSON.parse(pkg); - } catch (err) { - return callback(err); - } - callback(null, pkg.version); + versionHash[module] = pkg.version; + })); + }, { + batch: 50, }); + + return versionHash; } -function checkPlugins(standalone, callback) { - if (standalone) { - process.stdout.write('Checking installed plugins and themes for updates... '); - } +async function getInstalledPlugins() { + let [deps, bundled] = await Promise.all([ + fs.promises.readFile(paths.currentPackage, { encoding: 'utf-8' }), + fs.promises.readFile(paths.installPackage, { encoding: 'utf-8' }), + ]); - async.waterfall([ - async.apply(async.parallel, { - plugins: getInstalledPlugins, - version: getCurrentVersion, - }), - function (payload, next) { - const toCheck = Object.keys(payload.plugins); + deps = Object.keys(JSON.parse(deps).dependencies) + .filter(pkgName => pluginNamePattern.test(pkgName)); + bundled = Object.keys(JSON.parse(bundled).dependencies) + .filter(pkgName => pluginNamePattern.test(pkgName)); - if (!toCheck.length) { - process.stdout.write(' OK'.green + ''.reset); - return next(null, []); // no extraneous plugins installed - } - request({ - method: 'GET', - url: `https://packages.nodebb.org/api/v1/suggest?version=${payload.version}&package[]=${toCheck.join('&package[]=')}`, - json: true, - }, (err, res, body) => { - if (err) { - process.stdout.write('error'.red + ''.reset); - return next(err); - } - process.stdout.write(' OK'.green + ''.reset); - - if (!Array.isArray(body) && toCheck.length === 1) { - body = [body]; - } - - let current; - let suggested; - const upgradable = body.map((suggestObj) => { - current = payload.plugins[suggestObj.package]; - suggested = suggestObj.version; - - if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) { - return { - name: suggestObj.package, - current: current, - suggested: suggested, - }; - } - return null; - }).filter(Boolean); - - next(null, upgradable); - }); - }, - ], callback); -} - -function upgradePlugins(callback) { - let standalone = false; - if (typeof callback !== 'function') { - callback = function () {}; - standalone = true; - } - - checkPlugins(standalone, (err, found) => { - if (err) { - console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset); - return callback(err); + // Whittle down deps to send back only extraneously installed plugins/themes/etc + const checklist = deps.filter((pkgName) => { + if (bundled.includes(pkgName)) { + return false; } + // Ignore git repositories + try { + fs.accessSync(path.join(paths.nodeModules, pkgName, '.git')); + return false; + } catch (e) { + return true; + } + }); + + return await getModuleVersions(checklist); +} + +async function getCurrentVersion() { + let pkg = await fs.promises.readFile(paths.installPackage, { encoding: 'utf-8' }); + pkg = JSON.parse(pkg); + return pkg.version; +} + +async function getSuggestedModules(nbbVersion, toCheck) { + let body = await request({ + method: 'GET', + url: `https://packages.nodebb.org/api/v1/suggest?version=${nbbVersion}&package[]=${toCheck.join('&package[]=')}`, + json: true, + }); + if (!Array.isArray(body) && toCheck.length === 1) { + body = [body]; + } + return body; +} + +async function checkPlugins() { + process.stdout.write('Checking installed plugins and themes for updates... '); + const [plugins, nbbVersion] = await Promise.all([ + getInstalledPlugins, + getCurrentVersion, + ]); + + const toCheck = Object.keys(plugins); + if (!toCheck.length) { + process.stdout.write(' OK'.green + ''.reset); + return []; // no extraneous plugins installed + } + const suggestedModules = await getSuggestedModules(nbbVersion, toCheck); + process.stdout.write(' OK'.green + ''.reset); + + let current; + let suggested; + const upgradable = suggestedModules.map((suggestObj) => { + current = plugins[suggestObj.package]; + suggested = suggestObj.version; + + if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) { + return { + name: suggestObj.package, + current: current, + suggested: suggested, + }; + } + return null; + }).filter(Boolean); + + return upgradable; +} + +async function upgradePlugins() { + try { + const found = await checkPlugins(); if (found && found.length) { process.stdout.write(`\n\nA total of ${String(found.length).bold} package(s) can be upgraded:\n\n`); found.forEach((suggestObj) => { process.stdout.write(`${' * '.yellow + suggestObj.name.reset} (${suggestObj.current.yellow}${' -> '.reset}${suggestObj.suggested.green}${')\n'.reset}`); }); } else { - if (standalone) { - console.log('\nAll packages up-to-date!'.green + ''.reset); - } - return callback(); + console.log('\nAll packages up-to-date!'.green + ''.reset); + return; } prompt.message = ''; prompt.delimiter = ''; + const promptGet = util.promisify((schema, callback) => prompt.get(schema, callback)); prompt.start(); - prompt.get({ + const result = await promptGet({ name: 'upgrade', description: '\nProceed with upgrade (y|n)?'.reset, type: 'string', - }, (err, result) => { - if (err) { - return callback(err); - } - - if (['y', 'Y', 'yes', 'YES'].includes(result.upgrade)) { - console.log('\nUpgrading packages...'); - const args = packageManagerInstallArgs.concat(found.map(suggestObj => `${suggestObj.name}@${suggestObj.suggested}`)); - - cproc.execFile(packageManagerExecutable, args, { stdio: 'ignore' }, (err) => { - callback(err, false); - }); - } else { - console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade -p'.green + '".'.reset); - callback(); - } }); - }); + + if (['y', 'Y', 'yes', 'YES'].includes(result.upgrade)) { + console.log('\nUpgrading packages...'); + const args = packageManagerInstallArgs.concat(found.map(suggestObj => `${suggestObj.name}@${suggestObj.suggested}`)); + + cproc.execFileSync(packageManagerExecutable, args, { stdio: 'ignore' }); + } else { + console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade -p'.green + '".'.reset); + } + } catch (err) { + console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset); + throw err; + } } exports.upgradePlugins = upgradePlugins; diff --git a/src/cli/upgrade.js b/src/cli/upgrade.js index 0e1e96b1da..2198203b53 100644 --- a/src/cli/upgrade.js +++ b/src/cli/upgrade.js @@ -1,72 +1,59 @@ 'use strict'; -const async = require('async'); const nconf = require('nconf'); const packageInstall = require('./package-install'); -const upgrade = require('../upgrade'); -const build = require('../meta/build'); -const db = require('../database'); const { upgradePlugins } = require('./upgrade-plugins'); const steps = { package: { message: 'Updating package.json file with defaults...', - handler: function (next) { + handler: function () { packageInstall.updatePackageFile(); packageInstall.preserveExtraneousPlugins(); process.stdout.write(' OK\n'.green); - next(); }, }, install: { message: 'Bringing base dependencies up to date...', - handler: function (next) { + handler: function () { process.stdout.write(' started\n'.green); packageInstall.installAll(); - next(); }, }, plugins: { message: 'Checking installed plugins for updates...', - handler: function (next) { - async.series([ - db.init, - upgradePlugins, - ], next); + handler: async function () { + await require('../database').init(); + await upgradePlugins(); }, }, schema: { message: 'Updating NodeBB data store schema...', - handler: function (next) { - async.series([ - db.init, - require('../meta').configs.init, - upgrade.run, - ], next); + handler: async function () { + await require('../database').init(); + await require('../meta').configs.init(); + await require('../upgrade').run(); }, }, build: { message: 'Rebuilding assets...', - handler: build.buildAll, + handler: async function () { + await require('../meta/build').buildAll(); + }, }, }; -function runSteps(tasks) { - tasks = tasks.map((key, i) => function (next) { - process.stdout.write(`\n${(`${i + 1}. `).bold}${steps[key].message.yellow}`); - return steps[key].handler((err) => { - if (err) { return next(err); } - next(); - }); - }); - - async.series(tasks, (err) => { - if (err) { - console.error(`Error occurred during upgrade: ${err.stack}`); - throw err; +async function runSteps(tasks) { + try { + for (let i = 0; i < tasks.length; i++) { + const step = steps[tasks[i]]; + if (step && step.message && step.handler) { + process.stdout.write(`\n${(`${i + 1}. `).bold}${step.message.yellow}`); + /* eslint-disable-next-line */ + await step.handler(); + } } - const message = 'NodeBB Upgrade Complete!'; // some consoles will return undefined/zero columns, // so just use 2 spaces in upgrade script if we can't get our column count @@ -76,10 +63,13 @@ function runSteps(tasks) { console.log(`\n\n${spaces}${message.green.bold}${'\n'.reset}`); process.exit(); - }); + } catch (err) { + console.error(`Error occurred during upgrade: ${err.stack}`); + throw err; + } } -function runUpgrade(upgrades, options) { +async function runUpgrade(upgrades, options) { console.log('\nUpdating NodeBB...'.cyan); options = options || {}; // disable mongo timeouts during upgrade @@ -91,23 +81,14 @@ function runUpgrade(upgrades, options) { options.plugins || options.schema || options.build) { tasks = tasks.filter(key => options[key]); } - runSteps(tasks); + await runSteps(tasks); return; } - async.series([ - db.init, - require('../meta').configs.init, - async function () { - await upgrade.runParticular(upgrades); - }, - ], (err) => { - if (err) { - throw err; - } - - process.exit(0); - }); + await require('../database').init(); + await require('../meta').configs.init(); + await require('../upgrade').runParticular(upgrades); + process.exit(0); } exports.upgrade = runUpgrade; diff --git a/src/controllers/404.js b/src/controllers/404.js index da7a8141cd..c364ccd3fc 100644 --- a/src/controllers/404.js +++ b/src/controllers/404.js @@ -7,6 +7,7 @@ const validator = require('validator'); const meta = require('../meta'); const plugins = require('../plugins'); const middleware = require('../middleware'); +const helpers = require('../middleware/helpers'); exports.handle404 = function handle404(req, res) { const relativePath = nconf.get('relative_path'); @@ -22,7 +23,13 @@ exports.handle404 = function handle404(req, res) { if (isClientScript.test(req.url)) { res.type('text/javascript').status(404).send('Not Found'); - } else if (req.path.startsWith(`${relativePath}/assets/uploads`) || (req.get('accept') && !req.get('accept').includes('text/html')) || req.path === '/favicon.ico') { + } else if ( + !res.locals.isAPI && ( + req.path.startsWith(`${relativePath}/assets/uploads`) || + (req.get('accept') && !req.get('accept').includes('text/html')) || + req.path === '/favicon.ico' + ) + ) { meta.errors.log404(req.path || ''); res.sendStatus(404); } else if (req.accepts('html')) { @@ -41,7 +48,11 @@ exports.send404 = async function (req, res) { res.status(404); const path = String(req.path || ''); if (res.locals.isAPI) { - return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' }); + return res.json({ + path: validator.escape(path.replace(/^\/api/, '')), + title: '[[global:404.title]]', + bodyClass: helpers.buildBodyClass(req, res), + }); } if (req.method === 'GET') { @@ -49,5 +60,9 @@ exports.send404 = async function (req, res) { } await middleware.buildHeaderAsync(req, res); - await res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' }); + await res.render('404', { + path: validator.escape(path), + title: '[[global:404.title]]', + bodyClass: helpers.buildBodyClass(req, res), + }); }; diff --git a/src/controllers/accounts/blocks.js b/src/controllers/accounts/blocks.js index 7665d4d2b9..12962e1027 100644 --- a/src/controllers/accounts/blocks.js +++ b/src/controllers/accounts/blocks.js @@ -14,7 +14,7 @@ blocksController.getBlocks = async function (req, res, next) { const start = Math.max(0, page - 1) * resultsPerPage; const stop = start + resultsPerPage - 1; - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/categories.js b/src/controllers/accounts/categories.js index c752a377f7..a5cd86c9d5 100644 --- a/src/controllers/accounts/categories.js +++ b/src/controllers/accounts/categories.js @@ -10,7 +10,7 @@ const meta = require('../../meta'); const categoriesController = module.exports; categoriesController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/consent.js b/src/controllers/accounts/consent.js index 3456fceb54..a4b5cd02c9 100644 --- a/src/controllers/accounts/consent.js +++ b/src/controllers/accounts/consent.js @@ -12,7 +12,7 @@ consentController.get = async function (req, res, next) { return next(); } - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index c050ea422c..3bcaff1d85 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -12,7 +12,7 @@ const editController = module.exports; editController.get = async function (req, res, next) { const [userData, canUseSignature] = await Promise.all([ - accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid), + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query), privileges.global.can('signature', req.uid), ]); if (!userData) { @@ -114,7 +114,7 @@ async function renderRoute(name, req, res, next) { } async function getUserData(req) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return null; } diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js index 77543b5271..82b23cb2f9 100644 --- a/src/controllers/accounts/follow.js +++ b/src/controllers/accounts/follow.js @@ -16,7 +16,7 @@ followController.getFollowers = async function (req, res, next) { }; async function getFollow(tpl, name, req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/groups.js b/src/controllers/accounts/groups.js index db9651e9fe..7d2f03cbf3 100644 --- a/src/controllers/accounts/groups.js +++ b/src/controllers/accounts/groups.js @@ -7,7 +7,7 @@ const accountHelpers = require('./helpers'); const groupsController = module.exports; groupsController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 718f5fe7c4..359355da87 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -16,7 +16,7 @@ const categories = require('../../categories'); const helpers = module.exports; -helpers.getUserDataByUserSlug = async function (userslug, callerUID) { +helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {}) { const uid = await user.getUidByUserslug(userslug); if (!uid) { return null; @@ -117,7 +117,11 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) { await getCounts(userData, callerUID); - const hookData = await plugins.hooks.fire('filter:helpers.getUserDataByUserSlug', { userData: userData, callerUID: callerUID }); + const hookData = await plugins.hooks.fire('filter:helpers.getUserDataByUserSlug', { + userData: userData, + callerUID: callerUID, + query: query, + }); return hookData.userData; }; diff --git a/src/controllers/accounts/info.js b/src/controllers/accounts/info.js index 6fd247eb31..950b74945d 100644 --- a/src/controllers/accounts/info.js +++ b/src/controllers/accounts/info.js @@ -9,7 +9,7 @@ const pagination = require('../../pagination'); const infoController = module.exports; infoController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index 0d52621a9b..ab213609bf 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -8,6 +8,8 @@ const categories = require('../../categories'); const pagination = require('../../pagination'); const helpers = require('../helpers'); const accountHelpers = require('./helpers'); +const plugins = require('../../plugins'); +const utils = require('../../utils'); const postsController = module.exports; @@ -107,43 +109,43 @@ const templateToData = { }; postsController.getBookmarks = async function (req, res, next) { - await getFromUserSet('account/bookmarks', req, res, next); + await getPostsFromUserSet('account/bookmarks', req, res, next); }; postsController.getPosts = async function (req, res, next) { - await getFromUserSet('account/posts', req, res, next); + await getPostsFromUserSet('account/posts', req, res, next); }; postsController.getUpVotedPosts = async function (req, res, next) { - await getFromUserSet('account/upvoted', req, res, next); + await getPostsFromUserSet('account/upvoted', req, res, next); }; postsController.getDownVotedPosts = async function (req, res, next) { - await getFromUserSet('account/downvoted', req, res, next); + await getPostsFromUserSet('account/downvoted', req, res, next); }; postsController.getBestPosts = async function (req, res, next) { - await getFromUserSet('account/best', req, res, next); + await getPostsFromUserSet('account/best', req, res, next); }; postsController.getWatchedTopics = async function (req, res, next) { - await getFromUserSet('account/watched', req, res, next); + await getPostsFromUserSet('account/watched', req, res, next); }; postsController.getIgnoredTopics = async function (req, res, next) { - await getFromUserSet('account/ignored', req, res, next); + await getPostsFromUserSet('account/ignored', req, res, next); }; postsController.getTopics = async function (req, res, next) { - await getFromUserSet('account/topics', req, res, next); + await getPostsFromUserSet('account/topics', req, res, next); }; -async function getFromUserSet(template, req, res, callback) { +async function getPostsFromUserSet(template, req, res, callback) { const data = templateToData[template]; const page = Math.max(1, parseInt(req.query.page, 10) || 1); const [userData, settings] = await Promise.all([ - accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid), + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query), user.getSettings(req.uid), ]); @@ -154,12 +156,26 @@ async function getFromUserSet(template, req, res, callback) { const start = (page - 1) * itemsPerPage; const stop = start + itemsPerPage - 1; const sets = await data.getSets(req.uid, userData); - - const [itemCount, itemData] = await Promise.all([ - settings.usePagination ? db.sortedSetsCardSum(sets) : 0, - getItemData(sets, data, req, start, stop), - ]); - + let result; + if (plugins.hooks.hasListeners('filter:account.getPostsFromUserSet')) { + result = await plugins.hooks.fire('filter:account.getPostsFromUserSet', { + req: req, + template: template, + userData: userData, + settings: settings, + data: data, + start: start, + stop: stop, + itemCount: 0, + itemData: [], + }); + } else { + result = await utils.promiseParallel({ + itemCount: settings.usePagination ? db.sortedSetsCardSum(sets) : 0, + itemData: getItemData(sets, data, req, start, stop), + }); + } + const { itemCount, itemData } = result; userData[data.type] = itemData[data.type]; userData.nextStart = itemData.nextStart; diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index 599d0bab79..71a9f01ee6 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -26,7 +26,7 @@ profileController.get = async function (req, res, next) { } } - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/sessions.js b/src/controllers/accounts/sessions.js index 26bbc3c8b9..c1713d3d62 100644 --- a/src/controllers/accounts/sessions.js +++ b/src/controllers/accounts/sessions.js @@ -7,7 +7,7 @@ const accountHelpers = require('./helpers'); const sessionController = module.exports; sessionController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 8d561bc976..848f62b893 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -18,7 +18,7 @@ const accountHelpers = require('./helpers'); const settingsController = module.exports; settingsController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/accounts/uploads.js b/src/controllers/accounts/uploads.js index 95fce14801..d1c113846a 100644 --- a/src/controllers/accounts/uploads.js +++ b/src/controllers/accounts/uploads.js @@ -11,7 +11,7 @@ const accountHelpers = require('./helpers'); const uploadsController = module.exports; uploadsController.get = async function (req, res, next) { - const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); if (!userData) { return next(); } diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index ae26338dab..a05d1f1a60 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -92,27 +92,11 @@ async function getUsers(req, res) { return uids; } - async function getUsersWithFields(set) { - const uids = await getUids(set); - const [isAdmin, userData, lastonline] = await Promise.all([ - user.isAdministrator(uids), - user.getUsersWithFields(uids, userFields, req.uid), - db.sortedSetScores('users:online', uids), - ]); - userData.forEach((user, index) => { - if (user) { - user.administrator = isAdmin[index]; - const timestamp = lastonline[index] || user.joindate; - user.lastonline = timestamp; - user.lastonlineISO = utils.toISOString(timestamp); - } - }); - return userData; - } const set = buildSet(); + const uids = await getUids(set); const [count, users] = await Promise.all([ getCount(set), - getUsersWithFields(set), + loadUserInfo(req.uid, uids), ]); await render(req, res, { @@ -162,16 +146,8 @@ usersController.search = async function (req, res) { }); const uids = searchData.users.map(user => user && user.uid); - const userInfo = await user.getUsersFields(uids, ['email', 'flags', 'lastonline', 'joindate']); + searchData.users = await loadUserInfo(req.uid, uids); - searchData.users.forEach((user, index) => { - if (user && userInfo[index]) { - user.email = userInfo[index].email; - user.flags = userInfo[index].flags || 0; - user.lastonlineISO = userInfo[index].lastonlineISO; - user.joindateISO = userInfo[index].joindateISO; - } - }); searchData.query = validator.escape(String(req.query.query || '')); searchData.resultsPerPage = resultsPerPage; searchData.sortBy = req.query.sortBy; @@ -179,6 +155,24 @@ usersController.search = async function (req, res) { await render(req, res, searchData); }; +async function loadUserInfo(callerUid, uids) { + const [isAdmin, userData, lastonline] = await Promise.all([ + user.isAdministrator(uids), + user.getUsersWithFields(uids, userFields, callerUid), + db.sortedSetScores('users:online', uids), + ]); + userData.forEach((user, index) => { + if (user) { + user.administrator = isAdmin[index]; + user.flags = userData[index].flags || 0; + const timestamp = lastonline[index] || user.joindate; + user.lastonline = timestamp; + user.lastonlineISO = utils.toISOString(timestamp); + } + }); + return userData; +} + usersController.registrationQueue = async function (req, res) { const page = parseInt(req.query.page, 10) || 1; const itemsPerPage = 20; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index f5d44dec36..54415ee928 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -183,7 +183,7 @@ authenticationController.registerComplete = function (req, res, next) { const results = await Promise.allSettled(callbacks.map(async (cb) => { await cb(req.session.registration, req.body); })); - const errors = results.map(result => result.status === 'rejected').filter(Boolean); + const errors = results.map(result => result.status === 'rejected' && result.reason && result.reason.message).filter(Boolean); if (errors.length) { req.flash('errors', errors); return res.redirect(`${nconf.get('relative_path')}/register/complete`); diff --git a/src/controllers/category.js b/src/controllers/category.js index b8c7c56323..a2449957b1 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -3,6 +3,7 @@ const nconf = require('nconf'); const validator = require('validator'); +const qs = require('querystring'); const db = require('../database'); const privileges = require('../privileges'); @@ -42,7 +43,7 @@ categoryController.get = async function (req, res, next) { return next(); } if (topicIndex < 0) { - return helpers.redirect(res, `/category/${categoryFields.slug}`); + return helpers.redirect(res, `/category/${categoryFields.slug}?${qs.stringify(req.query)}`); } if (!userPrivileges.read) { @@ -50,7 +51,7 @@ categoryController.get = async function (req, res, next) { } if (!res.locals.isAPI && !req.params.slug && (categoryFields.slug && categoryFields.slug !== `${cid}/`)) { - return helpers.redirect(res, `/category/${categoryFields.slug}`, true); + return helpers.redirect(res, `/category/${categoryFields.slug}?${qs.stringify(req.query)}`, true); } if (categoryFields.link) { @@ -86,7 +87,7 @@ categoryController.get = async function (req, res, next) { } if (topicIndex > Math.max(categoryData.topic_count - 1, 0)) { - return helpers.redirect(res, `/category/${categoryData.slug}/${categoryData.topic_count}`); + return helpers.redirect(res, `/category/${categoryData.slug}/${categoryData.topic_count}?${qs.stringify(req.query)}`); } const pageCount = Math.max(1, Math.ceil(categoryData.topic_count / userSettings.topicsPerPage)); if (userSettings.usePagination && currentPage > pageCount) { diff --git a/src/controllers/mods.js b/src/controllers/mods.js index 936fd70107..7bbe91cdff 100644 --- a/src/controllers/mods.js +++ b/src/controllers/mods.js @@ -83,6 +83,7 @@ modsController.flags.list = async function (req, res, next) { filters: filters, sort: sort, uid: req.uid, + query: req.query, }), analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30), helpers.getSelectedCategory(filters.cid), diff --git a/src/controllers/user.js b/src/controllers/user.js index 353c4170c1..acd018ce67 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -14,7 +14,7 @@ userController.getCurrentUser = async function (req, res) { return res.status(401).json('not-authorized'); } const userslug = await user.getUserField(req.uid, 'userslug'); - const userData = await accountHelpers.getUserDataByUserSlug(userslug, req.uid); + const userData = await accountHelpers.getUserDataByUserSlug(userslug, req.uid, req.query); res.json(userData); }; diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index 5f58dfd93b..ec8a0b9c03 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -120,7 +120,7 @@ module.exports = function (module) { cache.set(key, cachedData[key]); }); - if (!fields.length) { + if (!Array.isArray(fields) || !fields.length) { return keys.map(key => (cachedData[key] ? { ...cachedData[key] } : null)); } return keys.map((key) => { @@ -156,7 +156,9 @@ module.exports = function (module) { const data = {}; fields.forEach((field) => { field = helpers.fieldToString(field); - data[field] = 1; + if (field) { + data[field] = 1; + } }); const item = await module.client.collection('objects').findOne({ _key: key }, { projection: data }); diff --git a/src/database/postgres/hash.js b/src/database/postgres/hash.js index 696e385bfd..1a733a3518 100644 --- a/src/database/postgres/hash.js +++ b/src/database/postgres/hash.js @@ -142,7 +142,9 @@ SELECT h."data"->>$2::TEXT f if (!key) { return null; } - + if (!Array.isArray(fields) || !fields.length) { + return await module.getObject(key); + } const res = await module.pool.query({ name: 'getObjectFields', text: ` @@ -174,7 +176,8 @@ SELECT (SELECT jsonb_object_agg(f, d."value") if (!Array.isArray(keys) || !keys.length) { return []; } - if (!fields.length) { + + if (!Array.isArray(fields) || !fields.length) { return await module.getObjects(keys); } const res = await module.pool.query({ diff --git a/src/database/redis.js b/src/database/redis.js index cef6105b5e..759f100bab 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -104,13 +104,11 @@ redisModule.info = async function (cxn) { }; redisModule.socketAdapter = async function () { - const redisAdapter = require('socket.io-redis'); + const redisAdapter = require('@socket.io/redis-adapter'); const pub = await connection.connect(nconf.get('redis')); const sub = await connection.connect(nconf.get('redis')); - return redisAdapter({ + return redisAdapter(pub, sub, { key: `db:${nconf.get('redis:database')}:adapter_key`, - pubClient: pub, - subClient: sub, }); }; diff --git a/src/database/redis/connection.js b/src/database/redis/connection.js index 6e685eadcf..6b43c9ee79 100644 --- a/src/database/redis/connection.js +++ b/src/database/redis/connection.js @@ -1,37 +1,36 @@ 'use strict'; const nconf = require('nconf'); -const redis = require('redis'); +const Redis = require('ioredis'); const winston = require('winston'); -const _ = require('lodash'); const connection = module.exports; -connection.getConnectionOptions = function (redis) { - redis = redis || nconf.get('redis'); - const connOptions = {}; - if (redis.password) { - connOptions.auth_pass = redis.password; - } - if (redis.hasOwnProperty('database')) { - connOptions.db = redis.database; - } - return _.merge(connOptions, redis.options || {}); -}; - connection.connect = async function (options) { return new Promise((resolve, reject) => { options = options || nconf.get('redis'); const redis_socket_or_host = options.host; - const connOptions = connection.getConnectionOptions(options); let cxn; - if (redis_socket_or_host && String(redis_socket_or_host).indexOf('/') >= 0) { - /* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */ - cxn = redis.createClient(options.host, connOptions); + if (options.cluster) { + cxn = new Redis.Cluster(options.cluster, options.options); + } else if (redis_socket_or_host && String(redis_socket_or_host).indexOf('/') >= 0) { + // If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock + cxn = new Redis({ + ...options.options, + path: redis_socket_or_host, + password: options.password, + db: options.database, + }); } else { - /* Else, connect over tcp/ip */ - cxn = redis.createClient(options.port, options.host, connOptions); + // Else, connect over tcp/ip + cxn = new Redis({ + ...options.options, + host: redis_socket_or_host, + port: options.port, + password: options.password, + db: options.database, + }); } const dbIdx = parseInt(options.database, 10); @@ -44,6 +43,8 @@ connection.connect = async function (options) { reject(err); }); cxn.on('ready', () => { + // back-compat with node_redis + cxn.batch = cxn.pipeline; resolve(cxn); }); diff --git a/src/database/redis/hash.js b/src/database/redis/hash.js index 3a83b861fe..24630ba371 100644 --- a/src/database/redis/hash.js +++ b/src/database/redis/hash.js @@ -98,9 +98,7 @@ module.exports = function (module) { if (!Array.isArray(keys) || !keys.length) { return []; } - if (!Array.isArray(fields)) { - return keys.map(() => ({})); - } + const cachedData = {}; const unCachedKeys = cache.getUnCachedKeys(keys, cachedData); @@ -113,12 +111,20 @@ module.exports = function (module) { data = [await module.client.async.hgetall(unCachedKeys[0])]; } + // convert empty objects into null for back-compat with node_redis + data = data.map((elem) => { + if (!Object.keys(elem).length) { + return null; + } + return elem; + }); + unCachedKeys.forEach((key, i) => { cachedData[key] = data[i] || null; cache.set(key, cachedData[key]); }); - if (!fields.length) { + if (!Array.isArray(fields) || !fields.length) { return keys.map(key => (cachedData[key] ? { ...cachedData[key] } : null)); } return keys.map((key) => { diff --git a/src/database/redis/helpers.js b/src/database/redis/helpers.js index 30b440d4e2..8961da8255 100644 --- a/src/database/redis/helpers.js +++ b/src/database/redis/helpers.js @@ -1,14 +1,17 @@ 'use strict'; -const util = require('util'); - const helpers = module.exports; helpers.noop = function () {}; helpers.execBatch = async function (batch) { - const proFn = util.promisify(batch.exec).bind(batch); - return await proFn(); + const results = await batch.exec(); + return results.map(([err, res]) => { + if (err) { + throw err; + } + return res; + }); }; helpers.resultsToBool = function (results) { diff --git a/src/database/redis/sets.js b/src/database/redis/sets.js index 2146e1ae5e..a0431995a4 100644 --- a/src/database/redis/sets.js +++ b/src/database/redis/sets.js @@ -29,6 +29,9 @@ module.exports = function (module) { if (!Array.isArray(key)) { key = [key]; } + if (!value.length) { + return; + } const batch = module.client.batch(); key.forEach(k => batch.srem(String(k), value)); diff --git a/src/flags.js b/src/flags.js index 0d20815756..e119a00e97 100644 --- a/src/flags.js +++ b/src/flags.js @@ -121,13 +121,13 @@ Flags.get = async function (flagId) { return data.flag; }; -Flags.getCount = async function ({ uid, filters }) { +Flags.getCount = async function ({ uid, filters, query }) { filters = filters || {}; - const flagIds = await Flags.getFlagIdsWithFilters({ filters, uid }); + const flagIds = await Flags.getFlagIdsWithFilters({ filters, uid, query }); return flagIds.length; }; -Flags.getFlagIdsWithFilters = async function ({ filters, uid }) { +Flags.getFlagIdsWithFilters = async function ({ filters, uid, query }) { let sets = []; const orSets = []; @@ -167,7 +167,13 @@ Flags.getFlagIdsWithFilters = async function ({ filters, uid }) { } } - return flagIds; + const result = await plugins.hooks.fire('filter:flags.getFlagIdsWithFilters', { + filters, + uid, + query, + flagIds, + }); + return result.flagIds; }; Flags.list = async function (data) { @@ -175,6 +181,7 @@ Flags.list = async function (data) { let flagIds = await Flags.getFlagIdsWithFilters({ filters, uid: data.uid, + query: data.query, }); flagIds = await Flags.sort(flagIds, data.sort); diff --git a/src/messaging/unread.js b/src/messaging/unread.js index 4a1ab60cfb..169374045f 100644 --- a/src/messaging/unread.js +++ b/src/messaging/unread.js @@ -31,7 +31,7 @@ module.exports = function (Messaging) { Messaging.markUnread = async (uids, roomId) => { const exists = await Messaging.roomExists(roomId); if (!exists) { - throw new Error('[[error:chat-room-does-not-exist]]'); + return; } const keys = uids.map(uid => `uid:${uid}:chat:rooms:unread`); return await db.sortedSetsAdd(keys, Date.now(), roomId); diff --git a/src/middleware/header.js b/src/middleware/header.js index 17b9987752..4f5aaad734 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -109,13 +109,14 @@ middleware.renderHeader = async function renderHeader(req, res, data) { unreadCount: templateValues.unreadCount, } = await appendUnreadCounts({ uid: req.uid, + query: req.query, navigation: results.navigation, unreadData, })); templateValues.isAdmin = results.user.isAdmin; templateValues.isGlobalMod = results.user.isGlobalMod; templateValues.showModMenu = results.user.isAdmin || results.user.isGlobalMod || results.user.isMod; - templateValues.canChat = results.canChat && meta.config.disableChat !== 1; + templateValues.canChat = results.privileges.chat && meta.config.disableChat !== 1; templateValues.user = results.user; templateValues.userJSON = jsesc(JSON.stringify(results.user), { isScriptContext: true }); templateValues.useCustomCSS = meta.config.useCustomCSS && meta.config.customCSS; @@ -152,7 +153,7 @@ middleware.renderHeader = async function renderHeader(req, res, data) { return await req.app.renderAsync('header', hookReturn.templateValues); }; -async function appendUnreadCounts({ uid, navigation, unreadData }) { +async function appendUnreadCounts({ uid, navigation, unreadData, query }) { const originalRoutes = navigation.map(nav => nav.originalRoute); const calls = { unreadData: topics.getUnreadData({ uid: uid }), @@ -162,6 +163,7 @@ async function appendUnreadCounts({ uid, navigation, unreadData }) { if (originalRoutes.includes('/flags') && await user.isPrivileged(uid)) { return flags.getCount({ uid, + query, filters: { quick: 'unresolved', cid: (await user.isAdminOrGlobalMod(uid)) ? [] : (await user.getModeratedCids(uid)), diff --git a/src/middleware/headers.js b/src/middleware/headers.js index e06082851c..dacfb62dec 100644 --- a/src/middleware/headers.js +++ b/src/middleware/headers.js @@ -7,6 +7,7 @@ const _ = require('lodash'); const meta = require('../meta'); const languages = require('../languages'); const helpers = require('./helpers'); +const plugins = require('../plugins'); module.exports = function (middleware) { middleware.addHeaders = helpers.try((req, res, next) => { @@ -74,9 +75,12 @@ module.exports = function (middleware) { }); middleware.autoLocale = helpers.try(async (req, res, next) => { - let langs; + await plugins.hooks.fire('filter:middleware.autoLocale', { + req: req, + res: res, + }); if (req.query.lang) { - langs = await listCodes(); + const langs = await listCodes(); if (!langs.includes(req.query.lang)) { req.query.lang = meta.config.defaultLang; } @@ -85,7 +89,7 @@ module.exports = function (middleware) { if (parseInt(req.uid, 10) > 0 || !meta.config.autoDetectLang) { return next(); } - langs = await listCodes(); + const langs = await listCodes(); const lang = req.acceptsLanguages(langs); if (!lang) { return next(); diff --git a/src/middleware/helpers.js b/src/middleware/helpers.js index cb67b454c5..b0bb86cefe 100644 --- a/src/middleware/helpers.js +++ b/src/middleware/helpers.js @@ -1,5 +1,9 @@ 'use strict'; +const winston = require('winston'); +const validator = require('validator'); +const slugify = require('../slugify'); + const helpers = module.exports; helpers.try = function (middleware) { @@ -20,3 +24,34 @@ helpers.try = function (middleware) { } }; }; + +helpers.buildBodyClass = function (req, res, templateData = {}) { + const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, ''); + const parts = clean.split('/').slice(0, 3); + parts.forEach((p, index) => { + try { + p = slugify(decodeURIComponent(p)); + } catch (err) { + winston.error(err.stack); + p = ''; + } + p = validator.escape(String(p)); + parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`; + }); + + if (templateData.template && templateData.template.topic) { + parts.push(`page-topic-category-${templateData.category.cid}`); + parts.push(`page-topic-category-${slugify(templateData.category.name)}`); + } + + if (Array.isArray(templateData.breadcrumbs)) { + templateData.breadcrumbs.forEach((crumb) => { + if (crumb && crumb.hasOwnProperty('cid')) { + parts.push(`parent-category-${crumb.cid}`); + } + }); + } + + parts.push(`page-status-${res.statusCode}`); + return parts.join(' '); +}; diff --git a/src/middleware/render.js b/src/middleware/render.js index 08f574dc5e..9132b18f93 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -2,14 +2,14 @@ const nconf = require('nconf'); const validator = require('validator'); -const winston = require('winston'); + const plugins = require('../plugins'); const meta = require('../meta'); const translator = require('../translator'); const widgets = require('../widgets'); const utils = require('../utils'); -const slugify = require('../slugify'); +const helpers = require('./helpers'); const relative_path = nconf.get('relative_path'); @@ -31,12 +31,18 @@ module.exports = function (middleware) { options.relative_path = relative_path; options.template = { name: template, [template]: true }; options.url = (req.baseUrl + req.path.replace(/^\/api/, '')); - options.bodyClass = buildBodyClass(req, res, options); + options.bodyClass = helpers.buildBodyClass(req, res, options); const buildResult = await plugins.hooks.fire(`filter:${template}.build`, { req: req, res: res, templateData: options }); + if (res.headersSent) { + return; + } const templateToRender = buildResult.templateData.templateToRender || template; const renderResult = await plugins.hooks.fire('filter:middleware.render', { req: req, res: res, templateData: buildResult.templateData }); + if (res.headersSent) { + return; + } options = renderResult.templateData; options._header = { tags: await meta.tags.parse(req, renderResult, res.locals.metaTags, res.locals.linkTags), @@ -117,34 +123,4 @@ module.exports = function (middleware) { const translated = await translator.translate(str, language); return translator.unescape(translated); } - - function buildBodyClass(req, res, templateData) { - const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, ''); - const parts = clean.split('/').slice(0, 3); - parts.forEach((p, index) => { - try { - p = slugify(decodeURIComponent(p)); - } catch (err) { - winston.error(err.stack); - p = ''; - } - p = validator.escape(String(p)); - parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`; - }); - - if (templateData.template.topic) { - parts.push(`page-topic-category-${templateData.category.cid}`); - parts.push(`page-topic-category-${slugify(templateData.category.name)}`); - } - if (templateData.breadcrumbs) { - templateData.breadcrumbs.forEach((crumb) => { - if (crumb.hasOwnProperty('cid')) { - parts.push(`parent-category-${crumb.cid}`); - } - }); - } - - parts.push(`page-status-${res.statusCode}`); - return parts.join(' '); - } }; diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index d3dec5965d..59f904d186 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -128,22 +128,32 @@ async function fireFilterHook(hook, hookList, params) { return await hookObj.method(params); } return new Promise((resolve, reject) => { + let resolved = false; + function _resolve(result) { + if (resolved) { + winston.warn(`[plugins] ${hook} already resolved in plugin ${hookObj.id}`); + return; + } + resolved = true; + resolve(result); + } const returned = hookObj.method(params, (err, result) => { - if (err) reject(err); else resolve(result); + if (err) reject(err); else _resolve(result); }); if (utils.isPromise(returned)) { returned.then( - payload => resolve(payload), + payload => _resolve(payload), err => reject(err) ); return; } if (returned) { - resolve(returned); + _resolve(returned); } }); } + for (const hookObj of hookList) { // eslint-disable-next-line params = await fireMethod(hookObj, params); diff --git a/src/posts/queue.js b/src/posts/queue.js index f3bb96b56b..d523420e43 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -228,10 +228,15 @@ module.exports = function (Posts) { } Posts.removeFromQueue = async function (id) { + const data = await getParsedObject(id); + if (!data) { + return; + } await removeQueueNotification(id); await db.sortedSetRemove('post:queue', id); await db.delete(`post:queue:${id}`); cache.del('post-queue'); + return data; }; Posts.submitFromQueue = async function (id) { @@ -240,11 +245,14 @@ module.exports = function (Posts) { return; } if (data.type === 'topic') { - await createTopic(data.data); + const result = await createTopic(data.data); + data.pid = result.postData.pid; } else if (data.type === 'reply') { - await createReply(data.data); + const result = await createReply(data.data); + data.pid = result.pid; } await Posts.removeFromQueue(id); + return data; }; async function getParsedObject(id) { @@ -260,6 +268,7 @@ module.exports = function (Posts) { async function createTopic(data) { const result = await topics.post(data); socketHelpers.notifyNew(data.uid, 'newTopic', { posts: [result.postData], topic: result.topicData }); + return result; } async function createReply(data) { @@ -270,6 +279,7 @@ module.exports = function (Posts) { 'downvote:disabled': !!meta.config['downvote:disabled'], }; socketHelpers.notifyNew(data.uid, 'newPost', result); + return postData; } Posts.editQueuedContent = async function (uid, editData) { diff --git a/src/routes/feeds.js b/src/routes/feeds.js index ff2e508ce7..7ace7cf216 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -13,7 +13,7 @@ const helpers = require('../controllers/helpers'); const privileges = require('../privileges'); const db = require('../database'); const utils = require('../utils'); -const controllers404 = require('../controllers/404.js'); +const controllers404 = require('../controllers/404'); const terms = { daily: 'day', @@ -60,9 +60,9 @@ async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) { return true; } -async function generateForTopic(req, res) { +async function generateForTopic(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } const tid = req.params.topic_id; @@ -73,7 +73,7 @@ async function generateForTopic(req, res) { ]); if (!privileges.topics.canViewDeletedScheduled(topic, userPrivileges)) { - return controllers404.send404(req, res); + return next(); } if (await validateTokenIfRequiresLogin(!userPrivileges['topics:read'], topic.cid, req, res)) { @@ -116,11 +116,8 @@ async function generateForTopic(req, res) { } async function generateForCategory(req, res, next) { - if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); - } const cid = req.params.category_id; - if (!parseInt(cid, 10)) { + if (meta.config['feeds:disableRSS'] || !parseInt(cid, 10)) { return next(); } @@ -153,9 +150,9 @@ async function generateForCategory(req, res, next) { } } -async function generateForTopics(req, res) { +async function generateForTopics(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } let token = null; if (req.query.token && req.query.uid) { @@ -171,9 +168,9 @@ async function generateForTopics(req, res) { }, 'topics:tid', res); } -async function generateForRecent(req, res) { +async function generateForRecent(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } let token = null; if (req.query.token && req.query.uid) { @@ -189,9 +186,9 @@ async function generateForRecent(req, res) { }, 'topics:recent', res); } -async function generateForTop(req, res) { +async function generateForTop(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } const term = terms[req.params.term] || 'day'; @@ -221,9 +218,9 @@ async function generateForTop(req, res) { sendFeed(feed, res); } -async function generateForPopular(req, res) { +async function generateForPopular(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } const term = terms[req.params.term] || 'day'; @@ -309,9 +306,9 @@ async function generateTopicsFeed(feedOptions, feedTopics) { return feed; } -async function generateForRecentPosts(req, res) { +async function generateForRecentPosts(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } const postData = await posts.getRecentPosts(req.uid, 0, 19, 'month'); const feed = generateForPostsFeed({ @@ -326,7 +323,7 @@ async function generateForRecentPosts(req, res) { async function generateForCategoryRecentPosts(req, res) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return controllers404.handle404(req, res); } const cid = req.params.category_id; @@ -337,7 +334,7 @@ async function generateForCategoryRecentPosts(req, res) { ]); if (!category) { - return controllers404.send404(req, res); + return controllers404.handle404(req, res); } if (await validateTokenIfRequiresLogin(!userPrivileges.read, cid, req, res)) { @@ -378,7 +375,7 @@ function generateForPostsFeed(feedOptions, posts) { async function generateForUserTopics(req, res, next) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return next(); } const { userslug } = req.params; @@ -398,7 +395,7 @@ async function generateForUserTopics(req, res, next) { async function generateForTag(req, res) { if (meta.config['feeds:disableRSS']) { - return controllers404.send404(req, res); + return controllers404.handle404(req, res); } const tag = validator.escape(String(req.params.tag)); const page = parseInt(req.query.page, 10) || 1; diff --git a/src/search.js b/src/search.js index b8c2717941..7ef8eb8062 100644 --- a/src/search.js +++ b/src/search.js @@ -284,7 +284,7 @@ async function getWatchedCids(data) { if (!data.categories.includes('watched')) { return []; } - return await user.getCategoriesByStates(data.uid, [categories.watchStates.watching]); + return await user.getWatchedCategories(data.uid); } async function getChildrenCids(data) { diff --git a/src/socket.io/categories/search.js b/src/socket.io/categories/search.js index 1cf2ffc29f..1affc248e5 100644 --- a/src/socket.io/categories/search.js +++ b/src/socket.io/categories/search.js @@ -8,7 +8,7 @@ const privileges = require('../../privileges'); const controllersHelpers = require('../../controllers/helpers'); module.exports = function (SocketCategories) { - // used by categorySeach module + // used by categorySearch module SocketCategories.categorySearch = async function (socket, data) { let cids = []; let matchedCids = []; diff --git a/src/socket.io/index.js b/src/socket.io/index.js index fc07f5f5c6..aaaceb2010 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -86,7 +86,17 @@ function onDisconnect(socket) { plugins.hooks.fire('action:sockets.disconnect', { socket: socket }); } -function onConnect(socket) { +async function onConnect(socket) { + try { + await validateSession(socket, '[[error:invalid-session]]'); + } catch (e) { + if (e.message === '[[error:invalid-session]]') { + socket.emit('event:invalid_session'); + return; + } + throw e; + } + if (socket.uid) { socket.join(`uid_${socket.uid}`); socket.join('online_users'); @@ -143,7 +153,7 @@ async function onMessage(socket, payload) { try { await checkMaintenance(socket); - await validateSession(socket); + await validateSession(socket, '[[error:revalidate-failure]]'); if (Namespaces[namespace].before) { await Namespaces[namespace].before(socket, eventName, params); @@ -191,14 +201,14 @@ const getSessionAsync = util.promisify( (sid, callback) => db.sessionStore.get(sid, (err, sessionObj) => callback(err, sessionObj || null)) ); -async function validateSession(socket) { +async function validateSession(socket, errorMsg) { const req = socket.request; if (!req.signedCookies || !req.signedCookies[nconf.get('sessionKey')]) { return; } const sessionData = await getSessionAsync(req.signedCookies[nconf.get('sessionKey')]); if (!sessionData) { - throw new Error('[[error:invalid-session]]'); + throw new Error(errorMsg); } const result = await plugins.hooks.fire('static:sockets.validateSession', { req: req, diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 2af48a17c6..aee411a0d1 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -7,6 +7,7 @@ const plugins = require('../plugins'); const meta = require('../meta'); const topics = require('../topics'); const user = require('../user'); +const notifications = require('../notifications'); const socketHelpers = require('./helpers'); const utils = require('../utils'); const api = require('../api'); @@ -130,11 +131,13 @@ SocketPosts.getReplies = async function (socket, pid) { }; SocketPosts.accept = async function (socket, data) { - await acceptOrReject(posts.submitFromQueue, socket, data); + const result = await acceptOrReject(posts.submitFromQueue, socket, data); + await sendQueueNotification('post-queue-accepted', result.uid, `/post/${result.pid}`); }; SocketPosts.reject = async function (socket, data) { - await acceptOrReject(posts.removeFromQueue, socket, data); + const result = await acceptOrReject(posts.removeFromQueue, socket, data); + await sendQueueNotification('post-queue-rejected', result.uid, '/'); }; async function acceptOrReject(method, socket, data) { @@ -142,7 +145,18 @@ async function acceptOrReject(method, socket, data) { if (!canEditQueue) { throw new Error('[[error:no-privileges]]'); } - await method(data.id); + return await method(data.id); +} + +async function sendQueueNotification(type, targetUid, path) { + const notifObj = await notifications.create({ + type: type, + nid: `${type}-${targetUid}-${path}`, + bodyShort: type === 'post-queue-accepted' ? + '[[notifications:post-queue-accepted]]' : '[[notifications:post-queue-rejected]]', + path: path, + }); + await notifications.push(notifObj, [targetUid]); } SocketPosts.editQueuedContent = async function (socket, data) { diff --git a/src/user/categories.js b/src/user/categories.js index 29f56cbdda..a1d141a628 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -4,6 +4,7 @@ const _ = require('lodash'); const db = require('../database'); const categories = require('../categories'); +const plugins = require('../plugins'); module.exports = function (User) { User.setCategoryWatchState = async function (uid, cids, state) { @@ -36,14 +37,24 @@ module.exports = function (User) { if (!(parseInt(uid, 10) > 0)) { return []; } - return await User.getCategoriesByStates(uid, [categories.watchStates.ignoring]); + const cids = await User.getCategoriesByStates(uid, [categories.watchStates.ignoring]); + const result = await plugins.hooks.fire('filter:user.getIgnoredCategories', { + uid: uid, + cids: cids, + }); + return result.cids; }; User.getWatchedCategories = async function (uid) { if (!(parseInt(uid, 10) > 0)) { return []; } - return await User.getCategoriesByStates(uid, [categories.watchStates.watching]); + const cids = await User.getCategoriesByStates(uid, [categories.watchStates.watching]); + const result = await plugins.hooks.fire('filter:user.getWatchedCategories', { + uid: uid, + cids: cids, + }); + return result.cids; }; User.getCategoriesByStates = async function (uid, states) { diff --git a/test/database/hash.js b/test/database/hash.js index e1ccd782af..39c4e39624 100644 --- a/test/database/hash.js +++ b/test/database/hash.js @@ -324,6 +324,15 @@ describe('Hash methods', () => { assert.strictEqual(Number(objects[1].age), 3); assert.strictEqual(!!objects[2], false); }); + + it('should return objects if fields is not an array', async () => { + const objects = await db.getObjectsFields(['testObject8', 'testObject9', 'doesnotexist'], undefined); + assert.strictEqual(objects[0].name, 'baris'); + assert.strictEqual(Number(objects[0].age), 99); + assert.strictEqual(objects[1].name, 'ginger'); + assert.strictEqual(Number(objects[1].age), 3); + assert.strictEqual(!!objects[2], false); + }); }); describe('getObjectKeys()', () => { @@ -397,6 +406,11 @@ describe('Hash methods', () => { done(); }); }); + + it('should not error if field is falsy', async () => { + const value = await db.isObjectField('hashTestObjectEmpty', ''); + assert.strictEqual(value, false); + }); }); @@ -418,6 +432,11 @@ describe('Hash methods', () => { done(); }); }); + + it('should not error if one field is falsy', async () => { + const values = await db.isObjectFields('hashTestObject', ['name', '']); + assert.deepStrictEqual(values, [true, false]); + }); }); describe('deleteObjectField()', () => { diff --git a/test/plugins.js b/test/plugins.js index b7b5575d28..ae5e403abf 100644 --- a/test/plugins.js +++ b/test/plugins.js @@ -71,6 +71,25 @@ describe('Plugins', () => { assert.strictEqual(data.foo, 8); }); + it('should not error with invalid hooks', async () => { + function method1(data, callback) { + data.foo += 1; + return data; + } + function method2(data, callback) { + data.foo += 2; + // this is invalid + callback(null, data); + return data; + } + + plugins.hooks.register('test-plugin', { hook: 'filter:test.hook3', method: method1 }); + plugins.hooks.register('test-plugin', { hook: 'filter:test.hook3', method: method2 }); + + const data = await plugins.hooks.fire('filter:test.hook3', { foo: 1 }); + assert.strictEqual(data.foo, 4); + }); + it('should register and fire a filter hook that returns a promise that gets rejected', (done) => { async function method(data) { return new Promise((resolve, reject) => { @@ -78,8 +97,8 @@ describe('Plugins', () => { reject(new Error('nope')); }); } - plugins.hooks.register('test-plugin', { hook: 'filter:test.hook3', method: method }); - plugins.hooks.fire('filter:test.hook3', { foo: 1 }, (err) => { + plugins.hooks.register('test-plugin', { hook: 'filter:test.hook4', method: method }); + plugins.hooks.fire('filter:test.hook4', { foo: 1 }, (err) => { assert(err); done(); }); diff --git a/test/user.js b/test/user.js index 3306ebee0b..e3482d5139 100644 --- a/test/user.js +++ b/test/user.js @@ -541,6 +541,17 @@ describe('User', () => { await Posts.upvote(result.postData.pid, 1); assert(!await db.isSortedSetMember('users:reputation', uid)); }); + + it('should delete user even if they started a chat', async () => { + const socketModules = require('../src/socket.io/modules'); + const uid1 = await User.create({ username: 'chatuserdelete1' }); + const uid2 = await User.create({ username: 'chatuserdelete2' }); + const roomId = await socketModules.chats.newRoom({ uid: uid1 }, { touid: uid2 }); + await socketModules.chats.send({ uid: uid1 }, { roomId: roomId, message: 'hello' }); + await socketModules.chats.leave({ uid: uid2 }, roomId); + await User.delete(1, uid1); + assert.strictEqual(await User.exists(uid1), false); + }); }); describe('passwordReset', () => {