diff --git a/app.js b/app.js index fb757a497d..dcdf8e1819 100644 --- a/app.js +++ b/app.js @@ -46,11 +46,6 @@ winston.add(winston.transports.Console, { level: global.env === 'production' ? 'info' : 'verbose' }); -// TODO: remove once https://github.com/flatiron/winston/issues/280 is fixed -winston.err = function (err) { - winston.error(err.stack); -}; - if(os.platform() === 'linux') { require('child_process').exec('/usr/bin/which convert', function(err, stdout, stderr) { if(err || !stdout) { @@ -121,7 +116,7 @@ function start() { nconf.set('use_port', !!urlObject.port); nconf.set('relative_path', relativePath); nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || 4567); - nconf.set('upload_url', relativePath + '/uploads/'); + nconf.set('upload_url', '/uploads/'); if (nconf.get('isPrimary') === 'true') { winston.info('Time: %s', (new Date()).toString()); diff --git a/install/data/defaults.json b/install/data/defaults.json index 5507ad0822..778dee3838 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -27,6 +27,10 @@ "field": "minimumPostLength", "value": 8 }, + { + "field": "maximumPostLength", + "value": 32767 + }, { "field": "allowGuestSearching", "value": 0 diff --git a/install/data/footer.json b/install/data/footer.json new file mode 100644 index 0000000000..69d55448ac --- /dev/null +++ b/install/data/footer.json @@ -0,0 +1,10 @@ +[ + { + "widget": "html", + "data" : { + "html": "", + "title":"", + "container":"" + } + } +] \ No newline at end of file diff --git a/install/data/welcome.md b/install/data/welcome.md new file mode 100644 index 0000000000..399850e6e2 --- /dev/null +++ b/install/data/welcome.md @@ -0,0 +1,10 @@ +# Welcome to your brand new NodeBB forum! + +This is what a topic and post looks like. As an administator, you can edit the post\'s title and content. +To customise your forum, go to the [Administrator Control Panel](../../admin). You can modify all aspects of your forum there, including installation of third-party plugins. + +## Additional Resources + +* [NodeBB Documentation](https://docs.nodebb.org) +* [Community Support Forum](https://community.nodebb.org) +* [Project repository](https://github.com/nodebb/nodebb) \ No newline at end of file diff --git a/package.json b/package.json index c8583eaf64..6d3525778c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.6.1-dev", + "version": "0.7.0-dev", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -37,13 +37,14 @@ "morgan": "^1.3.2", "nconf": "~0.7.1", "nodebb-plugin-dbsearch": "^0.1.0", + "nodebb-plugin-emoji-extended": "^0.4.1-4", "nodebb-plugin-markdown": "^0.8.0", "nodebb-plugin-mentions": "^0.9.0", "nodebb-plugin-soundpack-default": "~0.1.1", "nodebb-plugin-spam-be-gone": "^0.4.0", - "nodebb-theme-lavender": "^0.2.0", - "nodebb-theme-vanilla": "^0.2.0", - "nodebb-widget-essentials": "~0.2.0", + "nodebb-theme-lavender": "^1.0.4", + "nodebb-theme-vanilla": "^1.0.5", + "nodebb-widget-essentials": "~0.2.11", "npm": "^2.1.4", "passport": "^0.2.1", "passport-local": "1.0.0", @@ -59,11 +60,11 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "0.1.10", + "templates.js": "^0.1.15", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", - "validator": "~3.26.0", - "winston": "^0.8.1", + "validator": "^3.30.0", + "winston": "^0.9.0", "xregexp": "~2.0.0" }, "devDependencies": { diff --git a/public/language/ar/email.json b/public/language/ar/email.json index f2820e0600..98cb9c0b0d 100644 --- a/public/language/ar/email.json +++ b/public/language/ar/email.json @@ -9,6 +9,9 @@ "reset.text1": "لقد توصلنا بطلب إعادة تعيين كلمة السرالخاصة بك، ربما لكونك قد نسيتها, إن لم يكن الأمر كذلك، المرجو تجاهل هذه الرسالة.", "reset.text2": "لمواصلة طلب إعاة تعيين كلمة السر، المرجو تتبع هذا الرابط.", "reset.cta": "انقر هنا لإعادة تعيين كلمة السر الخاصة بك.", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "لديك تنبيهات غير مقروءة من طرف %1:", "digest.latest_topics": "آخر المستجدات من %1", "digest.cta": "انقر هنا لمشاهدة %1", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 592d7365e4..73eb289378 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -35,6 +35,7 @@ "topic-locked": "الموضوع مقفول", "still-uploading": "الرجاء انتظار الرفع", "content-too-short": "المرجو إدخال موضوع أطول من هذا. يجب أن تتوفر المواضيع على %1 حروف على الأقل.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "المرجو إدخال عنوان أطول من هذا. يجب أن تتوفر العناوين على %1 حروف على الأقل.", "title-too-long": "المرجو إدخال عنوان أقصر من هذا. يجب ألا تتجاوز العناوين %1 حرفًا.", "too-many-posts": "يمكنك إنشاء المواضيع بمعدل موضوع واحد كل %1 ثانية - المرجو الانتظار قليلا.", @@ -62,6 +63,7 @@ "signature-too-long": "عذرا، توقيعك يجب ألا يتجاوز %1 حرفًا", "cant-chat-with-yourself": "لايمكنك فتح محادثة مع نفسك", "chat-restricted": "هذا المستخدم عطل المحادثات الواردة عليه. يجب أن يتبعك حتى تتمكن من فتح محادثة معه.", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "نظام السمعة معطل", "downvoting-disabled": "التصويتات السلبية معطلة", "not-enough-reputation-to-downvote": "ليس لديك سمعة تكفي لإضافة صوت سلبي لهذا الموضوع", diff --git a/public/language/ar/groups.json b/public/language/ar/groups.json index 5ca494a696..b006f74391 100644 --- a/public/language/ar/groups.json +++ b/public/language/ar/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "آخر المشاركات", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/ar/pages.json b/public/language/ar/pages.json index 0dc17e025a..15e8209928 100644 --- a/public/language/ar/pages.json +++ b/public/language/ar/pages.json @@ -11,6 +11,7 @@ "user.followers": "المستخدمون الذين يتبعون %1", "user.posts": "ردود %1", "user.topics": "مواضيع %1", + "user.groups": "%1's Groups", "user.favourites": "مفضلات %1", "user.settings": "خيارات المستخدم", "maintenance.text": "جاري صيانة %1. المرجو العودة لاحقًا.", diff --git a/public/language/ar/reset_password.json b/public/language/ar/reset_password.json index 603f117b7e..b4f95dd780 100644 --- a/public/language/ar/reset_password.json +++ b/public/language/ar/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "يرجى إدخال عنوان البريد الإلكتروني الخاص بك وسوف نرسل لك رسالة بالبريد الالكتروني مع تعليمات حول كيفية إستعادة حسابك.", "enter_email_address": "ادخل عنوان البريد الإلكتروني", "password_reset_sent": "إعادة تعيين كلمة السر أرسلت", - "invalid_email": "بريد إلكتروني غير صالح أو غير موجود" + "invalid_email": "بريد إلكتروني غير صالح أو غير موجود", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ar/search.json b/public/language/ar/search.json index 581a791905..50b985d452 100644 --- a/public/language/ar/search.json +++ b/public/language/ar/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ar/users.json b/public/language/ar/users.json index b37bca619f..a842def62b 100644 --- a/public/language/ar/users.json +++ b/public/language/ar/users.json @@ -5,7 +5,7 @@ "search": "بحث", "enter_username": "أدخل اسم مستخدم للبحث", "load_more": "حمل المزيد", - "users-found-search-took": "تم إيجاد %1 مستخدمـ(ين)! استغرق البحث %2 ميليثانية.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/bn/email.json b/public/language/bn/email.json index b151164f2f..91169e5549 100644 --- a/public/language/bn/email.json +++ b/public/language/bn/email.json @@ -9,6 +9,9 @@ "reset.text1": "আমরা আপনার পাসওয়ার্ড রিসেট করার অনুরোধ পেয়েছি, সম্ভবত আপনি আপনার পাসওয়ার্ড ভুলে গিয়েছেন বলেই। তবে যদি তা না হয়ে থাকে, তাহলে এই মেইলকে উপেক্ষা করতে পারেন।", "reset.text2": "পাসওয়ার্ড রিসেট করতে নিচের লিংকে ক্লিক করুন", "reset.cta": "পাসওয়ার্ড রিসেট করতে এখানে ক্লিক করুন", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "%1 থেকে আনরিড নোটিফিকেশন আছে।", "digest.latest_topics": "%1 এর সর্বশেষ টপিকসমূহ", "digest.cta": "%1 ভিজিট করতে এখানে ক্লিক করুন", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index 83aa15b6b5..d1abf066d9 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -35,6 +35,7 @@ "topic-locked": "টপিক বন্ধ", "still-uploading": "আপলোড সম্পূর্ণ জন্য অনুগ্রহ করে অপেক্ষা করুন", "content-too-short": "অনুগ্রহকরে অপেক্ষকৃত বড় পোষ্ট করুন। একটি পোষ্টে নূন্যতম %1 অক্ষর থাকতে হবে।", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "অনুগ্রহপূর্বক বড় শিরোনাম ব্যাবহার করুন। শিরোনামের জন্য নূন্যতম %1 অক্ষর ব্যাবহার করতে হবে।", "title-too-long": "অনুগ্রহ করে সংক্ষিপ্ত শিরোনাম লিখুন। শিরোনাম %1 অক্ষরের বেশি হতে পারবে না।", "too-many-posts": "আপনি প্রতি %1 সেকেন্ডে একবার পোষ্ট করতে পারবেন। পরবর্তী পোষ্ট করার জন্য অপেক্ষা করুন। ", @@ -62,6 +63,7 @@ "signature-too-long": "দুঃখিত, আপনার সাক্ষর %1 অক্ষরের বেশী হতে পারবে না। ", "cant-chat-with-yourself": "আপনি নিজের সাথে চ্যাট করতে পারবেন না!", "chat-restricted": "এই সদস্য তার বার্তালাপ সংরক্ষিত রেখেছেন। এই সদস্য আপনাকে ফলো করার পরই কেবলমাত্র আপনি তার সাথে চ্যাট করতে পারবেন", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "সম্মাননা ব্যাবস্থা নিস্ক্রীয় রাখা হয়েছে", "downvoting-disabled": "ঋণাত্মক ভোট নিস্ক্রীয় রাখা হয়েছে।", "not-enough-reputation-to-downvote": "আপনার এই পোস্ট downvote করার জন্য পর্যাপ্ত সম্মাননা নেই", diff --git a/public/language/bn/groups.json b/public/language/bn/groups.json index a9f9207a2f..fe8c9fed1d 100644 --- a/public/language/bn/groups.json +++ b/public/language/bn/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "সর্বশেষ পোষ্টসমূহ", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/bn/pages.json b/public/language/bn/pages.json index 1e28db3a2d..4ab90a11a2 100644 --- a/public/language/bn/pages.json +++ b/public/language/bn/pages.json @@ -11,6 +11,7 @@ "user.followers": "যারা %1 কে অনুসরণ করেন", "user.posts": "%1 এর পোস্ট সমুহ", "user.topics": "%1 এর টপিক সমুহ", + "user.groups": "%1's Groups", "user.favourites": "%1'র প্রিয় পোস্টগুলো", "user.settings": "সদস্য সেটিংস", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/bn/reset_password.json b/public/language/bn/reset_password.json index d4aa6415c1..5643e1c427 100644 --- a/public/language/bn/reset_password.json +++ b/public/language/bn/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "অনুগ্রহপূর্বক আপনার ইমেইল এড্রেস প্রদান করুন, আমরা আপনাকে আপনার পাসওয়ার্ড রিসেট সম্পর্কিত তথ্যাবলী ইমেইলে পাঠিয়ে দিবো। ", "enter_email_address": "আপনার ইমেইল এড্রেস", "password_reset_sent": "পাসওয়ার্ড রিসেট মেইল পাঠানো হয়েছে", - "invalid_email": "ভুল ইমেইল / ইমেইল ডেটাবেইজে নেই" + "invalid_email": "ভুল ইমেইল / ইমেইল ডেটাবেইজে নেই", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/bn/search.json b/public/language/bn/search.json index eafce184ec..0038567599 100644 --- a/public/language/bn/search.json +++ b/public/language/bn/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/bn/users.json b/public/language/bn/users.json index 5d7dbd5cec..402aa33c27 100644 --- a/public/language/bn/users.json +++ b/public/language/bn/users.json @@ -5,7 +5,7 @@ "search": "খুঁজুন", "enter_username": "ইউজারনেম এর ভিত্তিতে সার্চ করুন", "load_more": "আরো লোড করুন", - "users-found-search-took": "%1 সদস্য(দের) খুঁজে পাওয়া গিয়েছে! সময় লেগেছে %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/cs/email.json b/public/language/cs/email.json index 27a2f06198..a259648e70 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -9,6 +9,9 @@ "reset.text1": "Obdrželi jsme požadavek na obnovu hesla, pravděpodobně kvůli tomu, že jste ho zapomněli. Pokud to není tento případ, ignorujte, prosím, tento email.", "reset.text2": "Přejete-li si pokračovat v obnově vašeho hesla, klikněte, prosím, na následující odkaz:", "reset.cta": "Klikněte zde, chcete-li obnovit vaše heslo", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Máte tu nepřečtená oznámení od %1:", "digest.latest_topics": "Nejnovější témata od %1", "digest.cta": "Kliknutím zde navštívíte %1", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index d9d20cdf64..f858b2b15f 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -35,6 +35,7 @@ "topic-locked": "Téma uzamčeno", "still-uploading": "Vyčkejte, prosím, nežli se vše kompletně nahraje.", "content-too-short": "Vložte, prosím, delší příspěvek. Příspěvky by měly obsahovat nejméně %1 znaků.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Vložte, prosím, delší titulek. Titulky by měly obsahovat nejméně %1 znaků.", "title-too-long": "Vložte, prosím, kratší titulek. Titulky by neměly být delší, než-li %1 znaků.", "too-many-posts": "Své příspěvky můžete odesílat po %1 sekundách - vyčkejte, prosím, před dalším odesláním", @@ -62,6 +63,7 @@ "signature-too-long": "Pardon, ale váš podpis nemůže být delší, než-li %1 znaků.", "cant-chat-with-yourself": "Nemůžete chatovat sami se sebou!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Systém reputací je zakázán.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/cs/groups.json b/public/language/cs/groups.json index 980b41e1b7..95d083451f 100644 --- a/public/language/cs/groups.json +++ b/public/language/cs/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Nejnovější příspěvky", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/cs/pages.json b/public/language/cs/pages.json index b77b6411ba..15386435af 100644 --- a/public/language/cs/pages.json +++ b/public/language/cs/pages.json @@ -11,6 +11,7 @@ "user.followers": "People who Follow %1", "user.posts": "Posts made by %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/cs/reset_password.json b/public/language/cs/reset_password.json index 41dce1549f..ba87244661 100644 --- a/public/language/cs/reset_password.json +++ b/public/language/cs/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Zadejte svou emailovou adresu a my Vám pošleme informace, jak můžete obnovit své heslo.", "enter_email_address": "Zadejte emailovou adresu", "password_reset_sent": "Obnova hesla odeslána", - "invalid_email": "Špatný email / Email neexistuje!" + "invalid_email": "Špatný email / Email neexistuje!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/cs/search.json b/public/language/cs/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/cs/search.json +++ b/public/language/cs/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/cs/users.json b/public/language/cs/users.json index fe3e7cb9b7..22b698a8c0 100644 --- a/public/language/cs/users.json +++ b/public/language/cs/users.json @@ -5,7 +5,7 @@ "search": "Vyhledávat", "enter_username": "Zadej uživatelské jméno k hledání", "load_more": "Načíst další", - "users-found-search-took": "Nazelezeno: %1 uživetel(ů)! Vyhledání trvalo %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/de/category.json b/public/language/de/category.json index f455b1604b..e3d45d3af8 100644 --- a/public/language/de/category.json +++ b/public/language/de/category.json @@ -1,6 +1,6 @@ { "new_topic_button": "Neues Thema", - "no_topics": "Es gibt noch keine Themen in dieser Kategorie.
Warum beginnst du nicht das erste?", + "no_topics": "Es gibt noch keine Themen in dieser Kategorie.
Warum beginnst du nicht eins?", "browsing": "Aktiv", "no_replies": "Niemand hat geantwortet", "share_this_category": "Teile diese Kategorie", diff --git a/public/language/de/email.json b/public/language/de/email.json index 408c511c84..b60e620dd8 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -9,6 +9,9 @@ "reset.text1": "Wir haben eine Anfrage auf Zurücksetzung deines Passworts erhalten, wahrscheinlich, weil du es vergessen hast. Falls dies nicht der Fall ist, ignoriere bitte diese E-Mail.", "reset.text2": "Klicke bitte auf den folgenden Link, um mit der Zurücksetzung deines Passworts fortzufahren:", "reset.cta": "Klicke hier, um dein Passwort zurückzusetzen", + "reset.notify.subject": "Passwort erfolgreich geändert", + "reset.notify.text1": "Wir benachrichtigen dich das am %1, dein Passwort erfolgreich geändert wurde.", + "reset.notify.text2": "Wenn du das nicht autorisiert hast, bitte benachrichtige umgehend einen Administrator.", "digest.notifications": "Du hast ungelesene Benachrichtigungen von %1:", "digest.latest_topics": "Aktuellste Themen vom %1", "digest.cta": "Klicke hier, um %1 zu besuchen", @@ -17,8 +20,8 @@ "notif.chat.subject": "Neue Chatnachricht von %1 erhalten", "notif.chat.cta": "Klicke hier, um die Unterhaltung fortzusetzen", "notif.chat.unsub.info": "Diese Chat-Benachrichtigung wurde dir aufgrund deiner Abonnement-Einstellungen gesendet.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Hier klicken, um das gesamte Thema zu lesen", + "notif.post.unsub.info": "Diese Mitteilung wurde wegen ihrer Abonnement-Einstellung gesendet.", "test.text1": "Dies ist eine Test-E-Mail, um zu überprüfen, ob der E-Mailer deines NodeBB korrekt eingestellt wurde.", "unsub.cta": "Klicke hier, um diese Einstellungen zu ändern.", "closing": "Danke!" diff --git a/public/language/de/error.json b/public/language/de/error.json index 67cf44ca9c..b2deb8a2d3 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -2,7 +2,7 @@ "invalid-data": "Daten ungültig", "not-logged-in": "Du bist nicht angemeldet.", "account-locked": "Dein Account wurde vorübergehend gesperrt.", - "search-requires-login": "Die Suche erfordert ein Konto! Bitte log dich ein oder registrieren dich!", + "search-requires-login": "Die Suche erfordert ein Konto! Bitte log dich ein oder registriere dich!", "invalid-cid": "Ungültige Kategorie-ID", "invalid-tid": "Ungültige Themen-ID", "invalid-pid": "Ungültige Beitrags-ID", @@ -18,7 +18,7 @@ "username-taken": "Der Benutzername ist bereits vergeben", "email-taken": "Die E-Mail-Adresse ist bereits vergeben", "email-not-confirmed": "Deine E-Mail wurde noch nicht bestätigt. Bitte klicke hier, um deine E-Mail zu bestätigen.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Der Chat ist deaktiviert bis Du deine E-Mail bestätigt hast", "username-too-short": "Benutzername ist zu kurz", "username-too-long": "Der Benutzername ist zu lang", "user-banned": "Der Benutzer ist gesperrt", @@ -35,6 +35,7 @@ "topic-locked": "Thema ist gesperrt", "still-uploading": "Bitte warte bis der Vorgang abgeschlossen ist.", "content-too-short": "Bitte gib einen längeren Beitrag ein. Beiträge sollten mindestens %1 Zeichen enthalten.", + "content-too-long": "Bitte schreibe einen kürzeren Beitrag. Beiträge können nicht mehr als %1 Zeichen enthalten.", "title-too-short": "Bitte gib einen längeren Titel ein. Titel sollten mindestens %1 Zeichen enthalten.", "title-too-long": "Der Titel darf maximal %1 Zeichen enthalten.", "too-many-posts": "Du kannst maximal alle %1 Sekunden einen Beitrag erstellen - bitte warte, bevor du einen neuen Beitrag erstellst", @@ -44,13 +45,13 @@ "already-favourited": "Dieser Beitrag ist bereits in deinen Favoriten enthalten", "already-unfavourited": "Du hast diesen Beitrag bereits aus deinen Favoriten entfernt", "cant-ban-other-admins": "Du kannst andere Administratoren nicht sperren!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Falsche Bildart. Erlaubte Arten sind: %1", + "invalid-image-extension": "Ungültige Dateinamenerweiterung", "group-name-too-short": "Gruppenname zu kurz", "group-already-exists": "Gruppe existiert bereits", "group-name-change-not-allowed": "Du kannst den Namen der Gruppe nicht ändern", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Du bist bereits Teil dieser Gruppe", + "group-needs-owner": "Diese Gruppe muss mindestens einen Besitzer vorweisen", "post-already-deleted": "Dieser Beitrag ist bereits gelöscht worden", "post-already-restored": "Dieser Beitrag ist bereits wiederhergestellt worden", "topic-already-deleted": "Dieses Thema ist bereits gelöscht worden", @@ -62,11 +63,12 @@ "signature-too-long": "Entschuldigung, deine Signatur darf maximal %1 Zeichen enthalten.", "cant-chat-with-yourself": "Du kannst nicht mit dir selber chatten!", "chat-restricted": "Dieser Benutzer hat seine Chatfunktion eingeschränkt. Du kannst nur mit diesem Benutzer chatten, wenn er dir folgt.", + "too-many-messages": "Du hast zu viele Nachrichten versandt, bitte warte eine Weile.", "reputation-system-disabled": "Das Reputationssystem ist deaktiviert.", "downvoting-disabled": "Downvotes sind deaktiviert.", "not-enough-reputation-to-downvote": "Deine Reputation ist zu niedrig, um diesen Beitrag negativ zu bewerten.", "not-enough-reputation-to-flag": "Deine Reputation ist nicht gut genug, um diesen Beitrag zu melden", "reload-failed": "Es ist ein Problem während des Reloads von NodeBB aufgetreten: \"%1\". NodeBB wird weiterhin clientseitige Assets bereitstellen, allerdings solltest du das, was du vor dem Reload gemacht hast, rückgängig machen.", "registration-error": "Registrierungsfehler", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Ein Fehler ist beim Parsen der Server-Antwort aufgetreten" } \ No newline at end of file diff --git a/public/language/de/global.json b/public/language/de/global.json index 3f4242ea16..8da4b23a06 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -3,10 +3,10 @@ "search": "Suche", "buttons.close": "Schließen", "403.title": "Zugriff verweigert", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Du hast keine Zugriffsberechtigung für diese Seite.", + "403.login": "Du solltest Dich einloggen.", "404.title": " Nicht Gefunden", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Diese Seite existiert nicht. Zur Homepage zurückkehren.", "500.title": "Interner Fehler.", "500.message": "Ups! Scheint als wäre etwas schief gelaufen!", "register": "Registrieren", @@ -27,7 +27,7 @@ "header.tags": "Tags", "header.popular": "Beliebt", "header.users": "Benutzer", - "header.groups": "Groups", + "header.groups": "Gruppen", "header.chats": "Chats", "header.notifications": "Benachrichtigungen", "header.search": "Suche", @@ -75,7 +75,7 @@ "updated.title": "Forum aktualisiert", "updated.message": "Dieses Forum wurde gerade auf die neueste Version aktualisiert. Klicke hier, um die Seite neuzuladen.", "privacy": "Privatsphäre", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Folgen", + "unfollow": "Entfolgen", "delete_all": "Alles löschen" } \ No newline at end of file diff --git a/public/language/de/groups.json b/public/language/de/groups.json index 28138f6426..375e09d9b5 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -1,21 +1,23 @@ { "groups": "Gruppen", "view_group": "Gruppe betrachten", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Gruppenbesitzer", + "new_group": "Neue Gruppe erstellen", + "no_groups_found": "Es sind keine Gruppen vorhanden", + "cover-instructions": "Drag and Drop ein Foto, bewege es in Position, dann drücke Speichern", + "cover-change": "Ändern", + "cover-save": "Speichern", + "cover-saving": "Am speichern", "details.title": "Gruppendetails", "details.members": "Mitgliederliste", - "details.pending": "Pending Members", + "details.pending": "Ausstehende Mitglieder", "details.has_no_posts": "Die Mitglieder dieser Gruppe haben keine Beiträge verfasst.", "details.latest_posts": "Aktuelle Beiträge", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Private Gruppe", + "details.public": "Öffentliche Gruppe", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Gruppenadministration", + "event.updated": "Gruppendetails wurden aktualisiert", + "event.deleted": "Die Gruppe \"% 1\" wurde gelöscht" } \ No newline at end of file diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 277678114f..78b7c7469d 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -11,6 +11,7 @@ "user.followers": "Nutzer, die %1 folgen", "user.posts": "Beiträge von %1", "user.topics": "Themen von %1", + "user.groups": "%1's Gruppen", "user.favourites": "Von %1 favorisierte Beiträge", "user.settings": "Benutzer-Einstellungen", "maintenance.text": "%1 befindet sich derzeit in der Wartung. Bitte komm später wieder.", diff --git a/public/language/de/recent.json b/public/language/de/recent.json index 86cdfa5713..7242d231da 100644 --- a/public/language/de/recent.json +++ b/public/language/de/recent.json @@ -6,13 +6,13 @@ "year": "Jahr", "alltime": "Gesamter Zeitraum", "no_recent_topics": "Es gibt keine aktuellen Themen.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Es gibt ein neues Thema.", + "there-is-a-new-topic-and-a-new-post": "Es gibt ein neues Thema und einen neuen Beitrag.", + "there-is-a-new-topic-and-new-posts": "Es gibt ein neues Thema und %1 neue Beiträge.", + "there-are-new-topics": "Es gibt %1 neue Themen.", + "there-are-new-topics-and-a-new-post": "Es gibt %1 neue Themen und einen neuen Beitrag.", + "there-are-new-topics-and-new-posts": "Es gibt %1 neue Themen und %2 neue Beiträge.", + "there-is-a-new-post": "Es gibt einen neuen Beitrag.", + "there-are-new-posts": "Es gibt %1 neue Beiträge.", + "click-here-to-reload": "Hier klicken um neu zu laden." } \ No newline at end of file diff --git a/public/language/de/reset_password.json b/public/language/de/reset_password.json index bbbfae1249..02d9329f7d 100644 --- a/public/language/de/reset_password.json +++ b/public/language/de/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Bitte gib Deine E-Mail Adresse ein und wir senden Dir eine Anleitung, wie Du Dein Passwort zurücksetzen kannst.", "enter_email_address": "E-Mail Adresse eingeben", "password_reset_sent": "Passwortzurücksetzung beantragt.", - "invalid_email": "Ungültige E-Mail / Adresse existiert nicht!" + "invalid_email": "Ungültige E-Mail / Adresse existiert nicht!", + "password_too_short": "Das eingegebene Passwort ist zu kurz, bitte wähle ein anderes Passwort.", + "passwords_do_not_match": "Die eingegebenen Passwörter stimmen nicht überein." } \ No newline at end of file diff --git a/public/language/de/search.json b/public/language/de/search.json index 3cdafdd487..d817f2aa7f 100644 --- a/public/language/de/search.json +++ b/public/language/de/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 Ergebniss(e) stimmen mit \"%2\" überein, (%3 Sekunden)", - "no-matches": "No matches found", + "no-matches": "Keine Ergebnisse gefunden", "in": "In", - "by": "By", - "posted-by": "Posted by" + "by": "Bei", + "titles": "Titel", + "titles-posts": "Titel und Beiträge", + "posted-by": "Geschrieben von", + "in-categories": "In Kategorien", + "search-child-categories": "Suche in Unterkategorien", + "reply-count": "Antwort Anzahl", + "at-least": "Mindestens", + "at-most": "Höchstens", + "post-time": "Beitrags Zeit", + "newer-than": "Neuer als", + "older-than": "Älter als", + "any-date": "Jeder Zeitpunkt", + "yesterday": "Gestern", + "one-week": "Eine Woche", + "two-weeks": "Zwei Wochen", + "one-month": "Ein Monat", + "three-months": "Drei Monate", + "six-months": "Sechs Monate", + "one-year": "Ein Jahr", + "sort-by": "Sortieren nach", + "last-reply-time": "Letzter Antwort Zeitpunkt", + "topic-title": "Thementitel", + "number-of-replies": "Anzahl von Antworten", + "number-of-views": "Anzahl der Aufrufe", + "topic-start-date": "Thema Startdatum", + "username": "Benutzername", + "category": "Kategorie", + "descending": "In absteigender Reihenfolge", + "ascending": "In aufsteigender Reihenfolge" } \ No newline at end of file diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 23d6b0771e..e2e47d83c1 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -94,5 +94,5 @@ "oldest_to_newest": "Älteste zuerst", "newest_to_oldest": "Neuster zuerst", "most_votes": "Die meisten Stimmen", - "most_posts": "Most posts" + "most_posts": "Die meisten Beiträge" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index 8e320bcb85..dcc5a89332 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -2,8 +2,8 @@ "banned": "Gebannt", "offline": "offline", "username": "Nutzername", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Registriert vor", + "postcount": "Beiträge", "email": "E-Mail", "confirm_email": "E-Mail bestätigen", "delete_account": "Konto löschen", @@ -18,7 +18,7 @@ "profile_views": "Profilaufrufe", "reputation": "Reputation", "favourites": "Favoriten", - "watched": "Watched", + "watched": "Beobachtet", "followers": "Folger", "following": "Folgt", "signature": "Signatur", @@ -59,12 +59,12 @@ "digest_weekly": "Wöchentlich", "digest_monthly": "Monatlich", "send_chat_notifications": "Sende eine E-Mail, wenn eine neue Chat-Nachricht eingeht und ich nicht online bin", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Sende eine E-Mail wenn auf Themen die ich abonniert habe geantwortet wird", "has_no_follower": "Dieser User hat noch keine Follower.", "follows_no_one": "Dieser User folgt noch niemandem :(", "has_no_posts": "Dieser Nutzer hat noch nichts gepostet.", "has_no_topics": "Dieser Nutzer hat noch keine Themen gepostet.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Diese Person beobachtet keine Themen", "email_hidden": "E-Mail Adresse versteckt", "hidden": "versteckt", "paginate_description": "Themen und Beiträge auf Seiten aufteilen statt unendliches Scrollen verwenden.", diff --git a/public/language/de/users.json b/public/language/de/users.json index 1e0bf2eb01..99b17f79f6 100644 --- a/public/language/de/users.json +++ b/public/language/de/users.json @@ -6,7 +6,7 @@ "enter_username": "Benutzer durchsuchen", "load_more": "mehr laden", "users-found-search-took": "%1 Benutzer gefunden! Die Suche dauerte %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "filter-by": "Filtern nach", + "online-only": "Nur Online", + "picture-only": "Nur mit Bildern" } \ No newline at end of file diff --git a/public/language/el/email.json b/public/language/el/email.json index 6563d675d5..c4a52f1ffa 100644 --- a/public/language/el/email.json +++ b/public/language/el/email.json @@ -9,6 +9,9 @@ "reset.text1": "Λάβαμε ένα αίτημα για επαναφορά του κωδικού σου, πιθανότατα γιατί τον ξέχασες. Αν δεν έκανες εσύ αυτό το αίτημα, αγνόησε αυτό το email.", "reset.text2": "Για να κάνεις την επαναφορά του κωδικού σου, παρακαλώ πάτα στο παρακάτω σύνδεσμο:", "reset.cta": "Κάνε κλικ εδώ για να επαναφέρεις τον κωδικό σου", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Πρόσφατα θέματα στο %1", "digest.cta": "Κάνε κλικ εδώ για να επισκεφτείς το %1", diff --git a/public/language/el/error.json b/public/language/el/error.json index ce1173a11d..9cadac2731 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -35,6 +35,7 @@ "topic-locked": "Το θέμα έχει κλειδωθεί", "still-uploading": "Παρακαλώ περίμενε να τελειώσει το ανέβασμα των αρχείων.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Παρακαλώ γράψε έναν μικρότερο τίτλο. Δεν μπορεί να είναι μεγαλύτερος από %1 χαρακτήρες.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Δεν μπορείς να συνομιλήσεις με τον εαυτό σου!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Το σύστημα φήμης έχει απενεργοποιηθεί.", "downvoting-disabled": "Η καταψήφιση έχει απενεργοποιηθεί", "not-enough-reputation-to-downvote": "Δεν έχεις αρκετή φήμη για να καταψηφίσεις αυτή την δημοσίευση", diff --git a/public/language/el/groups.json b/public/language/el/groups.json index 5fa5a25877..9ad8583476 100644 --- a/public/language/el/groups.json +++ b/public/language/el/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Τελευταίες δημοσιεύσεις.", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/el/pages.json b/public/language/el/pages.json index 04301ee967..0b9a89746e 100644 --- a/public/language/el/pages.json +++ b/public/language/el/pages.json @@ -11,6 +11,7 @@ "user.followers": "Άτομα που ακολουθούν τον/την %1", "user.posts": "Δημοσιεύσεις από τον/την %1", "user.topics": "Θέματα από τον/την %1", + "user.groups": "%1's Groups", "user.favourites": "Οι αγαπημένες δημοσιεύσεις του/της %1", "user.settings": "Επιλογές Χρήστη", "maintenance.text": "Το %1 αυτή την στιγμή συντηρείται. Παρακαλώ έλα αργότερα.", diff --git a/public/language/el/reset_password.json b/public/language/el/reset_password.json index e088a5bd9f..1ceecfd014 100644 --- a/public/language/el/reset_password.json +++ b/public/language/el/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Παρακαλώ γράψε την διεύθυνση email σου και θα σου στείλουμε ένα email με οδηγίες για το πως να επαναφέρεις τον λογαριασμό σου.", "enter_email_address": "Εισαγωγή Διεύθυνσης Email", "password_reset_sent": "Η Επαναφορά Κωδικού Εστάλη", - "invalid_email": "Άκυρο Email / Το email δεν υπάρχει!" + "invalid_email": "Άκυρο Email / Το email δεν υπάρχει!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/el/search.json b/public/language/el/search.json index fd5d9fa97e..eb08d6b538 100644 --- a/public/language/el/search.json +++ b/public/language/el/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/el/users.json b/public/language/el/users.json index 7a668b12a8..aae33e825c 100644 --- a/public/language/el/users.json +++ b/public/language/el/users.json @@ -5,7 +5,7 @@ "search": "Αναζήτηση", "enter_username": "Γράψε ένα όνομα χρήστη προς αναζήτηση", "load_more": "Φόρτωση περισσότερων", - "users-found-search-took": "%1 χρήστης(ες) βρέθηκαν! Η αναζήτηση πήρε %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/en@pirate/email.json b/public/language/en@pirate/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/en@pirate/email.json +++ b/public/language/en@pirate/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/en@pirate/error.json b/public/language/en@pirate/error.json index a40a628042..9bbcf03247 100644 --- a/public/language/en@pirate/error.json +++ b/public/language/en@pirate/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/en@pirate/groups.json b/public/language/en@pirate/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/en@pirate/groups.json +++ b/public/language/en@pirate/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/en@pirate/pages.json b/public/language/en@pirate/pages.json index b77b6411ba..15386435af 100644 --- a/public/language/en@pirate/pages.json +++ b/public/language/en@pirate/pages.json @@ -11,6 +11,7 @@ "user.followers": "People who Follow %1", "user.posts": "Posts made by %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/en@pirate/reset_password.json b/public/language/en@pirate/reset_password.json index dcdf4e76b6..ba9f012ea6 100644 --- a/public/language/en@pirate/reset_password.json +++ b/public/language/en@pirate/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Please enter your email address and we will send you an email with instructions on how to reset your account.", "enter_email_address": "Enter Email Address", "password_reset_sent": "Password Reset Sent", - "invalid_email": "Invalid Email / Email does not exist!" + "invalid_email": "Invalid Email / Email does not exist!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/en@pirate/search.json b/public/language/en@pirate/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/en@pirate/search.json +++ b/public/language/en@pirate/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/en@pirate/users.json b/public/language/en@pirate/users.json index adbfee83cc..daabbb899c 100644 --- a/public/language/en@pirate/users.json +++ b/public/language/en@pirate/users.json @@ -5,7 +5,7 @@ "search": "Search", "enter_username": "Gimme y'er handle", "load_more": "Load More", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/en_GB/email.json b/public/language/en_GB/email.json index efee400748..33fd28377b 100644 --- a/public/language/en_GB/email.json +++ b/public/language/en_GB/email.json @@ -13,6 +13,10 @@ "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index 7e21a1290a..bf4e7229fd 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -46,11 +46,14 @@ "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "invalid-title": "Invalid title!", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 seconds until you have earned %2 reputation - please wait before posting again", + "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 characters", + "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 characters", "file-too-big": "Maximum allowed file size is %1 kbs - please upload a smaller file", "cant-vote-self-post": "You cannot vote for your own post", @@ -83,6 +86,7 @@ "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/en_GB/groups.json b/public/language/en_GB/groups.json index eb9a45f994..964b5f42c6 100644 --- a/public/language/en_GB/groups.json +++ b/public/language/en_GB/groups.json @@ -17,6 +17,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index 54c926a597..96aef60183 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -2,6 +2,7 @@ "title": "Notifications", "no_notifs": "You have no new notifications", "see_all": "See all Notifications", + "mark_all_read": "Mark all notifications read", "back_to_home": "Back to %1", "outgoing_link": "Outgoing Link", diff --git a/public/language/en_GB/pages.json b/public/language/en_GB/pages.json index 8b231f8a94..4095ae38a3 100644 --- a/public/language/en_GB/pages.json +++ b/public/language/en_GB/pages.json @@ -11,6 +11,7 @@ "user.followers": "People who Follow %1", "user.posts": "Posts made by %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", diff --git a/public/language/en_GB/reset_password.json b/public/language/en_GB/reset_password.json index 27537ffdf2..96ba318a8a 100644 --- a/public/language/en_GB/reset_password.json +++ b/public/language/en_GB/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Please enter your email address and we will send you an email with instructions on how to reset your account.", "enter_email_address": "Enter Email Address", "password_reset_sent": "Password Reset Sent", - "invalid_email": "Invalid Email / Email does not exist!" + "invalid_email": "Invalid Email / Email does not exist!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } diff --git a/public/language/en_GB/search.json b/public/language/en_GB/search.json index 23519b038b..8c73511bda 100644 --- a/public/language/en_GB/search.json +++ b/public/language/en_GB/search.json @@ -3,5 +3,39 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "post-time": "Post time", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order", + "save-preferences": "Save preferences", + "clear-preferences": "Clear preferences", + "search-preferences-saved": "Search preferences saved", + "search-preferences-cleared": "Search preferences cleared", + "show-results-as": "Show results as" } diff --git a/public/language/en_GB/tags.json b/public/language/en_GB/tags.json index f67b2ca7b5..a3f75bb2e6 100644 --- a/public/language/en_GB/tags.json +++ b/public/language/en_GB/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", + "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/en_GB/users.json b/public/language/en_GB/users.json index 683ad7e155..0f3687c9ed 100644 --- a/public/language/en_GB/users.json +++ b/public/language/en_GB/users.json @@ -5,7 +5,7 @@ "search": "Search", "enter_username": "Enter a username to search", "load_more": "Load More", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/en_US/email.json b/public/language/en_US/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/en_US/email.json +++ b/public/language/en_US/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/en_US/error.json b/public/language/en_US/error.json index a40a628042..9bbcf03247 100644 --- a/public/language/en_US/error.json +++ b/public/language/en_US/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/en_US/groups.json b/public/language/en_US/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/en_US/groups.json +++ b/public/language/en_US/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/en_US/pages.json b/public/language/en_US/pages.json index d96ee1a8e6..c6d577d2f5 100644 --- a/public/language/en_US/pages.json +++ b/public/language/en_US/pages.json @@ -11,6 +11,7 @@ "user.followers": "People who Follow %1", "user.posts": "Posts made by %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "%1's Favorite Posts", "user.settings": "User Settings", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/en_US/reset_password.json b/public/language/en_US/reset_password.json index dcdf4e76b6..ba9f012ea6 100644 --- a/public/language/en_US/reset_password.json +++ b/public/language/en_US/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Please enter your email address and we will send you an email with instructions on how to reset your account.", "enter_email_address": "Enter Email Address", "password_reset_sent": "Password Reset Sent", - "invalid_email": "Invalid Email / Email does not exist!" + "invalid_email": "Invalid Email / Email does not exist!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/en_US/search.json b/public/language/en_US/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/en_US/search.json +++ b/public/language/en_US/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/en_US/users.json b/public/language/en_US/users.json index a06aee2734..0038dcffc4 100644 --- a/public/language/en_US/users.json +++ b/public/language/en_US/users.json @@ -5,7 +5,7 @@ "search": "Search", "enter_username": "Enter a username to search", "load_more": "Load More", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/es/email.json b/public/language/es/email.json index cff3a5d025..fd42293e1b 100644 --- a/public/language/es/email.json +++ b/public/language/es/email.json @@ -9,6 +9,9 @@ "reset.text1": "Recibimos una solicitud para reiniciar tu contraseña, posiblemente porque la olvidaste. Si no es así, por favor ignora este email.", "reset.text2": "Para continuar con el reinicio de contraseña, por favor cliquea en el siguiente vínculo:", "reset.cta": "Cliquea aquí para reiniciar tu contraseña", + "reset.notify.subject": "Se ha modificado correctamente la contraseña.", + "reset.notify.text1": "Te estamos notificando que a a %1, tu contraseña ha sido cambiado correctamente.", + "reset.notify.text2": "Si no has sido tu, por favor notifica al administrador inmediatamente.", "digest.notifications": "Tiene notificaciones sin leer de %1:", "digest.latest_topics": "Últimos temas de %1", "digest.cta": "Cliquea aquí para visitar %1", @@ -17,8 +20,8 @@ "notif.chat.subject": "Nuevo mensaje de chat recibido de %1", "notif.chat.cta": "Haz click aquí para continuar la conversación", "notif.chat.unsub.info": "Esta notificación de chat se te envió debido a tus ajustes de suscripción.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Cliquea aquí para leer la publicación completa", + "notif.post.unsub.info": "La notificación de este mensaje se te ha enviado debido a tus ajustes de subscripción.", "test.text1": "Este es un email de prueba para verificar que el envío de email está ajustado correctamente para tu NodeBB", "unsub.cta": "Haz click aquí para modificar los ajustes.", "closing": "¡Gracias!" diff --git a/public/language/es/error.json b/public/language/es/error.json index d656a309f6..7a79b28ba4 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -18,7 +18,7 @@ "username-taken": "Nombre de usuario ocupado", "email-taken": "Correo electrónico ocupado", "email-not-confirmed": "Su cuenta de correo electrónico no ha sido confirmada aún, por favor haga click aquí para confirmarla.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "No puedes hacer uso del chat hasta que confirmes tu email", "username-too-short": "Nombre de usuario es demasiado corto", "username-too-long": "Nombre de usuario demasiado largo", "user-banned": "Usuario baneado", @@ -35,6 +35,7 @@ "topic-locked": "Tema bloqueado", "still-uploading": "Por favor, espera a que terminen las subidas.", "content-too-short": "Por favor introduzca una publicación más larga. Las publicaciones deben contener al menos %1 caracteres.", + "content-too-long": "Por favor introduzca un mensaje más corto. Los mensajes no pueden exceder los %1 caracteres.", "title-too-short": "Por favor introduzca un título más largo. Los títulos deben contener al menos %1 caracteres.", "title-too-long": "Por favor, introduce un título más corto, que no sobrepase los %1 caracteres.", "too-many-posts": "Solo puedes publicar una vez cada %1 segundos - por favor espere antes de volver a publicar", @@ -44,13 +45,13 @@ "already-favourited": "Ya ha marcado esta publicación como favorita", "already-unfavourited": "Ya ha desmarcado esta publicación como favorita", "cant-ban-other-admins": "¡No puedes expulsar a otros administradores!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Tipo de imagen inválido. Los tipos permitidos son: %1", + "invalid-image-extension": "Extensión de imagen inválida", "group-name-too-short": "Nombre del grupo es demasiado corto.", "group-already-exists": "El grupo ya existe.", "group-name-change-not-allowed": "El nombre del grupo deseado no está permitido.", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Ya formas parte de este grupo", + "group-needs-owner": "Este grupo requiere al menos un propietario", "post-already-deleted": "Este publicación ya ha sido borrada", "post-already-restored": "Esta publicación ya ha sido restaurada", "topic-already-deleted": "Este tema ya ha sido borrado", @@ -62,11 +63,12 @@ "signature-too-long": "Lo sentimos, pero tu firma no puede ser más larga de %1 caracteres.", "cant-chat-with-yourself": "¡No puedes conversar contigo mismo!", "chat-restricted": "Este usuario tiene restringidos los mensajes de chat. Los usuarios deben seguirte antes de que pueda charlar con ellos", + "too-many-messages": "Has enviado demasiados mensajes, por favor espera un poco.", "reputation-system-disabled": "El sistema de reputación está deshabilitado.", "downvoting-disabled": "La votación negativa está deshabilitada.", "not-enough-reputation-to-downvote": "No tienes suficiente reputación para votar negativo este post", "not-enough-reputation-to-flag": "No tiene suficiente reputación para poner reportar esta publicación", "reload-failed": "NodeBB encontró un problema al refrescar: \"%1\". NodeBB intentará cargar el resto de contenido, aunque deberías deshacer lo que hiciste justo antes.", "registration-error": "Error de registro", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Algo ha ido mal mientras se parseaba la respuesta del servidor" } \ No newline at end of file diff --git a/public/language/es/global.json b/public/language/es/global.json index b452d2a26f..4e2b07be05 100644 --- a/public/language/es/global.json +++ b/public/language/es/global.json @@ -3,10 +3,10 @@ "search": "Buscar", "buttons.close": "Cerrar", "403.title": "Acceso denegado", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Al parecer has llegado a una página a la cual no tienes permisos para acceder.", + "403.login": "¿Quizás deberías intentar acceder?", "404.title": "No encontrado", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Al parecer has llegado a una página a la cual no tienes permisos para acceder. Volver a la página de inicio .", "500.title": "Error Interno.", "500.message": "¡Ooops! ¡Parece que algo salió mal! No te preocupes, ¡nuestros simios hiperinteligentes lo solucionarán!", "register": "Registrarse", @@ -27,7 +27,7 @@ "header.tags": "Etiquetas", "header.popular": "Popular", "header.users": "Usuarios", - "header.groups": "Groups", + "header.groups": "Grupos", "header.chats": "Chats", "header.notifications": "Notificaciones", "header.search": "Buscar", @@ -75,7 +75,7 @@ "updated.title": "Foro actualizado", "updated.message": "El foro acaba de ser actualizado a la última versión. Haz click aquí para refrescar la página.", "privacy": "Privacidad", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Seguir", + "unfollow": "Dejar de Seguir", "delete_all": "Eliminar todo" } \ No newline at end of file diff --git a/public/language/es/groups.json b/public/language/es/groups.json index 92be20f80a..999550b671 100644 --- a/public/language/es/groups.json +++ b/public/language/es/groups.json @@ -1,21 +1,23 @@ { "groups": "Grupos", "view_group": "Ver Grupo", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Propietario del Grupo", + "new_group": "Crear Nuevo Grupo", + "no_groups_found": "No hay grupos que ver", + "cover-instructions": "Arrastra y suelta una foto, arrastra a la posición, y pulsa Guardar ", + "cover-change": "Cambiar", + "cover-save": "Guardar", + "cover-saving": "Guardando", "details.title": "Detalles de Grupo", "details.members": "Lista de Miembros", - "details.pending": "Pending Members", + "details.pending": "Miembros Pendientes", "details.has_no_posts": "Los miembros de este grupo no han hecho ninguna publicación.", "details.latest_posts": "Últimas Publicaciones", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Grupo Privado", + "details.public": "Grupo Público", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Administración De Grupo", + "event.updated": "Los detalles del grupo han sido actualizados", + "event.deleted": "El grupo \"%1\" ha sido eliminado" } \ No newline at end of file diff --git a/public/language/es/pages.json b/public/language/es/pages.json index 27d9ca8f67..4cd102fdf0 100644 --- a/public/language/es/pages.json +++ b/public/language/es/pages.json @@ -11,6 +11,7 @@ "user.followers": "Seguidores de %1", "user.posts": "Mensajes de %1", "user.topics": "Temas creados por %1", + "user.groups": "%1's Grupos", "user.favourites": "Publicaciones favoritas de %1 ", "user.settings": "Preferencias de usuario", "maintenance.text": "%1 está en mantenimiento actualmente. Por favor vuelva en otro momento.", diff --git a/public/language/es/recent.json b/public/language/es/recent.json index 6c8600afec..ea473a2b51 100644 --- a/public/language/es/recent.json +++ b/public/language/es/recent.json @@ -6,13 +6,13 @@ "year": "Año", "alltime": "Siempre", "no_recent_topics": "No hay publicaciones recientes.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Hay una nueva publicación.", + "there-is-a-new-topic-and-a-new-post": "hay una nueva publicación y un nuevo mensaje.", + "there-is-a-new-topic-and-new-posts": "Hay una nueva publicación y %1 nuevos mensajes.", + "there-are-new-topics": "Hay %1 nuevos mensajes.", + "there-are-new-topics-and-a-new-post": "Hay %1 nuevas publicaciones y un nuevo mensaje.", + "there-are-new-topics-and-new-posts": "Hay %1 nuevas publicaciones y %2 nuevos mensajes.", + "there-is-a-new-post": "Hay un nuevo mensaje.", + "there-are-new-posts": "Hay %1 nuevos mensajes.", + "click-here-to-reload": "Cliquea aquí para recargar." } \ No newline at end of file diff --git a/public/language/es/reset_password.json b/public/language/es/reset_password.json index ea8e2b1fac..da269f5448 100644 --- a/public/language/es/reset_password.json +++ b/public/language/es/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Por favor ingresa tu correo electrónico y te enviaremos un mensaje con indicaciones para restablecer tu cuenta.", "enter_email_address": "Introduce tu correo electrónico", "password_reset_sent": "Restablecimiento de contraseña enviado", - "invalid_email": "¡Correo electrónico no válido o inexistente!" + "invalid_email": "¡Correo electrónico no válido o inexistente!", + "password_too_short": "La contraseña introducida es demasiado corta, por favor introduzca una contraseña diferente.", + "passwords_do_not_match": "Las dos contraseñas introducidas no concuerdan." } \ No newline at end of file diff --git a/public/language/es/search.json b/public/language/es/search.json index add13e50c1..e23eea6ba8 100644 --- a/public/language/es/search.json +++ b/public/language/es/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 resuldado(s) coinciden con \"%2\". (%3 segundos)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "No se encontraron coincidencias", + "in": "En", + "by": "Por", + "titles": "Títulos", + "titles-posts": "Títulos y publicaciones", + "posted-by": "Publicado por", + "in-categories": "En categorías", + "search-child-categories": "Buscar categorías hijas", + "reply-count": "Número de Respuestas", + "at-least": "De mínimo", + "at-most": "De máximo", + "post-time": "Fecha de publicación", + "newer-than": "Más reciente que", + "older-than": "Más antiguo que", + "any-date": "Cualquier fecha", + "yesterday": "Ayer", + "one-week": "Una semana", + "two-weeks": "Dos semanas", + "one-month": "Un mes", + "three-months": "Tres meses", + "six-months": "Seis meses", + "one-year": "Un año", + "sort-by": "Ordenar por", + "last-reply-time": "Fecha de última respuesta", + "topic-title": "Título de tema", + "number-of-replies": "Número de respuestas", + "number-of-views": "Número de visualizaciones", + "topic-start-date": "Fecha de inicio del tema", + "username": "Usuario", + "category": "Categoría", + "descending": "En orden descendente", + "ascending": "En orden ascendente" } \ No newline at end of file diff --git a/public/language/es/topic.json b/public/language/es/topic.json index 30563b67ae..f1a3f4221c 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "¡No has seleccionado ningún mensaje!", "fork_success": "¡Se ha creado un nuevo tema a partir del original! Haz click aquí para ir al nuevo tema.", "composer.title_placeholder": "Ingresa el título de tu tema...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Nombre", "composer.discard": "Descartar", "composer.submit": "Enviar", "composer.replying_to": "En respuesta a %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "Más antiguo a más nuevo", "newest_to_oldest": "Más nuevo a más antiguo", "most_votes": "Mayor número de votos", - "most_posts": "Most posts" + "most_posts": "Mayor número de mensajes" } \ No newline at end of file diff --git a/public/language/es/user.json b/public/language/es/user.json index 23976718fb..add6981c5f 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -2,8 +2,8 @@ "banned": "Baneado", "offline": "Desconectado", "username": "Nombre de usuario", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Fecha de Registro", + "postcount": "Número De Publicaciones", "email": "Correo electrónico", "confirm_email": "Confirmar correo electrónico", "delete_account": "Eliminar cuenta", @@ -18,7 +18,7 @@ "profile_views": "Visitas", "reputation": "Reputación", "favourites": "Favoritos", - "watched": "Watched", + "watched": "Visto", "followers": "Seguidores", "following": "Siguiendo", "signature": "Firma", @@ -59,12 +59,12 @@ "digest_weekly": "Semanalmente", "digest_monthly": "Mensualmente", "send_chat_notifications": "Enviar un email si recibo un mensaje de chat cuando no esté en línea.", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Enviarme un email cuando se realicen contestaciones en los temas en los que estoy subscrito", "has_no_follower": "Este usuario no tiene seguidores :(", "follows_no_one": "Este miembro no sigue a nadie :(", "has_no_posts": "Este usuario aún no ha publicado nada.", "has_no_topics": "Este usuario aún no ha publicado nada.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Este usuario todavía no ha visto ninguna publicación.", "email_hidden": "Correo electrónico oculto", "hidden": "oculto", "paginate_description": "Paginar hilos y mensajes en lugar de usar desplazamiento infinito.", diff --git a/public/language/es/users.json b/public/language/es/users.json index 18b783a6c1..81668516cf 100644 --- a/public/language/es/users.json +++ b/public/language/es/users.json @@ -5,8 +5,8 @@ "search": "Buscar", "enter_username": "Ingresa el nombre de usuario que quieres buscar", "load_more": "Cargar más", - "users-found-search-took": "¡%1 usuario(s) encontrados! La búsqueda tardó %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "¡%1 usuario(s) encontrado! La búsqueda ha llevado %2 segundos.", + "filter-by": "Filtrar Por", + "online-only": "Sólo en línea", + "picture-only": "Sólo imagen" } \ No newline at end of file diff --git a/public/language/et/email.json b/public/language/et/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/et/email.json +++ b/public/language/et/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/et/error.json b/public/language/et/error.json index 0cbb8ea85f..277568c591 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -35,6 +35,7 @@ "topic-locked": "Teema lukustatud", "still-uploading": "Palun oota, kuni üleslaadimised on laetud.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Palun sisesta lühem pealkiri. Pealkirjad ei saa olla pikemad kui %1 tähemärki.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Sa ei saa endaga vestelda!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "Sul ei ole piisavalt reputatsiooni, et anda negatiivset hinnangut sellele postitusele.", diff --git a/public/language/et/groups.json b/public/language/et/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/et/groups.json +++ b/public/language/et/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/et/pages.json b/public/language/et/pages.json index be7537527b..4a8ef6408f 100644 --- a/public/language/et/pages.json +++ b/public/language/et/pages.json @@ -11,6 +11,7 @@ "user.followers": "Kasutajad, kes jälgivad %1", "user.posts": "Postitused, mis on tehtud kasutaja %1 poolt", "user.topics": "Teemad on kirjutanud %1", + "user.groups": "%1's Groups", "user.favourites": "%1's lemmikud postitused", "user.settings": "Kasutaja sätted", "maintenance.text": "%1 foorumil on käimas hooldustööd. Palun külastage meid mõne aja pärast uuesti.", diff --git a/public/language/et/reset_password.json b/public/language/et/reset_password.json index c504ed9296..98e4fe4fae 100644 --- a/public/language/et/reset_password.json +++ b/public/language/et/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Palun sisesta oma emaili aadress ja me saadame sulle emaili koos õpetusega, kuidas oma parooli vahetada.", "enter_email_address": "Sisesta emaili aadress", "password_reset_sent": "Saadetud", - "invalid_email": "Vigane emaili aadress / emaili aadressi ei ekisteeri!" + "invalid_email": "Vigane emaili aadress / emaili aadressi ei ekisteeri!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/et/search.json b/public/language/et/search.json index 840538a793..448f45b055 100644 --- a/public/language/et/search.json +++ b/public/language/et/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/et/users.json b/public/language/et/users.json index 4782d131f5..ac83e6b160 100644 --- a/public/language/et/users.json +++ b/public/language/et/users.json @@ -5,7 +5,7 @@ "search": "Otsi", "enter_username": "Sisesta kasutajanimi, keda soovid otsida", "load_more": "Lae veel", - "users-found-search-took": "%1kasutaja(t) leiti! Otsing kestis %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/fa_IR/email.json b/public/language/fa_IR/email.json index 79cf1e91cf..206fe1823b 100644 --- a/public/language/fa_IR/email.json +++ b/public/language/fa_IR/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "برای تنظیم مجدد گذرواژه‌ی خود اینجا کلیک کنید", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "برای دیدن 1% اینجا کلیک کنید", diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index 8657d58d7d..e99118134c 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -35,6 +35,7 @@ "topic-locked": "جستار بسته شد.", "still-uploading": "خواهشمندیم تا پایان بارگذاری‌ها شکیبا باشید.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "خواهشمندیم عنوان کوتاه‌تری بنویسید. عنوان‌ها نمی‌توانند بیش‌تر از %1 نویسه داشته باشند.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "شما نمی‌توانید با خودتان گفتگو کنید!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "شما اعتبار کافی برای دادن رای منفی به این دیدگاه را ندارید.", diff --git a/public/language/fa_IR/groups.json b/public/language/fa_IR/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/fa_IR/groups.json +++ b/public/language/fa_IR/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/fa_IR/pages.json b/public/language/fa_IR/pages.json index ec3b4e6800..42dacfa193 100644 --- a/public/language/fa_IR/pages.json +++ b/public/language/fa_IR/pages.json @@ -11,6 +11,7 @@ "user.followers": "کاربرانی که %1 را دنبال می‌کنند", "user.posts": "دیدگاه‌های %1", "user.topics": "%1 این جستار را ساخت.", + "user.groups": "%1's Groups", "user.favourites": "دیدگاه‌های پسندیدهٔ %1", "user.settings": "تنظیمات کاربر", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/fa_IR/reset_password.json b/public/language/fa_IR/reset_password.json index a0171f831c..5e6ea61461 100644 --- a/public/language/fa_IR/reset_password.json +++ b/public/language/fa_IR/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "لطفا نشانی رایانامهٔ خود را بنویسید و ما دستورکار بازیابی شناسه‌تان را به این رایانامه می‌فرستیم.", "enter_email_address": "نوشتن نشانی رایانامه", "password_reset_sent": "رایانامهٔ بازیابی گذرواژه فرستاده شد", - "invalid_email": "رایانامهٔ نامعتبر / رایانامه وجود ندارد!" + "invalid_email": "رایانامهٔ نامعتبر / رایانامه وجود ندارد!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/fa_IR/search.json b/public/language/fa_IR/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/fa_IR/search.json +++ b/public/language/fa_IR/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/fa_IR/users.json b/public/language/fa_IR/users.json index aec64b6020..b164bd0839 100644 --- a/public/language/fa_IR/users.json +++ b/public/language/fa_IR/users.json @@ -5,7 +5,7 @@ "search": "جستجو", "enter_username": "یک نام کاربری برای جستجو وارد کنید", "load_more": "بارگذاری بیش‌تر", - "users-found-search-took": "%1 کاربر() در مدت زمان %2 میلی ثانیه یافت شد!", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/fi/email.json b/public/language/fi/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/fi/email.json +++ b/public/language/fi/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 0b28c1f98b..813f7896e2 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -35,6 +35,7 @@ "topic-locked": "Aihe lukittu", "still-uploading": "Ole hyvä ja odota tiedostojen lähettämisen valmistumista.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Otsikkosi on liian pitkä. Otsikoiden pituuden tulee olla enintään %1 merkkiä.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Et voi keskustella itsesi kanssa!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/fi/groups.json b/public/language/fi/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/fi/groups.json +++ b/public/language/fi/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/fi/pages.json b/public/language/fi/pages.json index 22b1b20306..07d941a4dc 100644 --- a/public/language/fi/pages.json +++ b/public/language/fi/pages.json @@ -11,6 +11,7 @@ "user.followers": "Käyttäjät, jotka seuraavat käyttäjää %1", "user.posts": "Käyttäjän %1 kirjoittamat viestit", "user.topics": "Käyttäjän %1 aloittamat aiheet", + "user.groups": "%1's Groups", "user.favourites": "Käyttäjän %1 suosikkiviestit", "user.settings": "Käyttäjän asetukset", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/fi/reset_password.json b/public/language/fi/reset_password.json index 071287708d..9d78c5f372 100644 --- a/public/language/fi/reset_password.json +++ b/public/language/fi/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Syötä sähköpostiosoitteesi, niin me lähetämme sinulle sähköpostilla ohjeet käyttäjätilisi palauttamiseksi.", "enter_email_address": "Syötä sähköpostiosoite", "password_reset_sent": "Salasanan palautuskoodi lähetetty", - "invalid_email": "Virheellinen sähköpostiosoite / Sähköpostiosoitetta ei ole olemassa!" + "invalid_email": "Virheellinen sähköpostiosoite / Sähköpostiosoitetta ei ole olemassa!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/fi/search.json b/public/language/fi/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/fi/search.json +++ b/public/language/fi/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/fi/users.json b/public/language/fi/users.json index 67556152ae..f1cca4ea56 100644 --- a/public/language/fi/users.json +++ b/public/language/fi/users.json @@ -5,7 +5,7 @@ "search": "Hae", "enter_username": "Syötä käyttäjätunnus hakeaksesi", "load_more": "Lataa lisää", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/fr/email.json b/public/language/fr/email.json index 1ed4d80cac..a3b80ecd21 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -9,6 +9,9 @@ "reset.text1": "Nous avons reçu une demande de réinitialisation de votre mot de passe, probablement parce que vous l'avez oublié. Si ce n'est pas le cas, veuillez ignorer cet email.", "reset.text2": "Pour confirmer la réinitialisation de votre mot de passe, veuillez cliquer sur le lien suivant :", "reset.cta": "Cliquez ici pour réinitialiser votre mot de passe", + "reset.notify.subject": "Mot de Passe modifié", + "reset.notify.text1": "Nous vous informons que le %1, votre mot de passe a été modifié.", + "reset.notify.text2": "Si vous n'avez pas autorisé ceci, veuillez contacter immédiatement un administrateur.", "digest.notifications": "Vous avez des notifications non-lues de %1 :", "digest.latest_topics": "Derniers sujets de %1 :", "digest.cta": "Cliquez ici pour aller sur %1", @@ -17,8 +20,8 @@ "notif.chat.subject": "Nouveau message de chat reçu de %1", "notif.chat.cta": "Cliquez ici pour continuer la conversation", "notif.chat.unsub.info": "Cette notification de chat a été envoyé en raison de vos paramètres d'abonnement.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Cliquer ici pour lire le sujet complet", + "notif.post.unsub.info": "La notification de ce message vous a été envoyé en raison de vos paramètres d'abonnement.", "test.text1": "Ceci est un email de test pour vérifier que l'emailer est correctement configuré pour NodeBB.", "unsub.cta": "Cliquez ici pour modifier ces paramètres", "closing": "Merci !" diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 28ab5566f6..bfa70c579c 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -18,7 +18,7 @@ "username-taken": "Nom d’utilisateur déjà utilisé", "email-taken": "Email déjà utilisé", "email-not-confirmed": "Votre adresse email n'est pas confirmée, cliquer ici pour la valider.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Vous ne pouver discuter tant que votre email n'est pas confirmé", "username-too-short": "Nom d'utilisateur trop court", "username-too-long": "Nom d'utilisateur trop long", "user-banned": "Utilisateur banni", @@ -35,6 +35,7 @@ "topic-locked": "Sujet verrouillé", "still-uploading": "Veuillez patienter pendant le téléchargement.", "content-too-short": "Veuillez entrer un message plus long. %1 caractères minimum.", + "content-too-long": "Veuillez poster un message plus cours. Les messages ne peuvent être plus long que %1 caractères.", "title-too-short": "Veuillez entrer un titre plus long. %1 caractères minimum.", "title-too-long": "Veuillez entrer un titre plus court. Les titres ne peuvent excéder %1 caractères.", "too-many-posts": "Vous ne pouvez poster que toutes les %1 secondes.", @@ -44,13 +45,13 @@ "already-favourited": "Vous avez déjà mis ce message en favoris", "already-unfavourited": "Vous avez déjà retiré ce message des favoris", "cant-ban-other-admins": "Vous ne pouvez pas bannir les autres administrateurs !", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Type d'image invalide. Les types autorisés sont: %1", + "invalid-image-extension": "Extension d'image invalide", "group-name-too-short": "Nom de groupe trop court", "group-already-exists": "Ce groupe existe déjà", "group-name-change-not-allowed": "Modification du nom de groupe non permise", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Vous faites déjà parti de ce groupe", + "group-needs-owner": "Ce groupe nécessite au moins un propriétaire", "post-already-deleted": "Message déjà supprimé", "post-already-restored": "Message déjà restauré", "topic-already-deleted": "Sujet déjà supprimé", @@ -62,11 +63,12 @@ "signature-too-long": "La signature ne peut dépasser %1 caractères !", "cant-chat-with-yourself": "Vous ne pouvez chatter avec vous même !", "chat-restricted": "Cet utilisateur a restreint les ses messages de chat. Il doit d'abord vous suivre avant de pouvoir discuter avec lui.", + "too-many-messages": "Vous avez envoyé trop de messages, veuillez patienter un instant.", "reputation-system-disabled": "Le système de réputation est désactivé", "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", "not-enough-reputation-to-downvote": "Vous n'avez pas une réputation assez élevée pour noter négativement ce message", "not-enough-reputation-to-flag": "Vous n'avez pas une réputation assez élevée pour signaler ce message", "reload-failed": "NodeBB a rencontré un problème lors du rechargement : \"% 1\" . NodeBB continuera de fonctionner côté client, même si vous devez annuler ce que vous avez fait juste avant de recharger .", "registration-error": "Erreur d'enregistrement", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Une erreur est survenue en analysant la réponse du serveur" } \ No newline at end of file diff --git a/public/language/fr/global.json b/public/language/fr/global.json index 1937e5faad..bb53439c13 100644 --- a/public/language/fr/global.json +++ b/public/language/fr/global.json @@ -3,10 +3,10 @@ "search": "Recherche", "buttons.close": "Fermer", "403.title": "Accès refusé", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Il semble que vous ayez atteint une page dont vous n'avez pas accès.", + "403.login": "Peut-être deviez vous essayer de vous connecter?", "404.title": "Introuvable", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Il semble que vous ayez atteint une page qui n'existe pas. Retourner à la page d'accueil.", "500.title": "Erreur interne.", "500.message": "Oops ! Il semblerait que quelque chose se soit mal passé !", "register": "S'inscrire", @@ -27,7 +27,7 @@ "header.tags": "Tags", "header.popular": "Populaire", "header.users": "Utilisateurs", - "header.groups": "Groups", + "header.groups": "Groupes", "header.chats": "Chats", "header.notifications": "Notifications", "header.search": "Recherche", @@ -75,7 +75,7 @@ "updated.title": "Forum mis à jour", "updated.message": "Ce forum a été mis à jour à la dernière version. Cliquez ici pour recharger la page.", "privacy": "Vie privée", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "S'abonner", + "unfollow": "Se désabonner", "delete_all": "Supprimer Tout" } \ No newline at end of file diff --git a/public/language/fr/groups.json b/public/language/fr/groups.json index c61f42e068..d8c81570df 100644 --- a/public/language/fr/groups.json +++ b/public/language/fr/groups.json @@ -1,21 +1,23 @@ { "groups": "Groupes", "view_group": "Voir le groupe", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Propriétaire du Groupe", + "new_group": "Créer un Nouveau Groupe", + "no_groups_found": "Il n'y a aucun groupe", + "cover-instructions": "Glisser et Coller une image, ajuster la position, et cliquer sur Enregistrer", + "cover-change": "Modifier", + "cover-save": "Enregistrer", + "cover-saving": "Enregistrement", "details.title": "Informations du groupe", "details.members": "Liste des membres", - "details.pending": "Pending Members", - "details.has_no_posts": "Ce membre du groupe n'a envoyé aucun message.", + "details.pending": "Membres en attente", + "details.has_no_posts": "Les membres de ce groupe n'ont envoyé aucun message.", "details.latest_posts": "Derniers messages", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Groupe Privé", + "details.public": "Groupe Public", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Administration du Groupe", + "event.updated": "Les détails du groupe ont été mis à jour", + "event.deleted": "Le groupe é%1\" a été supprimé" } \ No newline at end of file diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index 1085bcfc21..7698a55986 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -11,6 +11,7 @@ "user.followers": "Personnes qui suivent %1", "user.posts": "Message écrit par %1", "user.topics": "Sujets créés par %1", + "user.groups": "Les Groupes de %1", "user.favourites": "Messages favoris de %1", "user.settings": "Préférences utilisateur", "maintenance.text": "%1 est en maintenance. Veuillez revenir un peu plus tard.", diff --git a/public/language/fr/recent.json b/public/language/fr/recent.json index f244b31c35..d2ee95b1b6 100644 --- a/public/language/fr/recent.json +++ b/public/language/fr/recent.json @@ -6,13 +6,13 @@ "year": "An", "alltime": "Toujours", "no_recent_topics": "Il n'y a aucun sujet récent.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Il y a un nouveau sujet.", + "there-is-a-new-topic-and-a-new-post": "Il y a un nouveau sujet et un nouveau message.", + "there-is-a-new-topic-and-new-posts": "Il y a un nouveau sujet et %1 nouveaux messages.", + "there-are-new-topics": "Il y a %1 nouveaux sujets.", + "there-are-new-topics-and-a-new-post": "Il y a %1 nouveaux sujets et un nouveau message.", + "there-are-new-topics-and-new-posts": "Il y a %1 nouveaux sujets et %2 nouveaux messages.", + "there-is-a-new-post": "Il y a un nouveau message.", + "there-are-new-posts": "Il y a %1 nouveaux messages.", + "click-here-to-reload": "Cliquer ici pour recharger." } \ No newline at end of file diff --git a/public/language/fr/reset_password.json b/public/language/fr/reset_password.json index 00e531a9c4..f21186c870 100644 --- a/public/language/fr/reset_password.json +++ b/public/language/fr/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Veuillez entrer votre adresse email pour recevoir un email contenant les instructions permettant de réinitialiser votre compte.", "enter_email_address": "Entrer votre adresse email", "password_reset_sent": "La demande de réinitialisation du mot de passe a bien été envoyée", - "invalid_email": "Email invalide / L'email n'existe pas !" + "invalid_email": "Email invalide / L'email n'existe pas !", + "password_too_short": "Le mot de passe est trop court, veuillez entre un mot de passe différent.", + "passwords_do_not_match": "Les deux mots de passe saisient ne correspondent pas." } \ No newline at end of file diff --git a/public/language/fr/search.json b/public/language/fr/search.json index 63e5537663..20e22d2fa0 100644 --- a/public/language/fr/search.json +++ b/public/language/fr/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 résultat(s) correspondant(s) à \"%2\", (%3 secondes)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "Aucune réponse trouvée", + "in": "Dans", + "by": "Par", + "titles": "Titres", + "titles-posts": "Titres et Messages", + "posted-by": "Posté par", + "in-categories": "Dans les catégories", + "search-child-categories": "Chercher les sous catégories", + "reply-count": "Nombre de réponses", + "at-least": "Au moins", + "at-most": "Au plus", + "post-time": "Date de message", + "newer-than": "Plus récent que", + "older-than": "Plus vieux que", + "any-date": "Toute date", + "yesterday": "Hier", + "one-week": "Une semaine", + "two-weeks": "Deux semaines", + "one-month": "Un mois", + "three-months": "Trois mois", + "six-months": "Six mois", + "one-year": "Un an", + "sort-by": "Trier par", + "last-reply-time": "Date de dernière réponse", + "topic-title": "Titre de sujet", + "number-of-replies": "Nombre de réponses", + "number-of-views": "Nombre de vues", + "topic-start-date": "Date de création du sujet", + "username": "Nom d'utilisateur", + "category": "Catgorie", + "descending": "Par ordre décroissant", + "ascending": "Par ordre croissant" } \ No newline at end of file diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index b20ef314eb..135efce878 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "Aucun post sélectionné !", "fork_success": "Sujet copié avec succès! Cliquez ici pour aller au sujet copié.", "composer.title_placeholder": "Entrer le titre du sujet ici ...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Nom", "composer.discard": "Abandonner", "composer.submit": "Envoyer", "composer.replying_to": "Réponse à %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "Du plus ancien au plus récent", "newest_to_oldest": "Du plus récent au plus ancien", "most_votes": "Les mieux notés", - "most_posts": "Most posts" + "most_posts": "Nombre de messages" } \ No newline at end of file diff --git a/public/language/fr/user.json b/public/language/fr/user.json index 83bb6f5d9e..d2cf37feec 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -2,8 +2,8 @@ "banned": "Banni", "offline": "Hors-ligne", "username": "Nom d'utilisateur", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Date d'Adhésion", + "postcount": "Nombre de Messages", "email": "Email", "confirm_email": "Confirmer l'adresse email", "delete_account": "Supprimer le compte", @@ -18,7 +18,7 @@ "profile_views": "Vues", "reputation": "Réputation", "favourites": "Favoris", - "watched": "Watched", + "watched": "Suivis", "followers": "Abonnés", "following": "Abonnements", "signature": "Signature", @@ -59,12 +59,12 @@ "digest_weekly": "Hebdomadaire", "digest_monthly": "Mensuel", "send_chat_notifications": "Envoyer un e-mail si un nouveau message de chat arrive lorsque je ne suis pas en ligne", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Envoyer un email lors de réponses envoyées aux sujets auxquels je suis abonné.", "has_no_follower": "Cet utilisateur n'est suivi par personne :(", "follows_no_one": "Cet utilisateur ne suit personne :(", "has_no_posts": "Ce membre n'a rien posté pour le moment", "has_no_topics": "L’utilisateur n'a pas encore créé de sujet.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Cet utilisateur ne suis encore aucun sujet.", "email_hidden": "Email masqué", "hidden": "masqué", "paginate_description": "Utiliser la pagination des sujets et des messages au lieu du défilement infini.", diff --git a/public/language/fr/users.json b/public/language/fr/users.json index 3cd259f2c5..1028292a9b 100644 --- a/public/language/fr/users.json +++ b/public/language/fr/users.json @@ -5,8 +5,8 @@ "search": "Rechercher", "enter_username": "Entrer un nom d'utilisateur pour rechercher", "load_more": "Charger la suite", - "users-found-search-took": "%1 utilisateur(s) trouvé(s) ! Recherche effectuée en %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 utilisateur(s) trouvé(s)! La recherche a pris %2 secondes.", + "filter-by": "Filtrer Par", + "online-only": "En Ligne uniquement", + "picture-only": "Avec Image uniquement" } \ No newline at end of file diff --git a/public/language/he/category.json b/public/language/he/category.json index bc5e530729..86292076b6 100644 --- a/public/language/he/category.json +++ b/public/language/he/category.json @@ -4,5 +4,5 @@ "browsing": "צופים בנושא זה כעת", "no_replies": "אין תגובות", "share_this_category": "שתף קטגוריה זו", - "ignore": "Ignore" + "ignore": "התעלם" } \ No newline at end of file diff --git a/public/language/he/email.json b/public/language/he/email.json index e3199a9b14..8743ba21d8 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -1,25 +1,28 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.no_topics": "There have been no active topics in the past %1", - "notif.chat.subject": "New chat message received from %1", - "notif.chat.cta": "Click here to continue the conversation", - "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "unsub.cta": "Click here to alter those settings", - "closing": "Thanks!" + "password-reset-requested": "בקשת איפוס הסיסמה נשלחה - %1!", + "welcome-to": "ברוכים הבאים ל%1", + "greeting_no_name": "שלום", + "greeting_with_name": "שלום %1", + "welcome.text1": "תודה שנרשמת ל%1!", + "welcome.text2": "על מנת להפעיל את החשבון שלך, אנו צריכים לוודא שאתה בעל חשבון המייל שנרשמת איתו.", + "welcome.cta": "לחץ כאן על מנת לאשר את כתובת המייל שלך.", + "reset.text1": "קיבלנו בקשה לאפס את הסיסמה לחשבון שלך, כנראה מפני ששכחת אותה. אם לא ביקשת לאפס את הסיסמה, אנא התעלם ממייל זה.", + "reset.text2": "על מנת להמשיך עם תהליך איפוס הסיסמה, אנא לחץ על הלינק הבא:", + "reset.cta": "לחץ כאן לאפס את הסיסמה שלך.", + "reset.notify.subject": "הסיסמה שונתה בהצלחה.", + "reset.notify.text1": "אנו מודיעים לך שב%1, סיסמתך שונתה בהצלחה.", + "reset.notify.text2": "אם לא אישרת בקשה זו, אנא הודע למנהל מיד.", + "digest.notifications": "יש לך התראה שלא נקראה מ%1:", + "digest.latest_topics": "נושאים אחרונים מ%1", + "digest.cta": "לחץ כאן כדי לבקר ב %1", + "digest.unsub.info": "תקציר זה נשלח אליך על-פי הגדרות החשבון שלך.", + "digest.no_topics": "אין נושאים פעילים ב%1 האחרון/ים", + "notif.chat.subject": "הודעת צ'אט חדשה התקבלה מ%1", + "notif.chat.cta": "לחץ כאן כדי להמשיך את השיחה", + "notif.chat.unsub.info": "התראה הצ'אט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", + "notif.post.cta": "לחץ כאן בשביל לקרוא את כל הנושא", + "notif.post.unsub.info": "התראת הפוסט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", + "test.text1": "זהו אימייל ניסיון על מנת לוודא שהגדרות המייל בוצעו כהלכה בהגדרות NodeBB.", + "unsub.cta": "לחץ כאן לשנות הגדרות אלו", + "closing": "תודה!" } \ No newline at end of file diff --git a/public/language/he/error.json b/public/language/he/error.json index 28483df65e..23d21ee1ae 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -12,61 +12,63 @@ "invalid-title": "כותרת שגויה", "invalid-user-data": "מידע משתמש שגוי", "invalid-password": "סיסמא שגויה", - "invalid-username-or-password": "Please specify both a username and password", - "invalid-search-term": "Invalid search term", + "invalid-username-or-password": "אנא הגדר שם משתמש וסיסמה", + "invalid-search-term": "מילת חיפוש לא תקינה", "invalid-pagination-value": "ערך דפדוף שגוי", "username-taken": "שם משתמש תפוס", "email-taken": "כתובת אימייל תפוסה", - "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed": "כתובת המייל שלך עוד לא אושרה, לחץ כאן על-מנת לאשר את המייל שלך.", + "email-not-confirmed-chat": "לא תוכל לדבר בצ'אט עד שלא תאשר את כתובת המייל שלך", "username-too-short": "שם משתמש קצר מדי", - "username-too-long": "Username too long", + "username-too-long": "שם משתמש ארוך מדי", "user-banned": "המשתמש חסום", - "user-too-new": "Sorry, you are required to wait %1 seconds before making your first post", - "no-category": "Category does not exist", - "no-topic": "Topic does not exist", - "no-post": "Post does not exist", - "no-group": "Group does not exist", - "no-user": "User does not exist", - "no-teaser": "Teaser does not exist", - "no-privileges": "You do not have enough privileges for this action.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "user-too-new": "מצטערים, אתה צריך לחכות %1 שניות לפני שתוכל לפרסם את הפוסט הראשון שלך", + "no-category": "קטגוריה אינה קיימת", + "no-topic": "נושא אינו קיים", + "no-post": "פוסט אינו קיים", + "no-group": "קבוצה אינה קיימת", + "no-user": "משתמש אינו קיים", + "no-teaser": "תקציר אינו קיים", + "no-privileges": "ההרשאות שלך אינן מספיקות לביצוע פעולה זו", + "no-emailers-configured": "לא נמצאו פלאגינים למייל, לכן אין אפשרות לשלוח מייל ניסיון.", "category-disabled": "קטגוריה לא פעילה", "topic-locked": "נושא נעול", "still-uploading": "אנא המתן לסיום ההעלאות", - "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", - "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", + "content-too-short": "יש להכניס פוסט ארוך יותר. פוסטים חייבים להכיל לפחות %1 תווים.", + "content-too-long": "יש לקצר את הפוסט. פוסטים אינם יכולים להיות ארוכים מ %1 תווים.", + "title-too-short": "יש להכניס כותרת ארוכה יותר. כותרות חייבות להכיל לפחות %1 תווים.", "title-too-long": "יש לקצר את הכותרת. כותרות אינן יכולות להיות ארוכות מ %1 תווים.", - "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", - "too-many-posts-newbie": "As a new user, you can only post once every %1 seconds until you have earned %2 reputation - please wait before posting again", - "file-too-big": "Maximum allowed file size is %1 kbs - please upload a smaller file", + "too-many-posts": "אתה יכול להעלות פוסט כל %1 שניות בלבד - אנא המתן.", + "too-many-posts-newbie": "כמשתמש חדש, אתה יכול להעלות פוסט כל %1 שניות עד שצברת %2 מוניטין - אנא המתן.", + "file-too-big": "גודל קובץ מקסימלי הינו %1 קילובייט - אנא העלה קובץ קטן יותר.", "cant-vote-self-post": "לא ניתן להצביע לפוסט שלך", - "already-favourited": "You have already favourited this post", - "already-unfavourited": "You have already unfavourited this post", + "already-favourited": "כבר הוספת פוסט זה למועדפים", + "already-unfavourited": "כבר הסרת פוסט זה מהמועדפים", "cant-ban-other-admins": "אינך יכול לחסום מנהלים אחרים!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "פורמט תמונה לא תקין. הפורמטים המורשים הם: %1", + "invalid-image-extension": "פורמט תמונה לא תקין", "group-name-too-short": "שם הקבוצה קצר מדי", "group-already-exists": "הקבוצה כבר קיימת", "group-name-change-not-allowed": "לא ניתן לשנות את שם הקבוצה", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", - "post-already-deleted": "This post has already been deleted", - "post-already-restored": "This post has already been restored", - "topic-already-deleted": "This topic has already been deleted", - "topic-already-restored": "This topic has already been restored", + "group-already-member": "אתה כבר חבר בקבוצה זו", + "group-needs-owner": "קבוצה זו חייבת לפחות מנהל אחד", + "post-already-deleted": "פוסט זה כבר נמחק", + "post-already-restored": "פוסט זה כבר שוחזר", + "topic-already-deleted": "נושא זה כבר נמחק", + "topic-already-restored": "נושא זה כבר שוחזר", "topic-thumbnails-are-disabled": "תמונות ממוזערות לנושא אינן מאופשרות.", "invalid-file": "קובץ לא תקין", "uploads-are-disabled": "העלאת קבצים אינה מאופשרת", "upload-error": "שגיאה בהעלאה : %1", - "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", + "signature-too-long": "מצטערים, אורך החתימה המקסימלי הוא %1 תווים.", "cant-chat-with-yourself": "לא ניתן לעשות צ'אט עם עצמך!", - "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", - "reputation-system-disabled": "Reputation system is disabled.", - "downvoting-disabled": "Downvoting is disabled", + "chat-restricted": "משתמש זה חסם את הודעות הצ'אט שלו ממשתמשים זרים. המשתמש חייב לעקוב אחריך לפני שתוכל לשוחח איתו בצ'אט", + "too-many-messages": "שלחת יותר מדי הודעות, אנא המתן לזמן מה.", + "reputation-system-disabled": "מערכת המוניטין לא פעילה.", + "downvoting-disabled": "היכולת להצביע נגד לא פעילה", "not-enough-reputation-to-downvote": "אין לך מספיק מוניטין כדי להוריד את הדירוג של פוסט זה", - "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", - "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", - "registration-error": "Registration Error", - "parse-error": "Something went wrong while parsing server response" + "not-enough-reputation-to-flag": "אין לך מוניטין מספק על מנת לסמן את הפוסט הזה", + "reload-failed": "אירעה תקלה ב NodeBB בזמן הטעינה של: \"%1\". המערכת תמשיך להגיש דפים קיימים, אבל כדאי שתשחזר את הפעולות שלך מהפעם האחרונה שהמערכת עבדה כראוי.", + "registration-error": "שגיאה בהרשמה", + "parse-error": "אירעה שגיאה בעת בעת ניתוח תגובת השרת" } \ No newline at end of file diff --git a/public/language/he/global.json b/public/language/he/global.json index 7a5d014492..da7f284644 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -3,10 +3,10 @@ "search": "חיפוש", "buttons.close": "סגור", "403.title": "גישה נדחתה", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "נראה שהגעת לעמוד שאין לך הרשאה לצפות בו", + "403.login": "נסה להתחבר.", "404.title": "לא נמצא", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "נראה שהגעת לעמוד שלא קיים. חזור לעמוד הבית", "500.title": "שגיאה פנימית.", "500.message": "אופס! נראה שמשהו השתבש!", "register": "הרשמה", @@ -27,7 +27,7 @@ "header.tags": "תגיות", "header.popular": "פופולרי", "header.users": "משתמשים", - "header.groups": "Groups", + "header.groups": "קבוצות", "header.chats": "צ'אטים", "header.notifications": "התראות", "header.search": "חיפוש", @@ -74,8 +74,8 @@ "guests": "אורחים", "updated.title": "הפורום עודכן", "updated.message": "הפורום עודכן לגרסא האחרונה. נא ללחוץ כאן לעדכון הדף.", - "privacy": "Privacy", - "follow": "Follow", - "unfollow": "Unfollow", - "delete_all": "Delete All" + "privacy": "פרטיות", + "follow": "עקוב", + "unfollow": "הפסק לעקוב", + "delete_all": "מחק הכל" } \ No newline at end of file diff --git a/public/language/he/groups.json b/public/language/he/groups.json index 6dfd71256b..6754a5611c 100644 --- a/public/language/he/groups.json +++ b/public/language/he/groups.json @@ -1,21 +1,23 @@ { - "groups": "Groups", - "view_group": "View Group", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", - "details.title": "Group Details", - "details.members": "Member List", - "details.pending": "Pending Members", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "groups": "קבוצות", + "view_group": "צפה בקבוצה", + "owner": "מנהל הקבוצה", + "new_group": "צור קבוצה חדשה", + "no_groups_found": "אין קבוצות לצפייה", + "cover-instructions": "גרור תמונה, הזז למיקום הרצוי ואז לחץ על שמור", + "cover-change": "שנה", + "cover-save": "שמור", + "cover-saving": "שומר", + "details.title": "פרטי הקבוצה", + "details.members": "רשימת חברי הקבוצה", + "details.pending": "חברי קבוצה הממתינים לאישור", + "details.has_no_posts": "חברי הקבוצה הזו לא העלו אף פוסט.", + "details.latest_posts": "פוסטים אחרונים", + "details.private": "קבוצה פרטית", + "details.public": "קבוצה פומבית", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "ניהול הקבוצה", + "event.updated": "פרטי הקבוצה עודכנו", + "event.deleted": "קבוצת \"%1\" נמחקה" } \ No newline at end of file diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 521915ec96..43bf264e7b 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -1,20 +1,20 @@ { "chat.chatting_with": "שוחח עם ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "הקלד את הודעת הצ'אט כאן, לחץ אנטר לשליחה", "chat.send": "שלח", "chat.no_active": "אין לך צ'אטים פעילים", "chat.user_typing": "%1 מקליד ...", "chat.user_has_messaged_you": "ל%1 יש הודעה עבורך.", "chat.see_all": "צפה בכל הצ'אטים", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", - "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", - "chat.seven_days": "7 Days", - "chat.thirty_days": "30 Days", - "chat.three_months": "3 Months", + "chat.no-messages": "אנא בחר נמען על מנת לראות את היסטוריית הצ'אט איתו", + "chat.recent-chats": "צ'אטים אחרונים", + "chat.contacts": "אנשי קשר", + "chat.message-history": "היסטוריית הודעות", + "chat.pop-out": "הוצא את חלון הצ'אט", + "chat.maximize": "הרחב", + "chat.seven_days": "7 ימים", + "chat.thirty_days": "30 ימים", + "chat.three_months": "3 חודשים", "composer.user_said_in": "%1 אמר ב%2:", "composer.user_said": "%1 אמר:", "composer.discard": "האם למחוק פוסט זה?" diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index 9bc2d9c5d8..515b890810 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -2,26 +2,26 @@ "title": "התראות", "no_notifs": "אין התראות", "see_all": "צפה בכל ההתראות", - "back_to_home": "Back to %1", + "back_to_home": "חזרה ל%1", "outgoing_link": "לינק", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", - "new_notification": "New Notification", - "you_have_unread_notifications": "You have unread notifications.", - "new_message_from": "New message from %1", - "upvoted_your_post_in": "%1 has upvoted your post in %2.", - "moved_your_post": "%1 has moved your post.", - "moved_your_topic": "%1 has moved your topic.", - "favourited_your_post_in": "%1 has favourited your post in %2.", - "user_flagged_post_in": "%1 flagged a post in %2", - "user_posted_to": "%1 has posted a reply to: %2", - "user_posted_topic": "%1 has posted a new topic: %2", - "user_mentioned_you_in": "%1 mentioned you in %2", - "user_started_following_you": "%1 started following you.", - "email-confirmed": "Email Confirmed", - "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", - "email-confirm-error": "An error occurred...", - "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "outgoing_link_message": "אתה כעת עוזב את %1.", + "continue_to": "המשך ל %1", + "return_to": "חזור ל %1", + "new_notification": "התראה חדשה", + "you_have_unread_notifications": "יש לך התראות שלא נקראו.", + "new_message_from": "הודעה חדשה מ %1", + "upvoted_your_post_in": "%1 הצביע בעד הפוסט שלך ב %2", + "moved_your_post": "%1 העביר את הפוסט שלך.", + "moved_your_topic": "%1 הזיז את הנושא שלך.", + "favourited_your_post_in": "%1 הוסיף את הפוסט שלך ב %2 למועדפים שלו.", + "user_flagged_post_in": "%1 דיווח על פוסט ב %2", + "user_posted_to": "%1 פרסם תגובה ל: %2", + "user_posted_topic": "%1 העלה נושא חדש: %2", + "user_mentioned_you_in": "%1 הזכיר אותך ב %2", + "user_started_following_you": "%1 התחיל לעקוב אחריך.", + "email-confirmed": "כתובת המייל אושרה", + "email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.", + "email-confirm-error": "אירעה שגיאה...", + "email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.", + "email-confirm-sent": "מייל אישור נשלח." } \ No newline at end of file diff --git a/public/language/he/pages.json b/public/language/he/pages.json index 46544cf924..aaeb1fcac5 100644 --- a/public/language/he/pages.json +++ b/public/language/he/pages.json @@ -5,14 +5,15 @@ "recent": "נושאים אחרונים", "users": "משתמשים רשומים", "notifications": "התראות", - "tags": "Topics tagged under \"%1\"", + "tags": "נושאים שתויגו תחת \"%1\"", "user.edit": "עורך את %1", "user.following": "אנשים ש%1 עוקב אחריהם", "user.followers": "אנשים שעוקבים אחרי %1", "user.posts": "פוסטים שהועלו על ידי %1", "user.topics": "נושאים שנוצרו על ידי %1", + "user.groups": "הקבוצות של %1", "user.favourites": "הפוסטים המועדפים על %1", "user.settings": "הגדרות משתמש", - "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", - "maintenance.messageIntro": "Additionally, the administrator has left this message:" + "maintenance.text": "%1 כרגע תחת עבודות תחזוקה. אנא חזור בזמן מאוחר יותר.", + "maintenance.messageIntro": "בנוסף, המנהל השאיר את ההודעה הזו:" } \ No newline at end of file diff --git a/public/language/he/recent.json b/public/language/he/recent.json index 6e1cd5f811..44960c78f7 100644 --- a/public/language/he/recent.json +++ b/public/language/he/recent.json @@ -3,16 +3,16 @@ "day": "יום", "week": "שבוע", "month": "חודש", - "year": "Year", - "alltime": "All Time", + "year": "שנה", + "alltime": "כל הזמן", "no_recent_topics": "אין נושאים חדשים", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "יש נושא חדש.", + "there-is-a-new-topic-and-a-new-post": "יש נושא ופוסט חדש.", + "there-is-a-new-topic-and-new-posts": "יש נושא ו%1 פוסטים חדשים.", + "there-are-new-topics": "יש %1 נושאים חדשים.", + "there-are-new-topics-and-a-new-post": "יש %1 נושאים ופוסט חדש.", + "there-are-new-topics-and-new-posts": "יש %1 נושאים ו %2 פוסטים חדשים.", + "there-is-a-new-post": "יש פוסט חדש.", + "there-are-new-posts": "יש %1 פוסטים חדשים.", + "click-here-to-reload": "לחץ כאן על מנת לטעון מחדש." } \ No newline at end of file diff --git a/public/language/he/reset_password.json b/public/language/he/reset_password.json index 7aa44652cd..2ed1435b18 100644 --- a/public/language/he/reset_password.json +++ b/public/language/he/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "אנא הקלד את כתובת האימייל שלך ואנו נשלח לך הוראות כיצד לאפס את חשבונך", "enter_email_address": "הכנס כתובת אימייל", "password_reset_sent": "קוד איפוס סיסמה נשלח", - "invalid_email": "מייל שגוי / כתובת מייל לא נמצאה" + "invalid_email": "מייל שגוי / כתובת מייל לא נמצאה", + "password_too_short": "הסיסמה שבחרת קצרה מדי, אנא בחר סיסמה שונה.", + "passwords_do_not_match": "הסיסמאות שהזנת אינן תואמות." } \ No newline at end of file diff --git a/public/language/he/search.json b/public/language/he/search.json index c89241d382..fec789c3be 100644 --- a/public/language/he/search.json +++ b/public/language/he/search.json @@ -1,7 +1,35 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "results_matching": "נמצאו %1 תוצאות עבור החיפוש \"%2\", (%3 שניות)", + "no-matches": "לא נמצאו תוצאות", + "in": "ב", + "by": "על ידי", + "titles": "כותרות", + "titles-posts": "כותרות ופוסטים", + "posted-by": "פורסם על-ידי", + "in-categories": "בקטגוריות", + "search-child-categories": "חפש בתת קטגוריות", + "reply-count": "כמות תגובות", + "at-least": "לפחות", + "at-most": "לכל היותר", + "post-time": "זמן הפוסט", + "newer-than": "חדש מ", + "older-than": "ישן מ", + "any-date": "כל תאריך", + "yesterday": "אתמול", + "one-week": "שבוע אחד", + "two-weeks": "שבועיים", + "one-month": "חודש אחד", + "three-months": "שלושה חודשים", + "six-months": "שישה חודשים", + "one-year": "שנה אחת", + "sort-by": "סדר על-פי", + "last-reply-time": "תאריך תגובה אחרון", + "topic-title": "כותרת הנושא", + "number-of-replies": "מספר התגובות", + "number-of-views": "מספר הצפיות", + "topic-start-date": "זמן תחילת הנושא", + "username": "שם משתמש", + "category": "קטגוריה", + "descending": "בסדר יורד", + "ascending": "בסדר עולה" } \ No newline at end of file diff --git a/public/language/he/tags.json b/public/language/he/tags.json index 94d002603f..13912500cb 100644 --- a/public/language/he/tags.json +++ b/public/language/he/tags.json @@ -2,6 +2,6 @@ "no_tag_topics": "אין פוסטים עם תגית זו.", "tags": "תגיות", "enter_tags_here": "יש להכניס כאן את התגיות. לחץ אנטר אחרי כל תגית.", - "enter_tags_here_short": "Enter tags...", + "enter_tags_here_short": "הכנס תגיות", "no_tags": "אין עדיין תגיות." } \ No newline at end of file diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 2e0d4a0d2e..e16ebc08cf 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -1,61 +1,61 @@ { "topic": "נושא", - "topic_id": "Topic ID", - "topic_id_placeholder": "Enter topic ID", + "topic_id": "מזהה נושא", + "topic_id_placeholder": "הכנס מזהה נושא", "no_topics_found": "לא נמצאו נושאים!", "no_posts_found": "לא נמצאו פוסטים!", - "post_is_deleted": "This post is deleted!", + "post_is_deleted": "פוסט זה נמחק!", "profile": "פרופיל", "posted_by": "הפוסט הועלה על ידי %1", - "posted_by_guest": "Posted by Guest", + "posted_by_guest": "פורסם על-ידי אורח", "chat": "צ'אט", "notify_me": "קבל התראה כאשר יש תגובות חדשות בנושא זה", "quote": "ציטוט", "reply": "תגובה", "edit": "עריכה", "delete": "מחק", - "purge": "Purge", - "restore": "Restore", + "purge": "מחק הכל", + "restore": "שחזר", "move": "הזז", "fork": "פורק", "link": "לינק", "share": "Share", "tools": "כלים", "flag": "דווח", - "locked": "Locked", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "locked": "נעול", + "bookmark_instructions": "לחץ כאן על-מנת לחזור למיקום האחרון או סגור למחיקה.", "flag_title": "דווח על פוסט זה למנהל", - "flag_confirm": "Are you sure you want to flag this post?", - "flag_success": "This post has been flagged for moderation.", - "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", + "flag_confirm": "אתה בטוח שאתה רוצה לדווח על הפוסט הזה?", + "flag_success": "התקבל דיווח על פוסט זה.", + "deleted_message": "נושא זה נמחק. רק משתמשים עם ההרשאות המתאימות יכולים לצפות בו.", "following_topic.message": "מעתה, תקבל הודעות כאשר מישהו יעלה פוסט לנושא זה.", "not_following_topic.message": "לא תקבל הודעות נוספות בנושא זה.", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", + "login_to_subscribe": "אנא הרשם או התחבר על-מנת לעקוב אחר נושא זה.", + "markAsUnreadForAll.success": "נושא זה סומן כלא נקרא לכולם.", "watch": "עקוב", - "unwatch": "Unwatch", - "watch.title": "Be notified of new replies in this topic", - "unwatch.title": "Stop watching this topic", + "unwatch": "הפסק לעקוב", + "watch.title": "קבל התראה כאשר יש תגובות חדשות בנושא זה", + "unwatch.title": "הפסק לעקוב אחר נושא זה", "share_this_post": "שתף פוסט זה", - "thread_tools.title": "Topic Tools", + "thread_tools.title": "כלי נושא", "thread_tools.markAsUnreadForAll": "סמן כלא נקרא", "thread_tools.pin": "נעץ נושא", "thread_tools.unpin": "הסר נעץ", "thread_tools.lock": "נעל נושא", "thread_tools.unlock": "הסר נעילה", "thread_tools.move": "הזז נושא", - "thread_tools.move_all": "Move All", + "thread_tools.move_all": "הזז הכל", "thread_tools.fork": "שכפל נושא", "thread_tools.delete": "מחק נושא", - "thread_tools.delete_confirm": "Are you sure you want to delete this topic?", + "thread_tools.delete_confirm": "אתה בטוח שאתה רוצה למחוק את הנושא הזה?", "thread_tools.restore": "שחזר נושא", - "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", - "thread_tools.purge": "Purge Topic", - "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", - "topic_move_success": "This topic has been successfully moved to %1", - "post_delete_confirm": "Are you sure you want to delete this post?", - "post_restore_confirm": "Are you sure you want to restore this post?", - "post_purge_confirm": "Are you sure you want to purge this post?", + "thread_tools.restore_confirm": "אתה בטוח שאתה רוצה לשחזר את הנושא הזה?", + "thread_tools.purge": "מחק נושא", + "thread_tools.purge_confirm": "אתה בטוח שאתה רוצה למחוק את הנושא הזה?", + "topic_move_success": "נושא זה הועבר בהצלחה ל %1", + "post_delete_confirm": "אתה בטוח שאתה רוצה למחוק את הפוסט הזה?", + "post_restore_confirm": "אתה בטוח שאתה רוצה לשחזר את הפוסט הזה?", + "post_purge_confirm": "אתה בטוח שאתה רוצה למחוק את הפוסט הזה?", "load_categories": "טוען קטגוריות", "disabled_categories_note": "קטגוריות מבוטלות צבועות באפור", "confirm_move": "הזז", @@ -65,34 +65,34 @@ "favourites.has_no_favourites": "אין לך כרגע פוסטים מועדפים, סמן מספר פוסטים כמועדפים על מנת לראות אותם כאן!", "loading_more_posts": "טוען פוסטים נוספים", "move_topic": "הזז נושא", - "move_topics": "Move Topics", + "move_topics": "הזז נושאים", "move_post": "הזז פוסט", - "post_moved": "Post moved!", + "post_moved": "הפוסט הועבר!", "fork_topic": "שכפל נושא", "topic_will_be_moved_to": "נושא זה יועבר לקטגוריה", "fork_topic_instruction": "לחץ על הפוסטים שברצונך לשכפל", "fork_no_pids": "לא בחרת אף פוסט!", - "fork_success": "Successfully forked topic! Click here to go to the forked topic.", + "fork_success": "הפוסט שוכפל בהצלחה! לחץ כאן על מנת לעבור לפוסט המשוכפל.", "composer.title_placeholder": "הכנס את כותרת הנושא כאן...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "שם", "composer.discard": "מחק", "composer.submit": "שלח", - "composer.replying_to": "Replying to %1", + "composer.replying_to": "מגיב ל %1", "composer.new_topic": "נושא חדש", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", + "composer.uploading": "מעלה...", + "composer.thumb_url_label": "הדבק את כתובת ה URL לתמונה המוקטנת עבור הנושא", + "composer.thumb_title": "הוסף תמונה מוקטנת לנושא זה", "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", - "composer.drag_and_drop_images": "Drag and Drop Images Here", - "more_users_and_guests": "%1 more user(s) and %2 guest(s)", - "more_users": "%1 more user(s)", - "more_guests": "%1 more guest(s)", - "users_and_others": "%1 and %2 others", - "sort_by": "Sort by", - "oldest_to_newest": "Oldest to Newest", - "newest_to_oldest": "Newest to Oldest", - "most_votes": "Most votes", - "most_posts": "Most posts" + "composer.thumb_file_label": "או העלה קובץ", + "composer.thumb_remove": "נקה שדות", + "composer.drag_and_drop_images": "גרור תמונות לכאן", + "more_users_and_guests": "%1 משתמשים ו%2 אורחים נוספים", + "more_users": "%1 משתמשים נוספים", + "more_guests": "%1 אורחים נוספים", + "users_and_others": "%1 ו%2 אחרים", + "sort_by": "סדר על-פי", + "oldest_to_newest": "מהישן לחדש", + "newest_to_oldest": "מהחדש לישן", + "most_votes": "הכי הרבה הצבעות", + "most_posts": "הכי הרבה פוסטים" } \ No newline at end of file diff --git a/public/language/he/user.json b/public/language/he/user.json index ec3d0e5b7a..e8b3a5d3a7 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -2,12 +2,12 @@ "banned": "מורחק", "offline": "לא מחובר", "username": "שם משתמש", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "תאריך הצטרפות", + "postcount": "כמות פוסטים", "email": "כתובת אימייל", - "confirm_email": "Confirm Email", - "delete_account": "Delete Account", - "delete_account_confirm": "Are you sure you want to delete your account?
This action is irreversible and you will not be able to recover any of your data

Enter your username to confirm that you wish to destroy this account.", + "confirm_email": "אשר מייל", + "delete_account": "מחק חשבון", + "delete_account_confirm": "אתה בטוח שאתה רוצה למחוק את חשבונך?
פעולה זו לא ניתנת לשחזור ולא תוכל לגשת למידע שלך

הזן את שם המשתמש שלך על מנת לאשר שברצונך למחוק את חשבונך.", "fullname": "שם מלא", "website": "אתר", "location": "מיקום", @@ -18,7 +18,7 @@ "profile_views": "צפיות בפרופיל", "reputation": "מוניטין", "favourites": "מועדפים", - "watched": "Watched", + "watched": "נצפה", "followers": "עוקבים", "following": "עוקב אחרי", "signature": "חתימה", @@ -32,7 +32,7 @@ "edit": "ערוך", "uploaded_picture": "התמונה הועלתה", "upload_new_picture": "העלה תמונה חדשה", - "upload_new_picture_from_url": "Upload New Picture From URL", + "upload_new_picture_from_url": "העלה תמונה חדשה מ URL", "current_password": "סיסמה נוכחית", "change_password": "שנה סיסמה", "change_password_error": "סיסמה אינה תקינה!", @@ -43,28 +43,28 @@ "change_password_success": "הסיסמה שלך עודכנה!", "confirm_password": "אמת סיסמה", "password": "סיסמה", - "username_taken_workaround": "The username you requested was already taken, so we have altered it slightly. You are now known as %1", + "username_taken_workaround": "שם המשתמש שבחרת כבר תפוס, אז שינינו אותו מעט. שם המשתמש שלך כעת הוא %1", "upload_picture": "העלה תמונה", "upload_a_picture": "העלה תמונה", "image_spec": "ניתן להעלות תמונות בפורמט PNG, JPG או GIF בלבד", "max": "מקסימום", "settings": "הגדרות", "show_email": "פרסם את כתובת האימייל שלי", - "show_fullname": "Show My Full Name", - "restrict_chats": "Only allow chat messages from users I follow", - "digest_label": "Subscribe to Digest", - "digest_description": "Subscribe to email updates for this forum (new notifications and topics) according to a set schedule", - "digest_off": "Off", + "show_fullname": "הצג את שמי המלא", + "restrict_chats": "אשר הודעות צ'אט ממשתמשים שאני עוקב אחריהם בלבד", + "digest_label": "הרשם לקבלת תקציר", + "digest_description": "הרשם לקבלת עדכונים מפורום זה (התראות ונושאים חדשים) על-פי לוח זמנים קבוע מראש.", + "digest_off": "כבוי", "digest_daily": "יומי", "digest_weekly": "שבועי", "digest_monthly": "חודשי", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_chat_notifications": "שלח לי הודעה למייל כאשר הודעת צ'אט נשלחה אלי בזמן שאיני מחובר", + "send_post_notifications": "שלח לי הודעה למייל כאשר תגובות חדשות פורסמו לנושאים שאני עוקב אחריהם", "has_no_follower": "למשתמש זה אין עוקבים :(", "follows_no_one": "משתמש זה אינו עוקב אחרי אחרים :(", "has_no_posts": "המשתמש הזה עוד לא פרסם כלום.", "has_no_topics": "המשתמש טרם יצר נושאים כלשהם.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "משתמש זה לא עקב אחרי אף נושא עדיין.", "email_hidden": "כתובת אימייל מוסתרת", "hidden": "מוסתר", "paginate_description": "צור עימוד לנושאים במקום לטעון את כל התוכן בעמוד אחד.", @@ -72,9 +72,9 @@ "posts_per_page": "כמות פוסטים בעמוד", "notification_sounds": "השמע צליל כאשר מתקבלת הודעה עבורך.", "browsing": "הגדרות צפייה", - "open_links_in_new_tab": "Open outgoing links in new tab?", - "enable_topic_searching": "Enable In-Topic Searching", - "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", - "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "open_links_in_new_tab": "פתח לינקים חיצוניים בטאב חדש?", + "enable_topic_searching": "הפעל חיפוש בתוך נושא", + "topic_search_help": "אם מופעל, חיפוש בתוך נושא יעקוף את מנגנון החיפוש הרגיל של הדפדפן שלך על מנת לאפשר לך לחפש בתוך כל הנושא ולא רק מה שמוצג כרגע בעמוד.", + "follow_topics_you_reply_to": "עקוב אחר נושאים שהגבת עליהם.", + "follow_topics_you_create": "עקוב אחר נושאים שיצרת." } \ No newline at end of file diff --git a/public/language/he/users.json b/public/language/he/users.json index c37d6e3609..5b996d5f5d 100644 --- a/public/language/he/users.json +++ b/public/language/he/users.json @@ -5,8 +5,8 @@ "search": "חיפוש", "enter_username": "הכנס שם משתמש לחיפוש", "load_more": "טען עוד", - "users-found-search-took": "נמצאו %1 משתמש(ים)! החיפוש ארך %2 מילי שניות.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 משתמשים נמצאו! החיפוש ערך %2 שניות.", + "filter-by": "פלטר על-פי", + "online-only": "אונליין בלבד", + "picture-only": "תמונה בלבד" } \ No newline at end of file diff --git a/public/language/hu/email.json b/public/language/hu/email.json index eaf8595c79..8430b8ff27 100644 --- a/public/language/hu/email.json +++ b/public/language/hu/email.json @@ -9,6 +9,9 @@ "reset.text1": "Kaptunk egy kérést jelszava visszaállításához, valószínűleg azért, mert elfelejtette azt. Ha ez nem így van, hagyja figyelmen kívül ezt a levelet.", "reset.text2": "Ha szeretné, hogy továbbra alaphelyzetbe a jelszavát, kérjük kattintson az alábbi linkre:", "reset.cta": "Kattints ide a jelszavad visszaállításához", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Olvasatlan értesítéseid vannak a következőtől: %1", "digest.latest_topics": "Legutóbbi témák a következőből: %1", "digest.cta": "Kattints ide, hogy meglátogasd a következőt: %1", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index c0bab322ee..821145775e 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -35,6 +35,7 @@ "topic-locked": "Téma lezárva", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sajnáljuk, az aláírás nem lehet hosszabb %1 karakternél.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/hu/groups.json b/public/language/hu/groups.json index 3d8cddf1c1..09324055a0 100644 --- a/public/language/hu/groups.json +++ b/public/language/hu/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Legújabb bejegyzések", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/hu/pages.json b/public/language/hu/pages.json index 9dfa18ac9a..f8d1c20484 100644 --- a/public/language/hu/pages.json +++ b/public/language/hu/pages.json @@ -11,6 +11,7 @@ "user.followers": "Tagok akik követik %1 -t", "user.posts": "Hozzászólások által %1", "user.topics": "%1 által létrehozott témák", + "user.groups": "%1's Groups", "user.favourites": "%1 Kedvenc Hozzászólásai", "user.settings": "Felhasználói Beállítások", "maintenance.text": "%1 jelenleg karbantartás alatt van. Kérlek nézz vissza késöbb!", diff --git a/public/language/hu/reset_password.json b/public/language/hu/reset_password.json index d0efcfda44..3f5721d6d6 100644 --- a/public/language/hu/reset_password.json +++ b/public/language/hu/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Kérlek add meg az e-mail címedet, ahová elküldjük a további teendőket a jelszavad visszaállításával kapcsolatban.", "enter_email_address": "Email cím megadása", "password_reset_sent": "Jelszó-visszaállítás elküldve", - "invalid_email": "Helytelen E-mail cím / Nem létező E-mail cím!" + "invalid_email": "Helytelen E-mail cím / Nem létező E-mail cím!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/hu/search.json b/public/language/hu/search.json index f5df223660..6cae8bb926 100644 --- a/public/language/hu/search.json +++ b/public/language/hu/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/hu/users.json b/public/language/hu/users.json index 2f992c73b2..95e721a4d7 100644 --- a/public/language/hu/users.json +++ b/public/language/hu/users.json @@ -5,7 +5,7 @@ "search": "Keresés", "enter_username": "Írj be egy nicknevet a kereséshez", "load_more": "Több betöltése", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/id/email.json b/public/language/id/email.json index 86557a5832..481f412f23 100644 --- a/public/language/id/email.json +++ b/public/language/id/email.json @@ -9,6 +9,9 @@ "reset.text1": "Kami menerima permintan untuk mengatur ulang kata sandi anda, Ini dikarenakan anda telah lupa akan kata sandi anda. Tolong abaikan email ini jika sebaliknya.", "reset.text2": "Mohon klik link berikut untuk mengatur ulang kata sandi anda.", "reset.cta": "Klik di sini untuk mengatur ulang kata sandi anda", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Anda mempunyai notifikasi yang belum terbaca dari %1:", "digest.latest_topics": "Topik-topik terbaru dari %1", "digest.cta": "Klik di sini untuk mengunjungi %1", diff --git a/public/language/id/error.json b/public/language/id/error.json index 7b1413a957..ce802296e2 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topik dikunci", "still-uploading": "Tunggu proses upload sampai selesai", "content-too-short": "Mohon masukkan posting yang lebih panjang. Posting harus memuat setidaknya %1 karakter.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Mohon masukkan judul yang lebih panjang. Judul harus memuat setidaknya %1 karakter.", "title-too-long": "Mohon masukkan judul yang lebih pendek. Judul tidak dapat melebihi %1 karakter.", "too-many-posts": "Kamu hanya dapat melakukan posting satu kali setiap %1 detik - mohon tunggu beberapa saat sebelum melakukan posting kembali", @@ -62,6 +63,7 @@ "signature-too-long": "Maaf, tanda pengenalmu tidak dapat melebihi %1 karakter.", "cant-chat-with-yourself": "Kamu tidak dapat chat dengan akun sendiri", "chat-restricted": "Pengguna ini telah membatasi percakapa mereka. Mereka harus mengikutimu sebelum kamu dapat melakukan percakapan dengan mereka ", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Sistem reputasi ditiadakan.", "downvoting-disabled": "Downvoting ditiadakan", "not-enough-reputation-to-downvote": "Tidak cukup reputation untuk downvote post ini", diff --git a/public/language/id/groups.json b/public/language/id/groups.json index bca990761d..3bae971661 100644 --- a/public/language/id/groups.json +++ b/public/language/id/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Posting Terkini", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/id/pages.json b/public/language/id/pages.json index bfedbfaa27..83b55a2b22 100644 --- a/public/language/id/pages.json +++ b/public/language/id/pages.json @@ -11,6 +11,7 @@ "user.followers": "Pengguna yang mengikuti %1", "user.posts": "Posting dibuat oleh %1", "user.topics": "Topik dibuat oleh %1", + "user.groups": "%1's Groups", "user.favourites": "Posting Favorit %1", "user.settings": "Pengaturan Pengguna", "maintenance.text": "%1 saat ini sedang dalam masa pemeliharaan. Silahkan kembali lain waktu.", diff --git a/public/language/id/reset_password.json b/public/language/id/reset_password.json index 7ae5b9e8d7..ec65c5ca68 100644 --- a/public/language/id/reset_password.json +++ b/public/language/id/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Mohon masukkan alamat emailmu dan kami akan mengirimkan mu sebuah email dengan instruksi mengenai cara pengaturan ulang akunmu.", "enter_email_address": "Masukkan Alamat Email", "password_reset_sent": "Pengaturan Kembali Kata Sandi telah DIkirim", - "invalid_email": "Email Salah / Email tidak ada!" + "invalid_email": "Email Salah / Email tidak ada!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/id/search.json b/public/language/id/search.json index af974065ab..5eb7f1f851 100644 --- a/public/language/id/search.json +++ b/public/language/id/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/id/users.json b/public/language/id/users.json index 4f7636a9c3..783d9478f3 100644 --- a/public/language/id/users.json +++ b/public/language/id/users.json @@ -5,7 +5,7 @@ "search": "Pencarian", "enter_username": "Masukkan nama pengguna untuk mencari", "load_more": "Tampilkan Lebih Banyak", - "users-found-search-took": "%1 pengguna ditemukan! Pencarian butuh waktu %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/it/email.json b/public/language/it/email.json index 8c0a1666c2..d54cf8c4cd 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -9,6 +9,9 @@ "reset.text1": "Abbiamo ricevuto una richiesta di reset della tua password, probabilmente perché l'hai dimenticata. Se non è così si prega di ignorare questa email.", "reset.text2": "Per confermare il reset della password per favore clicca il seguente link:", "reset.cta": "Clicca qui per resettare la tua password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Hai una notifica non letta da %1:", "digest.latest_topics": "Ultimi argomenti su %1", "digest.cta": "Clicca qui per visitare %1", diff --git a/public/language/it/error.json b/public/language/it/error.json index 12ebc50080..fe207d0502 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -35,6 +35,7 @@ "topic-locked": "Discussione Bloccata", "still-uploading": "Per favore attendere il completamento degli uploads.", "content-too-short": "Inserisci un post più lungo. Il Messaggio deve contenere almeno %1 caratteri.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Inserisci un titolo più lungo. I titoli devono contenere almeno %1 caratteri.", "title-too-long": "Per favore inserire un titolo più corto, non può essere più lungo di %1 caratteri.", "too-many-posts": "È possibile inserire un Post ogni %1 secondi - si prega di attendere prima di postare di nuovo", @@ -62,6 +63,7 @@ "signature-too-long": "Spiacenti, la tua firma non può essere lunga %1 caratteri.", "cant-chat-with-yourself": "Non puoi chattare con te stesso!", "chat-restricted": "Questo utente ha ristretto i suoi messaggi in chat alle persone che segue. Per poter chattare con te ti deve prima seguire.", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Il sistema di reputazione è disabilitato.", "downvoting-disabled": "Il Downvoting è disabilitato", "not-enough-reputation-to-downvote": "Non hai i privilegi per votare negativamente questo post", diff --git a/public/language/it/groups.json b/public/language/it/groups.json index 51f67ec593..f4e5f32787 100644 --- a/public/language/it/groups.json +++ b/public/language/it/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Ultimi Post", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/it/pages.json b/public/language/it/pages.json index 38c22f82b7..72d2a3e042 100644 --- a/public/language/it/pages.json +++ b/public/language/it/pages.json @@ -11,6 +11,7 @@ "user.followers": "Persone che seguono %1", "user.posts": "Post creati da %1", "user.topics": "Discussioni create da %1", + "user.groups": "%1's Groups", "user.favourites": "Post Favoriti da %1", "user.settings": "Impostazioni Utente", "maintenance.text": "%1 è attualmente in manutenzione. Per favore ritorna più tardi.", diff --git a/public/language/it/reset_password.json b/public/language/it/reset_password.json index 9340714167..4789b7f1c1 100644 --- a/public/language/it/reset_password.json +++ b/public/language/it/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Inserisci il tuo indirizzo email e ti invieremo un'email con le istruzioni per resettare il tuo account.", "enter_email_address": "Inserisci l'Indirizzo Email", "password_reset_sent": "Password Reset Inviata", - "invalid_email": "Email invalida / L'email non esiste!" + "invalid_email": "Email invalida / L'email non esiste!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/it/search.json b/public/language/it/search.json index 6b1250cf39..9d021ec7c5 100644 --- a/public/language/it/search.json +++ b/public/language/it/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/it/users.json b/public/language/it/users.json index 3faed8adbb..44f4b4f916 100644 --- a/public/language/it/users.json +++ b/public/language/it/users.json @@ -5,7 +5,7 @@ "search": "Cerca", "enter_username": "Inserisci il nome utente da cercare", "load_more": "Carica altri", - "users-found-search-took": "%1 utente(i) trovati! La ricerca ha impiegato %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/ja/email.json b/public/language/ja/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/ja/email.json +++ b/public/language/ja/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index b55c713676..2a4a1ebac9 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -35,6 +35,7 @@ "topic-locked": "スレッドがロックされた", "still-uploading": "アップロードが完成するまでお待ちください。", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "タイトルに最大 %1 文字の制限があります。", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "自分にチャットすることはできません!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/ja/groups.json b/public/language/ja/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/ja/groups.json +++ b/public/language/ja/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/ja/pages.json b/public/language/ja/pages.json index e4534d567d..eb5274c6f1 100644 --- a/public/language/ja/pages.json +++ b/public/language/ja/pages.json @@ -11,6 +11,7 @@ "user.followers": "%1のフォロワー", "user.posts": "%1が作成したポスト", "user.topics": "%1が作成したスレッド", + "user.groups": "%1's Groups", "user.favourites": "%1のお気に入りポスト", "user.settings": "ユーザー設定", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/ja/reset_password.json b/public/language/ja/reset_password.json index c732e9e159..7e31c22720 100644 --- a/public/language/ja/reset_password.json +++ b/public/language/ja/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "メールアドレスを入力してください.パスワードリセットの指示をメールでご送付します。", "enter_email_address": "メールアドレスを入力してください", "password_reset_sent": "パスワードリセットのメールを送信しました", - "invalid_email": "このメールアドレスは存在しません" + "invalid_email": "このメールアドレスは存在しません", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ja/search.json b/public/language/ja/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/ja/search.json +++ b/public/language/ja/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ja/users.json b/public/language/ja/users.json index 9bf3d7a0d9..6d73cf0513 100644 --- a/public/language/ja/users.json +++ b/public/language/ja/users.json @@ -5,7 +5,7 @@ "search": "検索", "enter_username": "検索するユーザー名を入力してください", "load_more": "もっと表示", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/ko/email.json b/public/language/ko/email.json index a7e4ea2cfc..1c5032db35 100644 --- a/public/language/ko/email.json +++ b/public/language/ko/email.json @@ -9,6 +9,9 @@ "reset.text1": "패스워드 재설정 요청을 받았습니다. 패스워드를 분실해서 요청한 것이 아니라면 이 메일을 무시하셔도 좋습니다.", "reset.text2": "패스워드를 재설정하려면 다음 링크를 클릭하세요.", "reset.cta": "패스워드를 재설정하려면 여기를 클릭하세요.", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "%1에 읽지 않은 게시물이 있습니다.", "digest.latest_topics": "%1의 최근 주제", "digest.cta": "%1에 방문하시려면 클릭하세요.", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 9ce8f5dd42..fcca053185 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -35,6 +35,7 @@ "topic-locked": "잠긴 주제입니다.", "still-uploading": "업로드가 끝날 때까지 기다려 주세요.", "content-too-short": "게시물의 내용이 너무 짧습니다. 최소 %1자 이상이어야 합니다.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "제목이 너무 짧습니다. 최소 %1자 이상이어야 합니다.", "title-too-long": "제목은 최대 %1자로 제한됩니다.", "too-many-posts": "새 게시물 작성은 %1초 간격으로 제한됩니다 - 잠시 기다렸다가 작성해주세요.", @@ -62,6 +63,7 @@ "signature-too-long": "죄송합니다. 서명은 최대 %1자로 제한됩니다.", "cant-chat-with-yourself": "자신과는 채팅할 수 없습니다.", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "인기도 시스템을 사용하지 않습니다.", "downvoting-disabled": "비추천 기능을 사용하지 않습니다.", "not-enough-reputation-to-downvote": "인기도가 낮아 이 게시물에 반대할 수 없습니다.", diff --git a/public/language/ko/groups.json b/public/language/ko/groups.json index 8a788bebb2..344c35078b 100644 --- a/public/language/ko/groups.json +++ b/public/language/ko/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "최근 게시물", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/ko/pages.json b/public/language/ko/pages.json index 570f5b22f5..ce1f9e5a05 100644 --- a/public/language/ko/pages.json +++ b/public/language/ko/pages.json @@ -11,6 +11,7 @@ "user.followers": "%1님을 팔로우하는 사용자", "user.posts": "%1님이 작성한 게시물", "user.topics": "%1님이 생성한 주제", + "user.groups": "%1's Groups", "user.favourites": "%1님이 좋아하는 게시물", "user.settings": "설정", "maintenance.text": "%1 사이트는 현재 점검 중입니다. 나중에 다시 방문해주세요.", diff --git a/public/language/ko/reset_password.json b/public/language/ko/reset_password.json index d229a5a931..60fe18c8e5 100644 --- a/public/language/ko/reset_password.json +++ b/public/language/ko/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "이메일 주소를 입력하면 비밀번호를 초기화하는 방법을 메일로 알려드립니다.", "enter_email_address": "여기에 이메일 주소를 입력하세요.", "password_reset_sent": "이메일이 발송되었습니다.", - "invalid_email": "올바르지 않거나 가입되지 않은 이메일입니다." + "invalid_email": "올바르지 않거나 가입되지 않은 이메일입니다.", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ko/search.json b/public/language/ko/search.json index 391a7477ee..3905534515 100644 --- a/public/language/ko/search.json +++ b/public/language/ko/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ko/users.json b/public/language/ko/users.json index 14f0b96551..9135621eb6 100644 --- a/public/language/ko/users.json +++ b/public/language/ko/users.json @@ -5,7 +5,7 @@ "search": "검색", "enter_username": "검색할 사용자 이름을 입력하세요.", "load_more": "더 보기", - "users-found-search-took": "%1명의 사용자를 찾았습니다! 검색에 %2 ms가 소요되었습니다.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/lt/email.json b/public/language/lt/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index deb7944e24..1951d21778 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -35,6 +35,7 @@ "topic-locked": "Tema užrakinta", "still-uploading": "Prašome palaukti kol bus baigti visi kėlimai į serverį", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Pavadinimas turėtų būti trumpesnis. Maksimalus leistinas ilgis- %1 simbolių.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Jūs negalite susirašinėti su savimi!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "Jūs neturite pakankamai reputacijos balsuoti prieš šį pranešimą", diff --git a/public/language/lt/groups.json b/public/language/lt/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/lt/groups.json +++ b/public/language/lt/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/lt/pages.json b/public/language/lt/pages.json index 1551e325f2..338cd346f5 100644 --- a/public/language/lt/pages.json +++ b/public/language/lt/pages.json @@ -11,6 +11,7 @@ "user.followers": "Žmonės, kurie seka %1", "user.posts": "Pranešimai, kuriuos parašė %1", "user.topics": "Temos, kurias sukūrė %1", + "user.groups": "%1's Groups", "user.favourites": "Vartotojo %1 mėgstami pranešimai", "user.settings": "Vartotojo nustatymai", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/lt/reset_password.json b/public/language/lt/reset_password.json index 66192d423f..104f75e6e3 100644 --- a/public/language/lt/reset_password.json +++ b/public/language/lt/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Prašome įrašyti el. pašto adresą ir mes atsiųsime jums instrukciją, kaip atstatyti jūsų paskyrą.", "enter_email_address": "Įrašykite el. pašto adresą", "password_reset_sent": "Slaptažodžio atstatymas išsiųstas", - "invalid_email": "Klaidingas arba neegzistuojantis el. pašto adresas!" + "invalid_email": "Klaidingas arba neegzistuojantis el. pašto adresas!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/lt/search.json b/public/language/lt/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/lt/search.json +++ b/public/language/lt/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/lt/users.json b/public/language/lt/users.json index 58f5d1793e..043ca55bcc 100644 --- a/public/language/lt/users.json +++ b/public/language/lt/users.json @@ -5,7 +5,7 @@ "search": "Ieškoti", "enter_username": "Įrašykite vartotojo vardą paieškai", "load_more": "Įkelti daugiau", - "users-found-search-took": "%1 paskyra(-os)! Paieška užtruko %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/ms/email.json b/public/language/ms/email.json index 6e765e9f0b..4c5ca1adde 100644 --- a/public/language/ms/email.json +++ b/public/language/ms/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 336f7cd580..3c68a1d7e5 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/ms/groups.json b/public/language/ms/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/ms/groups.json +++ b/public/language/ms/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/ms/pages.json b/public/language/ms/pages.json index 6ce4a94980..dc7c0385e9 100644 --- a/public/language/ms/pages.json +++ b/public/language/ms/pages.json @@ -11,6 +11,7 @@ "user.followers": "Pengguna yang Mengikuti %1", "user.posts": "Kiriman dibuat oleh %1", "user.topics": "Topik dibuat oleh %1", + "user.groups": "%1's Groups", "user.favourites": "Mesej Kegemaran %1", "user.settings": "Tetapan pengguna", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/ms/reset_password.json b/public/language/ms/reset_password.json index 20c519aa55..2951ed5007 100644 --- a/public/language/ms/reset_password.json +++ b/public/language/ms/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Sila masukkan alamat emel dan kami akan menghantar arahan untuk penetapan semula akaun anda", "enter_email_address": "Masukkan alamat emel", "password_reset_sent": "Penetapan semula password telah dihantar", - "invalid_email": "Emel yang tidak sah / Emel tidak wujud" + "invalid_email": "Emel yang tidak sah / Emel tidak wujud", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ms/search.json b/public/language/ms/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/ms/search.json +++ b/public/language/ms/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ms/users.json b/public/language/ms/users.json index 3e1a3f089b..26475bd746 100644 --- a/public/language/ms/users.json +++ b/public/language/ms/users.json @@ -5,7 +5,7 @@ "search": "Cari", "enter_username": "Masukkan nama pengguna untuk carian", "load_more": "Muat lagi", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/nb/email.json b/public/language/nb/email.json index c3c3e3f474..65e1accaee 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -9,6 +9,9 @@ "reset.text1": "Vi har blir bedt om å tilbakestille passordet ditt, muligens fordi du har glemt det. Hvis dette ikke stemmer kan du ignorere denne eposten.", "reset.text2": "For å fortsette med tilbakestillingen, vennligst klikk på følgende lenke:", "reset.cta": "Klikk her for å tilbakestille passordet ditt", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Du har uleste varsler fra %1:", "digest.latest_topics": "Siste emner fra %1", "digest.cta": "Klikk her for å besøke %1", @@ -17,8 +20,8 @@ "notif.chat.subject": "Ny chat-melding mottatt fra %1", "notif.chat.cta": "Klikk her for å fortsette samtalen", "notif.chat.unsub.info": "Denne chat-varselen er sendt til deg basert på dine innstillinger for abonnering.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Trykk for å lese hele emnet", + "notif.post.unsub.info": "Dette postvarselet ble sendt til deg på grunn av dine abonnementsinnstillinger.", "test.text1": "Dette er en test-epost for å verifisere at epostsystemet i NodeBB fungerer som det skal.", "unsub.cta": "Klikk her for å endre disse innstillingene", "closing": "Takk!" diff --git a/public/language/nb/error.json b/public/language/nb/error.json index ef6f1a20b0..a19bdad64d 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -18,7 +18,7 @@ "username-taken": "Brukernavn opptatt", "email-taken": "E-post opptatt", "email-not-confirmed": "E-posten din har ikke blitt bekreftet enda, vennligst klikk for å bekrefte din e-post.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Du kan ikke chatte før e-posten din har blitt bekreftet", "username-too-short": "Brukernavnet er for kort", "username-too-long": "Brukernavnet er for langt", "user-banned": "Bruker utestengt", @@ -35,6 +35,7 @@ "topic-locked": "Emne låst", "still-uploading": "Vennligst vent til opplastingene blir fullført.", "content-too-short": "Vennligst skriv et lengere innlegg. Innlegg må inneholde minst %1 tegn.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Vennligst skriv en lengere tittel. Titler må inneholde minst %1 tegn.", "title-too-long": "Vennligst skriv en kortere tittel. Titler må inneholde minst %1 tegn.", "too-many-posts": "Du kan bare poste et innlegg hvert %1 sekund - vennligst vent før du poster igjen", @@ -44,13 +45,13 @@ "already-favourited": "Du har allerede favorittmerket dette innlegget", "already-unfavourited": "Du har allerede avfavorisert dette innlegget", "cant-ban-other-admins": "Du kan ikke utestenge andre administratorer!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Ugyldig bildetype. Tilatte typer er: %1", + "invalid-image-extension": "Ugyldig bildefiltype", "group-name-too-short": "Gruppenavnet er for kort", "group-already-exists": "Gruppe eksisterer allerede", "group-name-change-not-allowed": "Gruppenavn ikke tillatt", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Du er allerede en del av denne gruppen", + "group-needs-owner": "Denne gruppen kreves minst en eier", "post-already-deleted": "Dette innlegget har blitt slettet", "post-already-restored": "Dette innlegget har allerede blitt gjenopprettet", "topic-already-deleted": "Dette emnet har allerede blitt slettet", @@ -62,11 +63,12 @@ "signature-too-long": "Beklager, signaturen din kan ikke være lengre en %1 tegn.", "cant-chat-with-yourself": "Du kan ikke chatte med deg selv!", "chat-restricted": "Denne brukeren har begrenset sine chat-meldinger. De må følge deg før du kan chatte med dem", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Ryktesystem er deaktivert.", "downvoting-disabled": "Nedstemming av deaktivert", "not-enough-reputation-to-downvote": "Du har ikke nok rykte til å nedstemme det innlegget", "not-enough-reputation-to-flag": "Du har ikke nok rykte til å flagge dette innlegget", "reload-failed": "NodeBB støtte på et problem under lasting på nytt: \"%1\". NodeBB vil fortsette å servere eksisterende klientside ressureser, selv om du burde angre endringene du gjorde før du lastet på nytt.", "registration-error": "Feil under registrering", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Noe gikk feil under analysering av serversvar" } \ No newline at end of file diff --git a/public/language/nb/global.json b/public/language/nb/global.json index 34f3d08cc4..9528d360c5 100644 --- a/public/language/nb/global.json +++ b/public/language/nb/global.json @@ -3,10 +3,10 @@ "search": "Søk", "buttons.close": "Steng", "403.title": "Adgang nektet", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Du har funnet en side du ikke har tilgang til.", + "403.login": "Kanskje du skal prøve å logge inn?", "404.title": "Ikke funnet", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Du har funnet en side som ikke eksisterer. Returner til startsiden?", "500.title": "Intern feil.", "500.message": "Oops! Ser ut som noe gikk galt!", "register": "Registrer", @@ -27,7 +27,7 @@ "header.tags": "Tagger", "header.popular": "Populære", "header.users": "Brukere", - "header.groups": "Groups", + "header.groups": "Grupper", "header.chats": "Chatter", "header.notifications": "Varsler", "header.search": "Søk", @@ -75,7 +75,7 @@ "updated.title": "Forum oppdatert", "updated.message": "Dette forumet har nettopp blitt oppdatert til den nyeste versjonen. Klikk her for å laste siden på nytt.", "privacy": "Personvern", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Følg", + "unfollow": "Avfølg", "delete_all": "Slett alle" } \ No newline at end of file diff --git a/public/language/nb/groups.json b/public/language/nb/groups.json index 3319bcb9a2..894bbc0a12 100644 --- a/public/language/nb/groups.json +++ b/public/language/nb/groups.json @@ -1,21 +1,23 @@ { "groups": "Grupper", "view_group": "Vis gruppe", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Gruppe-eier", + "new_group": "Opprett ny gruppe", + "no_groups_found": "Det er ingen grupper å se", + "cover-instructions": "Dra og slipp et bilde, dra til posisjon, og trykk Lagre", + "cover-change": "Endre", + "cover-save": "Lagre", + "cover-saving": "Lagrer", "details.title": "Gruppedetaljer", "details.members": "Medlemsliste", - "details.pending": "Pending Members", + "details.pending": "Ventende meldemmer", "details.has_no_posts": "Medlemmene i denne gruppen har ikke skrevet noen innlegg.", "details.latest_posts": "Seneste innlegg", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Privat grup", + "details.public": "Offentlig grup", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Gruppeadministrasjon", + "event.updated": "Gruppedetaljer har blitt oppgradert", + "event.deleted": "Gruppen \"%1\" har blitt slettet" } \ No newline at end of file diff --git a/public/language/nb/pages.json b/public/language/nb/pages.json index 151b1c7a79..1d657bd759 100644 --- a/public/language/nb/pages.json +++ b/public/language/nb/pages.json @@ -11,6 +11,7 @@ "user.followers": "Personer som følger %1", "user.posts": "Innlegg laget av %1", "user.topics": "Emner opprettet av %1", + "user.groups": "%1's Groups", "user.favourites": "%1 sine favoritt-innlegg", "user.settings": "Brukerinnstillinger", "maintenance.text": "%1 er for tiden under vedlikehold. Kom tilbake en annen gang.", diff --git a/public/language/nb/recent.json b/public/language/nb/recent.json index 4a77aab5ab..24ece53c70 100644 --- a/public/language/nb/recent.json +++ b/public/language/nb/recent.json @@ -6,13 +6,13 @@ "year": "År", "alltime": "All tid", "no_recent_topics": "Det er ingen nye tråder.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Det finnes et nytt emne.", + "there-is-a-new-topic-and-a-new-post": "Det finnes et nytt emne og et nytt innlegg.", + "there-is-a-new-topic-and-new-posts": "Det finnes et nytt emne og %1 nye innlegg.", + "there-are-new-topics": "Det finnes %1 nye emner.", + "there-are-new-topics-and-a-new-post": "Det finnes %1 nye emner og et nytt innlegg.", + "there-are-new-topics-and-new-posts": "Det finnes %1 nye emner og %2 nye innlegg", + "there-is-a-new-post": "Det finnes et nytt innlegg.", + "there-are-new-posts": "Det finnes %1 nye innlegg.", + "click-here-to-reload": "Trykk her for å laste på nytt." } \ No newline at end of file diff --git a/public/language/nb/reset_password.json b/public/language/nb/reset_password.json index d8aab92154..ed6659abdf 100644 --- a/public/language/nb/reset_password.json +++ b/public/language/nb/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Vennligst skriv din e-post-adresse og vi vil sende den en e-post med instruksjoner om hvordan du tilbakestiller din konto.", "enter_email_address": "Skriv e-post", "password_reset_sent": "Passord-tilbakestilling sendt", - "invalid_email": "Ugyldig e-post / e-post eksisterer ikke" + "invalid_email": "Ugyldig e-post / e-post eksisterer ikke", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/nb/search.json b/public/language/nb/search.json index 2e9ad3665c..053950fd9e 100644 --- a/public/language/nb/search.json +++ b/public/language/nb/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 resultat(er) samsvarer med \"%2\", (%3 sekunder)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "Ingen matcher funnet", + "in": "I", + "by": "Av", + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Skapt av", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 7690cd7114..49096d9f6f 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "Ingen innlegg valgt!", "fork_success": "Dette emnet ble delt! Klikk for å gå til delt emne.", "composer.title_placeholder": "Skriv din tråd-tittel her", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Navn", "composer.discard": "Forkast", "composer.submit": "Send", "composer.replying_to": "Svarer i %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "Eldste til nyeste", "newest_to_oldest": "Nyeste til eldste", "most_votes": "Flest stemmer", - "most_posts": "Most posts" + "most_posts": "Flest innlegg" } \ No newline at end of file diff --git a/public/language/nb/user.json b/public/language/nb/user.json index b154436e80..f3e6523e25 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -2,8 +2,8 @@ "banned": "Utestengt", "offline": "Offline", "username": "Brukernavn", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Registereringsdato", + "postcount": "Antall innlegg", "email": "E-post", "confirm_email": "Bekfreft e-post", "delete_account": "Slett konto", @@ -18,7 +18,7 @@ "profile_views": "Profilvisninger", "reputation": "Rykte", "favourites": "Favoritter", - "watched": "Watched", + "watched": "Overvåkede", "followers": "Følgere", "following": "Følger", "signature": "Signatur", @@ -64,7 +64,7 @@ "follows_no_one": "Denne brukeren følger ingen :(", "has_no_posts": "Denne brukeren har ikke skrevet noe enda.", "has_no_topics": "Denne brukeren har ikke skrevet noen emner enda.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Denne brukeren overvåker ingen innlegg foreløpig.", "email_hidden": "E-post skjult", "hidden": "skjult", "paginate_description": "Paginer tråder og innlegg istedet for å bruke uendelig skrolling.", diff --git a/public/language/nb/users.json b/public/language/nb/users.json index e0f8363a64..661479fbf1 100644 --- a/public/language/nb/users.json +++ b/public/language/nb/users.json @@ -5,8 +5,8 @@ "search": "Søk", "enter_username": "Skriv ett brukernavn for å søke", "load_more": "Last flere", - "users-found-search-took": "%1 bruker(e) funnet! Søk tok %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "filter-by": "Filtrer etter", + "online-only": "Bare påloggede", + "picture-only": "Bare bilde" } \ No newline at end of file diff --git a/public/language/nl/email.json b/public/language/nl/email.json index ec4296182c..a1f26cd2ea 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -9,6 +9,9 @@ "reset.text1": "Wij ontvingen een verzoek van u om uw wachtwoord te resetten. Als dat niet het geval is, kunt u deze mail negeren ", "reset.text2": "Om uw wachtwoord te resetten, klik op de volgende link", "reset.cta": "Klik hier om u wachtwoord te resetten", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "U heeft ongelezen notificaties van %1:", "digest.latest_topics": "De laatste onderwerpen van %1", "digest.cta": "Klik hier om deze website te bezoeken %1 ", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 6e4553687a..8b2c37d5a1 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -35,6 +35,7 @@ "topic-locked": "Onderwerp gesloten", "still-uploading": "Heb even geduld totdat de alle bestanden geüpload zijn", "content-too-short": "Maak de bericht alsjeblieft wat langer. Op z'n minst %1 karakters", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Maak de titel wat langer. Op z'n minst %1 karakters", "title-too-long": "Maak de titel wat korter. Het kan niet langer zijn dan %1 karakters", "too-many-posts": "Je kan eens in de %1 seconden een bericht aanmaken. Wacht alstublieft.", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, maar deze handtekening kan niet groter zijn dan %1 karakters!", "cant-chat-with-yourself": "Je kan niet met jezelf chatten!", "chat-restricted": "Deze gebruiker heeft beperkingen gelegd op chatfunctie. Hun moeten jouw volgen voordat je met hun kan chatten", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputatie systeem is uitgeschakeld", "downvoting-disabled": "Downvoten is uitgeschakeld", "not-enough-reputation-to-downvote": "U heeft niet de benodigde reputatie om dit bericht te downvoten", diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json index 14a4023b74..59681475d1 100644 --- a/public/language/nl/groups.json +++ b/public/language/nl/groups.json @@ -1,13 +1,13 @@ { "groups": "Groepen", "view_group": "Bekijk Groep", - "owner": "Group Owner", - "new_group": "Create New Group", + "owner": "Groep eigenaar", + "new_group": "Maak een nieuwe groep", "no_groups_found": "There are no groups to see", "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "cover-save": "Opslaan", + "cover-saving": "Bezig met opslaan", "details.title": "Groep Details", "details.members": "Ledenlijst", "details.pending": "Pending Members", @@ -15,6 +15,8 @@ "details.latest_posts": "Nieuwste Berichten", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index b567e526d1..09cda815b9 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -11,6 +11,7 @@ "user.followers": "Mensen die %1 Volgen", "user.posts": "Berichten geplaatst door %1", "user.topics": "Topics gecreëerd door %1", + "user.groups": "%1's Groups", "user.favourites": "%1's Favoriete Berichten", "user.settings": "Gebruikersinstellingen", "maintenance.text": "%1 is momenteel in onderhoud modus. Probeer later opnieuw", diff --git a/public/language/nl/recent.json b/public/language/nl/recent.json index 56f3ca3288..2b1b292298 100644 --- a/public/language/nl/recent.json +++ b/public/language/nl/recent.json @@ -6,10 +6,10 @@ "year": "Jaar", "alltime": "Intussen", "no_recent_topics": "Er zijn geen recente reacties.", - "there-is-a-new-topic": "There is a new topic.", + "there-is-a-new-topic": "Er is een nieuw onderwerp", "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", + "there-is-a-new-topic-and-new-posts": "Er is een nieuwe onderwerp en %1 nieuwe berichten", + "there-are-new-topics": "Er zijn %1 nieuwe onderwerpen", "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", "there-is-a-new-post": "There is a new post.", diff --git a/public/language/nl/reset_password.json b/public/language/nl/reset_password.json index a529b6b8f8..2bac7d3849 100644 --- a/public/language/nl/reset_password.json +++ b/public/language/nl/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Vul a.u.b. je email address in en we versturen je een email met de stappen hoe je je account reset.", "enter_email_address": "Vul uw Email Adres in", "password_reset_sent": "Wachtwoord Reset Verzonden", - "invalid_email": "Fout Email Adres / Email Adres bestaat niet!" + "invalid_email": "Fout Email Adres / Email Adres bestaat niet!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/nl/search.json b/public/language/nl/search.json index 837a109e6f..168dde5142 100644 --- a/public/language/nl/search.json +++ b/public/language/nl/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 resulta(a)ten was een match \"%2\", (%3 seconds)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "Geen matches gevonden", + "in": "in", + "by": "door", + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index c5a7af6b2f..8ab45e30d3 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "Geen berichten geselecteerd!", "fork_success": "Met succes het onderwerp gesplitst. klik hier om naar het nieuwe onderwerp te gaan.", "composer.title_placeholder": "Vul de titel voor het onderwerp hier in...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Naam", "composer.discard": "Annuleren", "composer.submit": "Opslaan", "composer.replying_to": "Reageren op %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "Oud naar Nieuw", "newest_to_oldest": "Nieuw naar Oud", "most_votes": "Meeste stemmen", - "most_posts": "Most posts" + "most_posts": "Meeste berichten" } \ No newline at end of file diff --git a/public/language/nl/user.json b/public/language/nl/user.json index fccd6ac057..0cc9df6cbe 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -2,7 +2,7 @@ "banned": "Verbannen", "offline": "Offline", "username": "Gebruikersnaam", - "joindate": "Join Date", + "joindate": "Datum van registratie", "postcount": "Post Count", "email": "Email", "confirm_email": "Bevestig uw email adres", diff --git a/public/language/nl/users.json b/public/language/nl/users.json index 3f19d8316f..315b86fe31 100644 --- a/public/language/nl/users.json +++ b/public/language/nl/users.json @@ -5,8 +5,8 @@ "search": "Zoeken", "enter_username": "Vul een gebruikersnaam in om te zoeken", "load_more": "Meer Laden", - "users-found-search-took": "%1 gebruiker(s) gevonden! Zoekactie duurde %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "filter-by": "Filter op", + "online-only": "Online ", + "picture-only": "Alleen een afbeelding" } \ No newline at end of file diff --git a/public/language/pl/email.json b/public/language/pl/email.json index 04816f6185..d1f327d90a 100644 --- a/public/language/pl/email.json +++ b/public/language/pl/email.json @@ -9,6 +9,9 @@ "reset.text1": "Otrzymaliśmy żądanie przywrócenia Twojego hasła. Jeśli nie żądałeś przywrócenia hasła, zignoruj ten e-mail.", "reset.text2": "Aby przywrócić swoje hasło, skorzystaj z poniższego linku:", "reset.cta": "Kliknij tu, by przywrócić swoje hasło", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Masz nowe powiadomienia od %1:", "digest.latest_topics": "Ostatnie tematy z %1", "digest.cta": "Kliknij, by odwiedzić %1", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index d35d020cc6..119a9ca553 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -35,6 +35,7 @@ "topic-locked": "Temat zamknięty", "still-uploading": "Poczekaj na pełne załadowanie", "content-too-short": "Proszę wpisać dłuższy post. Posty powinny zawierać co najmniej %1 znaków.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Proszę podać dłuższy tytuł. Tytuły powinny zawierać co najmniej %1 znaków.", "title-too-long": "Wpisz krótszy tytuł, nie może być dłuższy niż %1 znaków.", "too-many-posts": "Możesz wysyłać posty co %1 sekund - proszę poczekać", @@ -62,6 +63,7 @@ "signature-too-long": "Przepraszamy, ale podpis nie może być dłuższy niż %1 znaków.", "cant-chat-with-yourself": "Nie możesz rozmawiać ze sobą", "chat-restricted": "Ten użytkownik ograniczył swoje czaty. Musi Cię śledzić, zanim będziesz mógł z nim czatować.", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "System reputacji został wyłączony", "downvoting-disabled": "Ocena postów jest wyłączona", "not-enough-reputation-to-downvote": "Masz za mało reputacji by ocenić ten post.", diff --git a/public/language/pl/groups.json b/public/language/pl/groups.json index 9fdd6d6c79..0cd285b938 100644 --- a/public/language/pl/groups.json +++ b/public/language/pl/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Ostatnie posty", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/pl/pages.json b/public/language/pl/pages.json index f8afb878f5..4aad8f6c6d 100644 --- a/public/language/pl/pages.json +++ b/public/language/pl/pages.json @@ -11,6 +11,7 @@ "user.followers": "Obserwujący %1", "user.posts": "Posty napisane przez %1", "user.topics": "Wątki stworzone przez %1", + "user.groups": "%1's Groups", "user.favourites": "Ulubione posty %1", "user.settings": "Ustawienia użytkownika", "maintenance.text": "Obecnie trwają prace konserwacyjne nad %1. Proszę wrócić później.", diff --git a/public/language/pl/reset_password.json b/public/language/pl/reset_password.json index fa0affeab6..99b7518a97 100644 --- a/public/language/pl/reset_password.json +++ b/public/language/pl/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Podaj swój adres e-mail i wyślemy ci wiadomość z instrukcjami jak zresetować hasło.", "enter_email_address": "Wpisz swój adres e-mail", "password_reset_sent": "Instrukcje zostały wysłane", - "invalid_email": "Niepoprawny adres e-mail." + "invalid_email": "Niepoprawny adres e-mail.", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/pl/search.json b/public/language/pl/search.json index 472b6bf10c..c8775e8c66 100644 --- a/public/language/pl/search.json +++ b/public/language/pl/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/pl/users.json b/public/language/pl/users.json index 38ff75b928..2df9600a30 100644 --- a/public/language/pl/users.json +++ b/public/language/pl/users.json @@ -5,7 +5,7 @@ "search": "Szukaj", "enter_username": "Wpisz nazwę użytkownika", "load_more": "Więcej", - "users-found-search-took": "Znaleziono %1 użytkowników. Szukanie zajęło %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/pt_BR/email.json b/public/language/pt_BR/email.json index 4465631a3e..250bf39788 100644 --- a/public/language/pt_BR/email.json +++ b/public/language/pt_BR/email.json @@ -9,6 +9,9 @@ "reset.text1": "Nós recebemos um pedido para reconfigurar sua senha, possivelmente porque você a esqueceu. Se este não é o caso, por favor ignore este email.", "reset.text2": "Para continuar com a reconfiguração de senha, por favor clique no seguinte link:", "reset.cta": "Clique aqui para reconfigurar sua senha", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Você tem notificações não lidas de %1:", "digest.latest_topics": "Últimos tópicos de %1", "digest.cta": "Clique aqui para visitar %1", @@ -17,8 +20,8 @@ "notif.chat.subject": "Nova mensagem de chat recebida de %1", "notif.chat.cta": "Clique aqui para continuar a conversa", "notif.chat.unsub.info": "Esta notificação de chat foi enviada a você devido às suas configurações de assinatura.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Clique aqui para ler o tópico completo", + "notif.post.unsub.info": "Esta notificação de postagem foi enviada para você devido as suas configurações de assinatura.", "test.text1": "Este é um e-mail de teste, para verificar que o enviador de emails está corretamente configurado no seu NodeBB.", "unsub.cta": "Clique aqui para alterar estas configurações", "closing": "Obrigado!" diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 127303d653..51d9f13502 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -18,7 +18,7 @@ "username-taken": "Nome de usuário já existe", "email-taken": "Email já cadastrado", "email-not-confirmed": "O seu email ainda não foi confirmado, por favor clique aqui para confirmar seu email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Você não pode usar o chat até que seu email seja confirmado", "username-too-short": "Nome de usuário muito curto", "username-too-long": "Nome de usuário muito longo", "user-banned": "Usuário banido", @@ -35,6 +35,7 @@ "topic-locked": "Tópico Trancado", "still-uploading": "Aguarde a conclusão dos uploads.", "content-too-short": "Por favor digite um post mais longo. Posts devem conter no mínimo %1 caracteres.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Por favor digite um título mais longo. Títulos devem conter no mínimo %1 caracteres.", "title-too-long": "Por favor entre com um título mais curto; Títulos não podem ser maiores que %1 caracteres.", "too-many-posts": "Você pode postar apenas uma vez a cada %1 segundos - por favor aguarde antes de postar novamente", @@ -44,13 +45,13 @@ "already-favourited": "Você já adicionou este post aos favoritos", "already-unfavourited": "Você já removeu este post dos favoritos", "cant-ban-other-admins": "Você não pode banir outros administradores!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Tipo inválido de imagem. Os tipos permitidos são: %1", + "invalid-image-extension": "Extensão de imagem inválida", "group-name-too-short": "Nome do grupo é muito curto", "group-already-exists": "O grupo já existe", "group-name-change-not-allowed": "Sem permissão para alterar nome do grupo", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Você já faz parte deste grupo", + "group-needs-owner": "Este grupo requer ao menos um dono", "post-already-deleted": "Este post já foi deletado", "post-already-restored": "Este post já foi restaurado", "topic-already-deleted": "Esté tópico já foi deletado", @@ -62,11 +63,12 @@ "signature-too-long": "Desculpe, sua assinatura não pode ser maior que %1 caracteres.", "cant-chat-with-yourself": "Você não pode iniciar um chat consigo mesmo!", "chat-restricted": "Este usuário restringiu suas mensagens de chat. Eles devem seguir você antes que você possa conversar com eles", + "too-many-messages": "Você enviou muitas mensagens, por favor aguarde um momento.", "reputation-system-disabled": "O sistema de reputação está desabilitado.", "downvoting-disabled": "Negativação está desabilitada", "not-enough-reputation-to-downvote": "Você não possui reputação suficiente para negativar este post", "not-enough-reputation-to-flag": "Você não possui reputação suficiente para sinalizar este post", "reload-failed": "O NodeBB encontrou um problema ao recarregar: \"%1\". O NodeBB continuará a servir os assets existentes no lado do cliente, apesar de que você deve desfazer o que você fez antes de recarregar.", "registration-error": "Erro de Cadastro", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Algo deu errado ao conseguir resposta do servidor" } \ No newline at end of file diff --git a/public/language/pt_BR/global.json b/public/language/pt_BR/global.json index 88a9d803e6..d9bb14a846 100644 --- a/public/language/pt_BR/global.json +++ b/public/language/pt_BR/global.json @@ -3,10 +3,10 @@ "search": "Procurar", "buttons.close": "Fechar", "403.title": "Acesso Negado", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Parece que você chegou à uma página à qual você não tem acesso.", + "403.login": "Talvez você deveria tentar logar?", "404.title": "Não Encontrado", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Parece que você chegou à uma página que não existe. Voltar para a página inicial.", "500.title": "Erro interno.", "500.message": "Oops! Parece que algo deu errado!", "register": "Cadastrar", @@ -27,7 +27,7 @@ "header.tags": "Tags", "header.popular": "Popular", "header.users": "Usuários", - "header.groups": "Groups", + "header.groups": "Grupos", "header.chats": "Chats", "header.notifications": "Notificações", "header.search": "Procurar", @@ -75,7 +75,7 @@ "updated.title": "Fórum Atualizado", "updated.message": "Este fórum foi atualizado para sua última versão. Clique aqui para atualizar a página.", "privacy": "Privacidade", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Seguir", + "unfollow": "Deixar de seguir", "delete_all": "Deletar Tudo" } \ No newline at end of file diff --git a/public/language/pt_BR/groups.json b/public/language/pt_BR/groups.json index 1893fb87a5..4095f4c3ce 100644 --- a/public/language/pt_BR/groups.json +++ b/public/language/pt_BR/groups.json @@ -1,21 +1,23 @@ { "groups": "Grupos", "view_group": "Ver Grupo", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Dono do Grupo", + "new_group": "Criar Novo Grupo", + "no_groups_found": "Não há grupos para ver", + "cover-instructions": "Arraste uma foto, arraste para a posição correta e clique em Salvar", + "cover-change": "Alterar", + "cover-save": "Salvar", + "cover-saving": "Salvando", "details.title": "Detalhes do Grupo", "details.members": "Lista de Membros", - "details.pending": "Pending Members", + "details.pending": "Membros Pendentes", "details.has_no_posts": "Os membros deste grupo não fizeram quaisquer posts.", "details.latest_posts": "Últimos Posts", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Grupo Privado", + "details.public": "Grupo Público.", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Administração do Grupo", + "event.updated": "Os detalhes do grupo foram atualizados", + "event.deleted": "O grupo \"%1\" foi deletado" } \ No newline at end of file diff --git a/public/language/pt_BR/pages.json b/public/language/pt_BR/pages.json index a65c95781b..ae42c35f0f 100644 --- a/public/language/pt_BR/pages.json +++ b/public/language/pt_BR/pages.json @@ -11,6 +11,7 @@ "user.followers": "Pessoas que Seguem %1", "user.posts": "Posts feitos por %1", "user.topics": "Tópicos criados por %1", + "user.groups": "%1's Groups", "user.favourites": "Posts Favoritos de %1", "user.settings": "Configurações de Usuário", "maintenance.text": "%1 está atualmente sob manutenção. Por favor retorne em outro momento.", diff --git a/public/language/pt_BR/recent.json b/public/language/pt_BR/recent.json index 3c3551e0c1..b0dd732602 100644 --- a/public/language/pt_BR/recent.json +++ b/public/language/pt_BR/recent.json @@ -6,13 +6,13 @@ "year": "Ano", "alltime": "Todos os Tempos", "no_recent_topics": "Não há tópicos recentes.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Há um novo tópico.", + "there-is-a-new-topic-and-a-new-post": "Há um novo tópico e um novo post.", + "there-is-a-new-topic-and-new-posts": "Há um novo tópico e %1 novos posts.", + "there-are-new-topics": "Há %1 novos tópicos.", + "there-are-new-topics-and-a-new-post": "Há %1 novos tópicos e um novo post.", + "there-are-new-topics-and-new-posts": "Há %1 novos tópicos e %2 novos posts.", + "there-is-a-new-post": "Há um novo post.", + "there-are-new-posts": "Há %1 novos posts.", + "click-here-to-reload": "Clique aqui para recarregar." } \ No newline at end of file diff --git a/public/language/pt_BR/reset_password.json b/public/language/pt_BR/reset_password.json index 7646899cd1..bf96416678 100644 --- a/public/language/pt_BR/reset_password.json +++ b/public/language/pt_BR/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Por favor digite seu endereço de email e nós iremos lhe enviar em email com instruções de como reconfigurar a sua conta.", "enter_email_address": "Digite seu Email", "password_reset_sent": "Reconfiguração de Senha Enviada", - "invalid_email": "Email Inválido / Email não existe!" + "invalid_email": "Email Inválido / Email não existe!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/pt_BR/search.json b/public/language/pt_BR/search.json index 9d1e425017..9f10c0970b 100644 --- a/public/language/pt_BR/search.json +++ b/public/language/pt_BR/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 resultado(s) contendo \"%2\", (%3 segundos)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "Nenhum resultado encontrado", + "in": "Em", + "by": "Por", + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Postado por", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/pt_BR/topic.json b/public/language/pt_BR/topic.json index d93e414d45..df49f8cb20 100644 --- a/public/language/pt_BR/topic.json +++ b/public/language/pt_BR/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "Nenhum post selecionado!", "fork_success": "Tópico clonado com sucesso! Clique aqui para ir ao tópico clonado.", "composer.title_placeholder": "Digite aqui o título para o seu tópico...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Nome", "composer.discard": "Descartar", "composer.submit": "Enviar", "composer.replying_to": "Respondendo para %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "Mais Antigo para Mais Recente", "newest_to_oldest": "Mais Recente para Mais Antigo", "most_votes": "Mais votados", - "most_posts": "Most posts" + "most_posts": "Mais posts" } \ No newline at end of file diff --git a/public/language/pt_BR/user.json b/public/language/pt_BR/user.json index f4fe0a6602..86412afd5c 100644 --- a/public/language/pt_BR/user.json +++ b/public/language/pt_BR/user.json @@ -2,8 +2,8 @@ "banned": "Banido", "offline": "Offline", "username": "Nome de Usuário", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Data de Entrada", + "postcount": "Número de Posts", "email": "Email", "confirm_email": "Confirmar Email", "delete_account": "Deletar Conta", @@ -18,7 +18,7 @@ "profile_views": "Visualizações de perfil", "reputation": "Reputação", "favourites": "Favoritos", - "watched": "Watched", + "watched": "Acompanhado", "followers": "Seguidores", "following": "Seguindo", "signature": "Assinatura", @@ -59,12 +59,12 @@ "digest_weekly": "Semanalmente", "digest_monthly": "Mensalmente", "send_chat_notifications": "Enviar-me um email se uma nova mensagem de chat chegar quando eu não estiver online.", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Enviar um email quando respostas forem dadas à tópicos que eu assino", "has_no_follower": "Este usuário não possui seguidores :(", "follows_no_one": "Este usuário não está seguindo ninguém :(", "has_no_posts": "Este usuário não postou nada ainda.", "has_no_topics": "Este usuário ainda não criou nenhum tópico.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Este usuário ainda não acompanhou quaisquer tópicos.", "email_hidden": "Email Escondido", "hidden": "escondido", "paginate_description": "Paginação de tópicos e posts ao invés de usar \"rolagem infinita\".", diff --git a/public/language/pt_BR/users.json b/public/language/pt_BR/users.json index 66ea217bd6..32edc568f5 100644 --- a/public/language/pt_BR/users.json +++ b/public/language/pt_BR/users.json @@ -5,8 +5,8 @@ "search": "Procurar", "enter_username": "Digite um nome de usuário para procurar", "load_more": "Carregar Mais", - "users-found-search-took": "%1 usuário(s) encontrado(s)! A pesquisa demorou %2 ms.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "filter-by": "Filtrar Por", + "online-only": "Apenas Online", + "picture-only": "Apenas foto" } \ No newline at end of file diff --git a/public/language/ro/email.json b/public/language/ro/email.json index 0e3a1da8ab..25f9723466 100644 --- a/public/language/ro/email.json +++ b/public/language/ro/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "Pentru a continua cu resetarea parolei, te rugăm sa apeși pe următorul link:", "reset.cta": "Apasă aici pentru a-ți reseta parola", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Ultimele mesaje de la %1", "digest.cta": "Apasă aici pentru a vizita %1", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index ce47fad775..1e7de8b50b 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -35,6 +35,7 @@ "topic-locked": "Subiect Închis", "still-uploading": "Te rugăm să aștepți până se termină uploadul.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Te rugăm să introduci un titlu mai scurt. Titlurile nu pot fi mai lungi de %1 caractere.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Nu poți conversa cu tine!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Sistemul de reputație este dezactivat.", "downvoting-disabled": "Votarea negativă este dezactivată", "not-enough-reputation-to-downvote": "Nu ai destulă reputație pentru a vota negativ acest post.", diff --git a/public/language/ro/groups.json b/public/language/ro/groups.json index 816af582ea..03cacf8b36 100644 --- a/public/language/ro/groups.json +++ b/public/language/ro/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Ultimele Mesaje", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/ro/pages.json b/public/language/ro/pages.json index c3b65dfd23..141c5fb1df 100644 --- a/public/language/ro/pages.json +++ b/public/language/ro/pages.json @@ -11,6 +11,7 @@ "user.followers": "Utilizatori care îl urmăresc pe %1", "user.posts": "Mesaje postate de %1", "user.topics": "Subiecte create de %1", + "user.groups": "%1's Groups", "user.favourites": "Mesajele favorite ale lui %1", "user.settings": "Setări Utilizator", "maintenance.text": "%1 este momentan în mentenanță. Întoarce-te în curând!", diff --git a/public/language/ro/reset_password.json b/public/language/ro/reset_password.json index b4ae4564f8..d9edc5c856 100644 --- a/public/language/ro/reset_password.json +++ b/public/language/ro/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Te rugăm sa introduci adresa ta de email și îți vom trimite un email cu instrucțiuni pentru a îți reseta contul tău de utilizator.", "enter_email_address": "Introdu adresă de email", "password_reset_sent": "Emailul pentru resetarea parolei a fost trimis", - "invalid_email": "Adresă de email invalidă / Adresa de email nu există!" + "invalid_email": "Adresă de email invalidă / Adresa de email nu există!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ro/search.json b/public/language/ro/search.json index 35c5b72b74..cdae3636ce 100644 --- a/public/language/ro/search.json +++ b/public/language/ro/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ro/users.json b/public/language/ro/users.json index 065d2b07e2..4ef70026a8 100644 --- a/public/language/ro/users.json +++ b/public/language/ro/users.json @@ -5,7 +5,7 @@ "search": "Căutare", "enter_username": "Introdu un nume de utilizator pentru a căuta", "load_more": "Încarcă mai multe", - "users-found-search-took": "%1 utilizator(i) găsit! Căutarea a durat %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/ru/email.json b/public/language/ru/email.json index 9b070ed2b2..eed54608d0 100644 --- a/public/language/ru/email.json +++ b/public/language/ru/email.json @@ -9,6 +9,9 @@ "reset.text1": "Мы получили запрос на сброс Вашего пароля. Если Вы не подавали запрос, пожалуйста, проигнорируйте это сообщение.", "reset.text2": "Для продолжения процедуры изменения пароля, пожалуйста, перейдите по ссылке:", "reset.cta": "Кликните здесь для изменения пароля", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "У Вас непрочитанные уведомления от %1:", "digest.latest_topics": "Последние темы %1", "digest.cta": "Кликните здесь для просмотра %1", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 8570dcc524..5683d863d1 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -18,7 +18,7 @@ "username-taken": "Имя пользователя занято", "email-taken": "Email занят", "email-not-confirmed": "Ваш email не подтвержден, нажмите для подтверждения.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Вы не можете оставлять сообщения, пока Ваш email не подтверждён", "username-too-short": "Слишком короткое имя пользователя", "username-too-long": "Имя пользователя слишком длинное", "user-banned": "Пользователь заблокирован", @@ -35,6 +35,7 @@ "topic-locked": "Тема закрыта", "still-uploading": "Пожалуйста, подождите завершения загрузки.", "content-too-short": "Пост должен содержать минимум %1 симв.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Заголовок должен содержать минимум %1 симв.", "title-too-long": "Заголовок не может быть длиннее %1 символов.", "too-many-posts": "Вы можете делать пост один раз в %1 сек.", @@ -45,12 +46,12 @@ "already-unfavourited": "Вы уже удалили этот пост из избранного", "cant-ban-other-admins": "Вы не можете забанить других администраторов!", "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-extension": "Недопустимое расширение файла", "group-name-too-short": "Название группы слишком короткое", "group-already-exists": "Группа уже существует", "group-name-change-not-allowed": "Изменение названия группы запрещено", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Вы уже состоите в этой группе", + "group-needs-owner": "У группы должен быть как минимум один владелец", "post-already-deleted": "Этот пост уже удалён", "post-already-restored": "Этот пост уже восстановлен.", "topic-already-deleted": "Тема уже удалена", @@ -62,6 +63,7 @@ "signature-too-long": "Ваша подпись не может быть длиннее %1 симв.", "cant-chat-with-yourself": "Вы не можете общаться с самим собой", "chat-restricted": "Пользователь ограничил прием сообщений. Он должен подписаться на Вас, чтобы Вы могли вести переписку с ним.", + "too-many-messages": "Вы отправили слишком много сообщений, подождите немного.", "reputation-system-disabled": "Система репутации отключена.", "downvoting-disabled": "Понижение оценки отключено", "not-enough-reputation-to-downvote": "У Вас недостаточно репутации для понижения оценки поста", diff --git a/public/language/ru/global.json b/public/language/ru/global.json index 8a4e0ad0ec..1983e9f1ab 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -4,7 +4,7 @@ "buttons.close": "Закрыть", "403.title": "Доступ запрещен", "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.login": "Возможно Вам следует войти под своим аккаунтом?", "404.title": "Страница не найдена", "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", "500.title": "Внутренняя ошибка.", @@ -27,7 +27,7 @@ "header.tags": "Тэги", "header.popular": "Популярные", "header.users": "Пользователи", - "header.groups": "Groups", + "header.groups": "Группы", "header.chats": "Чаты", "header.notifications": "Уведомления", "header.search": "Поиск", diff --git a/public/language/ru/groups.json b/public/language/ru/groups.json index 15bcdf5caa..4b86076056 100644 --- a/public/language/ru/groups.json +++ b/public/language/ru/groups.json @@ -1,21 +1,23 @@ { "groups": "Группы", "view_group": "Просмотр группы", - "owner": "Group Owner", - "new_group": "Create New Group", + "owner": "Владелец группы", + "new_group": "Создать группу", "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", + "cover-instructions": "Перетяните сюда изображение, переместите на нужную позицию и нажмите Сохранить", "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "cover-save": "Сохранить", + "cover-saving": "Сохраняем", "details.title": "Информация о группе", "details.members": "Список пользователей", - "details.pending": "Pending Members", + "details.pending": "Заявки в группу", "details.has_no_posts": "Пользователями этой группы не публиковали никаких записей", "details.latest_posts": "Последние записи", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Приватная группа", + "details.public": "Открытая группа", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Настройки группы", + "event.updated": "Настройки группы обновлены", + "event.deleted": "Группа \"%1\" удалена" } \ No newline at end of file diff --git a/public/language/ru/pages.json b/public/language/ru/pages.json index 85348af836..f8a014193b 100644 --- a/public/language/ru/pages.json +++ b/public/language/ru/pages.json @@ -11,6 +11,7 @@ "user.followers": "Читают %1", "user.posts": "Пост написан %1", "user.topics": "Темы созданы %1", + "user.groups": "%1's Groups", "user.favourites": "Избранные сообщения %1", "user.settings": "Настройки", "maintenance.text": "%1 в настоящее время на обслуживании. Пожалуйста, возвращайтесь позже.", diff --git a/public/language/ru/recent.json b/public/language/ru/recent.json index 3926272aaa..c232a6bb5e 100644 --- a/public/language/ru/recent.json +++ b/public/language/ru/recent.json @@ -6,13 +6,13 @@ "year": "Год", "alltime": "За всё время", "no_recent_topics": "Нет свежих тем.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Опубликована новая тема.", + "there-is-a-new-topic-and-a-new-post": "Опубликована новая тема и новое сообщение.", + "there-is-a-new-topic-and-new-posts": "Опубликована новая тема и %1 новых сообщений.", + "there-are-new-topics": "Опубликованы %1 новых тем.", + "there-are-new-topics-and-a-new-post": "Опубликованы %1 новых тем и новое сообщение.", + "there-are-new-topics-and-new-posts": "Опубликованы %1 новых тем и %2 новых сообщений.", + "there-is-a-new-post": "Опубликовано новое сообщение.", + "there-are-new-posts": "Опубликовано %1 новых сообщений.", + "click-here-to-reload": "Нажмите здесь, чтобы перезагрузить список." } \ No newline at end of file diff --git a/public/language/ru/reset_password.json b/public/language/ru/reset_password.json index fdcb497d10..c9b523cf2e 100644 --- a/public/language/ru/reset_password.json +++ b/public/language/ru/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Пожалуйста введите ваш email адрес и мы отправим Вам письмо с инструкцией восстановления пароля.", "enter_email_address": "Введите Email адрес", "password_reset_sent": "Пароль Отправлен", - "invalid_email": "Неверный Email / Email не существует!" + "invalid_email": "Неверный Email / Email не существует!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/ru/search.json b/public/language/ru/search.json index aeb1235df2..f6ecb8d611 100644 --- a/public/language/ru/search.json +++ b/public/language/ru/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 результатов по фразе \"%2\", (%3 секунды) ", - "no-matches": "No matches found", + "no-matches": "Совпадений не найдено", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/ru/user.json b/public/language/ru/user.json index d9f2cdc61e..ba337e227b 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -2,8 +2,8 @@ "banned": "Заблокирован", "offline": "Не в сети", "username": "Имя пользователя", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Дата регистрации", + "postcount": "Сообщений", "email": "Email", "confirm_email": "Подтвердить Email", "delete_account": "Удалить Аккаунт", @@ -59,7 +59,7 @@ "digest_weekly": "За Неделю", "digest_monthly": "За Месяц", "send_chat_notifications": "Уведомлять на E-mail при поступлении нового сообщения чата, когда я оффлайн", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Отправлять email, когда отвечают в темы, на которые я подписан(а)", "has_no_follower": "Этого пользователя никто не читает :(", "follows_no_one": "Этот пользователь никого не читает :(", "has_no_posts": "Это пользователь еще ничего не написал.", diff --git a/public/language/ru/users.json b/public/language/ru/users.json index 78251703d2..e4253bcf62 100644 --- a/public/language/ru/users.json +++ b/public/language/ru/users.json @@ -5,7 +5,7 @@ "search": "Поиск", "enter_username": "Введите имя пользователя для поиска", "load_more": "Загрузить еще", - "users-found-search-took": "Нашел %1 пользователя(ей)! Поиск занял %2 мс.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/sc/email.json b/public/language/sc/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/sc/email.json +++ b/public/language/sc/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index a40a628042..9bbcf03247 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/sc/groups.json b/public/language/sc/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/sc/groups.json +++ b/public/language/sc/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/sc/pages.json b/public/language/sc/pages.json index 4ccd57cfd2..0f846179c3 100644 --- a/public/language/sc/pages.json +++ b/public/language/sc/pages.json @@ -11,6 +11,7 @@ "user.followers": "Gente chi Sighit %1", "user.posts": "Arresonos fatos dae %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "Arresonos Preferidos de %1", "user.settings": "Sèberos de Impitadore", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/sc/reset_password.json b/public/language/sc/reset_password.json index 877f9c716e..d86b716c31 100644 --- a/public/language/sc/reset_password.json +++ b/public/language/sc/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Pro praghere pone s'indiritzu email tuo e t'amus a imbiare un'email cun is istrutziones pro torrare a assentare s'intrada tua.", "enter_email_address": "Pone s'Indiritzu Email", "password_reset_sent": "Còdighe pro Torrare a Assentare sa Password Imbiadu", - "invalid_email": "Email Non Bàlida / Email chi no esistit!" + "invalid_email": "Email Non Bàlida / Email chi no esistit!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/sc/search.json b/public/language/sc/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/sc/search.json +++ b/public/language/sc/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/sc/users.json b/public/language/sc/users.json index 56b67f30f8..19e6cfe95f 100644 --- a/public/language/sc/users.json +++ b/public/language/sc/users.json @@ -5,7 +5,7 @@ "search": "Chirca", "enter_username": "Pone unu nùmene de impitadore de chircare", "load_more": "Càrriga de prus", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/sk/email.json b/public/language/sk/email.json index e3199a9b14..f290435e75 100644 --- a/public/language/sk/email.json +++ b/public/language/sk/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", "reset.cta": "Click here to reset your password", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "You have unread notifications from %1:", "digest.latest_topics": "Latest topics from %1", "digest.cta": "Click here to visit %1", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index b278526244..0ca1924e76 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -35,6 +35,7 @@ "topic-locked": "Uzamknutá téma", "still-uploading": "Prosím čakajte na dokončenie nahrávania", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Prosím uvedťe kratší názov. Názov nesmie byť dlhší ako 1 % znakov", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Nemôžete chatovat so samým sebou.", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/sk/groups.json b/public/language/sk/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/sk/groups.json +++ b/public/language/sk/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/sk/pages.json b/public/language/sk/pages.json index bcc524ed0d..c54ac7e71f 100644 --- a/public/language/sk/pages.json +++ b/public/language/sk/pages.json @@ -11,6 +11,7 @@ "user.followers": "Užívatelia následujúci %1", "user.posts": "Príspevky od %1", "user.topics": "Téma vytvorená %1\n", + "user.groups": "%1's Groups", "user.favourites": "%1's obľubených príspevkov", "user.settings": "Užívatelské nadstavenie", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/sk/reset_password.json b/public/language/sk/reset_password.json index bceaea8148..2391c09cae 100644 --- a/public/language/sk/reset_password.json +++ b/public/language/sk/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Zadajte svoju emailovú adresu a my Vám pošleme informácie, ako môžete obnoviť svoje heslo.", "enter_email_address": "Zadajte e-mail", "password_reset_sent": "Obnova hesla odoslaná", - "invalid_email": "Zlý email / Email neexistuje!" + "invalid_email": "Zlý email / Email neexistuje!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/sk/search.json b/public/language/sk/search.json index c89241d382..a04eb4fc1e 100644 --- a/public/language/sk/search.json +++ b/public/language/sk/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/sk/users.json b/public/language/sk/users.json index 56188b953e..819f861de7 100644 --- a/public/language/sk/users.json +++ b/public/language/sk/users.json @@ -5,7 +5,7 @@ "search": "Vyhľadávať", "enter_username": "Zadaj užívateľské meno k hľadaniu", "load_more": "Načítať dalšie", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/sv/email.json b/public/language/sv/email.json index b6ef31353f..808c73caa8 100644 --- a/public/language/sv/email.json +++ b/public/language/sv/email.json @@ -9,6 +9,9 @@ "reset.text1": "Vi fick en förfrågan om att återställa ditt lösenord, möjligen för att du har glömt det. Om detta inte är fallet, så kan du bortse från det här epostmeddelandet. ", "reset.text2": "För att fortsätta med återställning av lösenordet så kan du klicka på följande länk:", "reset.cta": "Klicka här för att återställa ditt lösenord", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Du har olästa notiser från %1:", "digest.latest_topics": "Senaste ämnen från %1", "digest.cta": "Klicka här för att besöka %1", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index 28e67f55cf..bf9769aa41 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -35,6 +35,7 @@ "topic-locked": "Ämnet låst", "still-uploading": "Vänta medan uppladdningen slutförs.", "content-too-short": "Skriv ett längre inlägg. Inlägget måste ha minst %1 tecken.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Skriv en längre rubrik. Rubriken måste ha minst %1 tecken.", "title-too-long": "Skriv in en kortare rubrik. Rubriker får inte vara längre än %1 tecken.", "too-many-posts": "Du kan endast skapa inlägg var %1:e sekund - vänta ett tag innan du försöker skapa ett nytt inlägg", @@ -62,6 +63,7 @@ "signature-too-long": "Signaturer kan tyvärr inte vara längre än %1 tecken.", "cant-chat-with-yourself": "Du kan inte chatta med dig själv.", "chat-restricted": "Denna användaren har begränsat sina chatt-meddelanden. Användaren måste följa dig innan ni kan chatta med varann", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Ryktessystemet är inaktiverat.", "downvoting-disabled": "Nedröstning är inaktiverat", "not-enough-reputation-to-downvote": "Du har inte tillräckligt förtroende för att rösta ner det här meddelandet", diff --git a/public/language/sv/groups.json b/public/language/sv/groups.json index 92a4eeb90b..fdba1db1b1 100644 --- a/public/language/sv/groups.json +++ b/public/language/sv/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Senaste inlägg", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/sv/pages.json b/public/language/sv/pages.json index 2082249d8c..f7a4904a84 100644 --- a/public/language/sv/pages.json +++ b/public/language/sv/pages.json @@ -11,6 +11,7 @@ "user.followers": "Personer som följer %1", "user.posts": "Inlägg skapat av %1", "user.topics": "Ämnen skapade av %1", + "user.groups": "%1's Groups", "user.favourites": "%1's favorit-inlägg", "user.settings": "Avnändarinställningar", "maintenance.text": "%1 genomgår underhåll just nu. Vänligen kom tillbaka lite senare.", diff --git a/public/language/sv/reset_password.json b/public/language/sv/reset_password.json index 03682d812e..a3771a31b4 100644 --- a/public/language/sv/reset_password.json +++ b/public/language/sv/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Var god fyll i din epost-adress så får du snart en epost med instruktioner hur du återsätller ditt konto.", "enter_email_address": "Skriv in epostadress", "password_reset_sent": "Lösenordsåterställning skickad", - "invalid_email": "Felaktig epost / Epost finns inte!" + "invalid_email": "Felaktig epost / Epost finns inte!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/sv/search.json b/public/language/sv/search.json index 193ea99480..0e4e831f93 100644 --- a/public/language/sv/search.json +++ b/public/language/sv/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/sv/users.json b/public/language/sv/users.json index 2b370c1146..591a32c344 100644 --- a/public/language/sv/users.json +++ b/public/language/sv/users.json @@ -5,7 +5,7 @@ "search": "Sök", "enter_username": "Ange ett användarnamn för att söka", "load_more": "Ladda fler", - "users-found-search-took": "%1 användare hittades! Sökningen tog %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/th/email.json b/public/language/th/email.json index 18bf7c5d1f..d91ba43963 100644 --- a/public/language/th/email.json +++ b/public/language/th/email.json @@ -9,6 +9,9 @@ "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "เพื่อดำเนินการตั้งรหัสผ่านใหม่ต่อไป, โปรดกดที่ลิ้งค์นี้:", "reset.cta": "กดตรงนี้เพื่อตั้งรหัสผ่านใหม่", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "คุณมีข้อความแจ้งเตือนที่ยังไม่ได้อ่านจาก %1:", "digest.latest_topics": "หัวข้อสนทนาล่าสุดจาก %1", "digest.cta": "กดตรงนี้เพื่อเข้าดู %1", diff --git a/public/language/th/error.json b/public/language/th/error.json index f65481696d..05985e9b49 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -35,6 +35,7 @@ "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", @@ -62,6 +63,7 @@ "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/th/groups.json b/public/language/th/groups.json index 6dfd71256b..950fe6dca3 100644 --- a/public/language/th/groups.json +++ b/public/language/th/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Latest Posts", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/th/pages.json b/public/language/th/pages.json index a227f62340..44f8b127e1 100644 --- a/public/language/th/pages.json +++ b/public/language/th/pages.json @@ -11,6 +11,7 @@ "user.followers": "ผู้ใช้ที่ติดตาม %1", "user.posts": "กระทู้โดย %1", "user.topics": "Topics created by %1", + "user.groups": "%1's Groups", "user.favourites": "กระทู้ที่ %1 ชอบ", "user.settings": "ตั้งค่าผู้ใช้", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", diff --git a/public/language/th/reset_password.json b/public/language/th/reset_password.json index 2b12834604..499f2f7136 100644 --- a/public/language/th/reset_password.json +++ b/public/language/th/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "กรุณาใส่อีเมลของคุณ เราจะส่งอีเมลให้คุณพร้อมคำแนะนำเกี่ยวกับวิธีการรีเซ็ตบัญชีของคุณ", "enter_email_address": "ใส่อีเมล์", "password_reset_sent": "รหัสรีเซ็ตถูกส่งออกไปแล้ว", - "invalid_email": "อีเมล์ไม่ถูกต้อง / อีเมล์ไม่มีอยู่!" + "invalid_email": "อีเมล์ไม่ถูกต้อง / อีเมล์ไม่มีอยู่!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/th/search.json b/public/language/th/search.json index 973ff03e13..4e865998e1 100644 --- a/public/language/th/search.json +++ b/public/language/th/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/th/users.json b/public/language/th/users.json index a3dddb41fd..542689e182 100644 --- a/public/language/th/users.json +++ b/public/language/th/users.json @@ -5,7 +5,7 @@ "search": "ค้นหา", "enter_username": "ใส่ชื่อผู้ใช้เพื่อค้นหา", "load_more": "โหลดเพิ่มเติม", - "users-found-search-took": "%1 user(s) found! Search took %2 ms.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/tr/category.json b/public/language/tr/category.json index f29f0c81d0..ba1c4f34ef 100644 --- a/public/language/tr/category.json +++ b/public/language/tr/category.json @@ -1,7 +1,7 @@ { "new_topic_button": "Yeni Başlık", "no_topics": " Bu kategoride hiç konu yok.
Yeni bir konu açmak istemez misiniz?", - "browsing": "dolaşıyor", + "browsing": "gözden geçiriliyor", "no_replies": "Kimse yanıtlamadı", "share_this_category": "Bu kategoriyi paylaş", "ignore": "Yoksay" diff --git a/public/language/tr/email.json b/public/language/tr/email.json index c69e7d0c8f..350df09f81 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -9,6 +9,9 @@ "reset.text1": "Şifrenizi değiştirmek istediğinize dair bir ileti aldık. Eğer böyle bir istek göndermediyseniz, lütfen bu e-postayı görmezden gelin.", "reset.text2": "Parola değiştirme işlemine devam etmek için aşağıdaki bağlantıya tıklayın:", "reset.cta": "Parolanızı değiştirmek için buraya tıklayın", + "reset.notify.subject": "Şifre başarıyla değiştirildi", + "reset.notify.text1": "Şifrenizin %1 zamanında başarı ile değiştirildiğini bildirmek isteriz.", + "reset.notify.text2": "Bunu siz yetkilendirmediyseniz, lütfen hiç vakit kaybetmeden site yöneticisine bu durumu bildiriniz.", "digest.notifications": "Okunmamış bazı bildirimleriniz var", "digest.latest_topics": "En güncel konular", "digest.cta": "Ziyaret etmek için buraya tıklayın", @@ -17,8 +20,8 @@ "notif.chat.subject": "Okunmamış bazı iletileriniz var", "notif.chat.cta": "Sohbete devam etmek için buraya tıklayın", "notif.chat.unsub.info": "Bu bildirim şectiğiniz ayarlar yüzünden gönderildi.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Konunun tamamını okumak için buraya tıklayın", + "notif.post.unsub.info": "Bu yazı bildirimi size abonelik ayarlarınız nedeni ile gönderilmiştir.", "test.text1": "Bu ileti NodeBB e-posta ayarlarınızın doğru çalışıp çalışmadığını kontrol etmek için gönderildi.", "unsub.cta": "Buraya tıklayarak ayarlarınızı değiştirebilirsiniz.", "closing": "Teşekkürler!" diff --git a/public/language/tr/error.json b/public/language/tr/error.json index 4e509a438d..a18f42652b 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -18,7 +18,7 @@ "username-taken": "Kullanıcı İsmi Alınmış", "email-taken": "E-posta Alınmış", "email-not-confirmed": "E-postanız onaylanmamış, onaylamak için lütfen buraya tıklayın.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "Email adresiniz doğrulanmadan sohbet edemezsiniz.", "username-too-short": "Kullanıcı ismi çok kısa", "username-too-long": "Kullanıcı ismi çok uzun.", "user-banned": "Kullanıcı Yasaklı", @@ -35,6 +35,7 @@ "topic-locked": "Başlık Kilitli", "still-uploading": "Lütfen yüklemelerin bitmesini bekleyin.", "content-too-short": "Lütfen daha uzun bir ileti girin. En az %1 karakter.", + "content-too-long": "Lütfen daha kısa bir yayın girin. Yayınlar %1 karakterden uzun olamaz.", "title-too-short": "Lütfen daha uzun bir başlık girin. En az %1 karakter.", "title-too-long": "Lütfen daha kısa bir başlık girin. Başlıklar %1 karakterden uzun olamaz.", "too-many-posts": "Sadece %1 saniyede bir ileti gönderebilirsiniz.", @@ -44,13 +45,13 @@ "already-favourited": "Bu iletiyi zaten favorilerinize eklediniz", "already-unfavourited": "Bu iletiyi zaten favorilerinizden çıkardınız", "cant-ban-other-admins": "Başka yöneticileri yasaklayamazsınız!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", + "invalid-image-type": "Geçersiz resim uzantısı. Izin verilen uzantılar: %1", + "invalid-image-extension": "Geçersiz resim uzantısı", "group-name-too-short": "Grup ismi çok kısa", "group-already-exists": "Grup zaten var", "group-name-change-not-allowed": "Grup ismini değiştiremezsiniz", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Bu grubun zaten bir parçasısınız.", + "group-needs-owner": "Bu grubu en az bir kişi sahiplenmesi gerekiyor", "post-already-deleted": "İleti zaten silinmiş", "post-already-restored": "İleti zaten geri getirilmiş", "topic-already-deleted": "Başlık zaten silinmiş", @@ -62,11 +63,12 @@ "signature-too-long": "İmza en fazla %1 karakter olabilir!", "cant-chat-with-yourself": "Kendinizle sohbet edemezsiniz!", "chat-restricted": "Bu kullanıcı sohbet ayarlarını kısıtlamış. Bu kişiye mesaj gönderebilmeniz için sizi takip etmeleri gerekiyor", + "too-many-messages": "Ardı ardına çok fazla mesaj yolladınız, lütfen biraz bekleyiniz.", "reputation-system-disabled": "Saygınlık sistemi kapatılmış.", "downvoting-disabled": "Aşagı oylama kapatılmış", "not-enough-reputation-to-downvote": "Bu iletiyi aşagı oylamak için yeterince saygınlığınız yok.", "not-enough-reputation-to-flag": "Bu iletiyi bayraklamak için yeterince saygınlığınız yok", "reload-failed": "NodeBB tekrar yüklenirken bir sorunla karşılaştı: “%1“. NodeBB varolan dosyaları servis etmeye devam edecek.", "registration-error": "Kayıt Hatası", - "parse-error": "Something went wrong while parsing server response" + "parse-error": "Sunucu yanıtı çözümlemesi sırasında bir şeyler ters gitti" } \ No newline at end of file diff --git a/public/language/tr/global.json b/public/language/tr/global.json index 152aba5d0e..cd2e8e18c9 100644 --- a/public/language/tr/global.json +++ b/public/language/tr/global.json @@ -3,10 +3,10 @@ "search": "Arama", "buttons.close": "Kapat", "403.title": "Erişim Engellendi", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should try logging in?", + "403.message": "Erişim izniniz olmayan bir sayfaya denk gelmiş gibisiniz.", + "403.login": "Belki de tekrar giriş yapmayı denersiniz?", "404.title": "Bulunamadı", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", + "404.message": "Erişim izniniz olmayan bir sayfaya denk gelmiş gibisiniz.Anasayfaya geri dönün.", "500.title": "Dahili hata.", "500.message": "Ups! Bir şeyler ters gitti sanki!", "register": "Kayıt Ol", @@ -27,7 +27,7 @@ "header.tags": "Etiketler", "header.popular": "Popüler", "header.users": "Kullanıcılar", - "header.groups": "Groups", + "header.groups": "Gruplar", "header.chats": "Sohbetler", "header.notifications": "Bildirimler", "header.search": "Arama", @@ -75,7 +75,7 @@ "updated.title": "Forum güncellendi", "updated.message": "Bu forum şu anda güncellendi. Sayfayı tekrar yüklemek için buraya tıklayın.", "privacy": "Gizlilik", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Takip et", + "unfollow": "Takip etmeyi bırak", "delete_all": "Hepsini Sil" } \ No newline at end of file diff --git a/public/language/tr/groups.json b/public/language/tr/groups.json index d2c411228d..3b765a2f7b 100644 --- a/public/language/tr/groups.json +++ b/public/language/tr/groups.json @@ -1,21 +1,23 @@ { "groups": "Guruplar", "view_group": "Grubu Gör", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", + "owner": "Grup Kurucusu", + "new_group": "Yeni Grup Oluştur", + "no_groups_found": "Henüz hiç grup yok", + "cover-instructions": "Bir fotoğrafı Sürükleyin ve Bırakın, uygun yere sürükleyip Kaydet'e tıklayın.", + "cover-change": "Değiştir", + "cover-save": "Kaydet", + "cover-saving": "Kaydediliyor", "details.title": "Grup Detayları", "details.members": "Üye Listesi", - "details.pending": "Pending Members", + "details.pending": "Üyeler bekleniyor", "details.has_no_posts": "Bu grubun üyeleri henüz bir ileti göndermedi.", "details.latest_posts": "En son iletiler", - "details.private": "Private Group", - "details.public": "Public Group", - "details.owner_options": "Group Administration", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Özel Grup", + "details.public": "Herkese Açık Grup", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", + "details.owner_options": "Grup Yöneticisi", + "event.updated": "Grup detayları güncellenmiştir", + "event.deleted": "\"%1\" grubu silinmiş" } \ No newline at end of file diff --git a/public/language/tr/pages.json b/public/language/tr/pages.json index e3d1cf9cf8..5171f4232f 100644 --- a/public/language/tr/pages.json +++ b/public/language/tr/pages.json @@ -11,6 +11,7 @@ "user.followers": "%1 takip edenler", "user.posts": "%1 tarafından gönderilen iletiler", "user.topics": "%1 tarafından gönderilen başlıklar", + "user.groups": "%1 Kişisine Ait Gruplar", "user.favourites": "%1'in Favori İletileri", "user.settings": "Kullanıcı Ayarları", "maintenance.text": "%1 şu anda bakımda. Lütfen bir süre sonra tekrar deneyin.", diff --git a/public/language/tr/recent.json b/public/language/tr/recent.json index 4773c22dfd..a1af8adb56 100644 --- a/public/language/tr/recent.json +++ b/public/language/tr/recent.json @@ -6,13 +6,13 @@ "year": "Yıl", "alltime": "Hepsi", "no_recent_topics": "Güncel konular yok.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-is-a-new-topic": "Yeni bir konu mevcut.", + "there-is-a-new-topic-and-a-new-post": "Yeni bir konu ve yayın mevcut.", + "there-is-a-new-topic-and-new-posts": "Bir adet yeni konu ve %1 adet yeni yayın var.", + "there-are-new-topics": "%1 adet yeni konu mevcut.", + "there-are-new-topics-and-a-new-post": "%1 adet yeni konu ve bir adet yeni yayın mevcut.", + "there-are-new-topics-and-new-posts": "%1 adet yeni konu %2 adet yeni yayın mevcut.", + "there-is-a-new-post": "Yeni bir yayın mevcut.", + "there-are-new-posts": "%1 adet yeni yayın mevcut.", + "click-here-to-reload": "Yenilemek için buraya tıklayın." } \ No newline at end of file diff --git a/public/language/tr/reset_password.json b/public/language/tr/reset_password.json index 0eb0497ee3..60f0346516 100644 --- a/public/language/tr/reset_password.json +++ b/public/language/tr/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Lütfen e-posta adresinizi girin , size hesabınızı nasıl sıfırlayacağınızı anlatan bir e-posta gönderelim", "enter_email_address": "E-posta Adresinizi girin", "password_reset_sent": "Şifre Yenilemesi Gönderildi", - "invalid_email": "Geçersiz E-posta / E-posta mevcut değil!" + "invalid_email": "Geçersiz E-posta / E-posta mevcut değil!", + "password_too_short": "Girdiğiniz şifre çok kısa, lütfen farklı bir şifre seçiniz.", + "passwords_do_not_match": "Girdiğiniz iki şifre birbirine uymuyor." } \ No newline at end of file diff --git a/public/language/tr/search.json b/public/language/tr/search.json index d3c5da5c91..0d079ffe4a 100644 --- a/public/language/tr/search.json +++ b/public/language/tr/search.json @@ -1,7 +1,35 @@ { "results_matching": "%1 tane “%2“ bulundu (%3 saniye)", - "no-matches": "No matches found", - "in": "In", - "by": "By", - "posted-by": "Posted by" + "no-matches": "Hiç eşleşme bulunamadı", + "in": "Konum:", + "by": "Kim Tarafından :", + "titles": "Başlıklar", + "titles-posts": "Başlıklar ve Yayınlar", + "posted-by": "Gönderen", + "in-categories": "Kategorilerde", + "search-child-categories": "Alt kategorilerde arat", + "reply-count": "Cevap Sayısı", + "at-least": "En az", + "at-most": "En fazla", + "post-time": "Yayınlama zamanı", + "newer-than": "Daha yeni", + "older-than": "Daha eski", + "any-date": "Herhangi bir tarih", + "yesterday": "Dün", + "one-week": "Bir hafta", + "two-weeks": "İki hafta", + "one-month": "Bir ay", + "three-months": "Üç ay", + "six-months": "Altı ay", + "one-year": "Bir yıl", + "sort-by": "Şuna göre filtrele", + "last-reply-time": "En son cevaplama süresi", + "topic-title": "Konu başlığı", + "number-of-replies": "Cevap sayısı", + "number-of-views": "Görüntüleme sayısı", + "topic-start-date": "Başlık açılma tarihi", + "username": "Kullanıcı Adı", + "category": "Kategori", + "descending": "Azalan düzene göre", + "ascending": "Artan düzene göre" } \ No newline at end of file diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index aa6aa90855..6cd2424e0f 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -74,7 +74,7 @@ "fork_no_pids": "Hiç bir ileti seçilmedi!", "fork_success": "Başlık başarıyla ayrıldı!", "composer.title_placeholder": "Başlık ismini buraya girin...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "İsim", "composer.discard": "Vazgeç", "composer.submit": "Gönder", "composer.replying_to": "Yanıtlanan Konu %1", @@ -94,5 +94,5 @@ "oldest_to_newest": "En eskiden en yeniye", "newest_to_oldest": "En yeniden en eskiye", "most_votes": "En çok oy", - "most_posts": "Most posts" + "most_posts": "En sık yayın" } \ No newline at end of file diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 90bd5eb06b..8fa7b4c5c9 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -2,8 +2,8 @@ "banned": "Yasaklı", "offline": "Çevrimdışı", "username": "Kullanıcı Adı", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Katılım Tarihi", + "postcount": "Yayın Sayısı", "email": "E-posta", "confirm_email": "E-posta onayla", "delete_account": "Hesabı Sil", @@ -18,7 +18,7 @@ "profile_views": "Profil Görüntülemeleri", "reputation": "Saygınlık", "favourites": "Favoriler", - "watched": "Watched", + "watched": "İzlendi", "followers": "Takipçiler", "following": "Takip Ediyor", "signature": "İmza", @@ -59,12 +59,12 @@ "digest_weekly": "Haftalık", "digest_monthly": "Aylık", "send_chat_notifications": "Çevrimiçi değilken gelen iletileri e-posta olarak gönder", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Abone olduğum konulara cevap gelince bana eposta yolla", "has_no_follower": "Bu kullanıcının hiç takipçisi yok :(", "follows_no_one": "Bu kullanıcı kimseyi takip etmiyor :(", "has_no_posts": "Bu kullanıcı henüz birşey göndermedi.", "has_no_topics": "Bu kullanıcı henüz bir konu yaratmadı.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Bu kullanıcı henüz hiçbir konuyu izlemedi.", "email_hidden": "E-posta gizli", "hidden": "gizli", "paginate_description": "Sonsuz yükleme yerine konu ve iletileri sayfalara böl.", diff --git a/public/language/tr/users.json b/public/language/tr/users.json index 8858e75ddd..9e38f04530 100644 --- a/public/language/tr/users.json +++ b/public/language/tr/users.json @@ -5,8 +5,8 @@ "search": "Ara", "enter_username": "Aramak için bir kullanıcı adı girin", "load_more": "Daha Fazla Yükle", - "users-found-search-took": "%1 kullanıcı bulundu! Arama %2 ms sürdü.", - "filter-by": "Filter By", - "online-only": "Online only", - "picture-only": "Picture only" + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "filter-by": "Şu şekilde filtrele", + "online-only": "Sadece çevrimiçi", + "picture-only": "Sadece resim" } \ No newline at end of file diff --git a/public/language/vi/email.json b/public/language/vi/email.json index 97bd7549e8..d0d376eb34 100644 --- a/public/language/vi/email.json +++ b/public/language/vi/email.json @@ -9,6 +9,9 @@ "reset.text1": "Chúng tôi nhận được yêu cầu khởi tạo lại mật khẩu của bạn, rất có thể vì bạn đã quên mất nó. Nếu bạn không gởi yêu cầu, hãy bỏ qua email này.", "reset.text2": "Để đặt lại mật khẩu, hãy click vào liên kết sau:", "reset.cta": "Click vào đây để khởi tạo lại mật khẩu", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "Bạn có thông báo chưa đọc từ %1", "digest.latest_topics": "Chủ đề mới nhất từ %1", "digest.cta": "Click vào đây để truy cập %1", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 002f910fc4..e8da82c330 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -35,6 +35,7 @@ "topic-locked": "Chủ đề bị khóa", "still-uploading": "Vui lòng chờ upload", "content-too-short": "Vui lòng tạo bài viết dài hơn. Bài viết phải có ít nhất %1 ký tự.", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "Vui lòng nhập tiêu đề dài hơn. Tiêu đề phải có ít nhất %1 ký tự", "title-too-long": "Yêu cầu tiêu đề ngắn hơn. Không dài quá %1 ký tự", "too-many-posts": "Bạn chỉ có thể gửi một bài viết mỗi %1 giây - Xin chờ trong giây lát trước khi gửi lại.", @@ -62,6 +63,7 @@ "signature-too-long": "Chứ ký không được dài quá %1 ký tự", "cant-chat-with-yourself": "Bạn không thể chat với chính bạn!", "chat-restricted": "Người dùng này đã bật chế độ hạn chế tin nhắn chat. Bạn phải được anh/cô ta follow thì mới có thể gởi tin nhắn đến họ được.", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "Hệ thống tín nhiệm đã bị vô hiệu hóa.", "downvoting-disabled": "Downvote đã bị tắt", "not-enough-reputation-to-downvote": "Bạn không có đủ phiếu tín nhiệm để downvote bài này", diff --git a/public/language/vi/groups.json b/public/language/vi/groups.json index c3a1d060d0..b649073d9b 100644 --- a/public/language/vi/groups.json +++ b/public/language/vi/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "Bài mới nhất", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/vi/pages.json b/public/language/vi/pages.json index 697490930b..153a1f31d8 100644 --- a/public/language/vi/pages.json +++ b/public/language/vi/pages.json @@ -11,6 +11,7 @@ "user.followers": "Người đang theo dõi %1", "user.posts": "Các bài được %1 viết", "user.topics": "Các chủ đề được %1 tạo", + "user.groups": "%1's Groups", "user.favourites": "Các bài gửi yêu thích của %1", "user.settings": "Thiết lập cho người dùng", "maintenance.text": "%1 đang được bảo trì. Xin vui lòng quay lại sau.", diff --git a/public/language/vi/reset_password.json b/public/language/vi/reset_password.json index edc196ba6c..32db56aab3 100644 --- a/public/language/vi/reset_password.json +++ b/public/language/vi/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "Xin hãy nhập địa chỉ email của bạn và chúng tôi sẽ gửi một email hướng dẫn cách thiết lập lại tài khoản cho bạn", "enter_email_address": "Nhập địa chỉ Email", "password_reset_sent": "Đã gửi mật khẩu được thiết lập lại", - "invalid_email": "Email không đúng / Email không tồn tại!" + "invalid_email": "Email không đúng / Email không tồn tại!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/vi/search.json b/public/language/vi/search.json index 254873ed38..a6450e408b 100644 --- a/public/language/vi/search.json +++ b/public/language/vi/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/vi/users.json b/public/language/vi/users.json index 405c9de32b..5e08193fd4 100644 --- a/public/language/vi/users.json +++ b/public/language/vi/users.json @@ -5,7 +5,7 @@ "search": "Tìm kiếm", "enter_username": "Gõ tên người dùng để tìm kiếm", "load_more": "Tải thêm", - "users-found-search-took": "%1 tài khoản(s) tìm thấy! Tìm trong %2 mili giây.", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/zh_CN/email.json b/public/language/zh_CN/email.json index 341874ec67..e81b810a9a 100644 --- a/public/language/zh_CN/email.json +++ b/public/language/zh_CN/email.json @@ -9,6 +9,9 @@ "reset.text1": "我们收到了重置您帐户密码的申请,可能是因为您遗忘了密码。如果不是,请忽略这封邮件。", "reset.text2": "如需继续重置密码,请点击下面的链接:", "reset.cta": "点击这里重置您的密码", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "您有来自 %1 的未读通知:", "digest.latest_topics": "来自 %1 的最新主题", "digest.cta": "点击这里访问 %1", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index acab3971eb..cfcb33aee8 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -35,6 +35,7 @@ "topic-locked": "主题已锁定", "still-uploading": "请等待上传完成", "content-too-short": "请再输入一些内容,帖子至少要有 %1 个字符。", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "请再输入一些内容,标题至少要有 %1 个字符。", "title-too-long": "请输入更短的标题。不超过 %1 字。", "too-many-posts": "发帖间隔至少要 %1 秒 - 请稍候再发帖", @@ -62,6 +63,7 @@ "signature-too-long": "抱歉,您的签名不能超过 %1 个字符。", "cant-chat-with-yourself": "您不能和自己聊天!", "chat-restricted": "此用户限制了他的聊天消息。必须他先关注您,您才能和他聊天。", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "威望系统已禁用。", "downvoting-disabled": "反对功能已禁用", "not-enough-reputation-to-downvote": "您还没有足够的威望为此帖扣分", diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json index 10a70d94c2..5a4bdd5b1f 100644 --- a/public/language/zh_CN/groups.json +++ b/public/language/zh_CN/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "最新帖子", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/zh_CN/pages.json b/public/language/zh_CN/pages.json index 924e8bdfa4..36d10c1cb3 100644 --- a/public/language/zh_CN/pages.json +++ b/public/language/zh_CN/pages.json @@ -11,6 +11,7 @@ "user.followers": "关注 %1 的人", "user.posts": "%1 发布的帖子", "user.topics": "%1 创建的主题", + "user.groups": "%1's Groups", "user.favourites": "%1 收藏的帖子", "user.settings": "用户设置", "maintenance.text": "%1 正在进行维护。请稍后再来。", diff --git a/public/language/zh_CN/reset_password.json b/public/language/zh_CN/reset_password.json index 701651dfb6..ca294f9dc7 100644 --- a/public/language/zh_CN/reset_password.json +++ b/public/language/zh_CN/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "请输入您的电子邮箱地址,我们会发送一份邮件指导您重置密码。", "enter_email_address": "输入邮箱地址", "password_reset_sent": "密码重置邮件已发送。", - "invalid_email": "无效的电子邮箱/电子邮箱不存在!" + "invalid_email": "无效的电子邮箱/电子邮箱不存在!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/zh_CN/search.json b/public/language/zh_CN/search.json index 338db4e61b..25cc3605e5 100644 --- a/public/language/zh_CN/search.json +++ b/public/language/zh_CN/search.json @@ -3,5 +3,33 @@ "no-matches": "No matches found", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/zh_CN/users.json b/public/language/zh_CN/users.json index bd19c53fa9..f56a4fb88e 100644 --- a/public/language/zh_CN/users.json +++ b/public/language/zh_CN/users.json @@ -5,7 +5,7 @@ "search": "搜索", "enter_username": "输入用户名搜索", "load_more": "加载更多", - "users-found-search-took": "找到 %1 位用户!搜索耗时 %2 毫秒。", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/language/zh_TW/email.json b/public/language/zh_TW/email.json index 6a5e3ef124..1062070b96 100644 --- a/public/language/zh_TW/email.json +++ b/public/language/zh_TW/email.json @@ -9,6 +9,9 @@ "reset.text1": "我們收到一個重設密碼的請求,你忘掉了密碼嗎?如果不是,請忽略這封郵件。", "reset.text2": "要繼續重置密碼,請點擊以下鏈接:", "reset.cta": "點擊這裡重置密碼", + "reset.notify.subject": "Password successfully changed", + "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", + "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", "digest.notifications": "你有來自$1的未讀通知:", "digest.latest_topics": "來自%1的最新話題", "digest.cta": "點擊這裡訪問%1", diff --git a/public/language/zh_TW/error.json b/public/language/zh_TW/error.json index 32fdfd6f7f..cb254c35aa 100644 --- a/public/language/zh_TW/error.json +++ b/public/language/zh_TW/error.json @@ -35,6 +35,7 @@ "topic-locked": "該主題已被鎖定", "still-uploading": "請等待上傳完成。", "content-too-short": "請輸入一個較長的帖子。 帖子需至少有 %1 個字。", + "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", "title-too-short": "請輸入一個較長的標題。 標題需至少有 %1 個字。", "title-too-long": "請輸入一個較短的主題名稱。 標題不能超過 %1 個字元。", "too-many-posts": "你必須間隔 %1 秒後才能發表文章-請稍後", @@ -62,6 +63,7 @@ "signature-too-long": "對不起,簽名檔長度不能超過 %1 字元!", "cant-chat-with-yourself": "你不能與自己聊天!", "chat-restricted": "此用戶已限制了他的聊天功能。你要在他關注你之後,才能跟他聊天", + "too-many-messages": "You have sent too many messages, please wait awhile.", "reputation-system-disabled": "信譽系統已停用。", "downvoting-disabled": "Downvoting已停用", "not-enough-reputation-to-downvote": "你沒有足夠的信譽downvote這個帖子", diff --git a/public/language/zh_TW/groups.json b/public/language/zh_TW/groups.json index 7e9ba9f239..a6c0d93c19 100644 --- a/public/language/zh_TW/groups.json +++ b/public/language/zh_TW/groups.json @@ -15,6 +15,8 @@ "details.latest_posts": "最新帖子", "details.private": "Private Group", "details.public": "Public Group", + "details.grant": "Grant/Rescind Ownership", + "details.kick": "Kick", "details.owner_options": "Group Administration", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted" diff --git a/public/language/zh_TW/pages.json b/public/language/zh_TW/pages.json index deaa502ffe..bcb655c3e2 100644 --- a/public/language/zh_TW/pages.json +++ b/public/language/zh_TW/pages.json @@ -11,6 +11,7 @@ "user.followers": "People who Follow %1", "user.posts": "文章由 %1 所張貼", "user.topics": "主題由 %1 所創建", + "user.groups": "%1's Groups", "user.favourites": "%1's 最喜愛的文章", "user.settings": "使用者設定", "maintenance.text": "%1目前正在進行維修。請稍後再來。", diff --git a/public/language/zh_TW/reset_password.json b/public/language/zh_TW/reset_password.json index b4c454d4da..9f0ab67aa1 100644 --- a/public/language/zh_TW/reset_password.json +++ b/public/language/zh_TW/reset_password.json @@ -10,5 +10,7 @@ "enter_email": "請輸入您的Email地址,我們會發送郵件告訴您如何重設密碼。", "enter_email_address": "輸入郵箱地址", "password_reset_sent": "密碼重設郵件已發送。", - "invalid_email": "非法的郵箱地址/郵箱不存在!" + "invalid_email": "非法的郵箱地址/郵箱不存在!", + "password_too_short": "The password entered is too short, please pick a different password.", + "passwords_do_not_match": "The two passwords you've entered do not match." } \ No newline at end of file diff --git a/public/language/zh_TW/search.json b/public/language/zh_TW/search.json index 426fa932b4..9fa8e84f2a 100644 --- a/public/language/zh_TW/search.json +++ b/public/language/zh_TW/search.json @@ -1,7 +1,35 @@ { "results_matching": "有%1個跟\"%2\"匹配的結果(%3秒)", - "no-matches": "No matches found", + "no-matches": "沒有找到匹配的主題", "in": "In", "by": "By", - "posted-by": "Posted by" + "titles": "Titles", + "titles-posts": "Titles and Posts", + "posted-by": "Posted by", + "in-categories": "In Categories", + "search-child-categories": "Search child categories", + "reply-count": "Reply Count", + "at-least": "At least", + "at-most": "At most", + "post-time": "Post time", + "newer-than": "Newer than", + "older-than": "Older than", + "any-date": "Any date", + "yesterday": "Yesterday", + "one-week": "One week", + "two-weeks": "Two weeks", + "one-month": "One month", + "three-months": "Three months", + "six-months": "Six months", + "one-year": "One year", + "sort-by": "Sort by", + "last-reply-time": "Last reply time", + "topic-title": "Topic title", + "number-of-replies": "Number of replies", + "number-of-views": "Number of views", + "topic-start-date": "Topic start date", + "username": "Username", + "category": "Category", + "descending": "In descending order", + "ascending": "In ascending order" } \ No newline at end of file diff --git a/public/language/zh_TW/users.json b/public/language/zh_TW/users.json index 249b34d36f..b3c22fb165 100644 --- a/public/language/zh_TW/users.json +++ b/public/language/zh_TW/users.json @@ -5,7 +5,7 @@ "search": "搜尋", "enter_username": "輸入想找的使用者帳號", "load_more": "載入更多", - "users-found-search-took": "找到%1個用戶!搜索時間%2毫秒。", + "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", "filter-by": "Filter By", "online-only": "Online only", "picture-only": "Picture only" diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 2e5b868048..ee9a87b605 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -169,7 +169,6 @@ border-radius: 3px; box-shadow: 0px 1px 3px 0px rgba(165, 165, 165, 0.75); margin-bottom: 20px; - max-width: 1000px; &.panel-default .panel-heading { background: #fefefe; @@ -232,7 +231,7 @@ } } - + #acp-search { input { background: black; @@ -250,7 +249,7 @@ width: 200px; } } - + .search-match { font-weight: 700; color: black; @@ -266,4 +265,14 @@ // See: https://github.com/twbs/bootstrap/commit/8e2348e9eda51296eb680192379ab37f10355ca3 .navbar-brand > img { display: inline-block; -} \ No newline at end of file +} + +@media (min-width: 1200px) { + .acp-sidebar { + position: fixed; + top: 70px; + right: 15px; + width: initial; + max-width: calc( ~"(100% - 200px)/4" ); + } +} diff --git a/public/src/admin/advanced/events.js b/public/src/admin/advanced/events.js new file mode 100644 index 0000000000..9075947d60 --- /dev/null +++ b/public/src/admin/advanced/events.js @@ -0,0 +1,41 @@ +"use strict"; +/* global define, socket, app, templates */ + + +define('admin/advanced/events', ['forum/infinitescroll'], function(infinitescroll) { + var Events = {}; + + Events.init = function() { + + $('[data-action="clear"]').on('click', function() { + socket.emit('admin.deleteAllEvents', function(err) { + if (err) { + return app.alertError(err.message); + } + $('.events-list').empty(); + }); + }); + + infinitescroll.init(function(direction) { + if (direction < 0 || !$('.events').length) { + return; + } + + infinitescroll.loadMore('admin.getMoreEvents', $('[data-next]').attr('data-next'), function(data, done) { + if (data.events && data.events.length) { + templates.parse('admin/advanced/events', 'events', {events: data.events}, function(html) { + $('.events-list').append(html); + done(); + }); + + $('[data-next]').attr('data-next', data.next); + } else { + done(); + } + }); + }); + + }; + + return Events; +}); diff --git a/public/src/admin/extend/widgets.js b/public/src/admin/extend/widgets.js index 1bf4a043ec..9632bbfa68 100644 --- a/public/src/admin/extend/widgets.js +++ b/public/src/admin/extend/widgets.js @@ -46,8 +46,6 @@ define('admin/extend/widgets', function() { appendToggle(ui.item); }, connectWith: "div" - }).on('click', '.toggle-widget', function() { - $(this).parents('.widget-panel').children('.panel-body').toggleClass('hidden'); }).on('click', '.delete-widget', function() { var panel = $(this).parents('.widget-panel'); @@ -56,8 +54,10 @@ define('admin/extend/widgets', function() { panel.remove(); } }); - }).on('dblclick', '.panel-heading', function() { - $(this).parents('.widget-panel').children('.panel-body').toggleClass('hidden'); + }).on('mouseup', '.panel-heading', function(evt) { + if ( !( $(this).parents('.widget-panel').is('.ui-sortable-helper') || $(evt.target).closest('.delete-widget').length ) ) { + $(this).parents('.widget-panel').children('.panel-body').toggleClass('hidden'); + } }); $('#widgets .save').on('click', saveWidgets); diff --git a/public/src/admin/manage/groups.js b/public/src/admin/manage/groups.js index 7b8f8cb5b4..b2ae0c0afb 100644 --- a/public/src/admin/manage/groups.js +++ b/public/src/admin/manage/groups.js @@ -154,8 +154,8 @@ define('admin/manage/groups', [ socket.emit('admin.user.search', {query: searchText}, function(err, results) { if (!err && results && results.users.length > 0) { var numResults = results.users.length, x; - if (numResults > 4) { - numResults = 4; + if (numResults > 20) { + numResults = 20; } groupDetailsSearchResults.empty(); diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index fdd63556e4..dad64e35af 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -134,6 +134,19 @@ define('admin/manage/users', ['admin/modules/selectable'], function(selectable) return false; }); + $('.send-validation-email').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } + socket.emit('admin.user.sendValidationEmail', uids, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('[[notifications:email-confirm-sent]]'); + }); + }) + $('.password-reset-email').on('click', function() { var uids = getSelectedUids(); if (!uids.length) { diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js index 3dca037514..98ab422b14 100644 --- a/public/src/admin/settings.js +++ b/public/src/admin/settings.js @@ -86,14 +86,19 @@ define('admin/settings', ['uploader', 'sounds'], function(uploader, sounds) { $('button[data-action="email.test"]').off('click').on('click', function() { socket.emit('admin.email.test', function(err) { - app.alert({ - alert_id: 'test_email_sent', - type: !err ? 'info' : 'danger', - title: 'Test Email Sent', - message: err ? err.message : '', - timeout: 2500 - }); + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('Test Email Sent'); }); + return false; + }); + + $('#clear-sitemap-cache').off('click').on('click', function() { + socket.emit('admin.settings.clearSitemapCache', function() { + app.alertSuccess('Sitemap Cache Cleared!'); + }); + return false; }); if (typeof callback === 'function') { diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index cc7c0cbff1..cd87159420 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -275,8 +275,10 @@ $(document).ready(function() { // Enhancing all anchors to ajaxify... $(document.body).on('click', 'a', function (e) { - if (hrefEmpty(this.href) || this.target !== '' || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { + if (this.target !== '') { return; + } else if (hrefEmpty(this.href) || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { + return e.preventDefault(); } if (!window.location.pathname.match(/\/(403|404)$/g)) { diff --git a/public/src/app.js b/public/src/app.js index 35037c8033..5010ead25d 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -10,10 +10,6 @@ app.currentRoom = null; app.widgets = {}; app.cacheBuster = null; -// TODO: deprecate in 0.7.0, use app.user -app.username = null; -app.uid = null; - (function () { var showWelcomeMessage = false; var reconnecting = false; @@ -29,14 +25,7 @@ app.uid = null; socket = io.connect(config.websocketAddress, ioParams); reconnecting = false; - socket.on('event:connect', function (data) { - // TODO : deprecate in 0.7.0, use app.user - app.username = data.username; - app.userslug = data.userslug; - app.picture = data.picture; - app.uid = data.uid; - app.isAdmin = data.isAdmin; - + socket.on('event:connect', function () { app.showLoginMessage(); app.replaceSelfLinks(); $(window).trigger('action:connected'); @@ -182,9 +171,9 @@ app.uid = null; socket.emit('meta.rooms.enter', { enter: room, - username: app.username, - userslug: app.userslug, - picture: app.picture + username: app.user.username, + userslug: app.user.userslug, + picture: app.user.picture }); app.currentRoom = room; @@ -232,8 +221,8 @@ app.uid = null; selector = selector || $('a'); selector.each(function() { var href = $(this).attr('href'); - if (href && app.userslug && href.indexOf('user/_self_') !== -1) { - $(this).attr('href', href.replace(/user\/_self_/g, 'user/' + app.userslug)); + if (href && app.user.userslug && href.indexOf('user/_self_') !== -1) { + $(this).attr('href', href.replace(/user\/_self_/g, 'user/' + app.user.userslug)); } }); }; @@ -261,7 +250,7 @@ app.uid = null; function showAlert() { app.alert({ type: 'success', - title: '[[global:welcome_back]] ' + app.username + '!', + title: '[[global:welcome_back]] ' + app.user.username + '!', message: '[[global:you_have_successfully_logged_in]]', timeout: 5000 }); @@ -278,11 +267,11 @@ app.uid = null; }; app.openChat = function (username, touid) { - if (username === app.username) { + if (username === app.user.username) { return app.alertError('[[error:cant-chat-with-yourself]]'); } - if (!app.uid) { + if (!app.user.uid) { return app.alertError('[[error:not-logged-in]]'); } @@ -436,7 +425,7 @@ app.uid = null; e.preventDefault(); var input = $(this).find('input'); - search.query({term: input.val(), in: 'posts'}, function() { + search.query({term: input.val()}, function() { input.val(''); }); }); diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index f85e00951c..86e5d1f66d 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -152,7 +152,7 @@ define('forum/account/edit', ['forum/account/header', 'uploader'], function(head return; } - if ($('#confirm-username').val() !== app.username) { + if ($('#confirm-username').val() !== app.user.username) { app.alertError('[[error:invalid-username]]'); return false; } else { @@ -266,12 +266,15 @@ define('forum/account/edit', ['forum/account/header', 'uploader'], function(head password_confirm.on('blur', onPasswordConfirmChanged); $('#changePasswordBtn').on('click', function() { - if ((passwordvalid && passwordsmatch) || app.isAdmin) { + var btn = $(this); + if ((passwordvalid && passwordsmatch) || app.user.isAdmin) { + btn.addClass('disabled').find('i').removeClass('hide'); socket.emit('user.changePassword', { 'currentPassword': currentPassword.val(), 'newPassword': password.val(), 'uid': ajaxify.variables.get('theirid') }, function(err) { + btn.removeClass('disabled').find('i').addClass('hide'); currentPassword.val(''); password.val(''); password_confirm.val(''); diff --git a/public/src/client/account/groups.js b/public/src/client/account/groups.js new file mode 100644 index 0000000000..ea70433de3 --- /dev/null +++ b/public/src/client/account/groups.js @@ -0,0 +1,21 @@ +'use strict'; + +/* globals define, app, socket, utils */ + +define('forum/account/groups', ['forum/account/header'], function(header) { + var AccountTopics = {}; + + AccountTopics.init = function() { + header.init(); + + var groupsEl = $('#groups-list'); + + groupsEl.on('click', '.list-cover', function() { + var groupSlug = $(this).parents('[data-slug]').attr('data-slug'); + + ajaxify.go('groups/' + groupSlug); + }); + }; + + return AccountTopics; +}); diff --git a/public/src/client/account/header.js b/public/src/client/account/header.js index f0a0c112fa..6dcc0b27e4 100644 --- a/public/src/client/account/header.js +++ b/public/src/client/account/header.js @@ -1,3 +1,6 @@ +'use strict'; +/* globals define, app, ajaxify */ + define('forum/account/header', function() { var AccountHeader = {}; @@ -7,10 +10,11 @@ define('forum/account/header', function() { }; function displayAccountMenus() { - $('.account-sub-links .plugin-link').each(function() { - var $this = $(this); - $this.toggleClass('hide', $this.hasClass('private')); - }); + if (!app.user.uid || app.user.uid !== parseInt(ajaxify.variables.get('theirid'), 10)) { + $('.account-sub-links .plugin-link.private').each(function() { + $(this).addClass('hide'); + }); + } } function selectActivePill() { diff --git a/public/src/client/account/profile.js b/public/src/client/account/profile.js index 421fc006ef..89a555a702 100644 --- a/public/src/client/account/profile.js +++ b/public/src/client/account/profile.js @@ -41,6 +41,9 @@ define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll'] function processPage() { $('.user-recent-posts img, .post-signature img').addClass('img-responsive'); + + $('.user-recent-posts blockquote').prev('p').remove(); + $('.user-recent-posts blockquote').remove(); } function updateButtons() { diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js index 0b4bbbd00f..fef95fc495 100644 --- a/public/src/client/account/settings.js +++ b/public/src/client/account/settings.js @@ -44,7 +44,7 @@ define('forum/account/settings', ['forum/account/header'], function(header) { } app.exposeConfigToTemplates(); - if (parseInt(app.uid, 10) === parseInt(ajaxify.variables.get('theirid'), 10)) { + if (parseInt(app.user.uid, 10) === parseInt(ajaxify.variables.get('theirid'), 10)) { ajaxify.refresh(); } }); diff --git a/public/src/client/account/watched.js b/public/src/client/account/watched.js index bd0e8282dd..9a502b1ee8 100644 --- a/public/src/client/account/watched.js +++ b/public/src/client/account/watched.js @@ -11,7 +11,6 @@ define('forum/account/watched', ['forum/account/header', 'forum/infinitescroll'] }; function loadMore(direction) { - console.log(direction); if (direction < 0) { return; } diff --git a/public/src/client/home.js b/public/src/client/categories.js similarity index 67% rename from public/src/client/home.js rename to public/src/client/categories.js index 23049af741..6840f69e89 100644 --- a/public/src/client/home.js +++ b/public/src/client/categories.js @@ -2,35 +2,34 @@ /* globals define, socket, app, templates, translator, ajaxify*/ -define('forum/home', function() { - var home = {}; +define('forum/categories', function() { + var categories = {}; $(window).on('action:ajaxify.start', function(ev, data) { - if (data.tpl_url !== 'home') { - socket.removeListener('event:new_post', home.onNewPost); + if (data.tpl_url !== 'categories') { + socket.removeListener('event:new_post', categories.onNewPost); } }); + categories.init = function() { + app.enterRoom('categories'); - home.init = function() { - app.enterRoom('home'); + socket.removeListener('event:new_post', categories.onNewPost); + socket.on('event:new_post', categories.onNewPost); - socket.removeListener('event:new_post', home.onNewPost); - socket.on('event:new_post', home.onNewPost); - - $('.home .category-header').tooltip({ + $('.category-header').tooltip({ placement: 'bottom' }); }; - home.onNewPost = function(data) { + categories.onNewPost = function(data) { if (data && data.posts && data.posts.length && data.posts[0].topic) { renderNewPost(data.posts[0].topic.cid, data.posts[0]); } }; function renderNewPost(cid, post) { - var category = $('.home .category-item[data-cid="' + cid + '"]'); + var category = $('.category-item[data-cid="' + cid + '"]'); if (!category.length) { return; } @@ -59,12 +58,12 @@ define('forum/home', function() { recentPosts.last().remove(); } - $(window).trigger('action:posts.loaded'); + $(window).trigger('action:posts.loaded', {posts: [post]}); }); } function parseAndTranslate(posts, callback) { - templates.parse('home', 'posts', {categories: {posts: posts}}, function(html) { + templates.parse('categories', 'posts', {categories: {posts: posts}}, function(html) { translator.translate(html, function(translatedHTML) { translatedHTML = $(translatedHTML); translatedHTML.find('img').addClass('img-responsive'); @@ -74,5 +73,5 @@ define('forum/home', function() { }); } - return home; + return categories; }); diff --git a/public/src/client/categoryTools.js b/public/src/client/categoryTools.js index b94954626a..0e9bae608b 100644 --- a/public/src/client/categoryTools.js +++ b/public/src/client/categoryTools.js @@ -199,13 +199,8 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect'], function(move getTopicEl(data.tid).remove(); } - function onTopicPurged(tids) { - if (!tids) { - return; - } - for(var i=0; i Changing Password'); socket.emit('user.reset.commit', { code: reset_code, password: password.val() }, function(err) { - if(err) { + if (err) { + ajaxify.refresh(); return app.alertError(err.message); } - $('#error').addClass('hide').hide(); - $('#notice').addClass('hide').hide(); - $('#success').removeClass('hide').addClass('show').show(); + + window.location.href = RELATIVE_PATH + '/login'; }); } }); - socket.emit('user.reset.valid', reset_code, function(err, valid) { - if(err) { - return app.alertError(err.message); - } + // socket.emit('user.reset.valid', reset_code, function(err, valid) { + // if(err) { + // return app.alertError(err.message); + // } - if (valid) { - resetEl.prop('disabled', false); - } else { - var formEl = $('#reset-form'); - // Show error message - $('#error').show(); - formEl.remove(); - } - }); + // if (valid) { + // resetEl.prop('disabled', false); + // } else { + // var formEl = $('#reset-form'); + // // Show error message + // $('#error').show(); + // formEl.remove(); + // } + // }); }; return ResetCode; diff --git a/public/src/client/search.js b/public/src/client/search.js index e536aaa160..a8924ce8f9 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -9,41 +9,113 @@ define('forum/search', ['search'], function(searchModule) { var searchQuery = $('#results').attr('data-search-query'); $('#advanced-search #search-input').val(searchQuery); - var params = utils.params(); - var select = $('#advanced-search select'); - if (params && params.in) { - select.val(params.in); - } - if (params && params.by) { - $('.by-container #posted-by-input').val(params.by); - } + var searchIn = $('#advanced-search #search-in'); - select.on('change', function() { - $('.by-container').toggleClass('hide', select.val() !== 'posts'); + fillOutForm(); + + searchIn.on('change', function() { + updateFormItemVisiblity(searchIn.val()); }); highlightMatches(searchQuery); $('#advanced-search').off('submit').on('submit', function(e) { e.preventDefault(); - var input = $(this).find('#search-input'); - var searchIn = $(this).find('select'); - var postedBy = $(this).find('#posted-by-input'); - searchModule.query({ - term: input.val(), - in: searchIn.val(), - by: postedBy.val() - }, function() { + var input = $(this).find('#search-input'); + + var searchData = getSearchData(); + searchData.term = input.val(); + + searchModule.query(searchData, function() { input.val(''); }); }); + handleSavePreferences(); + enableAutoComplete(); }; + function getSearchData() { + var form = $('#advanced-search'); + var searchData = { + in: form.find('#search-in').val() + }; + + if (searchData.in === 'posts' || searchData.in === 'titlespost' || searchData.in === 'titles') { + searchData.by = form.find('#posted-by-user').val(); + searchData.categories = form.find('#posted-in-categories').val(); + searchData.searchChildren = form.find('#search-children').is(':checked'); + searchData.replies = form.find('#reply-count').val(); + searchData.repliesFilter = form.find('#reply-count-filter').val(); + searchData.timeFilter = form.find('#post-time-filter').val(); + searchData.timeRange = form.find('#post-time-range').val(); + searchData.sortBy = form.find('#post-sort-by').val(); + searchData.sortDirection = form.find('#post-sort-direction').val(); + searchData.showAs = form.find('#show-as-topics').is(':checked') ? 'topics' : 'posts'; + } + + return searchData; + } + + function updateFormItemVisiblity(searchIn) { + var hide = searchIn.indexOf('posts') === -1 && searchIn.indexOf('titles') === -1; + $('.post-search-item').toggleClass('hide', hide); + } + + function fillOutForm() { + var params = utils.params(); + var searchData = getSearchPreferences(); + params = utils.merge(searchData, params); + + if (params) { + if (params.in) { + $('#search-in').val(params.in); + updateFormItemVisiblity(params.in); + } + + if (params.by) { + $('#posted-by-user').val(params.by); + } + + if ((params['categories[]'] || params.categories)) { + $('#posted-in-categories').val(params['categories[]'] || params.categories); + } + + if (params.searchChildren) { + $('#search-children').prop('checked', true); + } + + if (params.replies) { + $('#reply-count').val(params.replies); + $('#reply-count-filter').val(params.repliesFilter); + } + + if (params.timeRange) { + $('#post-time-range').val(params.timeRange); + $('#post-time-filter').val(params.timeFilter); + } + + if (params.sortBy) { + $('#post-sort-by').val(params.sortBy); + $('#post-sort-direction').val(params.sortDirection); + } + + if (params.showAs) { + var isTopic = params.showAs === 'topics'; + var isPost = params.showAs === 'posts'; + $('#show-as-topics').prop('checked', isTopic).parent().toggleClass('active', isTopic); + $('#show-as-posts').prop('checked', isPost).parent().toggleClass('active', isPost); + } + } + } + function highlightMatches(searchQuery) { + if (!searchQuery) { + return; + } var searchTerms = searchQuery.split(' '); var regexes = []; for (var i=0; i 1 || !$('#post-container li[data-index="0"]').length) { + if($('#post-container .post-row').length > 1 || !$('#post-container [data-index="0"]').length) { $('.bottom-post-bar').removeClass('hide'); } } function hidePostToolsForDeletedPosts(element) { - element.find('li.deleted').each(function() { + element.find('.post-row.deleted').each(function() { postTools.toggle($(this).attr('data-pid'), true); }); } diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index 41a3d532bf..c3923e2720 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -61,7 +61,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func fork.init(); $('.posts').on('click', '.follow', function() { - socket.emit('topics.follow', tid, function(err, state) { + socket.emit('topics.toggleFollow', tid, function(err, state) { if(err) { return app.alert({ type: 'danger', @@ -99,7 +99,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func ThreadTools.setLockedState = function(data) { var threadEl = $('#post-container'); if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { - var isLocked = data.isLocked && !app.isAdmin; + var isLocked = data.isLocked && !app.user.isAdmin; $('.lock_thread').translateHtml(' [[topic:thread_tools.' + (data.isLocked ? 'un': '') + 'lock]]'); diff --git a/public/src/client/users.js b/public/src/client/users.js index b96f3f5501..c3f374c4ff 100644 --- a/public/src/client/users.js +++ b/public/src/client/users.js @@ -115,11 +115,6 @@ define('forum/users', function() { var username = $('#search-user').val(); var notify = $('#user-notfound-notify'); page = page || 1; - if (!username) { - notify.html(''); - notify.parent().removeClass('btn-warning label-warning btn-success label-success'); - return; - } notify.html(''); var filters = []; diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 02fcbba02e..06e8c75c7d 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -74,7 +74,7 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, } var username = data.message.fromUser.username; - var isSelf = parseInt(data.message.fromUser.uid, 10) === parseInt(app.uid, 10); + var isSelf = parseInt(data.message.fromUser.uid, 10) === parseInt(app.user.uid, 10); data.message.self = data.self; if (isSelf) { username = data.message.toUser.username; diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 5a80616517..29154d1523 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -68,13 +68,13 @@ define('composer', [ }); // Construct a save_id - if (0 !== parseInt(app.uid, 10)) { + if (0 !== parseInt(app.user.uid, 10)) { if (post.hasOwnProperty('cid')) { - post.save_id = ['composer', app.uid, 'cid', post.cid].join(':'); + post.save_id = ['composer', app.user.uid, 'cid', post.cid].join(':'); } else if (post.hasOwnProperty('tid')) { - post.save_id = ['composer', app.uid, 'tid', post.tid].join(':'); + post.save_id = ['composer', app.user.uid, 'tid', post.tid].join(':'); } else if (post.hasOwnProperty('pid')) { - post.save_id = ['composer', app.uid, 'pid', post.pid].join(':'); + post.save_id = ['composer', app.user.uid, 'pid', post.pid].join(':'); } } @@ -183,7 +183,7 @@ define('composer', [ function emit() { socket.emit('modules.composer.notifyTyping', { tid: postData.tid, - uid: app.uid + uid: app.user.uid }); } @@ -203,7 +203,7 @@ define('composer', [ } socket.emit('modules.composer.stopNotifyTyping', { tid: postData.tid, - uid: app.uid + uid: app.user.uid }); } @@ -219,7 +219,7 @@ define('composer', [ isTopic = composer.posts[post_uuid] ? !!composer.posts[post_uuid].cid : false, isMain = composer.posts[post_uuid] ? !!composer.posts[post_uuid].isMain : false, isEditing = composer.posts[post_uuid] ? !!composer.posts[post_uuid].pid : false, - isGuestPost = composer.posts[post_uuid] ? composer.posts[post_uuid].uid === '0' : null; + isGuestPost = composer.posts[post_uuid] ? parseInt(composer.posts[post_uuid].uid, 10) === 0 : null; composer.bsEnvironment = utils.findBootstrapEnvironment(); @@ -228,6 +228,8 @@ define('composer', [ var data = { allowTopicsThumbnail: allowTopicsThumbnail, showTags: isTopic || isMain, + minimumTagLength: config.minimumTagLength, + maximumTagLength: config.maximumTagLength, isTopic: isTopic, showHandleInput: (app.user.uid === 0 || (isEditing && isGuestPost && app.user.isAdmin)) && config.allowGuestHandles, handle: composer.posts[post_uuid] ? composer.posts[post_uuid].handle || '' : undefined @@ -406,6 +408,8 @@ define('composer', [ return composerAlert('[[error:invalid-title]]'); } else if (bodyEl.val().length < parseInt(config.minimumPostLength, 10)) { return composerAlert('[[error:content-too-short, ' + config.minimumPostLength + ']]'); + } else if (bodyEl.val().length > parseInt(config.maximumPostLength, 10)) { + return composerAlert('[[error:content-too-long, ' + config.maximumPostLength + ']]'); } var composerData = {}, action; diff --git a/public/src/modules/composer/tags.js b/public/src/modules/composer/tags.js index 93b33fbb38..f074a5abc2 100644 --- a/public/src/modules/composer/tags.js +++ b/public/src/modules/composer/tags.js @@ -14,7 +14,17 @@ define('composer/tags', function() { tagEl.tagsinput({ maxTags: config.tagsPerTopic, - confirmKeys: [13, 44] + confirmKeys: [13, 44], + trimValue: true + }); + + tagEl.on('beforeItemAdd', function(event) { + event.cancel = event.item.length < config.minimumTagLength || event.item.length > config.maximumTagLength; + if (event.item.length < config.minimumTagLength) { + app.alertError('[[error:tag-too-short, ' + config.minimumTagLength + ']]'); + } else if (event.item.length > config.maximumTagLength) { + app.alertError('[[error:tag-too-long, ' + config.maximumTagLength + ']]'); + } }); tagEl.on('itemAdded', function(event) { diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index bc40bde658..e8f77a5614 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -4,7 +4,7 @@ // export the class if we are in a Node-like system. if (typeof module === 'object' && module.exports === exports) { - exports = module.exports/* = SemVer*/; + exports = module.exports/* = SemVer*/; } var helpers = {}; @@ -21,6 +21,11 @@ return ''; }; + helpers.stringify = function(obj) { + // Turns the incoming object into a JSON string + return JSON.stringify(obj).replace(/&/gm,"&").replace(//gm,">").replace(/"/g, '"'); + }; + // Groups helpers helpers.membershipBtn = function(groupObj) { if (groupObj.isMember) { diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index 319d88041f..8ce107f20a 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -2,7 +2,6 @@ /* globals define, socket, translator, utils, config, app, ajaxify, Tinycon*/ - define('notifications', ['sounds'], function(sound) { var Notifications = {}; @@ -14,54 +13,44 @@ define('notifications', ['sounds'], function(sound) { notifTrigger.on('click', function(e) { e.preventDefault(); - if (!notifContainer.hasClass('open')) { - - socket.emit('notifications.get', null, function(err, data) { - - function createNotification(notification, callback) { - if (notification.image) { - image = ''; - } else { - image = ''; - } - - return '
  • ' + image + '' + $.timeago(new Date(parseInt(notification.datetime, 10))) + '' + notification.bodyShort + '
  • '; - } - - var x, html = ''; - - // Switch to shorthand - translator.toggleTimeagoShorthand(); - - if (!err && (data.read.length + data.unread.length) > 0) { - var image = ''; - for (x = 0; x < data.unread.length; x++) { - html += createNotification(data.unread[x]); - } - - for (x = 0; x < data.read.length; x++) { - html += createNotification(data.read[x]); - } - } else { - html += '
  • [[notifications:no_notifs]]
  • '; - } - - // Switch back to original timeago strings - translator.toggleTimeagoShorthand(); - - html += ''; - - notifList.translateHtml(html); - - updateNotifCount(data.unread.length); - - socket.emit('modules.notifications.markAllRead', null, function(err) { - if (!err) { - updateNotifCount(0); - } - }); - }); + if (notifContainer.hasClass('open')) { + return; } + + socket.emit('notifications.get', null, function(err, data) { + if (err) { + return app.alertError(err.message); + } + + var notifs = data.unread.concat(data.read); + + translator.toggleTimeagoShorthand(); + for(var i=0; i 0) { + query.replies = data.replies; + query.repliesFilter = data.repliesFilter || 'atleast'; + } + + if (data.timeRange) { + query.timeRange = data.timeRange; + query.timeFilter = data.timeFilter || 'newer'; + } + + if (data.sortBy) { + query.sortBy = data.sortBy; + query.sortDirection = data.sortDirection; + } + + if (data.showAs) { + query.showAs = data.showAs; + } + return decodeURIComponent($.param(query)); + } + Search.queryTopic = function(tid, term, callback) { socket.emit('topics.search', { tid: tid, diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index d2f7612c0e..6efdbd988c 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -49,7 +49,7 @@ define('uploader', ['csrf'], function(csrf) { }, error: function(xhr) { xhr = maybeParse(xhr); - showAlert('error', xhr.responseJSON.error); + showAlert('error', xhr.responseJSON ? xhr.responseJSON.error : 'error uploading, code : ' + xhr.status); }, uploadProgress: function(event, position, total, percent) { diff --git a/public/src/utils.js b/public/src/utils.js index b9658593cc..3b82573c9b 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -204,7 +204,15 @@ tags : ['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], - stripTags : ['abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'base', 'basefont', 'bdi', 'bdo', 'big', 'body', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'iframe', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'source', 'span', 'strike', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], + stripTags : ['abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'base', 'basefont', + 'bdi', 'bdo', 'big', 'blink', 'body', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', + 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', + 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'head', 'header', 'hr', 'html', 'iframe', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', + 'map', 'mark', 'marquee', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', + 'output', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', + 'source', 'span', 'strike', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', + 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], escapeRegexChars: function(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); @@ -256,7 +264,14 @@ value = options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1])); if (key) { - hash[key] = value; + if (!hash[key]) { + hash[key] = value; + } else { + if (!$.isArray(hash[key])) { + hash[key] = [hash[key]]; + } + hash[key].push(value); + } } }); return hash; diff --git a/public/src/widgets.js b/public/src/widgets.js index 9e34ba9513..936ce9cd95 100644 --- a/public/src/widgets.js +++ b/public/src/widgets.js @@ -51,12 +51,11 @@ if (!area.length && window.location.pathname.indexOf('/admin') === -1 && renderedWidgets.length) { if (location === 'footer' && !$('#content [widget-area="footer"]').length) { - $('#content').append($('
    ')); + $('#content').append($('
    ')); } else if (location === 'sidebar' && !$('#content [widget-area="sidebar"]').length) { - $('#content > *').wrapAll($('
    ')); - $('#content').append($('
    ')); + $('#content > *').wrapAll($('
    ')); } else if (location === 'header' && !$('#content [widget-area="header"]').length) { - $('#content').prepend($('
    ')); + $('#content').prepend($('
    ')); } area = $('#content [widget-area="' + location + '"]'); @@ -69,11 +68,11 @@ ajaxify.widgets.reposition(location); } - $('#content [widget-area] img:not(.user-img)').addClass('img-responsive'); + $('#content [widget-area] img:not(.user-img)').addClass('img-responsive'); } - + $(window).trigger('action:widgets.loaded', {}); - + if (typeof callback === 'function') { callback(); } diff --git a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css index 98cfa7f3c1..55f7c09df0 100644 --- a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css +++ b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css @@ -10,6 +10,7 @@ border-radius: 4px; max-width: 100%; line-height: 22px; + cursor: text; } .bootstrap-tagsinput input { border: none; diff --git a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js index aff7ea6cb8..d9047ac1ec 100644 --- a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js +++ b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js @@ -1,506 +1,6 @@ -(function ($) { - "use strict"; +/* + * bootstrap-tagsinput v0.4.2 by Tim Schlechter + * + */ - var defaultOptions = { - tagClass: function(item) { - return 'label label-info'; - }, - itemValue: function(item) { - return item ? item.toString() : item; - }, - itemText: function(item) { - return this.itemValue(item); - }, - freeInput: true, - maxTags: undefined, - confirmKeys: [13], - onTagExists: function(item, $tag) { - $tag.hide().fadeIn(); - } - }; - - /** - * Constructor function - */ - function TagsInput(element, options) { - this.itemsArray = []; - - this.$element = $(element); - this.$element.hide(); - - this.isSelect = (element.tagName === 'SELECT'); - this.multiple = (this.isSelect && element.hasAttribute('multiple')); - this.objectItems = options && options.itemValue; - this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; - this.inputSize = Math.max(1, this.placeholderText.length); - - this.$container = $('
    '); - this.$input = $('').appendTo(this.$container); - - this.$element.after(this.$container); - - this.build(options); - } - - TagsInput.prototype = { - constructor: TagsInput, - - /** - * Adds the given item as a new tag. Pass true to dontPushVal to prevent - * updating the elements val() - */ - add: function(item, dontPushVal) { - var self = this; - - if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) - return; - - // Ignore falsey values, except false - if (item !== false && !item) - return; - - // Throw an error when trying to add an object while the itemValue option was not set - if (typeof item === "object" && !self.objectItems) - throw("Can't add objects when itemValue option is not set"); - - // Ignore strings only containg whitespace - if (item.toString().match(/^\s*$/)) - return; - - // If SELECT but not multiple, remove current tag - if (self.isSelect && !self.multiple && self.itemsArray.length > 0) - self.remove(self.itemsArray[0]); - - if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { - var items = item.split(','); - if (items.length > 1) { - for (var i = 0; i < items.length; i++) { - this.add(items[i], true); - } - - if (!dontPushVal) - self.pushVal(); - return; - } - } - - var itemValue = self.options.itemValue(item), - itemText = self.options.itemText(item), - tagClass = self.options.tagClass(item); - - // Ignore items allready added - var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; - if (existing) { - // Invoke onTagExists - if (self.options.onTagExists) { - var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); - self.options.onTagExists(item, $existingTag); - } - return; - } - - // register item in internal array and map - self.itemsArray.push(item); - - // add a tag element - var $tag = $('' + htmlEncode(itemText) + ''); - $tag.data('item', item); - self.findInputWrapper().before($tag); - $tag.after(' '); - - // add
    ")}}))}if(e.options.typeaheadjs){var j=e.options.typeaheadjs||{};e.$input.typeahead(null,j).on("typeahead:selected",a.proxy(function(a,b){e.add(j.valueKey?b[j.valueKey]:b),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}{var k=c.val().length;Math.ceil(k/5)}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val(""),b.preventDefault());{var h=c.val().length;Math.ceil(h/5)}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d){var e=[];return this.each(function(){var f=a(this).data("tagsinput");if(f)if(c||d){if(void 0!==f[c]){var g=f[c](d);void 0!==g&&e.push(g)}}else e.push(f);else f=new b(this,c),a(this).data("tagsinput",f),e.push(f),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?e.length>1?e:e[0]:e},a.fn.tagsinput.Constructor=b;var i=a("
    ");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery); diff --git a/src/categories.js b/src/categories.js index 22c7807c96..a4b6ce2092 100644 --- a/src/categories.js +++ b/src/categories.js @@ -64,7 +64,9 @@ var async = require('async'), category.isIgnored = results.isIgnored[0]; category.topic_row_size = 'col-md-9'; - callback(null, category); + plugins.fireHook('filter:category.get', {category: category, uid: data.uid}, function(err, data) { + callback(err, data ? data.category : null); + }); }); }); }; diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index bb1ae32775..596bd6882e 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -103,7 +103,10 @@ module.exports = function(Categories) { pids = pids.concat(topicPids).filter(function(pid, index, array) { return !!pid && array.indexOf(pid) === index; - }); + }).sort(function(a, b) { + return b - a; + }).slice(0, count); + callback(null, pids); }); }); diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 741de9a626..13055ca852 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -233,6 +233,29 @@ accountsController.getTopics = function(req, res, next) { getFromUserSet('account/topics', 'topics', topics.getTopicsFromSet, 'topics', req, res, next); }; +accountsController.getGroups = function(req, res, next) { + var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; + + getBaseUser(req.params.userslug, callerUID, function(err, userData) { + if (err) { + return next(err); + } + + if (!userData) { + return helpers.notFound(req, res); + } + + groups.getUserGroups([userData.uid], function(err, groups) { + if (err) { + return next(err); + } + + userData.groups = groups[0]; + + res.render('account/groups', userData); + }); + }); +}; function getFromUserSet(tpl, set, method, type, req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; @@ -415,7 +438,7 @@ accountsController.uploadPicture = function (req, res, next) { user.setUserFields(updateUid, {uploadedpicture: image.url, picture: image.url}); - res.json([{name: userPhoto.name, url: image.url}]); + res.json([{name: userPhoto.name, url: nconf.get('relative_path') + image.url}]); } if (err) { @@ -443,7 +466,7 @@ accountsController.uploadPicture = function (req, res, next) { fs.unlink(absolutePath, function (err) { if (err) { - winston.err(err); + winston.error(err); } file.saveFileToLocal(filename, 'profile', userPhoto.path, done); @@ -498,9 +521,10 @@ accountsController.getChats = function(req, res, next) { async.waterfall([ async.apply(user.getUidByUserslug, req.params.userslug), function(toUid, next) { - if (!toUid) { + if (!toUid || parseInt(toUid, 10) === parseInt(req.user.uid, 10)) { return helpers.notFound(req, res); } + async.parallel({ toUser: async.apply(user.getUserFields, toUid, ['uid', 'username']), messages: async.apply(messaging.getMessages, req.user.uid, toUid, 'recent', false), diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 5ccfa3a6df..f03b7fdb88 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -113,11 +113,17 @@ function getStatsForSet(set, field, callback) { db.sortedSetCount(set, now - terms.month, now, next); }, alltime: function(next) { - db.getObjectField('global', field, next); + getGlobalField(field, next); } }, callback); } +function getGlobalField(field, callback) { + db.getObjectField('global', field, function(err, count) { + callback(err, parseInt(count, 10) || 0); + }); +} + adminController.categories.active = function(req, res, next) { filterAndRenderCategories(req, res, next, true); }; @@ -174,14 +180,14 @@ adminController.database.get = function(req, res, next) { }; adminController.events.get = function(req, res, next) { - events.getLog(-1, 5000, function(err, data) { - if(err || !data) { + events.getEvents(0, 19, function(err, events) { + if(err || !events) { return next(err); } res.render('admin/advanced/events', { - eventdata: data.data, - next: data.next + events: events, + next: 20 }); }); }; diff --git a/src/controllers/admin/uploads.js b/src/controllers/admin/uploads.js index 9ba3ad049c..81a98ed151 100644 --- a/src/controllers/admin/uploads.js +++ b/src/controllers/admin/uploads.js @@ -30,7 +30,7 @@ uploadsController.uploadFavicon = function(req, res, next) { var uploadedFile = req.files.files[0]; var allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon']; - if (validateUpload(res, req, next, uploadedFile, allowedTypes)) { + if (validateUpload(req, res, next, uploadedFile, allowedTypes)) { file.saveFileToLocal('favicon.ico', 'files', uploadedFile.path, function(err, image) { fs.unlink(uploadedFile.path); if (err) { @@ -63,7 +63,7 @@ function validateUpload(req, res, next, uploadedFile, allowedTypes) { if (allowedTypes.indexOf(uploadedFile.type) === -1) { fs.unlink(uploadedFile.path); - next(new Error('[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]')); + res.json({error: '[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]'}); return false; } diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index 17944b8370..283302b48e 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -31,7 +31,8 @@ usersController.banned = function(req, res, next) { }; function getUsers(set, req, res, next) { - user.getUsersFromSet(set, 0, 49, function(err, users) { + var uid = req.user ? parseInt(req.user.uid, 10) : 0; + user.getUsersFromSet(set, uid, 0, 49, function(err, users) { if (err) { return next(err); } diff --git a/src/controllers/api.js b/src/controllers/api.js index be4d8b2347..c335cdf272 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -23,6 +23,7 @@ apiController.getConfig = function(req, res, next) { config.minimumTitleLength = meta.config.minimumTitleLength; config.maximumTitleLength = meta.config.maximumTitleLength; config.minimumPostLength = meta.config.minimumPostLength; + config.maximumPostLength = meta.config.maximumPostLength; config.hasImageUploadPlugin = plugins.hasListeners('filter:uploadImage'); config.maximumProfileImageSize = meta.config.maximumProfileImageSize; config.minimumUsernameLength = meta.config.minimumUsernameLength; @@ -42,6 +43,8 @@ apiController.getConfig = function(req, res, next) { config.maxReconnectionAttempts = meta.config.maxReconnectionAttempts || 5; config.reconnectionDelay = meta.config.reconnectionDelay || 200; config.tagsPerTopic = meta.config.tagsPerTopic || 5; + config.minimumTagLength = meta.config.minimumTagLength || 3; + config.maximumTagLength = meta.config.maximumTagLength || 15; config.topicsPerPage = meta.config.topicsPerPage || 20; config.postsPerPage = meta.config.postsPerPage || 20; config.maximumFileSize = meta.config.maximumFileSize; diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 1783fd69b3..187653268d 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -3,6 +3,7 @@ var categoriesController = {}, async = require('async'), nconf = require('nconf'), + validator = require('validator'), privileges = require('../privileges'), user = require('../user'), categories = require('../categories'), @@ -22,7 +23,7 @@ categoriesController.recent = function(req, res, next) { } data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; - data['rssFeedUrl'] = nconf.get('relative_path') + '/recent.rss'; + data.rssFeedUrl = nconf.get('relative_path') + '/recent.rss'; data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[recent:title]]'}]); res.render('recent', data); }); @@ -92,6 +93,72 @@ categoriesController.unreadTotal = function(req, res, next) { }); }; +categoriesController.list = function(req, res, next) { + async.parallel({ + header: function (next) { + res.locals.metaTags = [{ + name: "title", + content: validator.escape(meta.config.title || 'NodeBB') + }, { + name: "description", + content: validator.escape(meta.config.description || '') + }, { + property: 'og:title', + content: 'Index | ' + validator.escape(meta.config.title || 'NodeBB') + }, { + property: 'og:type', + content: 'website' + }]; + + if(meta.config['brand:logo']) { + res.locals.metaTags.push({ + property: 'og:image', + content: meta.config['brand:logo'] + }); + } + + next(null); + }, + categories: function (next) { + var uid = req.user ? req.user.uid : 0; + categories.getCategoriesByPrivilege(uid, 'find', function (err, categoryData) { + if (err) { + return next(err); + } + var childCategories = []; + + for(var i=categoryData.length - 1; i>=0; --i) { + + if (Array.isArray(categoryData[i].children) && categoryData[i].children.length) { + childCategories.push.apply(childCategories, categoryData[i].children); + } + + if (categoryData[i].parent && categoryData[i].parent.cid) { + categoryData.splice(i, 1); + } + } + + async.parallel([ + function(next) { + categories.getRecentTopicReplies(categoryData, uid, next); + }, + function(next) { + categories.getRecentTopicReplies(childCategories, uid, next); + } + ], function(err) { + next(err, categoryData); + }); + }); + } + }, function (err, data) { + if (err) { + return next(err); + } + + res.render('categories', data); + }); +}; + categoriesController.get = function(req, res, next) { var cid = req.params.category_id, page = req.query.page || 1, @@ -259,9 +326,8 @@ categoriesController.get = function(req, res, next) { data.currentPage = page; data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; - data['rssFeedUrl'] = nconf.get('relative_path') + '/category/' + data.cid + '.rss'; - - pagination.create(data.currentPage, data.pageCount, data); + data.rssFeedUrl = nconf.get('relative_path') + '/category/' + data.cid + '.rss'; + data.pagination = pagination.create(data.currentPage, data.pageCount); data.pagination.rel.forEach(function(rel) { res.locals.linkTags.push(rel); diff --git a/src/controllers/groups.js b/src/controllers/groups.js index c20993a7df..8c29f2b397 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -2,6 +2,7 @@ var async = require('async'), nconf = require('nconf'), + meta = require('../meta'), groups = require('../groups'), user = require('../user'), helpers = require('./helpers'), @@ -17,7 +18,8 @@ groupsController.list = function(req, res, next) { return next(err); } res.render('groups/list', { - groups: groups + groups: groups, + allowGroupCreation: parseInt(meta.config.allowGroupCreation, 10) === 1 }); }); }; @@ -25,36 +27,43 @@ groupsController.list = function(req, res, next) { groupsController.details = function(req, res, next) { var uid = req.user ? parseInt(req.user.uid, 10) : 0; - async.parallel({ - group: function(next) { - groups.getByGroupslug(req.params.slug, { - expand: true, - uid: uid - }, next); - }, - posts: function(next) { - groups.getLatestMemberPosts(req.params.slug, 10, uid, next); - } - }, function(err, results) { - if (err) { - return next(err); - } + groups.existsBySlug(req.params.slug, function(err, exists) { + if (exists) { + async.parallel({ + group: function(next) { + groups.getByGroupslug(req.params.slug, { + expand: true, + uid: uid + }, next); + }, + posts: function(next) { + groups.getLatestMemberPosts(req.params.slug, 10, uid, next); + } + }, function(err, results) { + if (err) { + return next(err); + } - if (!results.group) { - return helpers.notFound(req, res); - } + if (!results.group) { + return helpers.notFound(req, res); + } - res.render('groups/details', results); + res.render('groups/details', results); + }); + } else { + return res.locals.isAPI ? res.status(302).json('/groups') : res.redirect('/groups'); + } }); }; groupsController.members = function(req, res, next) { + var uid = req.user ? parseInt(req.user.uid, 10) : 0; async.waterfall([ function(next) { groups.getGroupNameByGroupSlug(req.params.slug, next); }, function(groupName, next) { - user.getUsersFromSet('group:' + groupName + ':members', 0, 49, next); + user.getUsersFromSet('group:' + groupName + ':members', uid, 0, 49, next); }, ], function(err, users) { if (err) { diff --git a/src/controllers/index.js b/src/controllers/index.js index 797d30e22d..c8511c7c61 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -1,21 +1,10 @@ "use strict"; -var topicsController = require('./topics'), - categoriesController = require('./categories'), - tagsController = require('./tags'), - searchController = require('./search'), - usersController = require('./users'), - groupsController = require('./groups'), - accountsController = require('./accounts'), - staticController = require('./static'), - apiController = require('./api'), - adminController = require('./admin'), - helpers = require('./helpers'), - - async = require('async'), +var async = require('async'), nconf = require('nconf'), validator = require('validator'), winston = require('winston'), + auth = require('../routes/authentication'), meta = require('../meta'), user = require('../user'), @@ -23,92 +12,44 @@ var topicsController = require('./topics'), topics = require('../topics'), plugins = require('../plugins'), categories = require('../categories'), - privileges = require('../privileges'); + privileges = require('../privileges'), + helpers = require('./helpers'); var Controllers = { - topics: topicsController, - categories: categoriesController, - tags: tagsController, - search: searchController, - users: usersController, - groups: groupsController, - accounts: accountsController, - static: staticController, - api: apiController, - admin: adminController + topics: require('./topics'), + categories: require('./categories'), + tags: require('./tags'), + search: require('./search'), + users: require('./users'), + groups: require('./groups'), + accounts: require('./accounts'), + static: require('./static'), + api: require('./api'), + admin: require('./admin'), }; Controllers.home = function(req, res, next) { - async.parallel({ - header: function (next) { - res.locals.metaTags = [{ - name: "title", - content: validator.escape(meta.config.title || 'NodeBB') - }, { - name: "description", - content: validator.escape(meta.config.description || '') - }, { - property: 'og:title', - content: 'Index | ' + validator.escape(meta.config.title || 'NodeBB') - }, { - property: 'og:type', - content: 'website' - }]; - - if(meta.config['brand:logo']) { - res.locals.metaTags.push({ - property: 'og:image', - content: meta.config['brand:logo'] - }); - } - - next(null); - }, - categories: function (next) { - var uid = req.user ? req.user.uid : 0; - categories.getCategoriesByPrivilege(uid, 'find', function (err, categoryData) { - if (err) { - return next(err); - } - var childCategories = []; - - for(var i=categoryData.length - 1; i>=0; --i) { - - if (Array.isArray(categoryData[i].children) && categoryData[i].children.length) { - childCategories.push.apply(childCategories, categoryData[i].children); - } - - if (categoryData[i].parent && categoryData[i].parent.cid) { - categoryData.splice(i, 1); - } - } - - async.parallel([ - function(next) { - categories.getRecentTopicReplies(categoryData, uid, next); - }, - function(next) { - categories.getRecentTopicReplies(childCategories, uid, next); - } - ], function(err) { - next(err, categoryData); - }); - }); - } - }, function (err, data) { - if (err) { - return next(err); - } - res.render('home', data); - }); + var route = meta.config.homePageRoute || 'categories'; + if (route === 'categories') { + return Controllers.categories.list(req, res, next); + } else if (route === 'recent') { + Controllers.categories.recent(req, res, next); + } else if (route === 'popular') { + Controllers.categories.popular(req, res, next); + } else { + next(); + } }; Controllers.reset = function(req, res, next) { if (req.params.code) { - res.render('reset_code', { - reset_code: req.params.code ? req.params.code : null, - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]', url: '/reset'}, {text: '[[reset_password:update_password]]'}]) + user.reset.validate(req.params.code, function(err, valid) { + res.render('reset_code', { + valid: valid, + reset_code: req.params.code ? req.params.code : null, + breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]', url: '/reset'}, {text: '[[reset_password:update_password]]'}]) + }); }); } else { res.render('reset', { diff --git a/src/controllers/search.js b/src/controllers/search.js index 355fddeced..2020612094 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -5,6 +5,8 @@ var searchController = {}, validator = require('validator'), plugins = require('../plugins'), search = require('../search'), + categories = require('../categories'), + pagination = require('../pagination'), helpers = require('./helpers'); @@ -12,35 +14,75 @@ searchController.search = function(req, res, next) { if (!plugins.hasListeners('filter:search.query')) { return helpers.notFound(req, res); } - var breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]); - if (!req.params.term) { - return res.render('search', { - time: 0, - search_query: '', - posts: [], - topics: [], - users: [], - tags: [], - breadcrumbs: breadcrumbs - }); - } var uid = req.user ? req.user.uid : 0; + var breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]); - req.params.term = validator.escape(req.params.term); - - search.search({ - query: req.params.term, - searchIn: req.query.in, - postedBy: req.query.by, - uid: uid - }, function(err, results) { + categories.getCategoriesByPrivilege(uid, 'read', function(err, categories) { if (err) { return next(err); } - results.breadcrumbs = breadcrumbs; - res.render('search', results); + if (!req.params.term) { + var results = { + time: 0, + search_query: '', + posts: [], + users: [], + tags: [], + categories: categories, + breadcrumbs: breadcrumbs + }; + plugins.fireHook('filter:search.build', {data: {}, results: results}, function(err, data) { + if (err) { + return next(err); + } + res.render('search', data.results); + }); + return; + } + + req.params.term = validator.escape(req.params.term); + var page = Math.max(1, parseInt(req.query.page, 10)) || 1; + if (req.query.categories && !Array.isArray(req.query.categories)) { + req.query.categories = [req.query.categories]; + } + + var data = { + query: req.params.term, + searchIn: req.query.in || 'posts', + postedBy: req.query.by, + categories: req.query.categories, + searchChildren: req.query.searchChildren, + replies: req.query.replies, + repliesFilter: req.query.repliesFilter, + timeRange: req.query.timeRange, + timeFilter: req.query.timeFilter, + sortBy: req.query.sortBy, + sortDirection: req.query.sortDirection, + page: page, + uid: uid + }; + + search.search(data, function(err, results) { + if (err) { + return next(err); + } + + var pageCount = Math.max(1, Math.ceil(results.matchCount / 10)); + results.pagination = pagination.create(page, pageCount, req.query); + results.showAsPosts = !req.query.showAs || req.query.showAs === 'posts'; + results.showAsTopics = req.query.showAs === 'topics'; + results.breadcrumbs = breadcrumbs; + results.categories = categories; + + plugins.fireHook('filter:search.build', {data: data, results: results}, function(err, data) { + if (err) { + return next(err); + } + res.render('search', data.results); + }); + }); }); }; diff --git a/src/controllers/templates.js b/src/controllers/templates.js new file mode 100644 index 0000000000..dbf0be4870 --- /dev/null +++ b/src/controllers/templates.js @@ -0,0 +1,90 @@ +"use strict"; + +var async = require('async'), + nconf = require('nconf'), + fs = require('fs'), + path = require('path'), + meta = require('../meta'), + plugins = require('../plugins'), + utils = require('../../public/src/utils'), + templatesController = {}; + + +var availableTemplatesCache = null; +var configCache = null; + +templatesController.getTemplatesListing = function(req, res, next) { + async.parallel({ + availableTemplates: function(next) { + getAvailableTemplates(next); + }, + templatesConfig: function(next) { + async.waterfall([ + function(next) { + readConfigFile(next); + }, + function(config, next) { + config.custom_mapping['^/?$'] = meta.config.homePageRoute || 'categories'; + + plugins.fireHook('filter:templates.get_config', config, next); + } + ], next); + }, + }, function(err, results) { + if (err) { + return next(err); + } + + res.json(results); + }); +}; + +function readConfigFile(callback) { + if (configCache) { + return callback(null, configCache); + } + fs.readFile(path.join(nconf.get('views_dir'), 'config.json'), function(err, config) { + if (err) { + return callback(err); + } + try { + config = JSON.parse(config.toString()); + } catch (err) { + return callback(err); + } + configCache = config; + callback(null, config); + }); +} + +function getAvailableTemplates(callback) { + if (availableTemplatesCache) { + return callback(null, availableTemplatesCache); + } + + async.parallel({ + views: function(next) { + utils.walk(nconf.get('views_dir'), next); + }, + extended: function(next) { + plugins.fireHook('filter:templates.get_virtual', [], next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + var availableTemplates = results.views.filter(function(value, index, self) { + return value && self.indexOf(value) === index; + }).map(function(el) { + return el && el.replace(nconf.get('views_dir') + '/', ''); + }); + + availableTemplatesCache = availableTemplates.concat(results.extended); + callback(null, availableTemplatesCache); + }); + +} + + + +module.exports = templatesController; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 6b3b42ab93..498a3d81db 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -54,7 +54,7 @@ topicsController.get = function(req, res, next) { var settings = results.settings; var postCount = parseInt(results.topic.postcount, 10); - var pageCount = Math.ceil((postCount - 1) / settings.postsPerPage); + var pageCount = Math.max(1, Math.ceil((postCount - 1) / settings.postsPerPage)); if (utils.isNumber(req.params.post_index)) { var url = ''; @@ -89,17 +89,23 @@ topicsController.get = function(req, res, next) { var postIndex = 0; page = parseInt(req.query.page, 10) || 1; req.params.post_index = parseInt(req.params.post_index, 10) || 0; + if (reverse && req.params.post_index === 1) { + req.params.post_index = 0; + } if (!settings.usePagination) { if (reverse) { - if (req.params.post_index === 1) { - req.params.post_index = 0; - } - postIndex = Math.max(postCount - (req.params.post_index || postCount) - (settings.postsPerPage - 1), 0); + postIndex = Math.max(0, postCount - (req.params.post_index || postCount) - (settings.postsPerPage - 1)); } else { - postIndex = Math.max((req.params.post_index || 1) - (settings.postsPerPage + 1), 0); + postIndex = Math.max(0, (req.params.post_index || 1) - (settings.postsPerPage + 1)); } } else if (!req.query.page) { - var index = Math.max(req.params.post_index - 1, 0) || 0; + var index = 0; + if (reverse) { + index = Math.max(0, postCount - (req.params.post_index || postCount)); + } else { + index = Math.max(0, req.params.post_index - 1) || 0; + } + page = Math.max(1, Math.ceil(index / settings.postsPerPage)); } @@ -116,15 +122,13 @@ topicsController.get = function(req, res, next) { } topicData.pageCount = pageCount; - topicData.currentPage = page; - if(page > 1) { + + if (page > 1) { topicData.posts.splice(0, 1); } - plugins.fireHook('filter:controllers.topic.get', topicData, function(err, topicData) { - next(null, topicData); - }); + plugins.fireHook('filter:controllers.topic.get', topicData, next); }); }, function (topicData, next) { @@ -256,15 +260,12 @@ topicsController.get = function(req, res, next) { data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; data['rssFeedUrl'] = nconf.get('relative_path') + '/topic/' + data.tid + '.rss'; - - topics.increaseViewCount(tid); - - pagination.create(data.currentPage, data.pageCount, data); - + data.pagination = pagination.create(data.currentPage, data.pageCount); data.pagination.rel.forEach(function(rel) { res.locals.linkTags.push(rel); }); + topics.increaseViewCount(tid); res.render('topic', data); }); }; diff --git a/src/controllers/users.js b/src/controllers/users.js index 0a2d4d0d67..81001d0f3a 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -14,7 +14,7 @@ usersController.getOnlineUsers = function(req, res, next) { async.parallel({ users: function(next) { - user.getUsersFromSet('users:online', 0, 49, next); + user.getUsersFromSet('users:online', uid, 0, 49, next); }, count: function(next) { var now = Date.now(); @@ -63,7 +63,7 @@ usersController.getUsersSortedByJoinDate = function(req, res, next) { usersController.getUsers = function(set, count, req, res, next) { var uid = req.user ? req.user.uid : 0; - getUsersAndCount(set, count, function(err, data) { + getUsersAndCount(set, uid, count, function(err, data) { if (err) { return next(err); } @@ -78,10 +78,10 @@ usersController.getUsers = function(set, count, req, res, next) { }); }; -function getUsersAndCount(set, count, callback) { +function getUsersAndCount(set, uid, count, callback) { async.parallel({ users: function(next) { - user.getUsersFromSet(set, 0, count - 1, next); + user.getUsersFromSet(set, uid, 0, count - 1, next); }, count: function(next) { db.getObjectField('global', 'userCount', next); @@ -102,7 +102,7 @@ usersController.getUsersForSearch = function(req, res, next) { var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 20, uid = req.user ? req.user.uid : 0; - getUsersAndCount('users:joindate', resultsPerPage, function(err, data) { + getUsersAndCount('users:joindate', uid, resultsPerPage, function(err, data) { if (err) { return next(err); } diff --git a/src/database/redis/list.js b/src/database/redis/list.js index 115a56a767..7ebc068d53 100644 --- a/src/database/redis/list.js +++ b/src/database/redis/list.js @@ -2,34 +2,40 @@ module.exports = function(redisClient, module) { module.listPrepend = function(key, value, callback) { + callback = callback || function() {}; redisClient.lpush(key, value, function(err, res) { callback(err); }); }; module.listAppend = function(key, value, callback) { + callback = callback || function() {}; redisClient.rpush(key, value, function(err, res) { callback(err); }); }; module.listRemoveLast = function(key, callback) { + callback = callback || function() {}; redisClient.rpop(key, callback); }; module.listRemoveAll = function(key, value, callback) { + callback = callback || function() {}; redisClient.lrem(key, 0, value, function(err, res) { callback(err); }); }; module.listTrim = function(key, start, stop, callback) { + callback = callback || function() {}; redisClient.ltrim(key, start, stop, function(err, res) { callback(err); }); }; module.getListRange = function(key, start, stop, callback) { + callback = callback || function() {}; redisClient.lrange(key, start, stop, callback); }; }; \ No newline at end of file diff --git a/src/emailer.js b/src/emailer.js index 6eaf913e4c..557de96f6e 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -20,6 +20,7 @@ var fs = require('fs'), }; Emailer.send = function(template, uid, params, callback) { + if (!callback) { callback = function() {}; } if (!app) { winston.warn('[emailer] App not ready!'); return callback(); @@ -63,6 +64,7 @@ var fs = require('fs'), uid: uid, pid: params.pid }); + callback(); } else { winston.warn('[emailer] No active email plugin found!'); callback(); diff --git a/src/events.js b/src/events.js index bab042f28e..682e9549db 100644 --- a/src/events.js +++ b/src/events.js @@ -1,154 +1,128 @@ 'use strict'; -var fs = require('fs'), - winston = require('winston'), - path = require('path'), - nconf = require('nconf'), - user = require('./user'); +var async = require('async'), + + db = require('./database'), + batch = require('./batch'), + user = require('./user'), + utils = require('../public/src/utils'); (function(events) { - var logFileName = 'logs/events.log'; + events.log = function(data, callback) { + callback = callback || function() {}; - events.logPasswordChange = function(uid) { - events.logWithUser(uid, 'changed password'); + async.waterfall([ + function(next) { + db.incrObjectField('global', 'nextEid', next); + }, + function(eid, next) { + data.timestamp = Date.now(); + data.eid = eid; + + async.parallel([ + function(next) { + db.sortedSetAdd('events:time', data.timestamp, eid, next); + }, + function(next) { + db.setObject('event:' + eid, data, next); + } + ], next); + } + ], function(err, result) { + callback(err); + }); }; - events.logAdminChangeUserPassword = function(adminUid, theirUid, callback) { - logAdminEvent(adminUid, theirUid, 'changed password of', callback); + events.getEvents = function(start, stop, callback) { + async.waterfall([ + function(next) { + db.getSortedSetRevRange('events:time', start, stop, next); + }, + function(eids, next) { + var keys = eids.map(function(eid) { + return 'event:' + eid; + }); + db.getObjects(keys, next); + }, + function(eventsData, next) { + eventsData.forEach(function(event) { + var e = utils.merge(event); + e.eid = e.uid = e.type = e.ip = undefined; + event.jsonString = JSON.stringify(e, null, 4); + event.timestampISO = new Date(parseInt(event.timestamp, 10)).toUTCString(); + }); + addUserData(eventsData, 'uid', 'user', next); + }, + function(eventsData, next) { + addUserData(eventsData, 'targetUid', 'targetUser', next); + } + ], callback); }; - events.logAdminUserDelete = function(adminUid, theirUid, callback) { - logAdminEvent(adminUid, theirUid, 'deleted', callback); - }; + function addUserData(eventsData, field, objectName, callback) { + var uids = eventsData.map(function(event) { + return event && event[field]; + }).filter(function(uid, index, array) { + return uid && array.indexOf(uid) === index; + }); - function logAdminEvent(adminUid, theirUid, message, callback) { - user.getMultipleUserFields([adminUid, theirUid], ['username'], function(err, userData) { - if(err) { - return winston.error('Error logging event. ' + err.message); + if (!uids.length) { + return callback(null, eventsData); + } + + async.parallel({ + isAdmin: function(next) { + user.isAdministrator(uids, next); + }, + userData: function(next) { + user.getMultipleUserFields(uids, ['username', 'userslug', 'picture'], next); + } + }, function(err, results) { + if (err) { + return callback(err); } - var msg = userData[0].username + '(uid ' + adminUid + ') ' + message + ' ' + userData[1].username + '(uid ' + theirUid + ')'; - events.log(msg, callback); + var userData = results.userData; + + var map = {}; + userData.forEach(function(user, index) { + user.isAdmin = results.isAdmin[index]; + map[user.uid] = user; + }); + + eventsData.forEach(function(event) { + if (map[event[field]]) { + event[objectName] = map[event[field]]; + } + }); + callback(null, eventsData); }); } - events.logPasswordReset = function(uid) { - events.logWithUser(uid, 'reset password'); - }; - - events.logEmailChange = function(uid, oldEmail, newEmail) { - events.logWithUser(uid,'changed email from "' + oldEmail + '" to "' + newEmail +'"'); - }; - - events.logUsernameChange = function(uid, oldUsername, newUsername) { - events.logWithUser(uid,'changed username from "' + oldUsername + '" to "' + newUsername +'"'); - }; - - events.logAdminLogin = function(uid) { - events.logWithUser(uid, 'logged into admin panel'); - }; - - events.logPostEdit = function(uid, pid) { - events.logWithUser(uid, 'edited post (pid ' + pid + ')'); - }; - - events.logPostDelete = function(uid, pid) { - events.logWithUser(uid, 'deleted post (pid ' + pid + ')'); - }; - - events.logPostRestore = function(uid, pid) { - events.logWithUser(uid, 'restored post (pid ' + pid + ')'); - }; - - events.logPostPurge = function(uid, pid) { - events.logWithUser(uid, 'purged post (pid ' + pid + ')'); - }; - - events.logTopicMove = function(uid, tid) { - events.logWithUser(uid, 'moved topic (tid ' + tid + ')'); - }; - - events.logTopicDelete = function(uid, tid) { - events.logWithUser(uid, 'deleted topic (tid ' + tid + ')'); - }; - - events.logTopicRestore = function(uid, tid) { - events.logWithUser(uid, 'restored topic (tid ' + tid + ')'); - }; - - events.logAccountLock = function(uid, until) { - var date = new Date(); - date.setTime(date.getTime() + until); - - events.logWithUser(uid, 'locked out until ' + date.toString()); - }; - - events.logWithUser = function(uid, string) { - user.getUserField(uid, 'username', function(err, username) { - if(err) { - return winston.error('Error logging event. ' + err.message); + events.deleteEvents = function(eids, callback) { + callback = callback || function() {}; + async.parallel([ + function(next) { + var keys = eids.map(function(eid) { + return 'event:' + eid; + }); + db.deleteAll(keys, next); + }, + function(next) { + db.sortedSetRemove('events:time', eids, next); } - - var msg = username + '(uid ' + uid + ') ' + string; - events.log(msg); - }); + ], callback); }; - events.log = function(msg, callback) { - var logFile = path.join(nconf.get('base_dir'), logFileName); + events.deleteAll = function(callback) { + callback = callback || function() {}; - msg = '[' + new Date().toUTCString() + '] - ' + msg; - - fs.appendFile(logFile, msg + '\n', function(err) { - if(err) { - winston.error('Error logging event. ' + err.message); - if (typeof callback === 'function') { - callback(err); - } - return; - } - - if (typeof callback === 'function') { - callback(); - } - }); + batch.processSortedSet('events:time', function(eids, next) { + events.deleteEvents(eids, callback); + }, {alwaysStartAt: 0}, callback); }; - events.getLog = function(end, len, callback) { - var logFile = path.join(nconf.get('base_dir'), logFileName); - - fs.stat(logFile, function(err, stat) { - if (err) { - return callback(null, 'No logs found!'); - } - - var buffer = ''; - var size = stat.size; - if (end === -1) { - end = size; - } - - end = parseInt(end, 10); - var start = Math.max(0, end - len); - - var rs = fs.createReadStream(logFile, {start: start, end: end}); - rs.addListener('data', function(lines) { - buffer += lines.toString(); - }); - - rs.addListener('end', function() { - var firstNewline = buffer.indexOf('\n'); - if (firstNewline !== -1) { - buffer = buffer.slice(firstNewline); - buffer = buffer.split('\n').reverse().join('\n'); - } - - callback(null, {data: buffer, next: end - buffer.length}); - }); - }); - - }; }(module.exports)); diff --git a/src/favourites.js b/src/favourites.js index 0673626f51..fec00fd9cc 100644 --- a/src/favourites.js +++ b/src/favourites.js @@ -43,10 +43,6 @@ var async = require('async'), db.sortedSetAdd('users:reputation', newreputation, postData.uid); - if (type === 'downvote') { - banUserForLowReputation(postData.uid, newreputation); - } - adjustPostVotes(pid, uid, type, unvote, function(err, votes) { postData.votes = votes; callback(err, { @@ -62,23 +58,6 @@ var async = require('async'), }); } - function banUserForLowReputation(uid, newreputation) { - if (parseInt(meta.config['autoban:downvote'], 10) === 1 && newreputation < parseInt(meta.config['autoban:downvote:threshold'], 10)) { - user.getUserField(uid, 'banned', function(err, banned) { - if (err || parseInt(banned, 10) === 1) { - return; - } - var adminUser = require('./socket.io/admin/user'); - adminUser.banUser(uid, function(err) { - if (err) { - return winston.error(err.message); - } - winston.info('uid ' + uid + ' was banned for reaching ' + newreputation + ' reputation'); - }); - }); - } - } - function adjustPostVotes(pid, uid, type, unvote, callback) { var notType = (type === 'upvote' ? 'downvote' : 'upvote'); @@ -274,7 +253,7 @@ var async = require('async'), } if (!isFavouriting && !results.hasFavourited) { - return callback(new Error('[[error:alrady-unfavourited]]')); + return callback(new Error('[[error:already-unfavourited]]')); } async.waterfall([ diff --git a/src/groups.js b/src/groups.js index 4a7611c531..f82e452b96 100644 --- a/src/groups.js +++ b/src/groups.js @@ -299,7 +299,7 @@ var async = require('async'), }; Groups.getMemberCount = function(groupName, callback) { - db.sortedSetCard('group:' + groupName + ':members', callback); + db.getObjectField('group:' + groupName, 'memberCount', callback); }; Groups.isMemberOfGroupList = function(uid, groupListKey, callback) { @@ -422,6 +422,10 @@ var async = require('async'), } }; + Groups.existsBySlug = function(slug, callback) { + db.isObjectField('groupslug:groupname', slug, callback); + }; + Groups.create = function(data, callback) { if (data.name.length === 0) { return callback(new Error('[[error:group-name-too-short]]')); @@ -448,6 +452,7 @@ var async = require('async'), createtime: now, userTitle: data.name, description: data.description || '', + memberCount: 0, deleted: '0', hidden: data.hidden || '0', system: system ? '1' : '0', @@ -498,7 +503,11 @@ var async = require('async'), 'private': values.private === false ? '0' : '1' }; - db.setObject('group:' + groupName, payload, function(err) { + async.series([ + async.apply(updatePrivacy, groupName, values.private), + async.apply(db.setObject, 'group:' + groupName, payload), + async.apply(renameGroup, groupName, values.name) + ], function(err) { if (err) { return callback(err); } @@ -507,11 +516,37 @@ var async = require('async'), name: groupName, values: values }); - renameGroup(groupName, values.name, callback); + callback(); }); }); }; + function updatePrivacy(groupName, newValue, callback) { + // Grab the group's current privacy value + Groups.getGroupFields(groupName, ['private'], function(err, currentValue) { + currentValue = currentValue.private === '1'; // Now a Boolean + + if (currentValue !== newValue && currentValue === true) { + // Group is now public, so all pending users are automatically considered members + db.getSetMembers('group:' + groupName + ':pending', function(err, uids) { + if (err) { return callback(err); } + else if (!uids) { return callback(); } // No pending users, we're good to go + + var now = Date.now(), + scores = uids.map(function() { return now; }); // There's probably a better way to initialise an Array of size x with the same value... + + winston.verbose('[groups.update] Group is now public, automatically adding ' + uids.length + ' new members, who were pending prior.'); + async.series([ + async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', scores, uids), + async.apply(db.delete, 'group:' + groupName + ':pending') + ], callback); + }); + } else { + callback(); + } + }); + } + function renameGroup(oldName, newName, callback) { if (oldName === newName || !newName || newName.length === 0) { return callback(); @@ -611,46 +646,56 @@ var async = require('async'), }; Groups.join = function(groupName, uid, callback) { - callback = callback || function() {}; + function join() { + var tasks = [ + async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', Date.now(), uid), + async.apply(db.incrObjectField, 'group:' + groupName, 'memberCount') + ]; - Groups.exists(groupName, function(err, exists) { - if (exists) { - var tasks = [ - async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', Date.now(), uid) - ]; - - user.isAdministrator(uid, function(err, isAdmin) { + async.waterfall([ + function(next) { + user.isAdministrator(uid, next); + }, + function(isAdmin, next) { if (isAdmin) { tasks.push(async.apply(db.setAdd, 'group:' + groupName + ':owners', uid)); } - - async.parallel(tasks, function(err) { - plugins.fireHook('action:group.join', { - groupName: groupName, - uid: uid - }); - - callback(); - }); + async.parallel(tasks, next); + } + ], function(err, results) { + if (err) { + return callback(err); + } + plugins.fireHook('action:group.join', { + groupName: groupName, + uid: uid }); - } else { - Groups.create({ - name: groupName, - description: '', - hidden: 1 - }, function(err) { - if (err && err.message !== '[[error:group-already-exists]]') { - winston.error('[groups.join] Could not create new hidden group: ' + err.message); - return callback(err); - } + callback(); + }); + } - db.sortedSetAdd('group:' + groupName + ':members', Date.now(), uid, callback); - plugins.fireHook('action:group.join', { - groupName: groupName, - uid: uid - }); - }); + callback = callback || function() {}; + + Groups.exists(groupName, function(err, exists) { + if (err) { + return callback(err); } + + if (exists) { + return join(); + } + + Groups.create({ + name: groupName, + description: '', + hidden: 1 + }, function(err) { + if (err && err.message !== '[[error:group-already-exists]]') { + winston.error('[groups.join] Could not create new hidden group: ' + err.message); + return callback(err); + } + join(); + }); }); }; @@ -679,8 +724,14 @@ var async = require('async'), Groups.acceptMembership = function(groupName, uid, callback) { // Note: For simplicity, this method intentially doesn't check the caller uid for ownership! - db.setRemove('group:' + groupName + ':pending', uid, callback); - Groups.join.apply(Groups, arguments); + async.waterfall([ + function(next) { + db.setRemove('group:' + groupName + ':pending', uid, next); + }, + function(next) { + Groups.join(groupName, uid, next); + } + ], callback); }; Groups.rejectMembership = function(groupName, uid, callback) { @@ -692,9 +743,10 @@ var async = require('async'), callback = callback || function() {}; var tasks = [ - async.apply(db.sortedSetRemove, 'group:' + groupName + ':members', uid), - async.apply(db.setRemove, 'group:' + groupName + ':owners', uid) - ]; + async.apply(db.sortedSetRemove, 'group:' + groupName + ':members', uid), + async.apply(db.setRemove, 'group:' + groupName + ':owners', uid), + async.apply(db.decrObjectField, 'group:' + groupName, 'memberCount') + ]; async.parallel(tasks, function(err) { if (err) { @@ -715,7 +767,7 @@ var async = require('async'), if (group.hidden && group.memberCount === 0) { Groups.destroy(groupName, callback); } else { - return callback(); + callback(); } }); }); @@ -781,10 +833,15 @@ var async = require('async'), groupData = groupData.filter(function(group) { return parseInt(group.hidden, 10) !== 1 && !!group.userTitle; + }).map(function(group) { + group.createtimeISO = utils.toISOString(group.createtime); + return group; }); + var groupSets = groupData.map(function(group) { group.labelColor = group.labelColor || '#000000'; + group.createtimeISO = utils.toISOString(group.createtime); if (!group['cover:url']) { group['cover:url'] = nconf.get('relative_path') + '/images/cover-default.png'; diff --git a/src/install.js b/src/install.js index 54fb075ced..45d44d75ad 100644 --- a/src/install.js +++ b/src/install.js @@ -389,13 +389,23 @@ function createWelcomePost(next) { var db = require('./database'), Topics = require('./topics'); - db.sortedSetCard('topics:tid', function(err, numTopics) { - if (numTopics === 0) { + async.parallel([ + function(next) { + fs.readFile(path.join(__dirname, '../', 'install/data/welcome.md'), next); + }, + function(next) { + db.getObjectField('global', 'topicCount', next); + } + ], function(err, results) { + var content = results[0], + numTopics = results[1]; + + if (!parseInt(numTopics, 10)) { Topics.post({ uid: 1, cid: 2, title: 'Welcome to your NodeBB!', - content: '# Welcome to your brand new NodeBB forum!\n\nThis is what a topic and post looks like. As an administator, you can edit the post\'s title and content.\n\nTo customise your forum, go to the [Administrator Control Panel](../../admin). You can modify all aspects of your forum there, including installation of third-party plugins.\n\n## Additional Resources\n\n* [NodeBB Documentation](https://docs.nodebb.org)\n* [Community Support Forum](https://community.nodebb.org)\n* [Project repository](https://github.com/nodebb/nodebb)' + content: content.toString() }, next); } else { next(); @@ -420,12 +430,24 @@ function enableDefaultPlugins(next) { function setCopyrightWidget(next) { var db = require('./database'); - - db.init(function(err) { - if (!err) { - db.setObjectField('widgets:global', 'footer', "[{\"widget\":\"html\",\"data\":{\"html\":\"\",\"title\":\"\",\"container\":\"\"}}]", next); + async.parallel({ + footerJSON: function(next) { + fs.readFile(path.join(__dirname, '../', 'install/data/footer.json'), next); + }, + footer: function(next) { + db.getObjectField('widgets:global', 'footer', next); } - }); + }, function(err, results) { + if (err) { + return next(err); + } + + if (!results.footer && results.footerJSON) { + db.setObjectField('widgets:global', 'footer', results.footerJSON.toString(), next); + } else { + next(); + } + }); } install.setup = function (callback) { diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 111b0b1ceb..43e2a2ea86 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -340,6 +340,7 @@ middleware.renderHeader = function(req, res, callback) { return; } results.user.isAdmin = results.isAdmin || false; + results.user.uid = parseInt(results.user.uid, 10); results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1; templateValues.browserTitle = results.title; @@ -409,7 +410,10 @@ middleware.processRender = function(req, res, next) { }); } else if (res.locals.adminHeader) { str = res.locals.adminHeader + str; - fn(err, str); + var language = res.locals.config ? res.locals.config.userLang || 'en_GB' : 'en_GB'; + translator.translate(str, language, function(translated) { + fn(err, translated); + }); } else { fn(err, str); } diff --git a/src/notifications.js b/src/notifications.js index 2de4ec1709..dc3aae7ea2 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -18,9 +18,7 @@ var async = require('async'), (function(Notifications) { Notifications.init = function() { - if (process.env.NODE_ENV === 'development') { - winston.verbose('[notifications.init] Registering jobs.'); - } + winston.verbose('[notifications.init] Registering jobs.'); new cron('*/30 * * * *', Notifications.prune, null, true); }; @@ -270,12 +268,6 @@ var async = require('async'), }; Notifications.prune = function() { - var start = process.hrtime(); - - if (process.env.NODE_ENV === 'development') { - winston.info('[notifications.prune] Removing expired notifications from the database.'); - } - var week = 604800000, numPruned = 0; @@ -307,12 +299,6 @@ var async = require('async'), if (err) { return winston.error('Encountered error pruning notifications: ' + err.message); } - - if (process.env.NODE_ENV === 'development') { - winston.info('[notifications.prune] Notification pruning completed. ' + numPruned + ' expired notification' + (numPruned !== 1 ? 's' : '') + ' removed.'); - } - var diff = process.hrtime(start); - events.log('Pruning '+ numPruned + ' notifications took : ' + (diff[0] * 1e3 + diff[1] / 1e6) + ' ms'); }); }); }; diff --git a/src/pagination.js b/src/pagination.js index 3fa2e31bf7..d3a3ca9dd9 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -1,17 +1,17 @@ 'use strict'; +var qs = require('querystring'); + var pagination = {}; -pagination.create = function(currentPage, pageCount, data) { - +pagination.create = function(currentPage, pageCount, queryObj) { if (pageCount <= 1) { - data.pagination = { + return { prev: {page: 1, active: currentPage > 1}, next: {page: 1, active: currentPage < pageCount}, rel: [], pages: [] }; - return; } var pagesToShow = [1]; @@ -35,11 +35,14 @@ pagination.create = function(currentPage, pageCount, data) { return a - b; }); + queryObj = queryObj || {}; + var pages = pagesToShow.map(function(page) { - return {page: page, active: page === currentPage}; + queryObj.page = page; + return {page: page, active: page === currentPage, qs: qs.stringify(queryObj)}; }); - data.pagination = { + var data = { prev: {page: previous, active: currentPage > 1}, next: {page: next, active: currentPage < pageCount}, rel: [], @@ -47,19 +50,19 @@ pagination.create = function(currentPage, pageCount, data) { }; if (currentPage < pageCount) { - data.pagination.rel.push({ + data.rel.push({ rel: 'next', href: '?page=' + next }); } if (currentPage > 1) { - data.pagination.rel.push({ + data.rel.push({ rel: 'prev', href: '?page=' + previous }); } - + return data; }; diff --git a/src/plugins.js b/src/plugins.js index bd00bb8b0a..730377c673 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -6,6 +6,7 @@ var fs = require('fs'), winston = require('winston'), semver = require('semver'), express = require('express'), + nconf = require('nconf'), db = require('./database'), emitter = require('./emitter'), @@ -13,6 +14,7 @@ var fs = require('fs'), translator = require('../public/src/translator'), utils = require('../public/src/utils'), hotswap = require('./hotswap'), + pkg = require('../package.json'), controllers = require('./controllers'), app, middleware; @@ -169,7 +171,7 @@ var fs = require('fs'), Plugins.getAll = function(callback) { var request = require('request'); - request('https://packages.nodebb.org/api/v1/plugins', function(err, res, body) { + request((nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + pkg.version, function(err, res, body) { var plugins = []; try { @@ -184,8 +186,9 @@ var fs = require('fs'), plugins[i].id = plugins[i].name; plugins[i].installed = false; plugins[i].active = false; - plugins[i].url = plugins[i].repository ? plugins[i].repository.url : ''; + plugins[i].url = plugins[i].url ? plugins[i].url : plugins[i].repository ? plugins[i].repository.url : ''; plugins[i].latest = getLatestVersion(plugins[i].versions); + // plugins[i].latest = plugins[i].latest; pluginMap[plugins[i].name] = plugins[i]; } @@ -261,7 +264,7 @@ var fs = require('fs'), function(dirs, next) { dirs = dirs.filter(function(dir){ - return dir.substr(0, 14) === 'nodebb-plugin-' || dir.substr(0, 14) === 'nodebb-widget-'; + return dir.startsWith('nodebb-plugin-') || dir.startsWith('nodebb-widget-') || dir.startsWith('nodebb-theme-') }).map(function(dir){ return path.join(npmPluginPath, dir); }); @@ -343,16 +346,18 @@ var fs = require('fs'), }).reduce(function(prev, cur) { return prev.concat(cur); }); - next(null, paths); - } - ], function(err, paths) { - for (var x=0,numPaths=paths.length;x= postCount; + }); + } else { + posts = posts.filter(function(post) { + return post.topic && post.topic.postcount <= postCount; + }); + } + } + return posts; +} + +function filterByTimerange(posts, timeRange, timeFilter) { + timeRange = parseInt(timeRange) * 1000; + if (timeRange) { + var time = Date.now() - timeRange; + if (timeFilter === 'newer') { + posts = posts.filter(function(post) { + return post.timestamp >= time; + }); + } else { + posts = posts.filter(function(post) { + return post.timestamp <= time; + }); + } + } + return posts; +} + +function sortPosts(posts, data) { + if (!posts.length) { + return; + } + data.sortBy = data.sortBy || 'timestamp'; + data.sortDirection = data.sortDirection || 'desc'; + if (data.sortBy === 'timestamp') { + if (data.sortDirection === 'desc') { + posts.sort(function(p1, p2) { + return p2.timestamp - p1.timestamp; + }); + } else { + posts.sort(function(p1, p2) { + return p1.timestamp - p2.timestamp; + }); + } + + return; + } + + var firstPost = posts[0]; + var fields = data.sortBy.split('.'); + + if (!fields || fields.length !== 2 || !firstPost[fields[0]] || !firstPost[fields[0]][fields[1]]) { + return; + } + + var value = firstPost[fields[0]][fields[1]]; + var isNumeric = utils.isNumber(value); + + if (isNumeric) { + if (data.sortDirection === 'desc') { + sortDescendingNumeric(posts, fields); + } else { + sortAscendingNumeric(posts, fields); + } + } else { + if (data.sortDirection === 'desc') { + sortDescendingAlpha(posts, fields); + } else { + sortAscendingAlpha(posts, fields); + } + } +} + +function sortAscendingNumeric(posts, fields) { + posts.sort(function(p1, p2) { + return p1[fields[0]][fields[1]] - p2[fields[0]][fields[1]]; + }); +} + +function sortDescendingNumeric(posts, fields) { + posts.sort(function(p1, p2) { + return p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]]; + }); +} + +function sortAscendingAlpha(posts, fields) { + posts.sort(function(p1, p2) { + if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return -1; + if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return 1; + return 0; + }); +} + +function sortDescendingAlpha(posts, fields) { + posts.sort(function(p1, p2) { + if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return -1; + if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return 1; + return 0; + }); +} + +function getSearchCategories(data, callback) { + if (!Array.isArray(data.categories) || !data.categories.length || data.categories.indexOf('all') !== -1) { + return callback(null, []); + } + + async.parallel({ + watchedCids: function(next) { + if (data.categories.indexOf('watched') !== -1) { + user.getWatchedCategories(data.uid, next); + } else { + next(null, []); + } + }, + childrenCids: function(next) { + if (data.searchChildren) { + getChildrenCids(data.categories, data.uid, next); + } else { + next(null, []); + } + } + }, function(err, results) { + if (err) { + return callback(err); + } + + var cids = results.watchedCids.concat(results.childrenCids).concat(data.categories).filter(function(cid, index, array) { + return cid && array.indexOf(cid) === index; + }); + + callback(null, cids); + }); +} + +function getChildrenCids(cids, uid, callback) { + categories.getChildren(cids, uid, function(err, childrenCategories) { + if (err) { + return callback(err); + } + + var childrenCids = []; + childrenCategories.forEach(function(childrens) { + childrenCids = childrenCids.concat(childrens.map(function(category) { + return category && category.cid; + })); + }); + + callback(null, childrenCids); + }); +} + +function searchInUsers(query, uid, callback) { + user.search({query: query, uid: uid}, function(err, results) { + if (err) { + return callback(err); + } + callback(null, {matches: results.users, matchCount: results.matchCount}); }); } function searchInTags(query, callback) { - topics.searchAndLoadTags({query: query}, callback); + topics.searchAndLoadTags({query: query}, function(err, tags) { + if (err) { + return callback(err); + } + + callback(null, {matches: tags, matchCount: tags.length}); + }); } function getMainPids(tids, callback) { + if (!Array.isArray(tids) || !tids.length) { + return callback(null, []); + } + topics.getTopicsFields(tids, ['mainPid'], function(err, topics) { if (err) { return callback(err); } topics = topics.map(function(topic) { - return topic && topic.mainPid; + return topic && topic.mainPid && topic.mainPid.toString(); }).filter(Boolean); callback(null, topics); }); diff --git a/src/sitemap.js b/src/sitemap.js index ffc072b871..aab7451a61 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -10,104 +10,121 @@ var path = require('path'), topics = require('./topics'), privileges = require('./privileges'), meta = require('./meta'), - utils = require('../public/src/utils'), - sitemap = { - obj: undefined, - getStaticUrls: function(callback) { - callback(null, [{ - url: '', - changefreq: 'weekly', - priority: '0.6' - }, { - url: '/recent', - changefreq: 'daily', - priority: '0.4' - }, { - url: '/users', - changefreq: 'daily', - priority: '0.4' - }]); - }, - getDynamicUrls: function(callback) { - var returnUrls = []; + utils = require('../public/src/utils'); - async.parallel({ - categoryUrls: function(next) { - var categoryUrls = []; - categories.getCategoriesByPrivilege(0, 'find', function(err, categoriesData) { - if (err) { - return next(err); - } +var sitemap = {}; - categoriesData.forEach(function(category) { - if (category) { - categoryUrls.push({ - url: '/category/' + category.cid + '/' + encodeURIComponent(utils.slugify(category.name)), - changefreq: 'weekly', - priority: '0.4' - }); - } - }); +sitemap.render = function(callback) { + if (sitemap.obj && sitemap.obj.cache.length) { + return sitemap.obj.toXML(callback); + } - next(null, categoryUrls); - }); - }, - topicUrls: function(next) { - var topicUrls = []; + async.parallel([ + sitemap.getStaticUrls, + sitemap.getDynamicUrls + ], function(err, urls) { + if (err) { + return callback(err); + } - async.waterfall([ - function(next) { - db.getSortedSetRevRange('topics:recent', 0, parseInt(meta.config.sitemapTopics, 10) || -1, next); - }, - function(tids, next) { - privileges.topics.filter('read', tids, 0, next); - }, - function(tids, next) { - topics.getTopicsFields(tids, ['tid', 'title', 'lastposttime'], next); - } - ], function(err, topics) { - if (err) { - return next(err); - } + urls = urls[0].concat(urls[1]); - topics.forEach(function(topic) { - if (topic) { - topicUrls.push({ - url: '/topic/' + topic.tid + '/' + encodeURIComponent(utils.slugify(topic.title)), - lastmodISO: utils.toISOString(topic.lastposttime), - changefreq: 'daily', - priority: '0.6' - }); - } - }); + sitemap.obj = sm.createSitemap({ + hostname: nconf.get('url'), + cacheTime: 1000 * 60 * 60, // Cached for 1 hour + urls: urls + }); - next(null, topicUrls); - }); - } - }, function(err, data) { - if (!err) { - returnUrls = data.categoryUrls.concat(data.topicUrls); + sitemap.obj.toXML(callback); + }); +}; + +sitemap.getStaticUrls = function(callback) { + callback(null, [{ + url: '', + changefreq: 'weekly', + priority: '0.6' + }, { + url: '/recent', + changefreq: 'daily', + priority: '0.4' + }, { + url: '/users', + changefreq: 'daily', + priority: '0.4' + }]); +}; + +sitemap.getDynamicUrls = function(callback) { + var returnUrls = []; + + async.parallel({ + categoryUrls: function(next) { + var categoryUrls = []; + categories.getCategoriesByPrivilege(0, 'find', function(err, categoriesData) { + if (err) { + return next(err); } - callback(err, returnUrls); - }); - }, - render: function(callback) { - if (sitemap.obj !== undefined && sitemap.obj.cache.length) { - return sitemap.obj.toXML(callback); - } - - async.parallel([sitemap.getStaticUrls, sitemap.getDynamicUrls], function(err, urls) { - urls = urls[0].concat(urls[1]); - sitemap.obj = sm.createSitemap({ - hostname: nconf.get('url'), - cacheTime: 1000 * 60 * 60, // Cached for 1 hour - urls: urls + categoriesData.forEach(function(category) { + if (category) { + categoryUrls.push({ + url: '/category/' + category.cid + '/' + encodeURIComponent(utils.slugify(category.name)), + changefreq: 'weekly', + priority: '0.4' + }); + } }); - sitemap.obj.toXML(callback); + next(null, categoryUrls); + }); + }, + topicUrls: function(next) { + var topicUrls = []; + + async.waterfall([ + function(next) { + db.getSortedSetRevRange('topics:recent', 0, parseInt(meta.config.sitemapTopics, 10) || -1, next); + }, + function(tids, next) { + privileges.topics.filter('read', tids, 0, next); + }, + function(tids, next) { + topics.getTopicsFields(tids, ['tid', 'title', 'lastposttime'], next); + } + ], function(err, topics) { + if (err) { + return next(err); + } + + topics.forEach(function(topic) { + if (topic) { + topicUrls.push({ + url: '/topic/' + topic.tid + '/' + encodeURIComponent(utils.slugify(topic.title)), + lastmodISO: utils.toISOString(topic.lastposttime), + changefreq: 'daily', + priority: '0.6' + }); + } + }); + + next(null, topicUrls); }); } - }; + }, function(err, data) { + if (!err) { + returnUrls = data.categoryUrls.concat(data.topicUrls); + } + + callback(err, returnUrls); + }); +}; + + +sitemap.clearCache = function() { + if (sitemap.obj) { + sitemap.obj.clearCache(); + } +}; module.exports = sitemap; diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index b659397220..a770af5c53 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -49,7 +49,11 @@ SocketAdmin.before = function(socket, method, next) { }; SocketAdmin.reload = function(socket, data, callback) { - events.logWithUser(socket.uid, ' is reloading NodeBB'); + events.log({ + type: 'reload', + uid: socket.uid, + ip: socket.ip + }); if (process.send) { process.send({ action: 'reload' @@ -60,7 +64,11 @@ SocketAdmin.reload = function(socket, data, callback) { }; SocketAdmin.restart = function(socket, data, callback) { - events.logWithUser(socket.uid, ' is restarting NodeBB'); + events.log({ + type: 'restart', + uid: socket.uid, + ip: socket.ip + }); meta.restart(); }; @@ -175,6 +183,11 @@ SocketAdmin.settings.set = function(socket, data, callback) { meta.settings.set(data.hash, data.values, callback); }; +SocketAdmin.settings.clearSitemapCache = function(socket, data, callback) { + require('../sitemap').clearCache(); + callback(); +}; + SocketAdmin.email.test = function(socket, data, callback) { if (plugins.hasListeners('action:email.send')) { emailer.send('test', socket.uid, { @@ -269,10 +282,21 @@ function getMonthlyPageViews(callback) { } SocketAdmin.getMoreEvents = function(socket, next, callback) { - if (parseInt(next, 10) < 0) { + var start = parseInt(next, 10); + if (start < 0) { return callback(null, {data: [], next: next}); } - events.getLog(next, 5000, callback); + var end = next + 10; + events.getEvents(start, end, function(err, events) { + if (err) { + return callback(err); + } + callback(null, {events: events, next: end + 1}); + }); +}; + +SocketAdmin.deleteAllEvents = function(socket, data, callback) { + events.deleteAll(callback); }; SocketAdmin.dismissFlag = function(socket, pid, callback) { diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index 2ba036d7e0..9a9ef0ea7e 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -36,7 +36,7 @@ Categories.search = function(socket, data, callback) { var username = data.username, cid = data.cid; - user.search({query: username}, function(err, data) { + user.search({query: username, uid: socket.uid}, function(err, data) { if (err) { return callback(err); } diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 9189727fbb..0fa583d742 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -1,12 +1,13 @@ "use strict"; -var db = require('../../database'), +var async = require('async'), + db = require('../../database'), groups = require('../../groups'), user = require('../../user'), events = require('../../events'), + meta = require('../../meta'), websockets = require('../index'), - async = require('async'), User = {}; @@ -127,6 +128,30 @@ User.validateEmail = function(socket, uids, callback) { }, callback); }; +User.sendValidationEmail = function(socket, uids, callback) { + if (!Array.isArray(uids)) { + return callback(new Error('[[error:invalid-data]]')); + } + + if (parseInt(meta.config.requireEmailConfirmation, 10) !== 1) { + return callback(new Error('[[error:email-confirmations-are-disabled]]')); + } + + user.getMultipleUserFields(uids, ['uid', 'email'], function(err, usersData) { + if (err) { + return callback(err); + } + + async.eachLimit(usersData, 50, function(userData, next) { + if (userData.email && userData.uid) { + user.email.verify(userData.uid, userData.email, next); + } else { + next(); + } + }, callback); + }); +}; + User.sendPasswordResetEmail = function(socket, uids, callback) { if (!Array.isArray(uids)) { return callback(new Error('[[error:invalid-data]]')); @@ -157,7 +182,7 @@ User.deleteUsers = function(socket, uids, callback) { async.each(uids, function(uid, next) { user.isAdministrator(uid, function(err, isAdmin) { if (err || isAdmin) { - return callback(err || new Error('[[error:cant-ban-other-admins]]')); + return callback(err || new Error('[[error:cant-delete-other-admins]]')); } user.delete(uid, function(err) { @@ -165,7 +190,12 @@ User.deleteUsers = function(socket, uids, callback) { return next(err); } - events.logAdminUserDelete(socket.uid, uid); + events.log({ + type: 'user-delete', + uid: socket.uid, + targetUid: uid, + ip: socket.ip + }); websockets.logoutUser(uid); next(); @@ -175,7 +205,7 @@ User.deleteUsers = function(socket, uids, callback) { }; User.search = function(socket, data, callback) { - user.search({query: data.query, searchBy: data.searchBy, startsWith: false}, function(err, searchData) { + user.search({query: data.query, searchBy: data.searchBy, startsWith: false, uid: socket.uid}, function(err, searchData) { if (err) { return callback(err); } diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 1b97dad0bb..ba35e128c4 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -13,6 +13,10 @@ SocketGroups.join = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } + if (!parseInt(socket.uid, 10)) { + return callback(new Error('[[error:invalid-uid]]')); + } + if (meta.config.allowPrivateGroups !== '0') { async.parallel({ isAdmin: async.apply(user.isAdministrator, socket.uid), @@ -34,6 +38,10 @@ SocketGroups.leave = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } + if (!parseInt(socket.uid, 10)) { + return callback(new Error('[[error:invalid-uid]]')); + } + groups.leave(data.groupName, socket.uid, callback); }; @@ -94,7 +102,7 @@ SocketGroups.reject = function(socket, data, callback) { }; SocketGroups.update = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -108,18 +116,21 @@ SocketGroups.update = function(socket, data, callback) { }; SocketGroups.create = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } else if (socket.uid === 0) { return callback(new Error('[[error:no-privileges]]')); + } else if (parseInt(meta.config.allowGroupCreation, 10) !== 1) { + return callback(new Error('[[error:group-creation-disabled]]')); } + data.ownerUid = socket.uid; groups.create(data, callback); }; SocketGroups.delete = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -145,6 +156,20 @@ SocketGroups.search = function(socket, data, callback) { groups.search(data.query || '', data.options || {}, callback); }; +SocketGroups.kick = function(socket, data, callback) { + if (!data) { + return callback(new Error('[[error:invalid-data]]')); + } + + groups.ownership.isOwner(socket.uid, data.groupName, function(err, isOwner) { + if (!isOwner) { + return callback(new Error('[[error:no-privileges]]')); + } + + groups.leave(data.groupName, data.uid, callback); + }); +}; + SocketGroups.cover = {}; SocketGroups.cover.get = function(socket, data, callback) { @@ -152,7 +177,7 @@ SocketGroups.cover.get = function(socket, data, callback) { }; SocketGroups.cover.update = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } else if (socket.uid === 0) { return callback(new Error('[[error:no-privileges]]')); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 9274f72222..98d1d6e2e8 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -40,7 +40,7 @@ Sockets.init = function(server) { }; function onConnection(socket) { - socket.ip = socket.request.connection.remoteAddress; + socket.ip = socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress; logger.io_one(socket, socket.uid); @@ -66,32 +66,19 @@ function onConnect(socket) { socket.join('uid_' + socket.uid); socket.join('online_users'); - async.parallel({ - user: function(next) { - user.getUserFields(socket.uid, ['username', 'userslug', 'picture', 'status', 'email:confirmed'], next); - }, - isAdmin: function(next) { - user.isAdministrator(socket.uid, next); - } - }, function(err, userData) { - if (err || !userData.user) { + user.getUserFields(socket.uid, ['status'], function(err, userData) { + if (err || !userData) { return; } - userData.user.uid = socket.uid; - userData.user.isAdmin = userData.isAdmin; - userData.user['email:confirmed'] = parseInt(userData.user['email:confirmed'], 10) === 1; - socket.emit('event:connect', userData.user); - if (userData.user.status !== 'offline') { - socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: userData.user.status || 'online'}); + + socket.emit('event:connect'); + if (userData.status !== 'offline') { + socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: userData.status || 'online'}); } }); } else { socket.join('online_guests'); - socket.emit('event:connect', { - username: '[[global:guest]]', - isAdmin: false, - uid: 0 - }); + socket.emit('event:connect'); } } diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 71a44f36bd..00fdeaf433 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -12,7 +12,6 @@ var nconf = require('nconf'), meta = require('../meta'), Messaging = require('../messaging'), user = require('../user'), - notifications = require('../notifications'), plugins = require('../plugins'), utils = require('../../public/src/utils'), privileges = require('../privileges'), @@ -23,7 +22,6 @@ var nconf = require('nconf'), SocketModules = { composer: {}, chats: {}, - notifications: {}, sounds: {}, settings: {} }; @@ -246,14 +244,6 @@ SocketModules.chats.getRecentChats = function(socket, data, callback) { Messaging.getRecentChats(socket.uid, start, end, callback); }; -/* Notifications */ -SocketModules.notifications.markRead = function(socket, nid) { - notifications.markRead(nid, socket.uid); -}; - -SocketModules.notifications.markAllRead = function(socket, data, callback) { - notifications.markAllRead(socket.uid, callback); -}; /* Sounds */ SocketModules.sounds.getSounds = function(socket, data, callback) { diff --git a/src/socket.io/notifications.js b/src/socket.io/notifications.js index 657e46db52..ebd633b080 100644 --- a/src/socket.io/notifications.js +++ b/src/socket.io/notifications.js @@ -1,7 +1,7 @@ "use strict"; var user = require('../user'), - + notifications = require('../notifications'), SocketNotifs = {}; SocketNotifs.get = function(socket, data, callback) { @@ -20,4 +20,12 @@ SocketNotifs.deleteAll = function(socket, data, callback) { user.notifications.deleteAll(socket.uid, callback); }; +SocketNotifs.markRead = function(socket, nid, callback) { + notifications.markRead(nid, socket.uid, callback); +}; + +SocketNotifs.markAllRead = function(socket, data, callback) { + notifications.markAllRead(socket.uid, callback); +}; + module.exports = SocketNotifs; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 71e5577178..a2de8ca5d6 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -16,6 +16,7 @@ var async = require('async'), groups = require('../groups'), user = require('../user'), websockets = require('./index'), + events = require('../events'), utils = require('../../public/src/utils'), SocketPosts = {}; @@ -47,29 +48,34 @@ SocketPosts.reply = function(socket, data, callback) { socket.emit('event:new_post', result); - async.waterfall([ - function(next) { - user.getUidsFromSet('users:online', 0, -1, next); - }, - function(uids, next) { - privileges.categories.filterUids('read', postData.topic.cid, uids, next); - }, - function(uids, next) { - plugins.fireHook('filter:sockets.sendNewPostToUids', {uidsTo: uids, uidFrom: data.uid, type: 'newPost'}, next); - } - ], function(err, data) { - if (err) { - return winston.error(err.stack); - } + SocketPosts.notifyOnlineUsers(socket.uid, result); + }); +}; - var uids = data.uidsTo; +SocketPosts.notifyOnlineUsers = function(uid, result) { + var cid = result.posts[0].topic.cid; + async.waterfall([ + function(next) { + user.getUidsFromSet('users:online', 0, -1, next); + }, + function(uids, next) { + privileges.categories.filterUids('read', cid, uids, next); + }, + function(uids, next) { + plugins.fireHook('filter:sockets.sendNewPostToUids', {uidsTo: uids, uidFrom: uid, type: 'newPost'}, next); + } + ], function(err, data) { + if (err) { + return winston.error(err.stack); + } - for(var i=0; i parseInt(meta.config.maximumPostLength, 10)) { + return callback(new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]')); } // uid, pid, title, content, options @@ -304,9 +330,16 @@ function deleteOrRestore(command, socket, data, callback) { return callback(err); } - var eventName = command === 'restore' ? 'event:post_restored' : 'event:post_deleted'; + var eventName = command === 'delete' ? 'event:post_deleted' : 'event:post_restored'; websockets.in('topic_' + data.tid).emit(eventName, postData); + events.log({ + type: command === 'delete' ? 'post-delete' : 'post-restore', + uid: socket.uid, + pid: data.pid, + ip: socket.ip + }); + callback(); }); } @@ -322,6 +355,13 @@ SocketPosts.purge = function(socket, data, callback) { websockets.in('topic_' + data.tid).emit('event:post_purged', data.pid); + events.log({ + type: 'post-purge', + uid: socket.uid, + pid: data.pid, + ip: socket.ip + }); + callback(); }); }; @@ -374,9 +414,6 @@ SocketPosts.flag = function(socket, pid, callback) { post; async.waterfall([ - function(next) { - posts.flag(pid, next); - }, function(next) { user.getUserFields(socket.uid, ['username', 'reputation'], next); }, @@ -385,7 +422,6 @@ SocketPosts.flag = function(socket, pid, callback) { return next(new Error('[[error:not-enough-reputation-to-flag]]')); } userName = userData.username; - posts.getPostFields(pid, ['tid', 'uid', 'content', 'deleted'], next); }, function(postData, next) { @@ -393,7 +429,10 @@ SocketPosts.flag = function(socket, pid, callback) { return next(new Error('[[error:post-deleted]]')); } post = postData; - topics.getTopicFields(postData.tid, ['title', 'cid'], next); + posts.flag(pid, next); + }, + function(next) { + topics.getTopicFields(post.tid, ['title', 'cid'], next); }, function(topic, next) { post.topic = topic; @@ -429,23 +468,7 @@ SocketPosts.flag = function(socket, pid, callback) { return next(); } - db.setAdd('uid:' + post.uid + ':flagged_by', socket.uid, function(err) { - if (err) { - return next(err); - } - db.setCount('uid:' + post.uid + ':flagged_by', function(err, count) { - if (err) { - return next(err); - } - - if (count >= (meta.config.flagsForBan || 3) && parseInt(meta.config.flagsForBan, 10) !== 0) { - var adminUser = require('./admin/user'); - adminUser.banUser(post.uid, next); - return; - } - next(); - }); - }); + db.setAdd('uid:' + post.uid + ':flagged_by', socket.uid, next); } ], callback); }; diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 9f96f17f29..5cc6cb3bad 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -15,11 +15,13 @@ var nconf = require('nconf'), user = require('../user'), db = require('../database'), meta = require('../meta'), + events = require('../events'), utils = require('../../public/src/utils'), SocketPosts = require('./posts'), SocketTopics = {}; + SocketTopics.post = function(socket, data, callback) { if(!data) { return callback(new Error('[[error:invalid-data]]')); @@ -203,44 +205,34 @@ SocketTopics.markAsUnreadForAll = function(socket, tids, callback) { }; SocketTopics.delete = function(socket, data, callback) { - doTopicAction('delete', socket, data, callback); + doTopicAction('delete', 'event:topic_deleted', socket, data, callback); }; SocketTopics.restore = function(socket, data, callback) { - doTopicAction('restore', socket, data, callback); + doTopicAction('restore', 'event:topic_restored', socket, data, callback); }; SocketTopics.purge = function(socket, data, callback) { - doTopicAction('purge', socket, data, function(err) { - if (err) { - return callback(err); - } - - websockets.in('category_' + data.cid).emit('event:topic_purged', data.tids); - async.each(data.tids, function(tid, next) { - websockets.in('topic_' + tid).emit('event:topic_purged', tid); - next(); - }, callback); - }); + doTopicAction('purge', 'event:topic_purged', socket, data, callback); }; SocketTopics.lock = function(socket, data, callback) { - doTopicAction('lock', socket, data, callback); + doTopicAction('lock', 'event:topic_locked', socket, data, callback); }; SocketTopics.unlock = function(socket, data, callback) { - doTopicAction('unlock', socket, data, callback); + doTopicAction('unlock', 'event:topic_unlocked', socket, data, callback); }; SocketTopics.pin = function(socket, data, callback) { - doTopicAction('pin', socket, data, callback); + doTopicAction('pin', 'event:topic_pinned', socket, data, callback); }; SocketTopics.unpin = function(socket, data, callback) { - doTopicAction('unpin', socket, data, callback); + doTopicAction('unpin', 'event:topic_unpinned', socket, data, callback); }; -function doTopicAction(action, socket, data, callback) { +function doTopicAction(action, event, socket, data, callback) { if (!socket.uid) { return; } @@ -250,21 +242,45 @@ function doTopicAction(action, socket, data, callback) { async.each(data.tids, function(tid, next) { privileges.topics.canEdit(tid, socket.uid, function(err, canEdit) { - if(err) { + if (err) { return next(err); } - if(!canEdit) { + if (!canEdit) { return next(new Error('[[error:no-privileges]]')); } - if(typeof threadTools[action] === 'function') { - threadTools[action](tid, socket.uid, next); + if (typeof threadTools[action] !== 'function') { + return next(); } + + threadTools[action](tid, socket.uid, function(err, data) { + if (err) { + return next(err); + } + + emitToTopicAndCategory(event, data); + + if (action === 'delete' || action === 'restore' || action === 'purge') { + events.log({ + type: 'topic-' + action, + uid: socket.uid, + ip: socket.ip, + tid: tid + }); + } + + next(); + }); }); }, callback); } +function emitToTopicAndCategory(event, data) { + websockets.in('topic_' + data.tid).emit(event, data); + websockets.in('category_' + data.cid).emit(event, data); +} + SocketTopics.createTopicFromPosts = function(socket, data, callback) { if(!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); diff --git a/src/socket.io/user.js b/src/socket.io/user.js index d28421c383..fd23405758 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -12,6 +12,9 @@ var async = require('async'), utils = require('../../public/src/utils'), websockets = require('./index'), meta = require('../meta'), + events = require('../events'), + emailer = require('../emailer'), + db = require('../database'), SocketUser = {}; SocketUser.exists = function(socket, data, callback) { @@ -56,7 +59,7 @@ SocketUser.emailConfirm = function(socket, data, callback) { SocketUser.search = function(socket, data, callback) { if (!data) { - return callback(new Error('[[error:invalid-data]]')) + return callback(new Error('[[error:invalid-data]]')); } if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); @@ -66,7 +69,8 @@ SocketUser.search = function(socket, data, callback) { page: data.page, searchBy: data.searchBy, sortBy: data.sortBy, - filterBy: data.filterBy + filterBy: data.filterBy, + uid: socket.uid }, callback); }; @@ -79,16 +83,39 @@ SocketUser.reset.send = function(socket, email, callback) { } }; -SocketUser.reset.valid = function(socket, code, callback) { - if (code) { - user.reset.validate(code, callback); - } -}; - SocketUser.reset.commit = function(socket, data, callback) { - if(data && data.code && data.password) { - user.reset.commit(data.code, data.password, callback); + if (!data || !data.code || !data.password) { + return callback(new Error('[[error:invalid-data]]')); } + + async.parallel({ + uid: async.apply(db.getObjectField, 'reset:uid', data.code), + reset: async.apply(user.reset.commit, data.code, data.password) + }, function(err, results) { + if (err) { + return callback(err); + } + + var uid = results.uid, + now = new Date(), + parsedDate = now.getFullYear() + '/' + (now.getMonth()+1) + '/' + now.getDate(); + + user.getUserField(uid, 'username', function(err, username) { + emailer.send('reset_notify', uid, { + username: username, + date: parsedDate, + site_title: meta.config.title || 'NodeBB', + subject: '[[email:reset.notify.subject]]' + }); + }); + + events.log({ + type: 'password-reset', + uid: uid, + ip: socket.ip + }); + callback(); + }); }; SocketUser.checkStatus = function(socket, uid, callback) { @@ -109,12 +136,72 @@ SocketUser.checkStatus = function(socket, uid, callback) { }; SocketUser.changePassword = function(socket, data, callback) { - if (data && socket.uid) { - user.changePassword(socket.uid, data, callback); + if (!data || !data.uid) { + return callback(new Error('[[error:invalid-data]]')); } + if (!socket.uid) { + return callback('[[error:invalid-uid]]'); + } + + user.changePassword(socket.uid, data, function(err) { + if (err) { + return callback(err); + } + + events.log({ + type: 'password-change', + uid: socket.uid, + targetUid: data.uid, + ip: socket.ip + }); + callback(); + }); }; SocketUser.updateProfile = function(socket, data, callback) { + function update(oldUserData) { + function done(err, userData) { + if (err) { + return callback(err); + } + + if (userData.email !== oldUserData.email) { + events.log({ + type: 'email-change', + uid: socket.uid, + targetUid: data.uid, + ip: socket.ip, + oldEmail: oldUserData.email, + newEmail: userData.email + }); + } + + if (userData.username !== oldUserData.username) { + events.log({ + type: 'username-change', + uid: socket.uid, + targetUid: data.uid, + ip: socket.ip, + oldUsername: oldUserData.username, + newUsername: userData.username + }); + } + callback(null, userData); + } + + if (socket.uid === parseInt(data.uid, 10)) { + return user.updateProfile(socket.uid, data, done); + } + + user.isAdministrator(socket.uid, function(err, isAdmin) { + if (err || !isAdmin) { + return callback(err || new Error('[[error:no-privileges]]')); + } + + user.updateProfile(data.uid, data, done); + }); + } + if (!socket.uid) { return callback('[[error:invalid-uid]]'); } @@ -123,20 +210,12 @@ SocketUser.updateProfile = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - if (socket.uid === parseInt(data.uid, 10)) { - return user.updateProfile(socket.uid, data, callback); - } - - user.isAdministrator(socket.uid, function(err, isAdmin) { + user.getUserFields(data.uid, ['email', 'username'], function(err, oldUserData) { if (err) { return callback(err); } - if (!isAdmin) { - return callback(new Error('[[error:no-privileges]]')); - } - - user.updateProfile(data.uid, data, callback); + update(oldUserData, callback); }); }; @@ -332,7 +411,7 @@ SocketUser.loadMore = function(socket, data, callback) { var start = parseInt(data.after, 10), end = start + 19; - user.getUsersFromSet(data.set, start, end, function(err, userData) { + user.getUsersFromSet(data.set, socket.uid, start, end, function(err, userData) { if (err) { return callback(err); } diff --git a/src/threadTools.js b/src/threadTools.js index 1fe1369d35..96d8198291 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -1,18 +1,11 @@ 'use strict'; -var winston = require('winston'), - nconf = require('nconf'), - async = require('async'), +var async = require('async'), db = require('./database'), topics = require('./topics'), categories = require('./categories'), - user = require('./user'), - notifications = require('./notifications'), posts = require('./posts'), - meta = require('./meta'), - websockets = require('./socket.io'), - events = require('./events'), plugins = require('./plugins'), batch = require('./batch'); @@ -39,12 +32,6 @@ var winston = require('winston'), } topics[isDelete ? 'delete' : 'restore'](tid, function(err) { - function emitTo(room) { - websockets.in(room).emit(isDelete ? 'event:topic_deleted' : 'event:topic_restored', { - tid: tid, - isDelete: isDelete - }); - } if (err) { return callback(err); } @@ -56,19 +43,20 @@ var winston = require('winston'), plugins.fireHook('action:topic.restore', topicData); } - events[isDelete ? 'logTopicDelete' : 'logTopicRestore'](uid, tid); + var data = { + tid: tid, + cid: topicData.cid, + isDelete: isDelete, + uid: uid + }; - emitTo('topic_' + tid); - emitTo('category_' + topicData.cid); - - callback(null, { - tid: tid - }); + callback(null, data); }); }); } ThreadTools.purge = function(tid, uid, callback) { + var topic; async.waterfall([ function(next) { topics.exists(tid, next); @@ -82,13 +70,17 @@ var winston = require('winston'), }, {alwaysStartAt: 0}, next); }, function(next) { - topics.getTopicField(tid, 'mainPid', next); + topics.getTopicFields(tid, ['mainPid', 'cid'], next); }, - function(mainPid, next) { - posts.purge(mainPid, next); + function(_topic, next) { + topic = _topic; + posts.purge(topic.mainPid, next); }, function(next) { topics.purge(tid, next); + }, + function(next) { + next(null, {tid: tid, cid: topic.cid, uid: uid}); } ], callback); }; @@ -102,35 +94,24 @@ var winston = require('winston'), }; function toggleLock(tid, uid, lock, callback) { + callback = callback || function() {}; topics.getTopicField(tid, 'cid', function(err, cid) { - function emitTo(room) { - websockets.in(room).emit(lock ? 'event:topic_locked' : 'event:topic_unlocked', { - tid: tid, - isLocked: lock - }); - } - - if (err && typeof callback === 'function') { + if (err) { return callback(err); } topics.setTopicField(tid, 'locked', lock ? 1 : 0); - plugins.fireHook('action:topic.lock', { + var data = { tid: tid, isLocked: lock, - uid: uid - }); + uid: uid, + cid: cid + }; - emitTo('topic_' + tid); - emitTo('category_' + cid); + plugins.fireHook('action:topic.lock', data); - if (typeof callback === 'function') { - callback(null, { - tid: tid, - isLocked: lock - }); - } + callback(null, data); }); } @@ -144,13 +125,6 @@ var winston = require('winston'), function togglePin(tid, uid, pin, callback) { topics.getTopicFields(tid, ['cid', 'lastposttime'], function(err, topicData) { - function emitTo(room) { - websockets.in(room).emit(pin ? 'event:topic_pinned' : 'event:topic_unpinned', { - tid: tid, - isPinned: pin - }); - } - if (err) { return callback(err); } @@ -158,19 +132,16 @@ var winston = require('winston'), topics.setTopicField(tid, 'pinned', pin ? 1 : 0); db.sortedSetAdd('cid:' + topicData.cid + ':tids', pin ? Math.pow(2, 53) : topicData.lastposttime, tid); - plugins.fireHook('action:topic.pin', { + var data = { tid: tid, isPinned: pin, - uid: uid - }); + uid: uid, + cid: topicData.cid + }; - emitTo('topic_' + tid); - emitTo('category_' + topicData.cid); + plugins.fireHook('action:topic.pin', data); - callback(null, { - tid: tid, - isPinned: pin - }); + callback(null, data); }); } @@ -214,8 +185,6 @@ var winston = require('winston'), topics.setTopicField(tid, 'cid', cid, callback); - events.logTopicMove(uid, tid); - plugins.fireHook('action:topic.move', { tid: tid, fromCid: oldCid, diff --git a/src/topics.js b/src/topics.js index 1e9df9958f..a9514dabba 100644 --- a/src/topics.js +++ b/src/topics.js @@ -215,28 +215,14 @@ var async = require('async'), } async.parallel({ + mainPost: function(next) { + getMainPosts([topicData.mainPid], uid, next); + }, posts: function(next) { - posts.getPidsFromSet(set, start, end, reverse, function(err, pids) { - if (err) { - return next(err); - } - - pids = topicData.mainPid ? [topicData.mainPid].concat(pids) : pids; - - if (!pids.length) { - return next(null, []); - } - posts.getPostsByPids(pids, uid, function(err, posts) { - if (err) { - return next(err); - } - - Topics.addPostData(posts, uid, next); - }); - }); + Topics.getTopicPosts(tid, set, start, end, uid, reverse, next); }, category: async.apply(Topics.getCategoryData, tid), - threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', []), + threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', {topic: topicData, uid: uid, tools: []}), tags: async.apply(Topics.getTopicTagsObjects, tid), isFollowing: async.apply(Topics.isFollowing, [tid], uid) }, function(err, results) { @@ -244,9 +230,9 @@ var async = require('async'), return callback(err); } - topicData.posts = results.posts; + topicData.posts = Array.isArray(results.mainPost) && results.mainPost.length ? [results.mainPost[0]].concat(results.posts) : results.posts; topicData.category = results.category; - topicData.thread_tools = results.threadTools; + topicData.thread_tools = results.threadTools.tools; topicData.tags = results.tags; topicData.isFollowing = results.isFollowing[0]; @@ -255,7 +241,9 @@ var async = require('async'), topicData.locked = parseInt(topicData.locked, 10) === 1; topicData.pinned = parseInt(topicData.pinned, 10) === 1; - plugins.fireHook('filter:topic.get', topicData, callback); + plugins.fireHook('filter:topic.get', {topic: topicData, uid: uid}, function(err, data) { + callback(err, data ? data.topic : null); + }); }); }); }; @@ -276,16 +264,24 @@ var async = require('async'), return topic ? topic.mainPid : null; }); - posts.getPostsByPids(mainPids, uid, function(err, postData) { - if (err) { - return callback(err); - } - - Topics.addPostData(postData, uid, callback); - }); + getMainPosts(mainPids, uid, callback); }); }; + function getMainPosts(mainPids, uid, callback) { + posts.getPostsByPids(mainPids, uid, function(err, postData) { + if (err) { + return callback(err); + } + postData.forEach(function(post) { + if (post) { + post.index = 0; + } + }); + Topics.addPostData(postData, uid, callback); + }); + } + Topics.getTopicField = function(tid, field, callback) { db.getObjectField('topic:' + tid, field, callback); }; diff --git a/src/topics/create.js b/src/topics/create.js index b3038911c1..2eb882da80 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -289,6 +289,8 @@ module.exports = function(Topics) { function checkContentLength(content, callback) { if (!content || content.length < parseInt(meta.config.miminumPostLength, 10)) { return callback(new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]')); + } else if (content.length > parseInt(meta.config.maximumPostLength, 10)) { + return callback(new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]')); } callback(); } diff --git a/src/topics/follow.js b/src/topics/follow.js index 7d88c9752e..7bcfab8ea7 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -142,7 +142,7 @@ module.exports = function(Topics) { postBody: postData.content, site_title: meta.config.title || 'NodeBB', username: data.userData.username, - url: nconf.get('url') + '/topics/' + postData.topic.tid, + url: nconf.get('url') + '/topic/' + postData.topic.tid, base_url: nconf.get('url') }, next); } else { diff --git a/src/topics/popular.js b/src/topics/popular.js index ce2182cabf..a1149914fc 100644 --- a/src/topics/popular.js +++ b/src/topics/popular.js @@ -34,10 +34,12 @@ module.exports = function(Topics) { function getTopics(tids, uid, count, callback) { async.waterfall([ function(next) { - Topics.getTopicsFields(tids, ['tid', 'postcount'], next); + Topics.getTopicsFields(tids, ['tid', 'postcount', 'deleted'], next); }, function(topics, next) { - tids = topics.sort(function(a, b) { + tids = topics.filter(function(topic) { + return topic && parseInt(topic.deleted, 10) !== 1; + }).sort(function(a, b) { return b.postcount - a.postcount; }).slice(0, count).map(function(topic) { return topic.tid; diff --git a/src/topics/posts.js b/src/topics/posts.js index 9e3275887f..6d4cd9be8f 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -29,15 +29,28 @@ module.exports = function(Topics) { ], callback); }; - Topics.getTopicPosts = function(tid, set, start, end, uid, reverse, callback) { callback = callback || function() {}; - posts.getPostsByTid(tid, set, start, end, uid, reverse, function(err, postData) { + async.parallel({ + posts: function(next) { + posts.getPostsByTid(tid, set, start, end, uid, reverse, next); + }, + postCount: function(next) { + Topics.getTopicField(tid, 'postcount', next); + } + }, function(err, results) { if (err) { return callback(err); } - Topics.addPostData(postData, uid, callback); + var indices = Topics.calculatePostIndices(start, end, results.postCount, reverse); + results.posts.forEach(function(post, index) { + if (post) { + post.index = indices[index]; + } + }); + + Topics.addPostData(results.posts, uid, callback); }); }; @@ -103,9 +116,6 @@ module.exports = function(Topics) { }, privileges: function(next) { privileges.posts.get(pids, uid, next); - }, - indices: function(next) { - posts.getPostIndices(postData, uid, next); } }, function(err, results) { if (err) { @@ -114,7 +124,6 @@ module.exports = function(Topics) { postData.forEach(function(postObj, i) { if (postObj) { - postObj.index = results.indices[i]; postObj.deleted = parseInt(postObj.deleted, 10) === 1; postObj.user = parseInt(postObj.uid, 10) ? results.userData[postObj.uid] : _.clone(results.userData[postObj.uid]); postObj.editor = postObj.editor ? results.editors[postObj.editor] : null; @@ -141,6 +150,19 @@ module.exports = function(Topics) { }); }; + Topics.calculatePostIndices = function(start, end, postCount, reverse) { + var indices = []; + var count = end - start + 1; + for(var i=0; i b; }); - - callback(null, matches); + + plugins.fireHook('filter:tags.search', {data: data, matches: matches}, function(err, data) { + callback(err, data ? data.matches : []); + }); }); }; diff --git a/src/upgrade.js b/src/upgrade.js index d433c9c06f..52347bcb40 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -21,7 +21,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2015, 0, 21); + latestSchema = Date.UTC(2015, 1, 8); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -773,6 +773,60 @@ Upgrade.upgrade = function(callback) { winston.info('[2015/01/21] Upgrading groups to sorted set skipped'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 0, 30); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/01/30] Adding group member counts'); + + db.getSortedSetRange('groups:createtime', 0, -1, function(err, groupNames) { + if (err) { + return next(err); + } + + var now = Date.now(); + async.each(groupNames, function(groupName, next) { + db.sortedSetCard('group:' + groupName + ':members', function(err, memberCount) { + if (err) { + return next(err); + } + + if (parseInt(memberCount, 10)) { + db.setObjectField('group:' + groupName, 'memberCount', memberCount, next); + } else { + next(); + } + }); + }, function(err) { + winston.info('[2015/01/30] Adding group member counts done'); + Upgrade.update(thisSchemaDate, next); + }); + }); + } else { + winston.info('[2015/01/30] Adding group member counts skipped'); + next(); + } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 1, 8); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/02/08] Clearing reset tokens'); + + db.deleteAll(['reset:expiry', 'reset:uid'], function(err) { + if (err) { + winston.error('[2015/02/08] Error encountered while Clearing reset tokens'); + return next(err); + } + + winston.info('[2015/02/08] Clearing reset tokens done'); + Upgrade.update(thisSchemaDate, next); + }); + } else { + winston.info('[2015/02/08] Clearing reset tokens skipped'); + next(); + } } // Add new schema updates here diff --git a/src/user.js b/src/user.js index ccb30fecfb..109e67a3f0 100644 --- a/src/user.js +++ b/src/user.js @@ -7,6 +7,7 @@ var async = require('async'), plugins = require('./plugins'), db = require('./database'), meta = require('./meta'), + topics = require('./topics'), groups = require('./groups'), Password = require('./password'); @@ -119,7 +120,7 @@ var async = require('async'), if (user.picture) { if (user.picture === user.uploadedpicture) { - user.picture = user.picture.indexOf('http') === -1 ? nconf.get('relative_path') + user.picture : user.picture; + user.picture = user.uploadedpicture = user.picture.indexOf('http') === -1 ? nconf.get('relative_path') + user.picture : user.picture; } else { user.picture = User.createGravatarURLFromEmail(user.email); } @@ -147,24 +148,31 @@ var async = require('async'), User.updateOnlineUsers = function(uid, callback) { callback = callback || function() {}; - db.sortedSetScore('users:online', uid, function(err, score) { - var now = Date.now(); - if (err || now - parseInt(score, 10) < 300000) { - return callback(err); - } - db.sortedSetAdd('users:online', now, uid, function(err) { - if (err) { - return callback(err); + + var now = Date.now(); + async.waterfall([ + function(next) { + db.sortedSetScore('users:online', uid, next); + }, + function(userOnlineTime, next) { + if (now - parseInt(userOnlineTime, 10) < 300000) { + return callback(); } + db.sortedSetAdd('users:online', now, uid, next); + }, + function(next) { + topics.pushUnreadCount(uid); plugins.fireHook('action:user.online', {uid: uid, timestamp: now}); - }); - }); + next(); + } + ], callback); }; User.setUserField = function(uid, field, value, callback) { + callback = callback || function() {}; db.setObjectField('user:' + uid, field, value, function(err) { if (err) { - return callback(err) + return callback(err); } plugins.fireHook('action:user.set', {uid: uid, field: field, value: value, type: 'set'}); callback(); @@ -172,6 +180,7 @@ var async = require('async'), }; User.setUserFields = function(uid, data, callback) { + callback = callback || function() {}; db.setObject('user:' + uid, data, function(err) { if (err) { return callback(err); @@ -219,18 +228,18 @@ var async = require('async'), } }; - User.getUsersFromSet = function(set, start, stop, callback) { + User.getUsersFromSet = function(set, uid, start, stop, callback) { async.waterfall([ function(next) { User.getUidsFromSet(set, start, stop, next); }, function(uids, next) { - User.getUsers(uids, next); + User.getUsers(uids, uid, next); } ], callback); }; - User.getUsers = function(uids, callback) { + User.getUsers = function(uids, uid, callback) { var fields = ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'postcount', 'reputation', 'email:confirmed']; plugins.fireHook('filter:users.addFields', {fields: fields}, function(err, data) { if (err) { @@ -264,11 +273,10 @@ var async = require('async'), user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1; }); - plugins.fireHook('filter:userlist.get', {users: results.userData}, function(err, data) { + plugins.fireHook('filter:userlist.get', {users: results.userData, uid: uid}, function(err, data) { if (err) { return callback(err); } - callback(null, data.users); }); }); @@ -433,6 +441,26 @@ var async = require('async'), db.getSortedSetRange('uid:' + uid + ':ignored:cids', 0, -1, callback); }; + User.getWatchedCategories = function(uid, callback) { + async.parallel({ + ignored: function(next) { + User.getIgnoredCategories(uid, next); + }, + all: function(next) { + db.getSortedSetRange('categories:cid', 0, -1, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + var watched = results.all.filter(function(cid) { + return cid && results.ignored.indexOf(cid) === -1; + }); + callback(null, watched); + }); + }; + User.ignoreCategory = function(uid, cid, callback) { if (!uid) { return callback(); diff --git a/src/user/auth.js b/src/user/auth.js index b275882cf1..48f0c8fc2c 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -8,7 +8,7 @@ var async = require('async'), module.exports = function(User) { User.auth = {}; - User.auth.logAttempt = function(uid, callback) { + User.auth.logAttempt = function(uid, ip, callback) { db.exists('lockout:' + uid, function(err, exists) { if (err) { return callback(err); @@ -30,12 +30,15 @@ module.exports = function(User) { return callback(err); } var duration = 1000 * 60 * (meta.config.lockoutDuration || 60); - + db.delete('loginAttempts:' + uid); db.pexpire('lockout:' + uid, duration); - - events.logAccountLock(uid, duration); - callback(new Error('account-locked')); + events.log({ + type: 'account-locked', + uid: uid, + ip: ip + }); + callback(new Error('[[error:account-locked]]')); }); } else { db.pexpire('loginAttempts:' + uid, 1000 * 60 * 60); diff --git a/src/user/digest.js b/src/user/digest.js index 62c8a11ae8..06ea1aa967 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -9,7 +9,8 @@ var async = require('async'), user = require('../user'), topics = require('../topics'), batch = require('../batch'), - emailer = require('../emailer'); + emailer = require('../emailer'), + utils = require('../../public/src/utils'); (function(Digest) { Digest.execute = function(interval) { @@ -31,6 +32,22 @@ var async = require('async'), return winston.error('[user/jobs] Could not send digests (' + interval + '): ' + err.message); } + // Fix relative paths in topic data + data.topics.topics = data.topics.topics.map(function(topicObj) { + if (topicObj.hasOwnProperty('teaser') && topicObj.teaser !== undefined) { + if (utils.isRelativeUrl(topicObj.teaser.user.picture)) { + topicObj.teaser.user.picture = nconf.get('url') + topicObj.teaser.user.picture; + } + } else { + if (utils.isRelativeUrl(topicObj.user.picture)) { + topicObj.user.picture = nconf.get('url') + topicObj.user.picture; + } + } + + return topicObj; + }); + return; + data.interval = interval; if (data.subscribers.length) { diff --git a/src/user/email.js b/src/user/email.js index 9a4fd2cd73..74b86c0cfe 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -27,11 +27,16 @@ var async = require('async'), }); }; - UserEmail.verify = function(uid, email) { + UserEmail.verify = function(uid, email, callback) { + callback = callback || function() {}; var confirm_code = utils.generateUUID(), confirm_link = nconf.get('url') + '/confirm/' + confirm_code; plugins.fireHook('filter:user.verify.code', confirm_code, function(err, confirm_code) { + if (err) { + return callback(err); + } + async.series([ function(next) { db.setObject('confirm:' + confirm_code, { @@ -43,7 +48,9 @@ var async = require('async'), db.expireAt('confirm:' + confirm_code, Math.floor(Date.now() / 1000 + 60 * 60 * 2), next); } ], function(err) { - + if (err) { + return callback(err); + } user.getUserField(uid, 'username', function(err, username) { if (err) { return winston.error(err.stack); @@ -64,10 +71,12 @@ var async = require('async'), if (plugins.hasListeners('action:user.verify')) { plugins.fireHook('action:user.verify', {uid: uid, data: data}); + callback(); } else if (plugins.hasListeners('action:email.send')) { - emailer.send('welcome', uid, data); + emailer.send('welcome', uid, data, callback); } else { winston.warn('No emailer to send verification email!'); + callback(); } }); }); diff --git a/src/user/follow.js b/src/user/follow.js index c3e2cb340c..6b0c0a3973 100644 --- a/src/user/follow.js +++ b/src/user/follow.js @@ -59,7 +59,7 @@ module.exports = function(User) { return callback(err); } - User.getUsers(uids, callback); + User.getUsers(uids, uid, callback); }); } diff --git a/src/user/jobs.js b/src/user/jobs.js index 506f0d388b..16f6bd4ce8 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -4,7 +4,6 @@ var winston = require('winston'), cronJob = require('cron').CronJob, - user = require('../user'), meta = require('../meta'); module.exports = function(User) { @@ -23,6 +22,8 @@ module.exports = function(User) { winston.verbose('[user.startJobs] Digest job (monthly) started.'); User.digest.execute('month'); }, null, true); + + new cronJob('0 0 0 * * *', User.reset.clean, null, true); }; }; diff --git a/src/user/profile.js b/src/user/profile.js index 8c44b86a6f..829c143505 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -100,7 +100,7 @@ module.exports = function(User) { return callback(err); } plugins.fireHook('action:user.updateProfile', {data: data, uid: uid}); - User.getUserFields(uid, ['email', 'userslug', 'picture', 'gravatarpicture'], callback); + User.getUserFields(uid, ['email', 'username', 'userslug', 'picture', 'gravatarpicture'], callback); }); }); @@ -148,8 +148,6 @@ module.exports = function(User) { return callback(err); } - events.logEmailChange(uid, userData.email, newEmail); - var gravatarpicture = User.createGravatarURLFromEmail(newEmail); async.parallel([ function(next) { @@ -183,9 +181,13 @@ module.exports = function(User) { if (!newUsername) { return callback(); } + User.getUserFields(uid, ['username', 'userslug'], function(err, userData) { function update(field, object, value, callback) { - async.parallel([ + async.series([ + function(next) { + db.deleteObjectField(field + ':uid', userData[field], next); + }, function(next) { User.setUserField(uid, field, value, next); }, @@ -198,7 +200,6 @@ module.exports = function(User) { if (err) { return callback(err); } - var userslug = utils.slugify(newUsername); async.parallel([ function(next) { @@ -206,25 +207,15 @@ module.exports = function(User) { return next(); } - db.deleteObjectField('username:uid', userData.username, function(err) { - if (err) { - return next(err); - } - events.logUsernameChange(uid, userData.username, newUsername); - update('username', 'username:uid', newUsername, next); - }); + update('username', 'username:uid', newUsername, next); }, function(next) { - if (userslug === userData.userslug) { + var newUserslug = utils.slugify(newUsername); + if (newUserslug === userData.userslug) { return next(); } - db.deleteObjectField('userslug:uid', userData.userslug, function(err) { - if (err) { - return next(err); - } - update('userslug', 'userslug:uid', userslug, next); - }); + update('userslug', 'userslug:uid', newUserslug, next); } ], callback); }); @@ -261,23 +252,11 @@ module.exports = function(User) { function hashAndSetPassword(callback) { User.hashPassword(data.newPassword, function(err, hash) { - if(err) { + if (err) { return callback(err); } - User.setUserField(data.uid, 'password', hash, function(err) { - if(err) { - return callback(err); - } - - if(parseInt(uid, 10) === parseInt(data.uid, 10)) { - events.logPasswordChange(data.uid); - } else { - events.logAdminChangeUserPassword(uid, data.uid); - } - - callback(); - }); + User.setUserField(data.uid, 'password', hash, callback); }); } diff --git a/src/user/reset.js b/src/user/reset.js index 2e1a7ab80e..60ff820dbf 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -1,8 +1,8 @@ - 'use strict'; var async = require('async'), nconf = require('nconf'), + winston = require('winston'), user = require('../user'), utils = require('../../public/src/utils'), @@ -14,26 +14,19 @@ var async = require('async'), emailer = require('../emailer'); (function(UserReset) { - UserReset.validate = function(code, callback) { db.getObjectField('reset:uid', code, function(err, uid) { if (err || !uid) { return callback(err, false); } - db.getObjectField('reset:expiry', code, function(err, expiry) { + db.sortedSetScore('reset:issueDate', code, function(err, issueDate) { + // db.getObjectField('reset:expiry', code, function(err, expiry) { if (err) { return callback(err); } - if (parseInt(expiry, 10) >= Date.now() / 1000) { - callback(null, true); - } else { - // Expired, delete from db - db.deleteObjectField('reset:uid', code); - db.deleteObjectField('reset:expiry', code); - callback(null, false); - } + callback(null, parseInt(issueDate, 10) > (Date.now() - (1000*60*120))); }); }); }; @@ -46,7 +39,7 @@ var async = require('async'), var reset_code = utils.generateUUID(); db.setObjectField('reset:uid', reset_code, uid); - db.setObjectField('reset:expiry', reset_code, (60 * 60) + Math.floor(Date.now() / 1000)); + db.sortedSetAdd('reset:issueDate', Date.now(), reset_code); var reset_link = nconf.get('url') + '/reset/' + reset_code; @@ -70,7 +63,7 @@ var async = require('async'), } if (!validated) { - return; + return callback(new Error('[[error:reset-code-not-valid]]')); } db.getObjectField('reset:uid', code, function(err, uid) { @@ -83,10 +76,9 @@ var async = require('async'), return callback(err); } user.setUserField(uid, 'password', hash); - events.logPasswordReset(uid); db.deleteObjectField('reset:uid', code); - db.deleteObjectField('reset:expiry', code); + db.sortedSetRemove('reset:issueDate', code); user.auth.resetLockout(uid, callback); }); @@ -94,4 +86,20 @@ var async = require('async'), }); }; + UserReset.clean = function(callback) { + // Locate all codes that have expired, and remove them from the set/hash + async.waterfall([ + async.apply(db.getSortedSetRangeByScore, 'reset:issueDate', 0, -1, -1, +new Date()-(1000*60*120)), + function(tokens, next) { + if (!tokens.length) { return next(); } + + winston.verbose('[UserReset.clean] Removing ' + tokens.length + ' reset tokens from database'); + async.parallel([ + async.apply(db.deleteObjectField, 'reset:uid', tokens), + async.apply(db.sortedSetRemove, 'reset:issueDate', tokens) + ], next); + } + ], callback); + }; + }(exports)); diff --git a/src/user/search.js b/src/user/search.js index 95130bf68f..20bbec2258 100644 --- a/src/user/search.js +++ b/src/user/search.js @@ -14,13 +14,10 @@ module.exports = function(User) { var searchBy = data.searchBy || ['username']; var startsWith = data.hasOwnProperty('startsWith') ? data.startsWith : true; var page = data.page || 1; - - if (!query) { - return callback(null, {timing: 0, users: [], matchCount: 0, pages: []}); - } + var uid = data.uid || 0; if (searchBy.indexOf('ip') !== -1) { - return searchByIP(query, callback); + return searchByIP(query, uid, callback); } var startTime = process.hrtime(); @@ -46,21 +43,18 @@ module.exports = function(User) { matchCount = uids.length; uids = uids.slice(start, end); - User.getUsers(uids, next); + User.getUsers(uids, uid, next); }, function(userData, next) { - - var diff = process.hrtime(startTime); - var timing = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(1); var data = { - timing: timing, + timing: (process.elapsedTimeSince(startTime) / 1000).toFixed(2), users: userData, matchCount: matchCount }; var currentPage = Math.max(1, Math.ceil((start + 1) / resultsPerPage)); pageCount = Math.ceil(matchCount / resultsPerPage); - pagination.create(currentPage, pageCount, data); + data.pagination = pagination.create(currentPage, pageCount); next(null, data); } @@ -194,14 +188,14 @@ module.exports = function(User) { } } - function searchByIP(ip, callback) { + function searchByIP(ip, uid, callback) { var start = process.hrtime(); async.waterfall([ function(next) { db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, next); }, function(uids, next) { - User.getUsers(uids, next); + User.getUsers(uids, uid, next); }, function(users, next) { var diff = process.hrtime(start); diff --git a/src/views/admin/advanced/events.tpl b/src/views/admin/advanced/events.tpl index 03e3b7f4eb..7aec71b6f2 100644 --- a/src/views/admin/advanced/events.tpl +++ b/src/views/admin/advanced/events.tpl @@ -1,31 +1,31 @@
    -
    +
    Events
    -
    {eventdata}
    + +
    There are no events
    + +
    + +
    + #{events.eid} {events.type} + {events.user.username} (uid {events.user.uid}) (IP {events.ip}) + {events.timestampISO} +

    +
    {events.jsonString}
    +
    + +
    +
    +
    +
    +
    +
    +
    Events Control Panel
    +
    +
    - - - \ No newline at end of file diff --git a/src/views/admin/advanced/logs.tpl b/src/views/admin/advanced/logs.tpl index 0311573d25..24f91ce60b 100644 --- a/src/views/admin/advanced/logs.tpl +++ b/src/views/admin/advanced/logs.tpl @@ -7,7 +7,7 @@
    -
    +
    Logs Control Panel
    diff --git a/src/views/admin/appearance/skins.tpl b/src/views/admin/appearance/skins.tpl index e3e91680af..10211893f5 100644 --- a/src/views/admin/appearance/skins.tpl +++ b/src/views/admin/appearance/skins.tpl @@ -12,7 +12,7 @@
    -
    +
    Revert to Default
    @@ -29,4 +29,4 @@ t.render(data); }); }; - \ No newline at end of file + diff --git a/src/views/admin/development/logger.tpl b/src/views/admin/development/logger.tpl index 826f9e5bcc..6e9a932230 100644 --- a/src/views/admin/development/logger.tpl +++ b/src/views/admin/development/logger.tpl @@ -40,7 +40,7 @@
    -
    +
    Logger Control Panel
    diff --git a/src/views/admin/extend/plugins.tpl b/src/views/admin/extend/plugins.tpl index eb709885a2..b44c2461bc 100644 --- a/src/views/admin/extend/plugins.tpl +++ b/src/views/admin/extend/plugins.tpl @@ -79,7 +79,7 @@
    -
    +
    Plugin Search
    @@ -96,4 +96,4 @@
    -
    \ No newline at end of file +
    diff --git a/src/views/admin/general/languages.tpl b/src/views/admin/general/languages.tpl index bc75b2fee4..b2365e91a3 100644 --- a/src/views/admin/general/languages.tpl +++ b/src/views/admin/general/languages.tpl @@ -25,7 +25,7 @@
    -
    +
    Languages Control Panel
    @@ -37,4 +37,4 @@ \ No newline at end of file + diff --git a/src/views/admin/general/sounds.tpl b/src/views/admin/general/sounds.tpl index 3556bcbb7d..fb43c138aa 100644 --- a/src/views/admin/general/sounds.tpl +++ b/src/views/admin/general/sounds.tpl @@ -58,7 +58,7 @@
    -
    +
    Sounds Control Panel
    @@ -66,4 +66,4 @@
    -
    \ No newline at end of file +
    diff --git a/src/views/admin/manage/categories.tpl b/src/views/admin/manage/categories.tpl index 2c0dcf48da..711cdbce72 100644 --- a/src/views/admin/manage/categories.tpl +++ b/src/views/admin/manage/categories.tpl @@ -132,7 +132,7 @@
    -
    +
    Categories Control Panel
    @@ -153,4 +153,4 @@
    -
    \ No newline at end of file +
    diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 929fd6674d..23a5d6f796 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -41,7 +41,7 @@
    -
    +
    Flags Control Panel
    @@ -52,5 +52,3 @@
    - - diff --git a/src/views/admin/manage/groups.tpl b/src/views/admin/manage/groups.tpl index 69f8bad37b..26fe157dac 100644 --- a/src/views/admin/manage/groups.tpl +++ b/src/views/admin/manage/groups.tpl @@ -37,7 +37,7 @@
    -
    +
    Groups Control Panel
    diff --git a/src/views/admin/manage/tags.tpl b/src/views/admin/manage/tags.tpl index afacffb2d4..1b8c687b00 100644 --- a/src/views/admin/manage/tags.tpl +++ b/src/views/admin/manage/tags.tpl @@ -1,11 +1,11 @@
    - -
    - Your forum does not have any topics with tags yet! -
    -
    + +
    + Your forum does not have any topics with tags yet! +
    +
    Tag Management
    @@ -34,7 +34,7 @@
    -
    +
    Modify Tag
    @@ -52,4 +52,4 @@
    -
    \ No newline at end of file +
    diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl index 1e034474b8..a4997c49e0 100644 --- a/src/views/admin/manage/users.tpl +++ b/src/views/admin/manage/users.tpl @@ -18,6 +18,7 @@
  • Remove Admin
  • Validate Email
  • +
  • Send Validation Email
  • Send Password Reset Email
  • Ban User
  • @@ -123,7 +124,7 @@
    -
    +
    Users Control Panel
    @@ -132,4 +133,4 @@
    -
    \ No newline at end of file +
    diff --git a/src/views/admin/settings/footer.tpl b/src/views/admin/settings/footer.tpl index 77b495e33c..78e62335c5 100644 --- a/src/views/admin/settings/footer.tpl +++ b/src/views/admin/settings/footer.tpl @@ -1,6 +1,6 @@
    -
    +
    Save Settings
    @@ -14,4 +14,4 @@ require(['admin/settings'], function(Settings) { Settings.prepare(); }); - \ No newline at end of file + diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index 5c35ea8542..b403835994 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -28,6 +28,20 @@
    +
    +
    Home Page
    +
    +
    + + +
    +
    +
    +
    Site Logo
    diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index 7da62689ce..11a3c41f72 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -15,6 +15,15 @@

    + +
    + +
    diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index 15f65ef531..3cb55eac0e 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -49,6 +49,10 @@
    +
    + + +
    -
    -
    User Bans
    -
    -
    -
    - - -
    -
    -
    - -
    - - -
    -
    -
    -
    User Registration
    diff --git a/src/views/admin/settings/web-crawler.tpl b/src/views/admin/settings/web-crawler.tpl index c8fb03b0ff..349b5f6664 100644 --- a/src/views/admin/settings/web-crawler.tpl +++ b/src/views/admin/settings/web-crawler.tpl @@ -26,8 +26,12 @@
    - - +
    + + +
    + +
    diff --git a/src/views/config.json b/src/views/config.json index 70997cf4a8..f8a04fa620 100644 --- a/src/views/config.json +++ b/src/views/config.json @@ -1,6 +1,6 @@ { "custom_mapping": { - "^\/?$": "home", + "^\/?$": "categories", "^admin?$": "admin/general/dashboard", "^users/sort-posts": "users", "^users/latest": "users", @@ -14,6 +14,7 @@ "^user/.*/watched": "account/watched", "^user/.*/posts": "account/posts", "^user/.*/topics": "account/topics", + "^user/.*/groups": "account/groups", "^user/[^\/]+": "account/profile", "^reset/.*": "reset_code", "^tags/.*": "tag", diff --git a/src/views/emails/reset_notify.tpl b/src/views/emails/reset_notify.tpl new file mode 100644 index 0000000000..34c26aa481 --- /dev/null +++ b/src/views/emails/reset_notify.tpl @@ -0,0 +1,10 @@ +

    [[email:greeting_with_name, {username}]],

    + +

    [[email:reset.notify.text1, {date}]]

    + +

    [[email:reset.notify.text2]]

    + +

    + [[email:closing]]
    + {site_title} +

    \ No newline at end of file diff --git a/src/views/emails/reset_notify_plaintext.tpl b/src/views/emails/reset_notify_plaintext.tpl new file mode 100644 index 0000000000..788618f9d5 --- /dev/null +++ b/src/views/emails/reset_notify_plaintext.tpl @@ -0,0 +1,8 @@ +[[email:greeting_with_name, {username}]], + +[[email:reset.notify.text1, {date}]] + +[[email:reset.notify.text2]] + +[[email:closing]] +{site_title} \ No newline at end of file diff --git a/src/widgets.js b/src/widgets.js index 047befa8c2..c0234b2a28 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -44,6 +44,10 @@ var async = require('async'), return next(err); } + if (typeof html !== 'string') { + html = ''; + } + if (widget.data.container && widget.data.container.match('{body}')) { html = templates.parse(widget.data.container, { title: widget.data.title,