diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3fc954feb4..d025ff3ff5 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,6 +2,7 @@ == Github Issues are for bug reports and feature requests only == == Please visit https://community.nodebb.org for other support == == Found a security exploit? Please email us at security@nodebb.org instead for immediate attention == + == → DO NOT SUBMIT VULNERABILITIES TO THE PUBLIC BUG TRACKER == --> diff --git a/.gitignore b/.gitignore index 68651e533d..76eb6aa59c 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,4 @@ build test/files/normalise.jpg.png test/files/normalise-resized.jpg package-lock.json -package.json +/package.json diff --git a/.travis.yml b/.travis.yml index 653ddd14f1..13e6afdd3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - "sudo service mongod start" before_script: - sleep 15 # wait for mongodb to be ready - - cp package.default.json package.json + - cp install/package.json package.json - npm install - sh -c "if [ '$DB' = 'mongodb' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"mongo\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":27017,\\\"database\\\":0}\"; fi" - sh -c "if [ '$DB' = 'redis' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"redis\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":6379,\\\"database\\\":0}\"; fi" diff --git a/Dockerfile b/Dockerfile index adce1f33ad..872d15667e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /usr/src/app ARG NODE_ENV ENV NODE_ENV $NODE_ENV -COPY package.default.json /usr/src/app/package.json +COPY install/package.json /usr/src/app/package.json RUN npm install && npm cache clean --force COPY . /usr/src/app diff --git a/README.md b/README.md index 5af55c3d9d..6238f2c744 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/NodeBB/NodeBB?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/NodeBB/NodeBB.svg?branch=master)](https://travis-ci.org/NodeBB/NodeBB) [![Coverage Status](https://coveralls.io/repos/github/NodeBB/NodeBB/badge.svg?branch=master)](https://coveralls.io/github/NodeBB/NodeBB?branch=master) -[![Dependency Status](https://david-dm.org/nodebb/nodebb.svg)](https://david-dm.org/nodebb/nodebb) +[![Dependency Status](https://david-dm.org/nodebb/nodebb.svg?path=install)](https://david-dm.org/nodebb/nodebb?path=install) [![Code Climate](https://codeclimate.com/github/NodeBB/NodeBB/badges/gpa.svg)](https://codeclimate.com/github/NodeBB/NodeBB) [![Documentation Status](https://readthedocs.org/projects/nodebb/badge/?version=latest)](https://readthedocs.org/projects/nodebb/?badge=latest) diff --git a/app.js b/app.js index d1bf1c7c08..748a68bb54 100644 --- a/app.js +++ b/app.js @@ -30,47 +30,16 @@ nconf.argv().env({ separator: '__', }); -var url = require('url'); var async = require('async'); var winston = require('winston'); var path = require('path'); -var pkg = require('./package.json'); + var file = require('./src/file'); -var debug = require('./src/meta/debugFork').debugging; global.env = process.env.NODE_ENV || 'production'; -winston.remove(winston.transports.Console); -winston.add(winston.transports.Console, { - colorize: true, - timestamp: function () { - var date = new Date(); - return nconf.get('json-logging') ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 8) + ' [' + global.process.pid + ']'; - }, - level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'), - json: (!!nconf.get('json-logging')), - stringify: (!!nconf.get('json-logging')), -}); - -if (debug) { - var winstonCommon = require('winston/lib/winston/common'); - // Override to use real console.log etc for VSCode debugger - winston.transports.Console.prototype.log = function (level, message, meta, callback) { - const output = winstonCommon.log(Object.assign({}, this, { - level, - message, - meta, - })); - - console[level in console ? level : 'log'](output); - - setImmediate(callback, null, true); - }; -} - - // Alternate configuration file support -var configFile = path.join(__dirname, '/config.json'); +var configFile = path.join(__dirname, 'config.json'); if (nconf.get('config')) { configFile = path.resolve(__dirname, nconf.get('config')); @@ -78,8 +47,10 @@ if (nconf.get('config')) { var configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database')); -loadConfig(); -versionCheck(); +var prestart = require('./src/prestart'); +prestart.loadConfig(configFile); +prestart.versionCheck(); +prestart.setupWinston(); if (!process.send) { // If run using `node app`, log GNU copyright info along with server info @@ -89,224 +60,40 @@ if (!process.send) { winston.info(''); } - if (nconf.get('setup') || nconf.get('install')) { - setup(); + require('./src/cli/setup').setup(); } else if (!configExists) { require('./install/web').install(nconf.get('port')); } else if (nconf.get('upgrade')) { - upgrade(); + require('./src/cli/upgrade').upgrade(true); } else if (nconf.get('reset')) { - async.waterfall([ - async.apply(require('./src/reset').reset), - async.apply(require('./src/meta/build').buildAll), + var options = { + theme: nconf.get('t'), + plugin: nconf.get('p'), + widgets: nconf.get('w'), + settings: nconf.get('s'), + all: nconf.get('a'), + }; + + async.series([ + async.apply(require('./src/cli/reset').reset, options), + require('./src/meta/build').buildAll, ], function (err) { - process.exit(err ? 1 : 0); + if (err) { + throw err; + } + + process.exit(0); }); } else if (nconf.get('activate')) { - activate(); + require('./src/cli/manage').activate(nconf.get('activate')); } else if (nconf.get('plugins')) { - listPlugins(); + require('./src/cli/manage').listPlugins(); } else if (nconf.get('build')) { require('./src/meta/build').build(nconf.get('build')); } else if (nconf.get('events')) { - async.series([ - async.apply(require('./src/database').init), - async.apply(require('./src/events').output), - ]); + require('./src/cli/manage').listEvents(); } else { require('./src/start').start(); } -function loadConfig(callback) { - winston.verbose('* using configuration stored in: %s', configFile); - - nconf.file({ - file: configFile, - }); - - nconf.defaults({ - base_dir: __dirname, - themes_path: path.join(__dirname, 'node_modules'), - upload_path: 'public/uploads', - views_dir: path.join(__dirname, 'build/public/templates'), - version: pkg.version, - }); - - if (!nconf.get('isCluster')) { - nconf.set('isPrimary', 'true'); - nconf.set('isCluster', 'false'); - } - - // Ensure themes_path is a full filepath - nconf.set('themes_path', path.resolve(__dirname, nconf.get('themes_path'))); - nconf.set('core_templates_path', path.join(__dirname, 'src/views')); - nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); - - nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path'))); - - if (nconf.get('url')) { - nconf.set('url_parsed', url.parse(nconf.get('url'))); - } - - // Explicitly cast 'jobsDisabled' as Bool - var castAsBool = ['jobsDisabled']; - nconf.stores.env.readOnly = false; - castAsBool.forEach(function (prop) { - var value = nconf.get(prop); - if (value) { - nconf.set(prop, typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true'); - } - }); - nconf.stores.env.readOnly = true; - - if (typeof callback === 'function') { - callback(); - } -} - -function setup() { - winston.info('NodeBB Setup Triggered via Command Line'); - - var install = require('./src/install'); - var build = require('./src/meta/build'); - - process.stdout.write('\nWelcome to NodeBB!\n'); - process.stdout.write('\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.\n'); - process.stdout.write('Press enter to accept the default setting (shown in brackets).\n'); - - async.series([ - async.apply(install.setup), - async.apply(loadConfig), - async.apply(build.buildAll), - ], function (err, data) { - // Disregard build step data - data = data[0]; - - var separator = ' '; - if (process.stdout.columns > 10) { - for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) { - separator += '='; - } - } - process.stdout.write('\n' + separator + '\n\n'); - - if (err) { - winston.error('There was a problem completing NodeBB setup', err); - throw err; - } else { - if (data.hasOwnProperty('password')) { - process.stdout.write('An administrative user was automatically created for you:\n'); - process.stdout.write(' Username: ' + data.username + '\n'); - process.stdout.write(' Password: ' + data.password + '\n'); - process.stdout.write('\n'); - } - process.stdout.write('NodeBB Setup Completed. Run \'./nodebb start\' to manually start your NodeBB server.\n'); - - // If I am a child process, notify the parent of the returned data before exiting (useful for notifying - // hosts of auto-generated username/password during headless setups) - if (process.send) { - process.send(data); - } - } - - process.exit(); - }); -} - -function upgrade() { - var db = require('./src/database'); - var meta = require('./src/meta'); - var upgrade = require('./src/upgrade'); - var build = require('./src/meta/build'); - var tasks = [db.init, meta.configs.init]; - - if (nconf.get('upgrade') !== true) { - // Likely an upgrade script name passed in - tasks.push(async.apply(upgrade.runParticular, nconf.get('upgrade').split(','))); - } else { - tasks.push(upgrade.run, build.buildAll); - } - // disable mongo timeouts during upgrade - nconf.set('mongo:options:socketTimeoutMS', 0); - async.series(tasks, function (err) { - if (err) { - winston.error(err.stack); - process.exit(1); - } else { - process.exit(0); - } - }); -} - -function activate() { - var db = require('./src/database'); - var plugins = require('./src/plugins'); - var events = require('./src/events'); - var plugin = nconf.get('activate'); - async.waterfall([ - function (next) { - db.init(next); - }, - function (next) { - if (plugin.indexOf('nodebb-') !== 0) { - // Allow omission of `nodebb-plugin-` - plugin = 'nodebb-plugin-' + plugin; - } - plugins.isInstalled(plugin, next); - }, - function (isInstalled, next) { - if (!isInstalled) { - return next(new Error('plugin not installed')); - } - - winston.info('Activating plugin `%s`', plugin); - db.sortedSetAdd('plugins:active', 0, plugin, next); - }, - function (next) { - events.log({ - type: 'plugin-activate', - text: plugin, - }, next); - }, - ], function (err) { - if (err) { - winston.error('An error occurred during plugin activation', err); - throw err; - } - process.exit(0); - }); -} - -function listPlugins() { - require('./src/database').init(function (err) { - if (err) { - winston.error(err.stack); - process.exit(1); - } - - var db = require('./src/database'); - - db.getSortedSetRange('plugins:active', 0, -1, function (err, plugins) { - if (err) { - winston.error(err.stack); - process.exit(1); - } - - winston.info('Active plugins: \n\t - ' + plugins.join('\n\t - ')); - process.exit(); - }); - }); -} - -function versionCheck() { - var version = process.version.slice(1); - var range = pkg.engines.node; - var semver = require('semver'); - var compatible = semver.satisfies(version, range); - - if (!compatible) { - winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.'); - winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset); - } -} diff --git a/install/data/defaults.json b/install/data/defaults.json index 79fbcf07f4..9e08416ce6 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -37,5 +37,6 @@ "unreadCutoff": 2, "bookmarkThreshold": 5, "topicsPerList": 20, - "autoDetectLang": 1 + "autoDetectLang": 1, + "privileges:flag": 0 } diff --git a/install/databases.js b/install/databases.js index b55fa8ad0c..430a40e04d 100644 --- a/install/databases.js +++ b/install/databases.js @@ -12,8 +12,7 @@ var questions = { module.exports = function (config, callback) { async.waterfall([ function (next) { - process.stdout.write('\n'); - winston.info('Now configuring ' + config.database + ' database:'); + winston.info('\nNow configuring ' + config.database + ' database:'); getDatabaseConfig(config, next); }, function (databaseConfig, next) { diff --git a/install/package.json b/install/package.json new file mode 100644 index 0000000000..af744e25b6 --- /dev/null +++ b/install/package.json @@ -0,0 +1,140 @@ +{ + "name": "nodebb", + "license": "GPL-3.0", + "description": "NodeBB Forum", + "version": "1.7.2", + "homepage": "http://www.nodebb.org", + "repository": { + "type": "git", + "url": "https://github.com/NodeBB/NodeBB/" + }, + "main": "app.js", + "scripts": { + "start": "node loader.js", + "lint": "eslint --cache ./nodebb .", + "pretest": "npm run lint", + "test": "nyc --reporter=html --reporter=text-summary mocha", + "coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage" + }, + "dependencies": { + "ace-builds": "^1.2.9", + "async": "2.6.0", + "autoprefixer": "7.1.6", + "bcryptjs": "2.4.3", + "benchpressjs": "^1.2.0", + "body-parser": "^1.18.2", + "bootstrap": "^3.3.7", + "chart.js": "^2.7.0", + "colors": "^1.1.2", + "compression": "^1.7.1", + "commander": "^2.11.0", + "connect-ensure-login": "^0.1.1", + "connect-flash": "^0.1.1", + "connect-mongo": "2.0.0", + "connect-multiparty": "^2.1.0", + "connect-redis": "3.3.2", + "cookie-parser": "^1.4.3", + "cron": "^1.3.0", + "cropperjs": "^1.1.3", + "csurf": "^1.9.0", + "daemon": "^1.1.0", + "express": "^4.16.2", + "express-session": "^1.15.6", + "express-useragent": "1.0.8", + "graceful-fs": "^4.1.11", + "html-to-text": "3.3.0", + "ipaddr.js": "^1.5.4", + "jimp": "0.2.28", + "jquery": "^3.2.1", + "jsesc": "2.5.1", + "json-2-csv": "^2.1.2", + "less": "^2.7.2", + "lodash": "^4.17.4", + "logrotate-stream": "^0.2.5", + "lru-cache": "4.1.1", + "material-design-lite": "^1.3.0", + "mime": "^2.0.3", + "mkdirp": "^0.5.1", + "mongodb": "2.2.33", + "morgan": "^1.9.0", + "mousetrap": "^1.6.1", + "nconf": "^0.9.1", + "nodebb-plugin-composer-default": "6.0.7", + "nodebb-plugin-dbsearch": "2.0.9", + "nodebb-plugin-emoji": "2.0.7", + "nodebb-plugin-emoji-android": "2.0.0", + "nodebb-plugin-markdown": "8.2.2", + "nodebb-plugin-mentions": "2.2.2", + "nodebb-plugin-soundpack-default": "1.0.0", + "nodebb-plugin-spam-be-gone": "0.5.1", + "nodebb-rewards-essentials": "0.0.9", + "nodebb-theme-lavender": "5.0.0", + "nodebb-theme-persona": "7.2.7", + "nodebb-theme-slick": "1.1.2", + "nodebb-theme-vanilla": "8.1.4", + "nodebb-widget-essentials": "4.0.1", + "nodemailer": "4.4.0", + "passport": "^0.4.0", + "passport-local": "1.0.0", + "postcss": "6.0.14", + "postcss-clean": "1.1.0", + "promise-polyfill": "^6.0.2", + "prompt": "^1.0.0", + "redis": "2.8.0", + "request": "2.83.0", + "rimraf": "2.6.2", + "rss": "^1.2.2", + "sanitize-html": "^1.14.1", + "semver": "^5.4.1", + "serve-favicon": "^2.4.5", + "sitemap": "^1.13.0", + "socket.io": "2.0.4", + "socket.io-client": "2.0.4", + "socket.io-redis": "5.2.0", + "socketio-wildcard": "2.0.0", + "spdx-license-list": "^3.0.1", + "toobusy-js": "^0.5.1", + "uglify-js": "^3.1.5", + "validator": "9.1.2", + "winston": "^2.4.0", + "xml": "^1.0.1", + "xregexp": "3.2.0", + "zxcvbn": "^4.4.2" + }, + "devDependencies": { + "coveralls": "^3.0.0", + "eslint": "^4.9.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", + "grunt": "^1.0.1", + "grunt-contrib-watch": "^1.0.0", + "jsdom": "^11.3.0", + "mocha": "^4.0.1", + "mocha-lcov-reporter": "^1.3.0", + "nyc": "^11.2.1", + "smtp-server": "^3.3.0" + }, + "bugs": { + "url": "https://github.com/NodeBB/NodeBB/issues" + }, + "engines": { + "node": ">=6" + }, + "maintainers": [ + { + "name": "Andrew Rodrigues", + "email": "andrew@nodebb.org", + "url": "https://github.com/psychobunny" + }, + { + "name": "Julian Lam", + "email": "julian@nodebb.org", + "url": "https://github.com/julianlam" + }, + { + "name": "Barış Soner Uşaklı", + "email": "baris@nodebb.org", + "url": "https://github.com/barisusakli" + } + ] + } diff --git a/install/web.js b/install/web.js index 6898ee864d..92dcdb17d3 100644 --- a/install/web.js +++ b/install/web.js @@ -5,6 +5,7 @@ var express = require('express'); var bodyParser = require('body-parser'); var fs = require('fs'); var path = require('path'); +var childProcess = require('child_process'); var less = require('less'); var async = require('async'); var uglify = require('uglify-js'); @@ -26,6 +27,7 @@ winston.add(winston.transports.File, { var web = {}; var scripts = [ + 'node_modules/jquery/dist/jquery.js', 'public/vendor/xregexp/xregexp.js', 'public/vendor/xregexp/unicode/unicode-base.js', 'public/src/utils.js', @@ -53,7 +55,7 @@ web.install = function (port) { extended: true, })); - async.parallel([compileLess, compileJS], function (err) { + async.parallel([compileLess, compileJS, copyCSS], function (err) { if (err) { winston.error(err); } @@ -77,10 +79,14 @@ function setupRoutes() { function welcome(req, res) { var dbs = ['redis', 'mongo']; - var databases = dbs.map(function (el) { + var databases = dbs.map(function (databaseName) { + var questions = require('../src/database/' + databaseName).questions.filter(function (question) { + return question && !question.hideOnWebInstall; + }); + return { - name: el, - questions: require('../src/database/' + el).questions, + name: databaseName, + questions: questions, }; }); @@ -122,24 +128,25 @@ function launch(req, res) { res.json({}); server.close(); - var child = require('child_process').spawn('node', ['loader.js'], { + var child = childProcess.spawn('node', ['loader.js'], { detached: true, stdio: ['ignore', 'ignore', 'ignore'], }); - process.stdout.write('\nStarting NodeBB\n'); - process.stdout.write(' "./nodebb stop" to stop the NodeBB server\n'); - process.stdout.write(' "./nodebb log" to view server output\n'); - process.stdout.write(' "./nodebb restart" to restart NodeBB\n'); + console.log('\nStarting NodeBB'); + console.log(' "./nodebb stop" to stop the NodeBB server'); + console.log(' "./nodebb log" to view server output'); + console.log(' "./nodebb restart" to restart NodeBB'); - async.parallel([ - function (next) { - fs.unlink(path.join(__dirname, '../public/installer.css'), next); - }, - function (next) { - fs.unlink(path.join(__dirname, '../public/installer.min.js'), next); - }, - ], function (err) { + var filesToDelete = [ + 'installer.css', + 'installer.min.js', + 'bootstrap.min.css', + ]; + + async.each(filesToDelete, function (filename, next) { + fs.unlink(path.join(__dirname, '../public', filename), next); + }, function (err) { if (err) { winston.warn('Unable to remove installer files'); } @@ -194,4 +201,15 @@ function compileJS(callback) { }); } +function copyCSS(next) { + async.waterfall([ + function (next) { + fs.readFile(path.join(__dirname, '../node_modules/bootstrap/dist/css/bootstrap.min.css'), 'utf8', next); + }, + function (src, next) { + fs.writeFile(path.join(__dirname, '../public/bootstrap.min.css'), src, next); + }, + ], next); +} + module.exports = web; diff --git a/nodebb b/nodebb index adedd30826..546e608cd2 100755 --- a/nodebb +++ b/nodebb @@ -2,549 +2,4 @@ 'use strict'; -var fs = require('fs'); -var path = require('path'); -var cproc = require('child_process'); - -var packageInstall = require('./src/meta/package-install'); - -// check to make sure dependencies are installed -try { - fs.readFileSync(path.join(__dirname, './package.json')); - fs.readFileSync(path.join(__dirname, 'node_modules/async/package.json')); -} catch (e) { - if (e.code === 'ENOENT') { - process.stdout.write('Dependencies not yet installed.\n'); - process.stdout.write('Installing them now...\n\n'); - - packageInstall.updatePackageFile(); - packageInstall.preserveExtraneousPlugins(); - packageInstall.npmInstallProduction(); - } else { - throw e; - } -} - -var minimist; -var request; -var semver; -var prompt; -var async; - -try { - require('colors'); - minimist = require('minimist'); - request = require('request'); - semver = require('semver'); - prompt = require('prompt'); - async = require('async'); -} catch (e) { - process.stdout.write( - '\x1b[31mNodeBB could not be initialised because there was an error while loading dependencies.\n' + - 'Please run "\x1b[33mnpm install --production\x1b[31m" and try again.\x1b[0m\n\n' + - 'For more information, please see: https://docs.nodebb.org/installing/os/\n\n' - ); - - throw e; -} - -var args = minimist(process.argv.slice(2)); - -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(path.join(__dirname, 'pidfile'), { - encoding: 'utf-8', - }, function (err, pid) { - if (err) { - return callback(err); - } - - try { - process.kill(parseInt(pid, 10), 0); - callback(null, parseInt(pid, 10)); - } catch (e) { - callback(e); - } - }); -} -function getCurrentVersion(callback) { - fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) { - if (err) { - return callback(err); - } - - try { - pkg = JSON.parse(pkg); - return callback(null, pkg.version); - } catch (err) { - return callback(err); - } - }); -} -function fork(args) { - return cproc.fork(appPath, args, { - cwd: __dirname, - 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' }), - }, function (err, payload) { - if (err) { - return callback(err); - } - - var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/; - var moduleName; - var isGitRepo; - - payload.files = payload.files.filter(function (file) { - return isNbbModule.test(file); - }); - - try { - payload.deps = JSON.parse(payload.deps).dependencies; - payload.bundled = []; - payload.installed = []; - } catch (err) { - return callback(err); - } - - for (moduleName in payload.deps) { - if (isNbbModule.test(moduleName)) { - payload.bundled.push(moduleName); - } - } - - // Whittle down deps to send back only extraneously installed plugins/themes/etc - payload.files.forEach(function (moduleName) { - try { - fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git')); - isGitRepo = true; - } catch (e) { - isGitRepo = false; - } - - if ( - payload.files.indexOf(moduleName) !== -1 && // found in `node_modules/` - payload.bundled.indexOf(moduleName) === -1 && // not found in `package.json` - !fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() && // is not a symlink - !isGitRepo // .git/ does not exist, so it is not a git repository - ) { - payload.installed.push(moduleName); - } - }); - - getModuleVersions(payload.installed, callback); - }); -} -function getModuleVersions(modules, callback) { - var versionHash = {}; - - async.eachLimit(modules, 50, function (module, next) { - fs.readFile(path.join(__dirname, 'node_modules/' + module + '/package.json'), { encoding: 'utf-8' }, function (err, pkg) { - if (err) { - return next(err); - } - - try { - pkg = JSON.parse(pkg); - versionHash[module] = pkg.version; - next(); - } catch (err) { - next(err); - } - }); - }, function (err) { - callback(err, versionHash); - }); -} -function checkPlugins(standalone, callback) { - if (standalone) { - process.stdout.write('Checking installed plugins and themes for updates... '); - } - - async.waterfall([ - async.apply(async.parallel, { - plugins: async.apply(getInstalledPlugins), - version: async.apply(getCurrentVersion), - }), - function (payload, next) { - var toCheck = Object.keys(payload.plugins); - - if (!toCheck.length) { - process.stdout.write('OK'.green + '\n'.reset); - return next(null, []); // no extraneous plugins installed - } - - request({ - method: 'GET', - url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='), - json: true, - }, function (err, res, body) { - if (err) { - process.stdout.write('error'.red + '\n'.reset); - return next(err); - } - process.stdout.write('OK'.green + '\n'.reset); - - if (!Array.isArray(body) && toCheck.length === 1) { - body = [body]; - } - - 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) { - var standalone = false; - if (typeof callback !== 'function') { - callback = function () {}; - standalone = true; - } - - checkPlugins(standalone, function (err, found) { - if (err) { - process.stdout.write('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset); - return callback(err); - } - - if (found && found.length) { - process.stdout.write('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:\n'); - found.forEach(function (suggestObj) { - process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset); - }); - process.stdout.write('\n'); - } else { - if (standalone) { - process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset); - } - return callback(); - } - - prompt.message = ''; - prompt.delimiter = ''; - - prompt.start(); - prompt.get({ - name: 'upgrade', - description: 'Proceed with upgrade (y|n)?'.reset, - type: 'string', - }, function (err, result) { - if (err) { - return callback(err); - } - - if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) { - process.stdout.write('\nUpgrading packages...'); - var args = ['i']; - found.forEach(function (suggestObj) { - args.push(suggestObj.name + '@' + suggestObj.suggested); - }); - - cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', args, { stdio: 'ignore' }, function (err) { - if (!err) { - process.stdout.write(' OK\n'.green); - } - - callback(err); - }); - } else { - process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset); - callback(); - } - }); - }); -} - -var commands = { - status: { - description: 'View the status of the NodeBB server', - usage: 'Usage: ' + './nodebb status'.yellow, - handler: function () { - getRunningPid(function (err, pid) { - if (!err) { - process.stdout.write('\nNodeBB Running '.bold + '(pid '.cyan + pid.toString().cyan + ')\n'.cyan); - process.stdout.write('\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server\n'); - process.stdout.write('\t"' + './nodebb log'.yellow + '" to view server output\n'); - process.stdout.write('\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'); - } else { - process.stdout.write('\nNodeBB is not running\n'.bold); - process.stdout.write('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n\n'.reset); - } - }); - }, - }, - start: { - description: 'Start the NodeBB server', - usage: 'Usage: ' + './nodebb start'.yellow, - handler: function () { - process.stdout.write('\nStarting NodeBB\n'.bold); - process.stdout.write(' "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n'); - process.stdout.write(' "' + './nodebb log'.yellow + '" to view server output\n'); - process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset); - - // Spawn a new NodeBB process - cproc.fork(loaderPath, process.argv.slice(3), { - env: process.env, - }); - }, - }, - stop: { - description: 'Stop the NodeBB server', - usage: 'Usage: ' + './nodebb stop'.yellow, - handler: function () { - getRunningPid(function (err, pid) { - if (!err) { - process.kill(pid, 'SIGTERM'); - process.stdout.write('Stopping NodeBB. Goodbye!\n'); - } else { - process.stdout.write('NodeBB is already stopped.\n'); - } - }); - }, - }, - restart: { - description: 'Restart the NodeBB server', - usage: 'Usage: ' + './nodebb restart'.yellow, - handler: function () { - getRunningPid(function (err, pid) { - if (!err) { - process.kill(pid, 'SIGHUP'); - process.stdout.write('\nRestarting NodeBB\n'.bold); - } else { - process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n'); - } - }); - }, - }, - log: { - description: 'Open the output log (useful for debugging)', - usage: 'Usage: ' + './nodebb log'.yellow, - handler: function () { - process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); - process.stdout.write('\n\n'.reset); - cproc.spawn('tail', ['-F', './logs/output.log'], { - cwd: __dirname, - stdio: 'inherit', - }); - }, - }, - slog: { - description: 'Start the NodeBB server and view the live output log', - usage: 'Usage: ' + './nodebb slog'.yellow, - handler: function () { - process.stdout.write('\nStarting NodeBB with logging output\n'.bold); - process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); - process.stdout.write('\n\n'.reset); - - // Spawn a new NodeBB process - cproc.fork(loaderPath, { - env: process.env, - }); - cproc.spawn('tail', ['-F', './logs/output.log'], { - cwd: __dirname, - stdio: 'inherit', - }); - }, - }, - dev: { - description: 'Start NodeBB in verbose development mode', - usage: 'Usage: ' + './nodebb dev'.yellow, - handler: function () { - process.env.NODE_ENV = 'development'; - 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' + - ' e.g. ' + './nodebb build js,tpl'.yellow + '\tbuilds JS and templates\n' + - ' ' + './nodebb build'.yellow + '\t\tbuilds all targets\n', - handler: function () { - var arr = ['--build'].concat(process.argv.slice(3)); - fork(arr); - }, - }, - setup: { - description: 'Run the NodeBB setup script', - usage: 'Usage: ' + './nodebb setup'.yellow, - handler: function () { - var arr = ['--setup'].concat(process.argv.slice(3)); - fork(arr); - }, - }, - reset: { - description: 'Disable plugins and restore the default theme', - usage: 'Usage: ' + './nodebb reset '.yellow + '{-t|-p|-w|-s|-a}'.red + '\n' + - ' -t \tuse specified theme\n' + - ' -p \tdisable specified plugin\n' + - '\n' + - ' -t\t\tuse default theme\n' + - ' -p\t\tdisable all but core plugins\n' + - ' -w\t\twidgets\n' + - ' -s\t\tsettings\n' + - ' -a\t\tall of the above\n', - handler: function () { - var arr = ['--reset'].concat(process.argv.slice(3)); - fork(arr); - }, - }, - activate: { - description: 'Activate a plugin for the next startup of NodeBB', - usage: 'Usage: ' + './nodebb activate '.yellow, - handler: function () { - var name = args._[1]; - if (!name) { - process.stdout.write(commands.activate.usage + '\n'); - process.exit(); - } - if (name.startsWith('nodebb-theme')) { - fork(['--reset', '-t', name]); - return; - } - var arr = ['--activate=' + name].concat(process.argv.slice(4)); - fork(arr); - }, - }, - plugins: { - description: 'List all installed plugins', - usage: 'Usage: ' + './nodebb plugins'.yellow, - handler: function () { - var arr = ['--plugins'].concat(process.argv.slice(3)); - fork(arr); - }, - }, - upgrade: { - description: 'Run NodeBB upgrade scripts, ensure packages are up-to-date', - usage: 'Usage: ' + './nodebb upgrade'.yellow, - handler: function () { - if (process.argv[3]) { - process.stdout.write('\nUpdating NodeBB data store schema...\n'.yellow); - var arr = ['--upgrade'].concat(process.argv.slice(3)); - var upgradeProc = fork(arr); - - return upgradeProc.on('close', function (err) { - if (err) { - process.stdout.write('Error occurred during upgrade'); - throw err; - } - }); - } - - async.series([ - function (next) { - packageInstall.updatePackageFile(); - packageInstall.preserveExtraneousPlugins(); - next(); - }, - function (next) { - process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... \n'.yellow); - packageInstall.npmInstallProduction(); - next(); - }, - function (next) { - process.stdout.write('OK\n'.green); - process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow); - upgradePlugins(next); - }, - function (next) { - process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow); - var arr = ['--upgrade'].concat(process.argv.slice(3)); - var upgradeProc = fork(arr); - - upgradeProc.on('close', next); - upgradeProc.on('error', next); - }, - ], function (err) { - if (err) { - process.stdout.write('Error occurred during upgrade'); - throw err; - } - - 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(' ') : ' '; - - process.stdout.write('OK\n'.green); - process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset); - }); - }, - }, - upgradePlugins: { - hidden: true, - description: '', - handler: function () { - upgradePlugins(); - }, - }, - events: { - description: 'Outputs the last ten (10) administrative events recorded by NodeBB', - usage: 'Usage: ' + './nodebb events'.yellow, - handler: function () { - fork(['--events']); - }, - }, - help: { - description: 'Display the help message for a given command', - usage: 'Usage: ' + './nodebb help '.yellow, - handler: function () { - var command = commands[args._[1]]; - if (command) { - process.stdout.write(command.description + '\n'.reset); - process.stdout.write(command.usage + '\n'.reset); - - return; - } - var keys = Object.keys(commands).filter(function (key) { - return !commands[key].hidden; - }); - - process.stdout.write('\nWelcome to NodeBB\n\n'.bold); - process.stdout.write('Usage: ./nodebb {' + keys.join('|') + '}\n\n'); - - var usage = keys.map(function (key) { - var line = '\t' + key.yellow + (key.length < 8 ? '\t\t' : '\t'); - return line + commands[key].description; - }).join('\n'); - - process.stdout.write(usage + '\n'.reset); - }, - }, -}; - -commands['upgrade-plugins'] = commands.upgradePlugins; - -if (!commands[args._[0]]) { - commands.help.handler(); -} else { - commands[args._[0]].handler(); -} +require('./src/cli'); diff --git a/nodebb.bat b/nodebb.bat index daaf09224f..ba0e75d249 100644 --- a/nodebb.bat +++ b/nodebb.bat @@ -1 +1 @@ -node ./nodebb %* +@echo off && cd %~dp0 && node ./src/cli %* diff --git a/package.default.json b/package.default.json deleted file mode 100644 index 26e11cb2b2..0000000000 --- a/package.default.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "name": "nodebb", - "license": "GPL-3.0", - "description": "NodeBB Forum", - "version": "1.6.1", - "homepage": "http://www.nodebb.org", - "repository": { - "type": "git", - "url": "https://github.com/NodeBB/NodeBB/" - }, - "main": "app.js", - "scripts": { - "start": "node loader.js", - "lint": "eslint --cache ./nodebb .", - "pretest": "npm run lint", - "test": "nyc --reporter=html --reporter=text-summary mocha", - "coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage" - }, - "dependencies": { - "ace-builds": "^1.2.9", - "async": "2.5.0", - "autoprefixer": "7.1.6", - "bcryptjs": "2.4.3", - "benchpressjs": "^1.1.2", - "body-parser": "^1.18.2", - "bootstrap": "^3.3.7", - "chart.js": "^2.7.0", - "colors": "^1.1.2", - "compression": "^1.7.1", - "connect-ensure-login": "^0.1.1", - "connect-flash": "^0.1.1", - "connect-mongo": "2.0.0", - "connect-multiparty": "^2.1.0", - "connect-redis": "3.3.2", - "cookie-parser": "^1.4.3", - "cron": "^1.3.0", - "cropperjs": "^1.1.3", - "csurf": "^1.9.0", - "daemon": "^1.1.0", - "express": "^4.16.2", - "express-session": "^1.15.6", - "express-useragent": "1.0.8", - "html-to-text": "3.3.0", - "ipaddr.js": "^1.5.4", - "jimp": "0.2.28", - "jquery": "^3.2.1", - "jsesc": "2.5.1", - "json-2-csv": "^2.1.2", - "less": "^2.7.2", - "lodash": "^4.17.4", - "logrotate-stream": "^0.2.5", - "lru-cache": "4.1.1", - "mime": "^2.0.3", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "mongodb": "2.2.33", - "morgan": "^1.9.0", - "mousetrap": "^1.6.1", - "nconf": "^0.8.5", - "nodebb-plugin-composer-default": "6.0.5", - "nodebb-plugin-dbsearch": "2.0.8", - "nodebb-plugin-emoji-extended": "1.1.1", - "nodebb-plugin-emoji-one": "1.2.1", - "nodebb-plugin-markdown": "8.2.0", - "nodebb-plugin-mentions": "2.2.0", - "nodebb-plugin-soundpack-default": "1.0.0", - "nodebb-plugin-spam-be-gone": "0.5.1", - "nodebb-rewards-essentials": "0.0.9", - "nodebb-theme-lavender": "5.0.0", - "nodebb-theme-persona": "7.0.1", - "nodebb-theme-slick": "1.1.1", - "nodebb-theme-vanilla": "8.0.1", - "nodebb-widget-essentials": "4.0.1", - "nodemailer": "4.3.0", - "passport": "^0.4.0", - "passport-local": "1.0.0", - "postcss": "6.0.13", - "postcss-clean": "1.1.0", - "promise-polyfill": "^6.0.2", - "prompt": "^1.0.0", - "redis": "2.8.0", - "request": "2.83.0", - "rimraf": "2.6.2", - "rss": "^1.2.2", - "sanitize-html": "^1.14.1", - "semver": "^5.4.1", - "serve-favicon": "^2.4.5", - "sitemap": "^1.13.0", - "socket.io": "2.0.4", - "socket.io-client": "2.0.4", - "socket.io-redis": "5.2.0", - "socketio-wildcard": "2.0.0", - "spdx-license-list": "^3.0.1", - "toobusy-js": "^0.5.1", - "uglify-js": "^3.1.5", - "validator": "9.0.0", - "winston": "^2.4.0", - "xml": "^1.0.1", - "xregexp": "3.2.0", - "zxcvbn": "^4.4.2" - }, - "devDependencies": { - "coveralls": "^3.0.0", - "eslint": "^4.9.0", - "eslint-config-airbnb-base": "^12.1.0", - "eslint-plugin-import": "^2.8.0", - "grunt": "^1.0.1", - "grunt-contrib-watch": "^1.0.0", - "jsdom": "^11.3.0", - "mocha": "^4.0.1", - "mocha-lcov-reporter": "^1.3.0", - "nyc": "^11.2.1" - }, - "bugs": { - "url": "https://github.com/NodeBB/NodeBB/issues" - }, - "engines": { - "node": ">=6" - }, - "maintainers": [ - { - "name": "Andrew Rodrigues", - "email": "andrew@nodebb.org", - "url": "https://github.com/psychobunny" - }, - { - "name": "Julian Lam", - "email": "julian@nodebb.org", - "url": "https://github.com/julianlam" - }, - { - "name": "Barış Soner Uşaklı", - "email": "baris@nodebb.org", - "url": "https://github.com/barisusakli" - } - ] -} diff --git a/public/images/emails/digestheader.jpg b/public/images/emails/digestheader.jpg new file mode 100644 index 0000000000..4c873e41b7 Binary files /dev/null and b/public/images/emails/digestheader.jpg differ diff --git a/public/images/emails/digestheader.png b/public/images/emails/digestheader.png deleted file mode 100644 index 44ff4dd203..0000000000 Binary files a/public/images/emails/digestheader.png and /dev/null differ diff --git a/public/images/emails/notification.png b/public/images/emails/notification.png new file mode 100644 index 0000000000..0e10a1580c Binary files /dev/null and b/public/images/emails/notification.png differ diff --git a/public/language/ar/admin/admin.json b/public/language/ar/admin/admin.json index 9c01f56006..a307bc8d28 100644 --- a/public/language/ar/admin/admin.json +++ b/public/language/ar/admin/admin.json @@ -1,7 +1,7 @@ { - "alert.confirm-reload": "Are you sure you wish to reload NodeBB?", - "alert.confirm-restart": "Are you sure you wish to restart NodeBB?", + "alert.confirm-reload": "هل تريد بالتأكيد إعادة تحميل NodeBB؟", + "alert.confirm-restart": "هل تريد بالتأكيد إعادة تشغيل NodeBB؟", - "acp-title": "%1 | NodeBB Admin Control Panel", - "settings-header-contents": "Contents" + "acp-title": "لوحة تحكم إدارة NodeBB | %1", + "settings-header-contents": "محتويات" } \ No newline at end of file diff --git a/public/language/ar/admin/advanced/cache.json b/public/language/ar/admin/advanced/cache.json index 5a954f1232..e459eea6d5 100644 --- a/public/language/ar/admin/advanced/cache.json +++ b/public/language/ar/admin/advanced/cache.json @@ -1,11 +1,11 @@ { - "post-cache": "Post Cache", - "posts-in-cache": "Posts in Cache", - "average-post-size": "Average Post Size", - "length-to-max": "Length / Max", + "post-cache": "التخزين المؤقت للمشاركات", + "posts-in-cache": "المشاركات المخزنة مؤقتاً", + "average-post-size": "متوسط ​​حجم المشاركة", + "length-to-max": "الطول / أقصى حد", "percent-full": "%1% Full", - "post-cache-size": "Post Cache Size", - "items-in-cache": "Items in Cache", - "control-panel": "Control Panel", - "update-settings": "Update Cache Settings" + "post-cache-size": "حجم التخزين المؤقت للمشاركات", + "items-in-cache": "العناصر في التخزين المؤقت", + "control-panel": "لوحة التحكم", + "update-settings": "تحديث إعدادات التخزين المؤقت" } \ No newline at end of file diff --git a/public/language/ar/admin/advanced/database.json b/public/language/ar/admin/advanced/database.json index b88ca6fc82..8a8fc25a79 100644 --- a/public/language/ar/admin/advanced/database.json +++ b/public/language/ar/admin/advanced/database.json @@ -16,7 +16,7 @@ "mongo.index-size": "Index Size", "mongo.file-size": "File Size", "mongo.resident-memory": "Resident Memory", - "mongo.virtual-memory": "Virtual Memory", + "mongo.virtual-memory": "الذاكرة الإفتراضية", "mongo.mapped-memory": "Mapped Memory", "mongo.raw-info": "MongoDB Raw Info", @@ -25,10 +25,10 @@ "redis.connected-clients": "Connected Clients", "redis.connected-slaves": "Connected Slaves", "redis.blocked-clients": "Blocked Clients", - "redis.used-memory": "Used Memory", + "redis.used-memory": "الذاكرة المستخدمة", "redis.memory-frag-ratio": "Memory Fragmentation Ratio", - "redis.total-connections-recieved": "Total Connections Received", - "redis.total-commands-processed": "Total Commands Processed", + "redis.total-connections-recieved": "إجمالي الاتصالات المستلمة", + "redis.total-commands-processed": "إجمالي الأوامر التي تمت معالجتها", "redis.iops": "Instantaneous Ops. Per Second", "redis.keyspace-hits": "Keyspace Hits", "redis.keyspace-misses": "Keyspace Misses", diff --git a/public/language/ar/admin/advanced/errors.json b/public/language/ar/admin/advanced/errors.json index 546f0f1508..bf9bc97443 100644 --- a/public/language/ar/admin/advanced/errors.json +++ b/public/language/ar/admin/advanced/errors.json @@ -1,14 +1,14 @@ { - "figure-x": "Figure %1", - "error-events-per-day": "%1 events per day", - "error.404": "404 Not Found", - "error.503": "503 Service Unavailable", - "manage-error-log": "Manage Error Log", - "export-error-log": "Export Error Log (CSV)", - "clear-error-log": "Clear Error Log", - "route": "Route", - "count": "Count", - "no-routes-not-found": "Hooray! No 404 errors!", - "clear404-confirm": "Are you sure you wish to clear the 404 error logs?", - "clear404-success": "\"404 Not Found\" errors cleared" + "figure-x": "شكل %1", + "error-events-per-day": "%1 حدث كل يوم ", + "error.404": "404 لم يتم العثور", + "error.503": "503 الخدمة غير متوفرة", + "manage-error-log": "إدارة سجل الأخطاء", + "export-error-log": "تصدير سجل الأخطاء (CSV)", + "clear-error-log": "محو سجل الأخطاء", + "route": "مسار", + "count": "عدد", + "no-routes-not-found": "لا توجد اخطاء 404!", + "clear404-confirm": "هل تريد بالتأكيد محو سجلات الخطأ 404؟", + "clear404-success": "أخطاء \"404 لم يتم العثور\" تم محوها بنجاح" } \ No newline at end of file diff --git a/public/language/ar/admin/advanced/events.json b/public/language/ar/admin/advanced/events.json index 766eb5e951..662c3f9061 100644 --- a/public/language/ar/admin/advanced/events.json +++ b/public/language/ar/admin/advanced/events.json @@ -1,6 +1,6 @@ { - "events": "Events", - "no-events": "There are no events", - "control-panel": "Events Control Panel", - "delete-events": "Delete Events" + "events": "أحداث", + "no-events": "لا توجد أحداث", + "control-panel": "لوحة تحكم الأحداث", + "delete-events": "حذف الأحداث" } \ No newline at end of file diff --git a/public/language/ar/admin/advanced/logs.json b/public/language/ar/admin/advanced/logs.json index b9de400e1c..cb6a87021b 100644 --- a/public/language/ar/admin/advanced/logs.json +++ b/public/language/ar/admin/advanced/logs.json @@ -1,7 +1,7 @@ { - "logs": "Logs", - "control-panel": "Logs Control Panel", - "reload": "Reload Logs", - "clear": "Clear Logs", - "clear-success": "Logs Cleared!" + "logs": "السجلات", + "control-panel": "لوحة تحكم السجلات", + "reload": "إعادة تحميل السجلات", + "clear": "محو السجلات", + "clear-success": "تم محو السجلات!" } \ No newline at end of file diff --git a/public/language/ar/admin/appearance/customise.json b/public/language/ar/admin/appearance/customise.json index 5095f7a937..94280603a6 100644 --- a/public/language/ar/admin/appearance/customise.json +++ b/public/language/ar/admin/appearance/customise.json @@ -1,12 +1,16 @@ { - "custom-css": "Custom CSS", - "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS", + "custom-css": "CSS مخصص", + "custom-css.description": "أدخل CSS الخاصة بك هنا، والتي سيتم تطبيقها بعد كل القوالب الأخرى.", + "custom-css.enable": "تفعيل CSS المخصص", - "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", - "custom-header.enable": "Enable Custom Header", + "custom-js": "Javascript مخصصة", + "custom-js.description": "أدخل Javascript الخاص بك هنا. سيتم تنفيذها بعد تحميل الصفحة بالكامل.", + "custom-js.enable": "تفعيل Javascript المخصصة", - "custom-css.livereload": "Enable Live Reload", - "custom-css.livereload.description": "Enable this to force all sessions on every device under your account to refresh whenever you click save" + "custom-header": "ترويسة مخصصة", + "custom-header.description": "أدخل HTML الخاصة بك هنا (مثل العلامات الوصفية، وما إلى ذلك)، والتي سيتم إلحاقها الى<head> في تصميم المنتدى. يسمح باستخدام علامات النص البرمجي، ولكن سيتم تعطيلها؛ لتوفر تبويبة\nJavascript المخصصة", + "custom-header.enable": "تفعيل الترويسة المخصصة", + + "custom-css.livereload": "تفعيل إعادة التحميل المباشرة", + "custom-css.livereload.description": "فعل هذا الخيار لإجبار جميع الجلسات في الأجهزة التي قمت بتسجيل الدخول فيها بحسابك على التحديث عند النقر على زر الحفظ" } \ No newline at end of file diff --git a/public/language/ar/admin/appearance/skins.json b/public/language/ar/admin/appearance/skins.json index 4db6fbdd8a..7c97d46cc6 100644 --- a/public/language/ar/admin/appearance/skins.json +++ b/public/language/ar/admin/appearance/skins.json @@ -1,9 +1,9 @@ { - "loading": "Loading Skins...", - "homepage": "Homepage", - "select-skin": "Select Skin", - "current-skin": "Current Skin", - "skin-updated": "Skin Updated", - "applied-success": "%1 skin was succesfully applied", - "revert-success": "Skin reverted to base colours" + "loading": "جاري تحميل السمات...", + "homepage": "الصفحة الرئيسية", + "select-skin": "إختيار السمة", + "current-skin": "السمة الحالية", + "skin-updated": "تم تحديث السمة", + "applied-success": "تم تطبيق السمة %1 بنجاح", + "revert-success": "تم إستعادة الألوان الاساسية للسمة" } \ No newline at end of file diff --git a/public/language/ar/admin/appearance/themes.json b/public/language/ar/admin/appearance/themes.json index 3148a01337..6ca23eaf0e 100644 --- a/public/language/ar/admin/appearance/themes.json +++ b/public/language/ar/admin/appearance/themes.json @@ -1,11 +1,11 @@ { - "checking-for-installed": "Checking for installed themes...", - "homepage": "Homepage", - "select-theme": "Select Theme", - "current-theme": "Current Theme", - "no-themes": "No installed themes found", - "revert-confirm": "Are you sure you wish to restore the default NodeBB theme?", - "theme-changed": "Theme Changed", - "revert-success": "You have successfully reverted your NodeBB back to it's default theme.", - "restart-to-activate": "Please restart your NodeBB to fully activate this theme" + "checking-for-installed": "جاري التحقق من القوالب المثبتة...", + "homepage": "الصفحة الرئيسية", + "select-theme": "إختيار القالب", + "current-theme": "القالب المستخدم حالياً", + "no-themes": "لم يتم العثور على قوالب مثبتة", + "revert-confirm": "هل أنت متأكد من أنك ترغب في استعادة قااب NodeBB الافتراضي؟", + "theme-changed": "تم تغيير القالب", + "revert-success": "لقد قمت بنجاح بإستعادة القالب الأساسي لـNodeBB", + "restart-to-activate": "الرجاء إعادة تشغيل NodeBB لتنشيط هذا القالب بشكل كامل" } \ No newline at end of file diff --git a/public/language/ar/admin/extend/plugins.json b/public/language/ar/admin/extend/plugins.json index 7515f72590..a9082be614 100644 --- a/public/language/ar/admin/extend/plugins.json +++ b/public/language/ar/admin/extend/plugins.json @@ -1,51 +1,51 @@ { - "installed": "Installed", - "active": "Active", - "inactive": "Inactive", - "out-of-date": "Out of Date", - "none-found": "No plugins found.", - "none-active": "No Active Plugins", - "find-plugins": "Find Plugins", + "installed": "منصبة", + "active": "مفعلة", + "inactive": "معطلة", + "out-of-date": "غير محدثة", + "none-found": "لم يتم العثور على إضافات", + "none-active": "لا توجد إضافات مفعلة", + "find-plugins": "العثور على الإضافات", - "plugin-search": "Plugin Search", - "plugin-search-placeholder": "Search for plugin...", - "reorder-plugins": "Re-order Plugins", - "order-active": "Order Active Plugins", - "dev-interested": "Interested in writing plugins for NodeBB?", - "docs-info": "Full documentation regarding plugin authoring can be found in the NodeBB Docs Portal.", + "plugin-search": "البحث عن الإضافات", + "plugin-search-placeholder": "جاري البحث عن الإضافات...", + "reorder-plugins": "إعادة ترتيب الإضافات", + "order-active": "ترتيب الإضافات المفعلة", + "dev-interested": "هل انته مهتم ببرمجة إضافات لـNodeBB؟", + "docs-info": "دليل كامل حول برمجة الإضافات بالإمكان العثور عليه في NodeBB Docs Portal.", - "order.description": "Certain plugins work ideally when they are initialised before/after other plugins.", - "order.explanation": "Plugins load in the order specified here, from top to bottom", + "order.description": "بعض الإضافات تعمل بشكل مثالي عندما يتم تفعيلها قبل أو بعد الإضافات الأخرى.", + "order.explanation": "يتم تحميل الإضافات حسب الترتيب المحدد هنا، من الأعلى إلى الأسفل", - "plugin-item.themes": "Themes", - "plugin-item.deactivate": "Deactivate", - "plugin-item.activate": "Activate", - "plugin-item.install": "Install", - "plugin-item.uninstall": "Uninstall", - "plugin-item.settings": "Settings", - "plugin-item.installed": "Installed", - "plugin-item.latest": "Latest", - "plugin-item.upgrade": "Upgrade", - "plugin-item.more-info": "For more information:", - "plugin-item.unknown": "Unknown", - "plugin-item.unknown-explanation": "The state of this plugin could not be determined, possibly due to a misconfiguration error.", + "plugin-item.themes": "القوالب", + "plugin-item.deactivate": "تعطيل", + "plugin-item.activate": "تفعيل", + "plugin-item.install": "تنصيب", + "plugin-item.uninstall": "إلغاء التنصيب", + "plugin-item.settings": "الإعدادات", + "plugin-item.installed": "المنصبة", + "plugin-item.latest": "الأحدث", + "plugin-item.upgrade": "ترقية", + "plugin-item.more-info": "لمزيد من المعلومات:", + "plugin-item.unknown": "غير معروف", + "plugin-item.unknown-explanation": "تعذر تحديد حالة هذه الإضافة، ربما بسبب خطأ في الإعدادات.", - "alert.enabled": "Plugin Enabled", - "alert.disabled": "Plugin Disabled", - "alert.upgraded": "Plugin Upgraded", - "alert.installed": "Plugin Installed", - "alert.uninstalled": "Plugin Uninstalled", - "alert.activate-success": "Please restart your NodeBB to fully activate this plugin", - "alert.deactivate-success": "Plugin successfully deactivated", - "alert.upgrade-success": "Please reload your NodeBB to fully upgrade this plugin", - "alert.install-success": "Plugin successfully installed, please activate the plugin.", - "alert.uninstall-success": "The plugin has been successfully deactivated and uninstalled.", + "alert.enabled": "الإضافة مفعلة", + "alert.disabled": "الإضافة معطلة", + "alert.upgraded": "الإضافة مرقاة", + "alert.installed": "الإضافة منصبة", + "alert.uninstalled": "تم إلغاء تنصيب الإضافة", + "alert.activate-success": "يرجى إعادة تشغيل NodeBB لتنشيط الإضافة بشكل بالكامل", + "alert.deactivate-success": "تم تعطيل الإضافة بنجاح", + "alert.upgrade-success": "يرجى إعادة تحميل NodeBB لترقية هذه الإضافة بشكل كامل", + "alert.install-success": "تم تثبيت الإضافة بنجاح، يرجى تفعيلها.", + "alert.uninstall-success": "تم تعطيل الإضافة وإلغاء تنصيبها بنجاح.", "alert.suggest-error": "

NodeBB could not reach the package manager, proceed with installation of latest version?

Server returned (%1): %2
", "alert.package-manager-unreachable": "

NodeBB could not reach the package manager, an upgrade is not suggested at this time.

", "alert.incompatible": "

Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.

", "alert.possibly-incompatible": "

No Compatibility Information Found

This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.

In the event that NodeBB cannot boot properly:

$ ./nodebb reset plugin=\"%1\"

Continue installation of latest version of this plugin?

", - "license.title": "Plugin License Information", + "license.title": "معلومات ترخيص الإضافة", "license.intro": "The plugin %1 is licensed under the %2. Please read and understand the license terms prior to activating this plugin.", - "license.cta": "Do you wish to continue with activating this plugin?" + "license.cta": "هل ترغب بالاستمرار في تفعيل هذه الإضافة؟" } diff --git a/public/language/ar/admin/general/dashboard.json b/public/language/ar/admin/general/dashboard.json index 9f1c6d8a4e..e9fd0fddec 100644 --- a/public/language/ar/admin/general/dashboard.json +++ b/public/language/ar/admin/general/dashboard.json @@ -1,69 +1,69 @@ { "forum-traffic": "Forum Traffic", - "page-views": "Page Views", - "unique-visitors": "Unique Visitors", - "users": "Users", - "posts": "Posts", - "topics": "Topics", - "page-views-seven": "Last 7 Days", - "page-views-thirty": "Last 30 Days", - "page-views-last-day": "Last 24 hours", - "page-views-custom": "Custom Date Range", - "page-views-custom-start": "Range Start", - "page-views-custom-end": "Range End", - "page-views-custom-help": "Enter a date range of page views you would like to view. If no date picker is available, the accepted format is YYYY-MM-DD", - "page-views-custom-error": "Please enter a valid date range in the format YYYY-MM-DD", + "page-views": "مشاهدات الصفحات", + "unique-visitors": "زائرين فريدين", + "users": "أعضاء", + "posts": "مشاركات", + "topics": "مواضيع", + "page-views-seven": "آخر 7 ايام", + "page-views-thirty": "آخر 30 يوماً", + "page-views-last-day": "آخر 24 ساعة", + "page-views-custom": "مدة زمنية مخصصة", + "page-views-custom-start": "بداية المدة", + "page-views-custom-end": "نهاية المده", + "page-views-custom-help": "أدخل نطاقا زمنيا لمرات مشاهدة الصفحات التي ترغب في عرضها. إذا لم يظهر منتقي التاريخ، فإن التنسيق المقبول هو YYYY-MM-DD", + "page-views-custom-error": "الرجاء إدخال نطاق تاريخ صالح بالتنسيق YYYY-MM-DD", - "stats.day": "Day", - "stats.week": "Week", - "stats.month": "Month", - "stats.all": "All Time", + "stats.day": "يوم", + "stats.week": "إسبوع", + "stats.month": "شهر", + "stats.all": "كل الوقت", - "updates": "Updates", - "running-version": "You are running NodeBB v%1.", - "keep-updated": "Always make sure that your NodeBB is up to date for the latest security patches and bug fixes.", - "up-to-date": "

You are up-to-date

", - "upgrade-available": "

A new version (v%1) has been released. Consider upgrading your NodeBB.

", - "prerelease-upgrade-available": "

This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.

", - "prerelease-warning": "

This is a pre-release version of NodeBB. Unintended bugs may occur.

", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator.", + "updates": "تحديثات", + "running-version": "المنتدى يعمل حاليا على NodeBB الإصدار%1.", + "keep-updated": "تأكد دائما من أن NodeBB يعمل على احدث إصدار للحصول على أحدث التصحيحات الأمنية وإصلاحات الأخطاء.", + "up-to-date": "

المنتدى يعمل على أحدث إصدار

", + "upgrade-available": "

نسخة جديدة (الإصدار %1) تم إصدارها. خذ بعين الاعتبار ترقية NodeBB الخاص بك.

", + "prerelease-upgrade-available": "

نسخة ما قبل الإصدار من NodeBB هذه قديمة. إصدار أحدث (الإصدار %1) تم إصداره. خذ بعين الاعتبار ترقية NodeBB الخاص بك.

", + "prerelease-warning": "

هذه نسخة ماقبل الإصدار من NodeBB. قد تحدث أخطاء غير مقصودة.

", + "running-in-development": "المنتدى قيد التشغيل في وضع \"المطورين\". وقد تكون هناك ثغرات أمنية مفتوحة؛ من فضلك تواصل مع مسؤول نظامك.", - "notices": "Notices", - "restart-not-required": "Restart not required", - "restart-required": "Restart required", - "search-plugin-installed": "Search Plugin installed", - "search-plugin-not-installed": "Search Plugin not installed", - "search-plugin-tooltip": "Install a search plugin from the plugin page in order to activate search functionality", + "notices": "إشعارات", + "restart-not-required": "إعادة التشغيل غير مطلوب", + "restart-required": "إعادة التشغيل مطلوبة", + "search-plugin-installed": "إضافة البحث منصبة", + "search-plugin-not-installed": "إضافة البحث غير منصبة", + "search-plugin-tooltip": "نصب إضافة البحث من صفحة الإضافات البرمجية لتنشيط وظيفة البحث", - "control-panel": "System Control", - "reload": "Reload", - "restart": "Restart", - "restart-warning": "Reloading or Restarting your NodeBB will drop all existing connections for a few seconds.", - "maintenance-mode": "Maintenance Mode", - "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", - "realtime-chart-updates": "Realtime Chart Updates", + "control-panel": "التحكم بالنظام", + "reload": "إعادة تحمبل", + "restart": "إعادة تشغيل", + "restart-warning": "إعادة تحميل او تشغيل NodeBB سوف يؤدي لقطع جميع الإتصالات لبضع ثواني.", + "maintenance-mode": "وضع الصيانة", + "maintenance-mode-title": "انقر هنا لإعداد وضع الصيانة لـNodeBB", + "realtime-chart-updates": "التحديث الفوري للرسم البياني", - "active-users": "Active Users", - "active-users.users": "Users", - "active-users.guests": "Guests", - "active-users.total": "Total", + "active-users": "المستخدمين النشطين", + "active-users.users": "الأعضاء", + "active-users.guests": "الزوار", + "active-users.total": "المجموع", "active-users.connections": "Connections", - "anonymous-registered-users": "Anonymous vs Registered Users", - "anonymous": "Anonymous", - "registered": "Registered", + "anonymous-registered-users": "المجهولين مقابل المستخدمين المسجلين", + "anonymous": "مجهول", + "registered": "مسجل", - "user-presence": "User Presence", - "on-categories": "On categories list", - "reading-posts": "Reading posts", - "browsing-topics": "Browsing topics", - "recent": "Recent", - "unread": "Unread", + "user-presence": "تواجد المستخدمين", + "on-categories": "في قائمة الأقسام", + "reading-posts": "قراءة المشاركات", + "browsing-topics": "تصفح المواضيع", + "recent": "الأخيرة", + "unread": "غير مقروء", - "high-presence-topics": "High Presence Topics", + "high-presence-topics": "مواضيع ذات حضور قوي", - "graphs.page-views": "Page Views", - "graphs.unique-visitors": "Unique Visitors", - "graphs.registered-users": "Registered Users", - "graphs.anonymous-users": "Anonymous Users" + "graphs.page-views": "مشاهدات الصفحة", + "graphs.unique-visitors": "زوار فريدين", + "graphs.registered-users": "مستخدمين مسجلين", + "graphs.anonymous-users": "مستخدمين مجهولين" } diff --git a/public/language/ar/admin/general/languages.json b/public/language/ar/admin/general/languages.json index bdd57849b3..581e028ade 100644 --- a/public/language/ar/admin/general/languages.json +++ b/public/language/ar/admin/general/languages.json @@ -1,6 +1,6 @@ { - "language-settings": "Language Settings", - "description": "The default language determines the language settings for all users who are visiting your forum.
Individual users can override the default language on their account settings page.", - "default-language": "Default Language", - "auto-detect": "Auto Detect Language Setting for Guests" + "language-settings": "اعدادات اللغة", + "description": "تُحدد اللغة الافتراضية إعدادات اللغة لجميع المستخدمين الذين يزورون المنتدى.
يمكن للأعضاء تجاوز اللغة الافتراضية من خلال صفحة إعدادات الحساب الخاصة بهم.", + "default-language": "اللغة الافتراضية", + "auto-detect": "الكشف عن إعدادات اللغة للزوار بشكل آلي" } \ No newline at end of file diff --git a/public/language/ar/admin/menu.json b/public/language/ar/admin/menu.json index d42af99bce..07fe387d20 100644 --- a/public/language/ar/admin/menu.json +++ b/public/language/ar/admin/menu.json @@ -1,34 +1,34 @@ { - "section-general": "General", - "general/dashboard": "Dashboard", - "general/homepage": "Home Page", - "general/navigation": "Navigation", - "general/languages": "Languages", - "general/sounds": "Sounds", - "general/social": "Social", + "section-general": "عام", + "general/dashboard": "اللوحة الرئيسية", + "general/homepage": "الصفحة الرئيسية", + "general/navigation": "التصفح", + "general/languages": "اللغات", + "general/sounds": "الأصوات", + "general/social": "شبكات التواصل", - "section-manage": "Manage", - "manage/categories": "Categories", - "manage/tags": "Tags", - "manage/users": "Users", - "manage/registration": "Registration Queue", - "manage/post-queue": "Post Queue", - "manage/groups": "Groups", - "manage/ip-blacklist": "IP Blacklist", + "section-manage": "إدارة", + "manage/categories": "الأقسام", + "manage/tags": "الكلمات المفتاحية", + "manage/users": "الأعضاء", + "manage/registration": "قائمة انتظار التسجيل", + "manage/post-queue": "قائمة انتظار المشاركة", + "manage/groups": "المجموعات", + "manage/ip-blacklist": "قائمة حظر عناوين IP", - "section-settings": "Settings", - "settings/general": "General", - "settings/reputation": "Reputation", - "settings/email": "Email", - "settings/user": "User", - "settings/group": "Group", - "settings/guest": "Guests", - "settings/uploads": "Uploads", - "settings/post": "Post", - "settings/chat": "Chat", - "settings/pagination": "Pagination", - "settings/tags": "Tags", - "settings/notifications": "Notifications", + "section-settings": "إعدادات", + "settings/general": "عامة", + "settings/reputation": "السمعة", + "settings/email": "البريد الإلكتروني", + "settings/user": "الأعضاء", + "settings/group": "المجموعات", + "settings/guest": "الزوار", + "settings/uploads": "الرفع", + "settings/post": "المشاركة", + "settings/chat": "الدردشة", + "settings/pagination": "ترقيم الصفحات", + "settings/tags": "الكلمات المفتاحية", + "settings/notifications": "التنبيهات", "settings/cookies": "Cookies", "settings/web-crawler": "Web Crawler", "settings/sockets": "Sockets", @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/ar/admin/settings/notifications.json b/public/language/ar/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/ar/admin/settings/notifications.json +++ b/public/language/ar/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ar/admin/settings/post.json b/public/language/ar/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/ar/admin/settings/post.json +++ b/public/language/ar/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/ar/admin/settings/uploads.json b/public/language/ar/admin/settings/uploads.json index a458870354..50fc299283 100644 --- a/public/language/ar/admin/settings/uploads.json +++ b/public/language/ar/admin/settings/uploads.json @@ -1,28 +1,28 @@ { - "posts": "Posts", - "allow-files": "Allow users to upload regular files", - "private": "Make uploaded files private", - "max-image-width": "Resize images down to specified width (in pixels)", - "max-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)", - "max-file-size": "Maximum File Size (in KiB)", - "max-file-size-help": "(in kibibytes, default: 2048 KiB)", - "allow-topic-thumbnails": "Allow users to upload topic thumbnails", - "topic-thumb-size": "Topic Thumb Size", - "allowed-file-extensions": "Allowed File Extensions", - "allowed-file-extensions-help": "Enter comma-separated list of file extensions here (e.g. pdf,xls,doc). An empty list means all extensions are allowed.", - "profile-avatars": "Profile Avatars", - "allow-profile-image-uploads": "Allow users to upload profile images", - "convert-profile-image-png": "Convert profile image uploads to PNG", - "default-avatar": "Custom Default Avatar", - "upload": "Upload", - "profile-image-dimension": "Profile Image Dimension", - "profile-image-dimension-help": "(in pixels, default: 128 pixels)", - "max-profile-image-size": "Maximum Profile Image File Size", - "max-profile-image-size-help": "(in kibibytes, default: 256 KiB)", - "max-cover-image-size": "Maximum Cover Image File Size", - "max-cover-image-size-help": "(in kibibytes, default: 2,048 KiB)", - "keep-all-user-images": "Keep old versions of avatars and profile covers on the server", - "profile-covers": "Profile Covers", - "default-covers": "Default Cover Images", - "default-covers-help": "Add comma-separated default cover images for accounts that don't have an uploaded cover image" + "posts": "المشاركات", + "allow-files": "السماح للأعضاء بتحميل الملفات الإعتيادية", + "private": "جعل الملفات التي تم رفعها خاصة", + "max-image-width": "تغيير حجم الصور إلى عرض محدد (بالبكسل)", + "max-image-width-help": "(بالبكسل، الافتراضي: 760 بكسل، ضع إلى 0 لتعطيل الخاصية)", + "max-file-size": "الحد الأقصى لحجم الملف (بالكيبيبايت)", + "max-file-size-help": "(بالكيبيبايت، الافتراضي: 2048)", + "allow-topic-thumbnails": "السماح للاعضاء برفع الصور المصغرة للموضوع", + "topic-thumb-size": "حجم الصورة المصغرة للموضوع", + "allowed-file-extensions": "إمتدادات الملفات المسموح بها", + "allowed-file-extensions-help": "أدخل قائمة بامتدادات الملفات مفصولة بفواصل (مثال: pdf,xls,doc). القائمة الفارغة تعني أن كل الامتدادات مسموح بها.", + "profile-avatars": "الصورة الرمزية للملف الشخصي", + "allow-profile-image-uploads": "السماح للأعضاء برفع الصور الرمزية", + "convert-profile-image-png": "تحويل إمتداد الصور الرمزية المرفوعه الى PNG", + "default-avatar": "الصورة الرمزية الافتراضية", + "upload": "رفع", + "profile-image-dimension": "أبعاد الصورة الرمزية", + "profile-image-dimension-help": "(بالبكسل، الافتراضي: 128 بكسل)", + "max-profile-image-size": "الحد الأقصى لحجم الصورة الرمزية", + "max-profile-image-size-help": "(بالكيبيبايت، الافتراضي: 256)", + "max-cover-image-size": "الحد الأقصى لحجم صورة الغلاف", + "max-cover-image-size-help": "(بالكيبيبايت، الافتراضي: 2,048)", + "keep-all-user-images": "الاحتفاظ بالنسخ القديمة من الصور الرمزية وصور الغلاف في السيرفر", + "profile-covers": "غلاف الملف الشخصي", + "default-covers": "صورة الغلاف الافتراضية", + "default-covers-help": "اضف صور الغلاف الافتراضية متبوعة بفواصل لاستخدامها في الحسابات التي لا تحتوي على صور غلاف مرفوعة" } diff --git a/public/language/ar/admin/settings/user.json b/public/language/ar/admin/settings/user.json index a8bc2b176e..3d53253014 100644 --- a/public/language/ar/admin/settings/user.json +++ b/public/language/ar/admin/settings/user.json @@ -1,55 +1,57 @@ { - "authentication": "Authentication", - "allow-local-login": "Allow local login", - "require-email-confirmation": "Require Email Confirmation", - "email-confirm-interval": "User may not resend a confirmation email until", - "email-confirm-email2": "minutes have elapsed", - "allow-login-with": "Allow login with", - "allow-login-with.username-email": "Username or Email", - "allow-login-with.username": "Username Only", - "allow-login-with.email": "Email Only", - "account-settings": "Account Settings", - "disable-username-changes": "Disable username changes", - "disable-email-changes": "Disable email changes", - "disable-password-changes": "Disable password changes", - "allow-account-deletion": "Allow account deletion", - "user-info-private": "Hide user list and data from guests", - "hide-fullname": "Hide fullname from users", - "hide-email": "Hide email from users", - "themes": "Themes", - "disable-user-skins": "Prevent users from choosing a custom skin", - "account-protection": "Account Protection", - "login-attempts": "Login attempts per hour", - "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", - "lockout-duration": "Account Lockout Duration (minutes)", - "login-days": "Days to remember user login sessions", - "password-expiry-days": "Force password reset after a set number of days", - "registration": "User Registration", - "registration-type": "Registration Type", - "registration-type.normal": "Normal", - "registration-type.admin-approval": "Admin Approval", - "registration-type.admin-approval-ip": "Admin Approval for IPs", - "registration-type.invite-only": "Invite Only", - "registration-type.admin-invite-only": "Admin Invite Only", - "registration-type.disabled": "No registration", - "registration-type.help": "Normal - Users can register from the /register page.
\nAdmin Approval - User registrations are placed in an approval queue for administrators.
\nAdmin Approval for IPs - Normal for new users, Admin Approval for IP addresses that already have an account.
\nInvite Only - Users can invite others from the users page.
\nAdmin Invite Only - Only administrators can invite others from users and admin/manage/users pages.
\nNo registration - No user registration.
", - "registration.max-invites": "Maximum Invitations per User", - "max-invites": "Maximum Invitations per User", - "max-invites-help": "0 for no restriction. Admins get infinite invitations
Only applicable for \"Invite Only\"", - "invite-expiration": "Invite expiration", - "invite-expiration-help": "# of days invitations expire in.", - "min-username-length": "Minimum Username Length", - "max-username-length": "Maximum Username Length", - "min-password-length": "Minimum Password Length", - "min-password-strength": "Minimum Password Strength", - "max-about-me-length": "Maximum About Me Length", - "terms-of-use": "Forum Terms of Use (Leave blank to disable)", - "user-search": "User Search", - "user-search-results-per-page": "Number of results to display", - "default-user-settings": "Default User Settings", - "show-email": "Show email", - "show-fullname": "Show fullname", - "restrict-chat": "Only allow chat messages from users I follow", + "authentication": "المصادقة", + "allow-local-login": "السماح بتسجيل الدخول المحلي", + "require-email-confirmation": "يطلب تأكيد البريد الإلكتروني", + "email-confirm-interval": "لا يمكن للمستخدم إعادة إرسال رسالة تأكيد البريد الالكتروني حتى مرور", + "email-confirm-email2": "دقائق", + "allow-login-with": "السماح بتسجيل الدخول باستخدام", + "allow-login-with.username-email": "اسم المستخدم أو البريد الالكتروني", + "allow-login-with.username": "اسم المستخدم فقط", + "allow-login-with.email": "البريد الالكتروني فقط", + "account-settings": "إعدادت الحساب", + "disable-username-changes": "عدم السماح بتغيير اسم المستخدم", + "disable-email-changes": "عدم السماح بتغيير البريد الالكتروني", + "disable-password-changes": "عدم السماح بتغيير كلمة المرور", + "allow-account-deletion": "السماح بحذف الحساب", + "user-info-private": "إخفاء قائمة المستخدم والبيانات عن الزوار", + "hide-fullname": "إخفاء الإسم الكامل عن المستخدمين", + "hide-email": "إخفاء البريد الإلكتروني عن المستخدمين", + "themes": "القوالب", + "disable-user-skins": "منع المستخدمين من اختيار سمة مخصص", + "account-protection": "حماية الحساب", + "admin-relogin-duration": "المدة حتى طلب إعادة تسجيل الدخول للإدارة (دقائق)", + "admin-relogin-duration-help": "بعد مرور وقت معين، يتوجب إعادة تسجيل الدخول للوصول إلى قسم الإدارة، قم بتعيين القيمة الى 0 لتعطيل الخيار", + "login-attempts": "عدد محاولات تسجيل الدخول في الساعة", + "login-attempts-help": "إذا تجاوزت محاولات تسجيل الدخول لمستخدم معين العدد المحدد، فسوف يتم تأمين الحساب ومنعه من الدخول لمدة من الوقت", + "lockout-duration": "مدة تأمين الحساب (دقائق)", + "login-days": "عدد الأيام لتذكر جلسات تسجيل دخول المستخدم", + "password-expiry-days": "فرض عملية تغيير كلمة المرور بعد مرور عدد محدد من الأيام", + "registration": "تسجيل المستخدم", + "registration-type": "نوع التسجيل", + "registration-type.normal": "عادي", + "registration-type.admin-approval": "بموافقة الإدارة", + "registration-type.admin-approval-ip": "بموافقة الإدارة لعناوين IP", + "registration-type.invite-only": "بالدعوات فقط", + "registration-type.admin-invite-only": "بالدعوات من قبل الإدارة فقط", + "registration-type.disabled": "لا يوجد تسجيل", + "registration-type.help": "عادي - بإمكان المستخدمين التسجيل من خلال صفحة /التسجيل.
\nبموافقة الإدارة - يتم وضع قائمة تسجيلات المستخدمين في قائمة إنتظار موافقة الإدارة.
\nبموافقة الإدارة لعناوين IP - عادي بالنسبة للمستخدمين الجدد، ويتطلب موافقة الإدارة للتسجيل من عناوين IP تم التسجيل بإستخدامها مسبقاً.
\nبالدعوات فقط - بإمكان المستخدمين إرسال دعوات من خلال صفحة الأعضاء.
\nبالدعوات من قبل الإدارة فقط - فقط المراء بإمكانهم إرسال الدعوات من خلال صفحة الأعضاء و صفحات الإدارة/المشرفين/الأعضاء.
\nلا يوجد تسجيل - إغلاق خيار التسجيل بالكامل.
", + "registration.max-invites": "الحد الأقصى للدعوات لكل عضو", + "max-invites": "الحد الأقصى للدعوات لكل عضو", + "max-invites-help": "0 لعدم تحديد قيود، الإدارة تحصل على دعوات لامحدودة
هذا الخيار يعمل فقط عند تحديد خيار \"بالدعوات فقط\"", + "invite-expiration": "مدة صلاحية الدعوة", + "invite-expiration-help": "عدد الأيام حتى انتهاء صلاحية الدعوة.", + "min-username-length": "الحد الأدنى لطول اسم المستخدم", + "max-username-length": "الحد الأقصى لطول اسم المستخدم", + "min-password-length": "الحد الأدنى لطول كلمة المرور", + "min-password-strength": "الحد الأدنى لقوة كلمة المرور", + "max-about-me-length": "الحد الأعلى من الأحرف في حقل \"عني\"", + "terms-of-use": "شروط استخدام المنتدى (تترك فارغة لتعطيلها)", + "user-search": "بحث الأعضاء", + "user-search-results-per-page": "عدد النتائج المراد عرضها", + "default-user-settings": "إعدادات الأعضاء الافتراضية", + "show-email": "عرض البريد الإلكتروني", + "show-fullname": "عرض الاسم الكامل", + "restrict-chat": "السماح فقط برسائل الدردشة من المستخدمين الذين أتبعهم", "outgoing-new-tab": "Open outgoing links in new tab", "topic-search": "Enable In-Topic Searching", "digest-freq": "Subscribe to Digest", diff --git a/public/language/ar/category.json b/public/language/ar/category.json index 6f61d752c6..6c86d47b03 100644 --- a/public/language/ar/category.json +++ b/public/language/ar/category.json @@ -1,20 +1,20 @@ { - "category": "فئة", - "subcategories": "فئة فرعية", + "category": "قسم", + "subcategories": "قسم فرعي", "new_topic_button": "موضوع جديد", - "guest-login-post": "سجل بالدخول للرد", - "no_topics": "لا توجد مواضيع في هذه الفئةلم لا تحاول إنشاء موضوع؟
", + "guest-login-post": "سجل الدخول للمشاركة", + "no_topics": "لا توجد مواضيع في هذه القسملم لا تحاول إنشاء موضوع؟
", "browsing": "تصفح", "no_replies": "لم يرد أحد", "no_new_posts": "لا توجد مشاركات جديدة.", - "share_this_category": "انشر هذه الفئة", + "share_this_category": "شارك هذا القسم", "watch": "تابع", "ignore": "تجاهل", "watching": "متابع", "ignoring": "متجاهل", "watching.description": "أظهر المواضيع في غير مقروء", "ignoring.description": "لا تظهر المواضيع في غير مقروء", - "watch.message": "You are now watching updates from this category and all subcategories", - "ignore.message": "You are now ignoring updates from this category and all subcategories", - "watched-categories": "الفئات المتابعة" + "watch.message": "أنت الآن تتابع التحديثات من هذا القسم وجميع الأقسام الفرعية", + "ignore.message": "أنت الآن تتجاهل التحديثات من هذا القسم وجميع الأقسام الفرعية", + "watched-categories": "الأقسام المُتابعة" } \ No newline at end of file diff --git a/public/language/ar/email.json b/public/language/ar/email.json index 8e0fba7424..9b5b49fd1b 100644 --- a/public/language/ar/email.json +++ b/public/language/ar/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "تم إرسال هذا الإشعار بوجودة محادثة جديدة وفقا لخيارات تسجيلك.", "notif.post.cta": "انقر هنا لقراءة الموضوع بأكمله", "notif.post.unsub.info": "تم إشعارك بهذه المشاركة بناءً على الخيارات التي سبق وأن حددتها.", + "notif.cta": "Click here to go to forum", "test.text1": "هذه رسالة تجريبية للتأكد من صحة إعدادت الرسائل الإلكترونية في منتدى NodeBB خاصتك.", "unsub.cta": "انقر هنا لتغيير تلك الإعدادات", "banned.subject": "You have been banned from %1", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 75f6a0ee07..56700c46ef 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "ليس لديك سمعة تكفي لإضافة صوت سلبي لهذا الموضوع", "not-enough-reputation-to-flag": "ليس لديك سمعة تكفي للإشعار بموضوع مخل", "already-flagged": "لقد بلغت عن هذه المشاركة من قبل.", + "self-vote": "You cannot vote on your own post", "reload-failed": "المنتدى واجه مشكلة أثناء إعادة التحميل: \"%1\". سيواصل المنتدى خدمة العملاء السابقين لكن يجب عليك إلغاء أي تغيير قمت به قبل إعادة التحميل.", "registration-error": "حدث خطأ أثناء التسجيل", "parse-error": "حدث خطأ ما أثناء تحليل استجابة الخادم", "wrong-login-type-email": "الرجاء استعمال بريدك اﻹلكتروني للدخول", "wrong-login-type-username": "الرجاء استعمال اسم المستخدم الخاص بك للدخول", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "لقد قمت بدعوة الحد الأقصى من الأشخاص (%1 من %2)", "no-session-found": "لم دخول مسجل!", "not-in-room": "المستخدم غير موجود في الغرفة.", @@ -132,5 +134,6 @@ "no-users-selected": "لا يوجد مستخدم محدد.", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "يبدو أن فترة التسجيل لم تعد قائمة او هي غير مطابقة مع الخادم. يرجى إعادة تحميل هذه الصفحة." + "invalid-session-text": "يبدو أن فترة التسجيل لم تعد قائمة او هي غير مطابقة مع الخادم. يرجى إعادة تحميل هذه الصفحة.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ar/global.json b/public/language/ar/global.json index 73e23bfb28..97f55f0500 100644 --- a/public/language/ar/global.json +++ b/public/language/ar/global.json @@ -4,7 +4,7 @@ "buttons.close": "أغلق", "403.title": "غير مسموح بالدخول", "403.message": "يبدو أنك قد تعثرت على صفحة لا تمتلك الصلاحية للدخول إليها", - "403.login": "حاول أن تسجل دخولك.", + "403.login": "ربما يجب عليك تسجل دخولك.", "404.title": "لم يتم العثور", "404.message": "الصفحة غير موجودة. العودة لـ الرئيسية", "500.title": "خطأ داخلي", @@ -13,19 +13,19 @@ "400.message": "الرابط غير صحيح. رجاءًا تأكد من الرابط أو ارجع لـ الرئيسية", "register": "تسجيل", "login": "دخول", - "please_log_in": "المرجو تسجيل الدخول", + "please_log_in": "الرجاء تسجيل الدخول", "logout": "تسجيل الخروج", "posting_restriction_info": "إضافة مشاركات جديد حكر على الأعضاء المسجلين، انقر هنا لتسجيل الدخول.", "welcome_back": "مرحبًا بعودتك", "you_have_successfully_logged_in": "تم سجيل الدخول بنجاح", "save_changes": "حفظ التغييرات", - "save": "Save", + "save": "حفظ", "close": "أغلق", "pagination": "الصفحات", "pagination.out_of": "%1 من %2", "pagination.enter_index": "أدخل الرقم التسلسلي", - "header.admin": "مدبر نظام", - "header.categories": "الفئات", + "header.admin": "مدير النظام", + "header.categories": "الأقسام", "header.recent": "حديث", "header.unread": "غير مقروء", "header.tags": "وسم", @@ -37,9 +37,9 @@ "header.search": "بحث", "header.profile": "ملف", "header.navigation": "الاستكشاف", - "notifications.loading": "تحميل التبليغات", + "notifications.loading": "تحميل التنبيهات", "chats.loading": "تحميل الدردشات", - "motd.welcome": "مرحبا بكم NodeBB، منصة مناقشة المستقبل", + "motd.welcome": "مرحبا بكم في NodeBB، منصة المناقشة المستقبلية.", "previouspage": "الصفحة السابقة", "nextpage": "الصفحة التالية", "alert.success": "نجاح", @@ -75,7 +75,7 @@ "norecenttopics": "لاوجود لمواضيع جديدة", "recentposts": "آخر المشاركات", "recentips": "آخر عناوين ال IP التي سجلت الدخول", - "moderator_tools": "Moderator Tools", + "moderator_tools": "أدوات المشرف", "away": "غير متواجد", "dnd": "عدم الإزعاج", "invisible": "مخفي", @@ -85,7 +85,7 @@ "guest": "زائر", "guests": "الزوار", "updated.title": "تم تحديث المنتدى", - "updated.message": "لقد تم تحديث المنتدى إلى آخر نسخة للتو. المرجو إعادة تحميل الصفحة.", + "updated.message": "لقد تم تحديث المنتدى إلى آخر نسخة للتو. إضغط هنا لإعادة تحميل الصفحة.", "privacy": "الخصوصية", "follow": "متابعة", "unfollow": "إلغاء المتابعة", @@ -97,13 +97,13 @@ "upload_file": "ارفع ملف", "upload": "ارفع", "allowed-file-types": "صيغ الملفات المدعومة هي 1%", - "unsaved-changes": "لديك تغييرات لم تحفظ. هل أنت متأكد من تغيير الصفحة؟", + "unsaved-changes": "لديك تغييرات لم تحفظ. هل أنت متأكد من رغبتك بمغادرة الصفحة؟", "reconnecting-message": "يبدو أن اتصالك لـ %1 قد فقد. رجاءًا أنتظر ثم حاول الإتصال مرة اخرى.", - "play": "Play", - "cookies.message": "This website uses cookies to ensure you get the best experience on our website.", - "cookies.accept": "Got it!", - "cookies.learn_more": "Learn More", - "edited": "Edited", - "disabled": "Disabled", - "select": "Select" + "play": "تشغيل", + "cookies.message": "هذا الموقع يستخدم ملفات تعريف الارتباط لضمان حصولك على أفضل تجربة على موقعنا.", + "cookies.accept": "فهمت الأمر!", + "cookies.learn_more": "أعرف المزيد", + "edited": "حُرِر", + "disabled": "معطل", + "select": "تحديد" } \ No newline at end of file diff --git a/public/language/ar/login.json b/public/language/ar/login.json index 60bf2773af..5a7d602a0d 100644 --- a/public/language/ar/login.json +++ b/public/language/ar/login.json @@ -5,8 +5,8 @@ "remember_me": "تذكرني؟", "forgot_password": "نسيت كلمة المرور؟", "alternative_logins": "تسجيلات الدخول البديلة", - "failed_login_attempt": "Login Unsuccessful", + "failed_login_attempt": "تسجيل الدخول غير ناجح", "login_successful": "قمت بتسجيل الدخول بنجاح!", "dont_have_account": "لا تملك حساب؟", - "logged-out-due-to-inactivity": "You have been logged out of the Admin Control Panel due to inactivity" + "logged-out-due-to-inactivity": "لقد تم تسجيل خروجك من لوحة تحكم بسبب عدم نشاطك" } \ No newline at end of file diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json index 089a76e70c..9a934b2f3a 100644 --- a/public/language/ar/notifications.json +++ b/public/language/ar/notifications.json @@ -9,6 +9,7 @@ "continue_to": "استمر إلى %1", "return_to": "عودة إى %1", "new_notification": "تنبيه جديد", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "لديك تنبيهات غير مقروءة.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "تم التحقق من عنوان البريد الإلكتروني", "email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.", "email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.", - "email-confirm-sent": "تم إرسال بريد التفعيل." + "email-confirm-sent": "تم إرسال بريد التفعيل.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ar/register.json b/public/language/ar/register.json index c6ccf2231e..9fe1af535c 100644 --- a/public/language/ar/register.json +++ b/public/language/ar/register.json @@ -2,8 +2,8 @@ "register": "تسجيل", "cancel_registration": "إلغاء التسجيل", "help.email": "افتراضيا، سيتم إخفاء بريدك الإلكتروني من العامة.", - "help.username_restrictions": "اسم مستخدم فريدة من نوعها بين1% و2% حرفا. يمكن للآخرين ذكرك @ <'span id='your-username> اسم المستخدم .", - "help.minimum_password_length": "كلمة المرور يجب أن تكون على الأقل بها 1% أحرف", + "help.username_restrictions": "اسم مستخدم فريدة من نوعها بين 1% و 2% حرفا. بإمكان الآخرين مناداتك بـ @اسم المستخدم.", + "help.minimum_password_length": "كلمة المرور يجب أن تتكون على الأقل من 1% أحرف/حروف", "email_address": "عنوان البريد الإلكتروني", "email_address_placeholder": "ادخل عنوان البريد الإلكتروني", "username": "اسم المستخدم", @@ -16,8 +16,8 @@ "alternative_registration": "طريقة تسجيل بديلة", "terms_of_use": "شروط الاستخدام", "agree_to_terms_of_use": "أوافق على شروط الاستخدام", - "terms_of_use_error": "You must agree to the Terms of Use", - "registration-added-to-queue": "Your registration has been added to the approval queue. You will receive an email when it is accepted by an administrator.", - "interstitial.intro": "We require some additional information before we can create your account.", - "interstitial.errors-found": "We could not complete your registration:" + "terms_of_use_error": "يجب عليك الموافقة على شروط الاستخدام", + "registration-added-to-queue": "تمت إضافتك في قائمة الإنتضار. ستتلقى رسالة إلكترونية عند الموافقة على تسجيلك من قبل الإدارة.", + "interstitial.intro": "نحتاج إلى بعض المعلومات الإضافية قبل أن نتمكن من إنشاء حسابك.", + "interstitial.errors-found": "تعذر علينا إتمام عملية التسجيل:" } \ No newline at end of file diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 4a5c8789b0..851e10c292 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "هل أنت متأكد أنك تريد استعادة هذا الموضوع؟", "thread_tools.purge": "تطهير الموضوع", "thread_tools.purge_confirm": "هل أنت متأكد أنك تريد تطهير هذا الموضوع؟", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "تم نقل هذا الموضوع إلى %1 بنجاح", "post_delete_confirm": "هل أنت متأكد أنك تريد حذف هذه المشاركة؟", "post_restore_confirm": "هل أنت متأكد أنك تريد استعادة هذه المشاركة؟", @@ -89,6 +91,7 @@ "fork_pid_count": "1% مشاركة محددة", "fork_success": "تم إنشاء فرع للموضوع بنجاح! إضغط هنا لمعاينة الفرع.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "أدخل عنوان موضوعك هنا...", "composer.handle_placeholder": "اﻹسم", "composer.discard": "نبذ التغييرات", diff --git a/public/language/ar/user.json b/public/language/ar/user.json index 6436c70082..76b908b909 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -7,13 +7,13 @@ "email": "البريد الإلكتروني", "confirm_email": "تأكيد عنوان البريد الإلكتروني", "account_info": "معلومات الحساب", - "ban_account": "Ban Account", + "ban_account": "حظر الحساب", "ban_account_confirm": "هل تريد حقاً حظر هاذا العضو؟", - "unban_account": "Unban Account", + "unban_account": "إزالة حظر الحساب", "delete_account": "حذف الحساب", "delete_account_confirm": "هل أن متأكد أنك تريد حذف حسابك؟
هذه العملية غير قابلة للإلغاء ولن يكون بالإمكان استعادة بياناتك

أدخل اسم المستخدم الخاص بك لتأكيد عملية الحذف", - "delete_this_account_confirm": "Are you sure you want to delete this account?
This action is irreversible and you will not be able to recover any data

", - "account-deleted": "Account deleted", + "delete_this_account_confirm": "هل انت متأكد من رغبتك بحذف هذا الحساب؟
هذا الإجراء لا رجعة فيه ولن تتمكن من استرداد أي بيانات

", + "account-deleted": "تم حذف الحساب", "fullname": "الاسم الكامل", "website": "الموقع الإلكتروني", "location": "الموقع", @@ -25,15 +25,15 @@ "reputation": "السمعة", "bookmarks": "Bookmarks", "watched": "متابع", - "ignored": "Ignored", + "ignored": "تم تجاهله", "followers": "المتابعون", "following": "يتابع", "aboutme": "معلومة عنك او السيرة الذاتية", "signature": "توقيع", "birthday": "عيد ميلاد", "chat": "محادثة", - "chat_with": "Continue chat with %1", - "new_chat_with": "Start new chat with %1", + "chat_with": "متابعة الدردشة مع %1", + "new_chat_with": "بدء دردشة جديدة مع %1", "flag-profile": "Flag Profile", "follow": "تابع", "unfollow": "إلغاء المتابعة", @@ -44,7 +44,7 @@ "change_email": "تغيير البريد اﻹلكتروني", "edit": "تعديل", "edit-profile": "تعديل الملف الشخصي", - "default_picture": "Default Icon", + "default_picture": "أيقونة افتراضية", "uploaded_picture": "الصورة المرفوعة", "upload_new_picture": "رفع صورة جديدة", "upload_new_picture_from_url": "رفع صورة جديدة من رابط", @@ -58,17 +58,17 @@ "change_password_success": "تم تحديث كلمة السر خاصتك.", "confirm_password": "تأكيد كلمة السر", "password": "كلمة السر", - "username_taken_workaround": "اسم المستخدم الذي اخترته سبق أخذه، لذا تم تغييره قليلا. أن الآن مسجل تحت الاسم %1", - "password_same_as_username": "Your password is the same as your username, please select another password.", - "password_same_as_email": "Your password is the same as your email, please select another password.", - "weak_password": "Weak password.", + "username_taken_workaround": "اسم المستخدم الذي اخترته مستخدم سابقا، لذلك قمنا بتغييره لك قليلا. أنت الآن مسجل بالاسم %1", + "password_same_as_username": "كلمة المرور مطابقة لاسم المستخدم الخاص بك، يرجى تحديد كلمة مرور أخرى.", + "password_same_as_email": "كلمة المرور مطابقة لبريدك الإلكتروني، يرجى تحديد كلمة مرور أخرى.", + "weak_password": "كلمة مرور ضعيفة.", "upload_picture": "ارفع الصورة", "upload_a_picture": "رفع صورة", - "remove_uploaded_picture": "Remove Uploaded Picture", - "upload_cover_picture": "Upload cover picture", - "remove_cover_picture_confirm": "Are you sure you want to remove the cover picture?", - "crop_picture": "Crop picture", - "upload_cropped_picture": "Crop and upload", + "remove_uploaded_picture": "إزالة الصورة المرفوعة", + "upload_cover_picture": "رفع صورة الغلاف", + "remove_cover_picture_confirm": "هل تريد بالتأكيد إزالة صورة الغلاف؟", + "crop_picture": "إقتصاص الصورة", + "upload_cropped_picture": "إقتصاص ورفع", "settings": "خيارات", "show_email": "أظهر بريدي الإلكتروني", "show_fullname": "أظهر اسمي الكامل", @@ -79,61 +79,67 @@ "digest_daily": "يوميا", "digest_weekly": "أسبوعيًّا", "digest_monthly": "شهريًّا", - "send_chat_notifications": "استلام رسالة إلكترونية عند ورود محادثة وأنا غير متصل.", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "تغيير بعض اﻹعدادات يتطلب تحديث الصفحة. إضغط هنا لتحديث الصفحة", - "has_no_follower": "هذا المستخدم ليس لديه أي متابع :(", + "has_no_follower": "هذا المستخدم ليس لديه أية متابعين :(", "follows_no_one": "هذا المستخدم لا يتابع أحد :(", - "has_no_posts": "This user hasn't posted anything yet.", - "has_no_topics": "This user hasn't posted any topics yet.", - "has_no_watched_topics": "This user hasn't watched any topics yet.", - "has_no_ignored_topics": "This user hasn't ignored any topics yet.", - "has_no_upvoted_posts": "This user hasn't upvoted any posts yet.", - "has_no_downvoted_posts": "This user hasn't downvoted any posts yet.", - "has_no_voted_posts": "This user has no voted posts", + "has_no_posts": "هذا المستخدم لم يشارك حتى الآن.", + "has_no_topics": "هذا المستخدم لم يكتب أي موضوع حتى الآن.", + "has_no_watched_topics": "هذا المستخدم لم يقم بمراقبة اية مواضيع حتى الآن.", + "has_no_ignored_topics": "هذا المستخدم لم يقم بتجاهل اية مواضيع حتى الآن.", + "has_no_upvoted_posts": "هذا المستخدم لم يقم بالتصويت للأعلى لأي مشاركة حتى الآن.", + "has_no_downvoted_posts": "هذا المستخدم لم يقم بالتصويت للأسفل لأي مشاركة حتى الآن.", + "has_no_voted_posts": "هذا المستخدم لا يمتلك اية مشاركات تم التصويت عليها", "email_hidden": "البريد الإلكتروني مخفي", "hidden": "مخفي", - "paginate_description": "Paginate topics and posts instead of using infinite scroll", + "paginate_description": "عرض المواضيع والردود موزعة على صفحات عوضاً عن التمرير اللانهائي.", "topics_per_page": "المواضيع في كل صفحة", "posts_per_page": "الردود في كل صفحة", - "max_items_per_page": "Maximum %1", + "max_items_per_page": "أقصى %1", "notification_sounds": "تشغيل صوت عند تلقي تنبيه", - "notifications_and_sounds": "Notifications & Sounds", - "incoming-message-sound": "Incoming message sound", - "outgoing-message-sound": "Outgoing message sound", - "notification-sound": "Notification sound", - "no-sound": "No sound", + "notifications_and_sounds": "التنبيهات والأصوات", + "incoming-message-sound": "صوت الرسالة الواردة", + "outgoing-message-sound": "صوت الرسائل الصادرة", + "notification-sound": "صوت التنبيهات", + "no-sound": "بدون صوت", + "upvote-notif-freq": "معدل تكرار تنبيهات التصويت للأعلى", + "upvote-notif-freq.all": "كل التصويتات للأعلى", + "upvote-notif-freq.everyTen": "كل عشر تصويتات للأعلى", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "معطل", "browsing": "خيارات التصفح", "open_links_in_new_tab": "فتح الروابط الخارجية في نافدة جديدة", "enable_topic_searching": "تفعيل خاصية البحث داخل المواضيع", - "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen", - "delay_image_loading": "Delay Image Loading", - "image_load_delay_help": "If enabled, images in topics will not load until they are scrolled into view", + "topic_search_help": "إذا قمت بتفعيل ميزة البحث في-الموضوع، سيتم تجاوز الخيار الافتراضي للمتصفح مما يؤدي للبحث بكامل الموضوع بدلا عن البحث في الجزء الظاهر في الشاشة.", + "delay_image_loading": "تأخير عرض الصور", + "image_load_delay_help": "إذا تم تمكينه، فلن يتم تحميل الصور في المواضيع حتى يتم تمريرها في الشاشة", "scroll_to_my_post": "After posting a reply, show the new post", - "follow_topics_you_reply_to": "Watch topics that you reply to", - "follow_topics_you_create": "Watch topics you create", + "follow_topics_you_reply_to": "متابعة المواضيع التي تقوم بالرد عليها", + "follow_topics_you_create": "متابعة المواضيع التي تقوم بإنشائها", "grouptitle": "عنوان المجموعة", "no-group-title": "لا يوجد عنوان للمجموعة", - "select-skin": "Select a Skin", - "select-homepage": "Select a Homepage", + "select-skin": "إختر سمة", + "select-homepage": "إختر الصفحة الرئيسية", "homepage": "الصفحة الرئيسية", - "homepage_description": "Select a page to use as the forum homepage or 'None' to use the default homepage.", - "custom_route": "Custom Homepage Route", - "custom_route_help": "Enter a route name here, without any preceding slash (e.g. \"recent\", or \"popular\")", - "sso.title": "Single Sign-on Services", - "sso.associated": "Associated with", - "sso.not-associated": "Click here to associate with", - "info.latest-flags": "Latest Flags", - "info.no-flags": "No Flagged Posts Found", - "info.ban-history": "Recent Ban History", - "info.no-ban-history": "This user has never been banned", - "info.banned-until": "Banned until %1", - "info.banned-permanently": "Banned permanently", - "info.banned-reason-label": "Reason", - "info.banned-no-reason": "No reason given.", - "info.username-history": "Username History", - "info.email-history": "Email History", - "info.moderation-note": "Moderation Note", - "info.moderation-note.success": "Moderation note saved", - "info.moderation-note.add": "Add note" + "homepage_description": "حدد صفحة لاستخدامها كصفحة رئيسية للمنتدى أو \"لا شيء\" لاستخدام الصفحة الرئيسية الافتراضية.", + "custom_route": "مسار الصفحة الرئيسية المخصصة", + "custom_route_help": "أدخل اسم مسار هنا، بدون أي شرطة مائلة (على سبيل المثال \"حديثة\" أو \"شائعة\")", + "sso.title": "خدمات تسجيل الدخول الموحد", + "sso.associated": "مرتبط مع", + "sso.not-associated": "انقر هنا لربط مع", + "sso.dissociate": "فصل", + "sso.dissociate-confirm-title": "تأكيد الفصل", + "sso.dissociate-confirm": "هل تريد بالتأكيد فصل حسابك عن %1؟", + "info.latest-flags": "أحدث العلامات", + "info.no-flags": "لم يتم العثور على مشاركات معلمة", + "info.ban-history": "سجل الحظر الأحدث", + "info.no-ban-history": "هذا المستخدم لم يتم حظره مطلقا", + "info.banned-until": "محظور حتى %1", + "info.banned-permanently": "محظور بشكل دائم", + "info.banned-reason-label": "سبب", + "info.banned-no-reason": "لم يتم إعطاء سبب.", + "info.username-history": "سجل اسم المستخدم", + "info.email-history": "سجل البريد الإلكتروني", + "info.moderation-note": "ملاحظة الإشراف", + "info.moderation-note.success": "تم حفظ ملاحظة الإشراف", + "info.moderation-note.add": "إضافة ملاحظة" } \ No newline at end of file diff --git a/public/language/ar/users.json b/public/language/ar/users.json index 11a71a9341..eff3badb2a 100644 --- a/public/language/ar/users.json +++ b/public/language/ar/users.json @@ -10,12 +10,12 @@ "filter-by": "Filter By", "online-only": "المتصلون فقط", "invite": "دعوة", - "invitation-email-sent": "An invitation email has been sent to %1", + "invitation-email-sent": "تم إرسال دعوة بالبريد الإلكتروني إلى %1", "user_list": "قائمة اﻷعضاء", "recent_topics": "أحدث المواضيع", - "popular_topics": "Popular Topics", + "popular_topics": "المواضيع الأكثر شهرة", "unread_topics": "المواضيع الغير مقروءة", - "categories": "الفئات", - "tags": "الكلمات الدلالية", - "no-users-found": "No users found!" + "categories": "الأقسام", + "tags": "الوسوم", + "no-users-found": "لم يتم العثور على مستخدمين!" } \ No newline at end of file diff --git a/public/language/bg/admin/appearance/customise.json b/public/language/bg/admin/appearance/customise.json index f052e4e5c9..5f6214b70e 100644 --- a/public/language/bg/admin/appearance/customise.json +++ b/public/language/bg/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Въведете своите собствени декларации за стилове, те ще бъдат приложени след всички останали стилове.", "custom-css.enable": "Включване на персонализиран CSS", + "custom-js": "Персонализиран код на Javascript", + "custom-js.description": "Въведете свой собствен код на javascript тук. Той ще бъде изпълнен след като страницата се зареди напълно.", + "custom-js.enable": "Включване на персонализирания код на Javascript", + "custom-header": "Персонализирана заглавна част", - "custom-header.description": "Въведете своя персонализиран код HTML тук (напр. JavaScript, елементи „meta“ и т.н.), те ще бъдат добавени към секцията <head> в кода на Вашия форум.", + "custom-header.description": "Въведете своя персонализиран код HTML тук (напр. елементи „meta“ и т.н.), те ще бъдат добавени към секцията <head> в кода на Вашия форум. Ползването на елементи „script“ е позволено, но непрепоръчително, тъй като за това можете да ползвате раздела Персонализиран код на Javascript.", "custom-header.enable": "Включване на персонализирана заглавна част", "custom-css.livereload": "Включване на моменталното презареждане", diff --git a/public/language/bg/admin/menu.json b/public/language/bg/admin/menu.json index cd521781a7..fe3d478f54 100644 --- a/public/language/bg/admin/menu.json +++ b/public/language/bg/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Външен вид", "appearance/themes": "Теми", "appearance/skins": "Облици", - "appearance/customise": "Персонализиран HTML и CSS", + "appearance/customise": "Персонализирано съдържание (HTML/JS/CSS)", "section-extend": "Разширяване", "extend/plugins": "Добавки", diff --git a/public/language/bg/admin/settings/notifications.json b/public/language/bg/admin/settings/notifications.json index f04ceb8bd7..d32a556040 100644 --- a/public/language/bg/admin/settings/notifications.json +++ b/public/language/bg/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Известия", "welcome-notification": "Приветствено известие", - "welcome-notification-link": "Връзка за приветственото известие" + "welcome-notification-link": "Връзка за приветственото известие", + "welcome-notification-uid": "Потр. ид. за приветственото известие" } \ No newline at end of file diff --git a/public/language/bg/admin/settings/post.json b/public/language/bg/admin/settings/post.json index 2d3276ffe4..8aadba3e52 100644 --- a/public/language/bg/admin/settings/post.json +++ b/public/language/bg/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Първо най-старите", "sorting.newest-to-oldest": "Първо най-новите", "sorting.most-votes": "Първо тези с най-много гласове", + "sorting.most-posts": "Първо тези с най-много публикации", "sorting.topic-default": "Подредба по подразбиране на темите", "restrictions": "Ограничения за публикуването", "restrictions.post-queue": "Включване на опашката за публикации", diff --git a/public/language/bg/admin/settings/user.json b/public/language/bg/admin/settings/user.json index c0e975323f..a43f032ac5 100644 --- a/public/language/bg/admin/settings/user.json +++ b/public/language/bg/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Теми", "disable-user-skins": "Потребителите да не могат да избират собствен облик", "account-protection": "Защита на акаунта", + "admin-relogin-duration": "Повторно вписване на администратора (в минути)", + "admin-relogin-duration-help": "След определено време достъпът до административния раздел ще изисква повторно вписване. Задайте 0, за да изключите това.", "login-attempts": "Брой опити за вписване на час", "login-attempts-help": "Ако опитите за вписване на потребител минат тази граница, акаунтът ще бъде заключен за определено време.", "lockout-duration": "Продължителност на заключването на акаунта (в минути)", diff --git a/public/language/bg/email.json b/public/language/bg/email.json index aaf94585fd..2c72baef8f 100644 --- a/public/language/bg/email.json +++ b/public/language/bg/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Това известие за разговор беше изпратено до Вас поради настройките Ви за абонаментите.", "notif.post.cta": "Натиснете тук, за да прочетете цялата тема", "notif.post.unsub.info": "Това известие за публикация беше изпратено до Вас поради настройките Ви за абонаментите.", + "notif.cta": "Натиснете тук, за да преминете към форума", "test.text1": "Това е пробно е-писмо, за да потвърдим, че изпращачът на е-поща е правилно настроен за Вашия NodeBB.", "unsub.cta": "Натиснете тук, за да промените тези настройки", "banned.subject": "Вие бяхте блокиран(а) от %1", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index a8c2bb52ee..7612b0677a 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Нямате достатъчно репутация, за да гласувате отрицателно за тази публикация", "not-enough-reputation-to-flag": "Нямате достатъчно репутация, за да докладвате тази публикация", "already-flagged": "Вече сте докладвали тази публикация", + "self-vote": "Не можете да гласувате за собствената си публикация", "reload-failed": "NodeBB срещна проблем при презареждането: „%1“. NodeBB ще продължи да поддържа съществуващите клиентски ресурси, но Вие трябва да отмените последните си действия преди презареждането.", "registration-error": "Грешка при регистрацията", "parse-error": "Нещо се обърка при прочитането на отговора на сървъра", "wrong-login-type-email": "Моля, използвайте е-пощата си, за да се впишете", "wrong-login-type-username": "Моля, използвайте потребителското си име, за да се впишете", + "sso-registration-disabled": "Регистрацията за акаунти от %1 беше забранена, моля, регистрирайте се първо с е-поща", "invite-maximum-met": "Вие сте поканили максимално позволения брой хора (%1 от %2).", "no-session-found": "Няма намерена сесия на вписване!", "not-in-room": "Потребителят не е в стаята", @@ -132,5 +134,6 @@ "no-users-selected": "Няма избран(и) потребител(и)", "invalid-home-page-route": "Грешен път към началната страница", "invalid-session": "Несъответствие в сесията", - "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла или не съответства на сървъра. Моля, опреснете страницата." + "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла или не съответства на сървъра. Моля, опреснете страницата.", + "no-topics-selected": "Няма избрани теми!" } \ No newline at end of file diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json index f3be5bab25..c260ce6f1b 100644 --- a/public/language/bg/notifications.json +++ b/public/language/bg/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Продължаване към %1", "return_to": "Връщане към %1", "new_notification": "Ново известие", + "new_notification_from": "Имате ново известие от %1", "you_have_unread_notifications": "Имате непрочетени известия", "all": "Всички", "topics": "Теми", @@ -45,5 +46,19 @@ "email-confirmed": "Е-пощата беше потвърдена", "email-confirmed-message": "Благодарим Ви, че потвърдихте е-пощата си. Акаунтът Ви е вече напълно активиран.", "email-confirm-error-message": "Възникна проблем при потвърждаването на е-пощата Ви. Може кодът да е грешен или давността му да е изтекла.", - "email-confirm-sent": "Изпратено е е-писмо за потвърждение." + "email-confirm-sent": "Изпратено е е-писмо за потвърждение.", + "none": "Нищо", + "notification_only": "Само известие", + "email_only": "Само е-писмо", + "notification_and_email": "Известие и е-писмо", + "notificationType_upvote": "Когато някой гласува положително за Ваша публикация", + "notificationType_new-topic": "Когато някой, когото следвате, публикува тема", + "notificationType_new-reply": "Когато бъде публикуван нов отговор в тема, която следвате", + "notificationType_follow": "Когато някой започне да Ви следва", + "notificationType_new-chat": "Когато получите съобщение в разговор", + "notificationType_group-invite": "Когато получите покана за група", + "notificationType_new-register": "Когато някой бъде добавен в опашката за регистрация", + "notificationType_post-queue": "Когато бъде добавена нова публикация в опашката", + "notificationType_new-post-flag": "Когато публикация бъде докладвана", + "notificationType_new-user-flag": "Когато потребител бъде докладван" } \ No newline at end of file diff --git a/public/language/bg/topic.json b/public/language/bg/topic.json index fb7faaea2f..c09c9927d8 100644 --- a/public/language/bg/topic.json +++ b/public/language/bg/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Наистина ли искате да възстановите тази тема?", "thread_tools.purge": "Изчистване на темата", "thread_tools.purge_confirm": "Наистина ли искате да изчистите тази тема?", + "thread_tools.merge_topics": "Сливане на темите", + "thread_tools.merge": "Сливане", "topic_move_success": "Темата беше преместена успешно в %1", "post_delete_confirm": "Наистина ли искате да изтриете тази публикация?", "post_restore_confirm": "Наистина ли искате да възстановите тази публикация?", @@ -89,6 +91,7 @@ "fork_pid_count": "Избрани публикации: %1", "fork_success": "Темата е разделена успешно! Натиснете тук, за да преминете към отделената тема.", "delete_posts_instruction": "Натиснете публикациите, които искате да изтриете/изчистите", + "merge_topics_instruction": "Натиснете темите, които искате да слеете", "composer.title_placeholder": "Въведете заглавието на темата си тук...", "composer.handle_placeholder": "Име", "composer.discard": "Отхвърляне", diff --git a/public/language/bg/user.json b/public/language/bg/user.json index 453d45c0a5..c1d6f314e7 100644 --- a/public/language/bg/user.json +++ b/public/language/bg/user.json @@ -79,15 +79,13 @@ "digest_daily": "Ежедневно", "digest_weekly": "Ежеседмично", "digest_monthly": "Ежемесечно", - "send_chat_notifications": "Изпращане на е-писмо, ако получа ново съобщение в разговор, а не съм на линия", - "send_post_notifications": "Изпращане на е-писмо, когато се появи отговор в темите, за които съм абониран(а).", "settings-require-reload": "Някои промени в настройките изискват презареждане. Натиснете тук, за да презаредите страницата.", "has_no_follower": "Този потребител няма последователи :(", "follows_no_one": "Този потребител не следва никого :(", "has_no_posts": "Този потребител не е публикувал нищо досега.", "has_no_topics": "Този потребител не е създавал теми досега.", "has_no_watched_topics": "Този потребител не е следил нито една тема досега.", - "has_no_ignored_topics": "Този потребител не е пренебрегнали нито една тема досега.", + "has_no_ignored_topics": "Този потребител не е пренебрегнал нито една тема досега.", "has_no_upvoted_posts": "Този потребител не е гласувал положително досега.", "has_no_downvoted_posts": "Този потребител не е гласувал отрицателно досега.", "has_no_voted_posts": "Този потребител не е гласувал досега.", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Звук за изходящо съобщение", "notification-sound": "Звук за известие", "no-sound": "Без звук", + "upvote-notif-freq": "Честота на известията за положителни гласове", + "upvote-notif-freq.all": "Всички положителни гласове", + "upvote-notif-freq.everyTen": "На всеки десет положителни гласа", + "upvote-notif-freq.logarithmic": "На 10, 100, 1000…", + "upvote-notif-freq.disabled": "Изключено", "browsing": "Настройки за страниците", "open_links_in_new_tab": "Отваряне на външните връзки в нов подпрозорец", "enable_topic_searching": "Включване на търсенето в темите", @@ -123,6 +126,9 @@ "sso.title": "Услуги за еднократно вписване", "sso.associated": "Свързан с", "sso.not-associated": "Натиснете тук, за да свържете с", + "sso.dissociate": "Прекъсване на връзката", + "sso.dissociate-confirm-title": "Потвърждаване на прекъсването", + "sso.dissociate-confirm": "Наистина ли искате да прекъснете връзката на акаунта си от „%1“?", "info.latest-flags": "Последни доклади", "info.no-flags": "Не са намерени докладвани публикации", "info.ban-history": "Скорошна история на блокиранията", diff --git a/public/language/bn/admin/appearance/customise.json b/public/language/bn/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/bn/admin/appearance/customise.json +++ b/public/language/bn/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/bn/admin/menu.json b/public/language/bn/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/bn/admin/menu.json +++ b/public/language/bn/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/bn/admin/settings/notifications.json b/public/language/bn/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/bn/admin/settings/notifications.json +++ b/public/language/bn/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/bn/admin/settings/post.json b/public/language/bn/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/bn/admin/settings/post.json +++ b/public/language/bn/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/bn/admin/settings/user.json b/public/language/bn/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/bn/admin/settings/user.json +++ b/public/language/bn/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/bn/email.json b/public/language/bn/email.json index c4b24d267c..9d7b1cb1cc 100644 --- a/public/language/bn/email.json +++ b/public/language/bn/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "আপনার সাবস্ক্রীপশন সেটিংসের কারনে আপনার এই নোটিফিকেশন পাঠানো হয়েছে", "notif.post.cta": "পুরো বিষয়টি পড়তে এখানে ক্লিক করুন", "notif.post.unsub.info": "আপনার সাবস্ক্রিপশন সেটিংসের কারনে আপনার এই বার্তাটি পাঠানো হয়েছে", + "notif.cta": "Click here to go to forum", "test.text1": "আপনি সঠিকভাবে নোডবিবির জন্য মেইলার সেটাপ করেছেন কিনা নিশ্চিত করার জন্য এই টেষ্ট ইমেইল পাঠানো হয়েছে", "unsub.cta": "সেটিংসগুলো পরিবর্তন করতে এখানে ক্লিক করুন", "banned.subject": "You have been banned from %1", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index c63665943f..072039ee7c 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "আপনার এই পোস্ট downvote করার জন্য পর্যাপ্ত সম্মাননা নেই", "not-enough-reputation-to-flag": "এই পোষ্টকে ফ্লাগ করার জন্য আপনার পর্যাপ্ত সম্মাননা নেই", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "\"%1\" রিলোড করতে সমস্যা হয়েছে। রিলোডের পূর্বে যা করা হয়েছিল সেটি আনডু করা সমীচীন। ", "registration-error": "নিবন্ধন এরর!", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json index 0ad1832165..b69faabc9b 100644 --- a/public/language/bn/notifications.json +++ b/public/language/bn/notifications.json @@ -9,6 +9,7 @@ "continue_to": "%1 তে আগান", "return_to": "%1 এ ফেরত যান", "new_notification": "নতুন বিজ্ঞপ্তি", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "আপনার অপঠিত বিজ্ঞপ্তি আছে।", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "ইমেইল নিশ্চিত করা হয়েছে", "email-confirmed-message": "আপনার ইমেইল যাচাই করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টটি এখন সম্পূর্ণরূপে সক্রিয়।", "email-confirm-error-message": "আপনার ইমেল ঠিকানার বৈধতা যাচাইয়ে একটি সমস্যা হয়েছে। সম্ভবত কোডটি ভুল ছিল অথবা কোডের মেয়াদ শেষ হয়ে গিয়েছে।", - "email-confirm-sent": "নিশ্চিতকরণ ইমেইল পাঠানো হয়েছে।" + "email-confirm-sent": "নিশ্চিতকরণ ইমেইল পাঠানো হয়েছে।", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/bn/topic.json b/public/language/bn/topic.json index 46b6c48e0f..537b8a7200 100644 --- a/public/language/bn/topic.json +++ b/public/language/bn/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "আপনি নিশ্চিত যে আপনি টপিকটি পুনরূদ্ধার করতে চান?", "thread_tools.purge": "টপিক পার্জ করুন", "thread_tools.purge_confirm": "আপনি নিশ্চিত যে আপনি টপিকটি পার্জ করতে চাচ্ছেন ? ", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "টপিকটি %1 এ সরিয়ে নেয়া হয়েছে", "post_delete_confirm": "আপনি নিশ্চিত যে আপনি এই পোষ্টটি মুছে ফেলতে চান ?", "post_restore_confirm": "আপনি নিশ্চিত যে আপনি এই পোষ্টটি পুনরূূদ্ধার করতে চান ? ", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "টপিক ফর্ক করা হয়েছে। ফর্ক করা টপিকে যেতে এখানে ক্লিক করুন", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "আপনার টপিকের শিরোনাম দিন", "composer.handle_placeholder": "Name", "composer.discard": "বাতিল", diff --git a/public/language/bn/user.json b/public/language/bn/user.json index a9688ce532..ad611b4642 100644 --- a/public/language/bn/user.json +++ b/public/language/bn/user.json @@ -79,8 +79,6 @@ "digest_daily": "দৈনিক", "digest_weekly": "সাপ্তাহিক", "digest_monthly": "মাসিক", - "send_chat_notifications": "যদি আমি অনলাইনে না থাকি, সেক্ষেত্রে নতুন চ্যাট মেসেজ আসলে আমাকে ইমেইল করুন", - "send_post_notifications": "আমার সাবস্ক্রাইব করা টপিকগুলোতে রিপ্লাই করা হলে আমাকে মেইল করা হোক", "settings-require-reload": "কিছু কিছু পরিবর্তনের জন্য রিলোড করা আবশ্যক। পেজটি রিলোড করতে এখানে ক্লিক করুন", "has_no_follower": "এই সদস্যের কোন ফলোয়ার নেই :(", "follows_no_one": "এই সদস্য কাউকে ফলো করছেন না :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Browsing সেটিংস", "open_links_in_new_tab": "আউটগোয়িং লিংকগুলো নতুন ট্যাবে খুলুন", "enable_topic_searching": "In-Topic সার্চ সক্রীয় করো", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/cs/admin/appearance/customise.json b/public/language/cs/admin/appearance/customise.json index 03ee9c5652..c22a869f80 100644 --- a/public/language/cs/admin/appearance/customise.json +++ b/public/language/cs/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Zadejte vlastní deklarace CSS, které budou použity na všechny ostatních styly.", "custom-css.enable": "Povolit uživatelské CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Uživatelská hlavička", - "custom-header.description": "Zadejte zde uživatelské HTML (např.: javascript, meta značky, atp.), které bude přiřazeno k <head> části značek vašeho fóra.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Povolit uživatelskou hlavičku", "custom-css.livereload": "Povolit aktuální znovu načtení", diff --git a/public/language/cs/admin/menu.json b/public/language/cs/admin/menu.json index edc5afd806..8b9812e514 100644 --- a/public/language/cs/admin/menu.json +++ b/public/language/cs/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Vzhled", "appearance/themes": "Motivy", "appearance/skins": "Vzhledy", - "appearance/customise": "Uživatelské HTML a CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Rozšířit", "extend/plugins": "Rozšíření", diff --git a/public/language/cs/admin/settings/notifications.json b/public/language/cs/admin/settings/notifications.json index 15a5c2415b..fd95917606 100644 --- a/public/language/cs/admin/settings/notifications.json +++ b/public/language/cs/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Oznámení", "welcome-notification": "Uvítání", - "welcome-notification-link": "Odkaz na uvítání" + "welcome-notification-link": "Odkaz na uvítání", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/cs/admin/settings/post.json b/public/language/cs/admin/settings/post.json index c12559df24..67d297b33b 100644 --- a/public/language/cs/admin/settings/post.json +++ b/public/language/cs/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Od nejstarších po nejnovější", "sorting.newest-to-oldest": "Od nejnovějších po nejstarší", "sorting.most-votes": "Dle hlasování", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Výchozí třídění tématu", "restrictions": "Omezení příspěvků", "restrictions.post-queue": "Povolit frontu pro příspěvky", diff --git a/public/language/cs/admin/settings/user.json b/public/language/cs/admin/settings/user.json index 39f74a5a48..2ad41f23cf 100644 --- a/public/language/cs/admin/settings/user.json +++ b/public/language/cs/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Motivy", "disable-user-skins": "Zabránit uživateli ve výběru vlastního vzhledu", "account-protection": "Ochrana účtu", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Počet pokusů o přihlášení za hodinu", "login-attempts-help": "Překročí-li pokusy o přihlášení uživatele/ů tuto hranici, účet bude uzamknut na určený čas", "lockout-duration": "Délka blokování účtu (v minutách)", diff --git a/public/language/cs/email.json b/public/language/cs/email.json index 0206bccb5a..1d1efa10e9 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Toto upozornění na chat vám bylo odesláno na základě vašeho nastavení odběru.", "notif.post.cta": "Klikněte zde pro přečtené celého tématu", "notif.post.unsub.info": "Toto upozornění na příspěvek vám bylo odesláno na základě vašeho nastavení odběru.", + "notif.cta": "Click here to go to forum", "test.text1": "Tento testovací e-mail slouží k ověření, že je e-mailer správně nastaven pro práci s NodeBB.", "unsub.cta": "Chcete-li změnit tyto nastavení, klikněte zde.", "banned.subject": "Byl jste zablokován od %1", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 465ada0755..43ea641999 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nemáte dostatečnou reputaci pro vyjádření nesouhlasu u tohoto příspěvku", "not-enough-reputation-to-flag": "Pro označení tohoto příspěvku nemáte dostatečnou reputaci", "already-flagged": "Tento příspěvek jste již označil", + "self-vote": "You cannot vote on your own post", "reload-failed": "Vyskytla se chyba v NodeBB při znovu načtení: \"%1\". NodeBB bude pokračovat v běhu na straně klienta, nicméně byste měl/a přenastavit zpět to, co jste udělal/a před opětovným načtením.", "registration-error": "Chyba při registraci", "parse-error": "Při analýze odpovědi serveru nastala chyba", "wrong-login-type-email": "Pro přihlášení použijte vaši e-mailovou adresu", "wrong-login-type-username": "Pro přihlášení použijte vaše uživatelské jméno", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Již jste pozval/a maximálně možný počet lidí (%1 z %2).", "no-session-found": "Nebyla nalezena relace s přihlášením.", "not-in-room": "Uživatel není přítomen v místnosti", @@ -132,5 +134,6 @@ "no-users-selected": "Žádný uživatel/é nebyl/y vybrán/i", "invalid-home-page-route": "Neplatná cesta k domovské stránkce", "invalid-session": "Nesoulad v relacích", - "invalid-session-text": "Zdá se, že vše relace s přihlášením již není aktivní nebo již neodpovídá s relací na serveru. Obnovte prosím tuto stránku." + "invalid-session-text": "Zdá se, že vše relace s přihlášením již není aktivní nebo již neodpovídá s relací na serveru. Obnovte prosím tuto stránku.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json index 9c6a90153d..8182ae3f47 100644 --- a/public/language/cs/notifications.json +++ b/public/language/cs/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Pokračovat na %1", "return_to": "Vrátit se na %1", "new_notification": "Nové upozornění", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Máte nepřečtená upozornění.", "all": "Vše", "topics": "Témata", @@ -45,5 +46,19 @@ "email-confirmed": "E-mail potvrzen", "email-confirmed-message": "Děkujeme za ověření vaší e-mailové adresy. Váš účet je nyní aktivní.", "email-confirm-error-message": "Nastal problém s ověřením vaší e-mailové adresy. Kód je pravděpodobně neplatný nebo jeho platnost vypršela.", - "email-confirm-sent": "Ověřovací e-mail odeslán." + "email-confirm-sent": "Ověřovací e-mail odeslán.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/cs/topic.json b/public/language/cs/topic.json index c5ce32c134..7cedca5e24 100644 --- a/public/language/cs/topic.json +++ b/public/language/cs/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Jste si jist/a, že chcete toto téma obnovit?", "thread_tools.purge": "Vyčistit téma", "thread_tools.purge_confirm": "Jste si jist/a, že chcete vyčistit toto téma?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Toto téma bylo úspěšně přesunuto do %1", "post_delete_confirm": "Jste si jist/a, že chcete odstranit tento příspěvek?", "post_restore_confirm": "Jste si jist/a, že chcete obnovit tento příspěvek?", @@ -89,6 +91,7 @@ "fork_pid_count": "Vybráno %1 příspěvek/ů", "fork_success": "Téma úspěšně rozděleno. Pro přejití na rozdělené téma, zde klikněte.", "delete_posts_instruction": "Klikněte na příspěvek, který chcete odstranit/vyčistit", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Zadejte název tématu…", "composer.handle_placeholder": "Jméno", "composer.discard": "Zrušit", diff --git a/public/language/cs/user.json b/public/language/cs/user.json index 1dbf2cd49e..0042eb8ec6 100644 --- a/public/language/cs/user.json +++ b/public/language/cs/user.json @@ -79,8 +79,6 @@ "digest_daily": "Denně", "digest_weekly": "Týdně", "digest_monthly": "Měsíčně", - "send_chat_notifications": "Odeslat e-mail, dorazí-li nová zpráva chatu a já nejsem připojen", - "send_post_notifications": "Zaslat e-mail, přibudou-li nové odpovědi k tématu, kde mám přihlášen odběr", "settings-require-reload": "Některá nastavení vyžadují znovu načtení. Pro znovu načtení stránky, klikněte zde.", "has_no_follower": "Tohoto uživatele nikdo nesleduje :(", "follows_no_one": "Tento uživatel nikoho nesleduje :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Zvuk odchozí zprávy", "notification-sound": "Zvuk oznámení", "no-sound": "Bez zvuku", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Nastavení prohlížení", "open_links_in_new_tab": "Otevřít odchozí odkaz v nové záložce", "enable_topic_searching": "Povolit vyhledávání v tématu", @@ -123,6 +126,9 @@ "sso.title": "Služby jednotného přihlášení", "sso.associated": "Přiřazeno k", "sso.not-associated": "Zde klikněte pro přiřazení k", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Poslední označené", "info.no-flags": "Nebyly nalezeny žádné označené příspěvky", "info.ban-history": "Poslední historie blokovaných", diff --git a/public/language/da/admin/appearance/customise.json b/public/language/da/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/da/admin/appearance/customise.json +++ b/public/language/da/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/da/admin/menu.json b/public/language/da/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/da/admin/menu.json +++ b/public/language/da/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/da/admin/settings/notifications.json b/public/language/da/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/da/admin/settings/notifications.json +++ b/public/language/da/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/da/admin/settings/post.json b/public/language/da/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/da/admin/settings/post.json +++ b/public/language/da/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/da/admin/settings/user.json b/public/language/da/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/da/admin/settings/user.json +++ b/public/language/da/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/da/email.json b/public/language/da/email.json index afd7577d19..b06a283c0f 100644 --- a/public/language/da/email.json +++ b/public/language/da/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Denne chat notifikation blev sendt til dig pga. indstillingerne i dit abonnement.", "notif.post.cta": "Klik her for a læse hele emnet", "notif.post.unsub.info": "Denne indlægs notifikation var sendt pga. dine abonnering indstillinger.", + "notif.cta": "Click here to go to forum", "test.text1": "Dette er en test email for at kontrollere, at den udgående email server er opsat korrekt i forhold til din NodeBB installation.", "unsub.cta": "Klik her for at ændre disse indstillinger", "banned.subject": "You have been banned from %1", diff --git a/public/language/da/error.json b/public/language/da/error.json index 2165cad861..889c7fbd99 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Du har ikke nok omdømme til at nedstemme dette indlæg", "not-enough-reputation-to-flag": "Du har ikke nok omdømme til at vurdere dette indlæg", "already-flagged": "Du har allerede vurderet dette indlæg", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB stødte på et problem under genindlæsningen : \"%1\". NodeBB vil fortsætte med en ældre version, og det er nok god ide at genoptage fra lige før du genindlæste siden.", "registration-error": "Registeringsfejl", "parse-error": "Noget gik galt under fortolknings er serverens respons", "wrong-login-type-email": "Brug venligt din email til login", "wrong-login-type-username": "Brug venligt dit brugernavn til login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Du har inviteret det maksimale antal personer (%1 ud af %2)", "no-session-found": "Ingen login session kan findes!", "not-in-room": "Bruger er ikke i rummet", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json index 7754539229..85d0276864 100644 --- a/public/language/da/notifications.json +++ b/public/language/da/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Fortsæt til %1", "return_to": "Returnere til %t", "new_notification": "Ny notifikation", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Du har ulæste notifikationer.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email bekræftet", "email-confirmed-message": "Tak fordi du validerede din email. Din konto er nu fuldt ud aktiveret.", "email-confirm-error-message": "Der var et problem med valideringen af din emailadresse. Bekræftelses koden var muligvis forkert eller udløbet.", - "email-confirm-sent": "Bekræftelses email afsendt." + "email-confirm-sent": "Bekræftelses email afsendt.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/da/topic.json b/public/language/da/topic.json index de6b087b5d..e1c7cf0501 100644 --- a/public/language/da/topic.json +++ b/public/language/da/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Er du sikker på at du ønsker at genoprette denne tråd?", "thread_tools.purge": "Udrader tråd", "thread_tools.purge_confirm": "Er du sikker på at du vil udrense denne tråd?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Denne tråd blev flyttet til %1", "post_delete_confirm": "Er du sikker på at du vil slette dette indlæg?", "post_restore_confirm": "Er du sikker på at du vil gendanne dette indlæg?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Tråden blev fraskilt! Klik her for at gå til den fraskilte tråd.", "delete_posts_instruction": "Klik på de indlæg du vil slette/rense", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Angiv din trådtittel her ...", "composer.handle_placeholder": "Navn", "composer.discard": "Fortryd", diff --git a/public/language/da/user.json b/public/language/da/user.json index 9e87553d30..58936317a2 100644 --- a/public/language/da/user.json +++ b/public/language/da/user.json @@ -79,8 +79,6 @@ "digest_daily": "Daglig", "digest_weekly": "Ugentlig", "digest_monthly": "Månedlig", - "send_chat_notifications": "Send en email hvis en ny chat besked er modtaget og jeg ikke er online", - "send_post_notifications": "Send en email når der er skrevet svar til indlæg jeg abonnere på", "settings-require-reload": "Nogle indstillinger kræver en genindlæsning. Klik her for at genindlæse siden.", "has_no_follower": "Denne bruger har ingen følgere :(", "follows_no_one": "Denne bruger følger ikke nogen :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Udgående besked lyd", "notification-sound": "Meddelelse lyd", "no-sound": "Ingen lyd", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Gennemsenings indstillinger", "open_links_in_new_tab": "Åben udgående link i en ny tab", "enable_topic_searching": "Slå In-Topic søgning til", @@ -123,6 +126,9 @@ "sso.title": "Enkeltgangs Sign-on Servicer", "sso.associated": "Forbundet med", "sso.not-associated": "Klik her for at forbinde med", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/de/admin/appearance/customise.json b/public/language/de/admin/appearance/customise.json index 657fe93ea8..342552e881 100644 --- a/public/language/de/admin/appearance/customise.json +++ b/public/language/de/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Füge hier deine eigenen CSS-Eigenschaften ein, sie werden als letztes angewendet.", "custom-css.enable": "Benutzerdefiniertes CSS aktivieren", + "custom-js": "Benutzerdefiniertes Javascript", + "custom-js.description": "Füge dein eigenes Javascipt hier ein.\nEs wird ausgeführt nachdem die Seite komplett geladen wurde.", + "custom-js.enable": "Benutzerdefiniertes Javascript aktivieren", + "custom-header": "Benutzerdefinierter Header", - "custom-header.description": "Füge hier dein benutzerdefiniertes HTML (z.B. Javascript, Meta Tags, usw.) ein, welches in den <head> Tag eingefügt werden soll.", + "custom-header.description": "Füge dein benutzerdefiniertes HTML hier ein (wie z.B. meta Tags etc.), welche in die <head> Sektion im Markup des Forums eingefügt werden. script Tags sind erlaubt, es wird aber davon abgeraten, da es den Benutzerdefiniertes Javascript Tab gibt.", "custom-header.enable": "Benutzerdefinierten Header aktivieren", "custom-css.livereload": "Live-Aktualisierung aktivieren", diff --git a/public/language/de/admin/manage/post-queue.json b/public/language/de/admin/manage/post-queue.json index 4c6686e57d..e36b4de07e 100644 --- a/public/language/de/admin/manage/post-queue.json +++ b/public/language/de/admin/manage/post-queue.json @@ -7,5 +7,5 @@ "content": "Inhalt", "posted": "Gepostet", "reply-to": "Auf \"%1\" antworten", - "content-editable": "You can click on individual content to edit before posting." + "content-editable": "Du kannst auf den einzelnen Inhalt klicken um ihn zu ändern bevor du ihn postest." } \ No newline at end of file diff --git a/public/language/de/admin/menu.json b/public/language/de/admin/menu.json index 228ae81121..965724e772 100644 --- a/public/language/de/admin/menu.json +++ b/public/language/de/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Aussehen", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Benutzerdefiniertes HTML & CSS", + "appearance/customise": "Benutzerdefinierter Inhalt (HTML/JS/CSS)", "section-extend": "Erweitert", "extend/plugins": "Plugins", @@ -65,7 +65,7 @@ "logout": "Abmelden", "view-forum": "Forum anzeigen", - "search.placeholder": "Search for settings", + "search.placeholder": "Nach Einstellungen suchen", "search.no-results": "Keine Ergebnisse...", "search.search-forum": "Suche im Forum nach ", "search.keep-typing": "Gib mehr ein, um die Ergebnisse zu sehen...", diff --git a/public/language/de/admin/settings/notifications.json b/public/language/de/admin/settings/notifications.json index 3aab343267..e66499b081 100644 --- a/public/language/de/admin/settings/notifications.json +++ b/public/language/de/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Benachrichtigungen", "welcome-notification": "Wilkommensnachricht", - "welcome-notification-link": "Wilkommensnachricht-Link" + "welcome-notification-link": "Wilkommensnachricht-Link", + "welcome-notification-uid": "Wilkommensbenachrichtigung Benutzer (UID)" } \ No newline at end of file diff --git a/public/language/de/admin/settings/pagination.json b/public/language/de/admin/settings/pagination.json index 960cf3d0be..69d4f4484d 100644 --- a/public/language/de/admin/settings/pagination.json +++ b/public/language/de/admin/settings/pagination.json @@ -3,9 +3,9 @@ "enable": "Themen in Seiten einteilen anstatt endlos zu scrollen", "topics": "Themen Seitennummerierung", "posts-per-page": "Beiträge pro Seite", - "max-posts-per-page": "Maximum posts per page", + "max-posts-per-page": "Maximale Anzahl von Beiträgen pro Seite", "categories": "Kategorie Seitennummerierung", "topics-per-page": "Themen pro Seite", - "max-topics-per-page": "Maximum topics per page", + "max-topics-per-page": "Maximale Anzahl von Themen pro Seite", "initial-num-load": "Ursprüngliche Anzahl an Themen, die bei ungelesen, aktuell und beliebt geladen werden sollen" } \ No newline at end of file diff --git a/public/language/de/admin/settings/post.json b/public/language/de/admin/settings/post.json index 686b33012b..99c65998c4 100644 --- a/public/language/de/admin/settings/post.json +++ b/public/language/de/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Von Alt bis Neu", "sorting.newest-to-oldest": "Von Neu zu Alt", "sorting.most-votes": "Meiste Bewertungen", + "sorting.most-posts": "Meiste Beiträge", "sorting.topic-default": "Standardmäßige Themensortierung", "restrictions": "Posting beschränkungen", "restrictions.post-queue": "Beitragswarteschlange verwenden", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index 13809851b8..316a66ffae 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Verhindere das Benutzer eigene Skins verwenden", "account-protection": "Kontosicherheit", + "admin-relogin-duration": "Dauer bis zum erneuten Login (in Minuten)", + "admin-relogin-duration-help": "Nach einer gesetzten Zeit erfordert der Zugriff auf die Admin Sektion einen erneuten Login, 0 deaktiviert dies", "login-attempts": "Login-Versuche pro Stunde", "login-attempts-help": "Wenn die loginversuche zu einem Account diese Schwelle überschreiten, wird dieser Account für eine festgelegte Zeit gesperrt", "lockout-duration": "Account Aussperrzeitraum (Minuten)", diff --git a/public/language/de/email.json b/public/language/de/email.json index b897966610..f110343626 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Diese Chat-Benachrichtigung wurde dir aufgrund deiner Abonnement-Einstellungen gesendet.", "notif.post.cta": "Hier klicken, um das gesamte Thema zu lesen", "notif.post.unsub.info": "Diese Mitteilung wurde dir aufgrund deiner Abonnement-Einstellungen gesendet.", + "notif.cta": "Klicke hier um das Forum zu besuchen", "test.text1": "Dies ist eine Test-E-Mail, um zu überprüfen, ob der E-Mailer deines NodeBB korrekt eingestellt wurde.", "unsub.cta": "Klicke hier, um diese Einstellungen zu ändern", "banned.subject": "Du wurdest von %1 gebannt.", diff --git a/public/language/de/error.json b/public/language/de/error.json index 8aa2b0eb3c..096dc01623 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -11,7 +11,7 @@ "invalid-uid": "Ungültige Benutzer-ID", "invalid-username": "Ungültiger Benutzername", "invalid-email": "Ungültige E-Mail-Adresse", - "invalid-title": "Invalid title", + "invalid-title": "Ungültiger Titel", "invalid-user-data": "Ungültige Benutzerdaten", "invalid-password": "Ungültiges Passwort", "invalid-login-credentials": "Ungültige Zugangsdaten", @@ -81,7 +81,7 @@ "cant-ban-other-admins": "Du kannst andere Administratoren nicht sperren!", "cant-remove-last-admin": "Du bist der einzige Administrator. Füge zuerst einen anderen Administrator hinzu, bevor du dich selbst als Administrator entfernst", "cant-delete-admin": "Bevor du versuchst dieses Konto zu löschen, entferne die zugehörigen Administratorrechte.", - "invalid-image": "Invalid image", + "invalid-image": "Ungültiges Bild", "invalid-image-type": "Falsche Bildart. Erlaubte Arten sind: %1", "invalid-image-extension": "Ungültige Dateinamenerweiterung", "invalid-file-type": "Ungültiger Dateityp. Erlaubte Typen sind: %1", @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Dein Ansehen ist zu niedrig, um diesen Beitrag negativ zu bewerten.", "not-enough-reputation-to-flag": "Dein Ansehen ist zu niedrig, um diesen Beitrag zu melden", "already-flagged": "Du hast diesen Beitrag bereits gemeldet", + "self-vote": "Du kannst deine eigenen Beiträge nicht bewerten", "reload-failed": "Es ist ein Problem während des Reloads von NodeBB aufgetreten: \"%1\". NodeBB wird weiterhin clientseitige Assets bereitstellen, allerdings solltest du das, was du vor dem Reload gemacht hast, rückgängig machen.", "registration-error": "Registrierungsfehler", "parse-error": "Beim auswerten der Serverantwort ist etwas schiefgegangen", "wrong-login-type-email": "Bitte nutze deine E-Mail-Adresse zum einloggen", "wrong-login-type-username": "Bitte nutze deinen Benutzernamen zum einloggen", + "sso-registration-disabled": "Das Registrieren mit %1-Accounts wurde deaktiviert, bitte registriere dich zuerst mit einer Email-Adresse", "invite-maximum-met": "Du hast bereits die maximale Anzahl an Personen eingeladen (%1 von %2).", "no-session-found": "Keine Login-Sitzung gefunden!", "not-in-room": "Benutzer nicht im Raum", @@ -132,5 +134,6 @@ "no-users-selected": "Kein(e) Benutzer ausgewählt", "invalid-home-page-route": "Ungültiger Startseitenpfad", "invalid-session": "Sitzungsdiskrepanz", - "invalid-session-text": "Es scheint als wäre deine Login-Sitzung nicht mehr aktiv oder sie passt nicht mehr mit der des Servers. Bitte aktualisiere diese Seite." + "invalid-session-text": "Es scheint als wäre deine Login-Sitzung nicht mehr aktiv oder sie passt nicht mehr mit der des Servers. Bitte aktualisiere diese Seite.", + "no-topics-selected": "Keine Beiträge ausgewählt!" } \ No newline at end of file diff --git a/public/language/de/flags.json b/public/language/de/flags.json index 78ac4b540d..9ef54211e3 100644 --- a/public/language/de/flags.json +++ b/public/language/de/flags.json @@ -54,11 +54,11 @@ "modal-body": "Bitte geben Sie den Grund an, weshalb Sie %1 %2 melden wollen. Alternativ können Sie einen der Schnell-Meldungs-Knöpfe verwenden, wenn anwendbar.", "modal-reason-spam": "Spam", "modal-reason-offensive": "Beleidigend", - "modal-reason-other": "Other (specify below)", + "modal-reason-other": "Anderer (unten Angegeben)", "modal-reason-custom": "Grund für die Meldung dieses Inhalts...", "modal-submit": "Meldung abschicken", "modal-submit-success": "Der Inhalt wurde gemeldet.", - "modal-submit-confirm": "Confirm Submission", - "modal-submit-confirm-text": "You have a custom reason specified already. Are you sure you wish to submit via quick-report?", - "modal-submit-confirm-text-help": "Submitting a quick report will overwrite any custom reasons defined." + "modal-submit-confirm": "Einreichung bestätigen", + "modal-submit-confirm-text": "Du hast bereits einen benutzerdefinierten Grund angegeben. Bis du sicher, dass du per schnell-funktion abschicken willst?", + "modal-submit-confirm-text-help": "Das einreichen per schnell-funktion werden alle näher angegebenen Gründe ignoriert." } \ No newline at end of file diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index 3f29764fd0..93858808b7 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Fortfahren zu %1", "return_to": "Kehre zurück zu %1", "new_notification": "Neue Benachrichtigung", + "new_notification_from": "Du hast eine neue Nachricht von %1", "you_have_unread_notifications": "Du hast ungelesene Benachrichtigungen.", "all": "Alle", "topics": "Themen", @@ -45,5 +46,19 @@ "email-confirmed": "E-Mail bestätigt", "email-confirmed-message": "Vielen Dank für Ihre E-Mail-Validierung. Ihr Konto ist nun vollständig aktiviert.", "email-confirm-error-message": "Es gab ein Problem bei der Validierung Ihrer E-Mail-Adresse. Möglicherweise ist der Code ungültig oder abgelaufen.", - "email-confirm-sent": "Bestätigungs-E-Mail gesendet." + "email-confirm-sent": "Bestätigungs-E-Mail gesendet.", + "none": "Keine", + "notification_only": "Nur Benachrichtigungen", + "email_only": "Nur Emails", + "notification_and_email": "Benachrichtigungen & Emails", + "notificationType_upvote": "Wenn jemand deinen beitrag positiv bewertet", + "notificationType_new-topic": "Wenn jemand dem du folgst einen Beitrag erstellt", + "notificationType_new-reply": "Wenn es eine neue Antwort auf ein Thema das du beobachtest gibt", + "notificationType_follow": "Wenn dir jemand neues folgt", + "notificationType_new-chat": "Wenn du eine Chat Nachricht erhältst", + "notificationType_group-invite": "Wenn du eine Gruppeneinladung erhältst", + "notificationType_new-register": "Wenn jemand der Registrierungswarteschlange hinzugefügt wird", + "notificationType_post-queue": "Wenn ein neuer Beitrag eingereiht wird", + "notificationType_new-post-flag": "Wenn ein Beitrag gemeldet wird", + "notificationType_new-user-flag": "Wenn ein Benutzer gemeldet wird" } \ No newline at end of file diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 0a30df43ac..7c6d59d6e5 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -44,7 +44,7 @@ "account/bookmarks": "Lesezeichen von %1", "account/settings": "Benutzer-Einstellungen", "account/watched": "Von %1 beobachtete Themen", - "account/ignored": "Topics ignored by %1", + "account/ignored": "Ignorierte Themen von %1", "account/upvoted": "Von %1 positiv bewertete Beiträge", "account/downvoted": "Von %1 negativ bewertete Beiträge", "account/best": "Bestbewertete Beiträge von %1", diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 7793082abb..4a01b115ac 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Bist du sicher, dass du dieses Thema wiederherstellen möchtest?", "thread_tools.purge": "Thema endgültig löschen", "thread_tools.purge_confirm": "Bist du sicher, dass du dieses Thema endgültig löschen möchtest?", + "thread_tools.merge_topics": "Themen vereinen", + "thread_tools.merge": "Vereinen", "topic_move_success": "Thema wurde erfolgreich nach %1 verschoben.", "post_delete_confirm": "Sind Sie sicher, dass Sie diesen Beitrag löschen möchten?", "post_restore_confirm": "Sind Sie sicher, dass Sie diesen Beitrag wiederherstellen möchten?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 Beiträge ausgewählt", "fork_success": "Thema erfolgreich aufgespalten! Klicke hier, um zum abgespaltenen Thema zu gelangen.", "delete_posts_instruction": "Wähle die zu löschenden Beiträge aus", + "merge_topics_instruction": "Wähle die Themen aus, die du vereinen möchtest", "composer.title_placeholder": "Hier den Titel des Themas eingeben...", "composer.handle_placeholder": "Name", "composer.discard": "Verwerfen", diff --git a/public/language/de/unread.json b/public/language/de/unread.json index 4c2de5984c..ccfce6bbb5 100644 --- a/public/language/de/unread.json +++ b/public/language/de/unread.json @@ -10,6 +10,6 @@ "all-topics": "Alle Themen", "new-topics": "Neue Themen", "watched-topics": "Beobachtete Themen", - "unreplied-topics": "Unreplied Topics", - "multiple-categories-selected": "Multiple Selected" + "unreplied-topics": "Unbeantwortete Themen", + "multiple-categories-selected": "Mehrere ausgewählt" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index d6dcbd6753..38a7934f42 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -25,7 +25,7 @@ "reputation": "Ansehen", "bookmarks": "Lesezeichen", "watched": "Beobachtet", - "ignored": "Ignored", + "ignored": "Ignoriert", "followers": "Follower", "following": "Folge ich", "aboutme": "Über mich", @@ -79,15 +79,13 @@ "digest_daily": "Täglich", "digest_weekly": "Wöchentlich", "digest_monthly": "Monatlich", - "send_chat_notifications": "Sende eine E-Mail, wenn eine neue Chat-Nachricht eingeht während ich nicht online bin", - "send_post_notifications": "Sende eine E-Mail bei Antworten auf Themen die ich abonniert habe.", "settings-require-reload": "Einige Einstellungsänderung benötigen eine Aktualisierung. Hier klicken um die Seite neu zu laden.", "has_no_follower": "Diesem Benutzer folgt noch niemand. :(", "follows_no_one": "Dieser Benutzer folgt noch niemandem. :(", "has_no_posts": "Dieser Benutzer hat noch nichts geschrieben.", "has_no_topics": "Dieser Benutzer hat noch keine Themen erstellt.", "has_no_watched_topics": "Dieser Benutzer beobachtet keine Themen.", - "has_no_ignored_topics": "This user hasn't ignored any topics yet.", + "has_no_ignored_topics": "Dieser Benutzer ignoriert bisher keine Themen.", "has_no_upvoted_posts": "Dieser Benutzer hat bisher keine Beiträge positiv bewertet.", "has_no_downvoted_posts": "Dieser Benutzer hat bisher keine Beiträge negativ bewertet.", "has_no_voted_posts": "Dieser Benutzer hat keine bewerteten Beiträge.", @@ -96,13 +94,18 @@ "paginate_description": "Themen und Beiträge in Seiten aufteilen, anstatt unendlich zu scrollen", "topics_per_page": "Themen pro Seite", "posts_per_page": "Beiträge pro Seite", - "max_items_per_page": "Maximum %1", + "max_items_per_page": "Maximal %1", "notification_sounds": "Ton abspielen, wenn du eine Benachrichtigung erhältst", "notifications_and_sounds": "Benachrichtigungen & Klänge", "incoming-message-sound": "Ton bei empfangener Nachricht", "outgoing-message-sound": "Ton bei versendeter Nachricht", "notification-sound": "Benachrichtigungston ", "no-sound": "Kein Ton", + "upvote-notif-freq": "Benachrichtigungshäufigkeit für positive Bewertungen", + "upvote-notif-freq.all": "Alle positiven Bewertungen", + "upvote-notif-freq.everyTen": "Alle 10 positiven Bewertungen", + "upvote-notif-freq.logarithmic": "Bei 10, 100, 1000...", + "upvote-notif-freq.disabled": "Deaktiviert", "browsing": "Browsing", "open_links_in_new_tab": "Ausgehende Links in neuem Tab öffnen", "enable_topic_searching": "Suchen innerhalb von Themen aktivieren", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Dienste", "sso.associated": "Verbunden mit", "sso.not-associated": "Verbinde dich mit", + "sso.dissociate": "Trennen", + "sso.dissociate-confirm-title": "Trennung bestätigen", + "sso.dissociate-confirm": "Bist du sicher, dass du deinen Account von %1 trennen willst?", "info.latest-flags": "Neuste Meldungen", "info.no-flags": "Keine gemeldeten Beiträge gefunden", "info.ban-history": "Sperrungsverlauf", diff --git a/public/language/el/admin/appearance/customise.json b/public/language/el/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/el/admin/appearance/customise.json +++ b/public/language/el/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/el/admin/menu.json b/public/language/el/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/el/admin/menu.json +++ b/public/language/el/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/el/admin/settings/notifications.json b/public/language/el/admin/settings/notifications.json index 10009c6e08..e2d5967239 100644 --- a/public/language/el/admin/settings/notifications.json +++ b/public/language/el/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Ειδοποιήσεις", "welcome-notification": "Ειδοποίηση καλωσορίσματος", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/el/admin/settings/post.json b/public/language/el/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/el/admin/settings/post.json +++ b/public/language/el/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/el/admin/settings/user.json b/public/language/el/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/el/admin/settings/user.json +++ b/public/language/el/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/el/email.json b/public/language/el/email.json index 8cdc4b057d..c9b69997c2 100644 --- a/public/language/el/email.json +++ b/public/language/el/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Αυτή η ειδοποίηση για συνομιλία σου στάλθηκε λόγω των ρυθμίσεών σου. ", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "Αυτό είναι ένα δοκιμαστικό email για να επιβεβαιώσουμε ότι ο emailer έχει στηθεί σωστά για το NodeBB.", "unsub.cta": "Κάνε κλικ εδώ για να αλλάξεις αυτές τις ρυθμίσεις", "banned.subject": "You have been banned from %1", diff --git a/public/language/el/error.json b/public/language/el/error.json index 39862021c4..f98812eeac 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Δεν έχεις αρκετή φήμη για να καταψηφίσεις αυτή την δημοσίευση", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "Το NodeBB συνάντησε ένα πρόβλημα καθώς γινόταν η ανανέωση: \"%1\". Το NodeBB θα συνεχίσει να προσφέρει τα στοιχεία του χρήστη, αν και θα ήταν καλή ιδέα να επαναφέρεις ότι έκανες πριν την ανανέωση.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json index c59382c86c..5730d9c642 100644 --- a/public/language/el/notifications.json +++ b/public/language/el/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "New Notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "You have unread notifications.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Στάλθηκε email επιβεβαίωσης." + "email-confirm-sent": "Στάλθηκε email επιβεβαίωσης.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/el/topic.json b/public/language/el/topic.json index b2e35c7484..61f1988f50 100644 --- a/public/language/el/topic.json +++ b/public/language/el/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Είσαι σίγουρος/η πως θέλεις να επαναφέρεις αυτό το θέμα;", "thread_tools.purge": "Εκκαθάριση Θέματος", "thread_tools.purge_confirm": "Είσαι σίγουρος/η πως θέλεις να εκκαθαρίσεις αυτό το θέμα;", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Το θέμα μετακινήθηκε στο %1 με επιτυχία", "post_delete_confirm": "Είσαι σίγουρος/η πως θέλεις να διαγράψεις αυτή την δημοσίευση;", "post_restore_confirm": "Είσαι σίγουρος/η πως θέλεις να επαναφέρεις αυτή την δημοσίευση;", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Εισαγωγή του τίτλου του θέματος εδώ...", "composer.handle_placeholder": "Name", "composer.discard": "Πέταγμα", diff --git a/public/language/el/user.json b/public/language/el/user.json index 04c306f982..242f7e1080 100644 --- a/public/language/el/user.json +++ b/public/language/el/user.json @@ -79,8 +79,6 @@ "digest_daily": "Ημερήσια", "digest_weekly": "Εβδομαδιαίως", "digest_monthly": "Μηνιαία", - "send_chat_notifications": "Αποστολή email αν μου έρθει μήνυμα συνομιλίας και δεν είμαι συνδεδεμένος", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Αυτός ο χρήστης δεν έχει κανέναν ακόλουθο :(", "follows_no_one": "Αυτός ο χρήστης δεν ακολουθεί κανέναν :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Επιλογές Περιήγησης", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Enable In-Topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/en-GB/admin/general/homepage.json b/public/language/en-GB/admin/general/homepage.json index 4866b8baf6..7428d59eeb 100644 --- a/public/language/en-GB/admin/general/homepage.json +++ b/public/language/en-GB/admin/general/homepage.json @@ -3,5 +3,6 @@ "description": "Choose what page is shown when users navigate to the root URL of your forum.", "home-page-route": "Home Page Route", "custom-route": "Custom Route", - "allow-user-home-pages": "Allow User Home Pages" + "allow-user-home-pages": "Allow User Home Pages", + "home-page-title": "Title of the home page (default \"Home\")" } \ No newline at end of file diff --git a/public/language/en-GB/admin/manage/users.json b/public/language/en-GB/admin/manage/users.json index f1651a814b..5b68fcdc91 100644 --- a/public/language/en-GB/admin/manage/users.json +++ b/public/language/en-GB/admin/manage/users.json @@ -27,6 +27,8 @@ "pills.banned": "Banned", "pills.search": "User Search", + "search.uid": "By User ID", + "search.uid-placeholder": "Enter a user ID to search", "search.username": "By User Name", "search.username-placeholder": "Enter a username to search", "search.email": "By Email", diff --git a/public/language/en-GB/admin/settings/chat.json b/public/language/en-GB/admin/settings/chat.json index 0b22127341..c538790b95 100644 --- a/public/language/en-GB/admin/settings/chat.json +++ b/public/language/en-GB/admin/settings/chat.json @@ -5,5 +5,7 @@ "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", "max-room-size": "Maximum number of users in chat rooms", - "delay": "Time between chat messages in milliseconds" + "delay": "Time between chat messages in milliseconds", + "restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit chat messages after posting. (0 disabled)", + "restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete chat messages after posting. (0 disabled)" } \ No newline at end of file diff --git a/public/language/en-GB/admin/settings/post.json b/public/language/en-GB/admin/settings/post.json index a789025597..6a1ab9a2a5 100644 --- a/public/language/en-GB/admin/settings/post.json +++ b/public/language/en-GB/admin/settings/post.json @@ -4,22 +4,27 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", + "length": "Post Length", "restrictions": "Posting Restrictions", + "restrictions-new": "New User Restrictions", "restrictions.post-queue": "Enable post queue", + "restrictions-new.post-queue": "Enable new user restrictions", "restrictions.post-queue-help": "Enabling post queue will put the posts of new users in a queue for approval.", - "restrictions.seconds-between": "Seconds between Posts", - "restrictions.seconds-between-new": "Seconds between Posts for New Users", - "restrictions.rep-threshold": "Reputation threshold before this restriction is lifted", + "restrictions-new.post-queue-help": "Enabling new user restrictions will set restrictions on posts created by new users.", + "restrictions.seconds-between": "Seconds between posts", + "restrictions.seconds-between-new": "Seconds between posts for new users", + "restrictions.rep-threshold": "Reputation threshold before these restrictions are lifted", "restrictions.seconds-defore-new": "Seconds before new user can post", - "restrictions.seconds-edit-after": "Number of seconds users are allowed to edit posts after posting. (0 disabled)", - "restrictions.seconds-delete-after": "Number of seconds users are allowed to delete posts after posting. (0 disabled)", + "restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit posts after posting. (0 disabled)", + "restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete posts after posting. (0 disabled)", "restrictions.replies-no-delete": "Number of replies after users are disallowed to delete their own topics. (0 disabled)", "restrictions.min-title-length": "Minimum Title Length", "restrictions.max-title-length": "Maximum Title Length", "restrictions.min-post-length": "Minimum Post Length", "restrictions.max-post-length": "Maximum Post Length", - "restrictions.days-until-stale": "Days until Topic is considered stale", + "restrictions.days-until-stale": "Days until topic is considered stale", "restrictions.stale-help": "If a topic is considered \"stale\", then a warning will be shown to users who attempt to reply to that topic.", "timestamp": "Timestamp", "timestamp.cut-off": "Date cut-off (in days)", diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/en-GB/admin/settings/user.json +++ b/public/language/en-GB/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/en-GB/email.json b/public/language/en-GB/email.json index a55f4f1f52..488af122bd 100644 --- a/public/language/en-GB/email.json +++ b/public/language/en-GB/email.json @@ -40,6 +40,8 @@ "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", "unsub.cta": "Click here to alter those settings", diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index 9d716ce95f..7700006520 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -20,6 +20,7 @@ "invalid-login-credentials": "Invalid login credentials", "invalid-username-or-password": "Please specify both a username and password", "invalid-search-term": "Invalid search term", + "invalid-url": "Invalid URL", "csrf-invalid": "We were unable to log you in, likely due to an expired session. Please try again", "invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2", @@ -137,6 +138,8 @@ "cant-edit-chat-message": "You are not allowed to edit this message", "cant-remove-last-user": "You can't remove the last user", "cant-delete-chat-message": "You are not allowed to delete this message", + "chat-edit-duration-expired": "You are only allowed to edit chat messages for %1 second(s) after posting", + "chat-delete-duration-expired": "You are only allowed to delete chat messages for %1 second(s) after posting", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", @@ -144,6 +147,7 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", @@ -151,6 +155,7 @@ "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", @@ -162,5 +167,7 @@ "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + + "no-topics-selected": "No topics selected!" } diff --git a/public/language/en-GB/global.json b/public/language/en-GB/global.json index 741fb4d2b8..b61d8f27b9 100644 --- a/public/language/en-GB/global.json +++ b/public/language/en-GB/global.json @@ -66,6 +66,7 @@ "topics": "Topics", "posts": "Posts", "best": "Best", + "votes": "Votes", "upvoters": "Upvoters", "upvoted": "Upvoted", "downvoters": "Downvoters", diff --git a/public/language/en-GB/notifications.json b/public/language/en-GB/notifications.json index 7812eabf7c..50214f3f95 100644 --- a/public/language/en-GB/notifications.json +++ b/public/language/en-GB/notifications.json @@ -10,6 +10,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "New Notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "You have unread notifications.", "all": "All", @@ -50,5 +51,20 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "email-confirm-sent": "Confirmation email sent.", + + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } diff --git a/public/language/en-GB/pages.json b/public/language/en-GB/pages.json index c89266b661..201d10ef0a 100644 --- a/public/language/en-GB/pages.json +++ b/public/language/en-GB/pages.json @@ -6,6 +6,7 @@ "popular-month": "Popular topics this month", "popular-alltime": "All time popular topics", "recent": "Recent Topics", + "top": "Top Voted Topics", "moderator-tools": "Moderator Tools", "flagged-content": "Flagged Content", "ip-blacklist": "IP Blacklist", diff --git a/public/language/en-GB/top.json b/public/language/en-GB/top.json new file mode 100644 index 0000000000..b8a05bfa5f --- /dev/null +++ b/public/language/en-GB/top.json @@ -0,0 +1,4 @@ +{ + "title": "Top", + "no_top_topics": "No top topics" +} \ No newline at end of file diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index d206960156..39d2811931 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -79,6 +79,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm" : "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", @@ -105,6 +107,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Enter your topic title here...", "composer.handle_placeholder": "Name", diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index 3916663282..466f6c27e4 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -84,8 +84,6 @@ "digest_daily": "Daily", "digest_weekly": "Weekly", "digest_monthly": "Monthly", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "This user doesn't have any followers :(", @@ -112,6 +110,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Browsing Settings", "open_links_in_new_tab": "Open outgoing links in new tab", @@ -141,6 +144,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", diff --git a/public/language/en-US/admin/appearance/customise.json b/public/language/en-US/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/en-US/admin/appearance/customise.json +++ b/public/language/en-US/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/en-US/admin/menu.json b/public/language/en-US/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/en-US/admin/menu.json +++ b/public/language/en-US/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/en-US/admin/settings/notifications.json b/public/language/en-US/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/en-US/admin/settings/notifications.json +++ b/public/language/en-US/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/en-US/admin/settings/post.json b/public/language/en-US/admin/settings/post.json index f938a7e7d7..18283565b2 100644 --- a/public/language/en-US/admin/settings/post.json +++ b/public/language/en-US/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/en-US/admin/settings/user.json b/public/language/en-US/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/en-US/admin/settings/user.json +++ b/public/language/en-US/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/en-US/email.json b/public/language/en-US/email.json index c1e17018fa..164e70795e 100644 --- a/public/language/en-US/email.json +++ b/public/language/en-US/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", "unsub.cta": "Click here to alter those settings", "banned.subject": "You have been banned from %1", diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json index 82d34b5e05..a986e97f0f 100644 --- a/public/language/en-US/error.json +++ b/public/language/en-US/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/en-US/notifications.json b/public/language/en-US/notifications.json index 8fb6665d1c..cbb80a396e 100644 --- a/public/language/en-US/notifications.json +++ b/public/language/en-US/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "New Notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "You have unread notifications.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "email-confirm-sent": "Confirmation email sent.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/en-US/topic.json b/public/language/en-US/topic.json index 9c41963d50..2ba819ecdf 100644 --- a/public/language/en-US/topic.json +++ b/public/language/en-US/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", "post_delete_confirm": "Are you sure you want to delete this post?", "post_restore_confirm": "Are you sure you want to restore this post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Enter your topic title here...", "composer.handle_placeholder": "Name", "composer.discard": "Discard", diff --git a/public/language/en-US/user.json b/public/language/en-US/user.json index fb7fda5945..f92b22c3d5 100644 --- a/public/language/en-US/user.json +++ b/public/language/en-US/user.json @@ -79,8 +79,6 @@ "digest_daily": "Daily", "digest_weekly": "Weekly", "digest_monthly": "Monthly", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "This user doesn't have any followers :(", "follows_no_one": "This user isn't following anyone :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Browsing Settings", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Enable In-Topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/en-x-pirate/admin/appearance/customise.json b/public/language/en-x-pirate/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/en-x-pirate/admin/appearance/customise.json +++ b/public/language/en-x-pirate/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/en-x-pirate/admin/menu.json b/public/language/en-x-pirate/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/en-x-pirate/admin/menu.json +++ b/public/language/en-x-pirate/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/en-x-pirate/admin/settings/notifications.json b/public/language/en-x-pirate/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/en-x-pirate/admin/settings/notifications.json +++ b/public/language/en-x-pirate/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/en-x-pirate/admin/settings/post.json b/public/language/en-x-pirate/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/en-x-pirate/admin/settings/post.json +++ b/public/language/en-x-pirate/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/en-x-pirate/admin/settings/user.json b/public/language/en-x-pirate/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/en-x-pirate/admin/settings/user.json +++ b/public/language/en-x-pirate/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/en-x-pirate/email.json b/public/language/en-x-pirate/email.json index d46ef9d972..6cbe176151 100644 --- a/public/language/en-x-pirate/email.json +++ b/public/language/en-x-pirate/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", "unsub.cta": "Click here to alter those settings", "banned.subject": "You have been banned from %1", diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json index 82d34b5e05..a986e97f0f 100644 --- a/public/language/en-x-pirate/error.json +++ b/public/language/en-x-pirate/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/en-x-pirate/notifications.json b/public/language/en-x-pirate/notifications.json index e3641543d5..81473f4a92 100644 --- a/public/language/en-x-pirate/notifications.json +++ b/public/language/en-x-pirate/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "New Notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "You have unread notifications.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "email-confirm-sent": "Confirmation email sent.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/en-x-pirate/topic.json b/public/language/en-x-pirate/topic.json index 9c41963d50..2ba819ecdf 100644 --- a/public/language/en-x-pirate/topic.json +++ b/public/language/en-x-pirate/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", "post_delete_confirm": "Are you sure you want to delete this post?", "post_restore_confirm": "Are you sure you want to restore this post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Enter your topic title here...", "composer.handle_placeholder": "Name", "composer.discard": "Discard", diff --git a/public/language/en-x-pirate/user.json b/public/language/en-x-pirate/user.json index d60f568fa9..477d4992f5 100644 --- a/public/language/en-x-pirate/user.json +++ b/public/language/en-x-pirate/user.json @@ -79,8 +79,6 @@ "digest_daily": "Daily", "digest_weekly": "Weekly", "digest_monthly": "Monthly", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "This user doesn't have any followers :(", "follows_no_one": "This user isn't following anyone :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Browsing Settings", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Enable In-Topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/es/admin/appearance/customise.json b/public/language/es/admin/appearance/customise.json index ad8ae104a8..0f707eb156 100644 --- a/public/language/es/admin/appearance/customise.json +++ b/public/language/es/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Introduce tus propias declaraciones CSS aquí, las cuales serán aplicadas después de otros estilos.", "custom-css.enable": "Activar CSS personalizado", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Cabezera personalizada", - "custom-header.description": "Introduce HTML personalizado aquí (ej. JavaScript, Meta Etiquetas, etc.), el cual se adjuntará a la sección <head> del código de su foro.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Activar cabecera personalizada", "custom-css.livereload": "Activar Recargar en Vivo", diff --git a/public/language/es/admin/menu.json b/public/language/es/admin/menu.json index d4e0428127..092ff469e7 100644 --- a/public/language/es/admin/menu.json +++ b/public/language/es/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Apariencia", "appearance/themes": "Temas", "appearance/skins": "Pieles", - "appearance/customise": "HTML & CSS personalizado", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extender", "extend/plugins": "Extensiones", diff --git a/public/language/es/admin/settings/notifications.json b/public/language/es/admin/settings/notifications.json index 7cfd68f3d6..ab07a69717 100644 --- a/public/language/es/admin/settings/notifications.json +++ b/public/language/es/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notificaciones", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/es/admin/settings/post.json b/public/language/es/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/es/admin/settings/post.json +++ b/public/language/es/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/es/admin/settings/user.json b/public/language/es/admin/settings/user.json index 73e93f05d0..6147c898a3 100644 --- a/public/language/es/admin/settings/user.json +++ b/public/language/es/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/es/email.json b/public/language/es/email.json index 7eed5d4d2d..21168da991 100644 --- a/public/language/es/email.json +++ b/public/language/es/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Esta notificación de chat se te envió debido a tus ajustes de suscripción.", "notif.post.cta": "Cliquea aquí para leer la publicación completa", "notif.post.unsub.info": "La notificación de este mensaje se te ha enviado debido a tus ajustes de subscripción.", + "notif.cta": "Click here to go to forum", "test.text1": "Este es un email de prueba para verificar que el envío de email está ajustado correctamente para tu NodeBB", "unsub.cta": "Haz click aquí para modificar los ajustes.", "banned.subject": "Has sido baneado de %1", diff --git a/public/language/es/error.json b/public/language/es/error.json index da31813650..2bb7f77001 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "No tienes suficiente reputación para votar negativo este post", "not-enough-reputation-to-flag": "No tiene suficiente reputación para poner reportar esta publicación", "already-flagged": "Ya reportaste este mensaje anteriormente", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encontró un problema al refrescar: \"%1\". NodeBB intentará cargar el resto de contenido, aunque deberías deshacer lo que hiciste justo antes.", "registration-error": "Error de registro", "parse-error": "Algo ha ido mal mientras se parseaba la respuesta del servidor", "wrong-login-type-email": "Por favor emplea tu email para acceder", "wrong-login-type-username": "Por favor introduce tu nombre de usuario para acceder", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Has alcanzado el número máximo de personas invitadas (%1 de %2).", "no-session-found": "¡No se ha encontrado ningún inicio de sesión!", "not-in-room": "El usuario no está en la sala", @@ -132,5 +134,6 @@ "no-users-selected": "Ningun usuario(s) seleccionado", "invalid-home-page-route": "Ruta de página de inicio invalida", "invalid-session": "No concuerdan los datos de sesión", - "invalid-session-text": "Parece que su sesión ha expirado o no concuerda con el servidor. Por favor vuelva a cargar la página." + "invalid-session-text": "Parece que su sesión ha expirado o no concuerda con el servidor. Por favor vuelva a cargar la página.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json index 8d8ec31faf..b771224b29 100644 --- a/public/language/es/notifications.json +++ b/public/language/es/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuar a %1", "return_to": "Regresar a %1", "new_notification": "Nueva notificación", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Tienes notificaciones sin leer.", "all": "Todo", "topics": "Temas", @@ -45,5 +46,19 @@ "email-confirmed": "Correo electrónico confirmado", "email-confirmed-message": "Gracias por validar tu correo electrónico. Tu cuenta ya está completamente activa.", "email-confirm-error-message": "Hubo un problema al validar tu cuenta de correo electrónico. Quizá el código era erróneo o expiró...", - "email-confirm-sent": "Correo de confirmación enviado." + "email-confirm-sent": "Correo de confirmación enviado.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/es/topic.json b/public/language/es/topic.json index 50496a6106..7d3c75de23 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "¿Estás seguro que deseas restaurar este tema?", "thread_tools.purge": "Purgar tema", "thread_tools.purge_confirm": "¿Está seguro que desea eliminar definitivamente (purgar) este tema?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "El tema ha sido movido correctamente a %1", "post_delete_confirm": "¿Estás seguro de que quieres eliminar esta respuesta?", "post_restore_confirm": "¿Estás seguro de que quieres restaurar esta respuesta?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 mensaje(s) seleccionados", "fork_success": "¡Se ha creado un nuevo tema a partir del original! Haz click aquí para ir al nuevo tema.", "delete_posts_instruction": "Haz click en los mensajes que quieres eliminar/limpiar", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Ingresa el título de tu tema...", "composer.handle_placeholder": "Nombre", "composer.discard": "Descartar", diff --git a/public/language/es/user.json b/public/language/es/user.json index a46d95d741..87d86d5e66 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -79,8 +79,6 @@ "digest_daily": "Diariamente", "digest_weekly": "Semanalmente", "digest_monthly": "Mensualmente", - "send_chat_notifications": "Enviar un email si recibo un mensaje de chat cuando no esté en línea.", - "send_post_notifications": "Enviarme un email cuando se realicen contestaciones en los temas en los que estoy subscrito", "settings-require-reload": "Algunos cambios de configuración requieren una recarga la página. Haz click aquí para recargar la página.", "has_no_follower": "Este usuario no tiene seguidores :(", "follows_no_one": "Este miembro no sigue a nadie :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Sonido del mensaje saliente", "notification-sound": "Sonido de notificación", "no-sound": "Sin sonido", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Preferencias de navegación.", "open_links_in_new_tab": "Abrir los enlaces externos en una nueva pestaña", "enable_topic_searching": "Activar la búsqueda \"dentro del tema\"", @@ -123,6 +126,9 @@ "sso.title": "Servicios de Inicio de sesión Único", "sso.associated": "Asociado con", "sso.not-associated": "Da clic aquí para asociarse con", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Ultimos reportes", "info.no-flags": "Ningun mensaje reportado encontrado", "info.ban-history": "Histórico reciente de bans", diff --git a/public/language/et/admin/appearance/customise.json b/public/language/et/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/et/admin/appearance/customise.json +++ b/public/language/et/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/et/admin/menu.json b/public/language/et/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/et/admin/menu.json +++ b/public/language/et/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/et/admin/settings/notifications.json b/public/language/et/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/et/admin/settings/notifications.json +++ b/public/language/et/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/et/admin/settings/post.json b/public/language/et/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/et/admin/settings/post.json +++ b/public/language/et/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/et/admin/settings/user.json b/public/language/et/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/et/admin/settings/user.json +++ b/public/language/et/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/et/email.json b/public/language/et/email.json index 38d3a3bb82..a51f25e36e 100644 --- a/public/language/et/email.json +++ b/public/language/et/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "See chat teavitus on saadetud teile tellimuse seadistuse tõttu.", "notif.post.cta": "Vajuta siia, et lugeda teemat täies mahus", "notif.post.unsub.info": "See postituse teavitus on saadetud teile tellimuse seadistuse tõttu.", + "notif.cta": "Click here to go to forum", "test.text1": "See on test e-mail kinnitamaks, et emailer on korrektselt seadistatud sinu NodeBB jaoks.", "unsub.cta": "Vajuta siia, et muuta neid seadeid", "banned.subject": "You have been banned from %1", diff --git a/public/language/et/error.json b/public/language/et/error.json index 6d31ddc060..f3f6aee255 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Sul ei ole piisavalt reputatsiooni, et anda negatiivset hinnangut sellele postitusele.", "not-enough-reputation-to-flag": "Sul ei ole piisavalt reputatsiooni, et seda postitust raporteerida", "already-flagged": "Te juba teatasite sellest postitusest.", + "self-vote": "You cannot vote on your own post", "reload-failed": "\"%1\" värskendamisel tekkis süsteemne viga. Foorum ei lakka töötamast, kuid peaksid kindlasti eemaldama enne värskendamist tehtud muudatused.", "registration-error": "Viga registreerimisel", "parse-error": "Midagi läks valesti...", "wrong-login-type-email": "Sisse logimiseks kasuta oma emaili", "wrong-login-type-username": "Sisse logimiseks kasuta oma kasutajanime", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Sa oled kutsunud maksimaalse lubatud inimeste arvu (%1 %2 'st).", "no-session-found": "Sisse logimis sessiooni ei leitud!", "not-in-room": "Kasutaja pole ruumis", @@ -132,5 +134,6 @@ "no-users-selected": "Ühtki kasutajat pole valitud", "invalid-home-page-route": "Vigane avalehe suunamine", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json index 87d23584ed..fb06480814 100644 --- a/public/language/et/notifications.json +++ b/public/language/et/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Jätka %1", "return_to": "Pöördu tagasi %1", "new_notification": "Uus teade", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Sul ei ole lugemata teateid.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Emaili aadress kinnitatud", "email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja on nüüd täielikult aktiveeritud.", "email-confirm-error-message": "Emaili aadressi kinnitamisel tekkis viga. Võibolla kinnituskood oli vale või aegunud.", - "email-confirm-sent": "Kinnituskiri on saadetud." + "email-confirm-sent": "Kinnituskiri on saadetud.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/et/topic.json b/public/language/et/topic.json index ce17ec70e0..90f8a84493 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Oled kindel, et soovid selle teema taastada?", "thread_tools.purge": "Kustuta teema täielikult", "thread_tools.purge_confirm": "Oled kindel, et soovid puhastada selle teema?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Teema liigutatud kategooriasse %1", "post_delete_confirm": "Oled kindel, et soovid kustutada selle postituse?", "post_restore_confirm": "Oled kindel, et soovid taastada antud postituse?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 postitus(t) valitud", "fork_success": "Edukalt ''forkisid'' teema! Vajuta siia, et vaadata loodud teemat.", "delete_posts_instruction": "Klikka postitustel, mida tahad kustutada/puhastada", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Sisesta teema pealkiri siia...", "composer.handle_placeholder": "Nimi", "composer.discard": "Katkesta", diff --git a/public/language/et/user.json b/public/language/et/user.json index 94acd29c19..b1523455f9 100644 --- a/public/language/et/user.json +++ b/public/language/et/user.json @@ -79,8 +79,6 @@ "digest_daily": "Igapäevaselt", "digest_weekly": "Iga nädal", "digest_monthly": "Iga kuu", - "send_chat_notifications": "Saada mulle email kui mulle saabub uus sõnum ja ma ei ole antud hetkel online", - "send_post_notifications": "Saada e-mail kui minu poolt jälgitavatele teemadele vastatakse", "settings-require-reload": "Muudatused seadetes nõuavad lehe uuesti laadimist. Lehe värskendamiseks vajuta siia.", "has_no_follower": "Sellel kasutajal pole ühtegi jälgijat :(", "follows_no_one": "See kasutaja ei jälgi kedagi :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Sirvimis sätted", "open_links_in_new_tab": "Ava väljaminevad lingid uues aknas", "enable_topic_searching": "Võimalda teemasisene otsing", @@ -123,6 +126,9 @@ "sso.title": "Ühekordse sisselogimisega teenused", "sso.associated": "Seotud koos", "sso.not-associated": "Kliki siia, et siduda koos", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Viimased raporteerimised", "info.no-flags": "Raporteeritud postitusi ei leitud", "info.ban-history": "Hiljutiste keeldude ajalugu", diff --git a/public/language/fa-IR/admin/appearance/customise.json b/public/language/fa-IR/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/fa-IR/admin/appearance/customise.json +++ b/public/language/fa-IR/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/fa-IR/admin/extend/plugins.json b/public/language/fa-IR/admin/extend/plugins.json index 16bc9f33ae..7515f72590 100644 --- a/public/language/fa-IR/admin/extend/plugins.json +++ b/public/language/fa-IR/admin/extend/plugins.json @@ -1,14 +1,14 @@ { - "installed": "نصب شده", - "active": "فعال", - "inactive": "غیرفعال", + "installed": "Installed", + "active": "Active", + "inactive": "Inactive", "out-of-date": "Out of Date", - "none-found": "هیچ پلاگینی یافت نشد.", + "none-found": "No plugins found.", "none-active": "No Active Plugins", - "find-plugins": "پیدا کردن پلاگین ها", + "find-plugins": "Find Plugins", - "plugin-search": "جستجوی پلاگین", - "plugin-search-placeholder": "جستجو برای پلاگین", + "plugin-search": "Plugin Search", + "plugin-search-placeholder": "Search for plugin...", "reorder-plugins": "Re-order Plugins", "order-active": "Order Active Plugins", "dev-interested": "Interested in writing plugins for NodeBB?", @@ -17,35 +17,35 @@ "order.description": "Certain plugins work ideally when they are initialised before/after other plugins.", "order.explanation": "Plugins load in the order specified here, from top to bottom", - "plugin-item.themes": "پوسته", - "plugin-item.deactivate": "غیر فعال کردن", - "plugin-item.activate": "فعال کردن", - "plugin-item.install": "نصب کردن", - "plugin-item.uninstall": "حذف کردن", - "plugin-item.settings": "تنظیمات", - "plugin-item.installed": "نصب شده", - "plugin-item.latest": "آخرین", - "plugin-item.upgrade": "ارتقاء", - "plugin-item.more-info": "برای اطلاعات بیشتر:", - "plugin-item.unknown": "ناشناخته", + "plugin-item.themes": "Themes", + "plugin-item.deactivate": "Deactivate", + "plugin-item.activate": "Activate", + "plugin-item.install": "Install", + "plugin-item.uninstall": "Uninstall", + "plugin-item.settings": "Settings", + "plugin-item.installed": "Installed", + "plugin-item.latest": "Latest", + "plugin-item.upgrade": "Upgrade", + "plugin-item.more-info": "For more information:", + "plugin-item.unknown": "Unknown", "plugin-item.unknown-explanation": "The state of this plugin could not be determined, possibly due to a misconfiguration error.", - "alert.enabled": "پلاگین فعال شد", - "alert.disabled": "پلاگین غیرفعال شد", - "alert.upgraded": "پلاگین ارتقاء یافت", - "alert.installed": "پلاگین نصب شد", - "alert.uninstalled": "پلاگین حذف شد", + "alert.enabled": "Plugin Enabled", + "alert.disabled": "Plugin Disabled", + "alert.upgraded": "Plugin Upgraded", + "alert.installed": "Plugin Installed", + "alert.uninstalled": "Plugin Uninstalled", "alert.activate-success": "Please restart your NodeBB to fully activate this plugin", - "alert.deactivate-success": "پلاگین با موفقیت غیر فعال شد", + "alert.deactivate-success": "Plugin successfully deactivated", "alert.upgrade-success": "Please reload your NodeBB to fully upgrade this plugin", - "alert.install-success": "پلاگین با موفقیت نصب شد، لطفا پلاگین را فعال کنید", - "alert.uninstall-success": "پلاگین با موفقیت غیرفعال و حذف شده است", + "alert.install-success": "Plugin successfully installed, please activate the plugin.", + "alert.uninstall-success": "The plugin has been successfully deactivated and uninstalled.", "alert.suggest-error": "

NodeBB could not reach the package manager, proceed with installation of latest version?

Server returned (%1): %2
", "alert.package-manager-unreachable": "

NodeBB could not reach the package manager, an upgrade is not suggested at this time.

", "alert.incompatible": "

Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.

", "alert.possibly-incompatible": "

No Compatibility Information Found

This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.

In the event that NodeBB cannot boot properly:

$ ./nodebb reset plugin=\"%1\"

Continue installation of latest version of this plugin?

", - "license.title": "اطلاعات مجوز پلاگین ", + "license.title": "Plugin License Information", "license.intro": "The plugin %1 is licensed under the %2. Please read and understand the license terms prior to activating this plugin.", - "license.cta": "آیا می خواهید پلاگین را فعال کنید؟" + "license.cta": "Do you wish to continue with activating this plugin?" } diff --git a/public/language/fa-IR/admin/general/languages.json b/public/language/fa-IR/admin/general/languages.json index bd1b49274d..bdd57849b3 100644 --- a/public/language/fa-IR/admin/general/languages.json +++ b/public/language/fa-IR/admin/general/languages.json @@ -1,6 +1,6 @@ { - "language-settings": "تنظیمات زبان", + "language-settings": "Language Settings", "description": "The default language determines the language settings for all users who are visiting your forum.
Individual users can override the default language on their account settings page.", - "default-language": "زبان پیش فرض", - "auto-detect": "شناسایی خودکار تنظیمات زبان برای مهمانان" + "default-language": "Default Language", + "auto-detect": "Auto Detect Language Setting for Guests" } \ No newline at end of file diff --git a/public/language/fa-IR/admin/menu.json b/public/language/fa-IR/admin/menu.json index 204d8e24a9..4c61f97103 100644 --- a/public/language/fa-IR/admin/menu.json +++ b/public/language/fa-IR/admin/menu.json @@ -1,10 +1,10 @@ { "section-general": "General", - "general/dashboard": "داشبورد", + "general/dashboard": "Dashboard", "general/homepage": "Home Page", "general/navigation": "Navigation", - "general/languages": "زبان ها", - "general/sounds": "صداها", + "general/languages": "Languages", + "general/sounds": "Sounds", "general/social": "Social", "section-manage": "Manage", @@ -13,12 +13,12 @@ "manage/users": "Users", "manage/registration": "Registration Queue", "manage/post-queue": "Post Queue", - "manage/groups": "گروه ها", - "manage/ip-blacklist": "لیست سیاه IP", + "manage/groups": "Groups", + "manage/ip-blacklist": "IP Blacklist", - "section-settings": "تنظیمات", + "section-settings": "Settings", "settings/general": "General", - "settings/reputation": "اعتبار", + "settings/reputation": "Reputation", "settings/email": "Email", "settings/user": "User", "settings/group": "Group", @@ -36,34 +36,34 @@ "settings.page-title": "%1 Settings", - "section-appearance": "ظاهر", - "appearance/themes": "پوسته ها", + "section-appearance": "Appearance", + "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", - "extend/plugins": "پلاگین ها", - "extend/widgets": "ویجت ها", - "extend/rewards": "پاداش ها", + "extend/plugins": "Plugins", + "extend/widgets": "Widgets", + "extend/rewards": "Rewards", "section-social-auth": "Social Authentication", - "section-plugins": "پلاگین ها", + "section-plugins": "Plugins\n", "extend/plugins.install": "Install Plugins", "section-advanced": "Advanced", "advanced/database": "Database", "advanced/events": "Events", "advanced/logs": "Logs", - "advanced/errors": "خطاها", + "advanced/errors": "Errors", "advanced/cache": "Cache", "development/logger": "Logger", "development/info": "Info", "reload-forum": "Reload Forum", - "restart-forum": "راه اندازی مجدد انجمن", - "logout": "خروج", - "view-forum": "مشاهده انجمن", + "restart-forum": "Restart Forum", + "logout": "Log out", + "view-forum": "View Forum", "search.placeholder": "Search for settings", "search.no-results": "No results...", diff --git a/public/language/fa-IR/admin/settings/chat.json b/public/language/fa-IR/admin/settings/chat.json index 6c827e42f5..0b22127341 100644 --- a/public/language/fa-IR/admin/settings/chat.json +++ b/public/language/fa-IR/admin/settings/chat.json @@ -1,7 +1,7 @@ { - "chat-settings": "تنظیمات گفتگو ها", - "disable": "غیرفعال کردن چت", - "disable-editing": "غیرفعال کردن ویرایش کردن / پاک کردن پیام های چت", + "chat-settings": "Chat Settings", + "disable": "Disable chat", + "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", "max-room-size": "Maximum number of users in chat rooms", diff --git a/public/language/fa-IR/admin/settings/notifications.json b/public/language/fa-IR/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/fa-IR/admin/settings/notifications.json +++ b/public/language/fa-IR/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/fa-IR/admin/settings/post.json b/public/language/fa-IR/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/fa-IR/admin/settings/post.json +++ b/public/language/fa-IR/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/fa-IR/admin/settings/uploads.json b/public/language/fa-IR/admin/settings/uploads.json index 56161ea170..f7b860983a 100644 --- a/public/language/fa-IR/admin/settings/uploads.json +++ b/public/language/fa-IR/admin/settings/uploads.json @@ -1,6 +1,6 @@ { "posts": "پست‌ها", - "allow-files": "اجازه بارگذاری فایل های معمولی به کاربران", + "allow-files": "Allow users to upload regular files", "private": "Make uploaded files private", "max-image-width": "Resize images down to specified width (in pixels)", "max-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)", @@ -14,15 +14,15 @@ "allow-profile-image-uploads": "Allow users to upload profile images", "convert-profile-image-png": "Convert profile image uploads to PNG", "default-avatar": "Custom Default Avatar", - "upload": "بارگذاری", + "upload": "Upload", "profile-image-dimension": "Profile Image Dimension", "profile-image-dimension-help": "(in pixels, default: 128 pixels)", "max-profile-image-size": "Maximum Profile Image File Size", - "max-profile-image-size-help": "(برحسب kibibytes، پیش فرض : 256 KiB)", + "max-profile-image-size-help": "(in kibibytes, default: 256 KiB)", "max-cover-image-size": "Maximum Cover Image File Size", - "max-cover-image-size-help": "(برحسب kibibytes، پیش فرض : 2,048 KiB)", + "max-cover-image-size-help": "(in kibibytes, default: 2,048 KiB)", "keep-all-user-images": "Keep old versions of avatars and profile covers on the server", - "profile-covers": "کاور های پروفایل", - "default-covers": "عکس های کاور پیش فرض", + "profile-covers": "Profile Covers", + "default-covers": "Default Cover Images", "default-covers-help": "Add comma-separated default cover images for accounts that don't have an uploaded cover image" } diff --git a/public/language/fa-IR/admin/settings/user.json b/public/language/fa-IR/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/fa-IR/admin/settings/user.json +++ b/public/language/fa-IR/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/fa-IR/email.json b/public/language/fa-IR/email.json index b040de56ee..bb32850ecb 100644 --- a/public/language/fa-IR/email.json +++ b/public/language/fa-IR/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "این اطلاعیه ی چتیی که برای شما فرستاده شده به علت تنظیمات اشترک شماست.", "notif.post.cta": "برای مشاهده کامل موضوع اینجا کلیک کنید", "notif.post.unsub.info": "این اطلاعیه ی پستی که برای شما فرستاده شده به علت تنظیمات اشترک شماست.", + "notif.cta": "برای رفتن به انجمن اینجا کلیک کنید", "test.text1": "این یک ایمیل امتحانی جهت تایید اینکه فرستنده ایمیل برای انجمن NodeBB شما به درستی تنظیم و نصب شده است", "unsub.cta": "برای ویرایش آن تنظیمات اینجا کلیک کنید", "banned.subject": "You have been banned from %1", diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json index e92a1e5f67..27ca06d761 100644 --- a/public/language/fa-IR/error.json +++ b/public/language/fa-IR/error.json @@ -18,7 +18,7 @@ "invalid-username-or-password": "لطفا هم نام کاربری و هم کلمه عبور را مشخص کنید", "invalid-search-term": "کلمه جستجو نامعتبر است", "csrf-invalid": "اجازه ورود شما تمام شده است، لطفا دوباره وارد شوید.", - "invalid-pagination-value": "ارزش گذاری صفحه نامعتبر است، کمترین مقدار 1% و بیشترین مقدار 2% باید باشد", + "invalid-pagination-value": "ارزش گذاری صفحه نامعتبر است، کمترین مقدار %1 و بیشترین مقدار %2 باید باشد", "username-taken": "این نام کاربری گرفته شده است.", "email-taken": "این ایمیل گرفته شده است.", "email-not-confirmed": "ایمیل شما تاکنون تایید نشده است، برای تایید ایمیل خود را اینجا را کلیک کنید.", @@ -26,14 +26,14 @@ "email-not-confirmed-email-sent": "ایمیل شما هنوز تایید نشده است، لطفا صندوق پیام های خود را برای تایید ایمیل بررسی کنید.", "no-email-to-confirm": "ایمیل شما تایید نشده است ، لطفا برای وارد کردن ایمیل اینجا کلیک کنید", "email-confirm-failed": "سیستم موفق به تایید ایمیل شما نشد، لطفا بعدا دوباره سعی کنید", - "confirm-email-already-sent": "ایمیل فعال‌سازی قبلا فرستاده شده، لطفا %1 دقیقه صبر کنید تا ایمیل دیگری بفرستید.", + "confirm-email-already-sent": "ایمیل فعال‌سازی قبلا فرستاده شده، لطفا %1 دقیقه صبر کنید تا ایمیل دیگری فرستاده شود.", "sendmail-not-found": "اجازه ارسال رایانامه پیدا نشد، لطفا مطمئن شوید این قابلیت نصب شده و توسط کاربر مد نظر در نود‌بی‌بی قابل اجرا است.", "username-too-short": "نام کاربری خیلی کوتاه است.", "username-too-long": "نام کاربری بسیار طولانیست", "password-too-long": "کلمه عبور بسیار طولانیست", "user-banned": "کاربر اخراج شد", "user-banned-reason": "با عرض پوزش، این حساب کاربری از انجمن اخراج شده است (دلیل: %1)", - "user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)", + "user-banned-reason-until": "با عرض پوزش، این حساب کاربری تا %1 اخراج شده است (دلیل: %2)", "user-too-new": "با عرض پوزش، شما باید %1 ثانیه پیش از فرستادن پست نخست خود صبر کنید", "blacklisted-ip": "با عرض پوزش فراوان، نشانی آی پی شما در این انجمن مسدود شده است، اگر فکر می‌کنید اشتباهی رخ داده با مدیریت انجمن تماس بگیرید.", "ban-expiry-missing": "لطفا تاریخ پایان برای این مسدود کردن ارائه دهید", @@ -61,14 +61,14 @@ "post-delete-duration-expired-days": "شما تنها می توانید %1 روز(ها) پس از فرستادن پست آن‌ را پاک کنید", "post-delete-duration-expired-days-hours": "شما تنها می توانید %1 روز(ها) %2 ساعت(ها) پس از فرستادن پست آن‌ را پاک کنید", "cant-delete-topic-has-reply": "اگر کسی به موضوع شما پاسخ داده باشد، نمیتوانید آنرا حذف نمائید", - "cant-delete-topic-has-replies": "اگر 1% به موضوع جواب داده شده باشد ، نمیتوانید آنرا حذف نمائید", + "cant-delete-topic-has-replies": "اگر %1 به موضوع جواب داده شده باشد ، نمیتوانید آنرا حذف نمائید", "content-too-short": "خواهشمندیم پست بلندتری بنویسید. پست‌ها دست‌کم باید %1 کاراکتر داشته باشند.", "content-too-long": "لطفا طول مطلب را کوتاه تر کنید. طول پست نمیتواند بیشتر از %1 کاراکتر باشد.", "title-too-short": "لطفا یک عنوان بلندتر وارد کنید. عنوان باید حداقل %1 کاراکتر داشته باشد.", "title-too-long": "لطفا یک عنوان بلندتر وارد کنید. عنوان باید حداقل %1 کاراکتر داشته باشد.", "category-not-selected": "هیچ دسته‌بندی انتخاب نشده.", "too-many-posts": "شما می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ارسال پست جدید صبر کنید", - "too-many-posts-newbie": "به عنوان یک کاربر جدید ، تا زمانی که شما 2% اعتبار کسب کنید می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ایجاد پست جدید صبر کنید .", + "too-many-posts-newbie": "به عنوان یک کاربر جدید ، تا زمانی که شما %2 اعتبار کسب کنید می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ایجاد پست جدید صبر کنید .", "tag-too-short": "لطفا برچسب بلندتری وارد کنید. برچسبها باید حداقل %1 کاراکتر داشته باشند.", "tag-too-long": "لطفا برچسب کوتاه تری وارد کنید . برچسب ها نباید بیشتر از %1 کاراکتر داشته باشند", "not-enough-tags": "تعداد برچسب ها کافی نیست. موضوع ها یابد حداقل %1 برچسب داشته باشند", @@ -109,7 +109,7 @@ "chat-disabled": "سیستم گفتمان غیرفعال شده است", "too-many-messages": "شما پیامهای خیلی زیادی فرستاده اید، لطفا مدتی صبر نمایید", "invalid-chat-message": "پیام نامعتبر", - "chat-message-too-long": "پیام های چت نمی توانند بیشتر از 1 درصد کاراکتر ها باشند.", + "chat-message-too-long": "پیام های چت نمی توانند بیشتر از %1 کاراکتر باشند.", "cant-edit-chat-message": "شما اجازه ی ویرایش این پیام را ندارید", "cant-remove-last-user": "شما نمی توانید آخرین کاربر را حذف کنید", "cant-delete-chat-message": "شما اجازه حذف این پیام را ندارید.", @@ -118,19 +118,22 @@ "downvoting-disabled": "رأی منفی غیر فعال شده است", "not-enough-reputation-to-downvote": "شما اعتبار کافی برای دادن رأی منفی به این پست را ندارید.", "not-enough-reputation-to-flag": "شما اعتبار کافی برای نشاندار کردن این پست ندارید", - "already-flagged": "شما قبلا این پست را پرچمگذاری کرده اید", + "already-flagged": "شما قبلا این پست را گزارش کرده اید", + "self-vote": "شما نمی توانید به پست خود رای بدهید", "reload-failed": "NodeBB در هنگام بارگذاری مجدد با یک مشکل مواجه شده است: \"%1\". NodeBB سرویس رسانی به کلاینت های سرویس گیرنده را ادامه خواهد داد، اگرچه شما کاری را قبل از بارگیری مجدد انجام دادید بازگردانی کنید", "registration-error": "خطای ثبت نام", "parse-error": "هنگام تجزیه پاسخ سرور اشتباهی پیش امد", "wrong-login-type-email": "لطفا از ایمیل خود برای ورود استفاده کنید", "wrong-login-type-username": "لطفا از نام کاربری خود برای ورود استفاده کنید", - "invite-maximum-met": "ظرفیت دعوت شما تکمیل شده است (1% از 2%)", - "no-session-found": "هیچ سشن ورودی یافت نشد!", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", + "invite-maximum-met": "ظرفیت دعوت شما تکمیل شده است (%1 از %2)", + "no-session-found": "هیچ session ورودی یافت نشد!", "not-in-room": "هیچ کاربری در این گفتگو نیست", "no-users-in-room": "هیچ کاربری در این گفتگو نیست", "cant-kick-self": "شما نمی توانید خودتان را از گروه کیک کنید", "no-users-selected": "هیچ کاربر(های) انتخاب نشده", "invalid-home-page-route": "مسیر صفحه اصلی نامعتبر است", "invalid-session": "عدم تطابق جلسه", - "invalid-session-text": "به نظر می‌رسد این جلسه برای ورود دیگر فعال نیست و یا با سرور هماهنگ نیست. لطفا این صفحه را رفرش کنید." + "invalid-session-text": "به نظر می‌رسد این جلسه برای ورود دیگر فعال نیست و یا با سرور هماهنگ نیست. لطفا این صفحه را رفرش کنید.", + "no-topics-selected": "هیچ موضوعی انتخاب نشده است !" } \ No newline at end of file diff --git a/public/language/fa-IR/flags.json b/public/language/fa-IR/flags.json index 7d16875d5d..2a25fd56c8 100644 --- a/public/language/fa-IR/flags.json +++ b/public/language/fa-IR/flags.json @@ -1,16 +1,16 @@ { "state": "وضعیت", - "reporter": "گزارش دهنده", + "reporter": "کاربر گزارش دهنده", "reported-at": "گزارش شده در", "description": "شرح", "no-flags": "هووووورا ! هیچ گزارشی یافت نشد.", "assignee": "اختصاص دادن ", "update": "به روزرسانی", "updated": "به روز رسانی شد", - "target-purged": "The content this flag referred to has been purged and is no longer available.", + "target-purged": "محتوای این گزارش حذف شده است و در دسترس نیست.", "quick-filters": "فیلتر های سریع", - "filter-active": "There are one or more filters active in this list of flags", + "filter-active": "یک یا تعداد بیشتری از فیلتر ها در لیست گزارش ها فعال هستند", "filter-reset": "حذف فیلتر ها", "filters": "گزینه های فیلتر", "filter-reporterId": "UID گزارش دهنده", @@ -29,14 +29,14 @@ "flagged-user": "کاربر گزارش شده", "view-profile": "نمایش پروفایل", "start-new-chat": "شروع چت جدید", - "go-to-target": "مشاهده محتوا گزارش شده", + "go-to-target": "مشاهده محتوای گزارش شده", "user-view": "نمایش پروفایل", "user-edit": "ویرایش پروفایل", "notes": "یادداشت های گزارش", "add-note": "افزودن یادداشت", - "no-notes": "بدون یادداشت های به اشتراک گذاشته شده", + "no-notes": "بدون یادداشت", "history": "تاریخچه گزارش ", "back": "بازگشت به لیست گزارش ها", @@ -51,14 +51,14 @@ "note-added": "یادداشت افزوده شد", "modal-title": "گزارش محتوای نامناسب", - "modal-body": "Please specify your reason for flagging %1 %2 for review. Alternatively, use one of the quick report buttons if applicable.", + "modal-body": "لطفا علت گزارش %2 %1 را برای بررسی مشخص کنید. همچنین می توانید از یکی از دکمه های ارسال سریع استفاده کنید.", "modal-reason-spam": "هرزنامه", "modal-reason-offensive": "توهین آمیز", "modal-reason-other": "دیگر (در زیر مشخص کنید)", "modal-reason-custom": "علت گزارش این محتوا...", "modal-submit": "ارسال گزارش", - "modal-submit-success": "محتوا برای بررسی نشانه گذاری شد", + "modal-submit-success": "محتوا برای بررسی گزارش شد", "modal-submit-confirm": "تأیید ارسال", - "modal-submit-confirm-text": "You have a custom reason specified already. Are you sure you wish to submit via quick-report?", - "modal-submit-confirm-text-help": "Submitting a quick report will overwrite any custom reasons defined." + "modal-submit-confirm-text": "شما همواره علت دیگری را مشخص کردید. آیا مطمئن هستید که می خواهید از طریق گزینه های گزارش سریع ارسال کنید؟", + "modal-submit-confirm-text-help": "ارسال از طریق گزارش سریع جایگزین علت های مشخص شده دیگر می شود." } \ No newline at end of file diff --git a/public/language/fa-IR/global.json b/public/language/fa-IR/global.json index 6494a06de6..37b89f3405 100644 --- a/public/language/fa-IR/global.json +++ b/public/language/fa-IR/global.json @@ -53,9 +53,9 @@ "topics": "موضوع ها", "posts": "دیدگاه‌ها", "best": "بهترین", - "upvoters": "رای مثبت‌ها", + "upvoters": "موافقین", "upvoted": "رای مثبت", - "downvoters": "رای منفی‌ها", + "downvoters": "مخالفین", "downvoted": "رای منفی", "views": "بازدیدها", "reputation": "اعتبار", @@ -65,7 +65,7 @@ "posted_ago_by": "ارسال شده در %1 توسط %2", "posted_ago": "ارسال شده در %1", "posted_in": "پست شده در %1", - "posted_in_by": "پشت شده در %1 توسط 2%", + "posted_in_by": "پست شده در %1 توسط %2", "posted_in_ago": "ارسال شده در %1 %2", "posted_in_ago_by": "ارسال شده در %1 %2 توسط %3", "user_posted_ago": "%1 در %2 ارسال کرده است", diff --git a/public/language/fa-IR/notifications.json b/public/language/fa-IR/notifications.json index 2d5f0547b0..b80e40669c 100644 --- a/public/language/fa-IR/notifications.json +++ b/public/language/fa-IR/notifications.json @@ -9,16 +9,17 @@ "continue_to": "ادامه به %1", "return_to": "بازگشت به %1", "new_notification": "آگاه‌سازی‌ تازه", + "new_notification_from": "شما یک اعلان جدید از طرف %1 دارید", "you_have_unread_notifications": "شما آگاه‌سازی‌‌های نخوانده دارید.", "all": "همه", "topics": "موضوع ها", "replies": "پاسخ ها", "chat": "گفتگو ها", - "follows": "Follows", + "follows": "دنبال کننده ها", "upvote": "رای های مثبت", "new-flags": "گزارش های جدید", - "my-flags": "گزارش ها به من اختصاص یافت", - "bans": "Bans", + "my-flags": "گزارش های اختصاص یافته به من", + "bans": "اخراجی ها", "new_message_from": "پیام تازه از %1", "upvoted_your_post_in": "%1 امتیاز مثبت به پست شما در %2 داده", "upvoted_your_post_in_dual": "%1 و %2 رای مثبت به پست شما در\n %3.", @@ -28,9 +29,9 @@ "user_flagged_post_in": "%1 پست شما را در %2 علامتدار کرده", "user_flagged_post_in_dual": "%1 و %2 نشانه‌گذاری کرده اند پست را در %3", "user_flagged_post_in_multiple": "%1 و %2 نفر دیگر این پست را نشانه‌گذاری کرده در %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کاربری را برای بررسی گزارش کرد (%2)", + "user_flagged_user_dual": "%1و %2کاربری را برای بررسی گزارش کردند (%3)", + "user_flagged_user_multiple": "%1و %2 دیگران کاربری را برای بررسی گزارش کردند (%3)", "user_posted_to": "پاسخ دادن به %2 از سوی %1", "user_posted_to_dual": "%1 و %2 پاسخ به پست دادند در: %3", "user_posted_to_multiple": "%1 و %2 نفر دیگر به پست شما پاسخ ارسال کرده‌اند در: %3", @@ -40,10 +41,24 @@ "user_started_following_you_multiple": "%1 و %2 نفر دیگر شروع به دنبال کردن شما کرده.", "new_register": "%1 یک درخواست ثبت نام ارسال کرده است", "new_register_multiple": "تعداد %1 درخواست عضویت برای بررسی وجود دارد.", - "flag_assigned_to_you": "Flag %1 has been assigned to you", + "flag_assigned_to_you": "گزارش %1به شما تعلق گرفت", "post_awaiting_review": "Post awaiting review", "email-confirmed": "ایمیل تایید شد", "email-confirmed-message": "بابت تایید ایمیلتان سپاس‌گزاریم. حساب کاربری شما اکنون به صورت کامل فعال شده است.", "email-confirm-error-message": "خطایی در تایید آدرس ایمیل شما پیش آمده است. ممکن است کد نا‌معتبر و یا منقضی شده باشد.", - "email-confirm-sent": "ایمیل تایید ارسال شد." + "email-confirm-sent": "ایمیل تایید ارسال شد.", + "none": "هیچکدام", + "notification_only": "فقط اعلان", + "email_only": "فقط ایمیل", + "notification_and_email": "اعلان و ایمیل", + "notificationType_upvote": "هنگامی که شخصی به پست شما رای مثبت می دهد", + "notificationType_new-topic": "هنگامی که شخصی که شما فالو می کنید موضوعی ایجاد نماید", + "notificationType_new-reply": "هنگامی که پاسخ جدید در تاپیکی که شما پیگیری می کنید فرستاده می شود", + "notificationType_follow": "هنگامی که کسی شما را دنبال می کند", + "notificationType_new-chat": "هنگامی که شما پیام چتی دریافت می کنید", + "notificationType_group-invite": "هنگامی که شما دعوتنامه گروه دریافت می کنید", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "هنگامی که یک پست جدید در صف قرار می گیرد", + "notificationType_new-post-flag": "هنگامی که پستی گزارش می شود", + "notificationType_new-user-flag": "هنگامی که کاربری گزارش می شود" } \ No newline at end of file diff --git a/public/language/fa-IR/pages.json b/public/language/fa-IR/pages.json index 015e37b1e6..6abf1de1bc 100644 --- a/public/language/fa-IR/pages.json +++ b/public/language/fa-IR/pages.json @@ -30,7 +30,7 @@ "chats": "چتها", "chat": "چت با %1", "flags": "گزارش ها", - "flag-details": "Flag %1 Details", + "flag-details": "جزئیات گزارش %1", "account/edit": "ویرایش \"%1\"", "account/edit/password": "ویرایش کلمه ی عبورِ \"%1\"", "account/edit/username": "ویرایش نام کاربریِ \"%1\"", @@ -44,7 +44,7 @@ "account/bookmarks": "%1 پست نشانک گذاری شده است", "account/settings": "تنظیمات کاربر", "account/watched": "موضوع های دیده شده توسط \"%1\"", - "account/ignored": "Topics ignored by %1", + "account/ignored": "تاپیک های نادیده گرفته شده توسط %1", "account/upvoted": "رای مثبت داده شده به پست ها توسط %1", "account/downvoted": "رای منفی داده شده به پست ها توسط %1", "account/best": "بهترین پست های ارسال شده توسط %1", diff --git a/public/language/fa-IR/topic.json b/public/language/fa-IR/topic.json index 6dec761e4f..4c04d49e00 100644 --- a/public/language/fa-IR/topic.json +++ b/public/language/fa-IR/topic.json @@ -13,7 +13,7 @@ "notify_me": "از پاسخ‌های تازه در موضوع آگاه شوید", "quote": "نقل قول", "reply": "پاسخ", - "replies_to_this_post": "1 درصد انتخاب", + "replies_to_this_post": "%1 پاسخ ", "one_reply_to_this_post": "1 پاسخ", "last_reply_time": "آخرین پاسخ", "reply-as-topic": "پاسخ به موضوع", @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "آیا مطمئنید که می خواهید این موضوع را بازگردانی کنید؟", "thread_tools.purge": "پاک کردن موضوع", "thread_tools.purge_confirm": "آیا مطمئنید که میمید این موضوع را پاکسازی کنید؟", + "thread_tools.merge_topics": "ادغام موضوع ها", + "thread_tools.merge": "ادغام", "topic_move_success": "جابه‌جایی این موضوع به %1 باموفقیت انجام شد.", "post_delete_confirm": "آیا از پاک کردن این پست اطمینان دارید؟", "post_restore_confirm": "آیا از بازگردانی این پست اطمینان دارید؟", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 پست (ها) انتخاب شده اند", "fork_success": "موضوع با موفقیت منشعب شد! برای رفتن به موضوع انشعابی اینجا را کلیک کنید.", "delete_posts_instruction": "با کلیک بر روی پست شما می خواهید به حذف/پاکسازی", + "merge_topics_instruction": "بر روی عنوان موضوعاتی که می خواهید ادغام کنید کلیک کنید", "composer.title_placeholder": "عنوان موضوعتان را اینجا بنویسید...", "composer.handle_placeholder": "نام", "composer.discard": "دور بیانداز", diff --git a/public/language/fa-IR/unread.json b/public/language/fa-IR/unread.json index 227305d240..6dbfa319f1 100644 --- a/public/language/fa-IR/unread.json +++ b/public/language/fa-IR/unread.json @@ -11,5 +11,5 @@ "new-topics": "موضوع های جدید", "watched-topics": "موضوع های پیگیری شده", "unreplied-topics": "موضوع های بدون پاسخ", - "multiple-categories-selected": "Multiple Selected" + "multiple-categories-selected": "انتخاب چندگانه" } \ No newline at end of file diff --git a/public/language/fa-IR/user.json b/public/language/fa-IR/user.json index f4769ca682..54cd114210 100644 --- a/public/language/fa-IR/user.json +++ b/public/language/fa-IR/user.json @@ -50,7 +50,7 @@ "upload_new_picture_from_url": "بارگذاری تصویر جدید از نشانی وب", "current_password": "کلمه عبور کنونی", "change_password": "تغیر کلمه عبور", - "change_password_error": "کلمه عبورٔ نامعتبر!", + "change_password_error": "کلمه عبور نامعتبر!", "change_password_error_wrong_current": "این کلمه عبورٔ شما نادرست است.", "change_password_error_length": "کلمه عبور خیلی کوتاه است!", "change_password_error_match": "کلمه عبور‌ها باید یکسان باشند.", @@ -58,7 +58,7 @@ "change_password_success": "کلمه عبور‌تان تازه شد.", "confirm_password": "تکرار کلمه عبور", "password": "گذرواژه", - "username_taken_workaround": "نام کاربری درخواستی شما در حال حاضر گرفته شده است، بنابراین ما آن را کمی تغییر داده‌ایم. شما هم‌اکنون با نام %1<head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/fi/admin/menu.json b/public/language/fi/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/fi/admin/menu.json +++ b/public/language/fi/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/fi/admin/settings/notifications.json b/public/language/fi/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/fi/admin/settings/notifications.json +++ b/public/language/fi/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/fi/admin/settings/post.json b/public/language/fi/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/fi/admin/settings/post.json +++ b/public/language/fi/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/fi/admin/settings/user.json b/public/language/fi/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/fi/admin/settings/user.json +++ b/public/language/fi/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/fi/email.json b/public/language/fi/email.json index 33ba62f68d..ec849a5639 100644 --- a/public/language/fi/email.json +++ b/public/language/fi/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", "unsub.cta": "Click here to alter those settings", "banned.subject": "You have been banned from %1", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 8e73db4c3f..d79da5b654 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "Käyttäjä ei ole huoneessa", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json index c2ffeb4f82..561076543d 100644 --- a/public/language/fi/notifications.json +++ b/public/language/fi/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "Uusi ilmoitus", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Sinulla on lukemattomia ilmoituksia.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Sähköpostiosoite vahvistettu", "email-confirmed-message": "Kiitos sähköpostiosoitteesi vahvistamisesta. Käyttäjätilisi on nyt täysin aktivoitu.", "email-confirm-error-message": "Ongelma sähköpostiosoitteen vahvistamisessa. Ehkäpä koodi oli virheellinen tai vanhentunut.", - "email-confirm-sent": "Vahvistussähköposti lähetetty." + "email-confirm-sent": "Vahvistussähköposti lähetetty.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/fi/topic.json b/public/language/fi/topic.json index 84b298c455..96c9c894f7 100644 --- a/public/language/fi/topic.json +++ b/public/language/fi/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Haluatko varmasti palauttaa tämän aiheen?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", "post_delete_confirm": "Haluatko varmasti poistaa tämän viestin?", "post_restore_confirm": "Haluatko varmasti palauttaa tämän viestin?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Syötä aiheesi otsikko tähän...", "composer.handle_placeholder": "Name", "composer.discard": "Hylkää", diff --git a/public/language/fi/user.json b/public/language/fi/user.json index 9f5d8010a6..b15d2c3492 100644 --- a/public/language/fi/user.json +++ b/public/language/fi/user.json @@ -79,8 +79,6 @@ "digest_daily": "Päivittäin", "digest_weekly": "Viikottain", "digest_monthly": "Kuukausittain", - "send_chat_notifications": "Lähetä minulle sähköposti, jos uusi pikaviesti saapuu, kun en ole paikalla", - "send_post_notifications": "Lähetä minulle sähköposti, kun tilaamiini aiheisiin tulee vastauksia", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Kukaan ei seuraa tätä käyttäjää :(", "follows_no_one": "Tämä käyttäjä ei seuraa ketään :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Selataan asetuksia", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Salli aiheen sisäiset haut", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/fr/admin/appearance/customise.json b/public/language/fr/admin/appearance/customise.json index e867039801..ada04f6546 100644 --- a/public/language/fr/admin/appearance/customise.json +++ b/public/language/fr/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Entrez vos propres déclarations de CSS ici, elles seront appliquées après tous les autres styles.", "custom-css.enable": "Activer les CSS personnalisés", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "En-tête personnalisé", - "custom-header.description": "Entrez votre code HTML ici (ex. Javascripts, Méta tags, etc…), qui seront ajoutés à la section <head> du code de votre forum.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Activer les en-têtes personnalisés", "custom-css.livereload": "Activer le rechargement en direct", diff --git a/public/language/fr/admin/manage/post-queue.json b/public/language/fr/admin/manage/post-queue.json index ed8f9b71d1..5abf4cd55b 100644 --- a/public/language/fr/admin/manage/post-queue.json +++ b/public/language/fr/admin/manage/post-queue.json @@ -7,5 +7,5 @@ "content": "Contenu", "posted": "Posté", "reply-to": "Répondre à \"%1\"", - "content-editable": "You can click on individual content to edit before posting." + "content-editable": "Vous pouvez cliquer sur le contenu pour le modifier avant de le poster." } \ No newline at end of file diff --git a/public/language/fr/admin/menu.json b/public/language/fr/admin/menu.json index 07a2473bc5..8ab65fd51d 100644 --- a/public/language/fr/admin/menu.json +++ b/public/language/fr/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Apparence", "appearance/themes": "Thèmes", "appearance/skins": "Skins", - "appearance/customise": "HTML et CSS personnalisés", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extensions", "extend/plugins": "Plugins", @@ -65,7 +65,7 @@ "logout": "Déconnexion ", "view-forum": "Voir le forum", - "search.placeholder": "Search for settings", + "search.placeholder": "Rechercher dans les réglages", "search.no-results": "Aucun résultat…", "search.search-forum": "Rechercher dans le forum", "search.keep-typing": "Continuez de taper pour afficher les résultats…", diff --git a/public/language/fr/admin/settings/notifications.json b/public/language/fr/admin/settings/notifications.json index 8363491294..b679458498 100644 --- a/public/language/fr/admin/settings/notifications.json +++ b/public/language/fr/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Notification de bienvenue", - "welcome-notification-link": "Lien de notification de bienvenue" + "welcome-notification-link": "Lien de notification de bienvenue", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/fr/admin/settings/pagination.json b/public/language/fr/admin/settings/pagination.json index 455694e84f..e675776234 100644 --- a/public/language/fr/admin/settings/pagination.json +++ b/public/language/fr/admin/settings/pagination.json @@ -3,9 +3,9 @@ "enable": "Utiliser la pagination des sujets et messages au lieu du défilement infini", "topics": "Pagination des sujets", "posts-per-page": "Messages par page", - "max-posts-per-page": "Maximum posts per page", + "max-posts-per-page": "Messages maximum par page", "categories": "Pagination des categories", "topics-per-page": "Sujets par page", - "max-topics-per-page": "Maximum topics per page", + "max-topics-per-page": "Sujets maximum par page", "initial-num-load": "Nombre initial de sujets à charger dans Non lus, Récents et Populaires" } \ No newline at end of file diff --git a/public/language/fr/admin/settings/post.json b/public/language/fr/admin/settings/post.json index 3371e5b6d4..978f696168 100644 --- a/public/language/fr/admin/settings/post.json +++ b/public/language/fr/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Du plus ancien au plus récent", "sorting.newest-to-oldest": "Du plus récent au plus ancien", "sorting.most-votes": "Avec le plus de votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Tri des sujets par défaut", "restrictions": "Restrictions d'envoi", "restrictions.post-queue": "Activer la file d'attente des messages", diff --git a/public/language/fr/admin/settings/user.json b/public/language/fr/admin/settings/user.json index aeb9c7e9e6..9f6c78ea9b 100644 --- a/public/language/fr/admin/settings/user.json +++ b/public/language/fr/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Thèmes", "disable-user-skins": "Empêcher les utilisateurs de choisir un skin personnalisé", "account-protection": "Protection du compte", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Tentatives de connexions par heure", "login-attempts-help": "Si le nombre de tentatives de connexion à un compte dépasse ce seuil, le compte sera bloqué pour une durée pré-configurée", "lockout-duration": "Durée du blocage (minutes)", diff --git a/public/language/fr/email.json b/public/language/fr/email.json index cd244af52f..3e3c9c8976 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Cette notification de chat a été envoyé en raison de vos paramètres d'abonnement.", "notif.post.cta": "Cliquer ici pour lire le sujet complet", "notif.post.unsub.info": "La notification de ce message vous a été envoyé en raison de vos paramètres d'abonnement.", + "notif.cta": "Click here to go to forum", "test.text1": "Ceci est un e-mail de test pour vérifier que l'e-mailer est correctement configuré pour NodeBB.", "unsub.cta": "Cliquez ici pour modifier ces paramètres", "banned.subject": "Vous avez été banni de %1", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index a992ed875e..ab5a0d0974 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -11,7 +11,7 @@ "invalid-uid": "ID utilisateur invalide", "invalid-username": "Nom d'utilisateur invalide", "invalid-email": "Email invalide", - "invalid-title": "Invalid title", + "invalid-title": "Titre invalide", "invalid-user-data": "Données utilisateur invalides", "invalid-password": "Mot de passe invalide", "invalid-login-credentials": "Certificat d'identification invalide", @@ -81,7 +81,7 @@ "cant-ban-other-admins": "Vous ne pouvez pas bannir les autres administrateurs !", "cant-remove-last-admin": "Vous seul êtes administrateur. Ajouter un autre utilisateur en tant qu'administrateur avant de vous en retirer.", "cant-delete-admin": "Veuillez retirer les droits d'administration de ce compte avant de tenter de le supprimer.", - "invalid-image": "Invalid image", + "invalid-image": "Image invalide", "invalid-image-type": "Type d'image invalide. Les types autorisés sont: %1", "invalid-image-extension": "Extension d'image invalide", "invalid-file-type": "Type de fichier non valide. Les types autorisés sont : %1", @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Vous n'avez pas une réputation assez élevée pour noter négativement ce message", "not-enough-reputation-to-flag": "Vous n'avez pas une réputation assez élevée pour signaler ce message", "already-flagged": "Vous avez déjà signalé ce message", + "self-vote": "Vous ne pouvez pas voter sur votre propre message", "reload-failed": "NodeBB a rencontré un problème lors du rechargement : \"% 1\" . NodeBB continuera de fonctionner côté client, même si vous devez annuler ce que vous avez fait juste avant de recharger .", "registration-error": "Erreur d'enregistrement", "parse-error": "Une erreur est survenue en analysant la réponse du serveur", "wrong-login-type-email": "Veuillez utiliser votre adresse email pour vous connecter", "wrong-login-type-username": "Veuillez utiliser votre identifiant pour vous connecter", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Vous avez invité la quantité maximale de personnes (%1 de %2).", "no-session-found": "Pas de session de connexion trouvé!", "not-in-room": "L'utilisateur n'est pas dans cette salle", @@ -132,5 +134,6 @@ "no-users-selected": "Aucun utilisateur sélectionné", "invalid-home-page-route": "Route de page d'accueil invalide", "invalid-session": "Session Interrompue", - "invalid-session-text": "Il semble que votre session ne soit plus active, ou que le serveur ne la reconnaisse plus. Merci de rafraichir cette page." + "invalid-session-text": "Il semble que votre session ne soit plus active, ou que le serveur ne la reconnaisse plus. Merci de rafraichir cette page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/fr/flags.json b/public/language/fr/flags.json index 0631354adf..92f11b8fd9 100644 --- a/public/language/fr/flags.json +++ b/public/language/fr/flags.json @@ -51,14 +51,14 @@ "note-added": "Note ajoutée", "modal-title": "Signaler un contenu inapproprié", - "modal-body": "Veuillez spécifier votre raison de signaler %1 %2 pour une révision. Vous pouvez utiliser un des boutons de report rapide si c'est plus approprié", + "modal-body": "Veuillez spécifier votre signalement %1 %2 pour une révision. Vous pouvez utiliser un des boutons de demande si c'est plus approprié", "modal-reason-spam": "Spam", "modal-reason-offensive": "Choquant", - "modal-reason-other": "Other (specify below)", + "modal-reason-other": "Autre (précisez ci-dessous)", "modal-reason-custom": "Motif du signalement...", "modal-submit": "Soumettre le signalement", "modal-submit-success": "Le contenu a été soumis pour examen.", - "modal-submit-confirm": "Confirm Submission", - "modal-submit-confirm-text": "You have a custom reason specified already. Are you sure you wish to submit via quick-report?", - "modal-submit-confirm-text-help": "Submitting a quick report will overwrite any custom reasons defined." + "modal-submit-confirm": "Confirmer l'envoi", + "modal-submit-confirm-text": "Vous avez déjà spécifié un signalement. Êtes-vous sûr de vouloir soumettre une demande ?", + "modal-submit-confirm-text-help": "La soumission d'une demande écrase tous les signalements définis." } \ No newline at end of file diff --git a/public/language/fr/language.json b/public/language/fr/language.json index 0aaf9508de..21ce190574 100644 --- a/public/language/fr/language.json +++ b/public/language/fr/language.json @@ -1,5 +1,5 @@ { - "name": "Français", + "name": "French", "code": "fr", "dir": "ltr" } \ No newline at end of file diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json index 4d34dd3593..79be0264ba 100644 --- a/public/language/fr/notifications.json +++ b/public/language/fr/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuer vers %1", "return_to": "Revenir à %1", "new_notification": "Nouvelle notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Vous avez des notifications non-lues", "all": "Tout", "topics": "Sujets", @@ -45,5 +46,19 @@ "email-confirmed": "Email vérifié", "email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.", "email-confirm-error-message": "Il y a un un problème dans la vérification de votre adresse email. Le code est peut être invalide ou a expiré.", - "email-confirm-sent": "Email de vérification envoyé." + "email-confirm-sent": "Email de vérification envoyé.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index 50967383a6..e3f20da517 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -44,7 +44,7 @@ "account/bookmarks": "Marques-pages de %1", "account/settings": "Paramètres d'utilisateur", "account/watched": "Sujets auxquels %1 est abonné", - "account/ignored": "Topics ignored by %1", + "account/ignored": "Sujets ignorés par %1", "account/upvoted": "Messages pour lesquels %1 a voté", "account/downvoted": "Messages contre lesquels %1 a voté", "account/best": "Meilleurs messages postés par %1", diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index 1c59ccba72..3cbcdfefe8 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Êtes-vous sûr de bien vouloir restaurer ce sujet ?", "thread_tools.purge": "Supprimer définitivement le(s) sujet(s)", "thread_tools.purge_confirm": "Êtes-vous sûr de bien vouloir supprimer définitivement ce sujet ?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Ce sujet a bien été déplacé vers %1.", "post_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer ce message ?", "post_restore_confirm": "Êtes-vous sûr de bien vouloir restaurer ce message ?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 message(s) sélectionné(s)", "fork_success": "Sujet copié avec succès ! Cliquez ici pour aller au sujet copié.", "delete_posts_instruction": "Sélectionnez les messages que vous souhaitez supprimer/vider", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Entrer le titre du sujet ici…", "composer.handle_placeholder": "Nom", "composer.discard": "Abandonner", diff --git a/public/language/fr/unread.json b/public/language/fr/unread.json index ba4fe50469..dcd6303e98 100644 --- a/public/language/fr/unread.json +++ b/public/language/fr/unread.json @@ -10,6 +10,6 @@ "all-topics": "Tous les sujets", "new-topics": "Nouveau sujet", "watched-topics": "Abonnements", - "unreplied-topics": "Unreplied Topics", - "multiple-categories-selected": "Multiple Selected" + "unreplied-topics": "Sujets sans réponses", + "multiple-categories-selected": "Sélection multiple" } \ No newline at end of file diff --git a/public/language/fr/user.json b/public/language/fr/user.json index 8b27a0f0af..a5e84f9a27 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -25,7 +25,7 @@ "reputation": "Réputation", "bookmarks": "Marque-pages", "watched": "Abonnements", - "ignored": "Ignored", + "ignored": "Ignorés", "followers": "Abonnés", "following": "Abonnements", "aboutme": "À propos de moi", @@ -79,15 +79,13 @@ "digest_daily": "Quotidien", "digest_weekly": "Hebdomadaire", "digest_monthly": "Mensuel", - "send_chat_notifications": "Envoyer un e-mail si un nouveau message de chat arrive lorsque je ne suis pas en ligne", - "send_post_notifications": "Envoyer un email lors de réponses envoyées aux sujets auxquels je suis abonné", "settings-require-reload": "Certains réglages nécessitent un rechargement. Cliquez ici pour recharger la page.", "has_no_follower": "Personne n'est abonné à cet utilisateur :(", "follows_no_one": "Cet utilisateur n'est abonné à personne :(", "has_no_posts": "Cet utilisateur n'a encore rien posté.", "has_no_topics": "Cet utilisateur n'a encore créé aucun sujet.", "has_no_watched_topics": "Cet utilisateur ne s'est encore abonné à aucun sujet.", - "has_no_ignored_topics": "This user hasn't ignored any topics yet.", + "has_no_ignored_topics": "Cet utilisateur n'a encore ignoré aucun sujet.", "has_no_upvoted_posts": "Cet utilisateur n'a voté pour aucun message", "has_no_downvoted_posts": "Cet utilisateur n'a voté contre aucun message", "has_no_voted_posts": "Personne n'a voté pour des messages de cet utilisateur", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Son pour les messages sortants", "notification-sound": "Son de notification", "no-sound": "Pas de son", + "upvote-notif-freq": "Fréquence de notification des votes positif", + "upvote-notif-freq.all": "Tout les votes positif", + "upvote-notif-freq.everyTen": "Le top 10 des votes positif", + "upvote-notif-freq.logarithmic": "Les 10, 100, 1000...", + "upvote-notif-freq.disabled": "Désactivé", "browsing": "Paramètres de navigation", "open_links_in_new_tab": "Ouvrir les liens externes dans un nouvel onglet", "enable_topic_searching": "Activer la recherche dans les sujets", @@ -123,6 +126,9 @@ "sso.title": "Services d'authentification unique", "sso.associated": "Associé avec", "sso.not-associated": "Cliquez ici pour associer", + "sso.dissociate": "Dissocier", + "sso.dissociate-confirm-title": "Confirmer la dissociation", + "sso.dissociate-confirm": "Êtes-vous sûr de vouloir dissocier votre compte de %1 ?", "info.latest-flags": "Derniers signalements", "info.no-flags": "Aucun signalement trouvé", "info.ban-history": "Historique de bannissement récent", diff --git a/public/language/gl/admin/appearance/customise.json b/public/language/gl/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/gl/admin/appearance/customise.json +++ b/public/language/gl/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/gl/admin/menu.json b/public/language/gl/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/gl/admin/menu.json +++ b/public/language/gl/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/gl/admin/settings/notifications.json b/public/language/gl/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/gl/admin/settings/notifications.json +++ b/public/language/gl/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/gl/admin/settings/post.json b/public/language/gl/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/gl/admin/settings/post.json +++ b/public/language/gl/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/gl/admin/settings/user.json b/public/language/gl/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/gl/admin/settings/user.json +++ b/public/language/gl/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/gl/email.json b/public/language/gl/email.json index 0aee60f82d..dc00e2c996 100644 --- a/public/language/gl/email.json +++ b/public/language/gl/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Esta notificación de charla foiche enviada polas túas opcións de subscrición.", "notif.post.cta": "Pica aquí para leer todos os temas", "notif.post.unsub.info": "Esta notificación de mensaxe foiche enviada polas túas opcións de subscrición.", + "notif.cta": "Click here to go to forum", "test.text1": "Esta é unha mensaxe de proba para verificar que o envío de correo está configurado correctamente para o seu NodeBB.", "unsub.cta": "Pica aquí para cambiar os axustes", "banned.subject": "You have been banned from %1", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index 8756006b92..dc2579c4f5 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Non tes reputación dabonda para esta acción", "not-enough-reputation-to-flag": "Non tes reputación dabondo para reportar esta mensaxe.", "already-flagged": "Xa reportache-la mensaxe.", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB atopou un erro mentras recargaba: \"%1\". NodeBB seguirá a servir os activos dos clientes aínda que se deberá desfacer o que se fixo antes da descarga.", "registration-error": "Erro de rexistro", "parse-error": "Algo foi mal namentras se agardaba a resposta do servidor", "wrong-login-type-email": "Por favor, emprega o teu correo para contectarte", "wrong-login-type-username": "Por favor, usa o teu nome de usuario para conectarte", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Convidaches á cantidade máxima de persoas (%1 de %2).", "no-session-found": "Non se atopou ningún inicio de sesión!", "not-in-room": "O usuario non se atopa nesta sala", @@ -132,5 +134,6 @@ "no-users-selected": "Ningún usuario seleccionado", "invalid-home-page-route": "Ruta de páxina de inicio inválida", "invalid-session": "Non concordan os datos da sesión", - "invalid-session-text": "Parece que a súa sesión expirou ou non concorda co servidor. Por favor, recarge a páxina." + "invalid-session-text": "Parece que a súa sesión expirou ou non concorda co servidor. Por favor, recarge a páxina.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json index 0c4b8aab72..f5e6f5bfbc 100644 --- a/public/language/gl/notifications.json +++ b/public/language/gl/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuar a %1", "return_to": "Volver a %1", "new_notification": "Nova Notificación", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Tes notificacións non lidas", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Correo confirmado", "email-confirmed-message": "Grazas por validar o teu correo. A túa conta agora está activada.", "email-confirm-error-message": "Houbo un problema validando o teu correo. Poida que o código fose inválido ou expirase. ", - "email-confirm-sent": "Correo de confirmación enviado." + "email-confirm-sent": "Correo de confirmación enviado.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/gl/topic.json b/public/language/gl/topic.json index ace8074655..4752bf17ab 100644 --- a/public/language/gl/topic.json +++ b/public/language/gl/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Estás seguro de que desexas restaurar este tema?", "thread_tools.purge": "Purgar Tema", "thread_tools.purge_confirm": "Estás seguro de que desexas eliminar definitivamente (purgar) este tema?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Este tema foi movido correctamente a %1", "post_delete_confirm": "Estás seguro de que desexas eliminar esta publicación?", "post_restore_confirm": "Estás seguro de que desexas restaurar esta publicación?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 mensaxe(s) seleccionada(s)", "fork_success": "Creouse un novo tema a partir do orixinal! Fai clic aquí para ir ó novo tema.", "delete_posts_instruction": "Fai clic nas mensaxes que queres eliminar/limpar", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Introduce o título do teu tema", "composer.handle_placeholder": "Nome", "composer.discard": "Descartar", diff --git a/public/language/gl/user.json b/public/language/gl/user.json index 79833e3a40..b9b1948287 100644 --- a/public/language/gl/user.json +++ b/public/language/gl/user.json @@ -79,8 +79,6 @@ "digest_daily": "Diariamente", "digest_weekly": "Semanalmente", "digest_monthly": "Mensualmente", - "send_chat_notifications": "Enviar un correo se me chega unha mensaxe mentres estou desconectado.", - "send_post_notifications": "Enviádeme un correo cando haxa respostas nos temas nos que estou subscrito", "settings-require-reload": "Algúns cambios nas opcións requiren recarga-la páxina. Pica aquí para facelo.", "has_no_follower": "Ninguén segue a este usuario :(", "follows_no_one": "Este usuario non sigue a ninguén :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Son da mensaxe saínte", "notification-sound": "Son de notificación", "no-sound": "Sen son", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Opcións de busca", "open_links_in_new_tab": "Abrir ligazóns externos nunca nova pestaña", "enable_topic_searching": "Permitir buscar dentro dun tema", @@ -123,6 +126,9 @@ "sso.title": "Servizos de Inicio de Sesión Único", "sso.associated": "Asociado con", "sso.not-associated": "Pica aquí para asociarte con", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Últimos reportes", "info.no-flags": "Non se atopou ninguna mensaxe reportada", "info.ban-history": "Histórico recente de bans", diff --git a/public/language/he/admin/appearance/customise.json b/public/language/he/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/he/admin/appearance/customise.json +++ b/public/language/he/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index 311666c5f7..cde4e9a506 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/he/admin/settings/notifications.json b/public/language/he/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/he/admin/settings/notifications.json +++ b/public/language/he/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/he/admin/settings/post.json b/public/language/he/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/he/admin/settings/post.json +++ b/public/language/he/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/he/email.json b/public/language/he/email.json index 1495b88c48..79ddc36f99 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "התראה הצ'אט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", "notif.post.cta": "לחץ כאן בשביל לקרוא את כל הנושא", "notif.post.unsub.info": "התראת הפוסט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", + "notif.cta": "Click here to go to forum", "test.text1": "זהו אימייל ניסיון על מנת לוודא שהגדרות המייל בוצעו כהלכה בהגדרות NodeBB.", "unsub.cta": "לחץ כאן לשנות הגדרות אלו", "banned.subject": "הורחקת מ %1", diff --git a/public/language/he/error.json b/public/language/he/error.json index a0ff49b481..c2cac88605 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "אין לך מספיק מוניטין כדי להוריד את הדירוג של פוסט זה", "not-enough-reputation-to-flag": "אין לך מוניטין מספק על מנת לסמן את הפוסט הזה", "already-flagged": "כבר סימנת את הפוסט הזה", + "self-vote": "You cannot vote on your own post", "reload-failed": "אירעה תקלה ב NodeBB בזמן הטעינה של: \"%1\". המערכת תמשיך להגיש דפים קיימים, אבל כדאי שתשחזר את הפעולות שלך מהפעם האחרונה שהמערכת עבדה כראוי.", "registration-error": "שגיאה בהרשמה", "parse-error": "אירעה שגיאה בעת בעת ניתוח תגובת השרת", "wrong-login-type-email": "בבקשה השתמש בכתובת המייל שלך להתחברות", "wrong-login-type-username": "בבקשה השתמש בשם המשתמש שלך להתחברות", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "הזמנת את הכמות המירבית של אנשים (%1 מתוך %2).", "no-session-found": "לא נמצאו סשני התחברות!", "not-in-room": "משתמש זה לא בצ'אט", @@ -132,5 +134,6 @@ "no-users-selected": "לא נבחרו משתמשים", "invalid-home-page-route": "כתובת דף הבית הינה שגויה", "invalid-session": "סשן לא תקין", - "invalid-session-text": "נראה שסשן ההתחברות שלך כבר לא פעיל. אנא טען מחדש את העמוד." + "invalid-session-text": "נראה שסשן ההתחברות שלך כבר לא פעיל. אנא טען מחדש את העמוד.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index 1cab5188ab..0634c4b13d 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -9,6 +9,7 @@ "continue_to": "המשך ל %1", "return_to": "חזור ל %1", "new_notification": "התראה חדשה", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "יש לך התראות שלא נקראו.", "all": "הכל", "topics": "נושאים", @@ -45,5 +46,19 @@ "email-confirmed": "כתובת המייל אושרה", "email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.", "email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.", - "email-confirm-sent": "מייל אישור נשלח." + "email-confirm-sent": "מייל אישור נשלח.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/he/topic.json b/public/language/he/topic.json index b9630978ea..e8d77f491c 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "אתה בטוח שאתה רוצה לשחזר את הנושא הזה?", "thread_tools.purge": "מחק נושא", "thread_tools.purge_confirm": "אתה בטוח שאתה רוצה למחוק את הנושא הזה?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "נושא זה הועבר בהצלחה ל %1", "post_delete_confirm": "אתה בטוח שאתה רוצה למחוק את הפוסט הזה?", "post_restore_confirm": "אתה בטוח שאתה רוצה לשחזר את הפוסט הזה?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "הפוסט שוכפל בהצלחה! לחץ כאן על מנת לעבור לפוסט המשוכפל.", "delete_posts_instruction": "לחץ על הפוסטים שברצונך למחוק", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "הכנס את כותרת הנושא כאן...", "composer.handle_placeholder": "שם", "composer.discard": "מחק", diff --git a/public/language/he/user.json b/public/language/he/user.json index 4b46bc93ef..bb1b1a092f 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -79,8 +79,6 @@ "digest_daily": "יומי", "digest_weekly": "שבועי", "digest_monthly": "חודשי", - "send_chat_notifications": "שלח לי הודעה למייל כאשר הודעת צ'אט נשלחה אלי בזמן שאיני מחובר", - "send_post_notifications": "שלח לי הודעה למייל כאשר תגובות חדשות פורסמו לנושאים שאני עוקב אחריהם", "settings-require-reload": "כמה שינויים בהגדרות דורשים ריענון לדף. לחץ כאן כדי לרענן את הדף.", "has_no_follower": "למשתמש זה אין עוקבים :(", "follows_no_one": "משתמש זה אינו עוקב אחרי אחרים :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "צליל הודעה יוצאת", "notification-sound": "צליל הודעה", "no-sound": "ללא צליל", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "הגדרות צפייה", "open_links_in_new_tab": "פתח קישורים חיצוניים בכרטיסייה חדשה", "enable_topic_searching": "הפעל חיפוש בתוך נושא", @@ -123,6 +126,9 @@ "sso.title": "שירות יחיד להתחברות", "sso.associated": "משוייך עם", "sso.not-associated": "לחץ כאן כדי לשייך", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "דיווחים אחרונים", "info.no-flags": "לא נמצאו פוסטים שמשתמשים דיווחו עליהם", "info.ban-history": "היסטוריית הרחקות", diff --git a/public/language/hr/admin/appearance/customise.json b/public/language/hr/admin/appearance/customise.json index a283a153aa..ea5d0d5cc2 100644 --- a/public/language/hr/admin/appearance/customise.json +++ b/public/language/hr/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Unesi CSS deklaracije koje će biti upisane poslije svih stilova.", "custom-css.enable": "Omogući dodatni CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Uobičajno zaglavlje", - "custom-header.description": "Unesite Vaš HTML ovdje(npr. JavaScript Meta Tags itd.)koji će biti dodani <head> sekciji marže Vašeg foruma.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Omogući uobičajeno zaglavlje", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/hr/admin/menu.json b/public/language/hr/admin/menu.json index ae682e4f6b..2facf3eb41 100644 --- a/public/language/hr/admin/menu.json +++ b/public/language/hr/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Izgled", "appearance/themes": "Predlošci", "appearance/skins": "Izgled", - "appearance/customise": "Uobičajni HTML i CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Proširi", "extend/plugins": "Dodatci", diff --git a/public/language/hr/admin/settings/notifications.json b/public/language/hr/admin/settings/notifications.json index 1d1c969f34..d70a8007a4 100644 --- a/public/language/hr/admin/settings/notifications.json +++ b/public/language/hr/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Obavijesti", "welcome-notification": "Obavijest dobrodošlice", - "welcome-notification-link": "Poveznica objave dobrodošlice" + "welcome-notification-link": "Poveznica objave dobrodošlice", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/hr/admin/settings/post.json b/public/language/hr/admin/settings/post.json index 24906ac67e..340e076981 100644 --- a/public/language/hr/admin/settings/post.json +++ b/public/language/hr/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Starije prema Novijem", "sorting.newest-to-oldest": "Novije prema Starijem", "sorting.most-votes": "Najviše glasova", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Uobičajeno sortiranje tema", "restrictions": "Restrikcije objave", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/hr/admin/settings/user.json b/public/language/hr/admin/settings/user.json index a39e4b7472..442abf0ec3 100644 --- a/public/language/hr/admin/settings/user.json +++ b/public/language/hr/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Predlošci", "disable-user-skins": "Onemogući korisnicima odabir predloška", "account-protection": "Zaštita računa", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Pokušaji prijave po satu", "login-attempts-help": "U slučaju pokušaja prijave na račun user's u tolikoj količini da prelazi ovaj prag,račun će biti zaključan na pre-konfigurirano vrijeme", "lockout-duration": "Broj minuta u slučaju zaključavanja računa", diff --git a/public/language/hr/email.json b/public/language/hr/email.json index cdf26cd74f..87da70889b 100644 --- a/public/language/hr/email.json +++ b/public/language/hr/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Ova obavijest razgovora Vam je poslana na temelju vaših postavki pretplate.", "notif.post.cta": "Pročitaj temu", "notif.post.unsub.info": "Ova objava Vam je poslana na temelju vaših postavki pretplate.", + "notif.cta": "Click here to go to forum", "test.text1": "Ovo je test email za provjeru Vaše konfiguracije.", "unsub.cta": "Klikni ovdje za promjenu postavki", "banned.subject": "Blokirani se na %1", diff --git a/public/language/hr/error.json b/public/language/hr/error.json index 7c4bdb5b79..492f3afa18 100644 --- a/public/language/hr/error.json +++ b/public/language/hr/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nemate dovoljno reputacije da bi ste glasali", "not-enough-reputation-to-flag": "Nemate dovoljno reputacije da bi stavili zastavicu na ovu objavu", "already-flagged": "Već ste označili zastavicom ovu objavu", + "self-vote": "You cannot vote on your own post", "reload-failed": "Problem kod ponovnog podizanja: \"%1\" will continue to serve the existing client-side assets.", "registration-error": "Greška prilikom registracije", "parse-error": "Došlo je do pogreške u komunikaciji sa serverom", "wrong-login-type-email": "Upišite Vaš email za prijavu", "wrong-login-type-username": "Upišite Vaše korisničko ime za prijavu", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Pozvali ste maksimalan broj ljudi (%1 od %2).", "no-session-found": "Nije pronađena sesija prijave!", "not-in-room": "Korisnik nije u sobi", @@ -132,5 +134,6 @@ "no-users-selected": "Korisnici nisu odabrani", "invalid-home-page-route": "Netočna putanja naslovnice", "invalid-session": "Pogreška sesije", - "invalid-session-text": "Vaša sesija nije više aktivna ili se više ne poklapa sa serverom. Molimo osvježite stranicu." + "invalid-session-text": "Vaša sesija nije više aktivna ili se više ne poklapa sa serverom. Molimo osvježite stranicu.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/hr/notifications.json b/public/language/hr/notifications.json index a66e3f8b58..4e0c2d5ebf 100644 --- a/public/language/hr/notifications.json +++ b/public/language/hr/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Nastavite na %1", "return_to": "Vratite se na %1", "new_notification": "Nova obavijest", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Nepročitane obavijesti.", "all": "Sve", "topics": "Teme", @@ -45,5 +46,19 @@ "email-confirmed": "Email potvrđen", "email-confirmed-message": "Hvala na potvrdi emaila. Vaš račun je sada aktivan.", "email-confirm-error-message": "Nastao je problem pri potvrdi Vaše email adrese. Provjerite kod ili zatražite novi.", - "email-confirm-sent": "Provjera korisničkog emaila poslana." + "email-confirm-sent": "Provjera korisničkog emaila poslana.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/hr/topic.json b/public/language/hr/topic.json index 98a6210428..00ad1d8de7 100644 --- a/public/language/hr/topic.json +++ b/public/language/hr/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Sigurni ste da želite povratiti ovu temu?", "thread_tools.purge": "Odbaci temu", "thread_tools.purge_confirm": "Sigurni ste da želite odbaciti ovu temu?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Tema je uspješno pomaknuta u %1", "post_delete_confirm": "Sigurni ste da želite obrisati ovu objavu?", "post_restore_confirm": "Sigurni ste da želite povratiti ovu objavu?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 objava odabrana", "fork_success": "Uspješno duplirana tema. Kliknite ovdje za dupliranu temu.", "delete_posts_instruction": "Označite objave koje želite obrisati/odbaciti", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Unesite naslov teme ovdje ...", "composer.handle_placeholder": "Ime", "composer.discard": "Odbaci", diff --git a/public/language/hr/user.json b/public/language/hr/user.json index b93a75c577..e3c8e767fe 100644 --- a/public/language/hr/user.json +++ b/public/language/hr/user.json @@ -79,8 +79,6 @@ "digest_daily": "Dnevno", "digest_weekly": "Tjedno", "digest_monthly": "Mjesečno", - "send_chat_notifications": "Pošalji email ako stigne nova poruka i nisam na mreži", - "send_post_notifications": "Pošalji email kada se objavi odgovor na teme koje sam pretplaćen", "settings-require-reload": "Neke promjene zahtjevaju osvježenje. Kliknite ovdje za osvježavanje stranice.", "has_no_follower": "Ovaj korisnik nema pratitelja :(.", "follows_no_one": "Ovaj korisnik nikog ne prati :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Zvuk odlazećih poruka", "notification-sound": "Zvuk obavijesti", "no-sound": "Bez zvuka", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Postavke pretraživanja", "open_links_in_new_tab": "Otvori odlazne poveznice u novom tabu", "enable_topic_searching": "Omogući pretragu unutar tema", @@ -123,6 +126,9 @@ "sso.title": "Jednokratne usluge prijave", "sso.associated": "Povezano sa", "sso.not-associated": "Klikni ovdje za povezivanje sa", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Zadnja zastava", "info.no-flags": "Nema objava sa zastavama", "info.ban-history": "Povijest nedavno blokiranih", diff --git a/public/language/hu/admin/appearance/customise.json b/public/language/hu/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/hu/admin/appearance/customise.json +++ b/public/language/hu/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/hu/admin/menu.json b/public/language/hu/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/hu/admin/menu.json +++ b/public/language/hu/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/hu/admin/settings/notifications.json b/public/language/hu/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/hu/admin/settings/notifications.json +++ b/public/language/hu/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/hu/admin/settings/post.json b/public/language/hu/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/hu/admin/settings/post.json +++ b/public/language/hu/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/hu/admin/settings/user.json b/public/language/hu/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/hu/admin/settings/user.json +++ b/public/language/hu/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/hu/email.json b/public/language/hu/email.json index 2a4ce69b7d..e508d9cf61 100644 --- a/public/language/hu/email.json +++ b/public/language/hu/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Ez a chat-értesítés a feliratkozási beállításaid miatt lett kiküldve.", "notif.post.cta": "Kattints ide a teljes téma olvasásához", "notif.post.unsub.info": "Ez a hozzászólás-értesítés a feliratkozási beállításaid miatt lett kiküldve.", + "notif.cta": "Click here to go to forum", "test.text1": "Ez egy teszt levél, ami által ellenőrizzük, hogy a levelező helyesen lett beállítva a NodeBB-ben.", "unsub.cta": "Kattintson ide a beállítások módosításához", "banned.subject": "Ki lettél tiltva a(z) %1 oldalról", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index 09f5e7a15f..d6836b3bb7 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nem rendelkezel elég Hírnév ponttal, hogy leszavazhasd ezt a hozzászólást", "not-enough-reputation-to-flag": "Nem rendelkezel elég Hírnév ponttal, hogy jelentsd ezt a hozzászólást", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB egy hibát észlelt újratöltés közben: \"% 1\". A fórum továbbra is kiszolgálja a kliens-oldali eszközöket, bár vissza kellene csinálnod amit az újratöltés előtt elállítottál.", "registration-error": "Regisztrációs hiba", "parse-error": "Hiba történt a szerver válaszának feldolgozása közben", "wrong-login-type-email": "Kérlek az e-mail címedet használd a belépéshez", "wrong-login-type-username": "Kérlek a felhasználónevedet használd a belépéshez", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json index e1d3677df0..8ab1d0843d 100644 --- a/public/language/hu/notifications.json +++ b/public/language/hu/notifications.json @@ -9,6 +9,7 @@ "continue_to": "%1 megnyitás", "return_to": "Vissza - %1", "new_notification": "Új értesítés", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Olvasatlan értesítéseid vannak.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "E-mail megerősítve", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Megerősítő e-mail elküldve." + "email-confirm-sent": "Megerősítő e-mail elküldve.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/hu/topic.json b/public/language/hu/topic.json index 2643558f3d..11eeb4eb0f 100644 --- a/public/language/hu/topic.json +++ b/public/language/hu/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", "post_delete_confirm": "Are you sure you want to delete this post?", "post_restore_confirm": "Are you sure you want to restore this post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Írd be a témanevet...", "composer.handle_placeholder": "Name", "composer.discard": "Elvet", diff --git a/public/language/hu/user.json b/public/language/hu/user.json index cc0b0a70a7..68cc1adcb3 100644 --- a/public/language/hu/user.json +++ b/public/language/hu/user.json @@ -79,8 +79,6 @@ "digest_daily": "Napi", "digest_weekly": "Heti", "digest_monthly": "Havi", - "send_chat_notifications": "E-mail küldése, ha új chat üzenetem érkezett és nem vagyok aktív", - "send_post_notifications": "E-mail küldése, ha válasz érkezik a feliratkozott témakörökbe", "settings-require-reload": "Néhány módosítás újratöltést igényel. Kattints ide az oldal frissítéséhez.", "has_no_follower": "Ezt a felhasználót nem követi senki :(", "follows_no_one": "Ez a felhasználó már nem követ :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Kimenő üzenet hangja", "notification-sound": "Értesítési hang", "no-sound": "Nincs hang", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Böngészési beállítások", "open_links_in_new_tab": "Kimenő hivatkozások megnyitása új lapon", "enable_topic_searching": "Témán belüli keresés bekapcsolása", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/id/admin/appearance/customise.json b/public/language/id/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/id/admin/appearance/customise.json +++ b/public/language/id/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/id/admin/menu.json b/public/language/id/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/id/admin/menu.json +++ b/public/language/id/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/id/admin/settings/notifications.json b/public/language/id/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/id/admin/settings/notifications.json +++ b/public/language/id/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/id/admin/settings/post.json b/public/language/id/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/id/admin/settings/post.json +++ b/public/language/id/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/id/admin/settings/user.json b/public/language/id/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/id/admin/settings/user.json +++ b/public/language/id/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/id/email.json b/public/language/id/email.json index f8b4d249c5..a1336b1201 100644 --- a/public/language/id/email.json +++ b/public/language/id/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Sesuai pengaturan langganan anda, notifikasi obrolan ini dikirmkan kepada anda", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "Ini hanya email percobaan untuk menverifkasi pengiriman email telah diatur oleh NodeBB secara benar", "unsub.cta": "Klik di sini untuk mengubah pengaturan-pengaturan tersebut.", "banned.subject": "You have been banned from %1", diff --git a/public/language/id/error.json b/public/language/id/error.json index 8fed86543e..1076e7fc8f 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Tidak cukup reputation untuk downvote post ini", "not-enough-reputation-to-flag": "Tidak cukup reputation untuk flag post ini", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB mengalami masalah saat memuat \"%1\". NodeBB akan melanjutkan pemuatan, kamu harus membatalkan tindakanmu sebelum pemuatan kembali dilakukan.", "registration-error": "Registrasti Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json index 741909fd39..0ce32cb76d 100644 --- a/public/language/id/notifications.json +++ b/public/language/id/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Lanjut ke %1", "return_to": "Kembali ke %1", "new_notification": "Pemberitahuan Baru", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Kamu memiliki pemberitahuan yang belum dibaca.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email telah Dikonfirmasi", "email-confirmed-message": "Terimakasih telah melakukan validasi email. Akunmu saat ini telah aktif sepenuhnya.", "email-confirm-error-message": "Terjadi masalah saat melakukan validasi emailmu. Mungkin terjadi kesalahan kode atau waktu habis.", - "email-confirm-sent": "Email konfirmasi telah dikirim." + "email-confirm-sent": "Email konfirmasi telah dikirim.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/id/topic.json b/public/language/id/topic.json index 745de176bf..700acd9b84 100644 --- a/public/language/id/topic.json +++ b/public/language/id/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Kamu yakin ingin mengembalikan topik ini?", "thread_tools.purge": "Musnahkan Topik", "thread_tools.purge_confirm": "Kamu yakin ingin memusnahkan topik ini?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Topik ini berhasil dipindahkan ke %1", "post_delete_confirm": "Kamu yakin ingin menghapus posting ini?", "post_restore_confirm": "Kamu yakin ingin mengembalikan posting ini?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Topik berhasil dicabangkan! Klik disini untuk menuju topik yang telah dicabangkan.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Masukkan judul topik di sini...", "composer.handle_placeholder": "Nama", "composer.discard": "Buang", diff --git a/public/language/id/user.json b/public/language/id/user.json index b2f67b1298..7f2b874e76 100644 --- a/public/language/id/user.json +++ b/public/language/id/user.json @@ -79,8 +79,6 @@ "digest_daily": "Harian", "digest_weekly": "Mingguan", "digest_monthly": "Bulanan", - "send_chat_notifications": "Kirimkan email jika menerima pesan percakapan dan saya sedang tidak online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "User ini tidak memiliki pengikut :(", "follows_no_one": "User ini tidak mengikuti seorangpun :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Pengaturan Penelusuran", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Gunakan Pencarian Di dalam Topik", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/it/admin/appearance/customise.json b/public/language/it/admin/appearance/customise.json index c5eb9568ef..b07dc4bf4f 100644 --- a/public/language/it/admin/appearance/customise.json +++ b/public/language/it/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Inserisci le tue dichiarazioni CSS qui, verranno applicate dopo tutti gli altri stili.", "custom-css.enable": "Abilita CSS Personalizzato", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Intestazione Personalizzata", - "custom-header.description": "Inserisci l' HTML personalizzato qui (es. JavaScript, Meta Tags, ecc.), verrà attaccato al codice <head> sezione del markup del tuo forum", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Abilita l'Intestazione Personalizzata", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/it/admin/menu.json b/public/language/it/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/it/admin/menu.json +++ b/public/language/it/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/it/admin/settings/notifications.json b/public/language/it/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/it/admin/settings/notifications.json +++ b/public/language/it/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/it/admin/settings/post.json b/public/language/it/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/it/admin/settings/post.json +++ b/public/language/it/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/it/admin/settings/user.json b/public/language/it/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/it/admin/settings/user.json +++ b/public/language/it/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/it/email.json b/public/language/it/email.json index 48dbc3fd50..bcada51df4 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Questa notifica di chat ti è stata inviata perché l'hai scelta nelle impostazioni.", "notif.post.cta": "Clicca qui per leggere la discussione completa", "notif.post.unsub.info": "Questo post ti è stato notificato in base alle tue impostazioni di sottoscrizione.", + "notif.cta": "Vai alla discussione", "test.text1": "Questa è una email di test per verificare che il servizio di invio email è configurato correttamente sul tuo NodeBB.", "unsub.cta": "Clicca qui per modificare queste impostazioni", "banned.subject": "You have been banned from %1", diff --git a/public/language/it/error.json b/public/language/it/error.json index 4484e91246..9fa55ff42e 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Non hai i privilegi per votare negativamente questo post", "not-enough-reputation-to-flag": "Tu non hai abbastanza reputazione per segnalare questo Post", "already-flagged": "Hai già messo marcato questo post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB ha incontrato un problema durante il ricaricamento: \"%1\". NodeBB continuerà a servire gli assets esistenti lato client, così puoi annullare quello che hai fatto prima di ricaricare.", "registration-error": "Errore nella registrazione", "parse-error": "Qualcosa è andato storto durante l'analisi della risposta proveniente dal server", "wrong-login-type-email": "Per favore usa la tua email per accedere", "wrong-login-type-username": "Per favore usa il tuo nome utente per accedere", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Hai invitato il massimo numero di persone possibili (%1 su %2).", "no-session-found": "Nessuna sessione valida di login trovata!", "not-in-room": "L'utente non è in questa stanza", @@ -132,5 +134,6 @@ "no-users-selected": "Nessun utente selezionato", "invalid-home-page-route": "Percorso della pagina iniziale non valido", "invalid-session": "Discrepanza della sessione", - "invalid-session-text": "Sembra che la tua sessione non sia più attiva, oppure non corrisponde con il server. Per favore ricarica la pagina." + "invalid-session-text": "Sembra che la tua sessione non sia più attiva, oppure non corrisponde con il server. Per favore ricarica la pagina.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index dcf4cb684b..5aa5225d1b 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -9,9 +9,10 @@ "continue_to": "Continua a %1", "return_to": "Ritorna a %1", "new_notification": "Nuova Notifica", + "new_notification_from": "Notifica dal %1", "you_have_unread_notifications": "Hai notifiche non lette.", "all": "Tutte", - "topics": "Topics", + "topics": "Discussioni", "replies": "Risposte", "chat": "Chat", "follows": "Segui", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confermata", "email-confirmed-message": "Grazie per aver validato la tua email. Il tuo account è ora completamente attivato.", "email-confirm-error-message": "C'è stato un problema nella validazione del tuo indirizzo email. Potrebbe essere il codice non valido o scaduto.", - "email-confirm-sent": "Email di conferma inviata." + "email-confirm-sent": "Email di conferma inviata.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/it/topic.json b/public/language/it/topic.json index e9540a5b89..747ba4876b 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Sei sicuro di voler ripristinare questa discussione?", "thread_tools.purge": "Svuota Discussione", "thread_tools.purge_confirm": "Sei sicuro di voler svuotare questa discussione?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Questa discussione è stata correttamente spostata in %1", "post_delete_confirm": "Sei sicuro di voler cancellare questo post?", "post_restore_confirm": "Sei sicuro di voler ripristinare questo post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post selezionati", "fork_success": "Topic Diviso con successo ! Clicca qui per andare al Topic Diviso.", "delete_posts_instruction": "Clicca sui post che vuoi cancellare/eliminare", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Inserisci qui il titolo della discussione...", "composer.handle_placeholder": "Nome", "composer.discard": "Annulla", diff --git a/public/language/it/unread.json b/public/language/it/unread.json index 470c0e4c41..c1244d0fe3 100644 --- a/public/language/it/unread.json +++ b/public/language/it/unread.json @@ -10,6 +10,6 @@ "all-topics": "Tutte le Discussioni", "new-topics": "Nuova Discussione", "watched-topics": "Discussioni seguite", - "unreplied-topics": "Unreplied Topics", + "unreplied-topics": "Nessuna Risposta", "multiple-categories-selected": "Multiple Selected" } \ No newline at end of file diff --git a/public/language/it/user.json b/public/language/it/user.json index 9eea1dccfc..a24f325d24 100644 --- a/public/language/it/user.json +++ b/public/language/it/user.json @@ -79,8 +79,6 @@ "digest_daily": "Quotidiano", "digest_weekly": "Settimanale", "digest_monthly": "Mensile", - "send_chat_notifications": "Invia una email se arriva un nuovo messaggio di chat e non sono online", - "send_post_notifications": "Invia una email quando ci sono nuove risposte a discussioni a cui sono sottoscritto", "settings-require-reload": "Alcuni cambiamenti di impostazioni richiedono un ricaricamento. Clicca qui per ricaricare la pagina.", "has_no_follower": "Questo utente non è seguito da nessuno :(", "follows_no_one": "Questo utente non segue nessuno :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Suono messaggio in uscita", "notification-sound": "Suono di notifica", "no-sound": "Nessun suono", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Impostazioni di Navigazione", "open_links_in_new_tab": "Apri i link web in una nuova pagina", "enable_topic_searching": "Abilita la ricerca negli argomenti", @@ -123,6 +126,9 @@ "sso.title": "Servizi Single-Sign-On", "sso.associated": "Associa con", "sso.not-associated": "Clicca qui per associare con", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Ultime Segnalazioni", "info.no-flags": "Non è stato trovato nessun post segnalato", "info.ban-history": "Storico dei Ban recenti", diff --git a/public/language/ja/admin/appearance/customise.json b/public/language/ja/admin/appearance/customise.json index 590a0ca57d..1cfa0dea9d 100644 --- a/public/language/ja/admin/appearance/customise.json +++ b/public/language/ja/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "あなたのCSS設定をこちらに追加すると他のすべてのスタイルの後に適用されます。", "custom-css.enable": "カスタムCSSを有効にする", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "カスタムヘッダー", - "custom-header.description": "カスタムしたHTMLを入力してください(例. JavaScript, メタタグなど)。これはフォーラムのマークアップの<head>に追加されます。", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "カスタムヘッダーを有効にする", "custom-css.livereload": "ライブリロードを有効にする", diff --git a/public/language/ja/admin/menu.json b/public/language/ja/admin/menu.json index d64271ea7d..10ffdac477 100644 --- a/public/language/ja/admin/menu.json +++ b/public/language/ja/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "外観", "appearance/themes": "テーマ", "appearance/skins": "スキン", - "appearance/customise": "カスタムHTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "拡張", "extend/plugins": "プラグイン", diff --git a/public/language/ja/admin/settings/notifications.json b/public/language/ja/admin/settings/notifications.json index bda17cd95b..d69a16d629 100644 --- a/public/language/ja/admin/settings/notifications.json +++ b/public/language/ja/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "通知", "welcome-notification": "ウェルカム通知", - "welcome-notification-link": "ウェルカム通知のリンク" + "welcome-notification-link": "ウェルカム通知のリンク", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ja/admin/settings/post.json b/public/language/ja/admin/settings/post.json index 556fe7efc0..60c1ca251b 100644 --- a/public/language/ja/admin/settings/post.json +++ b/public/language/ja/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "新しい順に", "sorting.newest-to-oldest": "新しいものから古いものへ", "sorting.most-votes": "最も多い評価", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "デフォルトのスレッドの並び順", "restrictions": "転記の制限", "restrictions.post-queue": "投稿キューを有効にする", diff --git a/public/language/ja/admin/settings/user.json b/public/language/ja/admin/settings/user.json index 648809c1f9..b8f3bc16f0 100644 --- a/public/language/ja/admin/settings/user.json +++ b/public/language/ja/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "テーマ", "disable-user-skins": "ユーザーがカスタムスキンを選択できないようにする", "account-protection": "アカウント保護", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "時間ごとのログイン試行", "login-attempts-help": "ユーザのアカウントへのログイン試行数がこの値を超える場合、そのアカウントは予め設定された時間だけロックされます。", "lockout-duration": "アカウントロックアウト期間(分)", diff --git a/public/language/ja/email.json b/public/language/ja/email.json index f42c51eb3b..73cacee888 100644 --- a/public/language/ja/email.json +++ b/public/language/ja/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "このチャットの通知はあなたの購読設定により送られました。", "notif.post.cta": "ここをクリックして全て読みます", "notif.post.unsub.info": "この投稿の通知はあなたの申し込み設定により送られました。", + "notif.cta": "Click here to go to forum", "test.text1": "このメールはNodeBBのメーラー(emailer)が正しく設定されているか確認をするためのメールです。", "unsub.cta": "ここをクリックして設定を変更する", "banned.subject": "%1さんからBANされました。", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index ea59517924..0ddf8aa938 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "ユーザーが部屋にいません", @@ -132,5 +134,6 @@ "no-users-selected": "ユーザー(s)が選択されていません", "invalid-home-page-route": "ホームページのルートが無効", "invalid-session": "セッションの不一致", - "invalid-session-text": "ログインセッションの期限切れ、またはサーバーとの未接続が長すぎると思われます。このページを更新してみてください。" + "invalid-session-text": "ログインセッションの期限切れ、またはサーバーとの未接続が長すぎると思われます。このページを更新してみてください。", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json index 384e1d0342..a535562dcd 100644 --- a/public/language/ja/notifications.json +++ b/public/language/ja/notifications.json @@ -9,6 +9,7 @@ "continue_to": "%1へ行く", "return_to": "%1へ戻る", "new_notification": "新しい通知", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "未読の通知があります。", "all": "全て", "topics": "スレッド", @@ -45,5 +46,19 @@ "email-confirmed": "Eメールが確認されました", "email-confirmed-message": "メールアドレス検証をして頂き、ありがとうございます。あなたのアカウントは完全にアクティブになりました。", "email-confirm-error-message": "あなたのEメールアドレス検証に問題があります。コードが無効か、期限切れです。", - "email-confirm-sent": "確認メールが送信されました。" + "email-confirm-sent": "確認メールが送信されました。", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json index 98e0208920..f34844e326 100644 --- a/public/language/ja/topic.json +++ b/public/language/ja/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "本当にこのスレッドを戻しますか?", "thread_tools.purge": "スレッドを切り離します", "thread_tools.purge_confirm": "本当にこのスレッドを切り離しますか?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "このスレッドを%1に移動しました。", "post_delete_confirm": "本当にこの投稿を削除しますか?", "post_restore_confirm": "本当にこの投稿を元に戻しますか?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 投稿(s)が選択されました", "fork_success": "スレッドをフォークするのに成功しました。ここを押して、このフォークしたスレッドに行きます。", "delete_posts_instruction": "削除または切り離するには、当てはまる投稿を押してください", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "スレッドのタイトルを入力...", "composer.handle_placeholder": "名前", "composer.discard": "破棄する", diff --git a/public/language/ja/user.json b/public/language/ja/user.json index 552c6c944f..a9e5689f76 100644 --- a/public/language/ja/user.json +++ b/public/language/ja/user.json @@ -79,8 +79,6 @@ "digest_daily": "デイリー", "digest_weekly": "ウィークリー", "digest_monthly": "マンスリー", - "send_chat_notifications": "オンラインではない時に新しいチャットメッセージを受信した場合、通知メールを送信する。", - "send_post_notifications": "購読中のスレッドに返信があった場合、メールで通知する。", "settings-require-reload": "設定を変更するにはページを更新する必要があります。ここを押して、ページを更新します。", "has_no_follower": "フォロワーはまだいません :(", "follows_no_one": "フォロー中のユーザーはまだいません :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "送信メッセージの音", "notification-sound": "通知音", "no-sound": "無音", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "ブラウジングの設定", "open_links_in_new_tab": "外部リンクを新しいタブで開く", "enable_topic_searching": "インースレッドの検索を有効にします", @@ -123,6 +126,9 @@ "sso.title": "シングルサインオンサービス", "sso.associated": "関連付けられています", "sso.not-associated": "ここを押して、関連付けられています", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "最近のフラグ", "info.no-flags": "フラグのついた投稿はありません", "info.ban-history": "最近停止した履歴", diff --git a/public/language/ko/admin/appearance/customise.json b/public/language/ko/admin/appearance/customise.json index 37a5dc71a4..0c0b028b98 100644 --- a/public/language/ko/admin/appearance/customise.json +++ b/public/language/ko/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "사용자 정의 CSS를 이곳에 입력하세요. 이 스타일들은 맨 마지막에 적용됩니다.", "custom-css.enable": "사용자 정의 CSS 허용", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "사용자 정의 헤더", - "custom-header.description": "이곳에 사용자 정의 HTML을 입력하십시오 (예. JavaScript, Meta Tags, 등등). 당신의 포럼의 <head>1 섹션에 추가됩니다.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "사용자 정의 헤더 허용", "custom-css.livereload": "실시간 새로 고침 허용", diff --git a/public/language/ko/admin/general/dashboard.json b/public/language/ko/admin/general/dashboard.json index 61879612aa..d56ec7fb1b 100644 --- a/public/language/ko/admin/general/dashboard.json +++ b/public/language/ko/admin/general/dashboard.json @@ -23,8 +23,8 @@ "running-version": "NodeBB v%1 를 사용 중입니다.", "keep-updated": "사용하시는 NodeBB의 보안 및 오류 업데이트를 항상 최신 버젼으로 유지하십시오.", "up-to-date": "

최신 버전입니다

", - "upgrade-available": "

A new version (v%1) has been released. Consider upgrading your NodeBB.

", - "prerelease-upgrade-available": "

This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.

", + "upgrade-available": "

새로운 버전 (v%1)이 나왔습니다. NodeBB 업데이트가 가능합니다.

", + "prerelease-upgrade-available": "

NodeBB의 시험판을 사용중입니다. 새 버전 (v%1)이 출시되었습니다. NodeBB 업데이트를 하세요.

", "prerelease-warning": "

이것은 정식 발표 전 버젼의 NodeBB 입니다. 예상치 못한 버그가 발생할 수 있습니다.

", "running-in-development": "포럼이 개발자 모드로 실행되고 있습니다. 잠재적 취약점에 노출되어 있을 수 있으니 시스템 관리자에게 문의하십시오.", diff --git a/public/language/ko/admin/general/navigation.json b/public/language/ko/admin/general/navigation.json index f3c2940a65..81ad60c94c 100644 --- a/public/language/ko/admin/general/navigation.json +++ b/public/language/ko/admin/general/navigation.json @@ -11,7 +11,7 @@ "only-admins": "관리자에게만 보이기", "only-global-mods-and-admins": "(준)관리자와 관리자에게만 보이기", "only-logged-in": "로그인한 사용자에게만 보이기", - "only-guest": "Only display to guests", + "only-guest": "게스트에게만 보이기", "open-new-window": "새 창에서 열기", "installed-plugins-required": "설치된 플러그인 필수:", diff --git a/public/language/ko/admin/manage/post-queue.json b/public/language/ko/admin/manage/post-queue.json index 4de24c991b..176d740765 100644 --- a/public/language/ko/admin/manage/post-queue.json +++ b/public/language/ko/admin/manage/post-queue.json @@ -1,11 +1,11 @@ { - "post-queue": "Post Queue", - "description": "There are no posts in the post queue.
To enable this feature, go to Settings → Post → Posting Restrictions and enable Post Queue.", - "user": "User", - "category": "Category", - "title": "Title", - "content": "Content", - "posted": "Posted", - "reply-to": "Reply to \"%1\"", - "content-editable": "You can click on individual content to edit before posting." + "post-queue": "게시 대기열", + "description": "게시 대기열에 글이 없습니다.
이 기능을 사용하려면 설정 → 글→ 게시대기에서게시대기를 활성화 하세요.", + "user": "사용자", + "category": "카테고리", + "title": "제목", + "content": "컨텐츠", + "posted": "작성됨", + "reply-to": "'%1'에 대한 답글", + "content-editable": "게시하기 전에 콘텐츠를 클릭하여 편집 할 수 있습니다." } \ No newline at end of file diff --git a/public/language/ko/admin/menu.json b/public/language/ko/admin/menu.json index 4312e0a704..3dbb61f8f5 100644 --- a/public/language/ko/admin/menu.json +++ b/public/language/ko/admin/menu.json @@ -12,7 +12,7 @@ "manage/tags": "태그", "manage/users": "용자", "manage/registration": "회원 가입 승인 대기자", - "manage/post-queue": "Post Queue", + "manage/post-queue": "게시 대기열", "manage/groups": "그룹", "manage/ip-blacklist": "IP 블랙리스트", @@ -39,7 +39,7 @@ "section-appearance": "스타일", "appearance/themes": "테마", "appearance/skins": "스킨", - "appearance/customise": "사용자 정의 HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "추가 기능", "extend/plugins": "플러그인", @@ -65,7 +65,7 @@ "logout": "로그아웃", "view-forum": "포럼 보기", - "search.placeholder": "Search for settings", + "search.placeholder": "설정 검색", "search.no-results": "검색 결과가 없습니다...", "search.search-forum": "포럼에서 를 검색하세요", "search.keep-typing": "검색 결과를 보기 위해 더 입력하세요...", diff --git a/public/language/ko/admin/settings/notifications.json b/public/language/ko/admin/settings/notifications.json index 0b2bab42c5..4d08749154 100644 --- a/public/language/ko/admin/settings/notifications.json +++ b/public/language/ko/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "알림", "welcome-notification": "환영 알림", - "welcome-notification-link": "환영 알림 링크" + "welcome-notification-link": "환영 알림 링크", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ko/admin/settings/pagination.json b/public/language/ko/admin/settings/pagination.json index 5a5ef4fdab..ebcc672f9a 100644 --- a/public/language/ko/admin/settings/pagination.json +++ b/public/language/ko/admin/settings/pagination.json @@ -3,9 +3,9 @@ "enable": "무한 스크롤 대신 페이지로 주제와 포스트 보여주기", "topics": "주제 페이지", "posts-per-page": "페이지 당 포스트", - "max-posts-per-page": "Maximum posts per page", + "max-posts-per-page": "페이지당 최대 포스트수", "categories": "카테고리 페이지", "topics-per-page": "페이지 당 주제 수", - "max-topics-per-page": "Maximum topics per page", + "max-topics-per-page": "페이지당 최대 게시물 수", "initial-num-load": "읽지 않은 글, 최근 작성 글, 인기 글 게시판에서 처음 보여줄 게시글 개수" } \ No newline at end of file diff --git a/public/language/ko/admin/settings/post.json b/public/language/ko/admin/settings/post.json index 6c711c797e..001a8b7376 100644 --- a/public/language/ko/admin/settings/post.json +++ b/public/language/ko/admin/settings/post.json @@ -4,10 +4,11 @@ "sorting.oldest-to-newest": "오래된 순", "sorting.newest-to-oldest": "최신 순", "sorting.most-votes": "추천수 순으로 정렬", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "게시물 정렬기준 기본값", "restrictions": "글 작성 제약사항", - "restrictions.post-queue": "Enable post queue", - "restrictions.post-queue-help": "Enabling post queue will put the posts of new users in a queue for approval.", + "restrictions.post-queue": "게시 대기열 사용", + "restrictions.post-queue-help": "게시 대기열을 사용하면 사용자의 게시물이 대기열에 넣어집니다.", "restrictions.seconds-between": "글 작성 간 시간(초)", "restrictions.seconds-between-new": "신규 사용자인 경우, 글 작성 간 시간(초)", "restrictions.rep-threshold": "위 제약을 해제하기 위한 최소 등급", diff --git a/public/language/ko/admin/settings/user.json b/public/language/ko/admin/settings/user.json index 78a9bac909..5b803b612e 100644 --- a/public/language/ko/admin/settings/user.json +++ b/public/language/ko/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "테마", "disable-user-skins": "일반 사용자가 스킨 지정 금지", "account-protection": "계정 보호", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "시간당 가능한 로그인 시도 횟수", "login-attempts-help": "사용자의 로그인 시도가 이 횟수제한을 초과하면 정해진 시간만큼 해당 계정이 잠깁니다.", "lockout-duration": "계정 잠금 기간 (분)", diff --git a/public/language/ko/email.json b/public/language/ko/email.json index 3a35e5d41b..e0d56d6fc9 100644 --- a/public/language/ko/email.json +++ b/public/language/ko/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "이 대화 알림은 사용자의 구독 설정에 따라 전송되었습니다.", "notif.post.cta": "이곳을 클릭하여 전체 내용 보기", "notif.post.unsub.info": "이 게시물 알림은 사용자의 구독 설정에 따라 전송되었습니다.", + "notif.cta": "Click here to go to forum", "test.text1": "이 시험용 메일은 NodeBB에 설정된 메일 송신자가 정상적으로 메일을 송신할 수 있는지 시험할 목적으로 발송되었습니다.", "unsub.cta": "설정을 변경하려면 여기를 클릭하세요.", "banned.subject": "귀하는 %1 로 부터 차단되었습니다.", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 40af6bfcd7..38b837c798 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "인지도가 낮아 이 포스트를 비추천할 수 없습니다.", "not-enough-reputation-to-flag": "인지도가 낮아 이 포스트를 신고할 수 없습니다.", "already-flagged": "이미 이 게시물을 신고했습니다.", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB 서버를 다시 읽어들이는 중 다음과 같은 문제가 발생했으나 사용자측은 지속적으로 자원을 제공받습니다. 오류 문구: \"%1\" 문제를 해결하시려면 다시 읽어들이기 전의 수정사항을 원래대로 되돌려주세요. ", "registration-error": "등록 오류", "parse-error": "서버로 부터의 응답을 읽는 동안 문제가 발생했습니다.", "wrong-login-type-email": "이메일 주소를 통해 로그인하세요.", "wrong-login-type-username": "사용자명을 통해 로그인하세요.", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "초대 한도 만큼의 사용자를 초대했습니다. (%2명 중 %1을 초대)", "no-session-found": "로그인 세션을 찾을 수 없습니다.", "not-in-room": "없는 사용자입니다.", @@ -132,5 +134,6 @@ "no-users-selected": "선택된 사용자가 없습니다.", "invalid-home-page-route": "올바르지 않은 홈페이지 경로입니다. ", "invalid-session": "일치하지 않는 세션입니다.", - "invalid-session-text": "로그인 세션이 비활성화 되었거나 서버와 일치하지 않습니다. 페이지를 새로 고쳐주세요." + "invalid-session-text": "로그인 세션이 비활성화 되었거나 서버와 일치하지 않습니다. 페이지를 새로 고쳐주세요.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json index 76d9cb9830..a6f3f77b1e 100644 --- a/public/language/ko/notifications.json +++ b/public/language/ko/notifications.json @@ -9,6 +9,7 @@ "continue_to": "%1 사이트로 이동", "return_to": "%1 사이트로 돌아가기", "new_notification": "새 알림", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "읽지 않은 알림이 있습니다.", "all": "모든 알림", "topics": "게시물", @@ -41,9 +42,23 @@ "new_register": "%1님이 가입요청을 했습니다.", "new_register_multiple": "%1 개의 회원가입 요청이 승인 대기중입니다.", "flag_assigned_to_you": "신고 ID %1 이 나에게 배정되었습니다.", - "post_awaiting_review": "Post awaiting review", + "post_awaiting_review": "검토중인 게시물", "email-confirmed": "이메일 인증 되었습니다", "email-confirmed-message": "이메일을 인증해주셔서 감사합니다. 계정이 완전히 활성화되었습니다.", "email-confirm-error-message": "이메일 주소를 인증하지 못했습니다. 코드가 올바르지 않거나 만료 되었을 수 있습니다.", - "email-confirm-sent": "확인 이메일이 발송되었습니다." + "email-confirm-sent": "확인 이메일이 발송되었습니다.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ko/success.json b/public/language/ko/success.json index c671b6a09a..b910a81055 100644 --- a/public/language/ko/success.json +++ b/public/language/ko/success.json @@ -1,7 +1,7 @@ { "success": "성공", "topic-post": "성공적으로 게시물을 작성했습니다.", - "post-queued": "Your post is queued for approval.", + "post-queued": "게시물이 승인 대기 중입니다.", "authentication-successful": "인증에 성공했습니다.", "settings-saved": "설정이 저장되었습니다!" } \ No newline at end of file diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index 11d0d8fc7e..d55fb7fcec 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "이 게시물을 복원 하시겠습니까?", "thread_tools.purge": "게시물 폐기", "thread_tools.purge_confirm": "이 게시물을 폐기 하시겠습니까?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "성공적으로 이 게시물을 %1로 이동했습니다.", "post_delete_confirm": "이 포스트를 삭제 하시겠습니까?", "post_restore_confirm": "이 포스트를 복원 하시겠습니까?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 개의 포스트(들)이 선택되었습니다", "fork_success": "게시물이 분리되었습니다! 분리된 게시물을 보려면 여기를 클릭 하세요.", "delete_posts_instruction": "삭제할 포스트를 선택하세요.", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "게시물 제목을 입력하세요.", "composer.handle_placeholder": "이름", "composer.discard": "취소", diff --git a/public/language/ko/unread.json b/public/language/ko/unread.json index d508cae95c..48a092c25e 100644 --- a/public/language/ko/unread.json +++ b/public/language/ko/unread.json @@ -10,6 +10,6 @@ "all-topics": "모든 게시물", "new-topics": "새 게시물", "watched-topics": "관심있는 게시물", - "unreplied-topics": "Unreplied Topics", - "multiple-categories-selected": "Multiple Selected" + "unreplied-topics": "해결되지 않은 주제", + "multiple-categories-selected": "다중선택됨" } \ No newline at end of file diff --git a/public/language/ko/user.json b/public/language/ko/user.json index 60050414b5..a06592b287 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -79,8 +79,6 @@ "digest_daily": "매일", "digest_weekly": "매주", "digest_monthly": "매월", - "send_chat_notifications": "오프라인일 때 채팅 메시지가 도착하면 알림 메일을 보냅니다.", - "send_post_notifications": "내가 관심있는 게시물에 답글이 달리면 메일을 보냅니다.", "settings-require-reload": "일부 설정 변경은 새로고침이 필요합니다. 여기를 눌러서 페이지를 새로고침 해주세요.", "has_no_follower": "이 사용자는 팔로워가 없습니다 :(", "follows_no_one": "이 사용자는 아무도 팔로우하고 있지 않습니다 :(", @@ -96,13 +94,18 @@ "paginate_description": "주제와 게시물을 페이지로 정리", "topics_per_page": "페이지 당 게시물 수", "posts_per_page": "페이지 당 포스트 수", - "max_items_per_page": "Maximum %1", + "max_items_per_page": "최대 %1 ", "notification_sounds": "알림 수신시 소리로 알려주기", "notifications_and_sounds": "알림 / 알림음 설정", "incoming-message-sound": "수신 메시지 알림음", "outgoing-message-sound": "발신 메시지 알림음", "notification-sound": "알림음", "no-sound": "음소거", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "브라우징 설정", "open_links_in_new_tab": "외부 링크를 새로운 탭에서 열람", "enable_topic_searching": "게시물 내 검색 허용", @@ -123,6 +126,9 @@ "sso.title": "통합 인증 서비스", "sso.associated": "와/과 연동된", "sso.not-associated": "이 곳을 클릭하여 연동시키세요.", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "최근에 들어온 신고", "info.no-flags": "신고된 포스트가 없습니다.", "info.ban-history": "최근 차단 히스토리", diff --git a/public/language/lt/admin/appearance/customise.json b/public/language/lt/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/lt/admin/appearance/customise.json +++ b/public/language/lt/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/lt/admin/menu.json b/public/language/lt/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/lt/admin/menu.json +++ b/public/language/lt/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/lt/admin/settings/notifications.json b/public/language/lt/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/lt/admin/settings/notifications.json +++ b/public/language/lt/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/lt/admin/settings/post.json b/public/language/lt/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/lt/admin/settings/post.json +++ b/public/language/lt/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/lt/admin/settings/user.json b/public/language/lt/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/lt/admin/settings/user.json +++ b/public/language/lt/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/lt/email.json b/public/language/lt/email.json index 699f8cacd1..36e50d1fcc 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Šios žinutės perpėjimas buvo išsiųstas į tavo prenumeratos nustatymus", "notif.post.cta": "Spauskite čia norėdami skaityti visą temą", "notif.post.unsub.info": "Šios žinutės perspėjimas buvo išsiųstas į tavo prenumeratos nustatymus", + "notif.cta": "Click here to go to forum", "test.text1": "Ši žinutė yra bandomoji kad įsitikint, kad vartotojas teisingai nustatė nustatymus tavo NodeBB", "unsub.cta": "Spauskite čia norėdami pakeisti šiuos nustatymus", "banned.subject": "You have been banned from %1", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index ab2b25b580..064cd77941 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Jūs neturite pakankamai reputacijos balsuoti prieš šį pranešimą", "not-enough-reputation-to-flag": "Jūs neturite pakankamai reputacijos kad įspėti dėl šito pranešimo", "already-flagged": "Jūs jau pranešėte apie šį pranešimą", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB susidūrė su problema persikraunant: \"%1\", NodeBB pratęs veikti su šiuo klientu. bet jums reiktu patikrinti ką jūs darėte prieš perkraunant NodeBB", "registration-error": "Registracijos klaida", "parse-error": "Kažkokia klaida įvyko bandant gaut serverio atsaykmą", "wrong-login-type-email": "Prisijungimui prašom naudoti jūsų el. adresą", "wrong-login-type-username": "Prisijungimui prašome naudoti vartotojo vardą", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json index 6e8757cb8e..56a4698eeb 100644 --- a/public/language/lt/notifications.json +++ b/public/language/lt/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Tęsti į %1", "return_to": "Grįžti į %1", "new_notification": "Naujas pranešimas", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Jūs turite neperskaitytų pranešimų.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "El. paštas patvirtintas", "email-confirmed-message": "Dėkojame už el. pašto patvirtinimą. Jūsų paskyra pilnai aktyvuota.", "email-confirm-error-message": "Įvyko klaida mėginant patvirtinti Jūsų el. pašto adresą. Galbūt kodas yra neteisingas, arba nebegalioajantis.", - "email-confirm-sent": "Patvirtinimo laiškas išsiųstas." + "email-confirm-sent": "Patvirtinimo laiškas išsiųstas.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 406d1062b9..822acaf0b8 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Ar jūs tikrai norite atkurti šią temą?", "thread_tools.purge": "Išvalyti temą", "thread_tools.purge_confirm": "Ar tikrai norite išvalyti šią temą?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Ši tema buvo sėkmingai perkelta į %1", "post_delete_confirm": "Ar jūs tikrai norite ištrinti šį įrašą?", "post_restore_confirm": "Ar jūs tikrai norite atkurti šį įrašą?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Sėkmingai išsišakota iš temos! Spausk čia kad nueitu į išsišakota temą", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Įrašykite temos pavadinimą...", "composer.handle_placeholder": "Vardas ir pavardė", "composer.discard": "Atšaukti", diff --git a/public/language/lt/user.json b/public/language/lt/user.json index 0f4ecf0164..9e440fb137 100644 --- a/public/language/lt/user.json +++ b/public/language/lt/user.json @@ -79,8 +79,6 @@ "digest_daily": "Kas dieną", "digest_weekly": "Kas savaitę", "digest_monthly": "Kas mėnesį", - "send_chat_notifications": "Jeigu gaunama nauja pokalbių žinutė ir aš neprisijungęs, siųsti el. laišką", - "send_post_notifications": "Atsiųsti el. laišką kai parašomi atsakymai į mano prenumeruojamas temas", "settings-require-reload": "Kai kurie nustatymų pakeitimai reikalauja perkrovimo. Spauskite čia kad perkrauti puslapį", "has_no_follower": "Šis vartotojas neturi jokių sekėjų :(", "follows_no_one": "Šis vartotojas nieko neseka :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Siunčiamos žinutės garsas", "notification-sound": "Pranešimo garsas", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Naršymo nustatymai", "open_links_in_new_tab": "Atidaryti išeinančias nuorodas naujam skirtuke", "enable_topic_searching": "Įjungti Temų Ieškojimą ", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "Nerasta pažymėtų pranešimų", "info.ban-history": "Blokavimų istorija", diff --git a/public/language/ms/admin/appearance/customise.json b/public/language/ms/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/ms/admin/appearance/customise.json +++ b/public/language/ms/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/ms/admin/menu.json b/public/language/ms/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/ms/admin/menu.json +++ b/public/language/ms/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/ms/admin/settings/notifications.json b/public/language/ms/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/ms/admin/settings/notifications.json +++ b/public/language/ms/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ms/admin/settings/post.json b/public/language/ms/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/ms/admin/settings/post.json +++ b/public/language/ms/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/ms/admin/settings/user.json b/public/language/ms/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/ms/admin/settings/user.json +++ b/public/language/ms/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/ms/email.json b/public/language/ms/email.json index 804155fd84..36803dcd76 100644 --- a/public/language/ms/email.json +++ b/public/language/ms/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Pemberitahuan sembang ini dihantar berdasarkan tetapan langganan anda.", "notif.post.cta": "Klik sini untuk baca artikel penuh", "notif.post.unsub.info": "Kiriman pemberitahuan ini dihantar berdasarkan tetapan langganan anda.", + "notif.cta": "Click here to go to forum", "test.text1": "Ini adalah percubaan email untuk mengesahkan emailer ditetap dengan betul di NodeBB.", "unsub.cta": "Klik sini untuk mengubah tetapan itu", "banned.subject": "You have been banned from %1", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index bbef66b65a..08b28dd54a 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Anda tidak mempunyai reputasi mencukupi untuk mengundi turun kiriman ini", "not-enough-reputation-to-flag": "Anda tidak mempunyai reputasi mencukupi untuk menanda kiriman ini", "already-flagged": "Anda telah menanda kiriman ini", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB menemui masalah ketika muat semula: \"%1\". NodeBB akan terus melayan aset pelanggan sedia ada, tapi anda seharusnya undur perbuatan yang dilakukan sebelum muat semula.", "registration-error": "Ralat pendaftaran.", "parse-error": "Sesuatu tidak kena berlaku ketika menghuraikan repson pelayan (server)", "wrong-login-type-email": "Sila guna emel anda untuk log masuk", "wrong-login-type-username": "Sila guna nama pengguna anda untuk log masuk", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Anda telah menjemput semaksima jumlah orang (%1 daripada %2).", "no-session-found": "Tiada sesyen log masuk dijumpai", "not-in-room": "Pengguna tiada dalam bilik", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json index db4c47191b..96280e297e 100644 --- a/public/language/ms/notifications.json +++ b/public/language/ms/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Sambung ke %1", "return_to": "Kembali ke %1", "new_notification": "Pemberitahuan baru", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Ada pemberitahuan yang belum dibaca", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Emel Disahkan", "email-confirmed-message": "Terima kasih kerana mengesahkan emel anda. Akaun anda telah diaktifkan sepenuhnya.", "email-confirm-error-message": "Berlaku masalah semasa mengesahkan emel anda. Mungkin kod tidak sah atau tamat tempoh.", - "email-confirm-sent": "Pengesahan emel telah dihantar." + "email-confirm-sent": "Pengesahan emel telah dihantar.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ms/topic.json b/public/language/ms/topic.json index 3f8737d458..5467b70702 100644 --- a/public/language/ms/topic.json +++ b/public/language/ms/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Anda yakin untuk pulihkan topik ini?", "thread_tools.purge": "Singkirkan Topik", "thread_tools.purge_confirm": "Anda yakin untuk singkirkan topik ini?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Topik telah dipindahkan ke %1", "post_delete_confirm": "Adakah anda pasti untuk memadam kiriman ini?", "post_restore_confirm": "Adakah anda pasti untuk memulihkan kiriman ini?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Berjaya menyalin topik. Klik sini untuk ke topik yang disalin.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Masukkan tajuk topik disini", "composer.handle_placeholder": "Nama", "composer.discard": "Abaikan", diff --git a/public/language/ms/user.json b/public/language/ms/user.json index 43eb03be3c..e202ac1921 100644 --- a/public/language/ms/user.json +++ b/public/language/ms/user.json @@ -79,8 +79,6 @@ "digest_daily": "Harian", "digest_weekly": "Mingguan", "digest_monthly": "Bulanan", - "send_chat_notifications": "Hantar emel sekiranya ada mesej sembang baru dan saya di luar talian (offline)", - "send_post_notifications": "Hantarkan emel apabila topik yang saya langgan menerima balasan", "settings-require-reload": "Sebahagian perubahan tetapan memerlukan segar semula. Klik sini untuk segar semula halaman ini.", "has_no_follower": "Pengguna ini tiada pengikut :(", "follows_no_one": "Pengguna ini tidak mengikuti sesiapa :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Melihat-lihat Tetapan", "open_links_in_new_tab": "Buka pautan luar di tab yang baru", "enable_topic_searching": "Aktifkan Pencarian Dalam-Topik", @@ -123,6 +126,9 @@ "sso.title": "Servis Satu Log Masuk", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/nb/admin/appearance/customise.json b/public/language/nb/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/nb/admin/appearance/customise.json +++ b/public/language/nb/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/nb/admin/menu.json b/public/language/nb/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/nb/admin/menu.json +++ b/public/language/nb/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/nb/admin/settings/notifications.json b/public/language/nb/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/nb/admin/settings/notifications.json +++ b/public/language/nb/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/nb/admin/settings/post.json b/public/language/nb/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/nb/admin/settings/post.json +++ b/public/language/nb/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/nb/admin/settings/user.json b/public/language/nb/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/nb/admin/settings/user.json +++ b/public/language/nb/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/nb/email.json b/public/language/nb/email.json index 916aa5880b..faee4c1592 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Denne samtale-varselen ble sendt til deg basert på dine innstillinger for abonnering.", "notif.post.cta": "Trykk for å lese hele emnet", "notif.post.unsub.info": "Dette innleggsvarselet ble sendt til deg basert på dine innstillinger for abonnering.", + "notif.cta": "Click here to go to forum", "test.text1": "Dette er en test e-post for å verifisere at e-postsystemet i NodeBB fungerer som det skal.", "unsub.cta": "Klikk her for å endre disse innstillingene", "banned.subject": "You have been banned from %1", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index 37c81b0a5d..983ae1372e 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Du har ikke nok rykte til å nedstemme det innlegget", "not-enough-reputation-to-flag": "Du har ikke nok rykte til å flagge dette innlegget", "already-flagged": "Du har allerede flagget dette innlegget", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB støtte på et problem under lasting på nytt: \"%1\". NodeBB vil fortsette å servere eksisterende klientside ressurser, selv om du burde angre endringene du gjorde før du lastet på nytt.", "registration-error": "Feil under registrering", "parse-error": "Noe gikk feil under analysering av serversvar", "wrong-login-type-email": "Vennligst benytt e-posten din for å logge inn", "wrong-login-type-username": "Vennligst benytt brukernavnet ditt for å logge inn", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index d248bef66e..905f415d69 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Fortsett til %1", "return_to": "Gå tilbake til %1", "new_notification": "Nytt varsel", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Du har uleste varsler.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "E-post bekreftet", "email-confirmed-message": "Takk for at du har validert din e-post. Kontoen din er nå fullstendig aktivert.", "email-confirm-error-message": "Det oppsto et problem under valdiering av din e-post. Koden kan ha vært ugyldig eller ha utløpt.", - "email-confirm-sent": "Bekreftelsesepost sendt." + "email-confirm-sent": "Bekreftelsesepost sendt.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 031f366c51..27db8ac117 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Er du sikker på at du vil gjenopprette dette emnet?", "thread_tools.purge": "Rensk emne", "thread_tools.purge_confirm": "Er du sikker på at du vil renske dette emnet?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Emnet har blitt flyttet til %1", "post_delete_confirm": "Er du sikker på at du vil slette dette innlegget?", "post_restore_confirm": "Er du sikker på at du vil gjenopprette dette innlegget?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Dette emnet ble forgrenet! Klikk for å gå til forgrenet emne.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Skriv din tråd-tittel her", "composer.handle_placeholder": "Navn", "composer.discard": "Forkast", diff --git a/public/language/nb/user.json b/public/language/nb/user.json index a89d0f54ab..67b8e22f12 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -79,8 +79,6 @@ "digest_daily": "Daglig", "digest_weekly": "Ukentlig", "digest_monthly": "Månedlig", - "send_chat_notifications": "Send en epost hvis jeg mottar en chat-melding når jeg ikke er pålogget", - "send_post_notifications": "Send en e-post når svar postes til emner jeg abonnerer på", "settings-require-reload": "Noen innstillingsendringer krever at du laster siden på nytt. Klikk her for å laste på nytt.", "has_no_follower": "Denne brukeren har ingen følgere :(", "follows_no_one": "Denne brukeren følger ingen :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Surfeinnstillinger", "open_links_in_new_tab": "Åpne utgående lenker i en ny fane", "enable_topic_searching": "Aktiver søk-i-emne", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Assosiert med", "sso.not-associated": "Klikk her for å assosiere med", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/nl/admin/appearance/customise.json b/public/language/nl/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/nl/admin/appearance/customise.json +++ b/public/language/nl/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/nl/admin/menu.json b/public/language/nl/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/nl/admin/menu.json +++ b/public/language/nl/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/nl/admin/settings/notifications.json b/public/language/nl/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/nl/admin/settings/notifications.json +++ b/public/language/nl/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/nl/admin/settings/post.json b/public/language/nl/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/nl/admin/settings/post.json +++ b/public/language/nl/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/nl/admin/settings/user.json b/public/language/nl/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/nl/admin/settings/user.json +++ b/public/language/nl/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/nl/email.json b/public/language/nl/email.json index fe218e778a..48f35a2c6f 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Deze notificatie is verzonden vanwege de gebruikersinstellingen voor abonnementen.", "notif.post.cta": "Klik hier om het volledige bericht te lezen", "notif.post.unsub.info": "Deze notificatie is door ons verzonden vanwege gebruikersinstellingen voor abonnementen en berichten.", + "notif.cta": "Click here to go to forum", "test.text1": "Dit is een testbericht om te verifiëren dat NodeBB de e-mailberichtservice correct heeft opgezet.", "unsub.cta": "Klik hier om deze instellingen te wijzigen", "banned.subject": "U bent verbannen van %1", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 621adea52c..460254c097 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Je hebt onvoldoende reputatie om een negatieve stem uit te mogen brengen", "not-enough-reputation-to-flag": "Je hebt onvoldoende reputatie om dit bericht aan de beheerders te mogen melden", "already-flagged": "Je hebt deze post al gerapporteerd", + "self-vote": "You cannot vote on your own post", "reload-failed": "Tijdens het herladen van \"%1\" is NodeBB een fout of probleem tegengekomen. NodeBB blijft operationeel. Echter het is verstandig om de oorzaak te onderzoeken en wellicht de vorige actie, voor het herladen, ongedaan te maken.", "registration-error": "Fout tijdens registratie", "parse-error": "Tijdens het verwerken van het antwoord van de server is er iets misgegaan.", "wrong-login-type-email": "Gebruik je e-mailadres om in te loggen", "wrong-login-type-username": "Gebruik je gebruikersnaam om in te loggen", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Je heb het maximum aantal mensen uitgenodigd (%1 van de %2).", "no-session-found": "Geen login sessie gevonden!", "not-in-room": "Gebruiker niet in de chat", @@ -132,5 +134,6 @@ "no-users-selected": "Geen gebruiker(s) geselecteerd", "invalid-home-page-route": "Onbekende homepage route", "invalid-session": "Verkeerde sessie combinatie", - "invalid-session-text": "Het lijkt erop dat je login sessie niet meer actief is of niet langer synchroon is met de server. Ververs de pagina." + "invalid-session-text": "Het lijkt erop dat je login sessie niet meer actief is of niet langer synchroon is met de server. Ververs de pagina.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index 55e75afe74..c19dbaef83 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Door naar %1", "return_to": "Terug naar %1", "new_notification": "Nieuwe notificatie", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Je hebt nieuwe notificaties.", "all": "Alles", "topics": "Onderwerpen", @@ -45,5 +46,19 @@ "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.", - "email-confirm-sent": "Bevestigingsmail verstuurd." + "email-confirm-sent": "Bevestigingsmail verstuurd.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 4908453fee..b1d33fd9da 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Zeker weten dit onderwerp te herstellen?", "thread_tools.purge": "Wis onderwerp ", "thread_tools.purge_confirm": "Weet je zeker dat je dit onderwerp wil verwijderen?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Verplaatsen van onderwerp naar %1 succesvol", "post_delete_confirm": "Is het absoluut de bedoeling dit bericht te verwijderen?", "post_restore_confirm": "Is het de bedoeling dit bericht te herstellen?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 bericht(en) geselecteerd", "fork_success": "Onderwerp is succesvol afgesplitst. Klik hier om het nieuwe onderwerp te zien.", "delete_posts_instruction": "Klik op de berichten die verwijderd moeten worden", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Voer hier de titel van het onderwerp in...", "composer.handle_placeholder": "Naam", "composer.discard": "Annuleren", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index 3df4814190..6351ae8827 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -79,8 +79,6 @@ "digest_daily": "Dagelijks", "digest_weekly": "Wekelijks", "digest_monthly": "Maandelijks", - "send_chat_notifications": "Meld het mij per e-mail als iemand een chatbericht verstuurt wanneer ik niet online ben", - "send_post_notifications": "Meld het mij per e-mail wanneer er reacties volgen op onderwerpen waarop geabonneerd is", "settings-require-reload": "Sommige veranderingen vereisen het herladen van de pagina: klik hier om de pagina te herladen.", "has_no_follower": "Deze gebruiker heeft geen volgers :(", "follows_no_one": "Deze gebruiker volgt niemand :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Uitgaand bericht geluid", "notification-sound": "Notificatie geluid", "no-sound": "Geen geluid", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Instellingen voor bladeren", "open_links_in_new_tab": "Open uitgaande links naar een externe site in een nieuw tabblad", "enable_topic_searching": "Inschakelen mogelijkheid op onderwerp te kunnen zoeken", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Geassocieerd met", "sso.not-associated": "Klik hier om geassocieerd te worden met", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Laatste markeringen", "info.no-flags": "Geen gemarkeerde berichten gevonden", "info.ban-history": "Recente verban-geschiedenis", diff --git a/public/language/pl/admin/appearance/customise.json b/public/language/pl/admin/appearance/customise.json index a9f299498d..116fde835f 100644 --- a/public/language/pl/admin/appearance/customise.json +++ b/public/language/pl/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Wprowadź tu własne deklaracje CSS, będą one zastosowane po wszystkich innych stylach.", "custom-css.enable": "Włącz własne style CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Własny nagłówek", - "custom-header.description": "Wpisz tutaj kod HTML (JavaScript, tagi <meta>) który ma być dołączony do sekcji <head> w szablonie forum.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Włącz własny nagłówek", "custom-css.livereload": "Włącz dynamiczne przeładowanie", diff --git a/public/language/pl/admin/general/homepage.json b/public/language/pl/admin/general/homepage.json index 8f5360c47b..c80a434fa4 100644 --- a/public/language/pl/admin/general/homepage.json +++ b/public/language/pl/admin/general/homepage.json @@ -1,7 +1,7 @@ { - "home-page": "Strona startowa", + "home-page": "Strona Główna", "description": "Wybierz stronę startową dla twojego forum.", - "home-page-route": "Ścieżka strony startowej", - "custom-route": "Niestandardowy Adres", + "home-page-route": "Ścieżka strony głównej", + "custom-route": "Niestandardowa Ścieżka", "allow-user-home-pages": "Zezwalaj na strony startowe użytkowników" } \ No newline at end of file diff --git a/public/language/pl/admin/menu.json b/public/language/pl/admin/menu.json index e5830c32ce..dd9a0a33bf 100644 --- a/public/language/pl/admin/menu.json +++ b/public/language/pl/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Wygląd", "appearance/themes": "Motywy", "appearance/skins": "Skórki", - "appearance/customise": "Niestandardowy HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Rozszerzenia", "extend/plugins": "Wtyczki", diff --git a/public/language/pl/admin/settings/notifications.json b/public/language/pl/admin/settings/notifications.json index 9f00578b0f..9396577d28 100644 --- a/public/language/pl/admin/settings/notifications.json +++ b/public/language/pl/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Powiadomienia", "welcome-notification": "Powiadomienie na przywitanie", - "welcome-notification-link": "Odnośnik powiadomienia powitalnego" + "welcome-notification-link": "Odnośnik powiadomienia powitalnego", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/pl/admin/settings/post.json b/public/language/pl/admin/settings/post.json index 26279641c9..41a53c1882 100644 --- a/public/language/pl/admin/settings/post.json +++ b/public/language/pl/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Najstarsze do najnowszych", "sorting.newest-to-oldest": "Najnowsze do najstarszych", "sorting.most-votes": "Najwięcej głosów", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Domyślne sortowanie tematów", "restrictions": "Ograniczenia pisania", "restrictions.post-queue": "Włącz kolejkę postów", diff --git a/public/language/pl/admin/settings/user.json b/public/language/pl/admin/settings/user.json index 84b6a42ab8..d1c5e7f713 100644 --- a/public/language/pl/admin/settings/user.json +++ b/public/language/pl/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Motywy", "disable-user-skins": "Nie zezwalaj użytkownikom na wybranie niestandardowej skórki", "account-protection": "Ochrona konta", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Maksymalna liczba prób logowania na godzinę", "login-attempts-help": "Jeśli liczba prób logowania na konto użytkownika przekroczy ten próg, to konto zostanie zablokowane na zdefiniowany wcześniej czas", "lockout-duration": "Czas trwania blokady konta (minuty)", diff --git a/public/language/pl/email.json b/public/language/pl/email.json index b01b748ed6..fd0b9b8125 100644 --- a/public/language/pl/email.json +++ b/public/language/pl/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "To powiadomienie o czacie zostało Ci wysłane zgodnie z ustawieniami twojego konta.", "notif.post.cta": "Kliknij tutaj, aby przeczytać cały temat.", "notif.post.unsub.info": "To powiadomienie o poście zostało Ci wysłane zgodnie z ustawieniami twojego konta.", + "notif.cta": "Click here to go to forum", "test.text1": "To jest e-mail testowy, aby sprawdzić, czy poprawnie skonfigurowałeś e-mailer w swoim NodeBB.", "unsub.cta": "Kliknij tutaj, aby zmienić te ustawienia", "banned.subject": "Zostałeś zbanowany na %1", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 644b83c6b0..4be7c3d177 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Masz za mało reputacji, aby negatywnie ocenić ten post", "not-enough-reputation-to-flag": "Nie masz dość reputacji, by flagować ten post", "already-flagged": "Ten post jest już przez Ciebie oznaczony", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB napotkało problem w czasie przeładowywania \"%1\". Forum będzie nadal dostarczać istniejące zasoby strony klienta, jednak powinieneś cofnąć ostatnią akcję.", "registration-error": "Błąd rejestracji", "parse-error": "Coś poszło nie tak podczas przetwarzania odpowiedzi serwera", "wrong-login-type-email": "Zaloguj się, używając adresu email", "wrong-login-type-username": "Zaloguj się używając nazwy użytkownika", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Zaprosiłeś maksymalną liczba osób (%1 z %2).", "no-session-found": "Nie znaleziono sesji logowania", "not-in-room": "Użytkownik nie jest w pokoju", @@ -132,5 +134,6 @@ "no-users-selected": "Nie wybrano żadnych użytkowników", "invalid-home-page-route": "Niepoprawny odnośnik strony domowej", "invalid-session": "Niewłaściwa sesja", - "invalid-session-text": "Wygląda na to, że twoja sesja jest nieaktywna lub nie zgadza się z serwerem. Proszę odświeżyć tę stronę." + "invalid-session-text": "Wygląda na to, że twoja sesja jest nieaktywna lub nie zgadza się z serwerem. Proszę odświeżyć tę stronę.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json index 594ad62bb4..c29984664d 100644 --- a/public/language/pl/notifications.json +++ b/public/language/pl/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Kontynuuj do %1", "return_to": "Wróć do %1", "new_notification": "Nowe powiadomienie", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Masz nieprzeczytane powiadomienia.", "all": "Wszystko", "topics": "Tematy", @@ -45,5 +46,19 @@ "email-confirmed": "E-mail potwierdzony", "email-confirmed-message": "Dziękujemy za potwierdzenie maila. Twoje konto zostało aktywowane.", "email-confirm-error-message": "Wystąpił problem przy aktywacji - kod jest błędny lub przestarzały", - "email-confirm-sent": "E-mail potwierdzający wysłany." + "email-confirm-sent": "E-mail potwierdzający wysłany.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/pl/topic.json b/public/language/pl/topic.json index fb2fa3e93c..e3fd7d49fe 100644 --- a/public/language/pl/topic.json +++ b/public/language/pl/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Na pewno chcesz przywrócić ten temat?", "thread_tools.purge": "Wymaż temat", "thread_tools.purge_confirm": "Na pewno chcesz wymazać ten temat?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Temat przeniesiono do %1", "post_delete_confirm": "Na pewno chcesz usunąć ten post?", "post_restore_confirm": "Na pewno chcesz przywrócić ten post?", @@ -89,6 +91,7 @@ "fork_pid_count": "wybrano %1 post(-ów)", "fork_success": "Udało się skopiować temat. Kliknij tutaj, aby do niego przejść.", "delete_posts_instruction": "Kliknij na posty, które chcesz usunąć", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Wpisz tutaj tytuł tematu...", "composer.handle_placeholder": "Nazwa", "composer.discard": "Odrzuć", diff --git a/public/language/pl/user.json b/public/language/pl/user.json index 831e94cc04..6ad02f18e7 100644 --- a/public/language/pl/user.json +++ b/public/language/pl/user.json @@ -79,8 +79,6 @@ "digest_daily": "Codziennie", "digest_weekly": "Co tydzień", "digest_monthly": "Co miesiąc", - "send_chat_notifications": "Wyślij e-maila, jeśli dostanę nową wiadomość, a nie jestem on-line", - "send_post_notifications": "Wyślij email, kiedy w tematach, które subskrybuję, pojawią się odpowiedzi", "settings-require-reload": "Niektóre zmiany ustawień wymagają przeładowania. Kliknij tutaj, aby przeładować stronę.", "has_no_follower": "Ten użytkownik nie ma jeszcze żadnych śledzących", "follows_no_one": "Użytkownik jeszcze nikogo nie śledzi.", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Dźwięk wychodzącej wiadomości", "notification-sound": "Dźwięk powiadomienia", "no-sound": "Bez dźwięku", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Ustawienia szukania", "open_links_in_new_tab": "Otwieraj odnośniki wychodzące w nowej karcie", "enable_topic_searching": "Włącz szukanie w temacie", @@ -123,6 +126,9 @@ "sso.title": "Usługi Pojedynczego Logowania", "sso.associated": "Powiązane z", "sso.not-associated": "Kliknij tutaj, aby powiązać z", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Ostatnie flagi", "info.no-flags": "Brak oflagowanych postów", "info.ban-history": "Historia ostatnich banów", diff --git a/public/language/pt-BR/admin/appearance/customise.json b/public/language/pt-BR/admin/appearance/customise.json index b03e02e9f3..df52770144 100644 --- a/public/language/pt-BR/admin/appearance/customise.json +++ b/public/language/pt-BR/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Entre com as suas próprias declarações de CSS aqui, as quais serão aplicadas após todos os outros estilos.", "custom-css.enable": "Habilitar CSS Personalizado", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Cabeçalho Personalizado", - "custom-header.description": "Adicione HTML pessoal aqui (ex. JavaScript, Meta Tags, Tags, etc), os quais serão acrescentados ao final da seção <head> do markup do seu fórum.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Ligar o Cabeçalho Personalizado", "custom-css.livereload": "Habilitar Recarregamento Automático", diff --git a/public/language/pt-BR/admin/menu.json b/public/language/pt-BR/admin/menu.json index 81972b21d6..fe4800c8f5 100644 --- a/public/language/pt-BR/admin/menu.json +++ b/public/language/pt-BR/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Aparência", "appearance/themes": "Temas", "appearance/skins": "Skins", - "appearance/customise": "HTML & CSS Personalizados", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extenda", "extend/plugins": "Plugins", diff --git a/public/language/pt-BR/admin/settings/notifications.json b/public/language/pt-BR/admin/settings/notifications.json index 7366f6c350..9f2a9a9fac 100644 --- a/public/language/pt-BR/admin/settings/notifications.json +++ b/public/language/pt-BR/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notificações", "welcome-notification": "Notificação de Boas-vindas", - "welcome-notification-link": "Link da Notificação de Boas-vindas" + "welcome-notification-link": "Link da Notificação de Boas-vindas", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/settings/post.json b/public/language/pt-BR/admin/settings/post.json index 550e2fce12..eb0db578ba 100644 --- a/public/language/pt-BR/admin/settings/post.json +++ b/public/language/pt-BR/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Da Mais Antigo para Mais Recente", "sorting.newest-to-oldest": "Mais recente para mais Antigo", "sorting.most-votes": "Mais Votos", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Ordenação Padrão de Tópicos", "restrictions": "Restições de Postagem", "restrictions.post-queue": "Ligar enfileiramento de posts", diff --git a/public/language/pt-BR/admin/settings/user.json b/public/language/pt-BR/admin/settings/user.json index bb4d776376..c695659f1b 100644 --- a/public/language/pt-BR/admin/settings/user.json +++ b/public/language/pt-BR/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Temas", "disable-user-skins": "Impedir usuários de escolherem um skin personalizado", "account-protection": "Proteção de Conta", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Tentativas de login por hora", "login-attempts-help": "Se tentativas de login na conta de um usuário ultrapassar este limite, aquela conta será trancada por um período de tempo pré-configurado", "lockout-duration": "Duração de Trancamento de Conta (minutos)", diff --git a/public/language/pt-BR/email.json b/public/language/pt-BR/email.json index b70c27d5c2..a2e2128d03 100644 --- a/public/language/pt-BR/email.json +++ b/public/language/pt-BR/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Esta notificação de chat foi enviada a você devido às suas configurações de assinatura.", "notif.post.cta": "Clique aqui para ler o tópico completo", "notif.post.unsub.info": "Esta notificação de postagem foi enviada para você devido as suas configurações de assinatura.", + "notif.cta": "Click here to go to forum", "test.text1": "Este é um e-mail de teste, para verificar que o enviador de emails está corretamente configurado no seu NodeBB.", "unsub.cta": "Clique aqui para alterar estas configurações", "banned.subject": "Você foi banido de %1", diff --git a/public/language/pt-BR/error.json b/public/language/pt-BR/error.json index 8a69b5cd5f..982acd0441 100644 --- a/public/language/pt-BR/error.json +++ b/public/language/pt-BR/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Você não possui reputação suficiente para negativar este post", "not-enough-reputation-to-flag": "Você não possui reputação suficiente para sinalizar este post", "already-flagged": "Você já sinalizou esse post", + "self-vote": "You cannot vote on your own post", "reload-failed": "O NodeBB encontrou um problema ao recarregar: \"%1\". O NodeBB continuará a servir os assets existentes no lado do cliente, apesar de que você deve desfazer o que você fez antes de recarregar.", "registration-error": "Erro de Cadastro", "parse-error": "Algo deu errado ao receber a resposta do servidor", "wrong-login-type-email": "Por favor use seu email para fazer login", "wrong-login-type-username": "Por favor use o seu nome de usuário para fazer login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Você já convidou o número máximo de pessoas (%1 de %2).", "no-session-found": "Nenhuma sessão de login encontrada!", "not-in-room": "O usuário não está na sala", @@ -132,5 +134,6 @@ "no-users-selected": "Nenhuma escolha de usuário(s) foi feita", "invalid-home-page-route": "Rota de página inicial inválida", "invalid-session": "Erro de Sessão", - "invalid-session-text": "Parece que sua sessão de login não está mais ativa, ou não combina mais com a do servidor. Por gentileza, recarregue esta página." + "invalid-session-text": "Parece que sua sessão de login não está mais ativa, ou não combina mais com a do servidor. Por gentileza, recarregue esta página.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/pt-BR/notifications.json b/public/language/pt-BR/notifications.json index 555c8639aa..0eb34b27e5 100644 --- a/public/language/pt-BR/notifications.json +++ b/public/language/pt-BR/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuar para %1", "return_to": "Voltar para %1", "new_notification": "Nova Notificação", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Você possui notificações não lidas.", "all": "Tudo", "topics": "Tópicos", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confirmado", "email-confirmed-message": "Obrigado por validar o seu email. Agora sua conta está plenamente ativada.", "email-confirm-error-message": "Houve um problema ao validar o seu endereço de email. Talvez o código era invalido ou tenha expirado.", - "email-confirm-sent": "Email de confirmação enviado." + "email-confirm-sent": "Email de confirmação enviado.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/pt-BR/topic.json b/public/language/pt-BR/topic.json index 6ae93feb95..def9099360 100644 --- a/public/language/pt-BR/topic.json +++ b/public/language/pt-BR/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Tem certeza que deseja restaurar este tópico?", "thread_tools.purge": "Expurgar Tópico", "thread_tools.purge_confirm": "Tem certeza que deseja expurgar este tópico? ", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Tópico movido com sucesso para %1", "post_delete_confirm": "Tem certeza que deseja deletar este post?", "post_restore_confirm": "Tem certeza que deseja restaurar este post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selecionado(s)", "fork_success": "Tópico ramificado com sucesso! Clique aqui para ir ao tópico ramificado.", "delete_posts_instruction": "Clique nos posts que você deseja deletar/limpar", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Digite aqui o título para o seu tópico...", "composer.handle_placeholder": "Nome", "composer.discard": "Descartar", diff --git a/public/language/pt-BR/user.json b/public/language/pt-BR/user.json index 344e578fce..3a5ff85a58 100644 --- a/public/language/pt-BR/user.json +++ b/public/language/pt-BR/user.json @@ -79,8 +79,6 @@ "digest_daily": "Diariamente", "digest_weekly": "Semanalmente", "digest_monthly": "Mensalmente", - "send_chat_notifications": "Enviar-me um email se uma nova mensagem de chat chegar quando eu não estiver online.", - "send_post_notifications": "Enviar um email quando respostas forem dadas à tópicos que eu assino", "settings-require-reload": "Algumas mudanças de configuração exigem que recarregue. Clique aqui para recarregar a página.", "has_no_follower": "Este usuário não possui seguidores :(", "follows_no_one": "Este usuário não está seguindo ninguém :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Som de envio de mensagem", "notification-sound": "Som de notificação", "no-sound": "Sem som", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Configurações de Navegação", "open_links_in_new_tab": "Abrir links externos em nova aba", "enable_topic_searching": "Habilitar Pesquisa dentro de Tópico", @@ -123,6 +126,9 @@ "sso.title": "Logar por outros Serviços", "sso.associated": "Associado com", "sso.not-associated": "Clique aqui para associar com", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Últimas Sinalizações", "info.no-flags": "Nenhum Post Sinalizado Encontrado", "info.ban-history": "Histórico de Banimentos Recentes", diff --git a/public/language/pt-PT/admin/appearance/customise.json b/public/language/pt-PT/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/pt-PT/admin/appearance/customise.json +++ b/public/language/pt-PT/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/pt-PT/admin/menu.json b/public/language/pt-PT/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/pt-PT/admin/menu.json +++ b/public/language/pt-PT/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/pt-PT/admin/settings/notifications.json b/public/language/pt-PT/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/pt-PT/admin/settings/notifications.json +++ b/public/language/pt-PT/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/settings/post.json b/public/language/pt-PT/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/pt-PT/admin/settings/post.json +++ b/public/language/pt-PT/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/pt-PT/admin/settings/user.json b/public/language/pt-PT/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/pt-PT/admin/settings/user.json +++ b/public/language/pt-PT/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/pt-PT/email.json b/public/language/pt-PT/email.json index deddc31cb2..c4fe9fe43e 100644 --- a/public/language/pt-PT/email.json +++ b/public/language/pt-PT/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Esta notificação de chat foi enviada devido às suas definições de subscrição", "notif.post.cta": "Clique aqui para ler o tópico completo", "notif.post.unsub.info": "Esta notificação foi envidada devido às tuas definições de subscrição.", + "notif.cta": "Click here to go to forum", "test.text1": "Este é um e-mail de teste para verificar que o emailer está configurado corretamente para o teu NodeBB.", "unsub.cta": "Clica aqui para alterares essas definições", "banned.subject": "You have been banned from %1", diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index f61987ca2c..d0f7fff518 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Não tens reputação suficiente para atribuir um voto negativo a esta publicação", "not-enough-reputation-to-flag": "Não tens reputação suficiente para sinalizar esta publicação", "already-flagged": "Já sinalizaste esta publicação", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encontrou um erro enquanto recarregava: \"%1\". NodeBB irá continuar a servir os ativos existentes do lado do utilizador. No entanto deverias desfazer o que fizeste mesmo antes de teres voltado a recarregar.", "registration-error": "Erro de registro", "parse-error": "Ocorreu um erro enquanto analisávamos a resposta do servidor", "wrong-login-type-email": "Por favor utiliza o teu e-mail para efetuares o login", "wrong-login-type-username": "Por favor utiliza o teu nome de utilizador para efetuares o login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Convidaste o máximo de pessoas (%1 em %2).", "no-session-found": "Não encontramos sessões de login!", "not-in-room": "Utilizador não se encontra na sala", @@ -132,5 +134,6 @@ "no-users-selected": "Não existe(m) utilizador(es) selecionado(s)", "invalid-home-page-route": "Rota para a página principal inválida", "invalid-session": "Sessão incompatível", - "invalid-session-text": "Parece que a sua sessão de login não se encontra mais ativa ou não tem correspondência com o servidor. por favor recarregue esta página." + "invalid-session-text": "Parece que a sua sessão de login não se encontra mais ativa ou não tem correspondência com o servidor. por favor recarregue esta página.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/pt-PT/notifications.json b/public/language/pt-PT/notifications.json index a10b22ccbb..fb63eb9a7a 100644 --- a/public/language/pt-PT/notifications.json +++ b/public/language/pt-PT/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuar para %1", "return_to": "Voltar a %1", "new_notification": "Nova notificação", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Tens notificações por ler.", "all": "Tudo", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "E-mail confirmado", "email-confirmed-message": "Obrigado por validares o teu endereço de e-mai.. A tua conta está agora totalmente ativa.", "email-confirm-error-message": "Ocorreu um problema a validar o teu endereço de e-mail. Talvez o código fosse inválido ou tenha expirado.", - "email-confirm-sent": "E-mail de confirmação enviado." + "email-confirm-sent": "E-mail de confirmação enviado.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/pt-PT/topic.json b/public/language/pt-PT/topic.json index 9647b731c5..fb2ea14eee 100644 --- a/public/language/pt-PT/topic.json +++ b/public/language/pt-PT/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Tens a certeza que pretendes restaurar este tópico?", "thread_tools.purge": "Purgar tópico", "thread_tools.purge_confirm": "Tens a certeza que desejas continuar com a purgação deste tópico?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Este tópico foi movido com sucesso para %1", "post_delete_confirm": "Tens a certeza que desejas eliminar esta publicação?", "post_restore_confirm": "Tens a certeza que desejas restaurar esta publicação?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 publicação(ões) selecionada(s)", "fork_success": "Clonaste um tópico com sucesso! Carrega aqui para ires para o tópico clonado.", "delete_posts_instruction": "Carrega em publicações que queres apagar/purgar", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Insere aqui o título do tópico...", "composer.handle_placeholder": "Nome", "composer.discard": "Descartar", diff --git a/public/language/pt-PT/user.json b/public/language/pt-PT/user.json index 1f03ab13ca..2c21950e37 100644 --- a/public/language/pt-PT/user.json +++ b/public/language/pt-PT/user.json @@ -79,8 +79,6 @@ "digest_daily": "Diariamente ", "digest_weekly": "Semanalmente", "digest_monthly": "Mensalmente", - "send_chat_notifications": "Enviar um e-mail se receber uma nova mensagem e não estiver online", - "send_post_notifications": "Enviar um -email quando respostas forem dadas a tópicos que subscrevi", "settings-require-reload": "Algumas alterações requerem um recarregamento. Carregue aqui para recarregar a página.", "has_no_follower": "Este utilizador não tem nenhum seguidor :(", "follows_no_one": "Este utilizador não está a seguir ninguém :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Som de mensagem enviada", "notification-sound": "Som de notificação", "no-sound": "Sem som", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Definições de navegação", "open_links_in_new_tab": "Abrir links num novo separador", "enable_topic_searching": "Permitir pesquisa dentro dos tópicos", @@ -123,6 +126,9 @@ "sso.title": "Serviços de login único", "sso.associated": "Associado a", "sso.not-associated": "Carrega aqui para associares com", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Últimas sinalizações", "info.no-flags": "Não foram encontrados publicações sinalizadas", "info.ban-history": "Histórico de expulsões recentes", diff --git a/public/language/ro/admin/appearance/customise.json b/public/language/ro/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/ro/admin/appearance/customise.json +++ b/public/language/ro/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/ro/admin/menu.json b/public/language/ro/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/ro/admin/menu.json +++ b/public/language/ro/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/ro/admin/settings/notifications.json b/public/language/ro/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/ro/admin/settings/notifications.json +++ b/public/language/ro/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ro/admin/settings/post.json b/public/language/ro/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/ro/admin/settings/post.json +++ b/public/language/ro/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/ro/admin/settings/user.json b/public/language/ro/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/ro/admin/settings/user.json +++ b/public/language/ro/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/ro/email.json b/public/language/ro/email.json index 1fa8e4f2a8..4be51619f6 100644 --- a/public/language/ro/email.json +++ b/public/language/ro/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "Acesta este un email de test pentru a verica dacă mailul este setat corect pentru NodeBB-ul tău.", "unsub.cta": "Apasă aici pentru a modifica acele setări", "banned.subject": "You have been banned from %1", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index beb63b29a6..8b57f80498 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nu ai destulă reputație pentru a vota negativ acest post.", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB a întâmpinat o problemă la reîncarcare: \"%1\". NodeBB va continua să servească fișierele existente pentru partea-client, dar tu va trebuie să refaci modificările pe care le-ai facut înainte de reîncarcare.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json index 00ed32f237..7945f3ce74 100644 --- a/public/language/ro/notifications.json +++ b/public/language/ro/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continuă la %1", "return_to": "Întoarce-te la %1", "new_notification": "Notificare Nouă", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Ai notificări necitite.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email confirmat", "email-confirmed-message": "Îți mulțumim pentru validarea emailului. Contul tău este acuma activat.", "email-confirm-error-message": "A fost o problemă cu activarea adresei tale de email. Poate codul de activare a fost invalid sau expirat.", - "email-confirm-sent": "Un email de confirmare a fost trimis." + "email-confirm-sent": "Un email de confirmare a fost trimis.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ro/topic.json b/public/language/ro/topic.json index 36ed0ffb0f..fe89ee4244 100644 --- a/public/language/ro/topic.json +++ b/public/language/ro/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Esti sigur că vrei să restaurezi acest subiect?", "thread_tools.purge": "Curăță Subiect", "thread_tools.purge_confirm": "Ești sigur că vrei sa cureți acest subiect?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Acest mesaj a fost mutat cu succes în %1", "post_delete_confirm": "Ești sigur că vrei să ștergi acest mesaj?", "post_restore_confirm": "Esti sigur că vrei să restaurezi acest mesaj?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Introdu numele subiectului aici ...", "composer.handle_placeholder": "Name", "composer.discard": "Renunță", diff --git a/public/language/ro/user.json b/public/language/ro/user.json index c9415ea2a8..1a0d1d47e1 100644 --- a/public/language/ro/user.json +++ b/public/language/ro/user.json @@ -79,8 +79,6 @@ "digest_daily": "Zilnic", "digest_weekly": "Săptămânal", "digest_monthly": "Lunar", - "send_chat_notifications": "Trimite-mi un email dacă primesc un mesaj în chat si eu nu sunt online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Pe acest utilizator nu îl urmărește nimeni :(", "follows_no_one": "Acest utilizator nu urmărește pe nimeni :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Setări navigare", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Enable In-Topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/ru/admin/advanced/cache.json b/public/language/ru/admin/advanced/cache.json index 70e88bd261..b882409255 100644 --- a/public/language/ru/admin/advanced/cache.json +++ b/public/language/ru/admin/advanced/cache.json @@ -3,9 +3,9 @@ "posts-in-cache": "Закешировано сообщений", "average-post-size": "Средний размер сообщения", "length-to-max": "Размер / Максимум", - "percent-full": "%1% Full", + "percent-full": "Заполнен на%1%", "post-cache-size": "Размер кэша сообщений", - "items-in-cache": "Items in Cache", + "items-in-cache": "Элементы в Кэш", "control-panel": "Панель управления", "update-settings": "Обновить настройки кэша" } \ No newline at end of file diff --git a/public/language/ru/admin/advanced/database.json b/public/language/ru/admin/advanced/database.json index 50e8aae0aa..9687a6b8e9 100644 --- a/public/language/ru/admin/advanced/database.json +++ b/public/language/ru/admin/advanced/database.json @@ -1,36 +1,36 @@ { "x-b": "%1 байт", - "x-mb": "%1 мегабайт", - "x-gb": "%1 gb", + "x-mb": "%1 Мб", + "x-gb": "%1 Гб", "uptime-seconds": "Время работы в секундах", "uptime-days": "Время работы в днях", "mongo": "Mongo", "mongo.version": "Версия MongoDB", - "mongo.storage-engine": "Storage Engine", + "mongo.storage-engine": "Система хранения", "mongo.collections": "Коллекции", "mongo.objects": "Документы", "mongo.avg-object-size": "Средний размер документа", "mongo.data-size": "Размер данных", "mongo.storage-size": "Размер хранилища", - "mongo.index-size": "Index Size", + "mongo.index-size": "Размер Индекса", "mongo.file-size": "Размер файла", - "mongo.resident-memory": "Resident Memory", + "mongo.resident-memory": "Долгосрочная память", "mongo.virtual-memory": "Виртуальная память", - "mongo.mapped-memory": "Mapped Memory", + "mongo.mapped-memory": "Расширенная память", "mongo.raw-info": "Сырые данные о MongoDB", "redis": "Redis", "redis.version": "Версия Redis", "redis.connected-clients": "Подключенные клиенты", - "redis.connected-slaves": "Connected Slaves", + "redis.connected-slaves": "Подключенные устройства", "redis.blocked-clients": "Заблокированные клиенты", "redis.used-memory": "Используемая Память", - "redis.memory-frag-ratio": "Memory Fragmentation Ratio", + "redis.memory-frag-ratio": "Коэффициент фрагментации памяти", "redis.total-connections-recieved": "Общее число подключений получено", "redis.total-commands-processed": "Команд обработано в общем", - "redis.iops": "Instantaneous Ops. Per Second", - "redis.keyspace-hits": "Keyspace Hits", - "redis.keyspace-misses": "Keyspace Misses", - "redis.raw-info": "Redis Raw Info" + "redis.iops": "Мгновенные операции. в секунду", + "redis.keyspace-hits": "Количество ключевых просмотров", + "redis.keyspace-misses": "Количество не ключевых просмотров", + "redis.raw-info": "Redis необработанная информация" } \ No newline at end of file diff --git a/public/language/ru/admin/advanced/errors.json b/public/language/ru/admin/advanced/errors.json index b3185f3cdb..5134a7408a 100644 --- a/public/language/ru/admin/advanced/errors.json +++ b/public/language/ru/admin/advanced/errors.json @@ -4,8 +4,8 @@ "error.404": "404 Не найдено", "error.503": "503 Сервис недоступен", "manage-error-log": "Управление журналами ошибок", - "export-error-log": "Export Error Log (CSV)", - "clear-error-log": "Clear Error Log", + "export-error-log": "Экспорт логи ошибок (CSV)", + "clear-error-log": "Очистить логи ошибок", "route": "Путь", "count": "Кол-во", "no-routes-not-found": "Ура! Ошибок 404 нет!", diff --git a/public/language/ru/admin/advanced/logs.json b/public/language/ru/admin/advanced/logs.json index 5b91d16f4a..971dec1cf5 100644 --- a/public/language/ru/admin/advanced/logs.json +++ b/public/language/ru/admin/advanced/logs.json @@ -1,7 +1,7 @@ { "logs": "Логи", - "control-panel": "Logs Control Panel", - "reload": "Reload Logs", - "clear": "Clear Logs", - "clear-success": "Logs Cleared!" + "control-panel": "Логирование контрольной панели", + "reload": "Перезагрузить Логи", + "clear": "Очистить Логи", + "clear-success": "Логи очищены!" } \ No newline at end of file diff --git a/public/language/ru/admin/appearance/customise.json b/public/language/ru/admin/appearance/customise.json index dfed0bf11c..4ae01c2012 100644 --- a/public/language/ru/admin/appearance/customise.json +++ b/public/language/ru/admin/appearance/customise.json @@ -1,12 +1,16 @@ { "custom-css": "Свой CSS", - "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS", + "custom-css.description": "Введите свои собственные данные CSS здесь, которые будут применяться после всех других стилей.", + "custom-css.enable": "Включить пользовательский CSS", - "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", - "custom-header.enable": "Enable Custom Header", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", - "custom-css.livereload": "Enable Live Reload", - "custom-css.livereload.description": "Enable this to force all sessions on every device under your account to refresh whenever you click save" + "custom-header": "Пользовательский Заголовок", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", + "custom-header.enable": "Включить Пользовательский заголовок", + + "custom-css.livereload": "Включить автоматическую перезагрузку страниц", + "custom-css.livereload.description": "Включите эту опцию, чтобы принудительно обновлять все сеансы на каждом устройстве под этой учетной записью при каждом нажатии кнопки Сохранить" } \ No newline at end of file diff --git a/public/language/ru/admin/manage/registration.json b/public/language/ru/admin/manage/registration.json index f51b4d56e6..feb44fc50a 100644 --- a/public/language/ru/admin/manage/registration.json +++ b/public/language/ru/admin/manage/registration.json @@ -11,7 +11,7 @@ "list.ip-spam": "Frequency: %1 Appears: %2", "invitations": "Invitations", - "invitations.description": "Below is a complete list of invitations sent. Use ctrl-f to search through the list by email or username.

The username will be displayed to the right of the emails for users who have redeemed their invitations.", + "invitations.description": "Ниже приведен полный список отправленных приглашений. Для поиска по списку по электронной почте или имени пользователя используйте сочетание клавиш CTRL+F . < br > < br > Имена пользователей, которые приняли приглашение, будут отображаться справа от электронной почты.", "invitations.inviter-username": "Inviter Username", "invitations.invitee-email": "Invitee Email", "invitations.invitee-username": "Invitee Username (if registered)", diff --git a/public/language/ru/admin/menu.json b/public/language/ru/admin/menu.json index 200bdaa3b7..0178029256 100644 --- a/public/language/ru/admin/menu.json +++ b/public/language/ru/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Вид", "appearance/themes": "Темы", "appearance/skins": "Скины", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Расширения", "extend/plugins": "Плагины", diff --git a/public/language/ru/admin/settings/cookies.json b/public/language/ru/admin/settings/cookies.json index f8b0f0538b..d4954c13c3 100644 --- a/public/language/ru/admin/settings/cookies.json +++ b/public/language/ru/admin/settings/cookies.json @@ -1,5 +1,5 @@ { - "eu-consent": "EU Consent", + "eu-consent": "Соглашение", "consent.enabled": "Enabled", "consent.message": "Notification message", "consent.acceptance": "Acceptance message", diff --git a/public/language/ru/admin/settings/notifications.json b/public/language/ru/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/ru/admin/settings/notifications.json +++ b/public/language/ru/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/ru/admin/settings/post.json b/public/language/ru/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/ru/admin/settings/post.json +++ b/public/language/ru/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/ru/admin/settings/user.json b/public/language/ru/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/ru/admin/settings/user.json +++ b/public/language/ru/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/ru/email.json b/public/language/ru/email.json index d791e5a61f..dc9b87f26a 100644 --- a/public/language/ru/email.json +++ b/public/language/ru/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Вы получили это уведомление в соответствии с настройками своей подписки на новости сайта.", "notif.post.cta": "Нажмите для просмотра всей темы.", "notif.post.unsub.info": "Вы получили это уведомление согласно вашим настройкам подписки.", + "notif.cta": "Click here to go to forum", "test.text1": "Это тестовое сообщение для проверки почтового сервиса.", "unsub.cta": "Изменить настройки", "banned.subject": "You have been banned from %1", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index f8f2c2d9e7..42b8edb9e9 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "У вас недостаточно репутации для понижения оценки сообщения", "not-enough-reputation-to-flag": "У Вас недостаточно репутации, чтобы пометить это сообщение.", "already-flagged": "Вы уже отметили это сообщение", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB обнаружил проблему при перезагрузке: \"%1\". NodeBB продолжит работать с существующими ресурсами клиента, но вы должны отменить то, что сделали перед перезагрузкой.", "registration-error": "Ошибка при регистрации", "parse-error": "Похоже, что-то пошло не так в процессе обработки ответа сервера.", "wrong-login-type-email": "Пожалуйста, для входа используйте адрес своей электронной почты.", "wrong-login-type-username": "Пожалуйста, для входа используйте имя пользователя.", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Вы пригласили %1 людей из %2 возможных.", "no-session-found": "Сессия входа не найдена!", "not-in-room": "Пользователь отсутствует в этой комнате", @@ -132,5 +134,6 @@ "no-users-selected": "Выберите одного или нескольких пользователей", "invalid-home-page-route": "Неверная ссылка на домашнюю страницу", "invalid-session": "Сессия не существует", - "invalid-session-text": "Похоже, что ваша сессия больше не активна или она не совпадает с сессией на сервере. Пожалуйста, обновите эту страницу." + "invalid-session-text": "Похоже, что ваша сессия больше не активна или она не совпадает с сессией на сервере. Пожалуйста, обновите эту страницу.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/ru/flags.json b/public/language/ru/flags.json index ad87949c79..4f105ca1d3 100644 --- a/public/language/ru/flags.json +++ b/public/language/ru/flags.json @@ -17,7 +17,7 @@ "filter-targetUid": "Flagged UID", "filter-type": "Flag Type", "filter-type-all": "Весь контент", - "filter-type-post": "Post", + "filter-type-post": "Написать", "filter-state": "State", "filter-assignee": "Assignee UID", "filter-cid": "Категория", diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json index 828bab978f..a4c9b74119 100644 --- a/public/language/ru/notifications.json +++ b/public/language/ru/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Перейти на %1", "return_to": "Вернуться к %1", "new_notification": "Новое уведомление", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "У вас есть непрочитанные уведомления.", "all": "Все", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Электронная почта подтверждена", "email-confirmed-message": "Спасибо за подтверждение адреса электронной почты. Ваша учётная запись активирована. Добро пожаловать на наш сайт!", "email-confirm-error-message": "Ошибка проверки адреса электронной почты. Возможно, введён неправильно код подтверждения, либо у него истёк срок действия.", - "email-confirm-sent": "Письмо с проверочным кодом отправлено на ваш электронный адрес" + "email-confirm-sent": "Письмо с проверочным кодом отправлено на ваш электронный адрес", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index ba4e4fcec0..84aa1fa724 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Вы уверены, что хотите восстановить тему?", "thread_tools.purge": "Стереть тему", "thread_tools.purge_confirm": "Вы уверены, что хотите стереть эту тему?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Эта тема успешно перемещена в %1", "post_delete_confirm": "Вы уверены, что хотите удалить эту запись?", "post_restore_confirm": "Вы уверены, что хотите восстановить эту запись?", @@ -89,6 +91,7 @@ "fork_pid_count": "Отмечено %1 сообщений", "fork_success": "Готово! Просмотр отделённой темы.", "delete_posts_instruction": "Отметьте записи, которые вы хотите удалить", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Введите название темы...", "composer.handle_placeholder": "Название", "composer.discard": "Отменить", diff --git a/public/language/ru/user.json b/public/language/ru/user.json index 4d311a0b85..242763bade 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -79,8 +79,6 @@ "digest_daily": "За день", "digest_weekly": "За неделю", "digest_monthly": "За месяц", - "send_chat_notifications": "Отправлять уведомления по электронной почте при поступлении нового сообщения чата", - "send_post_notifications": "Отправлять уведомления по электронной почте при появлении новых ответов в подписанных темах", "settings-require-reload": "Для отображения изменений необходимо обновить страницу. Нажмите здесь, чтобы продолжить.", "has_no_follower": "На этого участника никто не подписан", "follows_no_one": "Этот участник ни на кого не подписан", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Звук исходящего сообщения", "notification-sound": "Звук уведомления", "no-sound": "Без звука", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Настройки просмотра", "open_links_in_new_tab": "Открывать внешние ссылки в новом окне", "enable_topic_searching": "Поиск во всех записях темы", @@ -123,6 +126,9 @@ "sso.title": "Для вашего удобства вы можете связать ваши учётные записи на других социальных сервисах с учётной записью на нашем сайте", "sso.associated": "Связан с", "sso.not-associated": "Нажмите здесь, что бы связать учётную запись с", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Новые отмеченные сообщения", "info.no-flags": "Отмеченных сообщений не найдено", "info.ban-history": "Недавно заблокированы", diff --git a/public/language/ru/users.json b/public/language/ru/users.json index f60ce7acf9..ef9f975dee 100644 --- a/public/language/ru/users.json +++ b/public/language/ru/users.json @@ -2,7 +2,7 @@ "latest_users": "Новые пользователи", "top_posters": "Самые активные", "most_reputation": "Лучшая репутация", - "most_flags": "Больше всего отмеченных сообщений", + "most_flags": "Больше всего отмеченных", "search": "Поиск", "enter_username": "Введите имя пользователя для поиска", "load_more": "Загрузить еще", diff --git a/public/language/rw/admin/appearance/customise.json b/public/language/rw/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/rw/admin/appearance/customise.json +++ b/public/language/rw/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/rw/admin/menu.json b/public/language/rw/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/rw/admin/menu.json +++ b/public/language/rw/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/rw/admin/settings/notifications.json b/public/language/rw/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/rw/admin/settings/notifications.json +++ b/public/language/rw/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/rw/admin/settings/post.json b/public/language/rw/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/rw/admin/settings/post.json +++ b/public/language/rw/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/rw/admin/settings/user.json b/public/language/rw/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/rw/admin/settings/user.json +++ b/public/language/rw/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/rw/email.json b/public/language/rw/email.json index aca6b1b8e1..fbeed00691 100644 --- a/public/language/rw/email.json +++ b/public/language/rw/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Iri tangazo rijyanye n'ubutumwa bwo mu gikari waryohererejwe kubera ko wabihisemo mu byo uzajya umenyeshwa", "notif.post.cta": "Kanda hano kugirango usome inkuru yose", "notif.post.unsub.info": "Iri tangazo rijyanye n'ibyashyizwe ku rubuga waryohererejwe kubera ko wabihisemo mu byo uzajya umenyeshwa", + "notif.cta": "Click here to go to forum", "test.text1": "Iyi message ni igerageza kugirango harebwe niba emailer ya NodeBB yarateguwe neza", "unsub.cta": "Kanda hano kugirango uhindure uko bizajya bigenda", "banned.subject": "You have been banned from %1", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index d36cc5e802..2cce2ebf54 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Ntabwo ufite amanota ahagije ngo ube wakwemererwa kugira uwo wambura amanota", "not-enough-reputation-to-flag": "Ntabwo ufite amanota ahagije ngo ube wakwemererwa gutambikana uyu muntu", "already-flagged": "Wari waramaze gutambikana ibi", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB yahuye n'ingorane mu gihe cy'ipakira: \"%1\". NodeBB irakomeza kuzana ibyo yari ifite ku ruhande rw'imbere nubwo ufite kuba wasubira inyuma ugafata ibyo wari wakoze mbere yo gupakira. ", "registration-error": "Ukwibeshya mu Iyandika", "parse-error": "Hari ikibazo cyavutse mu gihe twari kugerageza kuzana igisubizo kivuye kuri server", "wrong-login-type-email": "Koresha email yawe kugirango winjiremo", "wrong-login-type-username": "Koresha izina ry'umukoresha ryawe kugirango winjiremo", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/rw/notifications.json b/public/language/rw/notifications.json index 2d919d07cf..f26d109d5c 100644 --- a/public/language/rw/notifications.json +++ b/public/language/rw/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Komereza kuri %1", "return_to": "Subira kuri %1", "new_notification": "Itangazo Rishya", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Ufite amatangazo utarasoma. ", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email Yemejwe", "email-confirmed-message": "Urakoze kugaragaza ko email yawe ikora. Ubu ngubu konte yawe irakora nta kabuza. ", "email-confirm-error-message": "Havutse ikibazo mu gushaka kumenya niba email yawe ikora. Ushobora kuba wakoresheje kode itari yo cyangwa se yarengeje igihe. ", - "email-confirm-sent": "Hoherejwe email yo kubyemeza." + "email-confirm-sent": "Hoherejwe email yo kubyemeza.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/rw/topic.json b/public/language/rw/topic.json index dfe0130e0f..c01bbf1dd1 100644 --- a/public/language/rw/topic.json +++ b/public/language/rw/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Wiringiye neza ko ushaka kugarura iki kiganiro?", "thread_tools.purge": "Sibanganya Ikiganiro", "thread_tools.purge_confirm": "Wiringiye neza ko ushaka gusibanganya iki kiganiro?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Nta ngorane, iki kiganiro kimaze kwimurirwa muri %1", "post_delete_confirm": "Wiringiye neza ko ushaka gukuraho iki kiganiro?", "post_restore_confirm": "Wiringiye neza ko ushaka kugarura iki kiganiro? ", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Umaze kugabanyaho ku kiganiro! Kanda hano ugezwe ku kiganiro cyavutse. ", "delete_posts_instruction": "Kanda ku bintu ushaka guhisha/gusiba", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Shyira umutwe w'ikiganiro cyawe aha...", "composer.handle_placeholder": "Izina", "composer.discard": "Byihorere", diff --git a/public/language/rw/user.json b/public/language/rw/user.json index ed0b275bdf..ed5bd999d7 100644 --- a/public/language/rw/user.json +++ b/public/language/rw/user.json @@ -79,8 +79,6 @@ "digest_daily": "Buri Munsi", "digest_weekly": "Buri Cyumweru", "digest_monthly": "Buri Kwezi", - "send_chat_notifications": "Njye nohererezwa email igihe hari ubutumwa bwo mu gikari banyoherereje ntari ku murongo", - "send_post_notifications": "Njye nohererezwa email mu gihe hari abanditse ku biganiro niyandikishijeho", "settings-require-reload": "Hari igihe ibyo watunganyije bitagaragara iyo utongeye ngo upakire paji uriho. Kanda hano upakire iyi paji bundibushya. ", "has_no_follower": "Uyu muntu ntabwo afite abamukurikira :(", "follows_no_one": "Uyu muntu ntabwo akurikira umuntu numwe :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Gutunganya Uburyo Usoma", "open_links_in_new_tab": "Fungurira imirongo ijya hanze mu idirishya rishya", "enable_topic_searching": "Emerera Ugushakira mu Kiganiro", @@ -123,6 +126,9 @@ "sso.title": "Kwinjiramo ukoreshe serivisi za SSO", "sso.associated": "Bisanishijwe na", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/sc/admin/appearance/customise.json b/public/language/sc/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/sc/admin/appearance/customise.json +++ b/public/language/sc/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/sc/admin/menu.json b/public/language/sc/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/sc/admin/menu.json +++ b/public/language/sc/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/sc/admin/settings/notifications.json b/public/language/sc/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/sc/admin/settings/notifications.json +++ b/public/language/sc/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/sc/admin/settings/post.json b/public/language/sc/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/sc/admin/settings/post.json +++ b/public/language/sc/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/sc/admin/settings/user.json b/public/language/sc/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/sc/admin/settings/user.json +++ b/public/language/sc/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/sc/email.json b/public/language/sc/email.json index c1e17018fa..164e70795e 100644 --- a/public/language/sc/email.json +++ b/public/language/sc/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", "notif.post.cta": "Click here to read the full topic", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.cta": "Click here to go to forum", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", "unsub.cta": "Click here to alter those settings", "banned.subject": "You have been banned from %1", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index 82d34b5e05..a986e97f0f 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "already-flagged": "You have already flagged this post", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "Registration Error", "parse-error": "Something went wrong while parsing server response", "wrong-login-type-email": "Please use your email to login", "wrong-login-type-username": "Please use your username to login", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", @@ -132,5 +134,6 @@ "no-users-selected": "No user(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json index 91ea21d51c..90685c70d5 100644 --- a/public/language/sc/notifications.json +++ b/public/language/sc/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Continue to %1", "return_to": "Return to %1", "new_notification": "New Notification", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "You have unread notifications.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "email-confirm-sent": "Confirmation email sent.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/sc/topic.json b/public/language/sc/topic.json index f5e4b1b376..3074f4b2f0 100644 --- a/public/language/sc/topic.json +++ b/public/language/sc/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", "post_delete_confirm": "Are you sure you want to delete this post?", "post_restore_confirm": "Are you sure you want to restore this post?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Pone su tìtulu de s'arresonada inoghe...", "composer.handle_placeholder": "Name", "composer.discard": "Lassa a Pèrdere", diff --git a/public/language/sc/user.json b/public/language/sc/user.json index 601342a8b1..d22c0e62c3 100644 --- a/public/language/sc/user.json +++ b/public/language/sc/user.json @@ -79,8 +79,6 @@ "digest_daily": "Daily", "digest_weekly": "Weekly", "digest_monthly": "Monthly", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Custu impitadore non tenet perunu sighidore :(", "follows_no_one": "Custu impitadore no est sighende nissunu :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Outgoing message sound", "notification-sound": "Notification sound", "no-sound": "No sound", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Browsing Settings", "open_links_in_new_tab": "Open outgoing links in new tab", "enable_topic_searching": "Enable In-Topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on Services", "sso.associated": "Associated with", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/sk/admin/appearance/customise.json b/public/language/sk/admin/appearance/customise.json index 1cf04a6c75..645165e105 100644 --- a/public/language/sk/admin/appearance/customise.json +++ b/public/language/sk/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Zadajte svoje vlastné deklarácie CSS, ktoré budú použité po všetkých ostatných štýloch.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/sk/admin/menu.json b/public/language/sk/admin/menu.json index 64648aedc7..d612ad497a 100644 --- a/public/language/sk/admin/menu.json +++ b/public/language/sk/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/sk/admin/settings/notifications.json b/public/language/sk/admin/settings/notifications.json index 5154979af9..96fcb7ed90 100644 --- a/public/language/sk/admin/settings/notifications.json +++ b/public/language/sk/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Oznámenia", "welcome-notification": "Uvítacie upozornenie", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/sk/admin/settings/post.json b/public/language/sk/admin/settings/post.json index 72aac7dba0..4cff3ca723 100644 --- a/public/language/sk/admin/settings/post.json +++ b/public/language/sk/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Najviac hlasov", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/sk/admin/settings/user.json b/public/language/sk/admin/settings/user.json index d3bdd791e8..369bbf7e8a 100644 --- a/public/language/sk/admin/settings/user.json +++ b/public/language/sk/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/sk/email.json b/public/language/sk/email.json index 8b665092ea..7460b8d408 100644 --- a/public/language/sk/email.json +++ b/public/language/sk/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Túto správu konverzácie ste prijali na základe Vašich nastavení odoberania.", "notif.post.cta": "Kliknite sem pre zobrazenie celej diskusie", "notif.post.unsub.info": "Toto oznámenie o príspevkoch ste prijali na základe Vašich nastavení účtu.", + "notif.cta": "Click here to go to forum", "test.text1": "Toto je skúšobný e-mail na overenie funkčnosti e-mailovej aplikácie Vášho NodeBB fóra.", "unsub.cta": "Kliknite sem pre zmenu týchto nastavení", "banned.subject": "Boli ste zablokovaný používateľom %1", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 544c3d8ea9..4a4811880f 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nemáte dostatočnú reputáciu k odobratiu hlasu pre tento príspevok", "not-enough-reputation-to-flag": "Nemáte dostatočnú reputáciu na označenie tohto príspevku", "already-flagged": "Už ste označili tento príspevok", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB narazil na problém pri načítaní: \"%1\". NodeBB bude pokračovať v službe existujúcej aktívnej klientskej strane, aj keď by ste mali vrátiť to, čo ste spravili tesne pred znovu načítaním.", "registration-error": "Chyba registrácie", "parse-error": "Niečo sa pokazilo pri analýze odpovede servera", "wrong-login-type-email": "Prosím použite svoj e-mail, k prihláseniu", "wrong-login-type-username": "Použite svoje užívateľské meno pre prihlásenie", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Pozvali ste maximálny počet ľudí (%1 z %2).", "no-session-found": "Žiadne prihlásenie sa do relácií nenájdené!", "not-in-room": "Užívateľ nie je v miestnosti", @@ -132,5 +134,6 @@ "no-users-selected": "Žiadny užívateľ(ia) neboli vybratý", "invalid-home-page-route": "Neplatná cesta pre domovskú stránku", "invalid-session": "Relácia neodpovedá", - "invalid-session-text": "Vyzerá to, že Vaše prihlasovacia relácia už nie je aktívna, alebo sa už nezhoduje so serverom. Aktualizujte túto stránku." + "invalid-session-text": "Vyzerá to, že Vaše prihlasovacia relácia už nie je aktívna, alebo sa už nezhoduje so serverom. Aktualizujte túto stránku.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json index 9836ea6dce..651d15b910 100644 --- a/public/language/sk/notifications.json +++ b/public/language/sk/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Pokračujte k %1", "return_to": "Návrat do %1", "new_notification": "Nové oznámenie", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Máte neprečítané oznámenia", "all": "Všetko", "topics": "Témy", @@ -45,5 +46,19 @@ "email-confirmed": "E-mail bol potvrdený", "email-confirmed-message": "Ďakujeme za potvrdenie Vášho e-mailu. Účet je plne aktivovaný.", "email-confirm-error-message": "Vyskytla sa chyba pri overení Vašej e-mailovej adresy. ", - "email-confirm-sent": "Potvrdzovací e-mail bol odoslaný." + "email-confirm-sent": "Potvrdzovací e-mail bol odoslaný.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/sk/topic.json b/public/language/sk/topic.json index 9eeab330be..f32fa2c20e 100644 --- a/public/language/sk/topic.json +++ b/public/language/sk/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Ste si naozaj istý že chcete obnoviť túto tému?", "thread_tools.purge": "Vyčistiť tému", "thread_tools.purge_confirm": "Ste si naozaj istý že chcete vyčistiť túto tému?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Téma bola úspešne presunutá do %1", "post_delete_confirm": "Ste si istý, že chcete odstrániť tento príspevok?", "post_restore_confirm": "Ste si istí, že chcete obnoviť tento príspevok?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 príspevky(ov) vybraté", "fork_success": "Rozdelenie témy bolo úspešné! Kliknutím sem sa dostanete na rozdelenú tému", "delete_posts_instruction": "Kliknite na príspevky, ktoré chcete odstrániť/očistiť", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Sem zadajte názov témy...", "composer.handle_placeholder": "Meno", "composer.discard": "Zahodiť", diff --git a/public/language/sk/user.json b/public/language/sk/user.json index e6224d0d86..43c94065e4 100644 --- a/public/language/sk/user.json +++ b/public/language/sk/user.json @@ -79,8 +79,6 @@ "digest_daily": "Denne", "digest_weekly": "Týždenne", "digest_monthly": "Mesačne", - "send_chat_notifications": "Poslať e-mail, ak nová správa konverzácie príde a ja nie som on-line", - "send_post_notifications": "Poslať e-mail, ak bude nová odpoveď na témy, v ktorých mám prihlásený odber", "settings-require-reload": "Niektoré zmeny nastavení vyžadujú znovu načítanie stránky. Kliknutím sem znova načítate stránku.", "has_no_follower": "Tohto užívateľa nikto nesleduje :(", "follows_no_one": "Tento užívateľ nikoho nesleduje :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Odchádzajúci zvuk správy", "notification-sound": "Zvuk oznámenia", "no-sound": "Žiadny zvuk", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Nastavenia prehľadávania", "open_links_in_new_tab": "Otvárať odchádzajúce odkazy v novom liste", "enable_topic_searching": "Povoliť vyhľadávanie priamo v téme", @@ -123,6 +126,9 @@ "sso.title": "Služby jednotného prihlasovania", "sso.associated": "Spojené s", "sso.not-associated": "Kliknite tu pre spojenie s", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Najnovšie príznaky", "info.no-flags": "Neboli nájdené žiadne označené príspevky", "info.ban-history": "Nedávna história zablokovania", diff --git a/public/language/sl/admin/appearance/customise.json b/public/language/sl/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/sl/admin/appearance/customise.json +++ b/public/language/sl/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/sl/admin/menu.json b/public/language/sl/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/sl/admin/menu.json +++ b/public/language/sl/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/sl/admin/settings/notifications.json b/public/language/sl/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/sl/admin/settings/notifications.json +++ b/public/language/sl/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/sl/admin/settings/post.json b/public/language/sl/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/sl/admin/settings/post.json +++ b/public/language/sl/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/sl/admin/settings/user.json b/public/language/sl/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/sl/admin/settings/user.json +++ b/public/language/sl/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/sl/email.json b/public/language/sl/email.json index 7934ff9bfb..7cffd285a8 100644 --- a/public/language/sl/email.json +++ b/public/language/sl/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Obvestilo o klepetu vam je bilo poslano zaradi nastavitev vaše naročnine.", "notif.post.cta": "Kliknite tu, če želite prebrati celotno temo.", "notif.post.unsub.info": "Obvestilo o objavi vam je bilo poslano zaradi nastavitev vaše naročnine.", + "notif.cta": "Click here to go to forum", "test.text1": "To je testno elektronsko sporočilo za preverjanje pravilnosti nastavitev podsistema za pošiljanje NodeBB poštnih sporočil.", "unsub.cta": "Kliknite tu za spremembo nastavitev.", "banned.subject": "You have been banned from %1", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index a33f7a3c7b..a2a89d593b 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Nimate dovolj ugleda za negativno glasovanje.", "not-enough-reputation-to-flag": "Nimate dovolj ugleda za prijavo te objave.", "already-flagged": "To objavo ste že prijavili.", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB je zaznal težavo pri osveževanju: ", "registration-error": "Napaka pri registraciji", "parse-error": "Nekaj je šlo narobe pri pridobivanju odgovora s strežnika.", "wrong-login-type-email": "Uporabite svoj e-poštni naslov za prijavo.", "wrong-login-type-username": "Uporabite svoje uporabniško ime za prijavo.", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Povabili ste največje dovoljeno število ljudi (%1 od %2).", "no-session-found": "Prijavne seje ni mogoče najti!", "not-in-room": "Uporabnika ni v sobi.", @@ -132,5 +134,6 @@ "no-users-selected": "Ni izbranih uporabnikov.", "invalid-home-page-route": "Napačna pot do domače strani.", "invalid-session": "Seje se ne ujemajo.", - "invalid-session-text": "Kaže, da vaša prijavna seja ni več aktiva. Prosimo, osvežite to stran." + "invalid-session-text": "Kaže, da vaša prijavna seja ni več aktiva. Prosimo, osvežite to stran.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/sl/notifications.json b/public/language/sl/notifications.json index 0a69652eaf..06cf6ebcd1 100644 --- a/public/language/sl/notifications.json +++ b/public/language/sl/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Nadaljujte na %1.", "return_to": "Vrnite se na %1.", "new_notification": "Novo obvestilo", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Imate neprebrana obvestila.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "E-poštni naslov potrjen", "email-confirmed-message": "Hvala, da ste potrdili svoj e-naslov. Račun je sedaj aktiviran.", "email-confirm-error-message": "Prišlo je do napake pri preverjanju vašega e-poštnega naslova. Morda je bila koda napačna ali pa je potekla.", - "email-confirm-sent": "Potrditveno e-sporočilo je poslano." + "email-confirm-sent": "Potrditveno e-sporočilo je poslano.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/sl/topic.json b/public/language/sl/topic.json index cc539f3f40..0c2f4f135e 100644 --- a/public/language/sl/topic.json +++ b/public/language/sl/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Ste prepričani, da želite obnoviti to temo?", "thread_tools.purge": "Očisti temo", "thread_tools.purge_confirm": "Ste prepričani, da želite očistiti to temo?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Ta tema je bila uspešno prestavljena v %1", "post_delete_confirm": "Ste prepričani, da želite izbrisati to objavo?", "post_restore_confirm": "Ste prepričani, da želite razveljaviti to objavo?", @@ -89,6 +91,7 @@ "fork_pid_count": "Izbranih objav: %1 ", "fork_success": "Uspešno ste razcepili temo! Klikni tu za ogled te teme.", "delete_posts_instruction": "Kliknite na teme, ki jih želite izbrisati/očistiti ", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Vpiši naslov teme...", "composer.handle_placeholder": "Ime", "composer.discard": "Zavrzi", diff --git a/public/language/sl/user.json b/public/language/sl/user.json index 417b556497..b6eeb8763d 100644 --- a/public/language/sl/user.json +++ b/public/language/sl/user.json @@ -79,8 +79,6 @@ "digest_daily": "Dnevno", "digest_weekly": "Tedensko", "digest_monthly": "Mesečno", - "send_chat_notifications": "Pošlji mi e-pošto, če se pojavi novo sporočilo v klepetu, medtem ko sem neprijavljen", - "send_post_notifications": "Pošlji mi e-pošto, če se pojavijo nove objave v temi, kateri sledim", "settings-require-reload": "Nekatere spremembe potrebujejo osvežitev strani. Pritisni tukaj za ponovno nalaganje.", "has_no_follower": "Uporabniku nihče ne sledi :(", "follows_no_one": "Uporabnik nikomur ne sledi :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Zvok za poslano sporočilo", "notification-sound": "Zvok obvestila", "no-sound": "Ni zvoka", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Preglej nastavitve", "open_links_in_new_tab": "Zunanje povezave odpri v novem zavihku", "enable_topic_searching": "Omogoči iskanje znotraj teme", @@ -123,6 +126,9 @@ "sso.title": "Storitev enotne prijave ", "sso.associated": "Povezan z", "sso.not-associated": "Click here to associate with", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Latest Flags", "info.no-flags": "No Flagged Posts Found", "info.ban-history": "Recent Ban History", diff --git a/public/language/sr/admin/appearance/customise.json b/public/language/sr/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/sr/admin/appearance/customise.json +++ b/public/language/sr/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/sr/admin/menu.json b/public/language/sr/admin/menu.json index 56e84faf21..f715b7a83b 100644 --- a/public/language/sr/admin/menu.json +++ b/public/language/sr/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Izgled", "appearance/themes": "Teme", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Proširiti", "extend/plugins": "Plaginovi", diff --git a/public/language/sr/admin/settings/notifications.json b/public/language/sr/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/sr/admin/settings/notifications.json +++ b/public/language/sr/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/sr/admin/settings/post.json b/public/language/sr/admin/settings/post.json index 8a7a3630c3..859fcae17c 100644 --- a/public/language/sr/admin/settings/post.json +++ b/public/language/sr/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Od starijih ka novijim", "sorting.newest-to-oldest": "Od novijih ka starijim", "sorting.most-votes": "Najviše glasova", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Uobičajeno sortiranje tema", "restrictions": "Restrikcije postavljanja", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/sr/admin/settings/user.json b/public/language/sr/admin/settings/user.json index 99a15e7c09..17e529bd4d 100644 --- a/public/language/sr/admin/settings/user.json +++ b/public/language/sr/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Teme", "disable-user-skins": "Onemogući korisnike da izaberu određenu temu", "account-protection": "Začtita naloga", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Dozvoljeno logovanje po satu", "login-attempts-help": "Ako broj logovanja prema user's predje određenu granicu, taj nalog može biti zaključan na određeno prekonfigurisano vreme", "lockout-duration": "Trajanje dok se nalog ne otključa (minuta)", diff --git a/public/language/sr/email.json b/public/language/sr/email.json index c69628cbbf..98cb324038 100644 --- a/public/language/sr/email.json +++ b/public/language/sr/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Ова обавештење о ћаскању вам је послато услед вашег подешавања претплате.", "notif.post.cta": "Кликните овде за приказ целе теме", "notif.post.unsub.info": "Ово обавештење вам је послато услед вашег подешавања претплате.", + "notif.cta": "Кликните овде да посетите посетите форум", "test.text1": "Ово је пробно е-писмо за проверу исправности поставки е-поштара у NodeBB.", "unsub.cta": "Кликните овде да измените та подешавања", "banned.subject": "Забрањени сте на %1", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 08b1e81236..c44fef981b 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Немате довољно велики углед да бисте негативно гласали за ову поруку", "not-enough-reputation-to-flag": "Немате довољно велики углед да бисте означили заставицом ову поруку", "already-flagged": "Већ сте означили заставицом ову поруку", + "self-vote": "Не можете гласати за своју поруку", "reload-failed": "NodeBB је наишао на проблем док се поново учитавао: \"%1\". NodeBB ће наставити да опслужује постојећа клијентска средства , иако би требало да опозовете оно што сте урадили пре поновног учитавања.", "registration-error": "Грешка при регистрацији", "parse-error": "Нешто је кренуло погрешно приликом анализе одговора сервера", "wrong-login-type-email": "Користите вашу е-пошту за пријављивање", "wrong-login-type-username": "Користите ваше корисничко име за пријављивање", + "sso-registration-disabled": "Регистрација је онемогућена за %1 налога, региструјте се са адресом е-поште прво", "invite-maximum-met": "Позвали сте максимални број особа (%1 од %2).", "no-session-found": "Није пронађена сесија пријављивања!", "not-in-room": "Корисник није у соби", @@ -132,5 +134,6 @@ "no-users-selected": "Није одабран корисник", "invalid-home-page-route": "Неважећа путања почетне странице", "invalid-session": "Неподударање сесија", - "invalid-session-text": "Изгледа да ваша сесија пријављивања није више активна или се више не подудара са сервером. Поново учитајте ову страницу." + "invalid-session-text": "Изгледа да ваша сесија пријављивања није више активна или се више не подудара са сервером. Поново учитајте ову страницу.", + "no-topics-selected": "Нема одабраних тема!" } \ No newline at end of file diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json index 18421b0857..17ba4ee271 100644 --- a/public/language/sr/notifications.json +++ b/public/language/sr/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Продужи на %1", "return_to": "Врати се на %1", "new_notification": "Ново обавештење", + "new_notification_from": "Имате ново обавештење са %1", "you_have_unread_notifications": "Имате непрочитана обавештења.", "all": "Све", "topics": "Теме", @@ -45,5 +46,19 @@ "email-confirmed": "Е-пошта је потврђена.", "email-confirmed-message": "Хвала на овери ваше е-поште. Ваш налог је сада у потпуности активан.", "email-confirm-error-message": "Дошло је до проблема са овером ваше е-поште. Можда је код неисправан или је истекао.", - "email-confirm-sent": "Е-пошта за потврду је послата." + "email-confirm-sent": "Е-пошта за потврду је послата.", + "none": "Ниједно", + "notification_only": "Само обавештење", + "email_only": "Само е-пошта", + "notification_and_email": "Обавештење и е-пошта", + "notificationType_upvote": "Када неко гласа за вашу поруку", + "notificationType_new-topic": "Када неко кога пратите постави тему", + "notificationType_new-reply": "Када је постављен нови одговор у теми коју надгледате", + "notificationType_follow": "Када неко почне да вас прати.", + "notificationType_new-chat": "Када примите поруку за ћаскање", + "notificationType_group-invite": "Када примите позивницу за групу", + "notificationType_new-register": "Када је неко додат на чекање за регистрацију", + "notificationType_post-queue": "Када је нова порука на чекању", + "notificationType_new-post-flag": "Када је порука означена", + "notificationType_new-user-flag": "Када је корисник означен" } \ No newline at end of file diff --git a/public/language/sr/topic.json b/public/language/sr/topic.json index e104832976..787aa27a4b 100644 --- a/public/language/sr/topic.json +++ b/public/language/sr/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Да ли сте сигурни да желите да обновите ову тему?", "thread_tools.purge": "Очисти тему", "thread_tools.purge_confirm": "Да ли сте сигурни да желите да очистите ову тему?", + "thread_tools.merge_topics": "Споји теме", + "thread_tools.merge": "Споји", "topic_move_success": "Ова тема је успешно премештена у %1", "post_delete_confirm": "Да ли сте сигурни да желите да избришете ову поруку?", "post_restore_confirm": "Да ли сте сигурни да желите да обновите ову поруку?", @@ -89,6 +91,7 @@ "fork_pid_count": "Одабрано порука: %1", "fork_success": "Тема је успешно рачвана! Кликните овде за одлазак на рачвану тему.", "delete_posts_instruction": "Кликните на поруке које желите да избришете/очистите", + "merge_topics_instruction": "Кликните на теме које желите да спојите", "composer.title_placeholder": "Овде унесите назив теме...", "composer.handle_placeholder": "Име", "composer.discard": "Одбаци", diff --git a/public/language/sr/user.json b/public/language/sr/user.json index 0e7b5ad6ab..961ddef916 100644 --- a/public/language/sr/user.json +++ b/public/language/sr/user.json @@ -79,8 +79,6 @@ "digest_daily": "Дневно", "digest_weekly": "Седмично", "digest_monthly": "Месечно", - "send_chat_notifications": "Пошаљи е-поруку ако пристигне нова порука ћаскања а ја нисам на мрежи", - "send_post_notifications": "Пошаљи е-поруку када се појаве одговори на теме на које сам претплаћен", "settings-require-reload": "Неке измене у подешавањима захтевају поновно учитавање. Кликните овде да бисте поново учитали страницу.", "has_no_follower": "Овај корисник нема пратиоце :(", "follows_no_one": "Овај корисник не прати никога :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Звук одлазне поруке", "notification-sound": "Звук обавештења", "no-sound": "Без звука", + "upvote-notif-freq": "Учесталост обавештења о гласовима", + "upvote-notif-freq.all": "На сваки глас", + "upvote-notif-freq.everyTen": "На сваких десет гласова", + "upvote-notif-freq.logarithmic": "На 10, 100, 1000...", + "upvote-notif-freq.disabled": "Онемогућено", "browsing": "Подешавање прегледања", "open_links_in_new_tab": "Отвори одлазне везе у новој картици", "enable_topic_searching": "Омогући претрагу унутар тема", @@ -123,6 +126,9 @@ "sso.title": "Једноструки Sign-on сервиси", "sso.associated": "Повезано са", "sso.not-associated": "Кликните овде за повезивање са", + "sso.dissociate": "Одвоји", + "sso.dissociate-confirm-title": "Потврди одвајање", + "sso.dissociate-confirm": "Да ли сте сигурни да желите да одвојите овај налог од %1?", "info.latest-flags": "Најновије ознаке", "info.no-flags": "Нема пронађених означених порука", "info.ban-history": "Историја недавно забрањених налога", diff --git a/public/language/sv/admin/appearance/customise.json b/public/language/sv/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/sv/admin/appearance/customise.json +++ b/public/language/sv/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/sv/admin/menu.json b/public/language/sv/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/sv/admin/menu.json +++ b/public/language/sv/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/sv/admin/settings/notifications.json b/public/language/sv/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/sv/admin/settings/notifications.json +++ b/public/language/sv/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/sv/admin/settings/post.json b/public/language/sv/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/sv/admin/settings/post.json +++ b/public/language/sv/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/sv/admin/settings/user.json b/public/language/sv/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/sv/admin/settings/user.json +++ b/public/language/sv/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/sv/email.json b/public/language/sv/email.json index db54326e29..4e1b61ab40 100644 --- a/public/language/sv/email.json +++ b/public/language/sv/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Denna notifikation skickades till dig på grund av dina inställningar för prenumerationer.", "notif.post.cta": "Klicka här för att läsa hela ämnet", "notif.post.unsub.info": "Det här meddelandet fick du på grund av dina inställningar för prenumeration. ", + "notif.cta": "Click here to go to forum", "test.text1": "\nDet här är ett testmeddelande som verifierar att e-posten är korrekt installerad för din NodeBB. ", "unsub.cta": "Klicka här för att ändra inställningarna", "banned.subject": "You have been banned from %1", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index ee35a84906..70c14e7590 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Du har inte tillräckligt förtroende för att rösta ner det här meddelandet", "not-enough-reputation-to-flag": "Du har inte tillräckligt förtroende för att flagga det här inlägget.", "already-flagged": "Du har redan flaggat det här inlägget", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB stötte på problem med att ladda om: \"%1\". NodeBB kommer fortsätta servera befintliga resurser till klienten, men du borde återställa det du gjorde innan du försökte ladda om.", "registration-error": "Registreringsfel", "parse-error": "Något gick fel vid tolkning av svar från servern", "wrong-login-type-email": "Använd din e-postadress för att logga in", "wrong-login-type-username": "Använd ditt användarnamn för att logga in", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Du har bjudit in det maximala antalet användare (%1 av %2)", "no-session-found": "Ingen login-session hittades!", "not-in-room": "Användaren finns inte i rummet", @@ -132,5 +134,6 @@ "no-users-selected": "Ingen användare vald(a)", "invalid-home-page-route": "Ogiltig sidsökväg", "invalid-session": "Session fel", - "invalid-session-text": "Det ser ut som din inloggningssession inte längre är aktiv eller inte längre överensstämmer med servern. Uppdatera denna sida." + "invalid-session-text": "Det ser ut som din inloggningssession inte längre är aktiv eller inte längre överensstämmer med servern. Uppdatera denna sida.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index ea14561dc9..46d77ab13f 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Fortsätt till %1", "return_to": "Återgå till %1", "new_notification": "Ny notis", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Du har olästa notiser.", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "E-post bekräftad", "email-confirmed-message": "Tack för att du bekräftat din e-postadress. Ditt konto är nu fullt ut aktiverat.", "email-confirm-error-message": "Det uppstod ett problem med bekräftelsen av din e-postadress. Kanske var koden felaktig eller ogiltig.", - "email-confirm-sent": "Bekräftelsemeddelande skickat." + "email-confirm-sent": "Bekräftelsemeddelande skickat.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index bf51d85095..131077062e 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Är du säker på att du vill återställa det här ämnet?", "thread_tools.purge": "Rensa bort ämne", "thread_tools.purge_confirm": "Är du säker att du vill rensa bort det här ämnet?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Det här ämnet har flyttats till %1", "post_delete_confirm": "Är du säker på att du vill ta bort det här inlägget?", "post_restore_confirm": "Är du säker på att du vill återställa det här inlägget?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 inlägg vald(a)", "fork_success": "Ämnet har blivit förgrenat. Klicka här för att gå till det förgrenade ämnet.", "delete_posts_instruction": "Klicka på inläggen du vill radera/rensa bort", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Skriv in ämnets titel här...", "composer.handle_placeholder": "Namn", "composer.discard": "Avbryt", diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 9b1749b9b3..2cb295f536 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -79,8 +79,6 @@ "digest_daily": "Dagligen", "digest_weekly": "Veckovis", "digest_monthly": "Månadsvis", - "send_chat_notifications": "Skicka ett e-postmeddelande om nya chatt-meddelanden tas emot när jag inte är online.", - "send_post_notifications": "Skicka ett e-postmeddelande när svar tillkommit på ämnen jag prenumererar på", "settings-require-reload": "Vissa inställningar som ändrades kräver att sidan laddas om. Klicka här för att ladda om sidan.", "has_no_follower": "Denna användare har inga följare :(", "follows_no_one": "Denna användare följer ingen :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Utgående meddelande ljud", "notification-sound": "Meddelandeljud", "no-sound": "Inget ljud", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Inställning för bläddring", "open_links_in_new_tab": "Öppna utgående länkar i ny flik", "enable_topic_searching": "Aktivera sökning inom ämne", @@ -123,6 +126,9 @@ "sso.title": "Single Sign-on-tjänster", "sso.associated": "Associerad med", "sso.not-associated": "Klicka här för att associera med", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Senaste flaggade", "info.no-flags": "Inga flaggade inlägg hittades", "info.ban-history": "Ban historik", diff --git a/public/language/th/admin/appearance/customise.json b/public/language/th/admin/appearance/customise.json index e377c7781a..2f715a9bfc 100644 --- a/public/language/th/admin/appearance/customise.json +++ b/public/language/th/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "ใส่ CSS ของคุณที่นี่, มันจะถูกนำไปใช้ต่อจากสไตล์อื่นๆ", "custom-css.enable": "เปิดการปรับแต่ง CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "ปรับแต่งส่วนหัว", - "custom-header.description": "ใส่การปรับแต่ง HTML ที่นี่ (เช่น JavaScript, Meta Tags หรืออื่นๆ) , มันจะถูกเพิ่มใน <head>ของส่วนฟอรั่มของคุณ", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "เปิดการปรับแต่งส่วนหัว", "custom-css.livereload": "เปิดการบังคับให้มีผลในทันที", diff --git a/public/language/th/admin/menu.json b/public/language/th/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/th/admin/menu.json +++ b/public/language/th/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/th/admin/settings/notifications.json b/public/language/th/admin/settings/notifications.json index e5193fc159..c2f5b8b9b9 100644 --- a/public/language/th/admin/settings/notifications.json +++ b/public/language/th/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "การแจ้งเตือน", "welcome-notification": "การยินดีต้อนรับแจ้งเตือน", - "welcome-notification-link": "ลิงค์การยินดีต้อนรับแจ้งเตือน" + "welcome-notification-link": "ลิงค์การยินดีต้อนรับแจ้งเตือน", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/th/admin/settings/post.json b/public/language/th/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/th/admin/settings/post.json +++ b/public/language/th/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/th/admin/settings/user.json b/public/language/th/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/th/admin/settings/user.json +++ b/public/language/th/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/th/email.json b/public/language/th/email.json index 16b41971a7..54080a872b 100644 --- a/public/language/th/email.json +++ b/public/language/th/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "การแจ้งเตือนแชทนี้ถูกส่งไปหาคุณเนื่องจากการตั้งค่าสมาชิกของคุณ", "notif.post.cta": "คลิกที่นี่เพื่ออ่านกระทู้ฉบับเต็ม", "notif.post.unsub.info": "การแจ้งเตือนกระทู้นี้ถูกส่งไปยังคุณเนื่องการตั้งค่าสมาชิกของคุณ", + "notif.cta": "Click here to go to forum", "test.text1": "นี่คืออีเมลทดสอบเพื่อยืนยันว่าระบบอีเมลมีการตั้งค่าที่ถูกต้องสำหรับ NodeBB ของคุณ", "unsub.cta": "กดตรงนี้เพื่อเปลี่ยนแปลงการตั้งค่า", "banned.subject": "คุณถูกแบนจาก %1 แล้ว", diff --git a/public/language/th/error.json b/public/language/th/error.json index 1d740b7b0b..3f91fb4d47 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "คุณไม่มีชื่อเสียงพอที่จะโหวตโพสต์นี้ลง", "not-enough-reputation-to-flag": "คุณไม่มีชื่อเสียงพอที่จะปักธงให้โพสต์นี้", "already-flagged": "คุณได้ปักธงให้โพสต์นี้แล้ว", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", "registration-error": "การสมัครสมาชิกผิดพลาด", "parse-error": "มีบางอย่างผิดพลาดขณะรอการตอบกลับจากเซิร์ฟเวอร์", "wrong-login-type-email": "กรุณาใช้อีเมล์ของคุณในการเข้าสู่ระบบ", "wrong-login-type-username": "กรุณาใช้ชื่อผู้ใช้ของคุณในการเข้าสู่ระบบ", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "คุณได้ทำการเชิญผู้คนจำนวนมากที่สุด (%1 out of %2).", "no-session-found": "ไม่พบการเข้าสู่ระบบ", "not-in-room": "ผู้ใช้ไม่อยู่ในห้อง", @@ -132,5 +134,6 @@ "no-users-selected": "ไม่มีผู้ใช้ที่เลือก", "invalid-home-page-route": "เส้นทางไปหน้าแรกผิดพลาด", "invalid-session": "เซสชั่นไม่ถูกต้อง", - "invalid-session-text": "เหมือนกับว่าการเข้าสู่ระบบของคุณไม่ได้มีอยู่ในระบบ หรือไม่ก็ไม่ได้รับการตอบกลับจากเซิร์ฟเวอร์ กรุณารีเฟรชหน้าเว็บนี้" + "invalid-session-text": "เหมือนกับว่าการเข้าสู่ระบบของคุณไม่ได้มีอยู่ในระบบ หรือไม่ก็ไม่ได้รับการตอบกลับจากเซิร์ฟเวอร์ กรุณารีเฟรชหน้าเว็บนี้", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json index d40f9af8ef..727c91dbe0 100644 --- a/public/language/th/notifications.json +++ b/public/language/th/notifications.json @@ -9,6 +9,7 @@ "continue_to": "ดำเนินการต่อไปยัง %1", "return_to": "กลับสู่ %1", "new_notification": "ข้อความเตือนใหม่", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "คุณมีคำเตือนที่ยังไม่ได้อ่าน", "all": "ทั้งหมด", "topics": "กระทู้", @@ -45,5 +46,19 @@ "email-confirmed": "Email ได้รับการยืนยันแล้ว", "email-confirmed-message": "ขอบคุณที่ยืนยัน Email ของคุณ บัญชีของคุณสามารถใช้งานได้แล้ว", "email-confirm-error-message": "มีปัญหาในการยืนยัน Email ของคุณ บางทีรหัสไม่ถูกต้องหรือหมดอายุแล้ว", - "email-confirm-sent": "Email เพื่อยืนยันได้ส่งไปแล้ว" + "email-confirm-sent": "Email เพื่อยืนยันได้ส่งไปแล้ว", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/th/topic.json b/public/language/th/topic.json index 69e1b0b54f..980bf12387 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "มั่นใจแล้วหรือไม่ที่จะกู้คืน Topic นี้?", "thread_tools.purge": "ล้างกระทู้", "thread_tools.purge_confirm": "คุณแน่ใจแล้วใช้ไมว่าต้องการล้างกระทู้นี้?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "กระทู้นี้ได้รับการย้ายไปยัง %1 เรียบร้อยแล้ว", "post_delete_confirm": "คุณแน่ใจแล้วใช่ไหมว่าต้องการลบโพสต์นี้", "post_restore_confirm": "คุณแน่ใจแล้วใช้ไหมว่าต้องการกู้คืนโพสต์นี้", @@ -89,6 +91,7 @@ "fork_pid_count": " %1 โพสต์(s) ที่เลือก", "fork_success": "แตกกระทู้สำเร็จแล้ว! คลิกที่นี่เพื่อไปยั้งกระทู้ที่คุณแตกประเด็น", "delete_posts_instruction": "คลิกโพสต์ที่คุณต้องการลบ/ล้าง", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "ป้อนชื่อกระทู้ของคุณที่นี่ ...", "composer.handle_placeholder": "ชื่อ", "composer.discard": "ยกเลิก", diff --git a/public/language/th/user.json b/public/language/th/user.json index b4cb257cf5..0da95b8fa9 100644 --- a/public/language/th/user.json +++ b/public/language/th/user.json @@ -79,8 +79,6 @@ "digest_daily": "รายวัน", "digest_weekly": "รายสัปดาห์", "digest_monthly": "รายเดือน", - "send_chat_notifications": "ส่งอีเมลเมื่อมีข้อความใหม่เข้ามาขณะที่ฉันไม่ได้ออนไลน์", - "send_post_notifications": "ส่งอีเมลให้ฉันเมื่อมีการตอบกลับในหัวข้อที่ฉันเคยบอกรับเป็นสมาชิกไว้", "settings-require-reload": "การตั้งค่าบางอย่างต้องโหลดหน้าใหม่ คลิกที่นี่เพื่อโหลดหน้าใหม่", "has_no_follower": "ผู้ใช้รายนี้ไม่มีใครติดตาม :(", "follows_no_one": "ผู้ใช้รายนี้ไม่ติดตามใคร :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "เสียงข้อความออก", "notification-sound": "เสียงแจ้งเตือน", "no-sound": "ไม่มีเสียง", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "เปิดดูการตั้งค่า", "open_links_in_new_tab": "เปิดลิงค์ในแท็บใหม่", "enable_topic_searching": "เปิดใช้การค้นหาแบบ In-Topic", @@ -123,6 +126,9 @@ "sso.title": "บริการ Single Sign-on ", "sso.associated": "เกี่ยวข้องกับ", "sso.not-associated": "คลิกที่นี่เพื่อเชื่อมโยงกับ", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "ปักธงล่าสุด", "info.no-flags": "ไม่พบโพสต์ที่ถูกปักธง", "info.ban-history": "ประวัติแบนล่าสุด", diff --git a/public/language/tr/admin/appearance/customise.json b/public/language/tr/admin/appearance/customise.json index e5450f0c7d..ae428da7f4 100644 --- a/public/language/tr/admin/appearance/customise.json +++ b/public/language/tr/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Özel CSS kodlarınızı bu alana girin.", "custom-css.enable": "Özel CSS Etkinleştir", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Özel Header", - "custom-header.description": "Forumunuzun biçimlendirmesini sağlayacak <head> bölümüne eklenecek özel HTML'yi (ör. JavaScript, Meta Etiketler vb.) Girin.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Özel Header'ı Etkinleştir", "custom-css.livereload": "Canlı Yenilemeyi Etkinleştir", diff --git a/public/language/tr/admin/menu.json b/public/language/tr/admin/menu.json index c6f2a706a5..d4bc661658 100644 --- a/public/language/tr/admin/menu.json +++ b/public/language/tr/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Görünüm", "appearance/themes": "Temalar", "appearance/skins": "Deriler", - "appearance/customise": "Özel HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Genişletme", "extend/plugins": "Eklentiler", diff --git a/public/language/tr/admin/settings/notifications.json b/public/language/tr/admin/settings/notifications.json index 4718dab68f..9c7badb194 100644 --- a/public/language/tr/admin/settings/notifications.json +++ b/public/language/tr/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Bildirimler", "welcome-notification": "Hoş Geldin Bildirimi", - "welcome-notification-link": "Hoş Geldin Bildirimi Bağlantısı" + "welcome-notification-link": "Hoş Geldin Bildirimi Bağlantısı", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/tr/admin/settings/post.json b/public/language/tr/admin/settings/post.json index adf92b6e9a..9df8eaba0c 100644 --- a/public/language/tr/admin/settings/post.json +++ b/public/language/tr/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "En Eskiden En Yeniye", "sorting.newest-to-oldest": "En Yeniden En Eskiye", "sorting.most-votes": "En Çok Oylanan", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Varsayılan Konu Sıralaması", "restrictions": "İleti Kısıtlamaları", "restrictions.post-queue": "İleti kuyruğunu etkinleştir", diff --git a/public/language/tr/admin/settings/user.json b/public/language/tr/admin/settings/user.json index 315f82bf4a..610de51ebf 100644 --- a/public/language/tr/admin/settings/user.json +++ b/public/language/tr/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Temalar", "disable-user-skins": "Kullanıcıların özel bir deri seçmesini engelle", "account-protection": "Hesap Koruma", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Saatlik giriş deneme sayısı", "login-attempts-help": "Bir kullanıcının hesabına giriş denemesi bu sınırı aşarsa, bu hesap önceden belirlenmiş olan bir süre için kilitlenir.", "lockout-duration": "Hesap Kilitleme Süresi (dakika)", diff --git a/public/language/tr/email.json b/public/language/tr/email.json index e1007b3b1a..71077d5cc7 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Bu bildirim şectiğiniz ayarlar yüzünden gönderildi.", "notif.post.cta": "Konunun tamamını okumak için buraya tıklayın", "notif.post.unsub.info": "Bu yazı bildirimi size abonelik ayarlarınız nedeni ile gönderilmiştir.", + "notif.cta": "Click here to go to forum", "test.text1": "Bu ileti NodeBB e-posta ayarlarınızın doğru çalışıp çalışmadığını kontrol etmek için gönderildi.", "unsub.cta": "Buraya tıklayarak ayarlarınızı değiştirebilirsiniz.", "banned.subject": "%1 'den yasaklandınız", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index bee58ae855..b32474d28c 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Bu iletiyi eksilemek için yeterince itibarınız yok.", "not-enough-reputation-to-flag": "Bu iletiyi bayraklamak için yeterince itibarınız yok", "already-flagged": "Bu iletiyi zaten bayrakladınız", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB tekrar yüklenirken bir sorunla karşılaştı: “%1“. NodeBB varolan dosyaları servis etmeye devam edecek.", "registration-error": "Kayıt Hatası", "parse-error": "Sunucu yanıtı çözümlemesi sırasında bir şeyler ters gitti", "wrong-login-type-email": "Lütfen giriş için e-posta adresinizi kullanın", "wrong-login-type-username": "Lütfen giriş için kullanıcı adınızı kullanın", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Sen maksimum miktarda insanı davet ettin (%2 üzerinden %1).", "no-session-found": "Giriş yapılmış bir oturum bulunamadı!", "not-in-room": "Odada kullanıcı yok", @@ -132,5 +134,6 @@ "no-users-selected": "Seçili kullanıcı(s) bulunamadı", "invalid-home-page-route": "Geçersiz anasayfa yolu", "invalid-session": "Oturum Uyuşmazlığı", - "invalid-session-text": "Senin giriş oturumun pek aktif gözükmüyor, ya da sunucu ile eşleşmiyor. Lütfen sayfayı yenileyiniz." + "invalid-session-text": "Senin giriş oturumun pek aktif gözükmüyor, ya da sunucu ile eşleşmiyor. Lütfen sayfayı yenileyiniz.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json index e60e3a55b8..5cb4e12e66 100644 --- a/public/language/tr/notifications.json +++ b/public/language/tr/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Devam et", "return_to": "Geri dön.", "new_notification": "Yeni bildirim", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Okunmamış bildirimleriniz var.", "all": "Hepsi", "topics": "Başlıklar", @@ -45,5 +46,19 @@ "email-confirmed": "E-posta onaylandı", "email-confirmed-message": "E-postanızı onaylandığınız için teşekkürler. Hesabınız tamamen aktif edildi.", "email-confirm-error-message": "E-posta adresinizi onaylarken bir hata oluştu. Kodunuz geçersiz ya da eski olabilir.", - "email-confirm-sent": "Onay e-postası gönderildi." + "email-confirm-sent": "Onay e-postası gönderildi.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index b05175efa4..4fa9e54998 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Bu konuyu gerçekten geri getirmek istiyor musun?", "thread_tools.purge": "Konuyu Temizle", "thread_tools.purge_confirm": "Bu konuyu temizlemek istediğinize eminmisiniz?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Başlık %1 kategorisine başarıyla taşındı.", "post_delete_confirm": "Bu iletiyi gerçekten silmek istediğinize emin misiniz?", "post_restore_confirm": "Bu iletiyi gerçekten geri getirmek istiyor musun?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 ileti(ler) seçildi", "fork_success": "Başlık başarıyla ayrıldı!", "delete_posts_instruction": "Silmek/temizlemek istediğiniz iletilere tıklayın.", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Başlık ismini buraya girin...", "composer.handle_placeholder": "İsim", "composer.discard": "Vazgeç", diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 809bb2ba47..cb287892cc 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -79,8 +79,6 @@ "digest_daily": "Günlük", "digest_weekly": "Haftalık", "digest_monthly": "Aylık", - "send_chat_notifications": "Çevrimiçi değilken gelen iletileri e-posta olarak gönder", - "send_post_notifications": "Abone olduğum konulara cevap gelince bana e-posta yolla", "settings-require-reload": "Bazı ayar değişiklikleri sayfayı tekrar yüklemenizi gerektirir. Buraya tıklayarak sayfayı tekrar yükleyebilirsiniz.", "has_no_follower": "Bu kullanıcının hiç takipçisi yok :(", "follows_no_one": "Bu kullanıcı kimseyi takip etmiyor :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Giden ileti sesi", "notification-sound": "Bildirim sesi", "no-sound": "Ses yok", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Tarayıcı Ayaları", "open_links_in_new_tab": "Dışarı giden bağlantıları yeni sekmede aç", "enable_topic_searching": "Konu içi aramayı aktive et", @@ -123,6 +126,9 @@ "sso.title": "Tek giriş servisleri", "sso.associated": "Birleştirilmiş", "sso.not-associated": "Birleştirmek için buraya tıklayın", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Son Bayraklar", "info.no-flags": "Hiç bayraklanan bir ileti bulunamadı", "info.ban-history": "Yasaklama Olayları", diff --git a/public/language/uk/admin/appearance/customise.json b/public/language/uk/admin/appearance/customise.json index 0caddb1faa..20528f77e9 100644 --- a/public/language/uk/admin/appearance/customise.json +++ b/public/language/uk/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Уведіть власні CSS правила, що будуть примінені після всіх інших стилів.", "custom-css.enable": "Увімкнути користувацькі CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Користувацький заголовок", - "custom-header.description": "Уведіть власний HTML (JavaScript, мета теги, тощо), що буде додано до секції <head> вашого форуму.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Увімкнути користувацький заголовок", "custom-css.livereload": "Увімкнути Автоматичне Оновлення", diff --git a/public/language/uk/admin/menu.json b/public/language/uk/admin/menu.json index 7c5599d12d..108b4a991f 100644 --- a/public/language/uk/admin/menu.json +++ b/public/language/uk/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Зовнішній вигляд", "appearance/themes": "Теми", "appearance/skins": "Стилі", - "appearance/customise": "Користувацькі HTML та CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Розширити", "extend/plugins": "Плагіни", diff --git a/public/language/uk/admin/settings/notifications.json b/public/language/uk/admin/settings/notifications.json index 68634d4721..3a5f9976d1 100644 --- a/public/language/uk/admin/settings/notifications.json +++ b/public/language/uk/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Сповіщення", "welcome-notification": "Сповіщення \"Ласкаво просимо\"", - "welcome-notification-link": "Посилання для сповіщення \"Ласкаво просимо\"" + "welcome-notification-link": "Посилання для сповіщення \"Ласкаво просимо\"", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/uk/admin/settings/post.json b/public/language/uk/admin/settings/post.json index 99e2817cbc..74434de937 100644 --- a/public/language/uk/admin/settings/post.json +++ b/public/language/uk/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Старі > Нові", "sorting.newest-to-oldest": "Нові > Старі", "sorting.most-votes": "Кількість голосів", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Типове сортування тем", "restrictions": "Обмеження постингу", "restrictions.post-queue": "Увімкнути чергу постів", diff --git a/public/language/uk/admin/settings/user.json b/public/language/uk/admin/settings/user.json index d2f7f3f515..9bae26eb89 100644 --- a/public/language/uk/admin/settings/user.json +++ b/public/language/uk/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Теми", "disable-user-skins": "Заборонити користувачам обирати стиль сайту", "account-protection": "Захист акаунту", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Кількість спроб входу за годину", "login-attempts-help": "Якщо кількість спроб входу в акаунт користувача перевищить цей ліміт, акаунт буде заблоковано на задану кількість часу", "lockout-duration": "Тривалість блокування акаунту (хвилин)", diff --git a/public/language/uk/email.json b/public/language/uk/email.json index eddbf7c236..9d44cf9f7f 100644 --- a/public/language/uk/email.json +++ b/public/language/uk/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Це повідомлення чату було вислано вам, згідно ваших налаштувань підписки", "notif.post.cta": "Натисніть тут, щоб повністю прочитати статтю", "notif.post.unsub.info": "Це поштове повідомлення було вислано вам, згідно ваших налаштувань підписки", + "notif.cta": "Click here to go to forum", "test.text1": "Це пробний лист для верифікації поштової служби. Всі налаштування вірні для NodeBB.", "unsub.cta": "Натисніть тут, щоб змінити ці налаштування", "banned.subject": "Ви були забанені на %1", diff --git a/public/language/uk/error.json b/public/language/uk/error.json index 08c5c91e75..883f1b7bfc 100644 --- a/public/language/uk/error.json +++ b/public/language/uk/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "У вас недостатньо репутації, щоб голосувати проти цього посту", "not-enough-reputation-to-flag": "У вас недостатньо репутації, щоб помітити цей пост", "already-flagged": "Ви вже помітили цей пост", + "self-vote": "You cannot vote on your own post", "reload-failed": "У NodeBB виникла проблема при перевантаженні: \"%1\". NodeBB продовжить надавати існуючі клієнтські ресурси, проте радимо вам скасувати те, що було зроблено до перевантаження.", "registration-error": "Помилка реєстрації", "parse-error": "Щось пішло не так при розборі відповіді сервера", "wrong-login-type-email": "Будь ласка, використайте вашу електронну пошту для входу", "wrong-login-type-username": "Будь ласка, використайте ваше ім'я для входу", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Ви запросили максимальну кілкість людей (%1 з %2).", "no-session-found": "Жодної сесії не знайдено!", "not-in-room": "Користувача немає в кімнаті", @@ -132,5 +134,6 @@ "no-users-selected": "Не вибрано жодного користувача", "invalid-home-page-route": "Невірний шлях на головну", "invalid-session": "Сесія не існує", - "invalid-session-text": "Здається, що ваша сесія більше неактивна або розійшлася з серверною. Оновіть, будь ласка, цю сторінку." + "invalid-session-text": "Здається, що ваша сесія більше неактивна або розійшлася з серверною. Оновіть, будь ласка, цю сторінку.", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/uk/notifications.json b/public/language/uk/notifications.json index 858485d685..e7b2f9099b 100644 --- a/public/language/uk/notifications.json +++ b/public/language/uk/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Перейти до %1", "return_to": "Повернутись до %1", "new_notification": "Нове сповіщення", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "У вас немає непрочитаних сповіщень", "all": "Всі", "topics": "Теми", @@ -45,5 +46,19 @@ "email-confirmed": "Електронну пошту підтверджено", "email-confirmed-message": "Дякуємо за підтвердження електронної пошти. Ваш акаунт тепер повністю активовано.", "email-confirm-error-message": "При перевірці вашої електронної пошти сталася проблема. Можливо код був недійсним або простроченим.", - "email-confirm-sent": "Підтвердження по електронній пошті було надіслано." + "email-confirm-sent": "Підтвердження по електронній пошті було надіслано.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/uk/topic.json b/public/language/uk/topic.json index 76ac483f3b..5b464da5fe 100644 --- a/public/language/uk/topic.json +++ b/public/language/uk/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Ви точно бажаєте відновити цю тему?", "thread_tools.purge": "Стерти тему", "thread_tools.purge_confirm": "Ви точно бажаєте стерти цю тему?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "Тема була успішно переміщена до %1", "post_delete_confirm": "Ви точно бажаєте видалити цей пост?", "post_restore_confirm": "Ви точно бажаєте відновити цей пост?", @@ -89,6 +91,7 @@ "fork_pid_count": "вибрано %1 пост(ів) ", "fork_success": "Тему успішно відгалужено. Тисніть тут, щоб перейти до відгалуженої теми.", "delete_posts_instruction": "Тисніть пости які ви бажаєте видалити/стерти", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Уведіть заголовок теми...", "composer.handle_placeholder": "Ім'я", "composer.discard": "Скасувати", diff --git a/public/language/uk/user.json b/public/language/uk/user.json index d483c8e14d..eabe845183 100644 --- a/public/language/uk/user.json +++ b/public/language/uk/user.json @@ -79,8 +79,6 @@ "digest_daily": "Щоденно", "digest_weekly": "Щотижнево", "digest_monthly": "Щомісячно", - "send_chat_notifications": "Надсилати листа, коли я не в мережі, якщо приходить чат повідомлення", - "send_post_notifications": "Надсилати листа, коли в темах на які я підписаний з'являються відповіді", "settings-require-reload": "Змінам певних налаштувань необхідне перевантаження. Натисніть тут, щоб перевантажити сторінку.", "has_no_follower": "Цей користувач не має відстежувачів :(", "follows_no_one": "Цей користувач нікого не відстежує :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Звук вихідного повідомлення", "notification-sound": "Звук сповіщення", "no-sound": "Без звуку", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Налаштування перегляду", "open_links_in_new_tab": "Відкривати зовнішні посилання у новій вкладці", "enable_topic_searching": "Увімкнути пошук у темах", @@ -123,6 +126,9 @@ "sso.title": "Сервіси єдиного входу", "sso.associated": "Зв'язані з", "sso.not-associated": "Натисніть тут, щоб зв'язати з", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Останні скарги", "info.no-flags": "Не знайдено постів зі скаргами", "info.ban-history": "Історія банів", diff --git a/public/language/vi/admin/appearance/customise.json b/public/language/vi/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/vi/admin/appearance/customise.json +++ b/public/language/vi/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/vi/admin/menu.json b/public/language/vi/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/vi/admin/menu.json +++ b/public/language/vi/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/vi/admin/settings/notifications.json b/public/language/vi/admin/settings/notifications.json index 4eff7f341a..da6c9680a3 100644 --- a/public/language/vi/admin/settings/notifications.json +++ b/public/language/vi/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "Notifications", "welcome-notification": "Welcome Notification", - "welcome-notification-link": "Welcome Notification Link" + "welcome-notification-link": "Welcome Notification Link", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/vi/admin/settings/post.json b/public/language/vi/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/vi/admin/settings/post.json +++ b/public/language/vi/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/vi/admin/settings/user.json b/public/language/vi/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/vi/admin/settings/user.json +++ b/public/language/vi/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/vi/email.json b/public/language/vi/email.json index 9cab607e01..5199f136a5 100644 --- a/public/language/vi/email.json +++ b/public/language/vi/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "Thông báo tin nhắn này được gửi tới dựa theo cài đặt theo dõi của bạn.", "notif.post.cta": "Nhấn vào đây để đọc toàn bộ chủ đề", "notif.post.unsub.info": "Thông báo bài viết này được gửi cho bạn dựa tên thiết lập nhận thông báo của bạn", + "notif.cta": "Click here to go to forum", "test.text1": "Đây là email kiểm tra xem chức năng gửi mail trên hệ thống NodeBB của bạn có hoạt động tốt hay không.", "unsub.cta": "Nhấn vào đây để thay đổi cài đặt.", "banned.subject": "You have been banned from %1", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 5bdefda0a5..894ab8a3c6 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "Bạn không có đủ phiếu tín nhiệm để downvote bài này", "not-enough-reputation-to-flag": "Bạn không đủ tín nhiệm để đánh dấu bài viết này", "already-flagged": "Bạn đã gắn cờ cho bài viết này", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB gặp lỗi trong khi tải lại: \"%1\". NodeBB sẽ tiếp tục hoạt động với dữ liệu trước đó, tuy nhiên bạn nên tháo gỡ những gì bạn vừa thực hiện trước khi tải lại.", "registration-error": "Lỗi đăng kí", "parse-error": "Có gì không ổn khi nhận kết quả từ máy chủ", "wrong-login-type-email": "Xin vui lòng sửa dụng email của bạn để đăng nhập", "wrong-login-type-username": "Vui lòng sử dụng tên đăng nhập của bạn để đăng nhập", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "Bạn đã sử dụng hết số lượng lời mời bạn có thể gửi (%1 đã gửi trên tổng số %2 được cho phép)", "no-session-found": "Không tìm thấy phiên đăng nhập!", "not-in-room": "Thành viên không có trong phòng", @@ -132,5 +134,6 @@ "no-users-selected": "Chưa có người dùng(s) nào", "invalid-home-page-route": "Đường dẫn trang chủ không hợp lệ", "invalid-session": "Không đúng session", - "invalid-session-text": "Có vẻ như phiên đăng nhập của bạn đã không còn hoạt động nữa, hoặc không còn đúng với thông tin trên máy chủ. Vui lòng tải lại trang này" + "invalid-session-text": "Có vẻ như phiên đăng nhập của bạn đã không còn hoạt động nữa, hoặc không còn đúng với thông tin trên máy chủ. Vui lòng tải lại trang này", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json index 74e6ae5753..1f3e674954 100644 --- a/public/language/vi/notifications.json +++ b/public/language/vi/notifications.json @@ -9,6 +9,7 @@ "continue_to": "Tiếp tục tới %1", "return_to": "Quay lại %1", "new_notification": "Thông báo mới", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "Bạn có thông báo chưa đọc", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "Đã xác nhận email", "email-confirmed-message": "Cảm ơn bạn đã xác nhận địa chỉ email của bạn. Tài khoản của bạn đã được kích hoạt đầy đủ.", "email-confirm-error-message": "Đã có lỗi khi xác nhận địa chỉ email. Có thể đoạn mã không đúng hoặc đã hết hạn.", - "email-confirm-sent": "Email xác nhận đã gửi." + "email-confirm-sent": "Email xác nhận đã gửi.", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index d3379b29fd..6f8290fa75 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "Bạn có muốn phục hồi chủ đề này?", "thread_tools.purge": "Xóa hẳn chủ đề", "thread_tools.purge_confirm": "Bạn có muốn xóa hẳn chủ đề này?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "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?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 bài viết(s) đã được gửi", "fork_success": "Tạo bản sao thành công! Nhấn vào đây để chuyển tới chủ đề vừa tạo.", "delete_posts_instruction": "Chọn những bài viết bạn muốn xoá", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Nhập tiêu đề cho chủ đề của bạn tại đây...", "composer.handle_placeholder": "Tên", "composer.discard": "Huỷ bỏ", diff --git a/public/language/vi/user.json b/public/language/vi/user.json index eb0b34313f..fb7413330f 100644 --- a/public/language/vi/user.json +++ b/public/language/vi/user.json @@ -79,8 +79,6 @@ "digest_daily": "Hàng ngày", "digest_weekly": "Hàng tuần", "digest_monthly": "Hàng tháng", - "send_chat_notifications": "Gửi một email nếu có tin nhắn chat mới đến và tôi không online", - "send_post_notifications": "Gửi email khi có trả lời mới trong chủ đề mà tôi subscribe", "settings-require-reload": "Một số thay đổi trong cài đặt đòi hỏi tải lại. Nhấn vào đây để tải lại trang.", "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 :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "Âm báo tin nhắn đi", "notification-sound": "Âm thanh thông báo", "no-sound": "Không có âm thanh", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "Đang xem cài đặt", "open_links_in_new_tab": "Mở link trong tab mới.", "enable_topic_searching": "Bật In-topic Searching", @@ -123,6 +126,9 @@ "sso.title": "Đăng nhập một lần", "sso.associated": "Đã liên kết với", "sso.not-associated": "Nhấn vào đây để liên kết với", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "Cờ mới nhất", "info.no-flags": "Không có bài viết nào bị gắn c", "info.ban-history": "Lịch sử khóa tài khoản gần đây", diff --git a/public/language/zh-CN/admin/appearance/customise.json b/public/language/zh-CN/admin/appearance/customise.json index cc9050e9e0..8dfb53f0b1 100644 --- a/public/language/zh-CN/admin/appearance/customise.json +++ b/public/language/zh-CN/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "在这里输入自定义 CSS 变量声明,它们将被添加在样式中。", "custom-css.enable": "启用自定义 CSS", + "custom-js": "自定义 Javascript", + "custom-js.description": "在这里输入你想在页面加载完成后执行的 Javascript 代码。", + "custom-js.enable": "启用自定义 Javascript", + "custom-header": "自定义 Header", - "custom-header.description": "请输入自定义的 HTML 代码 (如 JavaScript,Meta Tags 等),这些代码会被添加到论坛的 <head> 部分。", + "custom-header.description": "在这里输入自定义的 HTML 代码 (如 JavaScript,Meta Tags 等),这些代码会被添加到论坛的 <head> 部分。 (您可以在这里使用<script> 标签,但我们建议您将您的 JavaScript 写到 自定义 Javascript 中)", "custom-header.enable": "启用自定义 Header", "custom-css.livereload": "启用实时重载", diff --git a/public/language/zh-CN/admin/menu.json b/public/language/zh-CN/admin/menu.json index 24e95dc2a8..943d7c8b76 100644 --- a/public/language/zh-CN/admin/menu.json +++ b/public/language/zh-CN/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "界面", "appearance/themes": "主题", "appearance/skins": "皮肤", - "appearance/customise": "自定义 HTML&CSS", + "appearance/customise": "自定义代码 (HTML/JavaScript/CSS)", "section-extend": "扩展", "extend/plugins": "插件", diff --git a/public/language/zh-CN/admin/settings/notifications.json b/public/language/zh-CN/admin/settings/notifications.json index fdda86bfaf..bd4ee2967f 100644 --- a/public/language/zh-CN/admin/settings/notifications.json +++ b/public/language/zh-CN/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "通知", "welcome-notification": "欢迎通知", - "welcome-notification-link": "欢迎通知链接" + "welcome-notification-link": "欢迎通知链接", + "welcome-notification-uid": "用户欢迎通知 (UID)" } \ 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 6fd9894103..fcddda5165 100644 --- a/public/language/zh-CN/admin/settings/post.json +++ b/public/language/zh-CN/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "从旧到新", "sorting.newest-to-oldest": "从新到旧", "sorting.most-votes": "最多投票", + "sorting.most-posts": "最多回复", "sorting.topic-default": "默认主题排序", "restrictions": "发帖限制", "restrictions.post-queue": "启用发布队列", diff --git a/public/language/zh-CN/admin/settings/user.json b/public/language/zh-CN/admin/settings/user.json index 37915f486e..113bfec19d 100644 --- a/public/language/zh-CN/admin/settings/user.json +++ b/public/language/zh-CN/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "主题", "disable-user-skins": "阻止用户选择自定义皮肤", "account-protection": "帐号保护", + "admin-relogin-duration": "管理面板无操作自动退出时长 (分钟)", + "admin-relogin-duration-help": "访问管理面板一段时间后需要重新登录以保证管理面板的安全,设置为0以禁用。", "login-attempts": "每小时尝试登录次数", "login-attempts-help": "如果用户的尝试登录次数超过此界限,该帐号将会被被锁定预设的时间。", "lockout-duration": "帐户锁定时间(分钟)", diff --git a/public/language/zh-CN/email.json b/public/language/zh-CN/email.json index 75ff03cf23..ce4228fd49 100644 --- a/public/language/zh-CN/email.json +++ b/public/language/zh-CN/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "根据您的订阅设置,为您发送此聊天提醒。", "notif.post.cta": "点击这里阅读全主题。", "notif.post.unsub.info": "根据您的订阅设置,为您发送此回帖提醒。", + "notif.cta": "点击这里前往论坛", "test.text1": "这是一封测试邮件,用来验证 NodeBB 的邮件配置是否设置正确。", "unsub.cta": "点击这里修改这些设置", "banned.subject": "您已被封禁从 %1", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index 90827ce8f4..d0f3a62642 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "您的声望不足以踩此帖", "not-enough-reputation-to-flag": "您的声望不足以举报此帖", "already-flagged": "您已举报此帖", + "self-vote": "你不能在您自己的帖子内投票", "reload-failed": "刷新 NodeBB 时遇到问题: \"%1\"。NodeBB 保持给已连接的客户端服务,您应该撤销刷新前做的更改。", "registration-error": "注册错误", "parse-error": "服务器响应解析出错", "wrong-login-type-email": "请输入您的电子邮箱地址登录", "wrong-login-type-username": "请输入您的用户名登录", + "sso-registration-disabled": "已经禁止注册注册 %1 账户, 请使用邮箱地址注册", "invite-maximum-met": "您的邀请人数超出了上限 (%1 超过了 %2)。", "no-session-found": "未登录!", "not-in-room": "用户已不在聊天室中", @@ -132,5 +134,6 @@ "no-users-selected": "尚未选择用户", "invalid-home-page-route": "无效的首页路径", "invalid-session": "Session 无法匹配", - "invalid-session-text": "您的登入状态已经失效,或者是与服务器信息不匹配。请刷新此页面。" + "invalid-session-text": "您的登入状态已经失效,或者是与服务器信息不匹配。请刷新此页面。", + "no-topics-selected": "没有主题被选中!" } \ No newline at end of file diff --git a/public/language/zh-CN/notifications.json b/public/language/zh-CN/notifications.json index 85366895e9..e9f73293f6 100644 --- a/public/language/zh-CN/notifications.json +++ b/public/language/zh-CN/notifications.json @@ -9,6 +9,7 @@ "continue_to": "继续前往 %1", "return_to": "返回 %1", "new_notification": "新通知", + "new_notification_from": "您有一条来自 %1 的新通知", "you_have_unread_notifications": "您有未读的通知。", "all": "所有", "topics": "主题", @@ -45,5 +46,19 @@ "email-confirmed": "电子邮箱已确认", "email-confirmed-message": "感谢您验证您的电子邮箱。您的帐户现已完全激活。", "email-confirm-error-message": "验证的您电子邮箱地址时出现了问题。可能是因为验证码无效或已过期。", - "email-confirm-sent": "确认邮件已发送。" + "email-confirm-sent": "确认邮件已发送。", + "none": "无", + "notification_only": "用通知提醒我", + "email_only": "用邮件提醒我", + "notification_and_email": "同时使用 通知 和 邮件 提醒我", + "notificationType_upvote": "当有人顶了我的帖子时", + "notificationType_new-topic": "当有人回复我的帖子时", + "notificationType_new-reply": "当您正在查看的主题中有新回复时", + "notificationType_follow": "当有人关注你时", + "notificationType_new-chat": "当你收到聊天消息时", + "notificationType_group-invite": "当你收到群组邀请时", + "notificationType_new-register": "当有人被添加到申请队列时", + "notificationType_post-queue": "当有新帖子等待审核时", + "notificationType_new-post-flag": "当有新的帖子举报时", + "notificationType_new-user-flag": "当有新的用户信息举报时" } \ No newline at end of file diff --git a/public/language/zh-CN/topic.json b/public/language/zh-CN/topic.json index 63d808ecd6..92dfcc59f2 100644 --- a/public/language/zh-CN/topic.json +++ b/public/language/zh-CN/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "确定要恢复此主题吗?", "thread_tools.purge": "清除主题", "thread_tools.purge_confirm": "确认清除此主题吗?", + "thread_tools.merge_topics": "合并主题", + "thread_tools.merge": "合并", "topic_move_success": "此主题已成功移到 %1", "post_delete_confirm": "确定删除此帖吗?", "post_restore_confirm": "确定恢复此帖吗?", @@ -89,6 +91,7 @@ "fork_pid_count": "选择了 %1 个帖子", "fork_success": "成功分割主题! 点这里跳转到分割后的主题。", "delete_posts_instruction": "点击想要删除/永久删除的帖子", + "merge_topics_instruction": "点击你想合并的主题", "composer.title_placeholder": "在此输入您主题的标题...", "composer.handle_placeholder": "姓名", "composer.discard": "撤销", diff --git a/public/language/zh-CN/user.json b/public/language/zh-CN/user.json index c6aa9f9d89..170700628e 100644 --- a/public/language/zh-CN/user.json +++ b/public/language/zh-CN/user.json @@ -79,8 +79,6 @@ "digest_daily": "每天", "digest_weekly": "每周", "digest_monthly": "每月", - "send_chat_notifications": "当我不在线并收到新的聊天消息时,给我发送邮件通知", - "send_post_notifications": "当我订阅的主题有新回复时,给我发送邮件通知", "settings-require-reload": "某些设置变更需要刷新页面。点击这里刷新页面。", "has_no_follower": "此用户还没有粉丝 :(", "follows_no_one": "此用户尚未关注任何人 :(", @@ -103,6 +101,11 @@ "outgoing-message-sound": "消息送出提示音", "notification-sound": "通知提示音", "no-sound": "无提示音", + "upvote-notif-freq": "帖子被顶的通知频率", + "upvote-notif-freq.all": "每一次被顶都通知我", + "upvote-notif-freq.everyTen": "每10次被顶通知我一次", + "upvote-notif-freq.logarithmic": "当被顶的数目为10, 100, 1000...时通知我", + "upvote-notif-freq.disabled": "任何时候都不要通知我", "browsing": "浏览设置", "open_links_in_new_tab": "在新标签打开外部链接", "enable_topic_searching": "启用主题内搜索", @@ -123,6 +126,9 @@ "sso.title": "单点登录服务", "sso.associated": "已关联到", "sso.not-associated": "点击这里来关联", + "sso.dissociate": "解除关联", + "sso.dissociate-confirm-title": "确认解除关联", + "sso.dissociate-confirm": "你确定要将你的账户与 %1 解除关联吗?", "info.latest-flags": "最新举报", "info.no-flags": "没有找到被举报的帖子", "info.ban-history": "最近封禁历史", diff --git a/public/language/zh-TW/admin/appearance/customise.json b/public/language/zh-TW/admin/appearance/customise.json index 5095f7a937..a1220ec96d 100644 --- a/public/language/zh-TW/admin/appearance/customise.json +++ b/public/language/zh-TW/admin/appearance/customise.json @@ -3,8 +3,12 @@ "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.enable": "Enable Custom CSS", + "custom-js": "Custom Javascript", + "custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.", + "custom-js.enable": "Enable Custom Javascript", + "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", + "custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <head> section of your forum's markup. Script tags are allowed, but are discouraged, as the Custom Javascript tab is available.", "custom-header.enable": "Enable Custom Header", "custom-css.livereload": "Enable Live Reload", diff --git a/public/language/zh-TW/admin/menu.json b/public/language/zh-TW/admin/menu.json index d42af99bce..2b836ed0f7 100644 --- a/public/language/zh-TW/admin/menu.json +++ b/public/language/zh-TW/admin/menu.json @@ -39,7 +39,7 @@ "section-appearance": "Appearance", "appearance/themes": "Themes", "appearance/skins": "Skins", - "appearance/customise": "Custom HTML & CSS", + "appearance/customise": "Custom Content (HTML/JS/CSS)", "section-extend": "Extend", "extend/plugins": "Plugins", diff --git a/public/language/zh-TW/admin/settings/notifications.json b/public/language/zh-TW/admin/settings/notifications.json index 6d4a1e4771..ad5bf1c7d0 100644 --- a/public/language/zh-TW/admin/settings/notifications.json +++ b/public/language/zh-TW/admin/settings/notifications.json @@ -1,5 +1,6 @@ { "notifications": "告示", "welcome-notification": "歡迎告示", - "welcome-notification-link": "歡迎告示連結" + "welcome-notification-link": "歡迎告示連結", + "welcome-notification-uid": "Welcome Notification User (UID)" } \ No newline at end of file diff --git a/public/language/zh-TW/admin/settings/post.json b/public/language/zh-TW/admin/settings/post.json index a789025597..7cef2f34a0 100644 --- a/public/language/zh-TW/admin/settings/post.json +++ b/public/language/zh-TW/admin/settings/post.json @@ -4,6 +4,7 @@ "sorting.oldest-to-newest": "Oldest to Newest", "sorting.newest-to-oldest": "Newest to Oldest", "sorting.most-votes": "Most Votes", + "sorting.most-posts": "Most Posts", "sorting.topic-default": "Default Topic Sorting", "restrictions": "Posting Restrictions", "restrictions.post-queue": "Enable post queue", diff --git a/public/language/zh-TW/admin/settings/user.json b/public/language/zh-TW/admin/settings/user.json index a8bc2b176e..cbdd4ee91c 100644 --- a/public/language/zh-TW/admin/settings/user.json +++ b/public/language/zh-TW/admin/settings/user.json @@ -19,6 +19,8 @@ "themes": "Themes", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", + "admin-relogin-duration": "Admin relogin duration (minutes)", + "admin-relogin-duration-help": "After a set amount of time accessing the admin section will require re-login, set to 0 to disable", "login-attempts": "Login attempts per hour", "login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time", "lockout-duration": "Account Lockout Duration (minutes)", diff --git a/public/language/zh-TW/email.json b/public/language/zh-TW/email.json index 3e95aee620..2f4a651286 100644 --- a/public/language/zh-TW/email.json +++ b/public/language/zh-TW/email.json @@ -30,6 +30,7 @@ "notif.chat.unsub.info": "本聊天通知按你的訂閱設置發送給你。", "notif.post.cta": "點擊此處來閱讀完整主題", "notif.post.unsub.info": "本張貼通知按你的訂閱設置發送給你。", + "notif.cta": "Click here to go to forum", "test.text1": "這是一個測試電子郵件,用於確認你的NodeBB郵件功能是否設置正確。", "unsub.cta": "點擊此處來更改這些設置", "banned.subject": "You have been banned from %1", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index 4408dcb9ac..152dad5f0d 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -119,11 +119,13 @@ "not-enough-reputation-to-downvote": "你沒有足夠的信譽可以對這個張貼進行反向投票", "not-enough-reputation-to-flag": "你沒有足夠的信譽來舉報這個帖子", "already-flagged": "你已經對這個張貼標記過了", + "self-vote": "You cannot vote on your own post", "reload-failed": "NodeBB重載\"%1\"時遇到了問題。 NodeBB將繼續提供現有的客戶端資源,但請你撤消重載前的動作。", "registration-error": "註冊錯誤", "parse-error": "當剖析伺服器回應時發生了某個錯誤", "wrong-login-type-email": "請使用你的電子郵件進行登入", "wrong-login-type-username": "請使用你的帳號進行登入", + "sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first", "invite-maximum-met": "你已經邀請最多可邀請的人數限制 (%1 於 %2)。", "no-session-found": "沒有找到登入的連線階段!", "not-in-room": "使用者沒有在聊天室中", @@ -132,5 +134,6 @@ "no-users-selected": "沒有選定使用者", "invalid-home-page-route": "無效的首頁路由", "invalid-session": "會話階段錯誤", - "invalid-session-text": "看起來你的登入會話階段已經無效,或是不符合於伺服器。請重新整理這個頁面。" + "invalid-session-text": "看起來你的登入會話階段已經無效,或是不符合於伺服器。請重新整理這個頁面。", + "no-topics-selected": "No topics selected!" } \ No newline at end of file diff --git a/public/language/zh-TW/notifications.json b/public/language/zh-TW/notifications.json index 7d8351c56e..17f11f3358 100644 --- a/public/language/zh-TW/notifications.json +++ b/public/language/zh-TW/notifications.json @@ -9,6 +9,7 @@ "continue_to": "繼續前往 %1", "return_to": "返回 %1", "new_notification": "新訊息通知", + "new_notification_from": "You have a new Notification from %1", "you_have_unread_notifications": "你有未讀的通知。", "all": "All", "topics": "Topics", @@ -45,5 +46,19 @@ "email-confirmed": "已確認電子郵件", "email-confirmed-message": "感謝你驗證電子郵件。你的帳戶現已完整的啟動。", "email-confirm-error-message": "驗證你的電子郵件地址時發生問題。也許是啟動碼無效或是已過期。", - "email-confirm-sent": "已發送確認電子郵件。" + "email-confirm-sent": "已發送確認電子郵件。", + "none": "None", + "notification_only": "Notification Only", + "email_only": "Email Only", + "notification_and_email": "Notification & Email", + "notificationType_upvote": "When someone upvotes your post", + "notificationType_new-topic": "When someone you follow posts a topic", + "notificationType_new-reply": "When a new reply is posted in a topic you are watching", + "notificationType_follow": "When someone starts following you", + "notificationType_new-chat": "When you receive a chat message", + "notificationType_group-invite": "When you receive a group invite", + "notificationType_new-register": "When someone gets added to registration queue", + "notificationType_post-queue": "When a new post is queued", + "notificationType_new-post-flag": "When a post is flagged", + "notificationType_new-user-flag": "When a user is flagged" } \ No newline at end of file diff --git a/public/language/zh-TW/topic.json b/public/language/zh-TW/topic.json index 07b37ee21e..bcfd71fb09 100644 --- a/public/language/zh-TW/topic.json +++ b/public/language/zh-TW/topic.json @@ -68,6 +68,8 @@ "thread_tools.restore_confirm": "你確定你要恢復這個主題嗎?", "thread_tools.purge": "清除主題", "thread_tools.purge_confirm": "你確定要清除這個主題?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "主題已成功移至 %1", "post_delete_confirm": "你確定要刪除這文章嗎?", "post_restore_confirm": "你確定要還原這文章嗎?", @@ -89,6 +91,7 @@ "fork_pid_count": "%1 張貼已選定", "fork_success": "成功分叉成新的主題!點擊這裡進入新的主題。", "delete_posts_instruction": "點擊你想要刪除/清除的張貼", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "輸入標題...", "composer.handle_placeholder": "名字", "composer.discard": "放棄", diff --git a/public/language/zh-TW/user.json b/public/language/zh-TW/user.json index 190ce21484..0455cb32b7 100644 --- a/public/language/zh-TW/user.json +++ b/public/language/zh-TW/user.json @@ -79,8 +79,6 @@ "digest_daily": "每日", "digest_weekly": "每週", "digest_monthly": "每月", - "send_chat_notifications": "如果有新的聊天消息而我不在線,發送郵件給我", - "send_post_notifications": "當我訂閱的主題有新回覆時寄送Email給我", "settings-require-reload": "有些設定的更動是需要重新整理。點擊這裡來重新整理頁面。", "has_no_follower": "該使用者還沒有被任何人關注。", "follows_no_one": "該使用者還沒有關注過任何人。", @@ -103,6 +101,11 @@ "outgoing-message-sound": "發出訊息音效", "notification-sound": "通知音效", "no-sound": "沒有聲音", + "upvote-notif-freq": "Upvote Notification Frequency", + "upvote-notif-freq.all": "All Upvotes", + "upvote-notif-freq.everyTen": "Every Ten Upvotes", + "upvote-notif-freq.logarithmic": "On 10, 100, 1000...", + "upvote-notif-freq.disabled": "Disabled", "browsing": "瀏覽設定", "open_links_in_new_tab": "在新的資料標籤裡打開外部的連結", "enable_topic_searching": "啟用在主題中的搜尋", @@ -123,6 +126,9 @@ "sso.title": "單一簽入SSO服務", "sso.associated": "關連於", "sso.not-associated": "點擊這裡進行關連於", + "sso.dissociate": "Dissociate", + "sso.dissociate-confirm-title": "Confirm Dissociation", + "sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?", "info.latest-flags": "最近標註", "info.no-flags": "沒有找到標註的張貼", "info.ban-history": "最近禁用歷史", diff --git a/public/less/install.less b/public/less/install.less index 1289c62941..a9f59dbb7b 100644 --- a/public/less/install.less +++ b/public/less/install.less @@ -1,3 +1,48 @@ +.working { + width: 24px; + height: 24px; + + position: relative; + display: inline-block; + vertical-align: bottom; + + &::before, &::after { + content: ' '; + + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #fff; + opacity: 0.6; + position: absolute; + top: 0; + left: 0; + + -webkit-animation: sk-bounce 2.0s infinite ease-in-out; + animation: sk-bounce 2.0s infinite ease-in-out; + } + + &::after { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; + } +} + +@-webkit-keyframes sk-bounce { + 0%, 100% { -webkit-transform: scale(0.0) } + 50% { -webkit-transform: scale(1.0) } +} + +@keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + -webkit-transform: scale(0.0); + } 50% { + transform: scale(1.0); + -webkit-transform: scale(1.0); + } +} + .btn, .form-control, .navbar { border-radius: 0; } @@ -8,7 +53,7 @@ } body, small, p, div { - font-family: "Roboto", sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .input-row { diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index 8c22a65720..b6c7b7aa03 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -306,7 +306,7 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator, var timeoutId = 0; - $('#search-user-name, #search-user-email, #search-user-ip').on('keyup', function () { + $('#search-user-uid, #search-user-name, #search-user-email, #search-user-ip').on('keyup', function () { if (timeoutId !== 0) { clearTimeout(timeoutId); timeoutId = 0; diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js index 6198984e19..493afc91f0 100644 --- a/public/src/admin/settings.js +++ b/public/src/admin/settings.js @@ -143,7 +143,7 @@ define('admin/settings', ['uploader'], function (uploader) { if (ajaxify.currentPage === 'admin/general/sounds') { ajaxify.refresh(); } else { - $('#' + uploadBtn.attr('data-target')).val(image); + $('#' + uploadBtn.attr('data-target')).val([image, Date.now()].join('?v=')); } }); }); diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 0be6453a88..39cbb48c48 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -37,6 +37,7 @@ $(document).ready(function () { } }); + ajaxify.count = 0; ajaxify.currentPage = null; ajaxify.go = function (url, callback, quiet) { @@ -100,11 +101,15 @@ $(document).ready(function () { return true; }; + ajaxify.isCold = function () { + return ajaxify.count <= 1; + }; + ajaxify.handleRedirects = function (url) { url = ajaxify.removeRelativePath(url.replace(/^\/|\/$/g, '')).toLowerCase(); var isClientToAdmin = url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0; var isAdminToClient = !url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') === 0; - var uploadsOrApi = url.startsWith('assets/uploads') || url.startsWith('uploads') || url.startsWith('api'); + var uploadsOrApi = url.startsWith('assets/') || url.startsWith('uploads') || url.startsWith('api'); if (isClientToAdmin || isAdminToClient || uploadsOrApi) { window.open(RELATIVE_PATH + '/' + url, '_top'); @@ -113,7 +118,6 @@ $(document).ready(function () { return false; }; - ajaxify.start = function (url) { url = ajaxify.removeRelativePath(url.replace(/^\/|\/$/g, '')); @@ -123,6 +127,8 @@ $(document).ready(function () { $(window).trigger('action:ajaxify.start', payload); + ajaxify.count += 1; + return payload.url; }; @@ -197,7 +203,6 @@ $(document).ready(function () { ajaxify.end = function (url, tpl_url) { var count = 2; - function done() { count -= 1; if (count === 0) { @@ -205,17 +210,11 @@ $(document).ready(function () { } } ajaxify.loadScript(tpl_url, done); - ajaxify.widgets.render(tpl_url, done); $(window).trigger('action:ajaxify.contentLoaded', { url: url, tpl: tpl_url }); app.processPage(); - - var timeElapsed = Date.now() - ajaxifyTimer; - if (config.environment === 'development' && !isNaN(timeElapsed)) { - console.info('[ajaxify /' + url + '] Time elapsed:', timeElapsed + 'ms'); - } }; ajaxify.parseData = function () { diff --git a/public/src/app.js b/public/src/app.js index 421cf71943..f56d894de8 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -9,7 +9,9 @@ app.widgets = {}; app.cacheBuster = null; (function () { - var showWelcomeMessage = !!utils.params().loggedin; + var params = utils.params(); + var showWelcomeMessage = !!params.loggedin; + var registerMessage = params.register; require(['benchpress'], function (Benchpress) { Benchpress.setGlobal('config', config); @@ -276,7 +278,9 @@ app.cacheBuster = null; app.replaceSelfLinks(); // Scroll back to top of page - window.scrollTo(0, 0); + if (!ajaxify.isCold()) { + window.scrollTo(0, 0); + } }; app.showMessages = function () { @@ -286,9 +290,12 @@ app.cacheBuster = null; title: '[[global:welcome_back]] ' + app.user.username + '!', message: '[[global:you_have_successfully_logged_in]]', }, + register: { + format: 'modal', + }, }; - function showAlert(type) { + function showAlert(type, message) { switch (messages[type].format) { case 'alert': app.alert({ @@ -301,7 +308,7 @@ app.cacheBuster = null; case 'modal': require(['translator'], function (translator) { - translator.translate(messages[type].message, function (translated) { + translator.translate(message || messages[type].message, function (translated) { bootbox.alert({ title: messages[type].title, message: translated, @@ -318,6 +325,12 @@ app.cacheBuster = null; showAlert('login'); }); } + if (registerMessage) { + $(document).ready(function () { + showAlert('register', decodeURIComponent(registerMessage)); + registerMessage = false; + }); + } }; app.openChat = function (roomId, uid) { diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index 7fa2026823..027e328037 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -239,25 +239,18 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' if (!url) { return false; } - socket.emit('user.uploadProfileImageFromUrl', { - uid: ajaxify.data.uid, + + uploadModal.modal('hide'); + + pictureCropper.handleImageCrop({ url: url, - }, function (err, url) { - if (err) { - return app.alertError(err); - } + socketMethod: 'user.uploadCroppedPicture', + aspectRatio: '1 / 1', + allowSkippingCrop: false, + paramName: 'uid', + paramValue: ajaxify.data.theirid, + }, onUploadComplete); - uploadModal.modal('hide'); - - pictureCropper.handleImageCrop({ - url: url, - socketMethod: 'user.uploadCroppedPicture', - aspectRatio: '1 / 1', - allowSkippingCrop: false, - paramName: 'uid', - paramValue: ajaxify.data.theirid, - }, onUploadComplete); - }); return false; }); }); diff --git a/public/src/client/category/tools.js b/public/src/client/category/tools.js index 0f0dc7b77d..dfa31ca86a 100644 --- a/public/src/client/category/tools.js +++ b/public/src/client/category/tools.js @@ -4,10 +4,11 @@ define('forum/category/tools', [ 'forum/topic/move', + 'forum/topic/merge', 'topicSelect', 'components', 'translator', -], function (move, topicSelect, components, translator) { +], function (move, merge, topicSelect, components, translator) { var CategoryTools = {}; CategoryTools.init = function (cid) { @@ -34,60 +35,65 @@ define('forum/category/tools', [ components.get('topic/lock').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - socket.emit('topics.lock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } + socket.emit('topics.lock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); return false; }); components.get('topic/unlock').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - socket.emit('topics.unlock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } + socket.emit('topics.unlock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); return false; }); components.get('topic/pin').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - socket.emit('topics.pin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } + socket.emit('topics.pin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); return false; }); components.get('topic/unpin').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - socket.emit('topics.unpin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } + socket.emit('topics.unpin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); return false; }); components.get('topic/mark-unread-for-all').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - socket.emit('topics.markAsUnreadForAll', tids, function (err) { - if (err) { - return app.alertError(err.message); - } - app.alertSuccess('[[topic:markAsUnreadForAll.success]]'); - tids.forEach(function (tid) { - $('[component="category/topic"][data-tid="' + tid + '"]').addClass('unread'); - }); - onCommandComplete(); - }); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } - + socket.emit('topics.markAsUnreadForAll', tids, function (err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('[[topic:markAsUnreadForAll.success]]'); + tids.forEach(function (tid) { + $('[component="category/topic"][data-tid="' + tid + '"]').addClass('unread'); + }); + onCommandComplete(); + }); return false; }); components.get('topic/move').on('click', function () { var tids = topicSelect.getSelectedTids(); - if (tids.length) { - move.init(tids, cid, onCommandComplete); + if (!tids.length) { + return app.alertError('[[error:no-topics-selected]]'); } + move.init(tids, cid, onCommandComplete); return false; }); @@ -101,6 +107,8 @@ define('forum/category/tools', [ }); }); + merge.init(); + CategoryTools.removeListeners(); socket.on('event:topic_deleted', setDeleteState); socket.on('event:topic_restored', setDeleteState); @@ -114,7 +122,7 @@ define('forum/category/tools', [ function categoryCommand(command, tids) { if (!tids.length) { - return; + return app.alertError('[[error:no-topics-selected]]'); } translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function (msg) { @@ -239,7 +247,8 @@ define('forum/category/tools', [ } function handlePinnedTopicSort() { - if (!ajaxify.data.privileges.isAdminOrMod) { + var env = utils.findBootstrapEnvironment(); + if (!ajaxify.data.privileges.isAdminOrMod || env === 'xs' || env === 'sm') { return; } app.loadJQueryUI(function () { diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 600331dc6f..f82623fd5d 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -90,7 +90,7 @@ define('forum/chats', [ return; } loading = true; - var start = parseInt($('.chat-content').children('[data-index]').first().attr('data-index'), 10) + 1; + var start = parseInt(el.children('[data-mid]').length, 10); socket.emit('modules.chats.getMessages', { roomId: roomId, uid: uid, diff --git a/public/src/client/register.js b/public/src/client/register.js index 4289c75d10..5d1794e9d3 100644 --- a/public/src/client/register.js +++ b/public/src/client/register.js @@ -85,13 +85,17 @@ define('forum/register', ['translator', 'zxcvbn'], function (translator, zxcvbn) return; } if (data.referrer) { - window.location.href = data.referrer; + var pathname = utils.urlToLocation(data.referrer).pathname; + + var params = utils.params({ url: data.referrer }); + params.registered = true; + var qs = decodeURIComponent($.param(params)); + + window.location.href = pathname + '?' + qs; } else if (data.message) { - require(['translator'], function (translator) { - translator.translate(data.message, function (msg) { - bootbox.alert(msg); - ajaxify.go('/'); - }); + translator.translate(data.message, function (msg) { + bootbox.alert(msg); + ajaxify.go('/'); }); } }, diff --git a/public/src/client/top.js b/public/src/client/top.js new file mode 100644 index 0000000000..9e80cb668a --- /dev/null +++ b/public/src/client/top.js @@ -0,0 +1,52 @@ +'use strict'; + +define('forum/top', ['forum/recent', 'forum/infinitescroll'], function (recent, infinitescroll) { + var Top = {}; + + $(window).on('action:ajaxify.start', function (ev, data) { + if (ajaxify.currentPage !== data.url) { + recent.removeListeners(); + } + }); + + Top.init = function () { + app.enterRoom('top_topics'); + + recent.watchForNewPosts(); + + recent.handleCategorySelection(); + + $('#new-topics-alert').on('click', function () { + $(this).addClass('hide'); + }); + + if (!config.usePagination) { + infinitescroll.init(loadMoreTopics); + } + + $(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); + }; + + function loadMoreTopics(direction) { + if (direction < 0 || !$('[component="category"]').length) { + return; + } + + infinitescroll.loadMore('topics.loadMoreTopTopics', { + after: $('[component="category"]').attr('data-nextstart'), + count: config.topicsPerPage, + cid: utils.params().cid, + filter: ajaxify.data.selectedFilter.filter, + }, function (data, done) { + if (data.topics && data.topics.length) { + recent.onTopicsLoaded('top', data.topics, true, done); + $('[component="category"]').attr('data-nextstart', data.nextStart); + } else { + done(); + $('#load-more-btn').hide(); + } + }); + } + + return Top; +}); diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 57d276d986..b3fa02b509 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -29,7 +29,6 @@ define('forum/topic', [ app.removeAlert('bookmark'); events.removeListeners(); - $(window).off('keydown', onKeyDown); require(['search'], function (search) { if (search.topicDOM.active) { @@ -63,8 +62,6 @@ define('forum/topic', [ addParentHandler(); - handleKeys(); - navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex); handleBookmark(tid); @@ -76,27 +73,6 @@ define('forum/topic', [ $(window).trigger('action:topic.loaded', ajaxify.data); }; - function handleKeys() { - if (!config.usePagination) { - $(window).off('keydown', onKeyDown).on('keydown', onKeyDown); - } - } - - function onKeyDown(ev) { - if (ev.target.nodeName === 'BODY') { - if (ev.shiftKey || ev.ctrlKey || ev.altKey) { - return; - } - if (ev.which === 36) { // home key - Topic.toTop(); - return false; - } else if (ev.which === 35) { // end key - Topic.toBottom(); - return false; - } - } - } - function handleTopicSearch() { require(['search', 'mousetrap'], function (search, mousetrap) { $('.topic-search').off('click') diff --git a/public/src/client/topic/merge.js b/public/src/client/topic/merge.js new file mode 100644 index 0000000000..473f76583c --- /dev/null +++ b/public/src/client/topic/merge.js @@ -0,0 +1,107 @@ +'use strict'; + + +define('forum/topic/merge', function () { + var Merge = {}; + var modal; + var mergeBtn; + + var selectedTids = {}; + + Merge.init = function () { + $('.category').on('click', '[component="topic/merge"]', onMergeTopicsClicked); + if (modal) { + $('[component="category/topic"]').on('click', 'a', onTopicClicked); + } + }; + + function onMergeTopicsClicked() { + if (modal) { + return; + } + app.parseAndTranslate('partials/merge_topics_modal', {}, function (html) { + modal = html; + + $('body').append(modal); + + mergeBtn = modal.find('#merge_topics_confirm'); + + modal.find('.close,#merge_topics_cancel').on('click', closeModal); + + $('[component="category/topic"]').on('click', 'a', onTopicClicked); + + showTopicsSelected(); + + mergeBtn.on('click', function () { + mergeTopics(mergeBtn); + }); + }); + } + + function onTopicClicked(ev) { + var tid = $(this).parents('[component="category/topic"]').attr('data-tid'); + var index = $(this).parents('[component="category/topic"]').attr('data-index'); + var title = ajaxify.data.topics[index] ? ajaxify.data.topics[index].title : 'No title'; + if (selectedTids[tid]) { + delete selectedTids[tid]; + } else { + selectedTids[tid] = title; + } + checkButtonEnable(); + showTopicsSelected(); + ev.preventDefault(); + ev.stopPropagation(); + return false; + } + + function mergeTopics(btn) { + btn.attr('disabled', true); + var tids = Object.keys(selectedTids); + socket.emit('topics.merge', tids, function (err) { + btn.removeAttr('disabled'); + if (err) { + return app.alertError(err.message); + } + ajaxify.go('/topic/' + tids[0]); + closeModal(); + }); + } + + function showTopicsSelected() { + var tids = Object.keys(selectedTids); + tids.sort(function (a, b) { + return a - b; + }); + + var topics = tids.map(function (tid) { + return { tid: tid, title: selectedTids[tid] }; + }); + + if (tids.length) { + app.parseAndTranslate('partials/merge_topics_modal', 'topics', { topics: topics }, function (html) { + modal.find('.topics-section').html(html); + }); + } else { + modal.find('.topics-section').translateHtml('[[error:no-topics-selected]]'); + } + } + + function checkButtonEnable() { + if (Object.keys(selectedTids).length) { + mergeBtn.removeAttr('disabled'); + } else { + mergeBtn.attr('disabled', true); + } + } + + function closeModal() { + if (modal) { + modal.remove(); + modal = null; + } + selectedTids = {}; + $('[component="category/topic"]').off('click', 'a', onTopicClicked); + } + + return Merge; +}); diff --git a/public/src/client/topic/votes.js b/public/src/client/topic/votes.js index 9bd20fc1a6..007fa5e6dd 100644 --- a/public/src/client/topic/votes.js +++ b/public/src/client/topic/votes.js @@ -70,11 +70,7 @@ define('forum/topic/votes', ['components', 'translator', 'benchpress'], function room_id: 'topic_' + ajaxify.data.tid, }, function (err) { if (err) { - if (err.message === 'self-vote') { - Votes.showVotes(post.attr('data-pid')); - } else { - app.alertError(err.message); - } + app.alertError(err.message); } }); diff --git a/public/src/installer/install.js b/public/src/installer/install.js index 9fa8a248c7..201905a3c1 100644 --- a/public/src/installer/install.js +++ b/public/src/installer/install.js @@ -46,7 +46,7 @@ $('document').ready(function () { return false; } - $('#submit .fa-spin').removeClass('hide'); + $('#submit .working').removeClass('hide'); } function activate(type, el) { @@ -112,7 +112,7 @@ $('document').ready(function () { } function launchForum() { - $('#launch .fa-spin').removeClass('hide'); + $('#launch .working').removeClass('hide'); $.post('/launch', function () { var successCount = 0; diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 77a060ed7a..07515b9834 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -210,14 +210,14 @@ function renderDigestAvatar(block) { if (block.teaser) { if (block.teaser.user.picture) { - return ''; + return ''; } - return '
' + block.teaser.user['icon:text'] + '
'; + return '
' + block.teaser.user['icon:text'] + '
'; } if (block.user.picture) { - return ''; + return ''; } - return '
' + block.user['icon:text'] + '
'; + return '
' + block.user['icon:text'] + '
'; } function userAgentIcons(data) { diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index ac6c06ac88..6c820cdd7f 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -8,12 +8,16 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co navigator.scrollActive = false; + $(window).on('action:ajaxify.start', function () { + $(window).off('keydown', onKeyDown); + }); + navigator.init = function (selector, count, toTop, toBottom, callback, calculateIndex) { index = 1; navigator.selector = selector; navigator.callback = callback; - toTop = toTop || function () {}; - toBottom = toBottom || function () {}; + navigator.toTop = toTop || function () {}; + navigator.toBottom = toBottom || function () {}; $(window).off('scroll', navigator.delayedUpdate).on('scroll', navigator.delayedUpdate); @@ -29,8 +33,8 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co $('.pagination-block .pageup').off('click').on('click', navigator.scrollUp); $('.pagination-block .pagedown').off('click').on('click', navigator.scrollDown); - $('.pagination-block .pagetop').off('click').on('click', toTop); - $('.pagination-block .pagebottom').off('click').on('click', toBottom); + $('.pagination-block .pagetop').off('click').on('click', navigator.toTop); + $('.pagination-block .pagebottom').off('click').on('click', navigator.toBottom); $('.pagination-block input').on('keydown', function (e) { if (e.which === 13) { @@ -52,10 +56,33 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co } }); + handleKeys(); + navigator.setCount(count); navigator.update(0); }; + function handleKeys() { + if (!config.usePagination) { + $(window).off('keydown', onKeyDown).on('keydown', onKeyDown); + } + } + + function onKeyDown(ev) { + if (ev.target.nodeName === 'BODY') { + if (ev.shiftKey || ev.ctrlKey || ev.altKey) { + return; + } + if (ev.which === 36 && navigator.toTop) { // home key + navigator.toTop(); + return false; + } else if (ev.which === 35 && navigator.toBottom) { // end key + navigator.toBottom(); + return false; + } + } + } + function generateUrl(index) { var pathname = window.location.pathname.replace(config.relative_path, ''); var parts = pathname.split('/'); @@ -164,13 +191,26 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co return; } index = index > count ? count : index; - - $('.pagination-block .pagination-text').translateHtml('[[global:pagination.out_of, ' + index + ', ' + count + ']]'); - var fraction = $(window).scrollTop() / ($(document).height() - $(window).height()); + var relIndex = getRelativeIndex(); + $('.pagination-block .pagination-text').translateHtml('[[global:pagination.out_of, ' + relIndex + ', ' + count + ']]'); + var fraction = relIndex / count; $('.pagination-block meter').val(fraction); $('.pagination-block .progress-bar').width((fraction * 100) + '%'); }; + function getRelativeIndex() { + var relIndex = index; + if (relIndex === 1) { + return 1; + } + if (ajaxify.data.template.topic) { + if (config.topicPostSort === 'most_votes' || config.topicPostSort === 'newest_to_oldest') { + relIndex = ajaxify.data.postcount - index + 2; + } + } + return relIndex; + } + navigator.scrollUp = function () { $('body,html').animate({ scrollTop: $(window).scrollTop() - $(window).height(), @@ -244,7 +284,7 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co } } else if (inCategory) { if (config.categoryTopicSort === 'most_posts' || config.categoryTopicSort === 'oldest_to_newest') { - index = ajaxify.data.ajaxify.data.topic_count - index; + index = ajaxify.data.topic_count - index; } } diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index b98ad68abe..817f6095b6 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -4,10 +4,7 @@ function loadClient(language, namespace) { return Promise.resolve(jQuery.getJSON(config.relative_path + '/assets/language/' + language + '/' + namespace + '.json?' + config['cache-buster'])); } - var warn = function () {}; - if (typeof config === 'object' && config.environment === 'development') { - warn = console.warn.bind(console); - } + var warn = console.warn; if (typeof define === 'function' && define.amd) { // AMD. Register as a named module define('translator', [], function () { @@ -505,7 +502,7 @@ Translator.compile = function compile() { var args = Array.prototype.slice.call(arguments, 0).map(function (text) { // escape commas and percent signs in arguments - return text.replace(/%/g, '%').replace(/,/g, ','); + return String(text).replace(/%/g, '%').replace(/,/g, ','); }); return '[[' + args.join(', ') + ']]'; diff --git a/public/vendor/jquery/sortable/Sortable.js b/public/vendor/jquery/sortable/Sortable.js index cf0b5f047b..8835d14375 100644 --- a/public/vendor/jquery/sortable/Sortable.js +++ b/public/vendor/jquery/sortable/Sortable.js @@ -7,20 +7,7 @@ (function (factory) { "use strict"; - - if (typeof define === "function" && define.amd) { - define(factory); - } - else if (typeof module != "undefined" && typeof module.exports != "undefined") { - module.exports = factory(); - } - else if (typeof Package !== "undefined") { - Sortable = factory(); // export for Meteor.js - } - else { - /* jshint sub:true */ - window["Sortable"] = factory(); - } + window.Sortable = factory(); })(function () { "use strict"; diff --git a/src/admin/search.js b/src/admin/search.js index 1803f3298c..6f9792138e 100644 --- a/src/admin/search.js +++ b/src/admin/search.js @@ -63,12 +63,11 @@ var fallbackCacheInProgress = {}; var fallbackCache = {}; function initFallback(namespace, callback) { - fs.readFile(path.resolve(nconf.get('views_dir'), namespace + '.tpl'), function (err, file) { + fs.readFile(path.resolve(nconf.get('views_dir'), namespace + '.tpl'), 'utf8', function (err, template) { if (err) { return callback(err); } - var template = file.toString(); var title = nsToTitle(namespace); var translations = sanitize(template); diff --git a/src/categories.js b/src/categories.js index 1487b543e2..6013091050 100644 --- a/src/categories.js +++ b/src/categories.js @@ -153,10 +153,10 @@ Categories.getCategories = function (cids, uid, callback) { uid = parseInt(uid, 10); results.categories.forEach(function (category, i) { if (category) { - category['unread-class'] = (parseInt(category.topic_count, 10) === 0 || (results.hasRead[i] && uid !== 0)) ? '' : 'unread'; category.children = results.children[i]; category.parent = results.parents[i] || undefined; category.tagWhitelist = results.tagWhitelist[i]; + category['unread-class'] = (parseInt(category.topic_count, 10) === 0 || (results.hasRead[i] && uid !== 0)) ? '' : 'unread'; calculateTopicPostCount(category); } }); @@ -259,9 +259,25 @@ function getChildrenRecursive(category, uid, callback) { } Categories.getCategoriesData(children, next); }, - function (childrenData, next) { - childrenData = childrenData.filter(Boolean); - category.children = childrenData; + function (children, next) { + children = children.filter(Boolean); + category.children = children; + + var cids = children.map(function (child) { + return child.cid; + }); + + Categories.hasReadCategories(cids, uid, next); + }, + function (hasRead, next) { + hasRead.forEach(function (read, i) { + var child = category.children[i]; + child['unread-class'] = (parseInt(child.topic_count, 10) === 0 || (read && uid !== 0)) ? '' : 'unread'; + }); + + next(); + }, + function (next) { async.each(category.children, function (child, next) { getChildrenRecursive(child, uid, next); }, next); diff --git a/src/categories/topics.js b/src/categories/topics.js index 2a3bd71e5a..32022b7a96 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -138,6 +138,8 @@ module.exports = function (Categories) { if (sort === 'most_posts') { set = 'cid:' + cid + ':tids:posts'; + } else if (sort === 'most_votes') { + set = 'cid:' + cid + ':tids:votes'; } if (data.targetUid) { @@ -163,7 +165,7 @@ module.exports = function (Categories) { Categories.getSortedSetRangeDirection = function (sort, callback) { sort = sort || 'newest_to_oldest'; - var direction = sort === 'newest_to_oldest' || sort === 'most_posts' ? 'highest-to-lowest' : 'lowest-to-highest'; + var direction = sort === 'newest_to_oldest' || sort === 'most_posts' || sort === 'most_votes' ? 'highest-to-lowest' : 'lowest-to-highest'; plugins.fireHook('filter:categories.getSortedSetRangeDirection', { sort: sort, direction: direction, diff --git a/src/cli/colors.js b/src/cli/colors.js new file mode 100644 index 0000000000..bb2648e1d5 --- /dev/null +++ b/src/cli/colors.js @@ -0,0 +1,127 @@ +'use strict'; + + +// override commander functions +// to include color styling in the output +// so the CLI looks nice + +var Command = require('commander').Command; + +var commandColor = 'yellow'; +var optionColor = 'cyan'; +var argColor = 'magenta'; +var subCommandColor = 'green'; +var subOptionColor = 'blue'; +var subArgColor = 'red'; + +Command.prototype.helpInformation = function () { + var desc = []; + if (this._description) { + desc = [ + ' ' + this._description, + '', + ]; + } + + var cmdName = this._name; + if (this._alias) { + cmdName = cmdName + ' | ' + this._alias; + } + var usage = [ + '', + ' Usage: ' + cmdName[commandColor] + ' '.reset + this.usage(), + '', + ]; + + var cmds = []; + var commandHelp = this.commandHelp(); + if (commandHelp) { + cmds = [commandHelp]; + } + + var options = [ + '', + ' Options:', + '', + '' + this.optionHelp().replace(/^/gm, ' '), + '', + ]; + + return usage + .concat(desc) + .concat(options) + .concat(cmds) + .join('\n'.reset); +}; + +function humanReadableArgName(arg) { + var nameOutput = arg.name + (arg.variadic === true ? '...' : ''); + + return arg.required ? '<' + nameOutput + '>' : '[' + nameOutput + ']'; +} + +Command.prototype.usage = function () { + var args = this._args.map(function (arg) { + return humanReadableArgName(arg); + }); + + var usage = '[options]'[optionColor] + + (this.commands.length ? ' [command]' : '')[subCommandColor] + + (this._args.length ? ' ' + args.join(' ') : '')[argColor]; + + return usage; +}; + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +Command.prototype.commandHelp = function () { + if (!this.commands.length) { + return ''; + } + + var commands = this.commands.filter(function (cmd) { + return !cmd._noHelp; + }).map(function (cmd) { + var args = cmd._args.map(function (arg) { + return humanReadableArgName(arg); + }).join(' '); + + return [ + cmd._name[subCommandColor] + + (cmd._alias ? ' | ' + cmd._alias : '')[subCommandColor] + + (cmd.options.length ? ' [options]' : '')[subOptionColor] + + ' ' + args[subArgColor], + cmd._description, + ]; + }); + + var width = commands.reduce(function (max, command) { + return Math.max(max, command[0].length); + }, 0); + + return [ + '', + ' Commands:', + '', + commands.map(function (cmd) { + var desc = cmd[1] ? ' ' + cmd[1] : ''; + return pad(cmd[0], width) + desc; + }).join('\n').replace(/^/gm, ' '), + '', + ].join('\n'); +}; + +Command.prototype.optionHelp = function () { + var width = this.largestOptionLength(); + + // Append the help information + return this.options + .map(function (option) { + return pad(option.flags, width)[optionColor] + ' ' + option.description; + }) + .concat([pad('-h, --help', width)[optionColor] + ' output usage information']) + .join('\n'); +}; diff --git a/src/cli/index.js b/src/cli/index.js new file mode 100644 index 0000000000..0bc95a7c6d --- /dev/null +++ b/src/cli/index.js @@ -0,0 +1,290 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +var packageInstall = require('../meta/package-install'); +var dirname = require('./paths').baseDir; + +// check to make sure dependencies are installed +try { + fs.readFileSync(path.join(dirname, 'package.json')); +} catch (e) { + if (e.code === 'ENOENT') { + console.warn('package.json not found.'); + console.log('Populating package.json...\n'); + + packageInstall.updatePackageFile(); + packageInstall.preserveExtraneousPlugins(); + + console.log('OK'.green + '\n'.reset); + } else { + throw e; + } +} + +try { + fs.readFileSync(path.join(dirname, 'node_modules/async/package.json'), 'utf8'); + fs.readFileSync(path.join(dirname, 'node_modules/commander/package.json'), 'utf8'); + fs.readFileSync(path.join(dirname, 'node_modules/colors/package.json'), 'utf8'); + fs.readFileSync(path.join(dirname, 'node_modules/nconf/package.json'), 'utf8'); +} catch (e) { + if (e.code === 'ENOENT') { + console.warn('Dependencies not yet installed.'); + console.log('Installing them now...\n'); + + packageInstall.npmInstallProduction(); + + require('colors'); + console.log('OK'.green + '\n'.reset); + } else { + throw e; + } +} + +require('colors'); +var nconf = require('nconf'); +var program = require('commander'); + +var pkg = require('../../package.json'); +var file = require('../file'); +var prestart = require('../prestart'); + +program + .name('./nodebb') + .description('Welcome to NodeBB') + .version(pkg.version) + .option('--json-logging', 'Output to logs in JSON format', false) + .option('--log-level ', 'Default logging level to use', 'info') + .option('-d, --dev', 'Development mode, including verbose logging', false) + .option('-l, --log', 'Log subprocess output to console', false) + .option('-c, --config ', 'Specify a config file', 'config.json') + .parse(process.argv); + +nconf.argv().env({ + separator: '__', +}); + +var env = program.dev ? 'development' : (process.env.NODE_ENV || 'production'); +process.env.NODE_ENV = env; +global.env = env; + +prestart.setupWinston(); + +// Alternate configuration file support +var configFile = path.resolve(dirname, program.config); +var configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database')); + +prestart.loadConfig(configFile); +prestart.versionCheck(); + +if (!configExists && process.argv[2] !== 'setup') { + require('./setup').webInstall(); + return; +} + +// running commands +program + .command('start') + .description('Start the NodeBB server') + .action(function () { + require('./running').start(program); + }); +program + .command('slog', null, { + noHelp: true, + }) + .description('Start the NodeBB server and view the live output log') + .action(function () { + program.log = true; + require('./running').start(program); + }); +program + .command('dev', null, { + noHelp: true, + }) + .description('Start NodeBB in verbose development mode') + .action(function () { + program.dev = true; + process.env.NODE_ENV = 'development'; + global.env = 'development'; + require('./running').start(program); + }); +program + .command('stop') + .description('Stop the NodeBB server') + .action(function () { + require('./running').stop(program); + }); +program + .command('restart') + .description('Restart the NodeBB server') + .action(function () { + require('./running').restart(program); + }); +program + .command('status') + .description('Check the running status of the NodeBB server') + .action(function () { + require('./running').status(program); + }); +program + .command('log') + .description('Open the output log (useful for debugging)') + .action(function () { + require('./running').log(program); + }); + +// management commands +program + .command('setup [config]') + .description('Run the NodeBB setup script, or setup with an initial config') + .action(function (initConfig) { + if (initConfig) { + try { + initConfig = JSON.parse(initConfig); + } catch (e) { + console.warn('Invalid JSON passed as initial config value.'.red); + console.log('If you meant to pass in an initial config value, please try again.\n'); + + throw e; + } + } + require('./setup').setup(initConfig); + }); + +program + .command('install') + .description('Launch the NodeBB web installer for configuration setup') + .action(function () { + require('./setup').webInstall(); + }); +program + .command('build [targets...]') + .description('Compile static assets ' + '(JS, CSS, templates, languages, sounds)'.red) + .action(function (targets) { + require('./manage').build(targets.length ? targets : true); + }) + .on('--help', function () { + require('./manage').buildTargets(); + }); +program + .command('activate [plugin]') + .description('Activate a plugin for the next startup of NodeBB (nodebb-plugin- prefix is optional)') + .action(function (plugin) { + require('./manage').activate(plugin); + }); +program + .command('plugins') + .action(function () { + require('./manage').listPlugins(); + }) + .description('List all installed plugins'); +program + .command('events') + .description('Outputs the last ten (10) administrative events recorded by NodeBB') + .action(function () { + require('./manage').listEvents(); + }); +program + .command('info') + .description('Outputs various system info') + .action(function () { + require('./manage').info(); + }); + +// reset +var resetCommand = program.command('reset'); + +resetCommand + .description('Reset plugins, themes, settings, etc') + .option('-t, --theme [theme]', 'Reset to [theme] or to the default theme') + .option('-p, --plugin [plugin]', 'Disable [plugin] or all plugins') + .option('-w, --widgets', 'Disable all widgets') + .option('-s, --settings', 'Reset settings to their default values') + .option('-a, --all', 'All of the above') + .action(function (options) { + var valid = ['theme', 'plugin', 'widgets', 'settings', 'all'].some(function (x) { + return options[x]; + }); + if (!valid) { + console.warn('\n No valid options passed in, so nothing was reset.'.red); + resetCommand.help(); + } + + require('./reset').reset(options, function (err) { + if (err) { throw err; } + require('../meta/build').buildAll(function (err) { + if (err) { throw err; } + + process.exit(); + }); + }); + }); + +// upgrades +program + .command('upgrade [scripts...]') + .description('Run NodeBB upgrade scripts and ensure packages are up-to-date, or run a particular upgrade script') + .option('-m, --package', 'Update package.json from defaults', false) + .option('-i, --install', 'Bringing base dependencies up to date', false) + .option('-p, --plugins', 'Check installed plugins for updates', false) + .option('-s, --schema', 'Update NodeBB data store schema', false) + .option('-b, --build', 'Rebuild assets', false) + .on('--help', function () { + console.log('\n' + [ + 'When running particular upgrade scripts, options are ignored.', + 'By default all options are enabled. Passing any options disables that default.', + 'Only package and dependency updates: ' + './nodebb upgrade -mi'.yellow, + 'Only database update: ' + './nodebb upgrade -d'.yellow, + ].join('\n')); + }) + .action(function (scripts, options) { + require('./upgrade').upgrade(scripts.length ? scripts : true, options); + }); + +program + .command('upgrade-plugins', null, { + noHelp: true, + }) + .alias('upgradePlugins') + .description('Upgrade plugins') + .action(function () { + require('./upgrade-plugins').upgradePlugins(function (err) { + if (err) { + throw err; + } + console.log('OK'.green); + process.exit(); + }); + }); + +program + .command('help [command]') + .description('Display help for [command]') + .action(function (name) { + if (!name) { + return program.help(); + } + + var command = program.commands.find(function (command) { return command._name === name; }); + if (command) { + command.help(); + } else { + program.help(); + } + }); + +program + .command('*', {}, { + noHelp: true, + }) + .action(function () { + program.help(); + }); + +require('./colors'); + +program.executables = false; + +program.parse(process.argv); diff --git a/src/cli/manage.js b/src/cli/manage.js new file mode 100644 index 0000000000..14f30a4749 --- /dev/null +++ b/src/cli/manage.js @@ -0,0 +1,142 @@ +'use strict'; + +var async = require('async'); +var winston = require('winston'); +var childProcess = require('child_process'); +var _ = require('lodash'); + +var build = require('../meta/build'); +var db = require('../database'); +var plugins = require('../plugins'); +var events = require('../events'); +var reset = require('./reset'); + +function buildTargets() { + var aliases = build.aliases; + var length = 0; + var output = Object.keys(aliases).map(function (name) { + var arr = aliases[name]; + if (name.length > length) { + length = name.length; + } + + return [name, arr.join(', ')]; + }).map(function (tuple) { + return ' ' + _.padEnd('"' + tuple[0] + '"', length + 2).magenta + ' | ' + tuple[1]; + }).join('\n'); + console.log( + '\n\n Build targets:\n' + + ('\n ' + _.padEnd('Target', length + 2) + ' | Aliases').green + + '\n ------------------------------------------------------\n'.blue + + output + '\n' + ); +} + +function activate(plugin) { + if (plugin.startsWith('nodebb-theme-')) { + reset.reset({ + theme: plugin, + }, function (err) { + if (err) { throw err; } + process.exit(); + }); + return; + } + + async.waterfall([ + function (next) { + db.init(next); + }, + function (next) { + if (!plugin.startsWith('nodebb-')) { + // Allow omission of `nodebb-plugin-` + plugin = 'nodebb-plugin-' + plugin; + } + plugins.isInstalled(plugin, next); + }, + function (isInstalled, next) { + if (!isInstalled) { + return next(new Error('plugin not installed')); + } + + winston.info('Activating plugin `%s`', plugin); + db.sortedSetAdd('plugins:active', 0, plugin, next); + }, + function (next) { + events.log({ + type: 'plugin-activate', + text: plugin, + }, next); + }, + ], function (err) { + if (err) { + winston.error('An error occurred during plugin activation', err); + throw err; + } + process.exit(0); + }); +} + +function listPlugins() { + async.waterfall([ + db.init, + function (next) { + db.getSortedSetRange('plugins:active', 0, -1, next); + }, + function (plugins) { + winston.info('Active plugins: \n\t - ' + plugins.join('\n\t - ')); + process.exit(); + }, + ], function (err) { + throw err; + }); +} + +function listEvents() { + async.series([ + db.init, + events.output, + ]); +} + +function info() { + console.log(''); + async.waterfall([ + function (next) { + var version = require('../../package.json').version; + console.log(' version: ' + version); + + console.log(' Node ver: ' + process.version); + next(); + }, + function (next) { + var hash = childProcess.execSync('git rev-parse HEAD'); + console.log(' git hash: ' + hash); + next(); + }, + function (next) { + var config = require('../../config.json'); + console.log(' database: ' + config.database); + next(); + }, + db.init, + function (next) { + db.info(db.client, next); + }, + function (info, next) { + console.log(' version: ' + info.version); + console.log(' engine: ' + info.storageEngine); + next(); + }, + ], function (err) { + if (err) { throw err; } + process.exit(); + }); +} + +exports.build = build.build; +exports.buildTargets = buildTargets; +exports.activate = activate; +exports.listPlugins = listPlugins; +exports.listEvents = listEvents; +exports.info = info; diff --git a/src/cli/paths.js b/src/cli/paths.js new file mode 100644 index 0000000000..2a9bec3547 --- /dev/null +++ b/src/cli/paths.js @@ -0,0 +1,17 @@ +'use strict'; + +var path = require('path'); + +var baseDir = path.join(__dirname, '../../'); +var loader = path.join(baseDir, 'loader.js'); +var app = path.join(baseDir, 'app.js'); +var pidfile = path.join(baseDir, 'pidfile'); +var config = path.join(baseDir, 'config.json'); + +module.exports = { + baseDir: baseDir, + loader: loader, + app: app, + pidfile: pidfile, + config: config, +}; diff --git a/src/reset.js b/src/cli/reset.js similarity index 53% rename from src/reset.js rename to src/cli/reset.js index d45c48deb5..bb0d110478 100644 --- a/src/reset.js +++ b/src/cli/reset.js @@ -3,79 +3,86 @@ require('colors'); var path = require('path'); var winston = require('winston'); -var nconf = require('nconf'); var async = require('async'); -var db = require('./database'); -var events = require('./events'); +var fs = require('fs'); -var Reset = {}; +var db = require('../database'); +var events = require('../events'); +var meta = require('../meta'); +var plugins = require('../plugins'); +var widgets = require('../widgets'); -Reset.reset = function (callback) { - db.init(function (err) { - if (err) { - winston.error(err); - throw err; - } +var dirname = require('./paths').baseDir; - if (nconf.get('t')) { - var themeId = nconf.get('t'); +exports.reset = function (options, callback) { + var map = { + theme: function (next) { + var themeId = options.theme; if (themeId === true) { - resetThemes(callback); + resetThemes(next); } else { - if (themeId.indexOf('nodebb-') !== 0) { + if (!themeId.startsWith('nodebb-theme-')) { // Allow omission of `nodebb-theme-` themeId = 'nodebb-theme-' + themeId; } - resetTheme(themeId, callback); + resetTheme(themeId, next); } - } else if (nconf.get('p')) { - var pluginId = nconf.get('p'); + }, + plugin: function (next) { + var pluginId = options.plugin; if (pluginId === true) { - resetPlugins(callback); + resetPlugins(next); } else { - if (pluginId.indexOf('nodebb-') !== 0) { + if (!pluginId.startsWith('nodebb-plugin-')) { // Allow omission of `nodebb-plugin-` pluginId = 'nodebb-plugin-' + pluginId; } - resetPlugin(pluginId, callback); + resetPlugin(pluginId, next); } - } else if (nconf.get('w')) { - resetWidgets(callback); - } else if (nconf.get('s')) { - resetSettings(callback); - } else if (nconf.get('a')) { - require('async').series([resetWidgets, resetThemes, resetPlugins, resetSettings], function (err) { - if (!err) { - winston.info('[reset] Reset complete.'); - } else { - winston.error('[reset] Errors were encountered while resetting your forum settings: %s', err); - } + }, + widgets: resetWidgets, + settings: resetSettings, + all: function (next) { + async.series([resetWidgets, resetThemes, resetPlugins, resetSettings], next); + }, + }; - callback(); - }); - } else { - process.stdout.write('\nNodeBB Reset\n'.bold); - process.stdout.write('No arguments passed in, so nothing was reset.\n\n'.yellow); - process.stdout.write('Use ./nodebb reset ' + '{-t|-p|-w|-s|-a}\n'.red); - process.stdout.write(' -t\tthemes\n'); - process.stdout.write(' -p\tplugins\n'); - process.stdout.write(' -w\twidgets\n'); - process.stdout.write(' -s\tsettings\n'); - process.stdout.write(' -a\tall of the above\n'); + var tasks = Object.keys(map) + .filter(function (x) { return options[x]; }) + .map(function (x) { return map[x]; }); - process.stdout.write('\nPlugin and theme reset flags (-p & -t) can take a single argument\n'); - process.stdout.write(' e.g. ./nodebb reset -p nodebb-plugin-mentions, ./nodebb reset -t nodebb-theme-persona\n'); - process.stdout.write(' Prefix is optional, e.g. ./nodebb reset -p markdown, ./nodebb reset -t persona\n'); + if (!tasks.length) { + console.log([ + 'No arguments passed in, so nothing was reset.\n'.yellow, + 'Use ./nodebb reset ' + '{-t|-p|-w|-s|-a}'.red, + ' -t\tthemes', + ' -p\tplugins', + ' -w\twidgets', + ' -s\tsettings', + ' -a\tall of the above', + '', + 'Plugin and theme reset flags (-p & -t) can take a single argument', + ' e.g. ./nodebb reset -p nodebb-plugin-mentions, ./nodebb reset -t nodebb-theme-persona', + ' Prefix is optional, e.g. ./nodebb reset -p markdown, ./nodebb reset -t persona', + ].join('\n')); - process.exit(0); + process.exit(0); + } + + async.series([db.init].concat(tasks), function (err) { + if (err) { + winston.error('[reset] Errors were encountered during reset', err); + throw err; } + + winston.info('[reset] Reset complete'); + callback(); }); }; function resetSettings(callback) { - var meta = require('./meta'); meta.configs.set('allowLocalLogin', 1, function (err) { winston.info('[reset] Settings reset to default'); callback(err); @@ -83,10 +90,7 @@ function resetSettings(callback) { } function resetTheme(themeId, callback) { - var meta = require('./meta'); - var fs = require('fs'); - - fs.access(path.join(__dirname, '../node_modules', themeId, 'package.json'), function (err) { + fs.access(path.join(dirname, 'node_modules', themeId, 'package.json'), function (err) { if (err) { winston.warn('[reset] Theme `%s` is not installed on this forum', themeId); callback(new Error('theme-not-found')); @@ -108,8 +112,6 @@ function resetTheme(themeId, callback) { } function resetThemes(callback) { - var meta = require('./meta'); - meta.themes.set({ type: 'local', id: 'nodebb-theme-persona', @@ -163,13 +165,11 @@ function resetPlugins(callback) { function resetWidgets(callback) { async.waterfall([ - require('./plugins').reload, - require('./widgets').reset, + plugins.reload, + widgets.reset, function (next) { winston.info('[reset] All Widgets moved to Draft Zone'); next(); }, ], callback); } - -module.exports = Reset; diff --git a/src/cli/running.js b/src/cli/running.js new file mode 100644 index 0000000000..b637e40f35 --- /dev/null +++ b/src/cli/running.js @@ -0,0 +1,124 @@ +'use strict'; + +var fs = require('fs'); +var childProcess = require('child_process'); + +var fork = require('../meta/debugFork'); +var paths = require('./paths'); + +var dirname = paths.baseDir; + +function getRunningPid(callback) { + fs.readFile(paths.pidfile, { + encoding: 'utf-8', + }, function (err, pid) { + if (err) { + return callback(err); + } + + pid = parseInt(pid, 10); + + try { + process.kill(pid, 0); + callback(null, pid); + } catch (e) { + callback(e); + } + }); +} + +function start(options) { + if (options.dev) { + process.env.NODE_ENV = 'development'; + fork(paths.loader, ['--no-daemon', '--no-silent'], { + env: process.env, + cwd: dirname, + stdio: 'inherit', + }); + return; + } + if (options.log) { + console.log('\n' + [ + 'Starting NodeBB with logging output'.bold, + 'Hit '.red + 'Ctrl-C '.bold + 'to exit'.red, + 'The NodeBB process will continue to run in the background', + 'Use "' + './nodebb stop'.yellow + '" to stop the NodeBB server', + ].join('\n')); + } else if (!options.silent) { + console.log('\n' + [ + 'Starting NodeBB'.bold, + ' "' + './nodebb stop'.yellow + '" to stop the NodeBB server', + ' "' + './nodebb log'.yellow + '" to view server output', + ' "' + './nodebb help'.yellow + '" for more commands\n'.reset, + ].join('\n')); + } + + // Spawn a new NodeBB process + var child = fork(paths.loader, process.argv.slice(3), { + env: process.env, + cwd: dirname, + }); + if (options.log) { + childProcess.spawn('tail', ['-F', './logs/output.log'], { + cwd: dirname, + stdio: 'inherit', + }); + } + + return child; +} + +function stop() { + getRunningPid(function (err, pid) { + if (!err) { + process.kill(pid, 'SIGTERM'); + console.log('Stopping NodeBB. Goodbye!'); + } else { + console.log('NodeBB is already stopped.'); + } + }); +} + +function restart(options) { + getRunningPid(function (err, pid) { + if (!err) { + console.log('\nRestarting NodeBB'.bold); + process.kill(pid, 'SIGTERM'); + + options.silent = true; + start(options); + } else { + console.warn('NodeBB could not be restarted, as a running instance could not be found.'); + } + }); +} + +function status() { + getRunningPid(function (err, pid) { + if (!err) { + console.log('\n' + [ + 'NodeBB Running '.bold + ('(pid ' + pid.toString() + ')').cyan, + '\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server', + '\t"' + './nodebb log'.yellow + '" to view server output', + '\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n', + ].join('\n')); + } else { + console.log('\nNodeBB is not running'.bold); + console.log('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n'.reset); + } + }); +} + +function log() { + console.log('\nHit '.red + 'Ctrl-C '.bold + 'to exit\n'.red + '\n'.reset); + childProcess.spawn('tail', ['-F', './logs/output.log'], { + cwd: dirname, + stdio: 'inherit', + }); +} + +exports.start = start; +exports.stop = stop; +exports.restart = restart; +exports.status = status; +exports.log = log; diff --git a/src/cli/setup.js b/src/cli/setup.js new file mode 100644 index 0000000000..509de52ddb --- /dev/null +++ b/src/cli/setup.js @@ -0,0 +1,73 @@ +'use strict'; + +var winston = require('winston'); +var async = require('async'); +var path = require('path'); +var nconf = require('nconf'); + +var install = require('../../install/web').install; + +function setup(initConfig) { + var paths = require('./paths'); + var install = require('../install'); + var build = require('../meta/build'); + var prestart = require('../prestart'); + var pkg = require('../../package.json'); + + winston.info('NodeBB Setup Triggered via Command Line'); + + console.log('\nWelcome to NodeBB v' + pkg.version + '!'); + console.log('\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.'); + console.log('Press enter to accept the default setting (shown in brackets).'); + + install.values = initConfig; + + async.series([ + install.setup, + function (next) { + var configFile = paths.config; + if (nconf.get('config')) { + configFile = path.resolve(paths.baseDir, nconf.get('config')); + } + + prestart.loadConfig(configFile); + next(); + }, + build.buildAll, + ], function (err, data) { + // Disregard build step data + data = data[0]; + + var separator = ' '; + if (process.stdout.columns > 10) { + for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) { + separator += '='; + } + } + console.log('\n' + separator + '\n'); + + if (err) { + winston.error('There was a problem completing NodeBB setup', err); + throw err; + } else { + if (data.hasOwnProperty('password')) { + console.log('An administrative user was automatically created for you:'); + console.log(' Username: ' + data.username + ''); + console.log(' Password: ' + data.password + ''); + console.log(''); + } + console.log('NodeBB Setup Completed. Run "./nodebb start" to manually start your NodeBB server.'); + + // If I am a child process, notify the parent of the returned data before exiting (useful for notifying + // hosts of auto-generated username/password during headless setups) + if (process.send) { + process.send(data); + } + } + + process.exit(); + }); +} + +exports.setup = setup; +exports.webInstall = install; diff --git a/src/cli/upgrade-plugins.js b/src/cli/upgrade-plugins.js new file mode 100644 index 0000000000..4011546fd3 --- /dev/null +++ b/src/cli/upgrade-plugins.js @@ -0,0 +1,216 @@ +'use strict'; + +var async = require('async'); +var prompt = require('prompt'); +var request = require('request'); +var cproc = require('child_process'); +var semver = require('semver'); +var fs = require('fs'); +var path = require('path'); + +var paths = require('./paths'); + +var dirname = paths.baseDir; + +function getModuleVersions(modules, callback) { + var versionHash = {}; + + async.eachLimit(modules, 50, function (module, next) { + fs.readFile(path.join(dirname, 'node_modules', module, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) { + if (err) { + return next(err); + } + + try { + pkg = JSON.parse(pkg); + versionHash[module] = pkg.version; + next(); + } catch (err) { + next(err); + } + }); + }, function (err) { + callback(err, versionHash); + }); +} + +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' }), + }, function (err, payload) { + if (err) { + return callback(err); + } + + var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/; + var moduleName; + var isGitRepo; + + payload.files = payload.files.filter(function (file) { + return isNbbModule.test(file); + }); + + try { + payload.deps = JSON.parse(payload.deps).dependencies; + payload.bundled = []; + payload.installed = []; + } catch (err) { + return callback(err); + } + + for (moduleName in payload.deps) { + if (isNbbModule.test(moduleName)) { + payload.bundled.push(moduleName); + } + } + + // Whittle down deps to send back only extraneously installed plugins/themes/etc + payload.files.forEach(function (moduleName) { + try { + fs.accessSync(path.join(dirname, 'node_modules', moduleName, '.git')); + isGitRepo = true; + } catch (e) { + isGitRepo = false; + } + + if ( + payload.files.indexOf(moduleName) !== -1 && // found in `node_modules/` + payload.bundled.indexOf(moduleName) === -1 && // not found in `package.json` + !fs.lstatSync(path.join(dirname, 'node_modules', moduleName)).isSymbolicLink() && // is not a symlink + !isGitRepo // .git/ does not exist, so it is not a git repository + ) { + payload.installed.push(moduleName); + } + }); + + getModuleVersions(payload.installed, callback); + }); +} + +function getCurrentVersion(callback) { + fs.readFile(path.join(dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) { + if (err) { + return callback(err); + } + + try { + pkg = JSON.parse(pkg); + } catch (err) { + return callback(err); + } + callback(null, pkg.version); + }); +} + +function checkPlugins(standalone, callback) { + if (standalone) { + console.log('Checking installed plugins and themes for updates... '); + } + + async.waterfall([ + async.apply(async.parallel, { + plugins: async.apply(getInstalledPlugins), + version: async.apply(getCurrentVersion), + }), + function (payload, next) { + var toCheck = Object.keys(payload.plugins); + + if (!toCheck.length) { + console.log('OK'.green + ''.reset); + return next(null, []); // no extraneous plugins installed + } + + request({ + method: 'GET', + url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='), + json: true, + }, function (err, res, body) { + if (err) { + console.log('error'.red + ''.reset); + return next(err); + } + console.log('OK'.green + ''.reset); + + if (!Array.isArray(body) && toCheck.length === 1) { + body = [body]; + } + + 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) { + var standalone = false; + if (typeof callback !== 'function') { + callback = function () {}; + standalone = true; + } + + checkPlugins(standalone, function (err, found) { + if (err) { + console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset); + return callback(err); + } + + if (found && found.length) { + console.log('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:'); + found.forEach(function (suggestObj) { + console.log(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset); + }); + console.log(''); + } else { + if (standalone) { + console.log('\nAll packages up-to-date!'.green + ''.reset); + } + return callback(); + } + + prompt.message = ''; + prompt.delimiter = ''; + + prompt.start(); + prompt.get({ + name: 'upgrade', + description: 'Proceed with upgrade (y|n)?'.reset, + type: 'string', + }, function (err, result) { + if (err) { + return callback(err); + } + + if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) { + console.log('\nUpgrading packages...'); + var args = ['i']; + found.forEach(function (suggestObj) { + args.push(suggestObj.name + '@' + suggestObj.suggested); + }); + + cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', args, { stdio: 'ignore' }, callback); + } else { + console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".'.reset); + callback(); + } + }); + }); +} + +exports.upgradePlugins = upgradePlugins; diff --git a/src/cli/upgrade.js b/src/cli/upgrade.js new file mode 100644 index 0000000000..026a104c30 --- /dev/null +++ b/src/cli/upgrade.js @@ -0,0 +1,113 @@ +'use strict'; + +var async = require('async'); +var nconf = require('nconf'); + +var packageInstall = require('../meta/package-install'); +var upgrade = require('../upgrade'); +var build = require('../meta/build'); +var db = require('../database'); +var meta = require('../meta'); +var upgradePlugins = require('./upgrade-plugins').upgradePlugins; + +var steps = { + package: { + message: 'Updating package.json file with defaults...', + handler: function (next) { + packageInstall.updatePackageFile(); + packageInstall.preserveExtraneousPlugins(); + next(); + }, + }, + install: { + message: 'Bringing base dependencies up to date...', + handler: function (next) { + packageInstall.npmInstallProduction(); + next(); + }, + }, + plugins: { + message: 'Checking installed plugins for updates...', + handler: function (next) { + async.series([ + db.init, + upgradePlugins, + ], next); + }, + }, + schema: { + message: 'Updating NodeBB data store schema...', + handler: function (next) { + async.series([ + db.init, + upgrade.run, + ], next); + }, + }, + build: { + message: 'Rebuilding assets...', + handler: build.buildAll, + }, +}; + +function runSteps(tasks) { + tasks = tasks.map(function (key, i) { + return function (next) { + console.log(((i + 1) + '. ').bold + steps[key].message.yellow); + return steps[key].handler(function (err) { + if (err) { return next(err); } + console.log(' OK'.green); + next(); + }); + }; + }); + + async.series(tasks, function (err) { + if (err) { + console.error('Error occurred during upgrade'); + throw err; + } + + 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(' ') : ' '; + + console.log('\n' + spaces + message.green.bold + '\n'.reset); + + process.exit(); + }); +} + +function runUpgrade(upgrades, options) { + console.log('\nUpdating NodeBB...'.cyan); + options = options || {}; + // disable mongo timeouts during upgrade + nconf.set('mongo:options:socketTimeoutMS', 0); + + if (upgrades === true) { + var tasks = Object.keys(steps); + if (options.package || options.install || + options.plugins || options.schema || options.build) { + tasks = tasks.filter(function (key) { + return options[key]; + }); + } + runSteps(tasks); + return; + } + + async.series([ + db.init, + meta.configs.init, + async.apply(upgrade.runParticular, upgrades), + ], function (err) { + if (err) { + throw err; + } + + process.exit(0); + }); +} + +exports.upgrade = runUpgrade; diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 61f4cad452..b5bd4cf3a5 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -148,7 +148,10 @@ editController.uploadPicture = function (req, res, next) { return helpers.notAllowed(req, res); } - user.uploadPicture(updateUid, userPhoto, next); + user.uploadCroppedPicture({ + uid: updateUid, + file: userPhoto, + }, next); }, ], function (err, image) { file.delete(userPhoto.path); diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 515cb33a4e..cadb7c12f8 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -84,13 +84,19 @@ settingsController.get = function (req, res, callback) { plugins.fireHook('filter:user.customSettings', { settings: results.settings, customSettings: [], uid: req.uid }, next); }, function (data, next) { - getHomePageRoutes(userData, function (err, routes) { - userData.homePageRoutes = routes; - next(err, data); - }); - }, - function (data) { userData.customSettings = data.customSettings; + async.parallel({ + notificationSettings: function (next) { + getNotificationSettings(userData, next); + }, + routes: function (next) { + getHomePageRoutes(userData, next); + }, + }, next); + }, + function (results) { + userData.homePageRoutes = results.routes; + userData.notificationSettings = results.notificationSettings; userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; userData.dailyDigestFreqOptions = [ @@ -129,6 +135,20 @@ settingsController.get = function (req, res, callback) { language.selected = language.code === userData.settings.userLang; }); + var notifFreqOptions = [ + 'all', + 'everyTen', + 'logarithmic', + 'disabled', + ]; + + userData.upvoteNotifFreq = notifFreqOptions.map(function (name) { + return { + name: name, + selected: name === userData.notifFreqOptions, + }; + }); + userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1; userData.allowUserHomePage = parseInt(meta.config.allowUserHomePage, 10) === 1; @@ -149,6 +169,56 @@ settingsController.get = function (req, res, callback) { ], callback); }; +function getNotificationSettings(userData, callback) { + var types = [ + 'notificationType_upvote', + 'notificationType_new-topic', + 'notificationType_new-reply', + 'notificationType_follow', + 'notificationType_new-chat', + 'notificationType_group-invite', + ]; + + var privilegedTypes = []; + + async.waterfall([ + function (next) { + user.getPrivileges(userData.uid, next); + }, + function (privileges, next) { + if (privileges.isAdmin) { + privilegedTypes.push('notificationType_new-register'); + } + if (privileges.isAdmin || privileges.isGlobalMod || privileges.isModeratorOfAnyCategory) { + privilegedTypes.push('notificationType_post-queue', 'notificationType_new-post-flag'); + } + if (privileges.isAdmin || privileges.isGlobalMod) { + privilegedTypes.push('notificationType_new-user-flag'); + } + plugins.fireHook('filter:user.notificationTypes', { + userData: userData, + types: types, + privilegedTypes: privilegedTypes, + }, next); + }, + function (results, next) { + function modifyType(type) { + var setting = userData.settings[type] || 'notification'; + + return { + name: type, + label: '[[notifications:' + type + ']]', + none: setting === 'none', + notification: setting === 'notification', + email: setting === 'email', + notificationemail: setting === 'notificationemail', + }; + } + var notificationSettings = results.types.map(modifyType).concat(results.privilegedTypes.map(modifyType)); + next(null, notificationSettings); + }, + ], callback); +} function getHomePageRoutes(userData, callback) { async.waterfall([ @@ -184,6 +254,10 @@ function getHomePageRoutes(userData, callback) { route: 'recent', name: 'Recent', }, + { + route: 'top', + name: 'Top', + }, { route: 'popular', name: 'Popular', @@ -222,6 +296,3 @@ function getHomePageRoutes(userData, callback) { }, ], callback); } - - -module.exports = settingsController; diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js index 4de2045518..baa461a21b 100644 --- a/src/controllers/admin/cache.js +++ b/src/controllers/admin/cache.js @@ -42,7 +42,7 @@ cacheController.get = function (req, res) { dump: req.query.debug ? JSON.stringify(objectCache.dump(), null, 4) : false, hits: utils.addCommas(String(objectCache.hits)), misses: utils.addCommas(String(objectCache.misses)), - missRatio: (1 - (objectCache.hits / (objectCache.hits + objectCache.misses))).toFixed(4), + hitRatio: (objectCache.hits / (objectCache.hits + objectCache.misses)).toFixed(4), }; } diff --git a/src/controllers/admin/homepage.js b/src/controllers/admin/homepage.js index bc0971622f..45fabeb2d4 100644 --- a/src/controllers/admin/homepage.js +++ b/src/controllers/admin/homepage.js @@ -37,6 +37,10 @@ homePageController.get = function (req, res, next) { route: 'recent', name: 'Recent', }, + { + route: 'top', + name: 'Top', + }, { route: 'popular', name: 'Popular', diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js index 28322892f3..860de1290d 100644 --- a/src/controllers/admin/settings.js +++ b/src/controllers/admin/settings.js @@ -1,12 +1,8 @@ 'use strict'; var async = require('async'); -var nconf = require('nconf'); -var fs = require('fs'); -var path = require('path'); var meta = require('../../meta'); -var file = require('../../file'); var emailer = require('../../emailer'); var settingsController = module.exports; @@ -26,42 +22,8 @@ settingsController.get = function (req, res, next) { function renderEmail(req, res, next) { - var emailsPath = path.join(nconf.get('views_dir'), 'emails'); - async.parallel({ - emails: function (cb) { - async.waterfall([ - function (next) { - file.walk(emailsPath, next); - }, - function (emails, next) { - // exclude .js files - emails = emails.filter(function (email) { - return !email.endsWith('.js'); - }); - - async.map(emails, function (email, next) { - var path = email.replace(emailsPath, '').substr(1).replace('.tpl', ''); - - async.waterfall([ - function (next) { - fs.readFile(email, next); - }, - function (original, next) { - var text = meta.config['email:custom:' + path] ? meta.config['email:custom:' + path] : original.toString(); - - next(null, { - path: path, - fullpath: email, - text: text, - original: original.toString(), - }); - }, - ], next); - }, next); - }, - ], cb); - }, + emails: async.apply(emailer.getTemplates, meta.config), services: emailer.listServices, }, function (err, results) { if (err) { diff --git a/src/controllers/admin/themes.js b/src/controllers/admin/themes.js index 850feb201d..717d4bf0dc 100644 --- a/src/controllers/admin/themes.js +++ b/src/controllers/admin/themes.js @@ -23,7 +23,7 @@ themesController.get = function (req, res, next) { return next(Error('invalid-data')); } - fs.readFile(themeConfigPath, next); + fs.readFile(themeConfigPath, 'utf8', next); }, function (themeConfig, next) { try { diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index d454b287a1..5c71c19da7 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -2,6 +2,7 @@ var async = require('async'); var validator = require('validator'); +var nconf = require('nconf'); var user = require('../../user'); var meta = require('../../meta'); @@ -183,6 +184,11 @@ function render(req, res, data) { } usersController.getCSV = function (req, res, next) { + var referer = req.headers.referer; + + if (!referer || !referer.replace(nconf.get('url'), '').startsWith('/admin/manage/users')) { + return res.status(403).send('[[error:invalid-origin]]'); + } events.log({ type: 'getUsersCSV', uid: req.user.uid, diff --git a/src/controllers/api.js b/src/controllers/api.js index b464748f49..4f9430826a 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -17,9 +17,7 @@ var apiController = module.exports; apiController.loadConfig = function (req, callback) { var config = {}; - config.environment = process.env.NODE_ENV; config.relative_path = nconf.get('relative_path'); - config.version = nconf.get('version'); config.siteTitle = validator.escape(String(meta.config.title || meta.config.browserTitle || 'NodeBB')); config.browserTitle = validator.escape(String(meta.config.browserTitle || meta.config.title || 'NodeBB')); config.titleLayout = (meta.config.titleLayout || '{pageTitle} | {browserTitle}').replace(/{/g, '{').replace(/}/g, '}'); @@ -32,7 +30,6 @@ apiController.loadConfig = function (req, callback) { config.maximumTagsPerTopic = parseInt(meta.config.maximumTagsPerTopic || 5, 10); config.minimumTagLength = meta.config.minimumTagLength || 3; config.maximumTagLength = meta.config.maximumTagLength || 15; - config.hasImageUploadPlugin = plugins.hasListeners('filter:uploadImage'); config.useOutgoingLinksPage = parseInt(meta.config.useOutgoingLinksPage, 10) === 1; config.allowGuestSearching = parseInt(meta.config.allowGuestSearching, 10) === 1; config.allowGuestUserSearching = parseInt(meta.config.allowGuestUserSearching, 10) === 1; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 73eb6be287..b2d46dcd70 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -57,18 +57,11 @@ authenticationController.register = function (req, res) { user.isPasswordValid(userData.password, next); }, function (next) { - user.shouldQueueUser(req.ip, next); - }, - function (queue, next) { res.locals.processLogin = true; // set it to false in plugin if you wish to just register only - plugins.fireHook('filter:register.check', { req: req, res: res, userData: userData, queue: queue }, next); + plugins.fireHook('filter:register.check', { req: req, res: res, userData: userData }, next); }, - function (data, next) { - if (data.queue) { - addToApprovalQueue(req, userData, next); - } else { - registerAndLoginUser(req, res, userData, next); - } + function (result, next) { + registerAndLoginUser(req, res, userData, next); }, ], function (err, data) { if (err) { @@ -108,7 +101,17 @@ function registerAndLoginUser(req, res, userData, callback) { return res.json({ referrer: nconf.get('relative_path') + '/register/complete' }); }, function (next) { - user.create(userData, next); + user.shouldQueueUser(req.ip, next); + }, + function (queue, next) { + plugins.fireHook('filter:register.shouldQueue', { req: req, res: res, userData: userData, queue: queue }, next); + }, + function (data, next) { + if (data.queue) { + addToApprovalQueue(req, userData, callback); + } else { + user.create(userData, next); + } }, function (_uid, next) { uid = _uid; @@ -155,9 +158,11 @@ authenticationController.registerComplete = function (req, res, next) { return memo; }, []); - var done = function () { + var done = function (err, data) { delete req.session.registration; - + if (!err && data && data.message) { + return res.redirect(nconf.get('relative_path') + '/?register=' + encodeURIComponent(data.message)); + } if (req.session.returnTo) { res.redirect(req.session.returnTo); } else { @@ -289,26 +294,30 @@ authenticationController.doLogin = function (req, uid, callback) { authenticationController.onSuccessfulLogin = function (req, uid, callback) { var uuid = utils.generateUUID(); - req.session.meta = {}; - - delete req.session.forceLogin; - - // Associate IP used during login with user account - user.logIP(uid, req.ip); - req.session.meta.ip = req.ip; - - // Associate metadata retrieved via user-agent - req.session.meta = _.extend(req.session.meta, { - uuid: uuid, - datetime: Date.now(), - platform: req.useragent.platform, - browser: req.useragent.browser, - version: req.useragent.version, - }); async.waterfall([ - async.apply(meta.blacklist.test, req.ip), function (next) { + meta.blacklist.test(req.ip, next); + }, + function (next) { + user.logIP(uid, req.ip, next); + }, + function (next) { + req.session.meta = {}; + + delete req.session.forceLogin; + // Associate IP used during login with user account + req.session.meta.ip = req.ip; + + // Associate metadata retrieved via user-agent + req.session.meta = _.extend(req.session.meta, { + uuid: uuid, + datetime: Date.now(), + platform: req.useragent.platform, + browser: req.useragent.browser, + version: req.useragent.version, + }); + async.parallel([ function (next) { user.auth.addSession(uid, req.sessionID, next); diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 25e384c0ed..1eb46a0041 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -13,9 +13,6 @@ categoriesController.list = function (req, res, next) { res.locals.metaTags = [{ name: 'title', content: String(meta.config.title || 'NodeBB'), - }, { - property: 'og:title', - content: '[[pages:categories]]', }, { property: 'og:type', content: 'website', @@ -36,12 +33,17 @@ categoriesController.list = function (req, res, next) { }, function () { var data = { - title: '[[pages:categories]]', + title: meta.config.homePageTitle || '[[pages:home]]', categories: categoryData, }; - if (req.path.startsWith('/api/categories') || req.path.startsWith('/categories')) { + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/categories') || req.originalUrl.startsWith(nconf.get('relative_path') + '/categories')) { + data.title = '[[pages:categories]]'; data.breadcrumbs = helpers.buildBreadcrumbs([{ text: data.title }]); + res.locals.metaTags.push({ + property: 'og:title', + content: '[[pages:categories]]', + }); } data.categories.forEach(function (category) { diff --git a/src/controllers/category.js b/src/controllers/category.js index c7414fc096..f231349a49 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -109,7 +109,7 @@ categoryController.get = function (req, res, callback) { return helpers.redirect(res, categoryData.link); } - buildBreadcrumbs(categoryData, next); + buildBreadcrumbs(req, categoryData, next); }, function (categoryData, next) { if (!categoryData.children.length) { @@ -148,7 +148,7 @@ categoryController.get = function (req, res, callback) { ], callback); }; -function buildBreadcrumbs(categoryData, callback) { +function buildBreadcrumbs(req, categoryData, callback) { var breadcrumbs = [ { text: categoryData.name, @@ -160,7 +160,9 @@ function buildBreadcrumbs(categoryData, callback) { helpers.buildCategoryBreadcrumbs(categoryData.parentCid, next); }, function (crumbs, next) { - categoryData.breadcrumbs = crumbs.concat(breadcrumbs); + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/category') || req.originalUrl.startsWith(nconf.get('relative_path') + '/category')) { + categoryData.breadcrumbs = crumbs.concat(breadcrumbs); + } next(null, categoryData); }, ], callback); diff --git a/src/controllers/composer.js b/src/controllers/composer.js index c0b0da2236..7bd61a5bb2 100644 --- a/src/controllers/composer.js +++ b/src/controllers/composer.js @@ -8,13 +8,13 @@ var plugins = require('../plugins'); var topics = require('../topics'); var helpers = require('./helpers'); -exports.get = function (req, res, next) { +exports.get = function (req, res, callback) { async.waterfall([ function (next) { plugins.fireHook('filter:composer.build', { req: req, res: res, - next: next, + next: callback, templateData: {}, }, next); }, @@ -28,7 +28,7 @@ exports.get = function (req, res, next) { res.render('compose', data.templateData); } }, - ], next); + ], callback); }; exports.post = function (req, res) { diff --git a/src/controllers/home.js b/src/controllers/home.js index d5a8c30050..6c67e7aaa2 100644 --- a/src/controllers/home.js +++ b/src/controllers/home.js @@ -36,8 +36,8 @@ function getRouteAllowUserHomePage(uid, next) { pubsub.on('config:update', configUpdated); configUpdated(); -module.exports = function (req, res, next) { - if (req.path !== '/' && req.path !== '/api/') { +function rewrite(req, res, next) { + if (req.path !== '/' && req.path !== '/api/' && req.path !== '/api') { return next(); } @@ -48,15 +48,26 @@ module.exports = function (req, res, next) { var hook = 'action:homepage.get:' + route; - if (plugins.hasListeners(hook)) { - return plugins.fireHook(hook, { - req: req, - res: res, - next: next, - }); + if (!plugins.hasListeners(hook)) { + req.url = req.path + (!req.path.endsWith('/') ? '/' : '') + route; + } else { + res.locals.homePageRoute = route; } - req.url = req.path + route; next(); }); -}; +} + +exports.rewrite = rewrite; + +function pluginHook(req, res, next) { + var hook = 'action:homepage.get:' + res.locals.homePageRoute; + + plugins.fireHook(hook, { + req: req, + res: res, + next: next, + }); +} + +exports.pluginHook = pluginHook; diff --git a/src/controllers/index.js b/src/controllers/index.js index 1861422db9..bddab21a11 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -19,6 +19,7 @@ Controllers.category = require('./category'); Controllers.unread = require('./unread'); Controllers.recent = require('./recent'); Controllers.popular = require('./popular'); +Controllers.top = require('./top'); Controllers.tags = require('./tags'); Controllers.search = require('./search'); Controllers.user = require('./user'); @@ -286,7 +287,7 @@ Controllers.outgoing = function (req, res, next) { var allowedProtocols = ['http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal']; var parsed = require('url').parse(url); - if (!url || !allowedProtocols.includes(parsed.protocol.slice(0, -1))) { + if (!url || !parsed.protocol || !allowedProtocols.includes(parsed.protocol.slice(0, -1))) { return next(); } diff --git a/src/controllers/popular.js b/src/controllers/popular.js index 99af5baf19..b6a189383c 100644 --- a/src/controllers/popular.js +++ b/src/controllers/popular.js @@ -45,14 +45,15 @@ popularController.get = function (req, res, next) { }, function (topics) { var data = { + title: meta.config.homePageTitle || '[[pages:home]]', topics: topics, 'feeds:disableRSS': parseInt(meta.config['feeds:disableRSS'], 10) === 1, rssFeedUrl: nconf.get('relative_path') + '/popular/' + (req.params.term || 'daily') + '.rss', - title: '[[pages:popular-' + term + ']]', term: term, }; - if (req.path.startsWith('/api/popular') || req.path.startsWith('/popular')) { + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/popular') || req.originalUrl.startsWith(nconf.get('relative_path') + '/popular')) { + data.title = '[[pages:popular-' + term + ']]'; var breadcrumbs = [{ text: termToBreadcrumb[term] }]; if (req.params.term) { diff --git a/src/controllers/recent.js b/src/controllers/recent.js index d6947d53a7..7b997894c1 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -61,7 +61,7 @@ recentController.get = function (req, res, next) { if (req.uid) { data.rssFeedUrl += '?uid=' + req.uid + '&token=' + rssToken; } - data.title = '[[pages:recent]]'; + data.title = meta.config.homePageTitle || '[[pages:home]]'; data.filters = helpers.buildFilters('recent', filter); data.selectedFilter = data.filters.find(function (filter) { @@ -71,7 +71,8 @@ recentController.get = function (req, res, next) { var pageCount = Math.max(1, Math.ceil(data.topicCount / settings.topicsPerPage)); data.pagination = pagination.create(page, pageCount, req.query); - if (req.path.startsWith('/api/recent') || req.path.startsWith('/recent')) { + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/recent') || req.originalUrl.startsWith(nconf.get('relative_path') + '/recent')) { + data.title = '[[pages:recent]]'; data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[recent:title]]' }]); } diff --git a/src/controllers/top.js b/src/controllers/top.js new file mode 100644 index 0000000000..7b500533d5 --- /dev/null +++ b/src/controllers/top.js @@ -0,0 +1,84 @@ + +'use strict'; + +var async = require('async'); +var nconf = require('nconf'); +var querystring = require('querystring'); + +var user = require('../user'); +var topics = require('../topics'); +var meta = require('../meta'); +var helpers = require('./helpers'); +var pagination = require('../pagination'); + +var topController = module.exports; + +topController.get = function (req, res, next) { + var page = parseInt(req.query.page, 10) || 1; + var stop = 0; + var settings; + var cid = req.query.cid; + var filter = req.params.filter || ''; + var categoryData; + var rssToken; + + if (!helpers.validFilters[filter]) { + return next(); + } + + async.waterfall([ + function (next) { + async.parallel({ + settings: function (next) { + user.getSettings(req.uid, next); + }, + watchedCategories: function (next) { + helpers.getWatchedCategories(req.uid, cid, next); + }, + rssToken: function (next) { + user.auth.getFeedToken(req.uid, next); + }, + }, next); + }, + function (results, next) { + rssToken = results.rssToken; + settings = results.settings; + categoryData = results.watchedCategories; + + var start = Math.max(0, (page - 1) * settings.topicsPerPage); + stop = start + settings.topicsPerPage - 1; + + topics.getTopTopics(cid, req.uid, start, stop, filter, next); + }, + function (data) { + data.categories = categoryData.categories; + data.selectedCategory = categoryData.selectedCategory; + data.selectedCids = categoryData.selectedCids; + data.nextStart = stop + 1; + data.set = 'topics:votes'; + data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; + data.rssFeedUrl = nconf.get('relative_path') + '/top.rss'; + if (req.uid) { + data.rssFeedUrl += '?uid=' + req.uid + '&token=' + rssToken; + } + data.title = meta.config.homePageTitle || '[[pages:home]]'; + data.filters = helpers.buildFilters('top', filter); + + data.selectedFilter = data.filters.find(function (filter) { + return filter && filter.selected; + }); + + var pageCount = Math.max(1, Math.ceil(data.topicCount / settings.topicsPerPage)); + data.pagination = pagination.create(page, pageCount, req.query); + + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/top') || req.originalUrl.startsWith(nconf.get('relative_path') + '/top')) { + data.title = '[[pages:top]]'; + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[top:title]]' }]); + } + + data.querystring = cid ? '?' + querystring.stringify({ cid: cid }) : ''; + + res.render('top', data); + }, + ], next); +}; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index c75f5c3602..4ecaf7486e 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -205,16 +205,11 @@ function buildBreadcrumbs(topicData, callback) { } function addTags(topicData, req, res) { - function findPost(index) { - for (var i = 0; i < topicData.posts.length; i += 1) { - if (parseInt(topicData.posts[i].index, 10) === parseInt(index, 10)) { - return topicData.posts[i]; - } - } - } - var description = ''; - var postAtIndex = findPost(Math.max(0, req.params.post_index - 1)); + var postAtIndex = topicData.posts.find(function (postData) { + return parseInt(postData.index, 10) === parseInt(Math.max(0, req.params.post_index - 1), 10); + }); + var description = ''; if (postAtIndex && postAtIndex.content) { description = utils.stripHTMLTags(utils.decodeHTMLEntities(postAtIndex.content)); } @@ -222,27 +217,8 @@ function addTags(topicData, req, res) { if (description.length > 255) { description = description.substr(0, 255) + '...'; } - - var ogImageUrl = ''; - if (topicData.thumb) { - ogImageUrl = topicData.thumb; - } else if (topicData.category.backgroundImage && (!postAtIndex || !postAtIndex.index)) { - ogImageUrl = topicData.category.backgroundImage; - } else if (postAtIndex && postAtIndex.user && postAtIndex.user.picture) { - ogImageUrl = postAtIndex.user.picture; - } else if (meta.config['og:image']) { - ogImageUrl = meta.config['og:image']; - } else if (meta.config['brand:logo']) { - ogImageUrl = meta.config['brand:logo']; - } else { - ogImageUrl = '/logo.png'; - } - - if (typeof ogImageUrl === 'string' && ogImageUrl.indexOf('http') === -1) { - ogImageUrl = nconf.get('url') + ogImageUrl; - } - description = description.replace(/\n/g, ' '); + res.locals.metaTags = [ { name: 'title', @@ -264,16 +240,6 @@ function addTags(topicData, req, res) { property: 'og:type', content: 'article', }, - { - property: 'og:image', - content: ogImageUrl, - noEscape: true, - }, - { - property: 'og:image:url', - content: ogImageUrl, - noEscape: true, - }, { property: 'article:published_time', content: utils.toISOString(topicData.timestamp), @@ -288,6 +254,8 @@ function addTags(topicData, req, res) { }, ]; + addOGImageTags(res, topicData, postAtIndex); + res.locals.linkTags = [ { rel: 'alternate', @@ -308,6 +276,60 @@ function addTags(topicData, req, res) { } } +function addOGImageTags(res, topicData, postAtIndex) { + var ogImageUrl = ''; + if (topicData.thumb) { + ogImageUrl = topicData.thumb; + } else if (topicData.category.backgroundImage && (!postAtIndex || !postAtIndex.index)) { + ogImageUrl = topicData.category.backgroundImage; + } else if (postAtIndex && postAtIndex.user && postAtIndex.user.picture) { + ogImageUrl = postAtIndex.user.picture; + } else if (meta.config['og:image']) { + ogImageUrl = meta.config['og:image']; + } else if (meta.config['brand:logo']) { + ogImageUrl = meta.config['brand:logo']; + } else { + ogImageUrl = '/logo.png'; + } + + addOGImageTag(res, ogImageUrl); + addOGImageTagsForPosts(res, topicData.posts); +} + +function addOGImageTagsForPosts(res, posts) { + posts.forEach(function (postData) { + var regex = /src\s*=\s*"(.+?)"/g; + var match = regex.exec(postData.content); + while (match !== null) { + var image = match[1]; + + if (image.startsWith(nconf.get('url') + '/plugins')) { + return; + } + + addOGImageTag(res, image); + + match = regex.exec(postData.content); + } + }); +} + +function addOGImageTag(res, imageUrl) { + if (typeof imageUrl === 'string' && !imageUrl.startsWith('http')) { + imageUrl = nconf.get('url') + imageUrl; + } + res.locals.metaTags.push({ + property: 'og:image', + content: imageUrl, + noEscape: true, + }); + res.locals.metaTags.push({ + property: 'og:image:url', + content: imageUrl, + noEscape: true, + }); +} + topicsController.teaser = function (req, res, next) { var tid = req.params.topic_id; diff --git a/src/controllers/unread.js b/src/controllers/unread.js index 7891012e19..b4b8e23f38 100644 --- a/src/controllers/unread.js +++ b/src/controllers/unread.js @@ -2,8 +2,10 @@ 'use strict'; var async = require('async'); +var nconf = require('nconf'); var querystring = require('querystring'); +var meta = require('../meta'); var pagination = require('../pagination'); var user = require('../user'); var topics = require('../topics'); @@ -53,6 +55,7 @@ unreadController.get = function (req, res, next) { }, next); }, function (data) { + data.title = meta.config.homePageTitle || '[[pages:home]]'; data.pageCount = Math.max(1, Math.ceil(data.topicCount / settings.topicsPerPage)); data.pagination = pagination.create(page, data.pageCount, req.query); @@ -64,12 +67,11 @@ unreadController.get = function (req, res, next) { data.categories = results.watchedCategories.categories; data.selectedCategory = results.watchedCategories.selectedCategory; data.selectedCids = results.watchedCategories.selectedCids; - - if (req.path.startsWith('/api/unread') || req.path.startsWith('/unread')) { + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/unread') || req.originalUrl.startsWith(nconf.get('relative_path') + '/unread')) { + data.title = '[[pages:unread]]'; data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[unread:title]]' }]); } - data.title = '[[pages:unread]]'; data.filters = helpers.buildFilters('unread', filter); data.selectedFilter = data.filters.find(function (filter) { diff --git a/src/database/mongo.js b/src/database/mongo.js index 04addc07d5..5bcab76a6f 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -22,6 +22,7 @@ mongoModule.questions = [ name: 'mongo:uri', description: 'MongoDB connection URI: (leave blank if you wish to specify host, port, username/password and database individually)\nFormat: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', default: nconf.get('mongo:uri') || '', + hideOnWebInstall: true, }, { name: 'mongo:host', diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index feeed1e20a..22c7e44196 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -41,6 +41,22 @@ module.exports = function (db, module) { key = { $in: key }; } + if (start < 0 && start > stop) { + return callback(null, []); + } + + var reverse = false; + if (start === 0 && stop < -1) { + reverse = true; + sort *= -1; + start = Math.abs(stop + 1); + stop = -1; + } else if (start < 0 && stop > start) { + var tmp1 = Math.abs(stop + 1); + stop = Math.abs(start + 1); + start = tmp1; + } + var limit = stop - start + 1; if (limit <= 0) { limit = 0; @@ -54,7 +70,9 @@ module.exports = function (db, module) { if (err || !data) { return callback(err); } - + if (reverse) { + data.reverse(); + } if (!withScores) { data = data.map(function (item) { return item.value; @@ -467,7 +485,7 @@ module.exports = function (db, module) { } } - module.processSortedSet = function (setKey, process, options, callback) { + module.processSortedSet = function (setKey, processFn, options, callback) { var done = false; var ids = []; var cursor = db.collection('objects').find({ _key: setKey }) @@ -492,9 +510,9 @@ module.exports = function (db, module) { } if (ids.length < options.batch && (!done || ids.length === 0)) { - return next(null); + return process.nextTick(next, null); } - process(ids, function (err) { + processFn(ids, function (err) { _next(err); }); }, @@ -503,7 +521,7 @@ module.exports = function (db, module) { if (options.interval) { setTimeout(next, options.interval); } else { - next(); + process.nextTick(next); } }, ], next); diff --git a/src/database/redis/hash.js b/src/database/redis/hash.js index 9cf320fb3d..1a9388f0a2 100644 --- a/src/database/redis/hash.js +++ b/src/database/redis/hash.js @@ -102,7 +102,7 @@ module.exports = function (redisClient, module) { module.deleteObjectField = function (key, field, callback) { callback = callback || function () {}; - if (field === null) { + if (key === undefined || key === null || field === undefined || field === null) { return setImmediate(callback); } redisClient.hdel(key, field, function (err) { diff --git a/src/emailer.js b/src/emailer.js index 38535367b9..10163cc512 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -8,14 +8,19 @@ var nodemailer = require('nodemailer'); var wellKnownServices = require('nodemailer/lib/well-known/services'); var htmlToText = require('html-to-text'); var url = require('url'); +var path = require('path'); +var fs = require('fs'); var User = require('./user'); var Plugins = require('./plugins'); var meta = require('./meta'); var translator = require('./translator'); var pubsub = require('./pubsub'); +var file = require('./file'); -var transports = { +var Emailer = module.exports; + +Emailer.transports = { sendmail: nodemailer.createTransport({ sendmail: true, newline: 'unix', @@ -25,9 +30,45 @@ var transports = { }; var app; -var fallbackTransport; -var Emailer = module.exports; +var viewsDir = nconf.get('views_dir'); +var emailsPath = path.join(viewsDir, 'emails'); + +Emailer.getTemplates = function (config, cb) { + async.waterfall([ + function (next) { + file.walk(emailsPath, next); + }, + function (emails, next) { + // exclude .js files + emails = emails.filter(function (email) { + return !email.endsWith('.js'); + }); + + async.map(emails, function (email, next) { + var path = email.replace(emailsPath, '').substr(1).replace('.tpl', ''); + + async.waterfall([ + function (next) { + fs.readFile(email, 'utf8', next); + }, + function (original, next) { + var isCustom = !!config['email:custom:' + path]; + var text = config['email:custom:' + path] || original; + + next(null, { + path: path, + fullpath: email, + text: text, + original: original, + isCustom: isCustom, + }); + }, + ], next); + }, next); + }, + ], cb); +}; Emailer.listServices = function (callback) { var services = Object.keys(wellKnownServices); @@ -71,13 +112,30 @@ Emailer.setupFallbackTransport = function (config) { smtpOptions.service = config['email:smtpTransport:service']; } - transports.smtp = nodemailer.createTransport(smtpOptions); - fallbackTransport = transports.smtp; + Emailer.transports.smtp = nodemailer.createTransport(smtpOptions); + Emailer.fallbackTransport = Emailer.transports.smtp; } else { - fallbackTransport = transports.sendmail; + Emailer.fallbackTransport = Emailer.transports.sendmail; } }; +var prevConfig = meta.config; +function smtpSettingsChanged(config) { + var settings = [ + 'email:smtpTransport:enabled', + 'email:smtpTransport:user', + 'email:smtpTransport:pass', + 'email:smtpTransport:service', + 'email:smtpTransport:port', + 'email:smtpTransport:host', + 'email:smtpTransport:security', + ]; + + return settings.some(function (key) { + return config[key] !== prevConfig[key]; + }); +} + Emailer.registerApp = function (expressApp) { app = expressApp; @@ -97,16 +155,21 @@ Emailer.registerApp = function (expressApp) { }; Emailer.setupFallbackTransport(meta.config); + buildCustomTemplates(meta.config); // Update default payload if new logo is uploaded pubsub.on('config:update', function (config) { if (config) { - if ('email:smtpTransport:enabled' in config) { - Emailer.setupFallbackTransport(config); - } Emailer._defaultPayload.logo.src = config['brand:emailLogo']; Emailer._defaultPayload.logo.height = config['brand:emailLogo:height']; Emailer._defaultPayload.logo.width = config['brand:emailLogo:width']; + + if (smtpSettingsChanged(config)) { + Emailer.setupFallbackTransport(config); + } + buildCustomTemplates(config); + + prevConfig = config; } }); @@ -150,7 +213,7 @@ Emailer.sendToEmail = function (template, email, language, params, callback) { function (next) { async.parallel({ html: function (next) { - renderAndTranslate('emails/' + template, params, lang, next); + Emailer.renderAndTranslate(template, params, lang, next); }, subject: function (next) { translator.translate(params.subject, lang, function (translated) { @@ -203,7 +266,7 @@ Emailer.sendViaFallback = function (data, callback) { delete data.from_name; winston.verbose('[emailer] Sending email to uid ' + data.uid + ' (' + data.to + ')'); - fallbackTransport.sendMail(data, function (err) { + Emailer.fallbackTransport.sendMail(data, function (err) { if (err) { winston.error(err); } @@ -211,23 +274,64 @@ Emailer.sendViaFallback = function (data, callback) { }); }; -function render(tpl, params, next) { - var customTemplate = meta.config['email:custom:' + tpl.replace('emails/', '')]; - if (customTemplate) { - Benchpress.compileParse(customTemplate, params, next); - } else { - app.render(tpl, params, next); - } -} +function buildCustomTemplates(config) { + async.waterfall([ + function (next) { + Emailer.getTemplates(config, next); + }, + function (templates, next) { + templates = templates.filter(function (template) { + return template.isCustom && template.text !== prevConfig['email:custom:' + path]; + }); + async.each(templates, function (template, next) { + async.waterfall([ + function (next) { + file.walk(viewsDir, next); + }, + function (paths, next) { + paths = paths.reduce(function (obj, p) { + var relative = path.relative(viewsDir, p); + obj['/' + relative] = p; + return obj; + }, {}); + meta.templates.processImports(paths, template.path, template.text, next); + }, + function (source, next) { + Benchpress.precompile(source, { + minify: global.env !== 'development', + }, next); + }, + function (compiled, next) { + fs.writeFile(template.fullpath.replace(/\.tpl$/, '.js'), compiled, next); + }, + ], next); + }, next); + }, + function (next) { + Benchpress.flush(); + next(); + }, + ], function (err) { + if (err) { + winston.error('[emailer] Failed to build custom email templates', err); + return; + } -function renderAndTranslate(tpl, params, lang, callback) { - render(tpl, params, function (err, html) { - translator.translate(html, lang, function (translated) { - callback(err, translated); - }); + winston.verbose('[emailer] Built custom email templates'); }); } +Emailer.renderAndTranslate = function (template, params, lang, callback) { + app.render('emails/' + template, params, function (err, html) { + if (err) { + return callback(err); + } + translator.translate(html, lang, function (translated) { + callback(null, translated); + }); + }); +}; + function getHostname() { var configUrl = nconf.get('url'); var parsed = url.parse(configUrl); diff --git a/src/events.js b/src/events.js index 65a2c36ad8..c19a948579 100644 --- a/src/events.js +++ b/src/events.js @@ -141,7 +141,7 @@ events.deleteAll = function (callback) { }; events.output = function () { - process.stdout.write('\nDisplaying last ten administrative events...\n'.bold); + console.log('\nDisplaying last ten administrative events...'.bold); events.getEvents(0, 9, function (err, events) { if (err) { winston.error('Error fetching events', err); @@ -149,7 +149,7 @@ events.output = function () { } events.forEach(function (event) { - process.stdout.write(' * ' + String(event.timestampISO).green + ' ' + String(event.type).yellow + (event.text ? ' ' + event.text : '') + ' (uid: '.reset + (event.uid ? event.uid : 0) + ')\n'); + console.log(' * ' + String(event.timestampISO).green + ' ' + String(event.type).yellow + (event.text ? ' ' + event.text : '') + ' (uid: '.reset + (event.uid ? event.uid : 0) + ')'); }); process.exit(0); diff --git a/src/file.js b/src/file.js index c091da614f..8027f7ad77 100644 --- a/src/file.js +++ b/src/file.js @@ -7,9 +7,12 @@ var winston = require('winston'); var jimp = require('jimp'); var mkdirp = require('mkdirp'); var mime = require('mime'); +var graceful = require('graceful-fs'); var utils = require('./utils'); +graceful.gracefulify(fs); + var file = module.exports; /** diff --git a/src/flags.js b/src/flags.js index df6ec625f3..4118cf8fb2 100644 --- a/src/flags.js +++ b/src/flags.js @@ -241,7 +241,7 @@ Flags.validate = function (payload, callback) { return callback(err); } - var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 1; + var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0; // Check if reporter meets rep threshold (or can edit the target post, in which case threshold does not apply) if (!editable.flag && parseInt(data.reporter.reputation, 10) < minimumReputation) { return callback(new Error('[[error:not-enough-reputation-to-flag]]')); @@ -257,7 +257,7 @@ Flags.validate = function (payload, callback) { return callback(err); } - var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 1; + var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0; // Check if reporter meets rep threshold (or can edit the target user, in which case threshold does not apply) if (!editable && parseInt(data.reporter.reputation, 10) < minimumReputation) { return callback(new Error('[[error:not-enough-reputation-to-flag]]')); @@ -696,6 +696,7 @@ Flags.notify = function (flagObj, uid, callback) { } notifications.create({ + type: 'new-user-flag', bodyShort: '[[notifications:user_flagged_user, ' + flagObj.reporter.username + ', ' + flagObj.target.username + ']]', bodyLong: flagObj.description, path: '/uid/' + flagObj.targetId, diff --git a/src/groups/membership.js b/src/groups/membership.js index 7547159910..f11eebcc0b 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -161,6 +161,7 @@ module.exports = function (Groups) { async.waterfall([ async.apply(inviteOrRequestMembership, groupName, uid, 'invite'), async.apply(notifications.create, { + type: 'group-invite', bodyShort: '[[groups:invited.notification_title, ' + groupName + ']]', bodyLong: '', nid: 'group:' + groupName + ':uid:' + uid + ':invite', diff --git a/src/image.js b/src/image.js index fc3ddd5e76..f2afb21003 100644 --- a/src/image.js +++ b/src/image.js @@ -120,9 +120,7 @@ image.size = function (path, callback) { }; image.convertImageToBase64 = function (path, callback) { - fs.readFile(path, function (err, data) { - callback(err, data ? data.toString('base64') : null); - }); + fs.readFile(path, 'base64', callback); }; image.mimeFromBase64 = function (imageData) { diff --git a/src/install.js b/src/install.js index 3a69595599..b55b1ed08e 100644 --- a/src/install.js +++ b/src/install.js @@ -8,7 +8,7 @@ var winston = require('winston'); var nconf = require('nconf'); var utils = require('./utils.js'); -var install = {}; +var install = module.exports; var questions = {}; questions.main = [ @@ -42,17 +42,15 @@ questions.optional = [ ]; function checkSetupFlag(next) { - var setupVal; + var setupVal = install.values; try { if (nconf.get('setup')) { setupVal = JSON.parse(nconf.get('setup')); } - } catch (err) { - setupVal = undefined; - } + } catch (err) {} - if (setupVal && setupVal instanceof Object) { + if (setupVal && typeof setupVal === 'object') { if (setupVal['admin:username'] && setupVal['admin:password'] && setupVal['admin:password:confirm'] && setupVal['admin:email']) { install.values = setupVal; next(); @@ -74,9 +72,8 @@ function checkSetupFlag(next) { process.exit(); } } else if (nconf.get('database')) { - install.values = { - database: nconf.get('database'), - }; + install.values = install.values || {}; + install.values.database = nconf.get('database'); next(); } else { next(); @@ -174,7 +171,7 @@ function completeConfigSetup(config, next) { } function setupDefaultConfigs(next) { - process.stdout.write('Populating database with default configs, if not already set...\n'); + console.log('Populating database with default configs, if not already set...'); var meta = require('./meta'); var defaults = require(path.join(__dirname, '../', 'install/data/defaults.json')); @@ -192,11 +189,11 @@ function enableDefaultTheme(next) { meta.configs.get('theme:id', function (err, id) { if (err || id) { - process.stdout.write('Previous theme detected, skipping enabling default theme\n'); + console.log('Previous theme detected, skipping enabling default theme'); return next(err); } var defaultTheme = nconf.get('defaultTheme') || 'nodebb-theme-persona'; - process.stdout.write('Enabling default theme: ' + defaultTheme + '\n'); + console.log('Enabling default theme: ' + defaultTheme); meta.themes.set({ type: 'local', id: defaultTheme, @@ -211,7 +208,7 @@ function createAdministrator(next) { return next(err); } if (memberCount > 0) { - process.stdout.write('Administrator found, skipping Admin setup\n'); + console.log('Administrator found, skipping Admin setup'); next(); } else { createAdmin(next); @@ -315,7 +312,7 @@ function createAdmin(callback) { } else { // If automated setup did not provide a user password, generate one, it will be shown to the user upon setup completion if (!install.values.hasOwnProperty('admin:password') && !nconf.get('admin:password')) { - process.stdout.write('Password was not provided during automated setup, generating one...\n'); + console.log('Password was not provided during automated setup, generating one...'); password = utils.generateUUID().slice(0, 8); } @@ -365,13 +362,13 @@ function createCategories(next) { } if (Array.isArray(categoryData) && categoryData.length) { - process.stdout.write('Categories OK. Found ' + categoryData.length + ' categories.\n'); + console.log('Categories OK. Found ' + categoryData.length + ' categories.'); return next(); } - process.stdout.write('No categories found, populating instance with default categories\n'); + console.log('No categories found, populating instance with default categories'); - fs.readFile(path.join(__dirname, '../', 'install/data/categories.json'), function (err, default_categories) { + fs.readFile(path.join(__dirname, '../', 'install/data/categories.json'), 'utf8', function (err, default_categories) { if (err) { return next(err); } @@ -402,7 +399,7 @@ function createWelcomePost(next) { async.parallel([ function (next) { - fs.readFile(path.join(__dirname, '../', 'install/data/welcome.md'), next); + fs.readFile(path.join(__dirname, '../', 'install/data/welcome.md'), 'utf8', next); }, function (next) { db.getObjectField('global', 'topicCount', next); @@ -416,12 +413,12 @@ function createWelcomePost(next) { var numTopics = results[1]; if (!parseInt(numTopics, 10)) { - process.stdout.write('Creating welcome post!\n'); + console.log('Creating welcome post!'); Topics.post({ uid: 1, cid: 2, title: 'Welcome to your NodeBB!', - content: content.toString(), + content: content, }, next); } else { next(); @@ -430,7 +427,7 @@ function createWelcomePost(next) { } function enableDefaultPlugins(next) { - process.stdout.write('Enabling default plugins\n'); + console.log('Enabling default plugins'); var defaultEnabled = [ 'nodebb-plugin-composer-default', @@ -439,8 +436,8 @@ function enableDefaultPlugins(next) { 'nodebb-widget-essentials', 'nodebb-rewards-essentials', 'nodebb-plugin-soundpack-default', - 'nodebb-plugin-emoji-extended', - 'nodebb-plugin-emoji-one', + 'nodebb-plugin-emoji', + 'nodebb-plugin-emoji-android', ]; var customDefaults = nconf.get('defaultplugins') || nconf.get('defaultPlugins'); @@ -473,7 +470,7 @@ function setCopyrightWidget(next) { var db = require('./database'); async.parallel({ footerJSON: function (next) { - fs.readFile(path.join(__dirname, '../', 'install/data/footer.json'), next); + fs.readFile(path.join(__dirname, '../', 'install/data/footer.json'), 'utf8', next); }, footer: function (next) { db.getObjectField('widgets:global', 'footer', next); @@ -484,7 +481,7 @@ function setCopyrightWidget(next) { } if (!results.footer && results.footerJSON) { - db.setObjectField('widgets:global', 'footer', results.footerJSON.toString(), next); + db.setObjectField('widgets:global', 'footer', results.footerJSON, next); } else { next(); } @@ -546,14 +543,12 @@ install.save = function (server_conf, callback) { return callback(err); } - process.stdout.write('Configuration Saved OK\n'); + console.log('Configuration Saved OK'); nconf.file({ - file: path.join(__dirname, '..', 'config.json'), + file: serverConfigPath, }); callback(); }); }; - -module.exports = install; diff --git a/src/languages.js b/src/languages.js index 77945bacc6..cdf56bf81d 100644 --- a/src/languages.js +++ b/src/languages.js @@ -29,7 +29,7 @@ Languages.listCodes = function (callback) { return callback(null, codeCache); } - fs.readFile(path.join(languagesPath, 'metadata.json'), function (err, buffer) { + fs.readFile(path.join(languagesPath, 'metadata.json'), 'utf8', function (err, file) { if (err && err.code === 'ENOENT') { return callback(null, []); } @@ -39,7 +39,7 @@ Languages.listCodes = function (callback) { var parsed; try { - parsed = JSON.parse(buffer.toString()); + parsed = JSON.parse(file); } catch (e) { return callback(e); } @@ -64,7 +64,7 @@ Languages.list = function (callback) { async.map(codes, function (folder, next) { var configPath = path.join(languagesPath, folder, 'language.json'); - fs.readFile(configPath, function (err, buffer) { + fs.readFile(configPath, 'utf8', function (err, file) { if (err && err.code === 'ENOENT') { return next(); } @@ -72,7 +72,7 @@ Languages.list = function (callback) { return next(err); } try { - var lang = JSON.parse(buffer.toString()); + var lang = JSON.parse(file); next(null, lang); } catch (e) { next(e); diff --git a/src/messaging/edit.js b/src/messaging/edit.js index f9c664d67f..b118ca03c5 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -44,10 +44,25 @@ module.exports = function (Messaging) { }; Messaging.canEdit = function (messageId, uid, callback) { + canEditDelete(messageId, uid, 'edit', callback); + }; + + Messaging.canDelete = function (messageId, uid, callback) { + canEditDelete(messageId, uid, 'delete', callback); + }; + + function canEditDelete(messageId, uid, type, callback) { + var durationConfig = ''; + if (type === 'edit') { + durationConfig = 'chatEditDuration'; + } else if (type === 'delete') { + durationConfig = 'chatDeleteDuration'; + } + if (parseInt(meta.config.disableChat, 10) === 1) { - return callback(null, false); + return callback(new Error('[[error:chat-disabled]]')); } else if (parseInt(meta.config.disableChatMessageEditing, 10) === 1) { - return callback(null, false); + return callback(new Error('[[error:chat-message-editing-disabled]]')); } async.waterfall([ @@ -56,25 +71,36 @@ module.exports = function (Messaging) { }, function (userData, next) { if (parseInt(userData.banned, 10) === 1) { - return callback(null, false); + return callback(new Error('[[error:user-banned]]')); } if (parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) { - return callback(null, false); + return callback(new Error('[[error:email-not-confirmed]]')); + } + async.parallel({ + isAdmin: function (next) { + user.isAdministrator(uid, next); + }, + messageData: function (next) { + Messaging.getMessageFields(messageId, ['fromuid', 'timestamp'], next); + }, + }, next); + }, + function (results, next) { + if (results.isAdmin) { + return callback(); + } + var chatConfigDuration = parseInt(meta.config[durationConfig], 10); + if (chatConfigDuration && Date.now() - parseInt(results.messageData.timestamp, 10) > chatConfigDuration * 1000) { + return callback(new Error('[[error:chat-' + type + '-duration-expired, ' + meta.config[durationConfig] + ']]')); } - Messaging.getMessageField(messageId, 'fromuid', next); - }, - function (fromUid, next) { - if (parseInt(fromUid, 10) === parseInt(uid, 10)) { - return callback(null, true); + if (parseInt(results.messageData.fromuid, 10) === parseInt(uid, 10)) { + return callback(); } - user.isAdministrator(uid, next); - }, - function (isAdmin, next) { - next(null, isAdmin); + next(new Error('[[error:cant-' + type + '-chat-message]]')); }, ], callback); - }; + } }; diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index a3512f478b..3116c31a2b 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -1,12 +1,9 @@ 'use strict'; var async = require('async'); -var winston = require('winston'); var user = require('../user'); -var emailer = require('../emailer'); var notifications = require('../notifications'); -var meta = require('../meta'); var sockets = require('../socket.io'); var plugins = require('../plugins'); @@ -92,46 +89,6 @@ module.exports = function (Messaging) { if (notification) { notifications.push(notification, uids); } - sendNotificationEmails(uids, messageObj); - } - }); - } - - function sendNotificationEmails(uids, messageObj) { - if (parseInt(meta.config.disableEmailSubscriptions, 10) === 1) { - return; - } - - async.waterfall([ - function (next) { - async.parallel({ - userData: function (next) { - user.getUsersFields(uids, ['uid', 'username', 'userslug'], next); - }, - userSettings: function (next) { - user.getMultipleUserSettings(uids, next); - }, - }, next); - }, - - function (results, next) { - results.userData = results.userData.filter(function (userData, index) { - return userData && results.userSettings[index] && results.userSettings[index].sendChatNotifications; - }); - async.each(results.userData, function (userData, next) { - emailer.send('notif_chat', userData.uid, { - subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]', - summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]', - message: messageObj, - roomId: messageObj.roomId, - username: userData.username, - userslug: userData.userslug, - }, next); - }, next); - }, - ], function (err) { - if (err) { - return winston.error(err); } }); } diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index c8d5b6a9fb..2b2f897284 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -68,7 +68,12 @@ Blacklist.test = function (clientIp, callback) { // clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp; - var addr = ipaddr.parse(clientIp); + var addr; + try { + addr = ipaddr.parse(clientIp); + } catch (err) { + return callback(err); + } if ( Blacklist._rules.ipv4.indexOf(clientIp) === -1 && // not explicitly specified in ipv4 list @@ -88,11 +93,7 @@ Blacklist.test = function (clientIp, callback) { analytics.increment('blacklist'); } - if (typeof callback === 'function') { - callback(err); - } else { - return !!err; - } + callback(err); }); } else { var err = new Error('[[error:blacklisted-ip]]'); @@ -100,11 +101,7 @@ Blacklist.test = function (clientIp, callback) { analytics.increment('blacklist'); - if (typeof callback === 'function') { - setImmediate(callback, err); - } else { - return true; - } + setImmediate(callback, err); } }; diff --git a/src/meta/build.js b/src/meta/build.js index b01a92cb86..df68e93375 100644 --- a/src/meta/build.js +++ b/src/meta/build.js @@ -83,6 +83,8 @@ var aliases = { sounds: ['sound'], }; +exports.aliases = aliases; + aliases = Object.keys(aliases).reduce(function (prev, key) { var arr = aliases[key]; arr.forEach(function (alias) { diff --git a/src/meta/cacheBuster.js b/src/meta/cacheBuster.js index f88cebb680..4ea3109dbe 100644 --- a/src/meta/cacheBuster.js +++ b/src/meta/cacheBuster.js @@ -31,18 +31,18 @@ exports.read = function read(callback) { return callback(null, cached); } - fs.readFile(filePath, function (err, buffer) { + fs.readFile(filePath, 'utf8', function (err, buster) { if (err) { winston.warn('[cache-buster] could not read cache buster', err); return callback(null, generate()); } - if (!buffer || buffer.toString().length !== 11) { - winston.warn('[cache-buster] cache buster string invalid: expected /[a-z0-9]{11}/, got `' + buffer + '`'); + if (!buster || buster.length !== 11) { + winston.warn('[cache-buster] cache buster string invalid: expected /[a-z0-9]{11}/, got `' + buster + '`'); return callback(null, generate()); } - cached = buffer.toString(); + cached = buster; callback(null, cached); }); }; diff --git a/src/meta/configs.js b/src/meta/configs.js index 12553d5a50..16445a2c32 100644 --- a/src/meta/configs.js +++ b/src/meta/configs.js @@ -83,9 +83,12 @@ function processConfig(data, callback) { var image = require('../image'); if (data['brand:logo']) { image.size(path.join(nconf.get('upload_path'), 'system', 'site-logo-x50.png'), function (err, size) { + if (err) { + return next(err); + } data['brand:emailLogo:height'] = size.height; data['brand:emailLogo:width'] = size.width; - next(err); + next(); }); } else { setImmediate(next); diff --git a/src/meta/js.js b/src/meta/js.js index 28b114434a..e8b71cf6a3 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -49,6 +49,7 @@ JS.scripts = { 'public/src/client/unread.js', 'public/src/client/topic.js', 'public/src/client/topic/events.js', + 'public/src/client/topic/merge.js', 'public/src/client/topic/fork.js', 'public/src/client/topic/move.js', 'public/src/client/topic/posts.js', @@ -76,6 +77,19 @@ JS.scripts = { 'public/src/modules/storage.js', ], + admin: [ + 'node_modules/material-design-lite/material.js', + 'public/vendor/jquery/sortable/Sortable.js', + 'public/vendor/colorpicker/colorpicker.js', + 'public/src/admin/admin.js', + 'public/vendor/semver/semver.browser.js', + 'public/vendor/jquery/serializeObject/jquery.ba-serializeobject.min.js', + 'public/vendor/jquery/deserialize/jquery.deserialize.min.js', + 'public/vendor/snackbar/snackbar.min.js', + 'public/vendor/slideout/slideout.min.js', + 'public/vendor/nprogress.min.js', + ], + // modules listed below are built (/src/modules) so they can be defined anonymously modules: { 'Chart.js': 'node_modules/chart.js/dist/Chart.min.js', @@ -106,7 +120,7 @@ function minifyModules(modules, fork, callback) { return prev; }, []); - async.eachLimit(moduleDirs, 1000, mkdirp, function (err) { + async.each(moduleDirs, mkdirp, function (err) { if (err) { return callback(err); } @@ -126,7 +140,7 @@ function minifyModules(modules, fork, callback) { minifier.js.minifyBatch(filtered.minify, fork, cb); }, function (cb) { - async.eachLimit(filtered.skip, 500, function (mod, next) { + async.each(filtered.skip, function (mod, next) { linkIfLinux(mod.srcPath, mod.destPath, next); }, cb); }, @@ -137,7 +151,7 @@ function minifyModules(modules, fork, callback) { function linkModules(callback) { var modules = JS.scripts.modules; - async.eachLimit(Object.keys(modules), 1000, function (relPath, next) { + async.each(Object.keys(modules), function (relPath, next) { var srcPath = path.join(__dirname, '../../', modules[relPath]); var destPath = path.join(__dirname, '../../build/public/src/modules', relPath); @@ -183,7 +197,7 @@ function getModuleList(callback) { modules = modules.concat(coreDirs); var moduleFiles = []; - async.eachLimit(modules, 1000, function (module, next) { + async.each(modules, function (module, next) { var srcPath = module.srcPath; var destPath = module.destPath; @@ -255,7 +269,7 @@ JS.linkStatics = function (callback) { if (err) { return callback(err); } - async.eachLimit(Object.keys(plugins.staticDirs), 1000, function (mappedPath, next) { + async.each(Object.keys(plugins.staticDirs), function (mappedPath, next) { var sourceDir = plugins.staticDirs[mappedPath]; var destDir = path.join(__dirname, '../../build/public/plugins', mappedPath); @@ -299,13 +313,15 @@ function getBundleScriptList(target, callback) { return callback(err); } - var scripts = JS.scripts.base.concat(pluginScripts); + var scripts = JS.scripts.base; if (target === 'client' && global.env !== 'development') { scripts = scripts.concat(JS.scripts.rjs); + } else if (target === 'acp') { + scripts = scripts.concat(JS.scripts.admin); } - scripts = scripts.map(function (script) { + scripts = scripts.concat(pluginScripts).map(function (script) { var srcPath = path.resolve(basePath, script).replace(/\\/g, '/'); return { srcPath: srcPath, diff --git a/src/meta/languages.js b/src/meta/languages.js index 3b9f3c3a9e..fc907e60be 100644 --- a/src/meta/languages.js +++ b/src/meta/languages.js @@ -13,7 +13,7 @@ var Plugins = require('../plugins'); var buildLanguagesPath = path.join(__dirname, '../../build/public/language'); var coreLanguagesPath = path.join(__dirname, '../../public/language'); -function getTranslationTree(callback) { +function getTranslationMetadata(callback) { async.waterfall([ // generate list of languages and namespaces function (next) { @@ -49,129 +49,113 @@ function getTranslationTree(callback) { // save a list of languages to `${buildLanguagesPath}/metadata.json` // avoids readdirs later on function (ref, next) { - async.waterfall([ + async.series([ function (next) { mkdirp(buildLanguagesPath, next); }, - function (x, next) { + function (next) { fs.writeFile(path.join(buildLanguagesPath, 'metadata.json'), JSON.stringify({ languages: ref.languages, namespaces: ref.namespaces, }), next); }, - function (next) { - next(null, ref); - }, - ], next); - }, - - // for each language and namespace combination, - // run through core and all plugins to generate - // a full translation hash - function (ref, next) { - var languages = ref.languages; - var namespaces = ref.namespaces; - var plugins = _.values(Plugins.pluginsData).filter(function (plugin) { - return typeof plugin.languages === 'string'; - }); - - var tree = {}; - - async.eachLimit(languages, 10, function (lang, next) { - async.eachLimit(namespaces, 10, function (namespace, next) { - var translations = {}; - - async.series([ - // core first - function (cb) { - fs.readFile(path.join(coreLanguagesPath, lang, namespace + '.json'), function (err, buffer) { - if (err) { - if (err.code === 'ENOENT') { - return cb(); - } - return cb(err); - } - - try { - Object.assign(translations, JSON.parse(buffer.toString())); - cb(); - } catch (err) { - cb(err); - } - }); - }, - function (cb) { - // for each plugin, fallback in this order: - // 1. correct language string (en-GB) - // 2. old language string (en_GB) - // 3. corrected plugin defaultLang (en-US) - // 4. old plugin defaultLang (en_US) - async.eachLimit(plugins, 20, function (pluginData, done) { - var pluginLanguages = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages); - var defaultLang = pluginData.defaultLang || 'en-GB'; - - async.eachSeries([ - defaultLang.replace('-', '_').replace('-x-', '@'), - defaultLang.replace('_', '-').replace('@', '-x-'), - lang.replace('-', '_').replace('-x-', '@'), - lang, - ], function (language, next) { - fs.readFile(path.join(pluginLanguages, language, namespace + '.json'), function (err, buffer) { - if (err) { - if (err.code === 'ENOENT') { - return next(null, false); - } - return next(err); - } - - try { - Object.assign(translations, JSON.parse(buffer.toString())); - next(null, true); - } catch (err) { - next(err); - } - }); - }, done); - }, function (err) { - if (err) { - return cb(err); - } - - if (Object.keys(translations).length) { - tree[lang] = tree[lang] || {}; - tree[lang][namespace] = translations; - } - cb(); - }); - }, - ], next); - }, next); - }, function (err) { - next(err, tree); + ], function (err) { + next(err, ref); }); }, ], callback); } -// write translation hashes from the generated tree to language files -function writeLanguageFiles(tree, callback) { - // iterate over languages and namespaces - async.eachLimit(Object.keys(tree), 100, function (language, cb) { - var namespaces = tree[language]; - async.eachLimit(Object.keys(namespaces), 10, function (namespace, next) { - var translations = namespaces[namespace]; +function writeLanguageFile(language, namespace, translations, callback) { + var dev = global.env === 'development'; + var filePath = path.join(buildLanguagesPath, language, namespace + '.json'); - var filePath = path.join(buildLanguagesPath, language, namespace + '.json'); + async.series([ + async.apply(mkdirp, path.dirname(filePath)), + async.apply(fs.writeFile, filePath, JSON.stringify(translations, null, dev ? 2 : 0)), + ], callback); +} - mkdirp(path.dirname(filePath), function (err) { - if (err) { - return next(err); - } +// for each language and namespace combination, +// run through core and all plugins to generate +// a full translation hash +function buildTranslations(ref, next) { + var namespaces = ref.namespaces; + var languages = ref.languages; + var plugins = _.values(Plugins.pluginsData).filter(function (plugin) { + return typeof plugin.languages === 'string'; + }); - fs.writeFile(filePath, JSON.stringify(translations), next); - }); - }, cb); - }, callback); + async.each(namespaces, function (namespace, next) { + async.each(languages, function (lang, next) { + var translations = {}; + + async.series([ + // core first + function (cb) { + fs.readFile(path.join(coreLanguagesPath, lang, namespace + '.json'), 'utf8', function (err, file) { + if (err) { + if (err.code === 'ENOENT') { + return cb(); + } + return cb(err); + } + + try { + Object.assign(translations, JSON.parse(file)); + cb(); + } catch (err) { + cb(err); + } + }); + }, + function (cb) { + // for each plugin, fallback in this order: + // 1. correct language string (en-GB) + // 2. old language string (en_GB) + // 3. corrected plugin defaultLang (en-US) + // 4. old plugin defaultLang (en_US) + async.each(plugins, function (pluginData, done) { + var pluginLanguages = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages); + var defaultLang = pluginData.defaultLang || 'en-GB'; + + async.eachSeries([ + defaultLang.replace('-', '_').replace('-x-', '@'), + defaultLang.replace('_', '-').replace('@', '-x-'), + lang.replace('-', '_').replace('-x-', '@'), + lang, + ], function (language, next) { + fs.readFile(path.join(pluginLanguages, language, namespace + '.json'), 'utf8', function (err, file) { + if (err) { + if (err.code === 'ENOENT') { + return next(null, false); + } + return next(err); + } + + try { + Object.assign(translations, JSON.parse(file)); + next(null, true); + } catch (err) { + next(err); + } + }); + }, done); + }, function (err) { + if (err) { + return cb(err); + } + + if (Object.keys(translations).length) { + writeLanguageFile(lang, namespace, translations, cb); + return; + } + cb(); + }); + }, + ], next); + }, next); + }, next); } exports.build = function buildLanguages(callback) { @@ -179,7 +163,7 @@ exports.build = function buildLanguages(callback) { function (next) { rimraf(buildLanguagesPath, next); }, - getTranslationTree, - writeLanguageFiles, + getTranslationMetadata, + buildTranslations, ], callback); }; diff --git a/src/meta/minifier.js b/src/meta/minifier.js index c51f41578b..ed6a68a625 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -11,6 +11,7 @@ var autoprefixer = require('autoprefixer'); var clean = require('postcss-clean'); var fork = require('./debugFork'); +require('../file'); // for graceful-fs var Minifier = module.exports; @@ -139,12 +140,12 @@ function executeAction(action, fork, callback) { function concat(data, callback) { if (data.files && data.files.length) { async.mapLimit(data.files, 1000, function (ref, next) { - fs.readFile(ref.srcPath, function (err, buffer) { + fs.readFile(ref.srcPath, 'utf8', function (err, file) { if (err) { return next(err); } - next(null, buffer.toString()); + next(null, file); }); }, function (err, files) { if (err) { @@ -163,18 +164,18 @@ function concat(data, callback) { actions.concat = concat; function minifyJS_batch(data, callback) { - async.eachLimit(data.files, 1000, function (ref, next) { + async.each(data.files, function (ref, next) { var srcPath = ref.srcPath; var destPath = ref.destPath; var filename = ref.filename; - fs.readFile(srcPath, function (err, buffer) { + fs.readFile(srcPath, 'utf8', function (err, file) { if (err) { return next(err); } var scripts = {}; - scripts[filename] = buffer.toString(); + scripts[filename] = file; try { var minified = uglifyjs.minify(scripts, { @@ -203,7 +204,7 @@ function minifyJS(data, callback) { var srcPath = ref.srcPath; var filename = ref.filename; - fs.readFile(srcPath, function (err, buffer) { + fs.readFile(srcPath, 'utf8', function (err, file) { if (err) { return next(err); } @@ -211,7 +212,7 @@ function minifyJS(data, callback) { next(null, { srcPath: srcPath, filename: filename, - source: buffer.toString(), + source: file, }); }); }, function (err, files) { diff --git a/src/meta/package-install.js b/src/meta/package-install.js index 3fee4cb9e4..2ae93612a0 100644 --- a/src/meta/package-install.js +++ b/src/meta/package-install.js @@ -5,7 +5,7 @@ var fs = require('fs'); var cproc = require('child_process'); var packageFilePath = path.join(__dirname, '../../package.json'); -var packageDefaultFilePath = path.join(__dirname, '../../package.default.json'); +var packageDefaultFilePath = path.join(__dirname, '../../install/package.json'); var modulesPath = path.join(__dirname, '../../node_modules'); function updatePackageFile() { @@ -53,13 +53,16 @@ function preserveExtraneousPlugins() { var packageContents = JSON.parse(fs.readFileSync(packageFilePath, 'utf8')); var extraneous = packages - // only extraneous plugins (ones not in package.json) + // only extraneous plugins (ones not in package.json) which are not links .filter(function (pkgName) { - return !packageContents.dependencies.hasOwnProperty(pkgName); + const extraneous = !packageContents.dependencies.hasOwnProperty(pkgName); + const isLink = fs.lstatSync(path.join(modulesPath, pkgName)).isSymbolicLink(); + + return extraneous && !isLink; }) // reduce to a map of package names to package versions .reduce(function (map, pkgName) { - var pkgConfig = JSON.parse(fs.readFileSync(path.join(modulesPath, pkgName, 'package.json'))); + var pkgConfig = JSON.parse(fs.readFileSync(path.join(modulesPath, pkgName, 'package.json'), 'utf8')); map[pkgName] = pkgConfig.version; return map; }, {}); diff --git a/src/meta/tags.js b/src/meta/tags.js index 79cb04cded..babd1d5f9d 100644 --- a/src/meta/tags.js +++ b/src/meta/tags.js @@ -1,12 +1,12 @@ 'use strict'; var nconf = require('nconf'); -var validator = require('validator'); var async = require('async'); var winston = require('winston'); var plugins = require('../plugins'); var Meta = require('../meta'); +var utils = require('../utils'); var Tags = module.exports; @@ -66,7 +66,7 @@ Tags.parse = function (req, data, meta, link, callback) { defaultLinks.push({ rel: 'search', type: 'application/opensearchdescription+xml', - title: validator.escape(String(Meta.config.title || Meta.config.browserTitle || 'NodeBB')), + title: utils.escapeHTML(String(Meta.config.title || Meta.config.browserTitle || 'NodeBB')), href: nconf.get('relative_path') + '/osd.xml', }); } @@ -116,7 +116,7 @@ Tags.parse = function (req, data, meta, link, callback) { } if (!tag.noEscape) { - tag.content = validator.escape(String(tag.content)); + tag.content = utils.escapeHTML(String(tag.content)); } return tag; @@ -124,7 +124,7 @@ Tags.parse = function (req, data, meta, link, callback) { addIfNotExists(meta, 'property', 'og:title', Meta.config.title || 'NodeBB'); - var ogUrl = nconf.get('url') + req.path; + var ogUrl = nconf.get('url') + (req.originalUrl !== '/' ? req.originalUrl : ''); addIfNotExists(meta, 'property', 'og:url', ogUrl); addIfNotExists(meta, 'name', 'description', Meta.config.description); @@ -159,7 +159,7 @@ function addIfNotExists(meta, keyName, tagName, value) { if (!exists && value) { var data = { - content: validator.escape(String(value)), + content: utils.escapeHTML(String(value)), }; data[keyName] = tagName; meta.push(data); diff --git a/src/meta/templates.js b/src/meta/templates.js index 4f9f59d861..943978ff56 100644 --- a/src/meta/templates.js +++ b/src/meta/templates.js @@ -15,41 +15,40 @@ var viewsPath = nconf.get('views_dir'); var Templates = module.exports; +function processImports(paths, templatePath, source, callback) { + var regex = //; + + var matches = source.match(regex); + + if (!matches) { + return callback(null, source); + } + + var partial = '/' + matches[1]; + if (paths[partial] && templatePath !== partial) { + fs.readFile(paths[partial], 'utf8', function (err, partialSource) { + if (err) { + return callback(err); + } + + source = source.replace(regex, partialSource); + processImports(paths, templatePath, source, callback); + }); + } else { + winston.warn('[meta/templates] Partial not loaded: ' + matches[1]); + source = source.replace(regex, ''); + + processImports(paths, templatePath, source, callback); + } +} +Templates.processImports = processImports; + Templates.compile = function (callback) { callback = callback || function () {}; var themeConfig = require(nconf.get('theme_config')); var baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')]; - function processImports(paths, relativePath, source, callback) { - var regex = //; - - var matches = source.match(regex); - - if (!matches) { - return callback(null, source); - } - - var partial = '/' + matches[1]; - if (paths[partial] && relativePath !== partial) { - fs.readFile(paths[partial], function (err, file) { - if (err) { - return callback(err); - } - - var partialSource = file.toString(); - source = source.replace(regex, partialSource); - - processImports(paths, relativePath, source, callback); - }); - } else { - winston.warn('[meta/templates] Partial not loaded: ' + matches[1]); - source = source.replace(regex, ''); - - processImports(paths, relativePath, source, callback); - } - } - async.waterfall([ function (next) { preparePaths(baseTemplatesPaths, next); @@ -58,10 +57,9 @@ Templates.compile = function (callback) { async.each(Object.keys(paths), function (relativePath, next) { async.waterfall([ function (next) { - fs.readFile(paths[relativePath], next); + fs.readFile(paths[relativePath], 'utf8', next); }, - function (file, next) { - var source = file.toString(); + function (source, next) { processImports(paths, relativePath, source, next); }, function (source, next) { diff --git a/src/meta/themes.js b/src/meta/themes.js index 2ebc091036..e6eeb7011d 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -42,7 +42,7 @@ Themes.get = function (callback) { async.map(themes, function (theme, next) { var config = path.join(themePath, theme, 'theme.json'); - fs.readFile(config, function (err, file) { + fs.readFile(config, 'utf8', function (err, file) { if (err) { if (err.code === 'ENOENT') { return next(null, null); @@ -50,7 +50,7 @@ Themes.get = function (callback) { return next(err); } try { - var configObj = JSON.parse(file.toString()); + var configObj = JSON.parse(file); // Minor adjustments for API output configObj.type = 'local'; @@ -96,9 +96,9 @@ Themes.set = function (data, callback) { }); }, function (next) { - fs.readFile(path.join(nconf.get('themes_path'), data.id, 'theme.json'), function (err, config) { + fs.readFile(path.join(nconf.get('themes_path'), data.id, 'theme.json'), 'utf8', function (err, config) { if (!err) { - config = JSON.parse(config.toString()); + config = JSON.parse(config); next(null, config); } else { next(err); diff --git a/src/middleware/index.js b/src/middleware/index.js index d5f7e5e6a3..cb91f82339 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -203,12 +203,19 @@ middleware.delayLoading = function (req, res, next) { }; var viewsDir = nconf.get('views_dir'); +var workingCache = {}; + middleware.templatesOnDemand = function (req, res, next) { var filePath = req.filePath || path.join(viewsDir, req.path); if (!filePath.endsWith('.js')) { return next(); } + if (workingCache[filePath]) { + workingCache[filePath].push(next); + return; + } + async.waterfall([ function (cb) { file.exists(filePath, cb); @@ -218,16 +225,31 @@ middleware.templatesOnDemand = function (req, res, next) { return next(); } - fs.readFile(filePath.replace(/\.js$/, '.tpl'), cb); + // need to check here again + // because compilation could have started since last check + if (workingCache[filePath]) { + workingCache[filePath].push(next); + return; + } + + workingCache[filePath] = [next]; + fs.readFile(filePath.replace(/\.js$/, '.tpl'), 'utf8', cb); }, function (source, cb) { Benchpress.precompile({ - source: source.toString(), + source: source, minify: global.env !== 'development', }, cb); }, function (compiled, cb) { fs.writeFile(filePath, compiled, cb); }, - ], next); + ], function (err) { + var arr = workingCache[filePath]; + workingCache[filePath] = null; + + arr.forEach(function (callback) { + callback(err); + }); + }); }; diff --git a/src/middleware/render.js b/src/middleware/render.js index f0e77540b4..a4571b6879 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -8,6 +8,7 @@ var winston = require('winston'); var plugins = require('../plugins'); var translator = require('../translator'); var widgets = require('../widgets'); +var utils = require('../utils'); module.exports = function (middleware) { middleware.processRender = function (req, res, next) { @@ -40,7 +41,7 @@ module.exports = function (middleware) { options.template = { name: template }; options.template[template] = true; options.url = (req.baseUrl + req.path.replace(/^\/api/, '')); - options.bodyClass = buildBodyClass(req); + options.bodyClass = buildBodyClass(req, options); plugins.fireHook('filter:' + template + '.build', { req: req, res: res, templateData: options }, next); }, @@ -125,7 +126,7 @@ module.exports = function (middleware) { }); } - function buildBodyClass(req) { + function buildBodyClass(req, templateData) { var clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, ''); var parts = clean.split('/').slice(0, 3); parts.forEach(function (p, index) { @@ -138,6 +139,12 @@ module.exports = function (middleware) { p = validator.escape(String(p)); parts[index] = index ? parts[0] + '-' + p : 'page-' + (p || 'home'); }); + + if (templateData.template.topic) { + parts.push('page-topic-category-' + templateData.category.cid); + parts.push('page-topic-category-' + utils.slugify(templateData.category.name)); + } + return parts.join(' '); } }; diff --git a/src/middleware/user.js b/src/middleware/user.js index b80b91fea3..e3123e6942 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -140,6 +140,22 @@ module.exports = function (middleware) { ], next); }; + middleware.redirectMeToUserslug = function (req, res, next) { + var uid = req.uid; + async.waterfall([ + function (next) { + user.getUserField(uid, 'userslug', next); + }, + function (userslug) { + if (!userslug) { + return controllers.helpers.notAllowed(req, res); + } + var path = req.path.replace(/^(\/api)?\/me/, '/user/' + userslug); + controllers.helpers.redirect(res, path); + }, + ], next); + }; + middleware.isAdmin = function (req, res, next) { async.waterfall([ function (next) { @@ -157,10 +173,12 @@ module.exports = function (middleware) { } var loginTime = req.session.meta ? req.session.meta.datetime : 0; - if (loginTime && parseInt(loginTime, 10) > Date.now() - 3600000) { - var timeLeft = parseInt(loginTime, 10) - (Date.now() - 3600000); - if (timeLeft < 300000) { - req.session.meta.datetime += 300000; + var adminReloginDuration = (meta.config.adminReloginDuration || 60) * 60000; + var disabled = parseInt(meta.config.adminReloginDuration, 10) === 0; + if (disabled || (loginTime && parseInt(loginTime, 10) > Date.now() - adminReloginDuration)) { + var timeLeft = parseInt(loginTime, 10) - (Date.now() - adminReloginDuration); + if (timeLeft < Math.min(300000, adminReloginDuration)) { + req.session.meta.datetime += Math.min(300000, adminReloginDuration); } return next(); diff --git a/src/notifications.js b/src/notifications.js index cbc58dae8e..6a7940d50d 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -13,6 +13,7 @@ var meta = require('./meta'); var batch = require('./batch'); var plugins = require('./plugins'); var utils = require('./utils'); +var emailer = require('./emailer'); var Notifications = module.exports; @@ -178,9 +179,78 @@ Notifications.push = function (notification, uids, callback) { }; function pushToUids(uids, notification, callback) { - var oneWeekAgo = Date.now() - 604800000; - var unreadKeys = []; - var readKeys = []; + function sendNotification(uids, callback) { + if (!uids.length) { + return callback(); + } + var oneWeekAgo = Date.now() - 604800000; + var unreadKeys = []; + var readKeys = []; + async.waterfall([ + function (next) { + uids.forEach(function (uid) { + unreadKeys.push('uid:' + uid + ':notifications:unread'); + readKeys.push('uid:' + uid + ':notifications:read'); + }); + + db.sortedSetsAdd(unreadKeys, notification.datetime, notification.nid, next); + }, + function (next) { + db.sortedSetsRemove(readKeys, notification.nid, next); + }, + function (next) { + db.sortedSetsRemoveRangeByScore(unreadKeys, '-inf', oneWeekAgo, next); + }, + function (next) { + db.sortedSetsRemoveRangeByScore(readKeys, '-inf', oneWeekAgo, next); + }, + function (next) { + var websockets = require('./socket.io'); + if (websockets.server) { + uids.forEach(function (uid) { + websockets.in('uid_' + uid).emit('event:new_notification', notification); + }); + } + next(); + }, + ], callback); + } + + function sendEmail(uids, callback) { + async.eachLimit(uids, 3, function (uid, next) { + emailer.send('notification', uid, { + path: notification.path, + subject: '[[notifications:new_notification_from, ' + meta.config.title + ']]', + intro: utils.stripHTMLTags(notification.bodyShort), + body: utils.stripHTMLTags(notification.bodyLong || ''), + showUnsubscribe: true, + }, next); + }, callback); + } + + function getUidsBySettings(uids, callback) { + var uidsToNotify = []; + var uidsToEmail = []; + async.waterfall([ + function (next) { + User.getMultipleUserSettings(uids, next); + }, + function (usersSettings, next) { + usersSettings.forEach(function (userSettings) { + var setting = userSettings['notificationType_' + notification.type] || 'notification'; + + if (setting === 'notification' || setting === 'notificationemail') { + uidsToNotify.push(userSettings.uid); + } + + if (setting === 'email' || setting === 'notificationemail') { + uidsToEmail.push(userSettings.uid); + } + }); + next(null, { uidsToNotify: uidsToNotify, uidsToEmail: uidsToEmail }); + }, + ], callback); + } async.waterfall([ function (next) { @@ -190,35 +260,32 @@ function pushToUids(uids, notification, callback) { if (!data || !data.notification || !data.uids || !data.uids.length) { return callback(); } - - uids = data.uids; notification = data.notification; - - uids.forEach(function (uid) { - unreadKeys.push('uid:' + uid + ':notifications:unread'); - readKeys.push('uid:' + uid + ':notifications:read'); - }); - - db.sortedSetsAdd(unreadKeys, notification.datetime, notification.nid, next); - }, - function (next) { - db.sortedSetsRemove(readKeys, notification.nid, next); - }, - function (next) { - db.sortedSetsRemoveRangeByScore(unreadKeys, '-inf', oneWeekAgo, next); - }, - function (next) { - db.sortedSetsRemoveRangeByScore(readKeys, '-inf', oneWeekAgo, next); - }, - function (next) { - var websockets = require('./socket.io'); - if (websockets.server) { - uids.forEach(function (uid) { - websockets.in('uid_' + uid).emit('event:new_notification', notification); - }); + if (notification.type) { + getUidsBySettings(data.uids, next); + } else { + next(null, { uidsToNotify: data.uids, uidsToEmail: [] }); } - - plugins.fireHook('action:notification.pushed', { notification: notification, uids: uids }); + }, + function (results, next) { + async.parallel([ + function (next) { + sendNotification(results.uidsToNotify, next); + }, + function (next) { + sendEmail(results.uidsToEmail, next); + }, + ], function (err) { + next(err, results); + }); + }, + function (results, next) { + plugins.fireHook('action:notification.pushed', { + notification: notification, + uids: results.uidsToNotify, + uidsNotified: results.uidsToNotify, + uidsEmailed: results.uidsToEmail, + }); next(); }, ], callback); diff --git a/src/plugins.js b/src/plugins.js index cc15650357..653edee5fe 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -97,12 +97,12 @@ Plugins.reload = function (callback) { function (next) { // If some plugins are incompatible, throw the warning here if (Plugins.versionWarning.length && nconf.get('isPrimary') === 'true') { - process.stdout.write('\n'); + console.log(''); winston.warn('[plugins/load] The following plugins may not be compatible with your version of NodeBB. This may cause unintended behaviour or crashing. In the event of an unresponsive NodeBB caused by this plugin, run `./nodebb reset -p PLUGINNAME` to disable it.'); for (var x = 0, numPlugins = Plugins.versionWarning.length; x < numPlugins; x += 1) { - process.stdout.write(' * '.yellow + Plugins.versionWarning[x] + '\n'); + console.log(' * '.yellow + Plugins.versionWarning[x]); } - process.stdout.write('\n'); + console.log(''); } Object.keys(Plugins.loadedHooks).forEach(function (hook) { @@ -119,10 +119,6 @@ Plugins.reload = function (callback) { Plugins.reloadRoutes = function (callback) { var router = express.Router(); - // var ensureLoggedIn = require('connect-ensure-login'); - - // router.all('(/api/admin|/api/admin/*?)', middleware.isAdmin); - // router.all('(/admin|/admin/*?)', ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login?local=1'), middleware.applyCSRF, middleware.isAdmin); router.hotswapId = 'plugins'; router.render = function () { @@ -219,7 +215,7 @@ Plugins.list = function (matching, callback) { }, function (err, res, body) { if (err) { winston.error('Error parsing plugins', err); - return callback(err); + return Plugins.normalise([], callback); } Plugins.normalise(body, callback); diff --git a/src/plugins/data.js b/src/plugins/data.js index b793a365d0..0dd7fa3a67 100644 --- a/src/plugins/data.js +++ b/src/plugins/data.js @@ -33,10 +33,10 @@ Data.getPluginPaths = getPluginPaths; function loadPluginInfo(pluginPath, callback) { async.parallel({ package: function (next) { - fs.readFile(path.join(pluginPath, 'package.json'), next); + fs.readFile(path.join(pluginPath, 'package.json'), 'utf8', next); }, plugin: function (next) { - fs.readFile(path.join(pluginPath, 'plugin.json'), next); + fs.readFile(path.join(pluginPath, 'plugin.json'), 'utf8', next); }, }, function (err, results) { if (err) { diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 71b91beeef..020ea4e024 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -82,20 +82,23 @@ module.exports = function (Plugins) { var hookList = Plugins.loadedHooks[hook]; var hookType = hook.split(':')[0]; - - switch (hookType) { - case 'filter': - fireFilterHook(hook, hookList, params, callback); - break; - case 'action': - fireActionHook(hook, hookList, params, callback); - break; - case 'static': - fireStaticHook(hook, hookList, params, callback); - break; - default: - winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); - break; + try { + switch (hookType) { + case 'filter': + fireFilterHook(hook, hookList, params, callback); + break; + case 'action': + fireActionHook(hook, hookList, params, callback); + break; + case 'static': + fireStaticHook(hook, hookList, params, callback); + break; + default: + winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); + break; + } + } catch (err) { + callback(err); } }; diff --git a/src/posts.js b/src/posts.js index f6b22b89ed..cf30bd4c64 100644 --- a/src/posts.js +++ b/src/posts.js @@ -256,11 +256,27 @@ Posts.updatePostVoteCount = function (postData, callback) { function (next) { async.waterfall([ function (next) { - topics.getTopicField(postData.tid, 'mainPid', next); + topics.getTopicFields(postData.tid, ['mainPid', 'cid'], next); }, - function (mainPid, next) { - if (parseInt(mainPid, 10) === parseInt(postData.pid, 10)) { - return next(); + function (topicData, next) { + if (parseInt(topicData.mainPid, 10) === parseInt(postData.pid, 10)) { + async.parallel([ + function (next) { + topics.setTopicFields(postData.tid, { + upvotes: postData.upvotes, + downvotes: postData.downvotes, + }, next); + }, + function (next) { + db.sortedSetAdd('topics:votes', postData.votes, postData.tid, next); + }, + function (next) { + db.sortedSetAdd('cid:' + topicData.cid + ':tids:votes', postData.votes, postData.tid, next); + }, + ], function (err) { + next(err); + }); + return; } db.sortedSetAdd('tid:' + postData.tid + ':posts:votes', postData.votes, postData.pid, next); }, @@ -270,7 +286,10 @@ Posts.updatePostVoteCount = function (postData, callback) { db.sortedSetAdd('posts:votes', postData.votes, postData.pid, next); }, function (next) { - Posts.setPostFields(postData.pid, { upvotes: postData.upvotes, downvotes: postData.downvotes }, next); + Posts.setPostFields(postData.pid, { + upvotes: postData.upvotes, + downvotes: postData.downvotes, + }, next); }, ], function (err) { callback(err); diff --git a/src/posts/queue.js b/src/posts/queue.js index 553fbb764e..6d8001f2f7 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -53,17 +53,25 @@ module.exports = function (Posts) { user.setUserField(data.uid, 'lastqueuetime', Date.now(), next); }, function (next) { - notifications.create({ - nid: 'post-queued-' + id, - mergeId: 'post-queue', - bodyShort: '[[notifications:post_awaiting_review]]', - bodyLong: data.content, - path: '/post-queue', + async.parallel({ + notification: function (next) { + notifications.create({ + type: 'post-queue', + nid: 'post-queue-' + id, + mergeId: 'post-queue', + bodyShort: '[[notifications:post_awaiting_review]]', + bodyLong: data.content, + path: '/post-queue', + }, next); + }, + cid: function (next) { + getCid(type, data, next); + }, }, next); }, - function (notification, next) { - if (notification) { - notifications.pushGroups(notification, ['administrators', 'Global Moderators'], next); + function (results, next) { + if (results.notification) { + notifications.pushGroups(results.notification, ['administrators', 'Global Moderators', 'cid:' + results.cid + ':privileges:moderate'], next); } else { next(); } @@ -79,20 +87,26 @@ module.exports = function (Posts) { ], callback); }; + function getCid(type, data, callback) { + if (type === 'topic') { + return setImmediate(callback, null, data.cid); + } else if (type === 'reply') { + topics.getTopicField(data.tid, 'cid', callback); + } else { + return setImmediate(callback, null, null); + } + } + function canPost(type, data, callback) { async.waterfall([ function (next) { - if (type === 'topic') { - next(null, data.cid); - } else if (type === 'reply') { - topics.getTopicField(data.tid, 'cid', next); - } + getCid(type, data, next); }, function (cid, next) { async.parallel({ canPost: function (next) { if (type === 'topic') { - privileges.categories.can('topics:create', data.cid, data.uid, next); + privileges.categories.can('topics:create', cid, data.uid, next); } else if (type === 'reply') { privileges.categories.can('topics:reply', cid, data.uid, next); } diff --git a/src/posts/votes.js b/src/posts/votes.js index 5598be9b24..f7fdde759e 100644 --- a/src/posts/votes.js +++ b/src/posts/votes.js @@ -153,7 +153,7 @@ module.exports = function (Posts) { }, function (results, next) { if (parseInt(uid, 10) === parseInt(results.owner, 10)) { - return callback(new Error('self-vote')); + return callback(new Error('[[error:self-vote]]')); } if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['privileges:downvote'], 10)) { @@ -232,6 +232,7 @@ module.exports = function (Posts) { user: { reputation: newreputation, }, + fromuid: uid, post: postData, upvote: type === 'upvote' && !unvote, downvote: type === 'downvote' && !unvote, diff --git a/src/prestart.js b/src/prestart.js new file mode 100644 index 0000000000..dbc904b3a8 --- /dev/null +++ b/src/prestart.js @@ -0,0 +1,83 @@ +'use strict'; + +var nconf = require('nconf'); +var url = require('url'); +var winston = require('winston'); +var path = require('path'); + +var pkg = require('../package.json'); +var dirname = require('./cli/paths').baseDir; + +function setupWinston() { + winston.remove(winston.transports.Console); + winston.add(winston.transports.Console, { + colorize: nconf.get('log-colorize') !== 'false', + timestamp: function () { + var date = new Date(); + return nconf.get('json-logging') ? date.toJSON() : + date.toISOString() + ' [' + global.process.pid + ']'; + }, + level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'), + json: !!nconf.get('json-logging'), + stringify: !!nconf.get('json-logging'), + }); +} + +function loadConfig(configFile) { + winston.verbose('* using configuration stored in: %s', configFile); + + nconf.file({ + file: configFile, + }); + + nconf.defaults({ + base_dir: dirname, + themes_path: path.join(dirname, 'node_modules'), + upload_path: 'public/uploads', + views_dir: path.join(dirname, 'build/public/templates'), + version: pkg.version, + }); + + if (!nconf.get('isCluster')) { + nconf.set('isPrimary', 'true'); + nconf.set('isCluster', 'false'); + } + + // Ensure themes_path is a full filepath + nconf.set('themes_path', path.resolve(dirname, nconf.get('themes_path'))); + nconf.set('core_templates_path', path.join(dirname, 'src/views')); + nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); + + nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path'))); + + if (nconf.get('url')) { + nconf.set('url_parsed', url.parse(nconf.get('url'))); + } + + // Explicitly cast 'jobsDisabled' as Bool + var castAsBool = ['jobsDisabled']; + nconf.stores.env.readOnly = false; + castAsBool.forEach(function (prop) { + var value = nconf.get(prop); + if (value) { + nconf.set(prop, typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true'); + } + }); + nconf.stores.env.readOnly = true; +} + +function versionCheck() { + var version = process.version.slice(1); + var range = pkg.engines.node; + var semver = require('semver'); + var compatible = semver.satisfies(version, range); + + if (!compatible) { + winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.'); + winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset); + } +} + +exports.setupWinston = setupWinston; +exports.loadConfig = loadConfig; +exports.versionCheck = versionCheck; diff --git a/src/privileges/posts.js b/src/privileges/posts.js index f2bfe38428..b157fa798b 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -200,7 +200,7 @@ module.exports = function (privileges) { }, next); }, function (results, next) { - var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 1; + var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0; var canFlag = results.isAdminOrMod || parseInt(results.userReputation, 10) >= minimumReputation; next(null, { flag: canFlag }); }, diff --git a/src/routes/accounts.js b/src/routes/accounts.js index 336a38e442..5c040b6af1 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -7,7 +7,8 @@ module.exports = function (app, middleware, controllers) { var middlewares = [middleware.checkGlobalPrivacySettings]; var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]; - setupPageRoute(app, '/uid/:uid/:section1?/:section2?', middleware, [], middleware.redirectUidToUserslug); + setupPageRoute(app, '/me/*', middleware, [], middleware.redirectMeToUserslug); + setupPageRoute(app, '/uid/:uid*', middleware, [], middleware.redirectUidToUserslug); setupPageRoute(app, '/user/:userslug', middleware, middlewares, controllers.accounts.profile.get); setupPageRoute(app, '/user/:userslug/following', middleware, middlewares, controllers.accounts.follow.getFollowing); diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 5aaf3590c2..eba2fee4ee 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -19,6 +19,7 @@ module.exports = function (app, middleware) { app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic); app.get('/category/:category_id.rss', middleware.maintenanceMode, generateForCategory); app.get('/recent.rss', middleware.maintenanceMode, generateForRecent); + app.get('/top.rss', middleware.maintenanceMode, generateForTop); app.get('/popular.rss', middleware.maintenanceMode, generateForPopular); app.get('/popular/:term.rss', middleware.maintenanceMode, generateForPopular); app.get('/recentposts.rss', middleware.maintenanceMode, generateForRecentPosts); @@ -209,6 +210,34 @@ function generateForRecent(req, res, next) { ], next); } +function generateForTop(req, res, next) { + if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { + return controllers404.send404(req, res); + } + + async.waterfall([ + function (next) { + if (req.query.token && req.query.uid) { + db.getObjectField('user:' + req.query.uid, 'rss_token', next); + } else { + next(null, null); + } + }, + function (token, next) { + next(null, token && token === req.query.token ? req.query.uid : req.uid); + }, + function (uid, next) { + generateForTopics({ + uid: uid, + title: 'Top Voted Topics', + description: 'A list of topics that have received the most votes', + feed_url: '/top.rss', + site_url: '/top', + }, 'topics:votes', req, res, next); + }, + ], next); +} + function generateForPopular(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { return controllers404.send404(req, res); diff --git a/src/routes/helpers.js b/src/routes/helpers.js index 0aae67cbec..8cf4e38c90 100644 --- a/src/routes/helpers.js +++ b/src/routes/helpers.js @@ -1,6 +1,6 @@ 'use strict'; -var helpers = {}; +var helpers = module.exports; helpers.setupPageRoute = function (router, name, middleware, middlewares, controller) { middlewares = [middleware.maintenanceMode, middleware.registrationComplete, middleware.pageView, middleware.pluginHooks].concat(middlewares); @@ -13,5 +13,3 @@ helpers.setupAdminPageRoute = function (router, name, middleware, middlewares, c router.get(name, middleware.admin.buildHeader, middlewares, controller); router.get('/api' + name, middlewares, controller); }; - -module.exports = helpers; diff --git a/src/routes/index.js b/src/routes/index.js index 9feaa0ff60..ce0a4045e8 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -65,6 +65,7 @@ function categoryRoutes(app, middleware, controllers) { setupPageRoute(app, '/categories', middleware, [], controllers.categories.list); setupPageRoute(app, '/popular/:term?', middleware, [], controllers.popular.get); setupPageRoute(app, '/recent/:filter?', middleware, [], controllers.recent.get); + setupPageRoute(app, '/top/:filter?', middleware, [], controllers.top.get); setupPageRoute(app, '/unread/:filter?', middleware, [middleware.authenticate], controllers.unread.get); setupPageRoute(app, '/category/:category_id/:slug/:topic_index', middleware, [], controllers.category.get); @@ -122,7 +123,9 @@ module.exports = function (app, middleware, hotswapIds, callback) { app.use(middleware.stripLeadingSlashes); // handle custom homepage routes - app.use(relativePath, controllers.home); + app.use(relativePath, controllers.home.rewrite); + // homepage handled by `action:homepage.get:[route]` + setupPageRoute(app, '/', middleware, [], controllers.home.pluginHook); adminRoutes(router, middleware, controllers); metaRoutes(router, middleware, controllers); diff --git a/src/search.js b/src/search.js index 71f212632e..4d2560e6cf 100644 --- a/src/search.js +++ b/src/search.js @@ -209,7 +209,7 @@ function getMatchedPosts(pids, data, callback) { db.getObjectsFields(cids, categoryFields, next); }, tags: function (next) { - if (data.hasTags && data.hasTags.length) { + if (Array.isArray(data.hasTags) && data.hasTags.length) { var tids = posts.map(function (post) { return post && post.tid; }); @@ -299,10 +299,10 @@ function filterByTimerange(posts, timeRange, timeFilter) { } function filterByTags(posts, hasTags) { - if (hasTags && hasTags.length) { + if (Array.isArray(hasTags) && hasTags.length) { posts = posts.filter(function (post) { var hasAllTags = false; - if (post && post.topic && post.topic.tags && post.topic.tags.length) { + if (post && post.topic && Array.isArray(post.topic.tags) && post.topic.tags.length) { hasAllTags = hasTags.every(function (tag) { return post.topic.tags.indexOf(tag) !== -1; }); diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 7e0eb64d98..628bbd97da 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -232,7 +232,7 @@ SocketAdmin.email.test = function (socket, data, callback) { switch (data.template) { case 'digest': userDigest.execute({ - interval: 'day', + interval: 'alltime', subscribers: [socket.uid], }, callback); break; diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 3fb4dfb9ff..d8d9a0f282 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -183,7 +183,11 @@ User.search = function (socket, data, callback) { var searchData; async.waterfall([ function (next) { - user.search({ query: data.query, searchBy: data.searchBy, uid: socket.uid }, next); + user.search({ + query: data.query, + searchBy: data.searchBy, + uid: socket.uid, + }, next); }, function (_searchData, next) { searchData = _searchData; diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index cbc01aff60..ae4c2b0b5a 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -13,7 +13,7 @@ var notifications = require('../notifications'); var plugins = require('../plugins'); var utils = require('../utils'); -var SocketHelpers = {}; +var SocketHelpers = module.exports; SocketHelpers.notifyOnlineUsers = function (uid, result) { winston.warn('[deprecated] SocketHelpers.notifyOnlineUsers, consider using socketHelpers.notifyNew(uid, \'newPost\', result);'); @@ -171,6 +171,51 @@ SocketHelpers.sendNotificationToTopicOwner = function (tid, fromuid, command, no }); }; +SocketHelpers.upvote = function (data, notification) { + if (!data || !data.post || !data.post.uid || !data.post.votes || !data.post.pid || !data.fromuid) { + return; + } + + var votes = data.post.votes; + var touid = data.post.uid; + var fromuid = data.fromuid; + var pid = data.post.pid; + + var shouldNotify = { + all: function () { + return votes > 0; + }, + everyTen: function () { + return votes > 0 && votes % 10 === 0; + }, + logarithmic: function () { + return votes > 1 && Math.log10(votes) % 1 === 0; + }, + disabled: function () { + return false; + }, + }; + + async.waterfall([ + function (next) { + user.getSettings(touid, next); + }, + function (settings, next) { + var should = shouldNotify[settings.upvoteNotifFreq] || shouldNotify.all; + + if (should()) { + SocketHelpers.sendNotificationToPostOwner(pid, fromuid, 'upvote', notification); + } + + next(); + }, + ], function (err) { + if (err) { + winston.error(err); + } + }); +}; + SocketHelpers.rescindUpvoteNotification = function (pid, fromuid) { var uid; async.waterfall([ @@ -199,5 +244,3 @@ SocketHelpers.emitToTopicAndCategory = function (event, data) { websockets.in('topic_' + data.tid).emit(event, data); websockets.in('category_' + data.cid).emit(event, data); }; - -module.exports = SocketHelpers; diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 172d91e60f..d58fb7fa59 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -21,17 +21,31 @@ SocketModules.settings = {}; /* Chat */ SocketModules.chats.getRaw = function (socket, data, callback) { - if (!data || !data.hasOwnProperty('mid') || !data.hasOwnProperty('roomId')) { + if (!data || !data.hasOwnProperty('mid')) { return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ function (next) { - Messaging.isUserInRoom(socket.uid, data.roomId, next); + Messaging.getMessageField(data.mid, 'roomId', next); }, - function (inRoom, next) { - if (!inRoom) { + function (roomId, next) { + async.parallel({ + isAdmin: function (next) { + user.isAdministrator(socket.uid, next); + }, + hasMessage: function (next) { + db.isSortedSetMember('uid:' + socket.uid + ':chat:room:' + roomId + ':mids', data.mid, next); + }, + inRoom: function (next) { + Messaging.isUserInRoom(socket.uid, roomId, next); + }, + }, next); + }, + function (results, next) { + if (!results.isAdmin && (!results.inRoom || !results.hasMessage)) { return next(new Error('[[error:not-allowed]]')); } + Messaging.getMessageField(data.mid, 'content', next); }, ], callback); @@ -232,10 +246,7 @@ SocketModules.chats.edit = function (socket, data, callback) { function (next) { Messaging.canEdit(data.mid, socket.uid, next); }, - function (allowed, next) { - if (!allowed) { - return next(new Error('[[error:cant-edit-chat-message]]')); - } + function (next) { Messaging.editMessage(socket.uid, data.mid, data.roomId, data.message, next); }, ], callback); @@ -248,13 +259,9 @@ SocketModules.chats.delete = function (socket, data, callback) { async.waterfall([ function (next) { - Messaging.canEdit(data.messageId, socket.uid, next); + Messaging.canDelete(data.messageId, socket.uid, next); }, - function (allowed, next) { - if (!allowed) { - return next(new Error('[[error:cant-delete-chat-message]]')); - } - + function (next) { Messaging.deleteMessage(data.messageId, data.roomId, next); }, ], callback); diff --git a/src/socket.io/posts/helpers.js b/src/socket.io/posts/helpers.js index a9bb9b451d..a4438ba981 100644 --- a/src/socket.io/posts/helpers.js +++ b/src/socket.io/posts/helpers.js @@ -69,7 +69,9 @@ function executeCommand(socket, command, eventName, notification, data, callback websockets.in(data.room_id).emit('event:' + eventName, result); } - if (result && notification) { + if (result && command === 'upvote') { + socketHelpers.upvote(result, notification); + } else if (result && notification) { socketHelpers.sendNotificationToPostOwner(data.pid, socket.uid, command, notification); } else if (result && command === 'unvote') { socketHelpers.rescindUpvoteNotification(data.pid, socket.uid); diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js index 7f80ce9805..a9bbc6137b 100644 --- a/src/socket.io/posts/tools.js +++ b/src/socket.io/posts/tools.js @@ -75,7 +75,7 @@ module.exports = function (SocketPosts) { }, function (results, next) { if (results.isMain && results.isLast) { - deleteTopicOf(data.pid, socket, next); + deleteOrRestoreTopicOf('delete', data.pid, socket, next); } else { next(); } @@ -99,12 +99,23 @@ module.exports = function (SocketPosts) { if (!data || !data.pid) { return callback(new Error('[[error:invalid-data]]')); } - + var postData; async.waterfall([ function (next) { posts.tools.restore(socket.uid, data.pid, next); }, - function (postData, next) { + function (_postData, next) { + postData = _postData; + isMainAndLastPost(data.pid, next); + }, + function (results, next) { + if (results.isMain && results.isLast) { + deleteOrRestoreTopicOf('restore', data.pid, socket, next); + } else { + setImmediate(next); + } + }, + function (next) { websockets.in('topic_' + data.tid).emit('event:post_restored', postData); events.log({ @@ -185,13 +196,19 @@ module.exports = function (SocketPosts) { ], callback); }; - function deleteTopicOf(pid, socket, callback) { + function deleteOrRestoreTopicOf(command, pid, socket, callback) { async.waterfall([ function (next) { - posts.getTopicFields(pid, ['tid', 'cid'], next); + posts.getTopicFields(pid, ['tid', 'cid', 'deleted'], next); }, function (topic, next) { - socketTopics.doTopicAction('delete', 'event:topic_deleted', socket, { tids: [topic.tid], cid: topic.cid }, next); + if (parseInt(topic.deleted, 10) !== 1 && command === 'delete') { + socketTopics.doTopicAction('delete', 'event:topic_deleted', socket, { tids: [topic.tid], cid: topic.cid }, next); + } else if (parseInt(topic.deleted, 10) === 1 && command === 'restore') { + socketTopics.doTopicAction('restore', 'event:topic_restored', socket, { tids: [topic.tid], cid: topic.cid }, next); + } else { + setImmediate(next); + } }, ], callback); } diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index f8d333e67a..a7aa7a3ab0 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -16,6 +16,7 @@ require('./topics/move')(SocketTopics); require('./topics/tools')(SocketTopics); require('./topics/infinitescroll')(SocketTopics); require('./topics/tags')(SocketTopics); +require('./topics/merge')(SocketTopics); SocketTopics.post = function (socket, data, callback) { if (!data) { diff --git a/src/socket.io/topics/infinitescroll.js b/src/socket.io/topics/infinitescroll.js index 17d44712ea..18be5f6341 100644 --- a/src/socket.io/topics/infinitescroll.js +++ b/src/socket.io/topics/infinitescroll.js @@ -109,6 +109,17 @@ module.exports = function (SocketTopics) { topics.getRecentTopics(data.cid, socket.uid, start, stop, data.filter, callback); }; + SocketTopics.loadMoreTopTopics = function (socket, data, callback) { + if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { + return callback(new Error('[[error:invalid-data]]')); + } + + var start = parseInt(data.after, 10); + var stop = start + Math.max(0, Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20) - 1); + + topics.getTopTopics(data.cid, socket.uid, start, stop, data.filter, callback); + }; + SocketTopics.loadMoreFromSet = function (socket, data, callback) { if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0 || !data.set) { return callback(new Error('[[error:invalid-data]]')); diff --git a/src/socket.io/topics/merge.js b/src/socket.io/topics/merge.js new file mode 100644 index 0000000000..8b475f2ede --- /dev/null +++ b/src/socket.io/topics/merge.js @@ -0,0 +1,27 @@ +'use strict'; + +var async = require('async'); +var topics = require('../../topics'); +var privileges = require('../../privileges'); + +module.exports = function (SocketTopics) { + SocketTopics.merge = function (socket, tids, callback) { + if (!Array.isArray(tids)) { + return callback(new Error('[[error:invalid-data]]')); + } + + async.waterfall([ + function (next) { + async.map(tids, function (tid, next) { + privileges.topics.isAdminOrMod(tid, socket.uid, next); + }, next); + }, + function (allowed, next) { + if (allowed.includes(false)) { + return next(new Error('[[error:no-privileges]]')); + } + topics.merge(tids, socket.uid, next); + }, + ], callback); + }; +}; diff --git a/src/socket.io/topics/tags.js b/src/socket.io/topics/tags.js index fd0c0d0987..2c50999b70 100644 --- a/src/socket.io/topics/tags.js +++ b/src/socket.io/topics/tags.js @@ -7,7 +7,7 @@ var utils = require('../../utils'); module.exports = function (SocketTopics) { SocketTopics.isTagAllowed = function (socket, data, callback) { - if (!data || !data.cid || !data.tag) { + if (!data || !utils.isNumber(data.cid) || !data.tag) { return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ @@ -15,10 +15,7 @@ module.exports = function (SocketTopics) { db.getSortedSetRange('cid:' + data.cid + ':tag:whitelist', 0, -1, next); }, function (tagWhitelist, next) { - if (!tagWhitelist.length) { - return next(null, true); - } - next(null, tagWhitelist.indexOf(data.tag) !== -1); + next(null, !tagWhitelist.length || tagWhitelist.includes(data.tag)); }, ], callback); }; diff --git a/src/socket.io/user/picture.js b/src/socket.io/user/picture.js index 682cd59239..8f8c0577c3 100644 --- a/src/socket.io/user/picture.js +++ b/src/socket.io/user/picture.js @@ -49,23 +49,6 @@ module.exports = function (SocketUser) { ], callback); }; - SocketUser.uploadProfileImageFromUrl = function (socket, data, callback) { - if (!socket.uid || !data.url || !data.uid) { - return callback(new Error('[[error:invalid-data]]')); - } - async.waterfall([ - function (next) { - user.isAdminOrSelf(socket.uid, data.uid, next); - }, - function (next) { - user.uploadFromUrl(data.uid, data.url, next); - }, - function (uploadedImage, next) { - next(null, uploadedImage ? uploadedImage.url : null); - }, - ], callback); - }; - SocketUser.removeUploadedPicture = function (socket, data, callback) { if (!socket.uid || !data || !data.uid) { return callback(new Error('[[error:invalid-data]]')); diff --git a/src/topics.js b/src/topics.js index 5f744316c0..f20c069d98 100644 --- a/src/topics.js +++ b/src/topics.js @@ -21,6 +21,7 @@ require('./topics/delete')(Topics); require('./topics/unread')(Topics); require('./topics/recent')(Topics); require('./topics/popular')(Topics); +require('./topics/top')(Topics); require('./topics/user')(Topics); require('./topics/fork')(Topics); require('./topics/posts')(Topics); @@ -31,6 +32,7 @@ require('./topics/suggested')(Topics); require('./topics/tools')(Topics); require('./topics/thumb')(Topics); require('./topics/bookmarks')(Topics); +require('./topics/merge')(Topics); Topics.exists = function (tid, callback) { db.isSortedSetMember('topics:tid', tid, callback); @@ -164,6 +166,9 @@ Topics.getTopicsByTids = function (tids, uid, callback) { topics[i].bookmark = results.bookmarks[i]; topics[i].unreplied = !topics[i].teaser; + topics[i].upvotes = parseInt(topics[i].upvotes, 10) || 0; + topics[i].downvotes = parseInt(topics[i].downvotes, 10) || 0; + topics[i].votes = topics[i].upvotes - topics[i].downvotes; topics[i].icons = []; } } @@ -225,6 +230,10 @@ Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, topicData.locked = parseInt(topicData.locked, 10) === 1; topicData.pinned = parseInt(topicData.pinned, 10) === 1; + topicData.upvotes = parseInt(topicData.upvotes, 10) || 0; + topicData.downvotes = parseInt(topicData.downvotes, 10) || 0; + topicData.votes = topicData.upvotes - topicData.downvotes; + topicData.icons = []; plugins.fireHook('filter:topic.get', { topic: topicData, uid: uid }, next); @@ -252,7 +261,7 @@ function getMainPostAndReplies(topic, set, uid, start, stop, reverse, callback) return callback(null, []); } - if (topic.mainPid && start === 0) { + if (parseInt(topic.mainPid, 10) && start === 0) { pids.unshift(topic.mainPid); } posts.getPostsByPids(pids, uid, next); diff --git a/src/topics/delete.js b/src/topics/delete.js index 1c6f261f73..6121868c00 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -20,7 +20,12 @@ module.exports = function (Topics) { }, next); }, function (next) { - db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); + db.sortedSetsRemove([ + 'topics:recent', + 'topics:posts', + 'topics:views', + 'topics:votes', + ], tid, next); }, function (next) { async.waterfall([ @@ -48,7 +53,7 @@ module.exports = function (Topics) { var topicData; async.waterfall([ function (next) { - Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], next); + Topics.getTopicData(tid, next); }, function (_topicData, next) { topicData = _topicData; @@ -68,6 +73,11 @@ module.exports = function (Topics) { function (next) { db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); }, + function (next) { + var upvotes = parseInt(topicData.upvotes, 10) || 0; + var downvotes = parseInt(topicData.downvotes, 10) || 0; + db.sortedSetAdd('topics:votes', upvotes - downvotes, tid, next); + }, function (next) { async.waterfall([ function (next) { @@ -138,7 +148,13 @@ module.exports = function (Topics) { ], next); }, function (next) { - db.sortedSetsRemove(['topics:tid', 'topics:recent', 'topics:posts', 'topics:views'], tid, next); + db.sortedSetsRemove([ + 'topics:tid', + 'topics:recent', + 'topics:posts', + 'topics:views', + 'topics:votes', + ], tid, next); }, function (next) { deleteTopicFromCategoryAndUser(tid, next); @@ -196,6 +212,7 @@ module.exports = function (Topics) { 'cid:' + topicData.cid + ':tids:pinned', 'cid:' + topicData.cid + ':tids:posts', 'cid:' + topicData.cid + ':tids:lastposttime', + 'cid:' + topicData.cid + ':tids:votes', 'cid:' + topicData.cid + ':recent_tids', 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', 'uid:' + topicData.uid + ':topics', diff --git a/src/topics/follow.js b/src/topics/follow.js index f1bad3ccf3..cf8754bcc5 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -2,15 +2,11 @@ 'use strict'; var async = require('async'); -var winston = require('winston'); var db = require('../database'); -var user = require('../user'); var posts = require('../posts'); var notifications = require('../notifications'); var privileges = require('../privileges'); -var meta = require('../meta'); -var emailer = require('../emailer'); var plugins = require('../plugins'); var utils = require('../utils'); @@ -239,36 +235,6 @@ module.exports = function (Topics) { notifications.push(notification, followers); } - if (parseInt(meta.config.disableEmailSubscriptions, 10) === 1) { - return next(); - } - - async.eachLimit(followers, 3, function (toUid, next) { - async.parallel({ - userData: async.apply(user.getUserFields, toUid, ['username', 'userslug']), - userSettings: async.apply(user.getSettings, toUid), - }, function (err, data) { - if (err) { - return next(err); - } - - if (data.userSettings.sendPostNotifications) { - emailer.send('notif_post', toUid, { - pid: postData.pid, - subject: '[' + (meta.config.title || 'NodeBB') + '] ' + title, - intro: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + titleEscaped + ']]', - postBody: postData.content.replace(/"\/\//g, '"https://'), - username: data.userData.username, - userslug: data.userData.userslug, - topicSlug: postData.topic.slug, - showUnsubscribe: true, - }, next); - } else { - winston.debug('[topics.notifyFollowers] uid ' + toUid + ' does not have post notifications enabled, skipping.'); - next(); - } - }); - }); next(); }, ], callback); diff --git a/src/topics/merge.js b/src/topics/merge.js new file mode 100644 index 0000000000..9fd97f60eb --- /dev/null +++ b/src/topics/merge.js @@ -0,0 +1,36 @@ +'use strict'; + +var async = require('async'); + +module.exports = function (Topics) { + Topics.merge = function (tids, uid, callback) { + var mergeIntoTid = findOldestTopic(tids); + + var otherTids = tids.filter(function (tid) { + return tid && parseInt(tid, 10) !== parseInt(mergeIntoTid, 10); + }); + + async.eachSeries(otherTids, function (tid, next) { + async.waterfall([ + function (next) { + Topics.getPids(tid, next); + }, + function (pids, next) { + async.eachSeries(pids, function (pid, next) { + Topics.movePostToTopic(pid, mergeIntoTid, next); + }, next); + }, + function (next) { + Topics.setTopicField(tid, 'mainPid', 0, next); + }, + function (next) { + Topics.delete(tid, uid, next); + }, + ], next); + }, callback); + }; + + function findOldestTopic(tids) { + return Math.min.apply(null, tids); + } +}; diff --git a/src/topics/posts.js b/src/topics/posts.js index ebfbd106c0..9816d8178f 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -326,7 +326,7 @@ module.exports = function (Topics) { }, next); }, function (results, next) { - if (results.mainPid) { + if (parseInt(results.mainPid, 10)) { results.pids = [results.mainPid].concat(results.pids); } next(null, results.pids); diff --git a/src/topics/tags.js b/src/topics/tags.js index f936d7da4a..4561c950fa 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -253,6 +253,9 @@ module.exports = function (Topics) { topicTags.forEach(function (tags, index) { if (Array.isArray(tags)) { topicTags[index] = tags.map(function (tag) { return tagData[tag]; }); + topicTags[index].sort(function (tag1, tag2) { + return tag2.score - tag1.score; + }); } }); diff --git a/src/topics/teaser.js b/src/topics/teaser.js index 2827e74d41..28fbeb9a35 100644 --- a/src/topics/teaser.js +++ b/src/topics/teaser.js @@ -12,6 +12,8 @@ var plugins = require('../plugins'); var utils = require('../utils'); module.exports = function (Topics) { + var stripTeaserTags = utils.stripTags.concat(['img']); + Topics.getTeasers = function (topics, uid, callback) { if (typeof uid === 'function') { winston.warn('[Topics.getTeasers] this usage is deprecated please provide uid'); @@ -90,7 +92,7 @@ module.exports = function (Topics) { if (tidToPost[topic.tid]) { tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index]; if (tidToPost[topic.tid].content) { - tidToPost[topic.tid].content = utils.stripHTMLTags(tidToPost[topic.tid].content, utils.stripTags); + tidToPost[topic.tid].content = utils.stripHTMLTags(tidToPost[topic.tid].content, stripTeaserTags); } } return tidToPost[topic.tid]; diff --git a/src/topics/tools.js b/src/topics/tools.js index 566fb62841..be87b8826f 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -179,12 +179,15 @@ module.exports = function (Topics) { async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:pinned', Date.now(), tid), async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids', tid), async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', tid), + async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:votes', tid), ], next); } else { + var votes = (parseInt(topicData.upvotes, 10) || 0) - (parseInt(topicData.downvotes, 10) || 0); async.parallel([ async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:pinned', tid), async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids', topicData.lastposttime, tid), async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid), + async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:votes', votes, tid), ], next); } }, diff --git a/src/topics/top.js b/src/topics/top.js new file mode 100644 index 0000000000..b4f10b9340 --- /dev/null +++ b/src/topics/top.js @@ -0,0 +1,90 @@ + + +'use strict'; + +var async = require('async'); + +var db = require('../database'); +var privileges = require('../privileges'); +var user = require('../user'); +var meta = require('../meta'); + +module.exports = function (Topics) { + Topics.getTopTopics = function (cid, uid, start, stop, filter, callback) { + var topTopics = { + nextStart: 0, + topics: [], + }; + if (cid && !Array.isArray(cid)) { + cid = [cid]; + } + async.waterfall([ + function (next) { + var key = 'topics:votes'; + if (cid) { + key = cid.map(function (cid) { + return 'cid:' + cid + ':tids:votes'; + }); + } + db.getSortedSetRevRange(key, 0, 199, next); + }, + function (tids, next) { + filterTids(tids, uid, filter, cid, next); + }, + function (tids, next) { + topTopics.topicCount = tids.length; + tids = tids.slice(start, stop + 1); + Topics.getTopicsByTids(tids, uid, next); + }, + function (topicData, next) { + topTopics.topics = topicData; + topTopics.nextStart = stop + 1; + next(null, topTopics); + }, + ], callback); + }; + + function filterTids(tids, uid, filter, cid, callback) { + async.waterfall([ + function (next) { + if (filter === 'watched') { + Topics.filterWatchedTids(tids, uid, next); + } else if (filter === 'new') { + Topics.filterNewTids(tids, uid, next); + } else if (filter === 'unreplied') { + Topics.filterUnrepliedTids(tids, next); + } else { + Topics.filterNotIgnoredTids(tids, uid, next); + } + }, + function (tids, next) { + privileges.topics.filterTids('read', tids, uid, next); + }, + function (tids, next) { + async.parallel({ + ignoredCids: function (next) { + if (filter === 'watched' || parseInt(meta.config.disableRecentCategoryFilter, 10) === 1) { + return next(null, []); + } + user.getIgnoredCategories(uid, next); + }, + topicData: function (next) { + Topics.getTopicsFields(tids, ['tid', 'cid'], next); + }, + }, next); + }, + function (results, next) { + cid = cid && cid.map(String); + tids = results.topicData.filter(function (topic) { + if (topic && topic.cid) { + return results.ignoredCids.indexOf(topic.cid.toString()) === -1 && (!cid || (cid.length && cid.indexOf(topic.cid.toString()) !== -1)); + } + return false; + }).map(function (topic) { + return topic.tid; + }); + next(null, tids); + }, + ], callback); + } +}; diff --git a/src/upgrade.js b/src/upgrade.js index 7229c87227..a0ceb5b7df 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -18,7 +18,7 @@ var file = require('../src/file'); * 3. Add your script under the "method" property */ -var Upgrade = {}; +var Upgrade = module.exports; Upgrade.getAll = function (callback) { async.waterfall([ @@ -91,7 +91,7 @@ Upgrade.check = function (callback) { }; Upgrade.run = function (callback) { - process.stdout.write('\nParsing upgrade scripts... '); + console.log('\nParsing upgrade scripts... '); var queue = []; var skipped = 0; @@ -120,7 +120,7 @@ Upgrade.run = function (callback) { }; Upgrade.runParticular = function (names, callback) { - process.stdout.write('\nParsing upgrade scripts... '); + console.log('\nParsing upgrade scripts... '); async.waterfall([ async.apply(file.walk, path.join(__dirname, './upgrades')), @@ -135,7 +135,7 @@ Upgrade.runParticular = function (names, callback) { }; Upgrade.process = function (files, skipCount, callback) { - process.stdout.write('OK'.green + ' | '.reset + String(files.length).cyan + ' script(s) found'.cyan + (skipCount > 0 ? ', '.cyan + String(skipCount).cyan + ' skipped'.cyan : '') + '\n'.reset); + console.log('OK'.green + ' | '.reset + String(files.length).cyan + ' script(s) found'.cyan + (skipCount > 0 ? ', '.cyan + String(skipCount).cyan + ' skipped'.cyan : '')); async.waterfall([ function (next) { @@ -157,14 +157,14 @@ Upgrade.process = function (files, skipCount, callback) { date: date, }; - process.stdout.write(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '...\n'); + console.log(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '...'); // For backwards compatibility, cross-reference with schemaDate (if found). If a script's date is older, skip it if ((!results.schemaDate && !results.schemaLogCount) || (scriptExport.timestamp <= results.schemaDate && semver.lt(version, '1.5.0'))) { readline.clearLine(process.stdout, 0); readline.cursorTo(process.stdout, 0); readline.moveCursor(process.stdout, 0, -1); - process.stdout.write(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '... ' + 'skipped\n'.grey); + console.log(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '... ' + 'skipped'.grey); db.sortedSetAdd('schemaLog', Date.now(), path.basename(file, '.js'), next); return; } @@ -174,14 +174,14 @@ Upgrade.process = function (files, skipCount, callback) { progress: progress, })(function (err) { if (err) { - process.stdout.write('error\n'.red); + console.error('Error occurred'); return next(err); } readline.clearLine(process.stdout, 0); readline.cursorTo(process.stdout, 0); readline.moveCursor(process.stdout, 0, -1); - process.stdout.write(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '... ' + 'OK\n'.green); + console.log(' → '.white + String('[' + [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()].join('/') + '] ').gray + String(scriptExport.name).reset + '... ' + 'OK'.green); // Record success in schemaLog db.sortedSetAdd('schemaLog', Date.now(), path.basename(file, '.js'), next); @@ -189,7 +189,7 @@ Upgrade.process = function (files, skipCount, callback) { }, next); }, function (next) { - process.stdout.write('Upgrade complete!\n\n'.green); + console.log('Upgrade complete!\n'.green); setImmediate(next); }, ], callback); @@ -212,4 +212,3 @@ Upgrade.incrementProgress = function (value) { process.stdout.write(' [' + (filled ? new Array(filled).join('#') : '') + new Array(unfilled).join(' ') + '] (' + this.current + '/' + (this.total || '??') + ') ' + percentage + ' '); }; -module.exports = Upgrade; diff --git a/src/upgrades/1.7.1/notification-settings.js b/src/upgrades/1.7.1/notification-settings.js new file mode 100644 index 0000000000..df6fe27404 --- /dev/null +++ b/src/upgrades/1.7.1/notification-settings.js @@ -0,0 +1,48 @@ +'use strict'; + +var async = require('async'); +var batch = require('../../batch'); +var db = require('../../database'); + +module.exports = { + name: 'Convert old notification digest settings', + timestamp: Date.UTC(2017, 10, 15), + method: function (callback) { + var progress = this.progress; + + batch.processSortedSet('users:joindate', function (uids, next) { + async.eachLimit(uids, 500, function (uid, next) { + progress.incr(); + async.waterfall([ + function (next) { + db.getObjectFields('user:' + uid + ':settings', ['sendChatNotifications', 'sendPostNotifications'], next); + }, + function (userSettings, _next) { + if (!userSettings) { + return next(); + } + var tasks = []; + if (parseInt(userSettings.sendChatNotifications, 10) === 1) { + tasks.push(async.apply(db.setObjectField, 'user:' + uid + ':settings', 'notificationType_new-chat', 'notificationemail')); + } + if (parseInt(userSettings.sendPostNotifications, 10) === 1) { + tasks.push(async.apply(db.setObjectField, 'user:' + uid + ':settings', 'notificationType_new-reply', 'notificationemail')); + } + if (!tasks.length) { + return next(); + } + + async.series(tasks, function (err) { + _next(err); + }); + }, + function (next) { + db.deleteObjectFields('user:' + uid + ':settings', ['sendChatNotifications', 'sendPostNotifications'], next); + }, + ], next); + }, next); + }, { + progress: progress, + }, callback); + }, +}; diff --git a/src/upgrades/1.7.3/topic_votes.js b/src/upgrades/1.7.3/topic_votes.js new file mode 100644 index 0000000000..76a4d0900c --- /dev/null +++ b/src/upgrades/1.7.3/topic_votes.js @@ -0,0 +1,60 @@ +'use strict'; + +var async = require('async'); +var batch = require('../../batch'); +var db = require('../../database'); + +module.exports = { + name: 'Add votes to topics', + timestamp: Date.UTC(2017, 11, 8), + method: function (callback) { + var progress = this.progress; + + batch.processSortedSet('topics:tid', function (tids, next) { + async.eachLimit(tids, 500, function (tid, _next) { + progress.incr(); + var topicData; + async.waterfall([ + function (next) { + db.getObjectFields('topic:' + tid, ['mainPid', 'cid'], next); + }, + function (_topicData, next) { + topicData = _topicData; + if (!topicData.mainPid || !topicData.cid) { + return _next(); + } + db.getObject('post:' + topicData.mainPid, next); + }, + function (postData, next) { + if (!postData) { + return _next(); + } + var upvotes = parseInt(postData.upvotes, 10) || 0; + var downvotes = parseInt(postData.downvotes, 10) || 0; + var data = { + upvotes: upvotes, + downvotes: downvotes, + }; + var votes = upvotes - downvotes; + async.parallel([ + function (next) { + db.setObject('topic:' + tid, data, next); + }, + function (next) { + db.sortedSetAdd('topics:votes', votes, tid, next); + }, + function (next) { + db.sortedSetAdd('cid:' + topicData.cid + ':tids:votes', votes, tid, next); + }, + ], function (err) { + next(err); + }); + }, + ], _next); + }, next); + }, { + progress: progress, + batch: 500, + }, callback); + }, +}; diff --git a/src/upgrades/TEMPLATE b/src/upgrades/TEMPLATE index 9618bc4f9e..54e4e2a2c0 100644 --- a/src/upgrades/TEMPLATE +++ b/src/upgrades/TEMPLATE @@ -6,7 +6,10 @@ var async = require('async'); var winston = require('winston'); module.exports = { + // you should use spaces + // the underscores are there so you can double click to select the whole thing name: 'User_friendly_upgrade_script_name', + // remember, month is zero-indexed (so January is 0, December is 11) timestamp: Date.UTC(2017, 0, 1), method: function (callback) { // Do stuff here... diff --git a/src/user.js b/src/user.js index 3275e25db3..6661dca8a7 100644 --- a/src/user.js +++ b/src/user.js @@ -208,13 +208,17 @@ User.isGlobalModerator = function (uid, callback) { privileges.users.isGlobalModerator(uid, callback); }; +User.getPrivileges = function (uid, callback) { + async.parallel({ + isAdmin: async.apply(User.isAdministrator, uid), + isGlobalModerator: async.apply(User.isGlobalModerator, uid), + isModeratorOfAnyCategory: async.apply(User.isModeratorOfAnyCategory, uid), + }, callback); +}; + User.isPrivileged = function (uid, callback) { - async.parallel([ - async.apply(User.isAdministrator, uid), - async.apply(User.isGlobalModerator, uid), - async.apply(User.isModeratorOfAnyCategory, uid), - ], function (err, results) { - callback(err, results ? results.some(Boolean) : false); + User.getPrivileges(uid, function (err, results) { + callback(err, results ? (results.isAdmin || results.isGlobalModerator || results.isModeratorOfAnyCategory) : false); }); }; @@ -235,6 +239,10 @@ User.isAdminOrGlobalModOrSelf = function (callerUid, uid, callback) { isSelfOrMethod(callerUid, uid, User.isAdminOrGlobalMod, callback); }; +User.isPrivilegedOrSelf = function (callerUid, uid, callback) { + isSelfOrMethod(callerUid, uid, User.isPrivileged, callback); +}; + function isSelfOrMethod(callerUid, uid, method, callback) { if (parseInt(callerUid, 10) === parseInt(uid, 10)) { return callback(); diff --git a/src/user/admin.js b/src/user/admin.js index d463523f89..1b273bca48 100644 --- a/src/user/admin.js +++ b/src/user/admin.js @@ -2,21 +2,41 @@ 'use strict'; var async = require('async'); +var winston = require('winston'); +var validator = require('validator'); + var db = require('../database'); var plugins = require('../plugins'); -var winston = require('winston'); module.exports = function (User) { - User.logIP = function (uid, ip) { + User.logIP = function (uid, ip, callback) { var now = Date.now(); - db.sortedSetAdd('uid:' + uid + ':ip', now, ip || 'Unknown'); - if (ip) { - db.sortedSetAdd('ip:' + ip + ':uid', now, uid); - } + async.waterfall([ + function (next) { + db.sortedSetAdd('uid:' + uid + ':ip', now, ip || 'Unknown', next); + }, + function (next) { + if (ip) { + db.sortedSetAdd('ip:' + ip + ':uid', now, uid, next); + } else { + next(); + } + }, + ], callback); }; User.getIPs = function (uid, stop, callback) { - db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, callback); + async.waterfall([ + function (next) { + db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, next); + }, + function (ips, next) { + ips = ips.map(function (ip) { + return validator.escape(String(ip)); + }); + next(null, ips); + }, + ], callback); }; User.getUsersCSV = function (callback) { diff --git a/src/user/approval.js b/src/user/approval.js index 96c25d8ad5..a42c400109 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -4,6 +4,7 @@ var async = require('async'); var request = require('request'); var winston = require('winston'); +var validator = require('validator'); var db = require('../database'); var meta = require('../meta'); @@ -49,6 +50,7 @@ module.exports = function (User) { async.waterfall([ function (next) { notifications.create({ + type: 'new-register', bodyShort: '[[notifications:new_register, ' + username + ']]', nid: 'new_register:' + username, path: '/admin/manage/registration', @@ -167,6 +169,7 @@ module.exports = function (User) { function (users, next) { users = users.filter(Boolean).map(function (user, index) { user.timestampISO = utils.toISOString(data[index].score); + user.email = validator.escape(String(user.email)); delete user.hashedPassword; return user; }); diff --git a/src/user/auth.js b/src/user/auth.js index 1fbc316f18..195e14ce50 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -2,6 +2,7 @@ var async = require('async'); var winston = require('winston'); +var validator = require('validator'); var db = require('../database'); var meta = require('../meta'); var events = require('../events'); @@ -126,12 +127,17 @@ module.exports = function (User) { next(err, sessions); }); }, - ], function (err, sessions) { - callback(err, sessions ? sessions.map(function (sessObj) { - sessObj.meta.datetimeISO = new Date(sessObj.meta.datetime).toISOString(); - return sessObj.meta; - }) : undefined); - }); + function (sessions, next) { + sessions = sessions.map(function (sessObj) { + if (sessObj.meta) { + sessObj.meta.datetimeISO = new Date(sessObj.meta.datetime).toISOString(); + sessObj.meta.ip = validator.escape(String(sessObj.meta.ip)); + } + return sessObj.meta; + }).filter(Boolean); + next(null, sessions); + }, + ], callback); }; User.auth.addSession = function (uid, sessionId, callback) { diff --git a/src/user/data.js b/src/user/data.js index 131d034f96..db41509aa0 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -78,7 +78,11 @@ module.exports = function (User) { function (results, next) { if (fields.length) { fields = fields.filter(function (field) { - return field && results.whitelist.includes(field); + var isFieldWhitelisted = field && results.whitelist.includes(field); + if (!isFieldWhitelisted) { + winston.verbose('[user/getUsersFields] ' + field + ' removed because it is not whitelisted, see `filter:user.whietlistFields`'); + } + return isFieldWhitelisted; }); } else { fields = results.whitelist; diff --git a/src/user/digest.js b/src/user/digest.js index 0ee46deba1..dba9c48f16 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -139,6 +139,7 @@ Digest.send = function (data, callback) { notifications: notifications, recent: data.topics, interval: data.interval, + showUnsubscribe: true, }, function (err) { if (err) { winston.error('[user/jobs] Could not send digest email', err); diff --git a/src/user/invite.js b/src/user/invite.js index d3d7189296..e211a67bc7 100644 --- a/src/user/invite.js +++ b/src/user/invite.js @@ -3,6 +3,7 @@ var async = require('async'); var nconf = require('nconf'); +var validator = require('validator'); var db = require('./../database'); var meta = require('../meta'); @@ -10,10 +11,19 @@ var emailer = require('../emailer'); var translator = require('../translator'); var utils = require('../utils'); - module.exports = function (User) { User.getInvites = function (uid, callback) { - db.getSetMembers('invitation:uid:' + uid, callback); + async.waterfall([ + function (next) { + db.getSetMembers('invitation:uid:' + uid, next); + }, + function (emails, next) { + emails = emails.map(function (email) { + return validator.escape(String(email)); + }); + next(null, emails); + }, + ], callback); }; User.getInvitesNumber = function (uid, callback) { diff --git a/src/user/picture.js b/src/user/picture.js index 429b67efe9..d1a4dac7b0 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -1,8 +1,7 @@ 'use strict'; var async = require('async'); -var request = require('request'); -var mime = require('mime'); +var winston = require('winston'); var plugins = require('../plugins'); var file = require('../file'); @@ -11,48 +10,13 @@ var meta = require('../meta'); var db = require('../database'); module.exports = function (User) { - User.uploadPicture = function (uid, picture, callback) { - User.uploadCroppedPicture({ uid: uid, file: picture }, callback); - }; - - User.uploadFromUrl = function (uid, url, callback) { - if (!plugins.hasListeners('filter:uploadImage')) { - return callback(new Error('[[error:no-plugin]]')); + User.updateCoverPosition = function (uid, position, callback) { + // Reject anything that isn't two percentages + if (!/^[\d.]+%\s[\d.]+%$/.test(position)) { + winston.warn('[user/updateCoverPosition] Invalid position received: ' + position); + return callback(new Error('[[error:invalid-data]]')); } - async.waterfall([ - function (next) { - request.head(url, next); - }, - function (res, body, next) { - var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256; - var size = res.headers['content-length']; - var type = res.headers['content-type']; - var extension = mime.getExtension(type); - - if (['png', 'jpeg', 'jpg', 'gif'].indexOf(extension) === -1) { - return callback(new Error('[[error:invalid-image-extension]]')); - } - - if (size > uploadSize * 1024) { - return callback(new Error('[[error:file-too-big, ' + uploadSize + ']]')); - } - - plugins.fireHook('filter:uploadImage', { - uid: uid, - image: { - url: url, - name: '', - }, - }, next); - }, - function (image, next) { - next(null, image); - }, - ], callback); - }; - - User.updateCoverPosition = function (uid, position, callback) { User.setUserField(uid, 'cover:position', position, callback); }; diff --git a/src/user/profile.js b/src/user/profile.js index 70dffeebe6..ae1e31c475 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -196,7 +196,7 @@ module.exports = function (User) { function updateUsername(uid, newUsername, callback) { if (!newUsername) { - return callback(); + return setImmediate(callback); } async.waterfall([ @@ -204,6 +204,9 @@ module.exports = function (User) { User.getUserFields(uid, ['username', 'userslug'], next); }, function (userData, next) { + if (userData.username === newUsername) { + return callback(); + } async.parallel([ function (next) { updateUidMapping('username', uid, newUsername, userData.username, next); diff --git a/src/user/search.js b/src/user/search.js index 37549232cd..198b027266 100644 --- a/src/user/search.js +++ b/src/user/search.js @@ -14,17 +14,19 @@ module.exports = function (User) { var uid = data.uid || 0; var paginate = data.hasOwnProperty('paginate') ? data.paginate : true; - if (searchBy === 'ip') { - return searchByIP(query, uid, callback); - } - var startTime = process.hrtime(); var searchResult = {}; async.waterfall([ function (next) { - var searchMethod = data.findUids || findUids; - searchMethod(query, searchBy, data.hardCap, next); + if (searchBy === 'ip') { + searchByIP(query, next); + } else if (searchBy === 'uid') { + next(null, [query]); + } else { + var searchMethod = data.findUids || findUids; + searchMethod(query, searchBy, data.hardCap, next); + } }, function (uids, next) { filterAndSortUids(uids, data, next); @@ -153,20 +155,7 @@ module.exports = function (User) { } } - function searchByIP(ip, uid, callback) { - var start = process.hrtime(); - async.waterfall([ - function (next) { - db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, next); - }, - function (uids, next) { - User.getUsers(uids, uid, next); - }, - function (users, next) { - var diff = process.hrtime(start); - var timing = ((diff[0] * 1e3) + (diff[1] / 1e6)).toFixed(1); - next(null, { timing: timing, users: users }); - }, - ], callback); + function searchByIP(ip, callback) { + db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, callback); } }; diff --git a/src/user/settings.js b/src/user/settings.js index f713b113d8..df5ed93d71 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -74,8 +74,7 @@ module.exports = function (User) { settings.categoryTopicSort = getSetting(settings, 'categoryTopicSort', 'newest_to_oldest'); settings.followTopicsOnCreate = parseInt(getSetting(settings, 'followTopicsOnCreate', 1), 10) === 1; settings.followTopicsOnReply = parseInt(getSetting(settings, 'followTopicsOnReply', 0), 10) === 1; - settings.sendChatNotifications = parseInt(getSetting(settings, 'sendChatNotifications', 0), 10) === 1; - settings.sendPostNotifications = parseInt(getSetting(settings, 'sendPostNotifications', 0), 10) === 1; + settings.upvoteNotifFreq = getSetting(settings, 'upvoteNotifFreq', 'all'); settings.restrictChat = parseInt(getSetting(settings, 'restrictChat', 0), 10) === 1; settings.topicSearchEnabled = parseInt(getSetting(settings, 'topicSearchEnabled', 0), 10) === 1; settings.delayImageLoading = parseInt(getSetting(settings, 'delayImageLoading', 1), 10) === 1; @@ -121,8 +120,6 @@ module.exports = function (User) { userLang: data.userLang || meta.config.defaultLang, followTopicsOnCreate: data.followTopicsOnCreate, followTopicsOnReply: data.followTopicsOnReply, - sendChatNotifications: data.sendChatNotifications, - sendPostNotifications: data.sendPostNotifications, restrictChat: data.restrictChat, topicSearchEnabled: data.topicSearchEnabled, delayImageLoading: data.delayImageLoading, @@ -131,6 +128,13 @@ module.exports = function (User) { notificationSound: data.notificationSound, incomingChatSound: data.incomingChatSound, outgoingChatSound: data.outgoingChatSound, + upvoteNotifFreq: data.upvoteNotifFreq, + notificationType_upvote: data.notificationType_upvote, + 'notificationType_new-topic': data['notificationType_new-topic'], + 'notificationType_new-reply': data['notificationType_new-reply'], + notificationType_follow: data.notificationType_follow, + 'notificationType_new-chat': data['notificationType_new-chat'], + 'notificationType_group-invite': data['notificationType_group-invite'], }; if (data.bootswatchSkin) { diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl index 1c2d98ca93..0a07425a78 100644 --- a/src/views/admin/advanced/cache.tpl +++ b/src/views/admin/advanced/cache.tpl @@ -42,7 +42,7 @@ {objectCache.hits}
{objectCache.misses}
- {objectCache.missRatio}
+ {objectCache.hitRatio}
{objectCache.dump}
diff --git a/src/views/admin/general/homepage.tpl b/src/views/admin/general/homepage.tpl index f6bc21b6cb..049721e829 100644 --- a/src/views/admin/general/homepage.tpl +++ b/src/views/admin/general/homepage.tpl @@ -24,6 +24,9 @@ [[admin/general/homepage:allow-user-home-pages]] +
+ + diff --git a/src/views/admin/header.tpl b/src/views/admin/header.tpl index 735dbd7264..d6eba4b640 100644 --- a/src/views/admin/header.tpl +++ b/src/views/admin/header.tpl @@ -19,17 +19,7 @@ }; - - - - - - - - - - diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl index 6a16141aca..3eca4f998d 100644 --- a/src/views/admin/manage/users.tpl +++ b/src/views/admin/manage/users.tpl @@ -28,7 +28,7 @@ [[admin/manage/users:download-csv]] - + @@ -49,6 +49,9 @@
+
+ + +
+ +
+ + +
+
diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index 2c77c48692..3eb7be42b8 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -17,50 +17,48 @@
+
+
[[admin/settings/post:length]]
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+ +
+
+
+
+
[[admin/settings/post:restrictions]]
-
-
- -
-

- [[admin/settings/post:restrictions.post-queue-help]] -

-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
+
@@ -73,22 +71,7 @@
-
- - -
-
- - -
-
- - -
-
- - -
+
@@ -100,6 +83,45 @@
+
+
[[admin/settings/post:restrictions-new]]
+
+ +
+
+
+ + +
+
+
+
+ + + +
+
+
+
+
+ +
+

+ [[admin/settings/post:restrictions.post-queue-help]] +

+
+ +
+ + +
+ +
+
+
[[admin/settings/post:timestamp]]
diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index 9d933b54e1..8b2528624e 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -105,6 +105,13 @@
[[admin/settings/user:account-protection]]
+
+ + +

+ [[admin/settings/user:admin-relogin-duration-help]] +

+
@@ -271,20 +278,6 @@
-
- -
- -
- -
-