diff --git a/.eslintrc b/.eslintrc
index 52211a126d..bbba3aa94e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -32,6 +32,7 @@
"no-prototype-builtins": "off",
"new-cap": "off",
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
+ "import/no-unresolved": "error",
// ES6
"prefer-rest-params": "off",
@@ -43,7 +44,6 @@
"vars-on-top": "off",
// TODO
- "import/no-unresolved": "off",
"import/no-extraneous-dependencies": "off",
"import/no-dynamic-require": "off",
"import/newline-after-import": "off",
diff --git a/app.js b/app.js
index de9d417045..5a6a782c57 100644
--- a/app.js
+++ b/app.js
@@ -19,6 +19,12 @@
'use strict';
+if (require.main !== module) {
+ require.main.require = function (path) {
+ return require(path);
+ };
+}
+
var nconf = require('nconf');
nconf.argv().env('__');
diff --git a/loader.js b/loader.js
index 654d77fb23..214f785eb9 100644
--- a/loader.js
+++ b/loader.js
@@ -7,6 +7,7 @@ var path = require('path');
var fork = require('child_process').fork;
var async = require('async');
var logrotate = require('logrotate-stream');
+
var file = require('./src/file');
var pkg = require('./package.json');
@@ -23,6 +24,7 @@ var workers = [];
var Loader = {
timesStarted: 0,
};
+var appPath = path.join(__dirname, 'app.js');
Loader.init = function (callback) {
if (silent) {
@@ -114,7 +116,7 @@ function forkWorker(index, isPrimary) {
process.env.isCluster = ports.length > 1;
process.env.port = ports[index];
- var worker = fork('app.js', args, {
+ var worker = fork(appPath, args, {
silent: silent,
env: process.env,
});
diff --git a/nodebb b/nodebb
index ee87b24288..757afabf40 100755
--- a/nodebb
+++ b/nodebb
@@ -2,16 +2,25 @@
'use strict';
+var cproc;
+var args;
+var fs;
+var path;
+var request;
+var semver;
+var prompt;
+var async;
+
try {
require('colors');
- var cproc = require('child_process');
- var args = require('minimist')(process.argv.slice(2));
- var fs = require('fs');
- var path = require('path');
- var request = require('request');
- var semver = require('semver');
- var prompt = require('prompt');
- var async = require('async');
+ cproc = require('child_process');
+ args = require('minimist')(process.argv.slice(2));
+ fs = require('fs');
+ path = require('path');
+ request = require('request');
+ semver = require('semver');
+ prompt = require('prompt');
+ async = require('async');
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
process.stdout.write('NodeBB could not be started because it\'s dependencies have not been installed.\n');
@@ -23,13 +32,16 @@ try {
}
}
+var loaderPath = path.join(__dirname, 'loader.js');
+var appPath = path.join(__dirname, 'app.js');
+
if (args.dev) {
process.env.NODE_ENV = 'development';
}
function getRunningPid(callback) {
- fs.readFile(__dirname + '/pidfile', {
- encoding: 'utf-8'
+ fs.readFile(path.join(__dirname, 'pidfile'), {
+ encoding: 'utf-8',
}, function (err, pid) {
if (err) {
return callback(err);
@@ -38,7 +50,7 @@ function getRunningPid(callback) {
try {
process.kill(parseInt(pid, 10), 0);
callback(null, parseInt(pid, 10));
- } catch(e) {
+ } catch (e) {
callback(e);
}
});
@@ -52,28 +64,29 @@ function getCurrentVersion(callback) {
try {
pkg = JSON.parse(pkg);
return callback(null, pkg.version);
- } catch(err) {
+ } catch (err) {
return callback(err);
}
});
}
function fork(args) {
- return cproc.fork('app.js', args, {
+ return cproc.fork(appPath, args, {
cwd: __dirname,
- silent: false
+ silent: false,
});
}
function getInstalledPlugins(callback) {
async.parallel({
files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')),
- deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' })
+ deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' }),
}, function (err, payload) {
if (err) {
return callback(err);
}
- var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w\-]+$/,
- moduleName, isGitRepo;
+ var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/;
+ var moduleName;
+ var isGitRepo;
payload.files = payload.files.filter(function (file) {
return isNbbModule.test(file);
@@ -98,7 +111,7 @@ function getInstalledPlugins(callback) {
try {
fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git'));
isGitRepo = true;
- } catch(e) {
+ } catch (e) {
isGitRepo = false;
}
@@ -144,7 +157,7 @@ function checkPlugins(standalone, callback) {
async.waterfall([
async.apply(async.parallel, {
plugins: async.apply(getInstalledPlugins),
- version: async.apply(getCurrentVersion)
+ version: async.apply(getCurrentVersion),
}),
function (payload, next) {
var toCheck = Object.keys(payload.plugins);
@@ -157,7 +170,7 @@ function checkPlugins(standalone, callback) {
request({
method: 'GET',
url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='),
- json: true
+ json: true,
}, function (err, res, body) {
if (err) {
process.stdout.write('error'.red + '\n'.reset);
@@ -169,25 +182,25 @@ function checkPlugins(standalone, callback) {
body = [body];
}
- var current, suggested,
- upgradable = body.map(function (suggestObj) {
- current = payload.plugins[suggestObj.package];
- suggested = suggestObj.version;
-
- if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
- return {
- name: suggestObj.package,
- current: current,
- suggested: suggested
- };
- } else {
- return null;
- }
- }).filter(Boolean);
+ var current;
+ var suggested;
+ var upgradable = body.map(function (suggestObj) {
+ current = payload.plugins[suggestObj.package];
+ suggested = suggestObj.version;
+
+ if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
+ return {
+ name: suggestObj.package,
+ current: current,
+ suggested: suggested,
+ };
+ }
+ return null;
+ }).filter(Boolean);
next(null, upgradable);
});
- }
+ },
], callback);
}
function upgradePlugins(callback) {
@@ -199,7 +212,7 @@ function upgradePlugins(callback) {
checkPlugins(standalone, function (err, found) {
if (err) {
- process.stdout.write('\Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
+ process.stdout.write('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
return callback(err);
}
@@ -223,7 +236,7 @@ function upgradePlugins(callback) {
prompt.get({
name: 'upgrade',
description: 'Proceed with upgrade (y|n)?'.reset,
- type: 'string'
+ type: 'string',
}, function (err, result) {
if (err) {
return callback(err);
@@ -279,8 +292,8 @@ var commands = {
process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset);
// Spawn a new NodeBB process
- cproc.fork(__dirname + '/loader.js', {
- env: process.env
+ cproc.fork(loaderPath, {
+ env: process.env,
});
},
},
@@ -320,7 +333,7 @@ var commands = {
process.stdout.write('\n\n'.reset);
cproc.spawn('tail', ['-F', './logs/output.log'], {
cwd: __dirname,
- stdio: 'inherit'
+ stdio: 'inherit',
});
},
},
@@ -333,12 +346,12 @@ var commands = {
process.stdout.write('\n\n'.reset);
// Spawn a new NodeBB process
- cproc.fork(__dirname + '/loader.js', {
- env: process.env
+ cproc.fork(loaderPath, {
+ env: process.env,
});
cproc.spawn('tail', ['-F', './logs/output.log'], {
cwd: __dirname,
- stdio: 'inherit'
+ stdio: 'inherit',
});
},
},
@@ -347,14 +360,14 @@ var commands = {
usage: 'Usage: ' + './nodebb dev'.yellow,
handler: function () {
process.env.NODE_ENV = 'development';
- cproc.fork(__dirname + '/loader.js', ['--no-daemon', '--no-silent'], {
- env: process.env
+ cproc.fork(loaderPath, ['--no-daemon', '--no-silent'], {
+ env: process.env,
});
},
},
build: {
description: 'Compile static assets (CSS, Javascript, etc)',
- usage: 'Usage: ' + './nodebb build'.yellow + ' [js,clientCSS,acpCSS,tpl,lang]'.red + '\n' +
+ usage: 'Usage: ' + './nodebb build'.yellow + ' [js,clientCSS,acpCSS,tpl,lang]'.red + '\n' +
' e.g. ' + './nodebb build js,tpl'.yellow + '\tbuilds JS and templates\n' +
' ' + './nodebb build'.yellow + '\t\tbuilds all targets\n',
handler: function () {
@@ -422,7 +435,7 @@ var commands = {
var upgradeProc = fork(arr);
upgradeProc.on('close', next);
- }
+ },
], function (err) {
if (err) {
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
@@ -430,7 +443,7 @@ var commands = {
var message = 'NodeBB Upgrade Complete!';
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
var columns = process.stdout.columns;
- var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : " ";
+ var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
process.stdout.write('OK\n'.green);
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
diff --git a/package.json b/package.json
index 828165182b..3c0bbb20d5 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"main": "app.js",
"scripts": {
"start": "node loader.js",
- "lint": "eslint --cache .",
+ "lint": "eslint --cache ./nodebb .",
"pretest": "npm run lint",
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
diff --git a/public/language/hu/global.json b/public/language/hu/global.json
index ea60f7dd9b..c05367f938 100644
--- a/public/language/hu/global.json
+++ b/public/language/hu/global.json
@@ -61,7 +61,7 @@
"reputation": "Hírnév",
"read_more": "tovább olvas",
"more": "Több",
- "posted_ago_by_guest": "Vendég hozzászólás %1",
+ "posted_ago_by_guest": "%1 vendég hozzászólás",
"posted_ago_by": "%2 hozzászólás %1",
"posted_ago": "%1 hozzászólás",
"posted_in": "hozzászólt itt: %1",
@@ -103,5 +103,5 @@
"cookies.message": "A weboldal sütiket használ, a legjobb weboldalas élmény érdekében.",
"cookies.accept": "Értem!",
"cookies.learn_more": "Tudnivalók",
- "edited": "Edited"
+ "edited": "Szerkesztett"
}
\ No newline at end of file
diff --git a/public/language/hu/recent.json b/public/language/hu/recent.json
index bddd57893f..95004a40a6 100644
--- a/public/language/hu/recent.json
+++ b/public/language/hu/recent.json
@@ -4,7 +4,7 @@
"week": "Hét",
"month": "Hónap",
"year": "Év",
- "alltime": "Minden idők",
+ "alltime": "Bármikor",
"no_recent_topics": "Nincs friss témakör.",
"no_popular_topics": "Nincs népszerű témakör.",
"there-is-a-new-topic": "Van egy új témakör.",
diff --git a/public/language/nl/global.json b/public/language/nl/global.json
index 73eb607f24..f18dccae8d 100644
--- a/public/language/nl/global.json
+++ b/public/language/nl/global.json
@@ -103,5 +103,5 @@
"cookies.message": "Deze website gebruikt cookies om je ervan te verzekeren dat je de beste ervaring krijgt tijdens het gebruik van onze website.",
"cookies.accept": "Begrepen",
"cookies.learn_more": "Meer",
- "edited": "Edited"
+ "edited": "Bewerkt"
}
\ No newline at end of file
diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json
index 912765ec55..0cf86d03a7 100644
--- a/public/language/nl/groups.json
+++ b/public/language/nl/groups.json
@@ -27,7 +27,7 @@
"details.disableJoinRequests": "Groepsverzoeken uitschakelen",
"details.grant": "Toekennen/herroepen van eigendom",
"details.kick": "Kick",
- "details.kick_confirm": "Are you sure you want to remove this member from the group?",
+ "details.kick_confirm": "Weet u zeker dat u de gebruiker wilt verwijderen uit de groep?",
"details.owner_options": "Groepsadministratie",
"details.group_name": "Groepsnaam",
"details.member_count": "Ledentelling",
@@ -54,5 +54,5 @@
"upload-group-cover": "Upload groepscover",
"bulk-invite-instructions": "Vul een lijst is met gebruikersnamen gescheiden met komma's om deze uit te nodigen voor deze groep",
"bulk-invite": "Massa uitnodiging",
- "remove_group_cover_confirm": "Are you sure you want to remove the cover picture?"
+ "remove_group_cover_confirm": "Weet u zeker dat u de cover foto wilt verwijderen?"
}
\ No newline at end of file
diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json
index 34c8925ae7..59d0396464 100644
--- a/public/language/nl/modules.json
+++ b/public/language/nl/modules.json
@@ -13,7 +13,7 @@
"chat.contacts": "Contacten",
"chat.message-history": "Berichtengeschiedenis",
"chat.pop-out": "Chatvenster opbrengen bij chat",
- "chat.minimize": "Minimize",
+ "chat.minimize": "Verkleinen",
"chat.maximize": "Maximaliseren",
"chat.seven_days": "7 dagen",
"chat.thirty_days": "30 dagen",
diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json
index a15226841a..29b4234fb7 100644
--- a/public/language/nl/notifications.json
+++ b/public/language/nl/notifications.json
@@ -10,14 +10,14 @@
"return_to": "Terug naar %1",
"new_notification": "Nieuwe notificatie",
"you_have_unread_notifications": "Je hebt nieuwe notificaties.",
- "all": "All",
- "topics": "Topics",
- "replies": "Replies",
+ "all": "Alles",
+ "topics": "Onderwerpen",
+ "replies": "Antwoorden",
"chat": "Chats",
- "follows": "Follows",
+ "follows": "Volgt",
"upvote": "Upvotes",
- "new-flags": "New Flags",
- "my-flags": "Flags assigned to me",
+ "new-flags": "Nieuwe markeringen",
+ "my-flags": "Markeringen toegewezen aan mij",
"bans": "Bans",
"new_message_from": "Nieuw bericht van %1",
"upvoted_your_post_in": "%1 heeft voor een bericht gestemd in %2.",
@@ -28,9 +28,9 @@
"user_flagged_post_in": "%1 rapporteerde een bericht in %2",
"user_flagged_post_in_dual": "%1 en %2 rapporteerde een bericht in %3",
"user_flagged_post_in_multiple": "%1 en %2 andere rapporteede een bericht in %3",
- "user_flagged_user": "%1 flagged a user profile (%2)",
- "user_flagged_user_dual": "%1 and %2 flagged a user profile (%3)",
- "user_flagged_user_multiple": "%1 and %2 others flagged a user profile (%3)",
+ "user_flagged_user": "%1 markeerde een gebruikersprofiel (%2)",
+ "user_flagged_user_dual": "%1 en %2 markeerden een gebruikersprofiel (%3)",
+ "user_flagged_user_multiple": "%1 en %2 anderen markeerde een gebruikersprofiel (%3)",
"user_posted_to": "%1 heeft een reactie geplaatst in %2",
"user_posted_to_dual": "%1 en %2 hebben een reactie geplaatst in: %3",
"user_posted_to_multiple": "%1 en %2 hebben een reactie geplaatst in: %3",
@@ -40,7 +40,7 @@
"user_started_following_you_multiple": "%1 en %2 andere volgen jou nu.",
"new_register": "%1 heeft een registratie verzoek aangevraagd.",
"new_register_multiple": "Er is/zijn %1 registratieverzoek(en) die wacht(en) op goedkeuring.",
- "flag_assigned_to_you": "Flag %1 has been assigned to you",
+ "flag_assigned_to_you": "Flag %1 is aan u toegewezen",
"email-confirmed": "E-mailadres bevestigd",
"email-confirmed-message": "Bedankt voor het bevestigen van je e-mailadres. Je account is nu volledig geactiveerd.",
"email-confirm-error-message": "Er was een probleem met het bevestigen van dit e-mailadres. Misschien is de code niet goed ingevoerd of was de beschikbare tijd inmiddels verstreken.",
diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json
index 816f62be22..64441b8b54 100644
--- a/public/language/nl/pages.json
+++ b/public/language/nl/pages.json
@@ -6,7 +6,7 @@
"popular-month": "De populaire onderwerpen van deze maand",
"popular-alltime": "De populaire onderwerpen",
"recent": "Recente onderwerpen",
- "flagged-content": "Flagged Content",
+ "flagged-content": "Gemarkeerde content",
"ip-blacklist": "IP zwarte lijst",
"users/online": "Online Gebruikers",
"users/latest": "Meest recente gebruikers",
@@ -27,7 +27,7 @@
"group": "%1's groep",
"chats": "Chats",
"chat": "Chatten met %1",
- "flags": "Flags",
+ "flags": "Markeringen",
"flag-details": "Flag %1 Details",
"account/edit": "\"%1\" aanpassen",
"account/edit/password": "Wachtwoord van \"%1\" aanpassen",
diff --git a/public/language/zh-CN/admin/manage/categories.json b/public/language/zh-CN/admin/manage/categories.json
index b535e4f0b8..77aa93ec68 100644
--- a/public/language/zh-CN/admin/manage/categories.json
+++ b/public/language/zh-CN/admin/manage/categories.json
@@ -12,55 +12,55 @@
"ext-link": "外部链接",
"upload-image": "上传图片",
"delete-image": "移除",
- "category-image": "板块图片",
- "parent-category": "父板块",
- "optional-parent-category": "(可选)父板块",
+ "category-image": "版块图片",
+ "parent-category": "父版块",
+ "optional-parent-category": "(可选)父版块",
"parent-category-none": "(无)",
"copy-settings": "复制设置",
- "optional-clone-settings": "(可选) 从板块复制设置",
- "purge": "删除板块",
+ "optional-clone-settings": "(可选) 从版块复制设置",
+ "purge": "删除版块",
"enable": "启用",
"disable": "禁用",
"edit": "编辑",
- "select-category": "选择板块",
- "set-parent-category": "设置父板块",
+ "select-category": "选择版块",
+ "set-parent-category": "设置父版块",
- "privileges.description": "您可以在此部分中配置此板块的访问控制权限。 可以根据每个用户或每个组授予权限。 您可以通过在下面的表格中搜索,将新用户添加到此表中。",
+ "privileges.description": "您可以在此部分中配置此版块的访问控制权限。 可以根据每个用户或每个组授予权限。 您可以通过在下面的表格中搜索,将新用户添加到此表中。",
"privileges.warning": "注意:权限设置会立即生效。 调整这些设置后,无需保存。",
"privileges.section-viewing": "查看权限",
"privileges.section-posting": "发帖权限",
"privileges.section-moderation": "审核权限",
"privileges.section-user": "用户",
"privileges.search-user": "添加用户",
- "privileges.no-users": "此板块中没有用户特定的权限。",
+ "privileges.no-users": "此版块中没有用户特定的权限。",
"privileges.section-group": "群组",
"privileges.group-private": "这个群组是私密的",
"privileges.search-group": "添加群组",
"privileges.copy-to-children": "复制到子版块",
- "privileges.copy-from-category": "从板块复制",
+ "privileges.copy-from-category": "从版块复制",
"privileges.inherit": "如果 registered-users
组被授予特定权限,所有其他组都会收到隐式权限,即使它们未被明确定义/检查。 将显示此隐式权限,因为所有用户都是 registered-users
群组的一部分,因此无需显式授予其他组的权限。",
- "analytics.back": "返回板块列表",
- "analytics.title": "“%1”板块的统计",
- "analytics.pageviews-hourly": "图1 – 此板块的每小时页面浏览量",
- "analytics.pageviews-daily": "图2 – 此板块的每日页面浏览量",
- "analytics.topics-daily": "图3 – 每日在此板块中创建的主题",
- "analytics.posts-daily": "图4 – 每日在此板块中每日发布的帖子",
+ "analytics.back": "返回版块列表",
+ "analytics.title": "“%1”版块的统计",
+ "analytics.pageviews-hourly": "图1 – 此版块的每小时页面浏览量",
+ "analytics.pageviews-daily": "图2 – 此版块的每日页面浏览量",
+ "analytics.topics-daily": "图3 – 每日在此版块中创建的主题",
+ "analytics.posts-daily": "图4 – 每日在此版块中每日发布的帖子",
"alert.created": "创建",
- "alert.create-success": "板块创建成功!",
- "alert.none-active": "您没有有效的板块。",
- "alert.create": "创建一个板块",
+ "alert.create-success": "版块创建成功!",
+ "alert.none-active": "您没有有效的版块。",
+ "alert.create": "创建一个版块",
"alert.confirm-moderate": "您确定要将审核权限授予此群组吗?此群组是公开的,任何用户都可以随意加入。",
- "alert.confirm-purge": "
您确定要清除此板块“%1”吗?
警告! 板块将被清除!
清除板块将删除所有主题和帖子,并从数据库中删除板块。 如果您想暂时移除板块,请使用停用板块。
",
- "alert.purge-success": "板块已删除!",
+ "alert.confirm-purge": "您确定要清除此版块“%1”吗?
警告! 版块将被清除!
清除版块将删除所有主题和帖子,并从数据库中删除版块。 如果您想暂时移除版块,请使用停用版块。
",
+ "alert.purge-success": "版块已删除!",
"alert.copy-success": "设置已复制!",
- "alert.set-parent-category": "设置父板块",
- "alert.updated": "板块已更新",
- "alert.updated-success": "板块ID %1 成功更新。",
- "alert.upload-image": "上传板块图片",
+ "alert.set-parent-category": "设置父版块",
+ "alert.updated": "版块已更新",
+ "alert.updated-success": "版块ID %1 成功更新。",
+ "alert.upload-image": "上传版块图片",
"alert.find-user": "查找用户",
"alert.user-search": "在这里查找用户…",
"alert.find-group": "查找群组",
diff --git a/public/language/zh-CN/admin/settings/pagination.json b/public/language/zh-CN/admin/settings/pagination.json
index ec44dd3661..b4e16d4f7f 100644
--- a/public/language/zh-CN/admin/settings/pagination.json
+++ b/public/language/zh-CN/admin/settings/pagination.json
@@ -3,7 +3,7 @@
"enable": "在主题和帖子使用分页替代无限滚动浏览。",
"topics": "话题分页",
"posts-per-page": "每页帖子数",
- "categories": "板块分页",
+ "categories": "版块分页",
"topics-per-page": "每页主题数",
"initial-num-load": "最初加载未读,最新,热门的话题"
}
\ No newline at end of file
diff --git a/public/language/zh-CN/admin/settings/post.json b/public/language/zh-CN/admin/settings/post.json
index d2f36c5a83..857f72b98e 100644
--- a/public/language/zh-CN/admin/settings/post.json
+++ b/public/language/zh-CN/admin/settings/post.json
@@ -6,21 +6,21 @@
"sorting.most-votes": "最多投票",
"sorting.topic-default": "默认主题排序",
"restrictions": "发帖限制",
- "restrictions.seconds-between": "发帖间隔",
- "restrictions.seconds-between-new": "对于新用户的发帖间隔",
+ "restrictions.seconds-between": "发帖间隔(单位:秒)",
+ "restrictions.seconds-between-new": "对于新用户的发帖间隔(单位:秒)",
"restrictions.rep-threshold": "取消发帖限制所需的声望值",
- "restrictions.seconds-defore-new": "见习时间",
- "restrictions.seconds-edit-after": "用户在发布后允许编辑帖子的秒数。 (0为禁用) ",
- "restrictions.seconds-delete-after": "允许在发布后删除帖子的秒数。 (0为禁用) ",
+ "restrictions.seconds-defore-new": "见习时间(单位:秒)",
+ "restrictions.seconds-edit-after": "用户在发布后允许编辑帖子的时间(0为禁用,单位:秒)",
+ "restrictions.seconds-delete-after": "用户在发布后允许删除帖子的时间(0为禁用,单位:秒)",
"restrictions.replies-no-delete": "在用户被禁止删除自己的主题后的回复数。 (0为禁用) ",
"restrictions.min-title-length": "最小标题长度",
"restrictions.max-title-length": "最大标题长度",
"restrictions.min-post-length": "最小帖子长度",
"restrictions.max-post-length": "最大帖子长度",
- "restrictions.days-until-stale": "主题过期时间",
+ "restrictions.days-until-stale": "主题过期时间(单位:天)",
"restrictions.stale-help": "如果某个主题被视为“过时”,则会向尝试回复该主题的用户显示警告。",
"timestamp": "时间戳",
- "timestamp.cut-off": "日期截止日期 (天) ",
+ "timestamp.cut-off": "日期截止日期(单位:天)",
"timestamp.cut-off-help": "日期&时间将以相对方式 (例如,“3小时前” / “5天前”) 显示,并且会依照访客语言时区转换。在某一时刻之后,可以切换该文本以显示本地化日期本身 (例如2016年11月5日15:30) 。
(默认值: 30
或一个月) 。 设置为0可始终显示日期,留空以始终显示相对时间。",
"teaser": "预览帖子",
"teaser.last-post": "最后– 显示最新的帖子,包括原帖,如果没有回复",
diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json
index e38d6114ee..235ec2c80b 100644
--- a/public/language/zh-CN/modules.json
+++ b/public/language/zh-CN/modules.json
@@ -38,7 +38,7 @@
"composer.upload-picture": "上传图片",
"composer.upload-file": "上传文件",
"composer.zen_mode": "无干扰模式",
- "composer.select_category": "选择一个板块",
+ "composer.select_category": "选择一个版块",
"bootbox.ok": "确认",
"bootbox.cancel": "取消",
"bootbox.confirm": "确认",
diff --git a/public/language/zh-CN/search.json b/public/language/zh-CN/search.json
index 92ea7f452f..2d6b500297 100644
--- a/public/language/zh-CN/search.json
+++ b/public/language/zh-CN/search.json
@@ -6,8 +6,8 @@
"titles": "标题",
"titles-posts": "标题和回帖",
"posted-by": "发表",
- "in-categories": "在版面",
- "search-child-categories": "搜索子版面",
+ "in-categories": "在版块",
+ "search-child-categories": "搜索子版块",
"has-tags": "有标签",
"reply-count": "回复数",
"at-least": "至少",
diff --git a/public/language/zh-CN/topic.json b/public/language/zh-CN/topic.json
index cb7880b641..cbd70048ef 100644
--- a/public/language/zh-CN/topic.json
+++ b/public/language/zh-CN/topic.json
@@ -48,7 +48,7 @@
"not-watching": "未关注",
"ignoring": "忽略中",
"watching.description": "有新回复时通知我。
在未读主题中显示。",
- "not-watching.description": "不要在有新回复时通知我。
如果这个分类未被忽略则在未读主题中显示。",
+ "not-watching.description": "不要在有新回复时通知我。
如果这个版块未被忽略则在未读主题中显示。",
"ignoring.description": "不要在有新回复时通知我。
不要在未读主题中显示该主题。",
"thread_tools.title": "主题工具",
"thread_tools.markAsUnreadForAll": "标记全部未读",
@@ -70,8 +70,8 @@
"post_delete_confirm": "确定删除此帖吗?",
"post_restore_confirm": "确定恢复此帖吗?",
"post_purge_confirm": "确认清除此回帖吗?",
- "load_categories": "正在载入板块",
- "disabled_categories_note": "停用的板块为灰色",
+ "load_categories": "正在载入版块",
+ "disabled_categories_note": "停用的版块为灰色",
"confirm_move": "移动",
"confirm_fork": "分割",
"bookmark": "书签",
diff --git a/public/language/zh-CN/users.json b/public/language/zh-CN/users.json
index a6a2267467..bdc9eda8de 100644
--- a/public/language/zh-CN/users.json
+++ b/public/language/zh-CN/users.json
@@ -15,7 +15,7 @@
"recent_topics": "最新主题",
"popular_topics": "热门主题",
"unread_topics": "未读主题",
- "categories": "版面",
+ "categories": "版块",
"tags": "话题",
"no-users-found": "未找到匹配的用户!"
}
\ No newline at end of file
diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js
index ce49f222f5..eea3f7495b 100644
--- a/public/src/modules/translator.js
+++ b/public/src/modules/translator.js
@@ -97,6 +97,9 @@
// and the strings of untranslated text in between
var toTranslate = [];
+ // to store the state of if we're currently in a top-level token for later
+ var inToken = false;
+
// split a translator string into an array of tokens
// but don't split by commas inside other translator strings
function split(text) {
@@ -141,6 +144,8 @@
// set the last break to our current
// spot since we just broke the string
lastBreak = cursor;
+ // we're in a token now
+ inToken = true;
// the current level of nesting of the translation strings
var level = 0;
@@ -176,6 +181,8 @@
invalidTextRegex.test(sliced[0])) {
cursor += 1;
lastBreak -= 2;
+ // no longer in a token
+ inToken = false;
if (level > 0) {
level -= 1;
} else {
@@ -191,18 +198,26 @@
// if we're at the base level, then this is the end
if (level === 0) {
// so grab the name and args
- var result = split(str.slice(lastBreak, cursor));
+ var currentSlice = str.slice(lastBreak, cursor);
+ var result = split(currentSlice);
var name = result[0];
var args = result.slice(1);
+ // make a backup based on the raw string of the token
+ // if there are arguments to the token
+ var backup = '';
+ if (args && args.length) {
+ backup = this.translate('[[' + currentSlice + '[[');
+ }
// add the translation promise to the array
- toTranslate.push(this.translateKey(name, args));
+ toTranslate.push(this.translateKey(name, args, backup));
// skip past the ending brackets
cursor += 2;
// set this as our last break
lastBreak = cursor;
// and we're no longer in a translation string,
// so continue with the main loop
+ inToken = false;
break;
}
// otherwise we lower the level
@@ -219,8 +234,16 @@
cursor += 1;
}
+ // ending string of source
+ var last = str.slice(lastBreak);
+
+ // if we were mid-token, treat it as invalid
+ if (inToken) {
+ last = this.translate('[[' + last);
+ }
+
// add the remaining text after the last translation string
- toTranslate.push(str.slice(lastBreak, cursor + 2));
+ toTranslate.push(last);
// and return a promise for the concatenated translated string
return Promise.all(toTranslate).then(function (translated) {
@@ -232,9 +255,10 @@
* Translates a specific key and array of arguments
* @param {string} name - Translation key (ex. 'global:home')
* @param {string[]} args - Arguments for `%1`, `%2`, etc
+ * @param {string|Promise} backup - Text to use in case the key can't be found
* @returns {Promise}
*/
- Translator.prototype.translateKey = function translateKey(name, args) {
+ Translator.prototype.translateKey = function translateKey(name, args, backup) {
var self = this;
var result = name.split(':', 2);
@@ -251,29 +275,27 @@
}
var translation = this.getTranslation(namespace, key);
- var argsToTranslate = args.map(function (arg) {
- return string(arg).collapseWhitespace().decodeHTMLEntities().escapeHTML().s;
- }).map(function (arg) {
- return self.translate(arg);
- });
-
- // so we can await all promises at once
- argsToTranslate.unshift(translation);
-
- return Promise.all(argsToTranslate).then(function (result) {
- var translated = result[0];
- var translatedArgs = result.slice(1);
-
+ return translation.then(function (translated) {
+ // check if the translation is missing first
if (!translated) {
warn('Missing translation "' + name + '"');
- return key;
+ return backup || key;
}
- var out = translated;
- translatedArgs.forEach(function (arg, i) {
- var escaped = arg.replace(/%/g, '%').replace(/\\,/g, ',');
- out = out.replace(new RegExp('%' + (i + 1), 'g'), escaped);
+
+ var argsToTranslate = args.map(function (arg) {
+ return string(arg).collapseWhitespace().decodeHTMLEntities().escapeHTML().s;
+ }).map(function (arg) {
+ return self.translate(arg);
+ });
+
+ return Promise.all(argsToTranslate).then(function (translatedArgs) {
+ var out = translated;
+ translatedArgs.forEach(function (arg, i) {
+ var escaped = arg.replace(/%/g, '%').replace(/\\,/g, ',');
+ out = out.replace(new RegExp('%' + (i + 1), 'g'), escaped);
+ });
+ return out;
});
- return out;
});
};
@@ -281,7 +303,7 @@
* Load translation file (or use a cached version), and optionally return the translation of a certain key
* @param {string} namespace - The file name of the translation namespace
* @param {string} [key] - The key of the specific translation to getJSON
- * @returns {Promise