diff --git a/.tx/config b/.tx/config
index 600be44023..eb73e33399 100644
--- a/.tx/config
+++ b/.tx/config
@@ -18,6 +18,7 @@ trans.fr = public/language/fr/category.json
trans.he = public/language/he/category.json
trans.hu = public/language/hu/category.json
trans.it = public/language/it/category.json
+trans.ja = public/language/ja/category.json
trans.lt = public/language/lt/category.json
trans.ms = public/language/ms/category.json
trans.nb = public/language/nb/category.json
@@ -30,6 +31,7 @@ trans.sk = public/language/sk/category.json
trans.sv = public/language/sv/category.json
trans.th = public/language/th/category.json
trans.tr = public/language/tr/category.json
+trans.vi = public/language/vi/category.json
trans.zh_CN = public/language/zh_CN/category.json
trans.zh_TW = public/language/zh_TW/category.json
type = KEYVALUEJSON
@@ -51,6 +53,7 @@ trans.fr = public/language/fr/login.json
trans.he = public/language/he/login.json
trans.hu = public/language/hu/login.json
trans.it = public/language/it/login.json
+trans.ja = public/language/ja/login.json
trans.lt = public/language/lt/login.json
trans.ms = public/language/ms/login.json
trans.nb = public/language/nb/login.json
@@ -63,6 +66,7 @@ trans.sk = public/language/sk/login.json
trans.sv = public/language/sv/login.json
trans.th = public/language/th/login.json
trans.tr = public/language/tr/login.json
+trans.vi = public/language/vi/login.json
trans.zh_CN = public/language/zh_CN/login.json
trans.zh_TW = public/language/zh_TW/login.json
type = KEYVALUEJSON
@@ -83,6 +87,7 @@ trans.fr = public/language/fr/recent.json
trans.he = public/language/he/recent.json
trans.hu = public/language/hu/recent.json
trans.it = public/language/it/recent.json
+trans.ja = public/language/ja/recent.json
trans.lt = public/language/lt/recent.json
trans.ms = public/language/ms/recent.json
trans.nb = public/language/nb/recent.json
@@ -95,6 +100,7 @@ trans.sk = public/language/sk/recent.json
trans.sv = public/language/sv/recent.json
trans.th = public/language/th/recent.json
trans.tr = public/language/tr/recent.json
+trans.vi = public/language/vi/recent.json
trans.zh_CN = public/language/zh_CN/recent.json
trans.zh_TW = public/language/zh_TW/recent.json
type = KEYVALUEJSON
@@ -115,6 +121,7 @@ trans.fr = public/language/fr/unread.json
trans.he = public/language/he/unread.json
trans.hu = public/language/hu/unread.json
trans.it = public/language/it/unread.json
+trans.ja = public/language/ja/unread.json
trans.lt = public/language/lt/unread.json
trans.ms = public/language/ms/unread.json
trans.nb = public/language/nb/unread.json
@@ -127,6 +134,7 @@ trans.sk = public/language/sk/unread.json
trans.sv = public/language/sv/unread.json
trans.th = public/language/th/unread.json
trans.tr = public/language/tr/unread.json
+trans.vi = public/language/vi/unread.json
trans.zh_CN = public/language/zh_CN/unread.json
trans.zh_TW = public/language/zh_TW/unread.json
type = KEYVALUEJSON
@@ -147,6 +155,7 @@ trans.fr = public/language/fr/modules.json
trans.he = public/language/he/modules.json
trans.hu = public/language/hu/modules.json
trans.it = public/language/it/modules.json
+trans.ja = public/language/ja/modules.json
trans.lt = public/language/lt/modules.json
trans.ms = public/language/ms/modules.json
trans.nb = public/language/nb/modules.json
@@ -159,6 +168,7 @@ trans.sk = public/language/sk/modules.json
trans.sv = public/language/sv/modules.json
trans.th = public/language/th/modules.json
trans.tr = public/language/tr/modules.json
+trans.vi = public/language/vi/modules.json
trans.zh_CN = public/language/zh_CN/modules.json
trans.zh_TW = public/language/zh_TW/modules.json
type = KEYVALUEJSON
@@ -179,6 +189,7 @@ trans.fr = public/language/fr/register.json
trans.he = public/language/he/register.json
trans.hu = public/language/hu/register.json
trans.it = public/language/it/register.json
+trans.ja = public/language/ja/register.json
trans.lt = public/language/lt/register.json
trans.ms = public/language/ms/register.json
trans.nb = public/language/nb/register.json
@@ -191,6 +202,7 @@ trans.sk = public/language/sk/register.json
trans.sv = public/language/sv/register.json
trans.th = public/language/th/register.json
trans.tr = public/language/tr/register.json
+trans.vi = public/language/vi/register.json
trans.zh_CN = public/language/zh_CN/register.json
trans.zh_TW = public/language/zh_TW/register.json
type = KEYVALUEJSON
@@ -211,6 +223,7 @@ trans.fr = public/language/fr/user.json
trans.he = public/language/he/user.json
trans.hu = public/language/hu/user.json
trans.it = public/language/it/user.json
+trans.ja = public/language/ja/user.json
trans.lt = public/language/lt/user.json
trans.ms = public/language/ms/user.json
trans.nb = public/language/nb/user.json
@@ -223,6 +236,7 @@ trans.sk = public/language/sk/user.json
trans.sv = public/language/sv/user.json
trans.th = public/language/th/user.json
trans.tr = public/language/tr/user.json
+trans.vi = public/language/vi/user.json
trans.zh_CN = public/language/zh_CN/user.json
trans.zh_TW = public/language/zh_TW/user.json
type = KEYVALUEJSON
@@ -243,6 +257,7 @@ trans.fr = public/language/fr/global.json
trans.he = public/language/he/global.json
trans.hu = public/language/hu/global.json
trans.it = public/language/it/global.json
+trans.ja = public/language/ja/global.json
trans.lt = public/language/lt/global.json
trans.ms = public/language/ms/global.json
trans.nb = public/language/nb/global.json
@@ -255,6 +270,7 @@ trans.sk = public/language/sk/global.json
trans.sv = public/language/sv/global.json
trans.th = public/language/th/global.json
trans.tr = public/language/tr/global.json
+trans.vi = public/language/vi/global.json
trans.zh_CN = public/language/zh_CN/global.json
trans.zh_TW = public/language/zh_TW/global.json
type = KEYVALUEJSON
@@ -275,6 +291,7 @@ trans.fr = public/language/fr/notifications.json
trans.he = public/language/he/notifications.json
trans.hu = public/language/hu/notifications.json
trans.it = public/language/it/notifications.json
+trans.ja = public/language/ja/notifications.json
trans.lt = public/language/lt/notifications.json
trans.ms = public/language/ms/notifications.json
trans.nb = public/language/nb/notifications.json
@@ -287,6 +304,7 @@ trans.sk = public/language/sk/notifications.json
trans.sv = public/language/sv/notifications.json
trans.th = public/language/th/notifications.json
trans.tr = public/language/tr/notifications.json
+trans.vi = public/language/vi/notifications.json
trans.zh_CN = public/language/zh_CN/notifications.json
trans.zh_TW = public/language/zh_TW/notifications.json
type = KEYVALUEJSON
@@ -307,6 +325,7 @@ trans.fr = public/language/fr/reset_password.json
trans.he = public/language/he/reset_password.json
trans.hu = public/language/hu/reset_password.json
trans.it = public/language/it/reset_password.json
+trans.ja = public/language/ja/reset_password.json
trans.lt = public/language/lt/reset_password.json
trans.ms = public/language/ms/reset_password.json
trans.nb = public/language/nb/reset_password.json
@@ -319,6 +338,7 @@ trans.sk = public/language/sk/reset_password.json
trans.sv = public/language/sv/reset_password.json
trans.th = public/language/th/reset_password.json
trans.tr = public/language/tr/reset_password.json
+trans.vi = public/language/vi/reset_password.json
trans.zh_CN = public/language/zh_CN/reset_password.json
trans.zh_TW = public/language/zh_TW/reset_password.json
type = KEYVALUEJSON
@@ -339,6 +359,7 @@ trans.fr = public/language/fr/users.json
trans.he = public/language/he/users.json
trans.hu = public/language/hu/users.json
trans.it = public/language/it/users.json
+trans.ja = public/language/ja/users.json
trans.lt = public/language/lt/users.json
trans.ms = public/language/ms/users.json
trans.nb = public/language/nb/users.json
@@ -351,6 +372,7 @@ trans.sk = public/language/sk/users.json
trans.sv = public/language/sv/users.json
trans.th = public/language/th/users.json
trans.tr = public/language/tr/users.json
+trans.vi = public/language/vi/users.json
trans.zh_CN = public/language/zh_CN/users.json
trans.zh_TW = public/language/zh_TW/users.json
type = KEYVALUEJSON
@@ -371,6 +393,7 @@ trans.fr = public/language/fr/language.json
trans.he = public/language/he/language.json
trans.hu = public/language/hu/language.json
trans.it = public/language/it/language.json
+trans.ja = public/language/ja/language.json
trans.lt = public/language/lt/language.json
trans.ms = public/language/ms/language.json
trans.nb = public/language/nb/language.json
@@ -383,6 +406,7 @@ trans.sk = public/language/sk/language.json
trans.sv = public/language/sv/language.json
trans.th = public/language/th/language.json
trans.tr = public/language/tr/language.json
+trans.vi = public/language/vi/language.json
trans.zh_CN = public/language/zh_CN/language.json
trans.zh_TW = public/language/zh_TW/language.json
type = KEYVALUEJSON
@@ -403,6 +427,7 @@ trans.fr = public/language/fr/pages.json
trans.he = public/language/he/pages.json
trans.hu = public/language/hu/pages.json
trans.it = public/language/it/pages.json
+trans.ja = public/language/ja/pages.json
trans.lt = public/language/lt/pages.json
trans.ms = public/language/ms/pages.json
trans.nb = public/language/nb/pages.json
@@ -415,6 +440,7 @@ trans.sk = public/language/sk/pages.json
trans.sv = public/language/sv/pages.json
trans.th = public/language/th/pages.json
trans.tr = public/language/tr/pages.json
+trans.vi = public/language/vi/pages.json
trans.zh_CN = public/language/zh_CN/pages.json
trans.zh_TW = public/language/zh_TW/pages.json
type = KEYVALUEJSON
@@ -435,6 +461,7 @@ trans.fr = public/language/fr/topic.json
trans.he = public/language/he/topic.json
trans.hu = public/language/hu/topic.json
trans.it = public/language/it/topic.json
+trans.ja = public/language/ja/topic.json
trans.lt = public/language/lt/topic.json
trans.ms = public/language/ms/topic.json
trans.nb = public/language/nb/topic.json
@@ -447,6 +474,7 @@ trans.sk = public/language/sk/topic.json
trans.sv = public/language/sv/topic.json
trans.th = public/language/th/topic.json
trans.tr = public/language/tr/topic.json
+trans.vi = public/language/vi/topic.json
trans.zh_CN = public/language/zh_CN/topic.json
trans.zh_TW = public/language/zh_TW/topic.json
type = KEYVALUEJSON
@@ -467,6 +495,7 @@ trans.fr = public/language/fr/success.json
trans.he = public/language/he/success.json
trans.hu = public/language/hu/success.json
trans.it = public/language/it/success.json
+trans.ja = public/language/ja/success.json
trans.lt = public/language/lt/success.json
trans.ms = public/language/ms/success.json
trans.nb = public/language/nb/success.json
@@ -479,6 +508,7 @@ trans.sk = public/language/sk/success.json
trans.sv = public/language/sv/success.json
trans.th = public/language/th/success.json
trans.tr = public/language/tr/success.json
+trans.vi = public/language/vi/success.json
trans.zh_CN = public/language/zh_CN/success.json
trans.zh_TW = public/language/zh_TW/success.json
type = KEYVALUEJSON
@@ -499,6 +529,7 @@ trans.fr = public/language/fr/error.json
trans.he = public/language/he/error.json
trans.hu = public/language/hu/error.json
trans.it = public/language/it/error.json
+trans.ja = public/language/ja/error.json
trans.lt = public/language/lt/error.json
trans.ms = public/language/ms/error.json
trans.nb = public/language/nb/error.json
@@ -511,6 +542,7 @@ trans.sk = public/language/sk/error.json
trans.sv = public/language/sv/error.json
trans.th = public/language/th/error.json
trans.tr = public/language/tr/error.json
+trans.vi = public/language/vi/error.json
trans.zh_CN = public/language/zh_CN/error.json
trans.zh_TW = public/language/zh_TW/error.json
type = KEYVALUEJSON
\ No newline at end of file
diff --git a/public/language/en_GB/global.json b/public/language/en_GB/global.json
index e306ed49ba..6ed0e914b1 100644
--- a/public/language/en_GB/global.json
+++ b/public/language/en_GB/global.json
@@ -66,7 +66,7 @@
"posted_in_ago_by_guest": "posted in %1 %2 by Guest",
"posted_in_ago_by": "posted in %1 %2 by %3",
- "posted_in_ago": "posted in %1",
+ "posted_in_ago": "posted in %1 %2",
"replied_ago": "replied %1",
"user_posted_ago": "%1 posted %2",
diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json
index 7669a23fe0..2af258a89d 100644
--- a/public/language/en_GB/topic.json
+++ b/public/language/en_GB/topic.json
@@ -10,6 +10,7 @@
"profile": "Profile",
"posted_by": "Posted by %1",
+ "posted_by_guest": "Posted by Guest",
"chat": "Chat",
"notify_me": "Be notified of new replies in this topic",
"quote": "Quote",
diff --git a/public/language/ja/category.json b/public/language/ja/category.json
new file mode 100644
index 0000000000..0a4892d07f
--- /dev/null
+++ b/public/language/ja/category.json
@@ -0,0 +1,7 @@
+{
+ "new_topic_button": "新規スレッド",
+ "no_topics": "まだスレッドはありません.
一番目のスレッドを書いてみないか?",
+ "browsing": "閲覧中",
+ "no_replies": "返事はまだありません",
+ "share_this_category": "この板を共有"
+}
diff --git a/public/language/ja/error.json b/public/language/ja/error.json
new file mode 100644
index 0000000000..facf88fcf5
--- /dev/null
+++ b/public/language/ja/error.json
@@ -0,0 +1,49 @@
+{
+ "invalid-data": "無効なデータ",
+ "not-logged-in": "ログインしていていないようです。",
+ "invalid-cid": "無効な板ID",
+ "invalid-tid": "無効なスレッドID",
+ "invalid-pid": "無効なポストID",
+ "invalid-uid": "無効なユーザーID",
+ "invalid-username": "無効なユーザー名",
+ "invalid-email": "無効なメール",
+ "invalid-title": "無効なタイトル",
+ "invalid-user-data": "無効なユーザーデータ",
+ "invalid-password": "無効なパスワード",
+ "invalid-pagination-value": "無効な改ページ設定値",
+ "username-taken": "ユーザー名が取られた",
+ "email-taken": "メールアドレスが使用された",
+ "user-banned": "ユーザーが停止された",
+ "no-category": "板が存在しない",
+ "no-topic": "スレッドが存在しない",
+ "no-post": "ポストが存在しない",
+ "no-group": "グループが存在しない",
+ "no-user": "ユーザーが存在しない",
+ "no-teaser": "ティーザーが存在しない",
+ "no-privileges": "このアクションを実行する権限を持っていない。",
+ "category-disabled": "この板は無効された",
+ "topic-locked": "スレッドがロックされた",
+ "still-uploading": "アップロードが完成するまでお待ちください。",
+ "content-too-short": "ポストに最小 %1 文字の制限があります。",
+ "title-too-short": "タイトルに最小 %1 文字の制限があります。",
+ "title-too-long": "タイトルに最大 %1 文字の制限があります。",
+ "too-many-posts": "%1 秒間で最大 1 ポストの投稿が可能です。",
+ "file-too-big": "最大ファイルサイズは %1 kbs",
+ "cant-vote-self-post": "自分のポストに評価することはできません。",
+ "already-favourited": "このポストはすでにお気に入りに追加されました。",
+ "already-unfavourited": "このポストはすでにお気に入りから削除されました。",
+ "cant-ban-other-admins": "ほかの管理者を停止することはできません!",
+ "invalid-image-type": "無効なユーザータイプ",
+ "group-name-too-short": "グループ名は短すぎます。",
+ "group-already-exists": "グループ名はすでに存在しています",
+ "group-name-change-not-allowed": "グループ名の修正はできません",
+ "post-already-deleted": "ポストはすでに削除された",
+ "post-already-restored": "ポストはすでにリストアされた",
+ "topic-already-deleted": "スレッドはすでに削除された",
+ "topic-already-restored": "スレッドはすでにリストアされた",
+ "topic-thumbnails-are-disabled": "スレッドのサムネイルが無効された",
+ "invalid-file": "無効なファイル",
+ "uploads-are-disabled": "アップロードが無効された",
+ "signature-too-long": "署名は最大%1文字までです!",
+ "cant-chat-with-yourself": "自分にチャットすることはできません!"
+}
diff --git a/public/language/ja/footer.json b/public/language/ja/footer.json
new file mode 100644
index 0000000000..41437643ee
--- /dev/null
+++ b/public/language/ja/footer.json
@@ -0,0 +1,7 @@
+{
+ "stats.online": "利用者",
+ "stats.users": "登録",
+ "stats.topics": "スレッド",
+ "stats.posts": "ポスト",
+ "success": "成功"
+}
diff --git a/public/language/ja/global.json b/public/language/ja/global.json
new file mode 100644
index 0000000000..35269d5d82
--- /dev/null
+++ b/public/language/ja/global.json
@@ -0,0 +1,70 @@
+{
+ "home": "ホーム",
+ "search": "検索",
+ "buttons.close": "閉じる",
+ "403.title": "アクセス拒否",
+ "403.message": "アクセスが拒否されました.ログインしますか?",
+ "404.title": "見つかりません",
+ "404.message": "アクセスしようとしていたページは存在しません.ホームへ",
+ "500.title": "内部エラー",
+ "500.message": "何とも言えない障害が発生しているようです.m(_ _)m",
+ "register": "登録",
+ "login": "ログイン",
+ "please_log_in": "ログインください",
+ "logout": "ログアウト",
+ "posting_restriction_info": "登録ユーザーのみが投稿可能となります.こちらからログインください。",
+ "welcome_back": "お帰りなさい",
+ "you_have_successfully_logged_in": "ログインできました",
+ "save_changes": "保存する",
+ "close": "閉じる",
+ "pagination": "ページ",
+ "header.admin": "管理",
+ "header.recent": "最近",
+ "header.unread": "未読",
+ "header.popular": "人気",
+ "header.users": "ユーザー",
+ "header.chats": "チャット",
+ "header.notifications": "通知",
+ "header.search": "検索",
+ "header.profile": "プロフィール",
+ "notifications.loading": "通知をロード中",
+ "chats.loading": "チャットをロード中",
+ "motd.welcome": "次世代の掲示板システム NodeBB へようこそ!",
+ "previouspage": "前のページ",
+ "nextpage": "次のページ",
+ "alert.success": "成功",
+ "alert.error": "エラー",
+ "alert.banned": "停止した",
+ "alert.banned.message": "このアカウントが停止されました!",
+ "alert.unfollow": "%1へのフォローを停止しました!",
+ "alert.follow": "%1をフォローしています!",
+ "online": "オンライン",
+ "users": "ユーザー",
+ "topics": "スレッド",
+ "posts": "ポスト",
+ "views": "閲覧数",
+ "reputation": "評価",
+ "read_more": "続きを読む",
+ "posted_ago_by_guest": "%1にゲストが投稿",
+ "posted_ago_by": "%1に %2 が投稿",
+ "posted_ago": "%1に投稿された",
+ "posted_in_ago_by_guest": "%1に %2 ゲストが投稿",
+ "posted_in_ago_by": "%1 %2に %3 が投稿",
+ "posted_in_ago": "%1 に投稿",
+ "replied_ago": "%1 に返答",
+ "user_posted_ago": "%1 が%2に投稿",
+ "guest_posted_ago": "ゲストが%1に投稿",
+ "last_edited_by_ago": "%1が%2に最終編集",
+ "norecentposts": "最近のポストはありません",
+ "norecenttopics": "最近のスレッドはありません",
+ "recentposts": "最近のポスト",
+ "recentips": "最近ログインしたIPアドレス",
+ "away": "不在",
+ "dnd": "仕事中",
+ "invisible": "不可視",
+ "offline": "オフライン",
+ "email": "メール",
+ "language": "言語",
+ "guest": "ゲスト",
+ "guests": "ゲスト"
+}
diff --git a/public/language/ja/language.json b/public/language/ja/language.json
new file mode 100644
index 0000000000..19a14e500a
--- /dev/null
+++ b/public/language/ja/language.json
@@ -0,0 +1,5 @@
+{
+ "name": "日本語",
+ "code": "ja",
+ "dir": "ltr"
+}
diff --git a/public/language/ja/login.json b/public/language/ja/login.json
new file mode 100644
index 0000000000..a16f10ddf2
--- /dev/null
+++ b/public/language/ja/login.json
@@ -0,0 +1,8 @@
+{
+ "username": "ユーザー名 / メール",
+ "remember_me": "ログイン情報を記憶",
+ "forgot_password": "パスワードがわからない?",
+ "alternative_logins": "ほかのログイン方法",
+ "failed_login_attempt": "ログインに失敗しました.ユーザー名やパスワードをご確認ください。",
+ "login_successful": "ログインしました!"
+}
diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json
new file mode 100644
index 0000000000..7a01eeca56
--- /dev/null
+++ b/public/language/ja/modules.json
@@ -0,0 +1,7 @@
+{
+ "chat.chatting_with": "とチャット",
+ "chat.placeholder": "メッセージを入力する",
+ "chat.send": "送信",
+ "chat.no_active": "チャットはありません。",
+ "chat.user_typing": "%1 は入力中 ..."
+}
diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json
new file mode 100644
index 0000000000..de907f0fcc
--- /dev/null
+++ b/public/language/ja/notifications.json
@@ -0,0 +1,18 @@
+{
+ "title": "通知センター",
+ "no_notifs": "新しい通知はありません",
+ "see_all": "すべての通知を確認",
+ "back_to_home": "NodeBBへ戻る",
+ "outgoing_link": "外部サイトへのリンク",
+ "outgoing_link_message": "リービング",
+ "continue_to": "続き",
+ "return_to": "戻る ",
+ "new_notification": "新しい通知",
+ "you_have_unread_notifications": "未読の通知があります。",
+ "user_made_post": "%1は新しいポストを投稿しました。",
+ "new_message_from": "%1からの新しいメッセージ",
+ "upvoted_your_post": "%1はあなたのポストを評価しました。",
+ "favourited_your_post": "%1はあなたのポストをお気に入りにしました。",
+ "user_flagged_post": "%1 ポストを報告しました。",
+ "user_posted_to": "%1 は %2 への返事を作成しました。"
+}
diff --git a/public/language/ja/pages.json b/public/language/ja/pages.json
new file mode 100644
index 0000000000..8387697fe1
--- /dev/null
+++ b/public/language/ja/pages.json
@@ -0,0 +1,15 @@
+{
+ "home": "ホーム",
+ "unread": "未読スレッド",
+ "popular": "人気スレッド",
+ "recent": "最新スレッド",
+ "users": "登録したユーザー",
+ "notifications": "通知",
+ "user.edit": "編集中 \"%1\"",
+ "user.following": "%1がフォロー中",
+ "user.followers": "%1のフォロワー",
+ "user.posts": "%1が作成したポスト",
+ "user.topics": "%1が作成したスレッド",
+ "user.favourites": "%1のお気に入りポスト",
+ "user.settings": "ユーザー設定"
+}
diff --git a/public/language/ja/recent.json b/public/language/ja/recent.json
new file mode 100644
index 0000000000..88125f8432
--- /dev/null
+++ b/public/language/ja/recent.json
@@ -0,0 +1,7 @@
+{
+ "title": "最近の更新",
+ "day": "最近 1 日",
+ "week": "最近 1 週",
+ "month": "最近 1 ヶ月",
+ "no_recent_topics": "最近のスレッドはありません。"
+}
diff --git a/public/language/ja/register.json b/public/language/ja/register.json
new file mode 100644
index 0000000000..b1ce4c0794
--- /dev/null
+++ b/public/language/ja/register.json
@@ -0,0 +1,18 @@
+{
+ "register": "登録",
+ "help.email": "デフォルト設定ではメールアドレスは公開されません。",
+ "help.username_restrictions": "%1 から %2 文字までのユニークなユーザー名.Twitter の @username 方式でメンションすることができます。",
+ "help.minimum_password_length": "パスワードには最小 %1 文字が必要です。",
+ "email_address": "メールアドレス",
+ "email_address_placeholder": "メールアドレスを入力ください",
+ "username": "ユーザー名",
+ "username_placeholder": "ユーザー名を入力してください",
+ "password": "パスワード",
+ "password_placeholder": "パスワードを入力してください",
+ "confirm_password": "パスワード再入力",
+ "confirm_password_placeholder": "パスワード再入力してください",
+ "register_now_button": "今すぐ登録する",
+ "alternative_registration": "ほかの登録方法",
+ "terms_of_use": "利用規約",
+ "agree_to_terms_of_use": "利用規約に同意する"
+}
diff --git a/public/language/ja/reset_password.json b/public/language/ja/reset_password.json
new file mode 100644
index 0000000000..4c2d9e6858
--- /dev/null
+++ b/public/language/ja/reset_password.json
@@ -0,0 +1,14 @@
+{
+ "reset_password": "パスワードをリセット",
+ "update_password": "パスワードを更新",
+ "password_changed.title": "パスワードを更新しました",
+ "password_changed.message": "
パスワードをリセットできました.こちらでログインしてください。",
+ "wrong_reset_code.title": "リセットコードは正しくありません",
+ "wrong_reset_code.message": "リセットコードは正しくありません.もう一度入力するか、新しいリセットコードを請求することができます。",
+ "new_password": "新しいパスワード",
+ "repeat_password": "パスワード再入力",
+ "enter_email": "メールアドレスを入力してください.パスワードリセットの指示をメールでご送付します。",
+ "enter_email_address": "メールアドレスを入力してください",
+ "password_reset_sent": "パスワードリセットのメールを送信しました",
+ "invalid_email": "このメールアドレスは存在しません"
+}
diff --git a/public/language/ja/success.json b/public/language/ja/success.json
new file mode 100644
index 0000000000..b8ea2c4056
--- /dev/null
+++ b/public/language/ja/success.json
@@ -0,0 +1,6 @@
+{
+ "success": "成功",
+ "topic-post": "成功に投稿しました。",
+ "authentication-successful": "認証が成功しました",
+ "settings-saved": "設定を保存しました。"
+}
diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json
new file mode 100644
index 0000000000..d446179ca8
--- /dev/null
+++ b/public/language/ja/topic.json
@@ -0,0 +1,93 @@
+{
+ "topic": "スレッド",
+ "topic_id": "スレッド ID",
+ "topic_id_placeholder": "スレッド ID を入力してください",
+ "no_topics_found": "スレッドが見つかりません!",
+ "no_posts_found": "ポストはありません!",
+ "post_is_deleted": "このポストが削除されます!",
+ "profile": "プロフィール",
+ "posted_by": "%1 のポスト",
+ "chat": "チャット",
+ "notify_me": "このスレッドに新しいポストが投稿された際に通知する",
+ "quote": "引用",
+ "reply": "返答",
+ "edit": "編集",
+ "delete": "削除",
+ "restore": "リストア",
+ "move": "移動",
+ "fork": "フォーク",
+ "banned": "停止した",
+ "link": "リンク",
+ "share": "シェア",
+ "tools": "ツール",
+ "flag": "フラグ",
+ "bookmark_instructions": "こちらをクリックして前の場所に戻ります。",
+ "flag_title": "リポートする",
+ "flag_confirm": "本当にこのポストをリポートするか?",
+ "flag_success": "このポストをリポートしました。",
+ "deleted_message": "このスレッドは削除されました。管理者しか見れません。",
+ "following_topic.message": "このスレッドが更新された際に通知を受け取ります。",
+ "not_following_topic.message": "このスレッドの更新通知を停止しました。",
+ "login_to_subscribe": "このスレッドを購読するためにログインが必要です。",
+ "markAsUnreadForAll.success": "すべてのスレッドを未読にしました。",
+ "watch": "ウオッチ",
+ "watch.title": "新しいポストの通知を受ける",
+ "share_this_post": "ポストを共有",
+ "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": "すべてを移動",
+ "thread_tools.fork": "スレッドをフォーク",
+ "thread_tools.delete": "スレッドを削除",
+ "thread_tools.delete_confirm": "本当にスレッドを削除しますか?",
+ "thread_tools.restore": "スレッドをリストア",
+ "thread_tools.restore_confirm": "本当にスレッドをリストアしますか?",
+ "topic_lock_success": "スレッドはロックされました。",
+ "topic_unlock_success": "スレッドはアンロックされました。",
+ "topic_pin_success": "スレッドは上部に固定されました。",
+ "topic_unpin_success": "スレッドの固定を取り消しました。",
+ "topic_move_success": "このスレッドを %1 に移動しました。",
+ "post_delete_confirm": "本当にポストを削除しますか?",
+ "post_restore_confirm": "本当にポストをリストアしますか?",
+ "post_delete_error": "ポストを削除できませんでした!",
+ "post_restore_error": "ポストをリストアできませんでした!",
+ "load_categories": "板をローディング中...",
+ "disabled_categories_note": "使用不可の板はグレーに表示されます。",
+ "confirm_move": "移動",
+ "confirm_fork": "フォーク",
+ "favourite": "お気に入り",
+ "favourites": "お気に入り",
+ "favourites.has_no_favourites": "お気に入りはまだありません!",
+ "loading_more_posts": "もっと見る",
+ "move_topic": "スレッドを移動",
+ "move_post": "ポストを移動",
+ "post_moved": "ポストを移動しました!",
+ "fork_topic": "スレッドをフォーク",
+ "topic_will_be_moved_to": "スレッドはこちらのカテゴリへ移動",
+ "fork_topic_instruction": "フォークしたいポストをクリックして",
+ "fork_no_pids": "ポストが選択されていません!",
+ "fork_success": "スレッドをフォークできました!",
+ "composer.title_placeholder": "スレッドのタイトルを入力して...",
+ "composer.write": "作成する",
+ "composer.preview": "プレビュー",
+ "composer.help": "ヘルプ",
+ "composer.discard": "破棄する",
+ "composer.submit": "保存する",
+ "composer.replying_to": "%1へ返答中",
+ "composer.new_topic": "新規スレッド",
+ "composer.uploading": "アップロード中...",
+ "composer.thumb_url_label": "スレッドのサムネイルのURLを入力して",
+ "composer.thumb_title": "スレッドにサムネイルを追加",
+ "composer.thumb_url_placeholder": "http://example.com/thumb.png",
+ "composer.thumb_file_label": "またはファイルをアップロード",
+ "composer.thumb_remove": "入力をクリア",
+ "composer.drag_and_drop_images": "こちらへ画像をドラッグ&ドロップ",
+ "composer.upload_instructions": "ドラッグ&ドロップで画像をアップロードすることができます。",
+ "more_users_and_guests": "%1 more user(s) and %2 guest(s)",
+ "more_users": "%1 more user(s)",
+ "more_guests": "%1 more guest(s)"
+}
diff --git a/public/language/ja/unread.json b/public/language/ja/unread.json
new file mode 100644
index 0000000000..a6027a54b3
--- /dev/null
+++ b/public/language/ja/unread.json
@@ -0,0 +1,9 @@
+{
+ "title": "未読",
+ "no_unread_topics": "未読のスレッドがあります。",
+ "load_more": "もっと見る",
+ "mark_as_read": "既読にする",
+ "selected": "選択済み",
+ "all": "すべて",
+ "topics_marked_as_read.success": "すべてのスレッドを既読にしました。"
+}
diff --git a/public/language/ja/user.json b/public/language/ja/user.json
new file mode 100644
index 0000000000..25ce70a83e
--- /dev/null
+++ b/public/language/ja/user.json
@@ -0,0 +1,62 @@
+{
+ "banned": "停止された",
+ "offline": "オフライン",
+ "username": "ユーザー名",
+ "email": "メール",
+ "fullname": "フルネーム",
+ "website": "ウェブサイト",
+ "location": "ロケーション",
+ "age": "年齢",
+ "joined": "参加",
+ "lastonline": "最後オンライン",
+ "profile": "プロフィール",
+ "profile_views": "閲覧数",
+ "reputation": "評価",
+ "favourites": "お気に入り",
+ "followers": "フォロワー",
+ "following": "フォロー中",
+ "signature": "署名",
+ "gravatar": "Gravatar",
+ "birthday": "誕生日",
+ "chat": "チャット",
+ "follow": "フォロー",
+ "unfollow": "フォローしない",
+ "profile_update_success": "プロフィールを更新しました!",
+ "change_picture": "画像を変更",
+ "edit": "編集",
+ "uploaded_picture": "アップロード済みの画像",
+ "upload_new_picture": "新しい画像をアップロード",
+ "current_password": "現在のパスワード",
+ "change_password": "パスワードを変更",
+ "change_password_error": "無効のパスワード!",
+ "change_password_error_wrong_current": "現在のパスワードは正しくありません!",
+ "change_password_error_length": "パスワードは短い過ぎです!",
+ "change_password_error_match": "パスワードは一致しません!",
+ "change_password_error_privileges": "パスワードを更新する権限はありません。",
+ "change_password_success": "パスワードを更新しました!",
+ "confirm_password": "パスワードを再入力",
+ "password": "パスワード",
+ "username_taken_workaround": "このユーザー名はすでに使用されています。いまのユーザー名は %1 です。",
+ "upload_picture": "画像をアップロード",
+ "upload_a_picture": "画像をアップロード",
+ "image_spec": "PNG、JPGかGIFフォーマットの画像をアップロードしてください。",
+ "max": "max。",
+ "settings": "設定",
+ "show_email": "メールアドレスを表示",
+ "digest_label": "ダイジェストを購読",
+ "digest_description": "この掲示板のアップデートを受信する",
+ "digest_off": "オフ",
+ "digest_daily": "デイリー",
+ "digest_weekly": "ウィークリー",
+ "digest_monthly": "マンスリー",
+ "has_no_follower": "フォロワーはまだいません :(",
+ "follows_no_one": "フォロー中のユーザーはまだいません :(",
+ "has_no_posts": "まだポストを投稿したことありません。",
+ "has_no_topics": "まだスレッドを作成したありません。",
+ "email_hidden": "メールアドレスを非表示",
+ "hidden": "非表示",
+ "paginate_description": "スクロールでのページ自動ロードはしない",
+ "topics_per_page": "ページ毎のスレッド数",
+ "posts_per_page": "ページ毎のポスト数",
+ "notification_sounds": "通知が来たとき音を流す"
+}
diff --git a/public/language/ja/users.json b/public/language/ja/users.json
new file mode 100644
index 0000000000..fa9b441a9a
--- /dev/null
+++ b/public/language/ja/users.json
@@ -0,0 +1,8 @@
+{
+ "latest_users": "最新ユーザー",
+ "top_posters": "最も投稿したユーザー",
+ "most_reputation": "最も評価されたユーザー",
+ "search": "検索",
+ "enter_username": "検索するユーザー名を入力してください",
+ "load_more": "もっと表示"
+}
diff --git a/public/language/vi/category.json b/public/language/vi/category.json
new file mode 100644
index 0000000000..972df0d4f3
--- /dev/null
+++ b/public/language/vi/category.json
@@ -0,0 +1,7 @@
+{
+ "new_topic_button": "Chủ đề mới",
+ "no_topics": "Không có bài viết trong danh mục.
Hãy đăng một bài viết mới?",
+ "browsing": "đang duyệt",
+ "no_replies": "Chưa có ai bình luận",
+ "share_this_category": "Chia sẻ phần mục này"
+}
\ No newline at end of file
diff --git a/public/language/vi/error.json b/public/language/vi/error.json
new file mode 100644
index 0000000000..3612b00e3d
--- /dev/null
+++ b/public/language/vi/error.json
@@ -0,0 +1,49 @@
+{
+ "invalid-data": "Dữ liệu không hợp lệ",
+ "not-logged-in": "Bạn không được đăng nhập.",
+ "invalid-cid": "Danh mục ID không hợp lệ",
+ "invalid-tid": "ID chủ đề không hợp lệ",
+ "invalid-pid": "ID bài viết không hợp lệ",
+ "invalid-uid": "ID tài khoản không hợp lệ",
+ "invalid-username": "Tên đăng nhập không hợp lệ",
+ "invalid-email": "Email không hợp lệ",
+ "invalid-title": "Tiêu đề không hợp lệ",
+ "invalid-user-data": "Dữ liệu tài khoản không hợp lệ",
+ "invalid-password": "Mật khẩu không hợp lệ",
+ "invalid-pagination-value": "Số trang không hợp lệ",
+ "username-taken": "Tên đăng nhập đã tồn tại",
+ "email-taken": "Email đã tồn tại",
+ "user-banned": "Tài khoản bị ban",
+ "no-category": "Phần mục không tồn tại",
+ "no-topic": "Chủ đề không tồn tại",
+ "no-post": "Bài viết không tồn tại",
+ "no-group": "Nhóm không tồn tại",
+ "no-user": "Tài khoản không tồn tại",
+ "no-teaser": "Teaser không tồn tại",
+ "no-privileges": "Bạn không đủ quyền cho hành động này",
+ "category-disabled": "Danh mục bị disabled",
+ "topic-locked": "Chủ đề bị khóa",
+ "still-uploading": "Vui lòng chờ upload",
+ "content-too-short": "Vui lòng nhập dài hơn. Ít nhất %1 ký tự",
+ "title-too-short": "Yêu cầu nhập tiêu đề dài hơn. Í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 bài viết %1 giây nữa",
+ "file-too-big": "Kích thước file tối đa %1kb",
+ "cant-vote-self-post": "Bạn không thể vote cho chính bài viết của bạn",
+ "already-favourited": "Bạn đã bấm yêu thích cho bài viết này",
+ "already-unfavourited": "Bạn đã từ bỏ yêu thích cho bài viết này",
+ "cant-ban-other-admins": "Bạn không thể ban được các admin khác",
+ "invalid-image-type": "Kiểu hình ảnh không hợp lệ",
+ "group-name-too-short": "Tên nhóm quá ngắn",
+ "group-already-exists": "Nhóm đã tồn tại",
+ "group-name-change-not-allowed": "Không cho phép đổi tên nhóm",
+ "post-already-deleted": "Bài viết đã được xóa rồi",
+ "post-already-restored": "Bài viết đã được phục hồi rồi",
+ "topic-already-deleted": "Chủ đề đã bị xóa rồi",
+ "topic-already-restored": "Chủ đề đã được phục hồi rồi",
+ "topic-thumbnails-are-disabled": "Thumbnails cho chủ đề đã bị tắt",
+ "invalid-file": "File không hợp lệ",
+ "uploads-are-disabled": "Đã khóa lựa chọn tải lên",
+ "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!"
+}
\ No newline at end of file
diff --git a/public/language/vi/global.json b/public/language/vi/global.json
new file mode 100644
index 0000000000..433101d4cd
--- /dev/null
+++ b/public/language/vi/global.json
@@ -0,0 +1,70 @@
+{
+ "home": "Trang chủ",
+ "search": "Tìm kiếm",
+ "buttons.close": "Đóng lại",
+ "403.title": "Từ chối truy cập",
+ "403.message": "Có vẻ như bạn đang cố vào một trang mà bạn không có quyền truy cập. Bạn nên thử đăng nhập để truy cập ",
+ "404.title": "Không tìm thấy",
+ "404.message": "Có vẻ bạn đang cố vào một trang không tồn tại. Hãy trở lại trang chủ",
+ "500.title": "Lỗi nội bộ",
+ "500.message": "Úi chà! Có vẻ như có trục trặc rồi!",
+ "register": "Đăng ký",
+ "login": "Đăng nhập",
+ "please_log_in": "Xin hãy đăng nhập",
+ "logout": "Đăng xuất",
+ "posting_restriction_info": "Hiện giờ chỉ có các thành viên mới được quyền gửi bài viết, hãy nhấn vào đây để đăng nhập",
+ "welcome_back": "Chào mừng bạn quay lại",
+ "you_have_successfully_logged_in": "Bạn đã đăng nhập thành công",
+ "save_changes": "Lưu thay đổi",
+ "close": "Đóng lại",
+ "pagination": "Số trang",
+ "header.admin": "Quản trị viên",
+ "header.recent": "Gần đây",
+ "header.unread": "Chưa đọc",
+ "header.popular": "Nổi bật",
+ "header.users": "Số người dùng",
+ "header.chats": "Phần Chat",
+ "header.notifications": "Thông báo",
+ "header.search": "Tìm kiếm",
+ "header.profile": "Hồ sơ",
+ "notifications.loading": "Đang tải Thông báo",
+ "chats.loading": "Đang tải phần Chat",
+ "motd.welcome": "Chào mừng bạn tới NodeBB, Platform của tương lai",
+ "previouspage": "Trang trước",
+ "nextpage": "Trang kế tiếp",
+ "alert.success": "Thành công",
+ "alert.error": "Lỗi",
+ "alert.banned": "Bị ban",
+ "alert.banned.message": "Bạn đã bị ban, giờ bạn sẽ đăng xuất",
+ "alert.unfollow": "Bạn đã không còn theo dõi %1!",
+ "alert.follow": "Bạn giờ đang theo dõi %1!",
+ "online": "Đang online",
+ "users": "Số người dùng",
+ "topics": "Số Chủ đề",
+ "posts": "Số bài viết",
+ "views": "Số lượt view",
+ "reputation": "Độ uy tín",
+ "read_more": "Đọc thêm",
+ "posted_ago_by_guest": "Đã viết %1 bởi Khách",
+ "posted_ago_by": "Đã viết %1 bởi %2",
+ "posted_ago": "Đã viết %1",
+ "posted_in_ago_by_guest": "Đã viết trong %1 %2 bởi Khách",
+ "posted_in_ago_by": "Đã viết trong %1 %2 bởi %3",
+ "posted_in_ago": "Đã viết trong %1",
+ "replied_ago": "Đã trả lời %1",
+ "user_posted_ago": "%1 đã viết %2",
+ "guest_posted_ago": "Khách đã viết %1",
+ "last_edited_by_ago": "Được chỉnh sửa lần cuối bởi %1 %2",
+ "norecentposts": "Không có bài viết nào gần đây",
+ "norecenttopics": "Không có chủ đề gần đây",
+ "recentposts": "Số bài viết gần đây",
+ "recentips": "Các IP vừa mới đăng nhập",
+ "away": "Đang away",
+ "dnd": "Không được quấy rầy",
+ "invisible": "Ẩn",
+ "offline": "Đang offline",
+ "email": "Email",
+ "language": "Ngôn ngữ",
+ "guest": "Khách",
+ "guests": "Số khách"
+}
\ No newline at end of file
diff --git a/public/language/vi/language.json b/public/language/vi/language.json
new file mode 100644
index 0000000000..f0787f748a
--- /dev/null
+++ b/public/language/vi/language.json
@@ -0,0 +1,5 @@
+{
+ "name": "Tiếng Việt",
+ "code": "vi",
+ "dir": "ltr"
+}
\ No newline at end of file
diff --git a/public/language/vi/login.json b/public/language/vi/login.json
new file mode 100644
index 0000000000..713509be4e
--- /dev/null
+++ b/public/language/vi/login.json
@@ -0,0 +1,8 @@
+{
+ "username": "Tên người dùng / Email",
+ "remember_me": "Ghi nhớ tôi?",
+ "forgot_password": "Quên mật khẩu?",
+ "alternative_logins": "Đăng nhập bằng tên khác",
+ "failed_login_attempt": "Đăng nhập thất bại, xin hãy thử lại",
+ "login_successful": "Bạn đã đăng nhập thành công!"
+}
\ No newline at end of file
diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json
new file mode 100644
index 0000000000..0f80e4414d
--- /dev/null
+++ b/public/language/vi/modules.json
@@ -0,0 +1,7 @@
+{
+ "chat.chatting_with": "Chat với ",
+ "chat.placeholder": "đánh đoạn tin nhắn chat ở đây, nhấn phím enter để gửi đi",
+ "chat.send": "Gửi đi",
+ "chat.no_active": "Bạn hiện giờ không có cuộc chat nào",
+ "chat.user_typing": "%1b đang gõ"
+}
\ No newline at end of file
diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json
new file mode 100644
index 0000000000..5a83eafd01
--- /dev/null
+++ b/public/language/vi/notifications.json
@@ -0,0 +1,18 @@
+{
+ "title": "Thông báo",
+ "no_notifs": "Bạn không có thông báo nào mới",
+ "see_all": "Xem tất cả thông báo",
+ "back_to_home": "Quay lại NodeBB",
+ "outgoing_link": "Liên kết ngoài",
+ "outgoing_link_message": "Bạn giờ đang thoát",
+ "continue_to": "Tiếp tục đến",
+ "return_to": "Trở về",
+ "new_notification": "Thông báo mới",
+ "you_have_unread_notifications": "Bạn có thông báo chưa đọc",
+ "user_made_post": "%1 đã viết bài mới",
+ "new_message_from": "Tin nhắn mới từ %1",
+ "upvoted_your_post": "%1 đã hủy vote cho bài viết của bạn",
+ "favourited_your_post": "%1 thích bài viết của bạn",
+ "user_flagged_post": "%1 đã flag một bài viết",
+ "user_posted_to": "%1 đã trả lời %2"
+}
\ No newline at end of file
diff --git a/public/language/vi/pages.json b/public/language/vi/pages.json
new file mode 100644
index 0000000000..36cb72eb47
--- /dev/null
+++ b/public/language/vi/pages.json
@@ -0,0 +1,15 @@
+{
+ "home": "Trang chủ",
+ "unread": "Chủ đề chưa đọc",
+ "popular": "Các chủ đề nổi bật",
+ "recent": "Chủ đề gần đây",
+ "users": "Số người dùng đã đăng ký",
+ "notifications": "Thông báo",
+ "user.edit": "Chỉnh sửa \"%1\"",
+ "user.following": "Người mà %1 theo dõi",
+ "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.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"
+}
\ No newline at end of file
diff --git a/public/language/vi/recent.json b/public/language/vi/recent.json
new file mode 100644
index 0000000000..571084e721
--- /dev/null
+++ b/public/language/vi/recent.json
@@ -0,0 +1,7 @@
+{
+ "title": "Mới nhất",
+ "day": "Ngày",
+ "week": "Tuần",
+ "month": "Tháng",
+ "no_recent_topics": "Không có chủ đề nào gần đây"
+}
\ No newline at end of file
diff --git a/public/language/vi/register.json b/public/language/vi/register.json
new file mode 100644
index 0000000000..848cfdafa5
--- /dev/null
+++ b/public/language/vi/register.json
@@ -0,0 +1,18 @@
+{
+ "register": "Đăng ký",
+ "help.email": "Theo mặc định, Email của bạn sẽ ở dạng ẩn và public sẽ không thấy được",
+ "help.username_restrictions": "Một tên truy cập duy nhất có từ %1 đến %2 ký tự. Những người khác có thể nhắc đến bạn bằng @tên truy cập.",
+ "help.minimum_password_length": "Mật khẩu của bạn phải có ít nhất %1 ký tự",
+ "email_address": "Địa chỉ Email",
+ "email_address_placeholder": "Nhập địa chỉ Email",
+ "username": "Tên truy cập",
+ "username_placeholder": "Nhập tên truy cập",
+ "password": "Mật khẩu",
+ "password_placeholder": "Nhập mật khẩu",
+ "confirm_password": "Xác nhận mật khẩu",
+ "confirm_password_placeholder": "Xác nhận mật khẩu",
+ "register_now_button": "Đăng ký ngay",
+ "alternative_registration": "Đăng ký tài khoản khác",
+ "terms_of_use": "Điều khoản sử dụng",
+ "agree_to_terms_of_use": "Tôi đồng ý với các điều khoản sử dụng"
+}
\ No newline at end of file
diff --git a/public/language/vi/reset_password.json b/public/language/vi/reset_password.json
new file mode 100644
index 0000000000..edc196ba6c
--- /dev/null
+++ b/public/language/vi/reset_password.json
@@ -0,0 +1,14 @@
+{
+ "reset_password": "Thiết lập lại mật khẩu",
+ "update_password": "Cập nhật mật khẩu",
+ "password_changed.title": "Mật khẩu đã được thay đổi",
+ "password_changed.message": "
Mật khẩu đã được thiết lập lại thành công, xin hãy đăng nhập lại.",
+ "wrong_reset_code.title": "Mã thiết lập lại không đúng",
+ "wrong_reset_code.message": "Mã thiết lập lại không đúng. Xin hãy thử lại, hoặc yêu cầu một mã thiết lập lại khác.",
+ "new_password": "Mật khẩu mới",
+ "repeat_password": "Xác nhận lại mật khẩu",
+ "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!"
+}
\ No newline at end of file
diff --git a/public/language/vi/success.json b/public/language/vi/success.json
new file mode 100644
index 0000000000..f88527f3ad
--- /dev/null
+++ b/public/language/vi/success.json
@@ -0,0 +1,6 @@
+{
+ "success": "Thành công",
+ "topic-post": "Bạn đã gửi bài thành công",
+ "authentication-successful": "Xác thực thành công",
+ "settings-saved": "Đã lưu thiết lập"
+}
\ No newline at end of file
diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json
new file mode 100644
index 0000000000..3cae01a414
--- /dev/null
+++ b/public/language/vi/topic.json
@@ -0,0 +1,93 @@
+{
+ "topic": "Chủ đề",
+ "topic_id": "ID của chủ đề",
+ "topic_id_placeholder": "Nhập ID của chủ đề",
+ "no_topics_found": "Không tìm thấy chủ đề nào!",
+ "no_posts_found": "Không tìm thấy bài gửi nào",
+ "post_is_deleted": "Bài gửi này đã bị xóa!",
+ "profile": "Hồ sơ",
+ "posted_by": "Được viết bởi %1",
+ "chat": "Chat",
+ "notify_me": "Được thông báo khi có trả lời mới trong chủ đề này",
+ "quote": "Trích dẫn",
+ "reply": "Trả lời",
+ "edit": "Chỉnh sửa",
+ "delete": "Xóa",
+ "restore": "Phục hồi",
+ "move": "Chuyển đi",
+ "fork": "Fork",
+ "banned": "bị ban",
+ "link": "đường dẫn",
+ "share": "Chia sẻ",
+ "tools": "Công cụ",
+ "flag": "Flag",
+ "bookmark_instructions": "Bấm vào đây để quay về hoặc đóng lại để hủy",
+ "flag_title": "Flag bài viết này để chỉnh sửa",
+ "flag_confirm": "Bạn có chắc là muốn flag bài viết này không?",
+ "flag_success": "Chủ đề này đã được flag để chỉnh sửa",
+ "deleted_message": "Thread này đã bị xóa. Chỉ người dùng có quyền quản lý thread mới xem được.",
+ "following_topic.message": "Từ giờ bạn sẽ nhận được thông báo khi có ai đó gửi bài viết trong chủ đề này",
+ "not_following_topic.message": "Bạn sẽ không còn nhận được thông báo từ chủ đề này",
+ "login_to_subscribe": "Xin hãy đăng ký hoặc đăng nhập để theo dõi topic này",
+ "markAsUnreadForAll.success": "Chủ đề đã được đánh dấu là chưa đọc toàn bộ",
+ "watch": "Xem",
+ "watch.title": "Được thông báo khi có trả lời mới trong chủ đề này",
+ "share_this_post": "Chia sẻ bài viết này",
+ "thread_tools.title": "Công cụ cho Thread",
+ "thread_tools.markAsUnreadForAll": "Đánh dấu chưa đọc",
+ "thread_tools.pin": "Pin chủ đề",
+ "thread_tools.unpin": "Bỏ pin chủ đề",
+ "thread_tools.lock": "Khóa chủ đề",
+ "thread_tools.unlock": "Mở khóa chủ đề",
+ "thread_tools.move": "Chuyển chủ đề",
+ "thread_tools.move_all": "Chuyển tất cả",
+ "thread_tools.fork": "Fork chủ đề",
+ "thread_tools.delete": "Xóa chủ đề",
+ "thread_tools.delete_confirm": "Bạn có chắc là muốn hủy thread này không?",
+ "thread_tools.restore": "Phục hồi chủ đề",
+ "thread_tools.restore_confirm": "Bạn có chắc là muốn phục hồi thread này không",
+ "topic_lock_success": "Đã khóa thành công chủ đề.",
+ "topic_unlock_success": "Đã mở khóa thành công chủ đề.",
+ "topic_pin_success": "Đã pin chủ đề thành công",
+ "topic_unpin_success": "Đã bỏ pin chủ đề thành công",
+ "topic_move_success": "Đã chuyển thành công chủ đề này sang %1",
+ "post_delete_confirm": "Bạn có chắc là muốn xóa bài gửi này không?",
+ "post_restore_confirm": "Bạn có chắc là muốn phục hồi bài gửi này không?",
+ "post_delete_error": "Không thể xóa bài gửi này!",
+ "post_restore_error": "Không thể phục hồi bài gửi này!",
+ "load_categories": "Đang tải các phần mục",
+ "disabled_categories_note": "Các phần mục bị khóa đã được đánh xám",
+ "confirm_move": "Chuyển",
+ "confirm_fork": "Fork",
+ "favourite": "Yêu thích",
+ "favourites": "Đang yêu thích",
+ "favourites.has_no_favourites": "Bạn đang không có yêu thích nào. Hãy yêu thích một vài bài viết để thấy được chúng tại đây!",
+ "loading_more_posts": "Tải thêm các bài gửi khác",
+ "move_topic": "Chuyển chủ đề",
+ "move_post": "Chuyển bài gửi",
+ "post_moved": "Đã chuyển bài gửi!",
+ "fork_topic": "Fork chủ đề",
+ "topic_will_be_moved_to": "Chủ đề này sẽ được chuyển tới phần mục",
+ "fork_topic_instruction": "Nhấp vào bài gửi mà bạn muốn fork",
+ "fork_no_pids": "Chưa chọn bài gửi nào!",
+ "fork_success": "Đã fork chủ đề thành công!",
+ "composer.title_placeholder": "Nhập tiêu đề cho chủ đề của bạn tại đây...",
+ "composer.write": "Viết",
+ "composer.preview": "Xem trước",
+ "composer.help": "Trợ giúp",
+ "composer.discard": "Loại bỏ",
+ "composer.submit": "Gửi",
+ "composer.replying_to": "Đang trả lời %1",
+ "composer.new_topic": "Chủ đề mới",
+ "composer.uploading": "đang tải lên...",
+ "composer.thumb_url_label": "Dán một thumbnail URL cho chủ đề",
+ "composer.thumb_title": "Thêm một thumbnail cho chủ đề này",
+ "composer.thumb_url_placeholder": "http://example.com/thumb.png",
+ "composer.thumb_file_label": "Hoặc tải lên một tệp",
+ "composer.thumb_remove": "Xóa toàn bộ",
+ "composer.drag_and_drop_images": "Kéo và thả hình ảnh tại đây",
+ "composer.upload_instructions": "Tải lên hình ảnh bằng cách kéo và thả",
+ "more_users_and_guests": "%1 người dùng và %2 khách nữa",
+ "more_users": "%1 người dùng nữa",
+ "more_guests": "%1 khách nữa"
+}
\ No newline at end of file
diff --git a/public/language/vi/unread.json b/public/language/vi/unread.json
new file mode 100644
index 0000000000..634efe34d4
--- /dev/null
+++ b/public/language/vi/unread.json
@@ -0,0 +1,9 @@
+{
+ "title": "Chưa đọc",
+ "no_unread_topics": "Không có chủ đề chưa được đọc",
+ "load_more": "Tải thêm",
+ "mark_as_read": "Đánh dấu đã đọc",
+ "selected": "Đã chọn",
+ "all": "Tất cả",
+ "topics_marked_as_read.success": "Chủ đề được đánh dấu đã đọc"
+}
\ No newline at end of file
diff --git a/public/language/vi/user.json b/public/language/vi/user.json
new file mode 100644
index 0000000000..fa9fc38c60
--- /dev/null
+++ b/public/language/vi/user.json
@@ -0,0 +1,62 @@
+{
+ "banned": "Bị ban",
+ "offline": "Offline",
+ "username": "Tên truy cập",
+ "email": "Email",
+ "fullname": "Tên đầy đủ",
+ "website": "Website",
+ "location": "Địa điểm",
+ "age": "Tuổi",
+ "joined": "Đã gia nhập",
+ "lastonline": "Online lần cuối vào",
+ "profile": "Hồ sơ",
+ "profile_views": "Khung hiển thị hồ sơ",
+ "reputation": "Mức uy tín",
+ "favourites": "Yêu thích",
+ "followers": "Số người theo dõi",
+ "following": "Đang theo dõi",
+ "signature": "Chữ ký",
+ "gravatar": "Gavatar",
+ "birthday": "Ngày sinh ",
+ "chat": "Chat",
+ "follow": "Theo dõi",
+ "unfollow": "Hủy theo dõi",
+ "profile_update_success": "Hồ sơ đã được cập nhật thành công",
+ "change_picture": "Thay đổi hình ảnh",
+ "edit": "Chỉnh sửa",
+ "uploaded_picture": "Ảnh đã tải lên",
+ "upload_new_picture": "Tải lên ảnh mới",
+ "current_password": "Mật khẩu hiện tại",
+ "change_password": "Thay đổi mật khẩu",
+ "change_password_error": "Mật khẩu không đúng!",
+ "change_password_error_wrong_current": "Mật khẩu hiện tại của bạn không đúng",
+ "change_password_error_length": "Mật khẩu quá ngắn!",
+ "change_password_error_match": "Mật khẩu phải khớp!",
+ "change_password_error_privileges": "Bạn không có quyền thay đổi mật khẩu này",
+ "change_password_success": "Mật khẩu của bạn đã được cập nhật",
+ "confirm_password": "Xác nhận mật khẩu",
+ "password": "Mật khẩu",
+ "username_taken_workaround": "Tên truy cập này đã tồn tại, vì vậy chúng tôi đã sửa đổi nó một chút. Tên truy cập của bạn giờ là %1",
+ "upload_picture": "Tải lên hình ảnh",
+ "upload_a_picture": "Tải lên một hình ảnh",
+ "image_spec": "Bạn chỉ có thể tải lên được các file PNG, JPG hoặc GIF",
+ "max": "tối đa",
+ "settings": "Thiết lập",
+ "show_email": "Hiện Email của tôi",
+ "digest_label": "Đăng ký để digest",
+ "digest_description": "Đăng ký để được forum gửi cập nhật tới email (thông báo và chủ đề mới) trong một khoảng thời gian lặp lại nhất định ",
+ "digest_off": "Off",
+ "digest_daily": "Hàng ngày",
+ "digest_weekly": "Hàng tuần",
+ "digest_monthly": "Hàng tháng",
+ "has_no_follower": "Người dùng này hiện chưa có ai theo dõi :(",
+ "follows_no_one": "Người dùng này hiện chưa theo dõi ai :(",
+ "has_no_posts": "Người dùng này chưa viết bài nào",
+ "has_no_topics": "Người dùng này chưa tạo một chủ đề nào",
+ "email_hidden": "Ẩn Email",
+ "hidden": "Đã ẩn",
+ "paginate_description": "Phân trang cho chủ đề và bài viết thay vì cuộn liên tục",
+ "topics_per_page": "Số chủ đề trong một trang",
+ "posts_per_page": "Số bài viết trong một trang",
+ "notification_sounds": "Xuất hiện âm thanh khi bạn nhận được một thông báo"
+}
\ No newline at end of file
diff --git a/public/language/vi/users.json b/public/language/vi/users.json
new file mode 100644
index 0000000000..e09f3c94ea
--- /dev/null
+++ b/public/language/vi/users.json
@@ -0,0 +1,8 @@
+{
+ "latest_users": "Những người dùng mới nhất",
+ "top_posters": "Những người viết bài nhiều nhất",
+ "most_reputation": "Uy tín nhất",
+ "search": "Tìm kiếm",
+ "enter_username": "Gõ tên người dùng để tìm kiếm",
+ "load_more": "Tải thêm"
+}
\ No newline at end of file
diff --git a/public/src/forum/admin/plugins.js b/public/src/forum/admin/plugins.js
index 68b03c4b50..6246c48851 100644
--- a/public/src/forum/admin/plugins.js
+++ b/public/src/forum/admin/plugins.js
@@ -48,7 +48,7 @@ define(function() {
btn.html(' Install');
}
- btn.toggleClass('btn-warning', status.installed).toggleClass('btn-success', !status.installed)
+ btn.toggleClass('btn-danger', status.installed).toggleClass('btn-success', !status.installed)
.attr('disabled', false);
activateBtn.toggleClass('hide', !status.installed);
diff --git a/public/src/forum/admin/settings.js b/public/src/forum/admin/settings.js
index cddd48428b..6bc5d782d0 100644
--- a/public/src/forum/admin/settings.js
+++ b/public/src/forum/admin/settings.js
@@ -61,21 +61,7 @@ define(['uploader', 'sounds'], function(uploader, sounds) {
}
});
- $('#uploadLogoBtn').on('click', function() {
- uploader.open(RELATIVE_PATH + '/admin/uploadlogo', {}, 0, function(image) {
- $('#logoUrl').val(image);
- });
-
- uploader.hideAlerts();
- });
-
- $('#uploadFaviconBtn').on('click', function() {
- uploader.open(RELATIVE_PATH + '/admin/uploadfavicon', {}, 0, function(icon) {
- $('#faviconUrl').val(icon);
- });
-
- uploader.hideAlerts();
- });
+ handleUploads();
$('#settings-tab a').click(function (e) {
e.preventDefault();
@@ -88,6 +74,19 @@ define(['uploader', 'sounds'], function(uploader, sounds) {
}
};
+ function handleUploads() {
+ $('#content input[data-action="upload"]').each(function() {
+ var uploadBtn = $(this);
+ uploadBtn.on('click', function() {
+ uploader.open(uploadBtn.attr('data-route'), {}, 0, function(image) {
+ $('#' + uploadBtn.attr('data-target')).val(image);
+ });
+
+ uploader.hideAlerts();
+ });
+ });
+ }
+
Settings.remove = function(key) {
socket.emit('admin.config.remove', key);
};
diff --git a/public/src/forum/category.js b/public/src/forum/category.js
index af69859270..e71dfc185f 100644
--- a/public/src/forum/category.js
+++ b/public/src/forum/category.js
@@ -169,11 +169,14 @@ define(['composer', 'forum/pagination', 'share', 'navigator', 'forum/categoryToo
}
}
- Category.onNewTopic = function(data) {
- $(window).trigger('filter:categories.new_topic', data);
+ Category.onNewTopic = function(topic) {
+ $(window).trigger('filter:categories.new_topic', topic);
ajaxify.loadTemplate('category', function(categoryTemplate) {
- var html = templates.parse(templates.getBlock(categoryTemplate, 'topics'), {topics: [data]});
+ var html = templates.parse(templates.getBlock(categoryTemplate, 'topics'), {
+ privileges: {editable: !!$('.thread-tools').length},
+ topics: [topic]
+ });
translator.translate(html, function(translatedHTML) {
var topic = $(translatedHTML),
diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js
index 3162f87f61..50954debfa 100644
--- a/public/src/forum/topic.js
+++ b/public/src/forum/topic.js
@@ -243,8 +243,21 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools',
socket.on('user.isOnline', function(err, data) {
app.populateOnlineUsers();
+
+ updateActiveUsers(data);
});
+ function updateActiveUsers(data) {
+ var activeEl = $('.thread_active_users');
+ var user = activeEl.find('a[data-uid="'+ data.uid + '"]');
+ if (user.length && !data.online) {
+ user.parent().remove();
+ } else if(!user.length && data.online) {
+ user = createUserIcon(data.uid, data.picture, data.userslug, data.username);
+ activeEl.append(user);
+ }
+ }
+
socket.on('event:voted', function(data) {
updatePostVotesAndUserReputation(data);
});
diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js
index 4972eaf3c3..6e57037a47 100644
--- a/public/src/modules/composer.js
+++ b/public/src/modules/composer.js
@@ -953,7 +953,12 @@ define(['taskbar'], function(taskbar) {
content: bodyEl.val(),
topic_thumb: thumbEl.val() || '',
category_id: postData.cid
- }, done);
+ }, function(err, topic) {
+ done(err);
+ if (!err) {
+ ajaxify.go('topic/' + topic.slug);
+ }
+ });
} else if (parseInt(postData.tid, 10) > 0) {
socket.emit('posts.reply', {
tid: postData.tid,
diff --git a/public/src/modules/topicSelect.js b/public/src/modules/topicSelect.js
index 4fbbc38f12..a5b131a7a2 100644
--- a/public/src/modules/topicSelect.js
+++ b/public/src/modules/topicSelect.js
@@ -4,21 +4,38 @@
define(function() {
var TopicSelect = {};
+ var lastSelected;
TopicSelect.init = function(onSelect) {
- $('#topics-container').on('click', '.select', function() {
+
+ $('#topics-container').on('selectstart', function() {
+ return false;
+ });
+
+ $('#topics-container').on('click', '.select', function(ev) {
var select = $(this);
- var isChecked = !select.hasClass('fa-square-o');
- select.toggleClass('fa-check-square-o', !isChecked);
- select.toggleClass('fa-square-o', isChecked);
- select.parents('.category-item').toggleClass('selected', !isChecked);
+ if (ev.shiftKey) {
+ selectRange($(this).parents('.category-item').attr('data-tid'));
+ lastSelected = select;
+ return false;
+ }
+
+ var isSelected = select.hasClass('fa-check-square-o');
+ toggleSelect(select, !isSelected);
+ lastSelected = select;
if (typeof onSelect === 'function') {
onSelect();
}
});
};
+ function toggleSelect(select, isSelected) {
+ select.toggleClass('fa-check-square-o', isSelected);
+ select.toggleClass('fa-square-o', !isSelected);
+ select.parents('.category-item').toggleClass('selected', isSelected);
+ }
+
TopicSelect.getSelectedTids = function() {
var tids = [];
$('#topics-container .category-item.selected').each(function() {
@@ -32,5 +49,35 @@ define(function() {
$('#topics-container .select').toggleClass('fa-check-square-o', false).toggleClass('fa-square-o', true);
};
+ function selectRange(clickedTid) {
+
+ if(!lastSelected) {
+ lastSelected = $('.category-item[data-tid]').first().find('.select');
+ }
+
+ var isClickedSelected = $('.category-item[data-tid="' + clickedTid + '"]').hasClass('selected');
+
+ var clickedIndex = getIndex(clickedTid);
+ var lastIndex = getIndex(lastSelected.parents('.category-item[data-tid]').attr('data-tid'));
+ selectIndexRange(clickedIndex, lastIndex, !isClickedSelected);
+ }
+
+ function selectIndexRange(start, end, isSelected) {
+ if (start > end) {
+ var tmp = start;
+ start = end;
+ end = tmp;
+ }
+
+ for(var i=start; i<=end; ++i) {
+ var topic = $('.category-item[data-tid]').eq(i);
+ toggleSelect(topic.find('.select'), isSelected);
+ }
+ }
+
+ function getIndex(tid) {
+ return $('.category-item[data-tid="' + tid + '"]').index('.category-item');
+ }
+
return TopicSelect;
});
\ No newline at end of file
diff --git a/src/categories.js b/src/categories.js
index 11c86e81fd..713ce64220 100644
--- a/src/categories.js
+++ b/src/categories.js
@@ -317,8 +317,6 @@ var db = require('./database'),
if(parseInt(topicData.pinned, 10) === 0) {
db.sortedSetAdd('categories:' + cid + ':tid', postData.timestamp, postData.tid);
}
-
- Categories.addActiveUser(cid, postData.uid, postData.timestamp);
});
};
diff --git a/src/categories/activeusers.js b/src/categories/activeusers.js
index 9b8e558aae..57873944b8 100644
--- a/src/categories/activeusers.js
+++ b/src/categories/activeusers.js
@@ -1,83 +1,31 @@
'use strict';
var async = require('async'),
-
db = require('./../database'),
posts = require('./../posts'),
topics = require('./../topics');
module.exports = function(Categories) {
- Categories.isUserActiveIn = function(cid, uid, callback) {
-
- db.getSortedSetRange('uid:' + uid + ':posts', 0, -1, function(err, pids) {
- if (err) {
- return callback(err);
- }
-
- var index = 0,
- active = false;
-
- async.whilst(
- function() {
- return active === false && index < pids.length;
- },
- function(callback) {
- posts.getCidByPid(pids[index], function(err, postCid) {
- if (err) {
- return callback(err);
- }
-
- if (postCid === cid) {
- active = true;
- }
+ Categories.getActiveUsers = function(cid, callback) {
+ db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, 99, function(err, pids) {
+ var keys = pids.map(function(pid) {
+ return 'post:' + pid;
+ });
- ++index;
- callback();
- });
- },
- function(err) {
- callback(err, active);
+ db.getObjectsFields(keys, ['uid'], function(err, users) {
+ if (err) {
+ return callback(err);
}
- );
- });
- };
- Categories.addActiveUser = function(cid, uid, timestamp) {
- if(parseInt(uid, 10)) {
- db.sortedSetAdd('cid:' + cid + ':active_users', timestamp, uid);
- }
- };
-
- Categories.removeActiveUser = function(cid, uid, callback) {
- db.sortedSetRemove('cid:' + cid + ':active_users', uid, callback);
- };
+ var uids = users.map(function(user) {
+ return user.uid;
+ }).filter(function(value, index, array) {
+ return parseInt(value, 10) !== 0 && array.indexOf(value) === index;
+ }).slice(0, 24);
- Categories.getActiveUsers = function(cid, callback) {
- db.getSortedSetRevRange('cid:' + cid + ':active_users', 0, 23, callback);
- };
-
- Categories.moveActiveUsers = function(tid, oldCid, cid) {
- function updateUser(uid, timestamp) {
- Categories.addActiveUser(cid, uid, timestamp);
- Categories.isUserActiveIn(oldCid, uid, function(err, active) {
-
- if (!err && !active) {
- Categories.removeActiveUser(oldCid, uid);
- }
+ callback(null, uids);
});
- }
-
- topics.getTopicField(tid, 'timestamp', function(err, timestamp) {
- if(!err) {
- topics.getUids(tid, function(err, uids) {
- if (!err && uids) {
- for (var i = 0; i < uids.length; ++i) {
- updateUser(uids[i], timestamp);
- }
- }
- });
- }
});
};
};
diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js
index 33ee629811..925e83e42e 100644
--- a/src/categories/recentreplies.js
+++ b/src/categories/recentreplies.js
@@ -2,6 +2,8 @@
'use strict';
var async = require('async'),
+ winston = require('winston'),
+
db = require('./../database'),
posts = require('./../posts'),
topics = require('./../topics'),
@@ -23,26 +25,40 @@ module.exports = function(Categories) {
};
Categories.moveRecentReplies = function(tid, oldCid, cid) {
- function movePost(pid, next) {
- posts.getPostField(pid, 'timestamp', function(err, timestamp) {
- if(err) {
- return next(err);
+ function movePost(postData, next) {
+ async.parallel([
+ function(next) {
+ db.sortedSetRemove('categories:recent_posts:cid:' + oldCid, postData.pid, next);
+ },
+ function(next) {
+ db.sortedSetAdd('categories:recent_posts:cid:' + cid, postData.timestamp, postData.pid, next);
}
-
- db.sortedSetRemove('categories:recent_posts:cid:' + oldCid, pid);
- db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
- next();
- });
+ ], next);
}
topics.getPids(tid, function(err, pids) {
- if(!err && pids) {
- async.each(pids, movePost, function(err) {
+ if (err) {
+ return winston.error(err.message);
+ }
+ if (pids && !pids.length) {
+ return;
+ }
+
+ var keys = pids.map(function(pid) {
+ return 'post:' + pid;
+ });
+
+ db.getObjectsFields(keys, ['pid', 'timestamp'], function(err, postData) {
+ if (err) {
+ return winston.error(err.message);
+ }
+
+ async.each(postData, movePost, function(err) {
if (err) {
winston.error(err.message);
}
});
- }
+ });
});
};
};
diff --git a/src/controllers/admin/uploads.js b/src/controllers/admin/uploads.js
index e7c79d6e7e..e0543c9add 100644
--- a/src/controllers/admin/uploads.js
+++ b/src/controllers/admin/uploads.js
@@ -87,7 +87,20 @@ uploadsController.uploadLogo = function(req, res, next) {
if (validateUpload(res, req, allowedTypes)) {
var filename = 'site-logo' + path.extname(req.files.userPhoto.name);
uploadsController.uploadImage(filename, req, res);
- }
+ }
+};
+
+
+uploadsController.uploadGravatarDefault = function(req, res, next) {
+ var allowedTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif'],
+ er;
+
+ if (validateUpload(res, req, allowedTypes)) {
+ var filename = 'gravatar-default' + path.extname(req.files.userPhoto.name);
+ uploadsController.uploadImage(filename, req, res);
+ }
};
+
+
module.exports = uploadsController;
diff --git a/src/plugins.js b/src/plugins.js
index d660d90eae..832c43fef1 100644
--- a/src/plugins.js
+++ b/src/plugins.js
@@ -484,27 +484,60 @@ var fs = require('fs'),
return callback(null, []);
}
- async.map(plugins, function(plugin, next) {
+ var pluginMap = {};
+ for(var i=0; i