mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-06-14 15:20:17 +02:00
Merge branch 'master' of github.com:designcreateplay/NodeBB
This commit is contained in:
32
.tx/config
32
.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
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
7
public/language/ja/category.json
Normal file
7
public/language/ja/category.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"new_topic_button": "新規スレッド",
|
||||
"no_topics": "<strong>まだスレッドはありません.</strong><br />一番目のスレッドを書いてみないか?",
|
||||
"browsing": "閲覧中",
|
||||
"no_replies": "返事はまだありません",
|
||||
"share_this_category": "この板を共有"
|
||||
}
|
||||
49
public/language/ja/error.json
Normal file
49
public/language/ja/error.json
Normal file
@@ -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": "自分にチャットすることはできません!"
|
||||
}
|
||||
7
public/language/ja/footer.json
Normal file
7
public/language/ja/footer.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"stats.online": "利用者",
|
||||
"stats.users": "登録",
|
||||
"stats.topics": "スレッド",
|
||||
"stats.posts": "ポスト",
|
||||
"success": "成功"
|
||||
}
|
||||
70
public/language/ja/global.json
Normal file
70
public/language/ja/global.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"home": "ホーム",
|
||||
"search": "検索",
|
||||
"buttons.close": "閉じる",
|
||||
"403.title": "アクセス拒否",
|
||||
"403.message": "アクセスが拒否されました.<a href='/login'>ログインしますか</a>?",
|
||||
"404.title": "見つかりません",
|
||||
"404.message": "アクセスしようとしていたページは存在しません.<a href='/'>ホーム</a>へ",
|
||||
"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": "ゲスト"
|
||||
}
|
||||
5
public/language/ja/language.json
Normal file
5
public/language/ja/language.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "日本語",
|
||||
"code": "ja",
|
||||
"dir": "ltr"
|
||||
}
|
||||
8
public/language/ja/login.json
Normal file
8
public/language/ja/login.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"username": "ユーザー名 / メール",
|
||||
"remember_me": "ログイン情報を記憶",
|
||||
"forgot_password": "パスワードがわからない?",
|
||||
"alternative_logins": "ほかのログイン方法",
|
||||
"failed_login_attempt": "ログインに失敗しました.ユーザー名やパスワードをご確認ください。",
|
||||
"login_successful": "ログインしました!"
|
||||
}
|
||||
7
public/language/ja/modules.json
Normal file
7
public/language/ja/modules.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"chat.chatting_with": "<span id=\"chat-with-name\"></span>とチャット",
|
||||
"chat.placeholder": "メッセージを入力する",
|
||||
"chat.send": "送信",
|
||||
"chat.no_active": "チャットはありません。",
|
||||
"chat.user_typing": "%1 は入力中 ..."
|
||||
}
|
||||
18
public/language/ja/notifications.json
Normal file
18
public/language/ja/notifications.json
Normal file
@@ -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": "<strong>%1</strong>は新しいポストを投稿しました。",
|
||||
"new_message_from": "<strong>%1</strong>からの新しいメッセージ",
|
||||
"upvoted_your_post": "<strong>%1</strong>はあなたのポストを評価しました。",
|
||||
"favourited_your_post": "<strong>%1</strong>はあなたのポストをお気に入りにしました。",
|
||||
"user_flagged_post": "<strong>%1</strong> ポストを報告しました。",
|
||||
"user_posted_to": "<strong>%1</strong> は <strong>%2</strong> への返事を作成しました。"
|
||||
}
|
||||
15
public/language/ja/pages.json
Normal file
15
public/language/ja/pages.json
Normal file
@@ -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": "ユーザー設定"
|
||||
}
|
||||
7
public/language/ja/recent.json
Normal file
7
public/language/ja/recent.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "最近の更新",
|
||||
"day": "最近 1 日",
|
||||
"week": "最近 1 週",
|
||||
"month": "最近 1 ヶ月",
|
||||
"no_recent_topics": "最近のスレッドはありません。"
|
||||
}
|
||||
18
public/language/ja/register.json
Normal file
18
public/language/ja/register.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"register": "登録",
|
||||
"help.email": "デフォルト設定ではメールアドレスは公開されません。",
|
||||
"help.username_restrictions": "%1 から %2 文字までのユニークなユーザー名.Twitter の @<span id='yourUsername'>username</span> 方式でメンションすることができます。",
|
||||
"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": "利用規約に同意する"
|
||||
}
|
||||
14
public/language/ja/reset_password.json
Normal file
14
public/language/ja/reset_password.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"reset_password": "パスワードをリセット",
|
||||
"update_password": "パスワードを更新",
|
||||
"password_changed.title": "パスワードを更新しました",
|
||||
"password_changed.message": "<p>パスワードをリセットできました.こちらで<a href=\"/login\">ログインしてください</a>。",
|
||||
"wrong_reset_code.title": "リセットコードは正しくありません",
|
||||
"wrong_reset_code.message": "リセットコードは正しくありません.もう一度入力するか、<a href=\"/reset\">新しいリセットコードを請求する</a>ことができます。",
|
||||
"new_password": "新しいパスワード",
|
||||
"repeat_password": "パスワード再入力",
|
||||
"enter_email": "<strong>メールアドレス</strong>を入力してください.パスワードリセットの指示をメールでご送付します。",
|
||||
"enter_email_address": "メールアドレスを入力してください",
|
||||
"password_reset_sent": "パスワードリセットのメールを送信しました",
|
||||
"invalid_email": "このメールアドレスは存在しません"
|
||||
}
|
||||
6
public/language/ja/success.json
Normal file
6
public/language/ja/success.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"success": "成功",
|
||||
"topic-post": "成功に投稿しました。",
|
||||
"authentication-successful": "認証が成功しました",
|
||||
"settings-saved": "設定を保存しました。"
|
||||
}
|
||||
93
public/language/ja/topic.json
Normal file
93
public/language/ja/topic.json
Normal file
@@ -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)"
|
||||
}
|
||||
9
public/language/ja/unread.json
Normal file
9
public/language/ja/unread.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"title": "未読",
|
||||
"no_unread_topics": "未読のスレッドがあります。",
|
||||
"load_more": "もっと見る",
|
||||
"mark_as_read": "既読にする",
|
||||
"selected": "選択済み",
|
||||
"all": "すべて",
|
||||
"topics_marked_as_read.success": "すべてのスレッドを既読にしました。"
|
||||
}
|
||||
62
public/language/ja/user.json
Normal file
62
public/language/ja/user.json
Normal file
@@ -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": "このユーザー名はすでに使用されています。いまのユーザー名は <strong>%1</strong> です。",
|
||||
"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": "通知が来たとき音を流す"
|
||||
}
|
||||
8
public/language/ja/users.json
Normal file
8
public/language/ja/users.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"latest_users": "最新ユーザー",
|
||||
"top_posters": "最も投稿したユーザー",
|
||||
"most_reputation": "最も評価されたユーザー",
|
||||
"search": "検索",
|
||||
"enter_username": "検索するユーザー名を入力してください",
|
||||
"load_more": "もっと表示"
|
||||
}
|
||||
7
public/language/vi/category.json
Normal file
7
public/language/vi/category.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"new_topic_button": "Chủ đề mới",
|
||||
"no_topics": "<strong>Không có bài viết trong danh mục.</strong><br />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"
|
||||
}
|
||||
49
public/language/vi/error.json
Normal file
49
public/language/vi/error.json
Normal file
@@ -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!"
|
||||
}
|
||||
70
public/language/vi/global.json
Normal file
70
public/language/vi/global.json
Normal file
@@ -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"
|
||||
}
|
||||
5
public/language/vi/language.json
Normal file
5
public/language/vi/language.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Tiếng Việt",
|
||||
"code": "vi",
|
||||
"dir": "ltr"
|
||||
}
|
||||
8
public/language/vi/login.json
Normal file
8
public/language/vi/login.json
Normal file
@@ -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!"
|
||||
}
|
||||
7
public/language/vi/modules.json
Normal file
7
public/language/vi/modules.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"chat.chatting_with": "Chat với <span id=\"chat-with-name\"></span>",
|
||||
"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õ"
|
||||
}
|
||||
18
public/language/vi/notifications.json
Normal file
18
public/language/vi/notifications.json
Normal file
@@ -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": "<strong>%1</strong> đã viết bài mới",
|
||||
"new_message_from": "Tin nhắn mới từ <strong>%1</strong>",
|
||||
"upvoted_your_post": "<strong>%1</strong> đã hủy vote cho bài viết của bạn",
|
||||
"favourited_your_post": "<strong>%1</strong> thích bài viết của bạn",
|
||||
"user_flagged_post": "<strong>%1</strong> đã flag một bài viết",
|
||||
"user_posted_to": "<strong>%1</strong> đã trả lời <strong>%2</strong>"
|
||||
}
|
||||
15
public/language/vi/pages.json
Normal file
15
public/language/vi/pages.json
Normal file
@@ -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"
|
||||
}
|
||||
7
public/language/vi/recent.json
Normal file
7
public/language/vi/recent.json
Normal file
@@ -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"
|
||||
}
|
||||
18
public/language/vi/register.json
Normal file
18
public/language/vi/register.json
Normal file
@@ -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 @<span id='yourUsername'>tên truy cập</span>.",
|
||||
"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"
|
||||
}
|
||||
14
public/language/vi/reset_password.json
Normal file
14
public/language/vi/reset_password.json
Normal file
@@ -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": "<p>Mật khẩu đã được thiết lập lại thành công, xin hãy <a href=\"/login\">đăng nhập lại</a>.",
|
||||
"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 <a href=\"/reset\">yêu cầu một mã thiết lập lại khác</a>.",
|
||||
"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 <strong>địa chỉ email</strong> 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!"
|
||||
}
|
||||
6
public/language/vi/success.json
Normal file
6
public/language/vi/success.json
Normal file
@@ -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"
|
||||
}
|
||||
93
public/language/vi/topic.json
Normal file
93
public/language/vi/topic.json
Normal file
@@ -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"
|
||||
}
|
||||
9
public/language/vi/unread.json
Normal file
9
public/language/vi/unread.json
Normal file
@@ -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"
|
||||
}
|
||||
62
public/language/vi/user.json
Normal file
62
public/language/vi/user.json
Normal file
@@ -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à <strong>%1</strong>",
|
||||
"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"
|
||||
}
|
||||
8
public/language/vi/users.json
Normal file
8
public/language/vi/users.json
Normal file
@@ -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"
|
||||
}
|
||||
@@ -48,7 +48,7 @@ define(function() {
|
||||
btn.html('<i class="fa fa-download"></i> 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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,21 +4,38 @@
|
||||
|
||||
define(function() {
|
||||
var TopicSelect = {};
|
||||
var lastSelected;
|
||||
|
||||
TopicSelect.init = function(onSelect) {
|
||||
$('#topics-container').on('click', '.select', function() {
|
||||
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);
|
||||
$('#topics-container').on('selectstart', function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#topics-container').on('click', '.select', function(ev) {
|
||||
var select = $(this);
|
||||
|
||||
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;
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
++index;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
callback(err, active);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, 99, function(err, pids) {
|
||||
var keys = pids.map(function(pid) {
|
||||
return 'post:' + pid;
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
db.getObjectsFields(keys, ['uid'], function(err, users) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
callback(null, uids);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -484,27 +484,60 @@ var fs = require('fs'),
|
||||
return callback(null, []);
|
||||
}
|
||||
|
||||
async.map(plugins, function(plugin, next) {
|
||||
var pluginMap = {};
|
||||
for(var i=0; i<plugins.length; ++i) {
|
||||
plugins[i].id = plugins[i].name;
|
||||
plugins[i].installed = false;
|
||||
plugins[i].active = false;
|
||||
pluginMap[plugins[i].name] = plugins[i];
|
||||
}
|
||||
|
||||
plugin.id = plugin.name;
|
||||
Plugins.showInstalled(function(err, installedPlugins) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
active: function(next) {
|
||||
Plugins.isActive(plugin.id, next);
|
||||
},
|
||||
installed: function(next) {
|
||||
Plugins.isInstalled(plugin.id, next);
|
||||
}
|
||||
}, function(err, results) {
|
||||
async.each(installedPlugins, function(plugin, next) {
|
||||
|
||||
pluginMap[plugin.id] = pluginMap[plugin.id] || {};
|
||||
pluginMap[plugin.id].id = pluginMap[plugin.id].id || plugin.id;
|
||||
pluginMap[plugin.id].description = plugin.description;
|
||||
pluginMap[plugin.id].url = plugin.url;
|
||||
pluginMap[plugin.id].installed = true;
|
||||
|
||||
Plugins.isActive(plugin.id, function(err, active) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
pluginMap[plugin.id].active = active;
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
return callback(err);
|
||||
}
|
||||
plugin.active = results.active;
|
||||
plugin.installed = results.installed;
|
||||
next(null, plugin);
|
||||
});
|
||||
|
||||
}, callback);
|
||||
var pluginArray = [];
|
||||
|
||||
for (var key in pluginMap) {
|
||||
if (pluginMap.hasOwnProperty(key)) {
|
||||
pluginArray.push(pluginMap[key]);
|
||||
}
|
||||
}
|
||||
|
||||
pluginArray.sort(function(a, b) {
|
||||
if(a.installed && !b.installed) {
|
||||
return -1;
|
||||
} else if(!a.installed && b.installed) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
callback(null, pluginArray);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -536,7 +569,7 @@ var fs = require('fs'),
|
||||
}
|
||||
|
||||
callback(stats.isDirectory());
|
||||
})
|
||||
});
|
||||
}, function(plugins){
|
||||
next(null, plugins);
|
||||
});
|
||||
@@ -556,7 +589,7 @@ var fs = require('fs'),
|
||||
try {
|
||||
var config = JSON.parse(configJSON);
|
||||
} catch (err) {
|
||||
winston.warn("Plugin: " + file + " is corrupted or invalid. Please check plugin.json for errors.")
|
||||
winston.warn("Plugin: " + file + " is corrupted or invalid. Please check plugin.json for errors.");
|
||||
return next(err, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ var winston = require('winston'),
|
||||
}
|
||||
|
||||
function updateTopicTimestamp(tid, callback) {
|
||||
threadTools.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
topics.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
if(err || !pid) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ var db = require('./database'),
|
||||
reputation: userData.reputation || 0,
|
||||
postcount: userData.postcount || 0,
|
||||
banned: parseInt(userData.banned, 10) === 1,
|
||||
picture: userData.picture || gravatar.url('', {}, true)
|
||||
picture: userData.picture || user.createGravatarURLFromEmail('')
|
||||
};
|
||||
|
||||
for (var info in customUserInfo) {
|
||||
|
||||
@@ -57,6 +57,7 @@ function apiRoutes(app, middleware, controllers) {
|
||||
app.post('/admin/category/uploadpicture', middleware.authenticate, controllers.admin.uploads.uploadCategoryPicture);
|
||||
app.post('/admin/uploadfavicon', middleware.authenticate, controllers.admin.uploads.uploadFavicon);
|
||||
app.post('/admin/uploadlogo', middleware.authenticate, controllers.admin.uploads.uploadLogo);
|
||||
app.post('/admin/uploadgravatardefault', middleware.authenticate, controllers.admin.uploads.uploadGravatarDefault);
|
||||
}
|
||||
|
||||
function miscRoutes(app, middleware, controllers) {
|
||||
|
||||
@@ -225,6 +225,22 @@ Sockets.getUserSockets = function(uid) {
|
||||
|
||||
/* Helpers */
|
||||
|
||||
Sockets.reqFromSocket = function(socket) {
|
||||
var headers = socket.handshake.headers,
|
||||
host = headers.host,
|
||||
referer = headers.referer;
|
||||
|
||||
return {
|
||||
ip: headers['x-forwarded-for'] || (socket.handshake.address || {}).address,
|
||||
host: host,
|
||||
protocol: headers.secure ? 'https' : 'http',
|
||||
secure: !!headers.secure,
|
||||
url: referer,
|
||||
path: referer.substr(referer.indexOf(host) + host.length),
|
||||
headers: headers
|
||||
};
|
||||
};
|
||||
|
||||
Sockets.isUserOnline = isUserOnline;
|
||||
function isUserOnline(uid) {
|
||||
return Sockets.getUserSockets(uid).length > 0;
|
||||
@@ -263,8 +279,6 @@ function updateRoomBrowsingText(roomName) {
|
||||
var uids = getUidsInRoom(),
|
||||
anonymousCount = getAnonymousCount();
|
||||
|
||||
|
||||
|
||||
user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture', 'status'], function(err, users) {
|
||||
if(!err) {
|
||||
users = users.filter(function(user) {
|
||||
|
||||
@@ -67,9 +67,7 @@ SocketMeta.updateHeader = function(socket, data, callback) {
|
||||
uid: 0,
|
||||
username: '[[global:guest]]',
|
||||
email: '',
|
||||
picture: gravatar.url('', {
|
||||
s: '24'
|
||||
}, true),
|
||||
picture: user.createGravatarURLFromEmail(''),
|
||||
config: {
|
||||
allowGuestSearching: meta.config.allowGuestSearching
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ SocketModules.chats.send = function(socket, data, callback) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
var touid = data.touid;
|
||||
var touid = parseInt(data.touid, 10);
|
||||
if (touid === socket.uid || socket.uid === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ var async = require('async'),
|
||||
|
||||
SocketPosts = {};
|
||||
|
||||
|
||||
|
||||
SocketPosts.reply = function(socket, data, callback) {
|
||||
|
||||
if (!socket.uid && !parseInt(meta.config.allowGuestPosting, 10)) {
|
||||
@@ -26,6 +28,7 @@ SocketPosts.reply = function(socket, data, callback) {
|
||||
}
|
||||
|
||||
data.uid = socket.uid;
|
||||
data.req = websockets.reqFromSocket(socket);
|
||||
|
||||
topics.reply(data, function(err, postData) {
|
||||
if(err) {
|
||||
|
||||
@@ -5,7 +5,7 @@ var topics = require('../topics'),
|
||||
categories = require('../categories'),
|
||||
threadTools = require('../threadTools'),
|
||||
categoryTools = require('../categoryTools'),
|
||||
index = require('./index'),
|
||||
websockets = require('./index'),
|
||||
user = require('../user'),
|
||||
db = require('./../database'),
|
||||
meta = require('./../meta'),
|
||||
@@ -25,26 +25,33 @@ SocketTopics.post = function(socket, data, callback) {
|
||||
return callback(new Error('[[error:not-logged-in]]'));
|
||||
}
|
||||
|
||||
topics.post({uid: socket.uid, title: data.title, content: data.content, cid: data.category_id, thumb: data.topic_thumb}, function(err, result) {
|
||||
topics.post({
|
||||
uid: socket.uid,
|
||||
title: data.title,
|
||||
content: data.content,
|
||||
cid: data.category_id,
|
||||
thumb: data.topic_thumb,
|
||||
req: websockets.reqFromSocket(socket)
|
||||
}, function(err, result) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
|
||||
index.server.sockets.in('category_' + data.category_id).emit('event:new_topic', result.topicData);
|
||||
index.server.sockets.in('recent_posts').emit('event:new_topic', result.topicData);
|
||||
index.server.sockets.in('home').emit('event:new_topic', result.topicData);
|
||||
index.server.sockets.in('home').emit('event:new_post', {
|
||||
websockets.server.sockets.in('category_' + data.category_id).emit('event:new_topic', result.topicData);
|
||||
websockets.server.sockets.in('recent_posts').emit('event:new_topic', result.topicData);
|
||||
websockets.server.sockets.in('home').emit('event:new_topic', result.topicData);
|
||||
websockets.server.sockets.in('home').emit('event:new_post', {
|
||||
posts: result.postData
|
||||
});
|
||||
index.server.sockets.in('user/' + socket.uid).emit('event:new_post', {
|
||||
websockets.server.sockets.in('user/' + socket.uid).emit('event:new_post', {
|
||||
posts: result.postData
|
||||
});
|
||||
|
||||
module.parent.exports.emitTopicPostStats();
|
||||
|
||||
callback();
|
||||
callback(null, result.topicData);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -253,11 +260,11 @@ SocketTopics.move = function(socket, data, callback) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
index.server.sockets.in('topic_' + tid).emit('event:topic_moved', {
|
||||
websockets.server.sockets.in('topic_' + tid).emit('event:topic_moved', {
|
||||
tid: tid
|
||||
});
|
||||
|
||||
index.server.sockets.in('category_' + oldCid).emit('event:topic_moved', {
|
||||
websockets.server.sockets.in('category_' + oldCid).emit('event:topic_moved', {
|
||||
tid: tid
|
||||
});
|
||||
|
||||
@@ -300,7 +307,7 @@ SocketTopics.moveAll = function(socket, data, callback) {
|
||||
};
|
||||
|
||||
SocketTopics.followCheck = function(socket, tid, callback) {
|
||||
threadTools.isFollowing(tid, socket.uid, callback);
|
||||
topics.isFollowing(tid, socket.uid, callback);
|
||||
};
|
||||
|
||||
SocketTopics.follow = function(socket, tid, callback) {
|
||||
|
||||
@@ -74,6 +74,12 @@ 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);
|
||||
}
|
||||
@@ -86,15 +92,8 @@ var winston = require('winston'),
|
||||
|
||||
websockets.emitTopicPostStats();
|
||||
|
||||
websockets.in('topic_' + tid).emit(isDelete ? 'event:topic_deleted' : 'event:topic_restored', {
|
||||
tid: tid,
|
||||
isDelete: isDelete
|
||||
});
|
||||
|
||||
websockets.in('category_' + topicData.cid).emit(isDelete ? 'event:topic_deleted' : 'event:topic_restored', {
|
||||
tid: tid,
|
||||
isDelete: isDelete
|
||||
});
|
||||
emitTo('topic_' + tid);
|
||||
emitTo('category_' + topicData.cid);
|
||||
|
||||
callback(null, {
|
||||
tid: tid
|
||||
@@ -113,21 +112,21 @@ var winston = require('winston'),
|
||||
|
||||
function toggleLock(tid, uid, lock, callback) {
|
||||
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) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
topics.setTopicField(tid, 'locked', lock ? 1 : 0);
|
||||
|
||||
websockets.in('topic_' + tid).emit(lock ? 'event:topic_locked' : 'event:topic_unlocked', {
|
||||
tid: tid,
|
||||
isLocked: lock
|
||||
});
|
||||
|
||||
websockets.in('category_' + cid).emit(lock ? 'event:topic_locked' : 'event:topic_unlocked', {
|
||||
tid: tid,
|
||||
isLocked: lock
|
||||
});
|
||||
emitTo('topic_' + tid);
|
||||
emitTo('category_' + cid);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(null, {
|
||||
@@ -148,6 +147,13 @@ var winston = require('winston'),
|
||||
|
||||
function togglePin(tid, uid, pin, callback) {
|
||||
topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||
function emitTo(room) {
|
||||
websockets.in(room).emit(pin ? 'event:topic_pinned' : 'event:topic_unpinned', {
|
||||
tid: tid,
|
||||
isPinned: pin
|
||||
});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
@@ -157,15 +163,8 @@ var winston = require('winston'),
|
||||
db.sortedSetAdd('categories:' + topicData.cid + ':tid', pin ? Math.pow(2, 53) : topicData.lastposttime, tid);
|
||||
});
|
||||
|
||||
websockets.in('topic_' + tid).emit(pin ? 'event:topic_pinned' : 'event:topic_unpinned', {
|
||||
tid: tid,
|
||||
isPinned: pin
|
||||
});
|
||||
|
||||
websockets.in('category_' + cid).emit(pin ? 'event:topic_pinned' : 'event:topic_unpinned', {
|
||||
tid: tid,
|
||||
isPinned: pin
|
||||
});
|
||||
emitTo('topic_' + tid);
|
||||
emitTo('category_' + cid);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(null, {
|
||||
@@ -201,25 +200,21 @@ var winston = require('winston'),
|
||||
categories.incrementCategoryFieldBy(cid, 'topic_count', 1);
|
||||
}
|
||||
|
||||
categories.moveActiveUsers(tid, oldCid, cid);
|
||||
|
||||
categories.moveRecentReplies(tid, oldCid, cid);
|
||||
|
||||
topics.setTopicField(tid, 'cid', cid, callback);
|
||||
});
|
||||
};
|
||||
|
||||
ThreadTools.isFollowing = function(tid, uid, callback) {
|
||||
db.isSetMember('tid:' + tid + ':followers', uid, callback);
|
||||
};
|
||||
|
||||
|
||||
ThreadTools.toggleFollow = function(tid, uid, callback) {
|
||||
ThreadTools.isFollowing(tid, uid, function(err, following) {
|
||||
topics.isFollowing(tid, uid, function(err, following) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db[following?'setRemove':'setAdd']('tid:' + tid + ':followers', uid, function(err, success) {
|
||||
db[following ? 'setRemove' : 'setAdd']('tid:' + tid + ':followers', uid, function(err, success) {
|
||||
if (callback) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
@@ -231,97 +226,4 @@ var winston = require('winston'),
|
||||
});
|
||||
};
|
||||
|
||||
ThreadTools.getFollowers = function(tid, callback) {
|
||||
db.getSetMembers('tid:' + tid + ':followers', function(err, followers) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if(followers) {
|
||||
followers = followers.map(function(follower) {
|
||||
return parseInt(follower, 10);
|
||||
});
|
||||
}
|
||||
callback(null, followers);
|
||||
});
|
||||
};
|
||||
|
||||
ThreadTools.notifyFollowers = function(tid, pid, exceptUid) {
|
||||
async.parallel([
|
||||
function(next) {
|
||||
topics.getTopicFields(tid, ['title', 'slug'], function(err, topicData) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
user.getUserField(exceptUid, 'username', function(err, username) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
notifications.create({
|
||||
text: '[[notifications:user_posted_to, ' + username + ', ' + topicData.title + ']]',
|
||||
path: nconf.get('relative_path') + '/topic/' + topicData.slug + '#' + pid,
|
||||
uniqueId: 'topic:' + tid,
|
||||
from: exceptUid
|
||||
}, function(nid) {
|
||||
next(null, nid);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
ThreadTools.getFollowers(tid, function(err, followers) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
exceptUid = parseInt(exceptUid, 10);
|
||||
if (followers.indexOf(exceptUid) !== -1) {
|
||||
followers.splice(followers.indexOf(exceptUid), 1);
|
||||
}
|
||||
|
||||
next(null, followers);
|
||||
});
|
||||
}
|
||||
], function(err, results) {
|
||||
if (!err && results[1].length) {
|
||||
notifications.push(results[0], results[1]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ThreadTools.getLatestUndeletedPost = function(tid, callback) {
|
||||
ThreadTools.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
posts.getPostData(pid, callback);
|
||||
});
|
||||
};
|
||||
|
||||
ThreadTools.getLatestUndeletedPid = function(tid, callback) {
|
||||
db.getSortedSetRevRange('tid:' + tid + ':posts', 0, -1, function(err, pids) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!pids.length) {
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
async.detectSeries(pids, function(pid, next) {
|
||||
posts.getPostField(pid, 'deleted', function(err, deleted) {
|
||||
next(parseInt(deleted, 10) === 0);
|
||||
});
|
||||
}, function(pid) {
|
||||
if (pid) {
|
||||
callback(null, pid);
|
||||
} else {
|
||||
callback(null, null);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
}(exports));
|
||||
|
||||
@@ -20,6 +20,7 @@ var async = require('async'),
|
||||
require('./topics/recent')(Topics);
|
||||
require('./topics/fork')(Topics);
|
||||
require('./topics/posts')(Topics);
|
||||
require('./topics/follow')(Topics);
|
||||
|
||||
|
||||
Topics.getTopicData = function(tid, callback) {
|
||||
@@ -304,7 +305,7 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
Topics.getTeaser = function(tid, callback) {
|
||||
threadTools.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
Topics.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,16 @@ module.exports = function(Topics) {
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
plugins.fireHook('filter:topic.post', data, function(err, filteredData) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
content = filteredData.content || data.content;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
categoryTools.exists(cid, next);
|
||||
},
|
||||
@@ -105,7 +115,7 @@ module.exports = function(Topics) {
|
||||
Topics.create({uid: uid, title: title, cid: cid, thumb: thumb}, next);
|
||||
},
|
||||
function(tid, next) {
|
||||
Topics.reply({uid:uid, tid:tid, content:content}, next);
|
||||
Topics.reply({uid:uid, tid:tid, content:content, req: data.req}, next);
|
||||
},
|
||||
function(postData, next) {
|
||||
threadTools.toggleFollow(postData.tid, uid);
|
||||
@@ -140,6 +150,16 @@ module.exports = function(Topics) {
|
||||
postData;
|
||||
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
plugins.fireHook('filter:topic.reply', data, function(err, filteredData) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
content = filteredData.content || data.content;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
threadTools.exists(tid, next);
|
||||
},
|
||||
@@ -180,7 +200,8 @@ module.exports = function(Topics) {
|
||||
},
|
||||
function(data, next) {
|
||||
postData = data;
|
||||
threadTools.notifyFollowers(tid, postData.pid, uid);
|
||||
|
||||
Topics.notifyFollowers(tid, postData.pid, uid);
|
||||
|
||||
user.notifications.sendPostNotificationToFollowers(uid, tid, postData.pid);
|
||||
|
||||
|
||||
62
src/topics/follow.js
Normal file
62
src/topics/follow.js
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var async = require('async'),
|
||||
nconf = require('nconf'),
|
||||
|
||||
db = require('../database'),
|
||||
user = require('../user'),
|
||||
notifications = require('../notifications');
|
||||
|
||||
module.exports = function(Topics) {
|
||||
|
||||
|
||||
Topics.isFollowing = function(tid, uid, callback) {
|
||||
db.isSetMember('tid:' + tid + ':followers', uid, callback);
|
||||
};
|
||||
|
||||
Topics.getFollowers = function(tid, callback) {
|
||||
db.getSetMembers('tid:' + tid + ':followers', callback);
|
||||
};
|
||||
|
||||
Topics.notifyFollowers = function(tid, pid, exceptUid) {
|
||||
async.parallel({
|
||||
nid: function(next) {
|
||||
Topics.getTopicFields(tid, ['title', 'slug'], function(err, topicData) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
user.getUserField(exceptUid, 'username', function(err, username) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
notifications.create({
|
||||
text: '[[notifications:user_posted_to, ' + username + ', ' + topicData.title + ']]',
|
||||
path: nconf.get('relative_path') + '/topic/' + topicData.slug + '#' + pid,
|
||||
uniqueId: 'topic:' + tid,
|
||||
from: exceptUid
|
||||
}, function(nid) {
|
||||
next(null, nid);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
followers: function(next) {
|
||||
Topics.getFollowers(tid, next);
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (!err && results.followers.length) {
|
||||
|
||||
var index = results.followers.indexOf(exceptUid.toString());
|
||||
if (index !== -1) {
|
||||
results.followers.splice(index, 1);
|
||||
}
|
||||
|
||||
notifications.push(results.nid, results.followers);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
@@ -68,6 +68,7 @@ module.exports = function(Topics) {
|
||||
postData[i].votes = postData[i].votes || 0;
|
||||
postData[i].display_moderator_tools = parseInt(uid, 10) !== 0 && results.privileges[i].editable;
|
||||
postData[i].display_move_tools = results.privileges[i].move;
|
||||
postData[i].selfPost = parseInt(uid, 10) === parseInt(postData[i].uid, 10);
|
||||
|
||||
if(postData[i].deleted && !results.privileges[i].view_deleted) {
|
||||
postData[i].content = '[[topic:post_is_deleted]]';
|
||||
@@ -79,6 +80,36 @@ module.exports = function(Topics) {
|
||||
});
|
||||
};
|
||||
|
||||
Topics.getLatestUndeletedPost = function(tid, callback) {
|
||||
Topics.getLatestUndeletedPid(tid, function(err, pid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
posts.getPostData(pid, callback);
|
||||
});
|
||||
};
|
||||
|
||||
Topics.getLatestUndeletedPid = function(tid, callback) {
|
||||
db.getSortedSetRevRange('tid:' + tid + ':posts', 0, -1, function(err, pids) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!pids || !pids.length) {
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
async.detectSeries(pids, function(pid, next) {
|
||||
posts.getPostField(pid, 'deleted', function(err, deleted) {
|
||||
next(parseInt(deleted, 10) === 0);
|
||||
});
|
||||
}, function(pid) {
|
||||
callback(null, pid ? pid : null);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Topics.addPostToTopic = function(tid, pid, timestamp, callback) {
|
||||
db.sortedSetAdd('tid:' + tid + ':posts', timestamp, pid, callback);
|
||||
};
|
||||
|
||||
23
src/user.js
23
src/user.js
@@ -210,15 +210,15 @@ var bcrypt = require('bcryptjs'),
|
||||
};
|
||||
|
||||
User.createGravatarURLFromEmail = function(email) {
|
||||
|
||||
var options = {
|
||||
size: '128',
|
||||
default: 'identicon',
|
||||
default: meta.config.customGravatarDefaultImage || meta.config.defaultGravatarImage || '',
|
||||
rating: 'pg'
|
||||
};
|
||||
|
||||
if (!email) {
|
||||
email = '';
|
||||
options.forcedefault = 'y';
|
||||
}
|
||||
|
||||
return gravatar.url(email, options, true);
|
||||
@@ -294,7 +294,7 @@ var bcrypt = require('bcryptjs'),
|
||||
callback(null, {
|
||||
username: data.username || '[[global:guest]]',
|
||||
userslug: data.userslug || '',
|
||||
picture: data.picture || gravatar.url('', {}, true)
|
||||
picture: data.picture || User.createGravatarURLFromEmail('')
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -354,25 +354,24 @@ var bcrypt = require('bcryptjs'),
|
||||
};
|
||||
|
||||
User.isOnline = function(uid, callback) {
|
||||
User.getUserField(uid, 'status', function(err, status) {
|
||||
User.getUserFields(uid, ['username', 'userslug', 'picture', 'status'] , function(err, data) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var online = require('./socket.io').isUserOnline(uid);
|
||||
|
||||
status = online ? (status || 'online') : 'offline';
|
||||
data.status = online ? (data.status || 'online') : 'offline';
|
||||
|
||||
if(status === 'offline') {
|
||||
if(data.status === 'offline') {
|
||||
online = false;
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
online: online,
|
||||
uid: uid,
|
||||
timestamp: Date.now(),
|
||||
status: status
|
||||
});
|
||||
data.online = online;
|
||||
data.uid = uid;
|
||||
data.timestamp = Date.now();
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -266,9 +266,6 @@ module.exports = function(User) {
|
||||
function(next) {
|
||||
db.delete('uid:' + uid + ':downvote', next);
|
||||
},
|
||||
function(next) {
|
||||
deleteUserFromCategoryActiveUsers(uid, next);
|
||||
},
|
||||
function(next) {
|
||||
deleteUserFromFollowers(uid, next);
|
||||
},
|
||||
@@ -298,18 +295,6 @@ module.exports = function(User) {
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUserFromCategoryActiveUsers(uid, callback) {
|
||||
db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.each(cids, function(cid, next) {
|
||||
categories.removeActiveUser(cid, uid, next);
|
||||
}, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUserFromFollowers(uid, callback) {
|
||||
db.getSetMembers('followers:' + uid, function(err, uids) {
|
||||
if (err) {
|
||||
|
||||
Reference in New Issue
Block a user