From d095e5925caff36ca17d035d65f0d8e7658b8a6e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 21 Jul 2015 11:17:28 -0400 Subject: [PATCH 1/5] #3343 --- .gitattributes | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..e0fa7609a5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +# These files are text and should be normalized (convert crlf => lf) +*.json text +*.css text +*.less text +*.tpl text +*.html text +*.js text +*.md text + +# Images should be treated as binary +# (binary is a macro for -text -diff) +*.png binary +*.jpg binary \ No newline at end of file From c781e55ea939cb52f76d7505ef776d5e8f49586f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 21 Jul 2015 11:20:37 -0400 Subject: [PATCH 2/5] line endings? #3343 --- src/routes/authentication.js | 172 +++++++++++++++++------------------ 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 53a02a833c..37439ba523 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -1,86 +1,86 @@ -(function(Auth) { - "use strict"; - - var passport = require('passport'), - passportLocal = require('passport-local').Strategy, - nconf = require('nconf'), - winston = require('winston'), - express = require('express'), - - controllers = require('../controllers'), - plugins = require('../plugins'), - hotswap = require('../hotswap'), - - loginStrategies = []; - - Auth.initialize = function(app, middleware) { - app.use(passport.initialize()); - app.use(passport.session()); - - app.use(function(req, res, next) { - req.uid = req.user ? parseInt(req.user.uid, 10) : 0; - next(); - }); - - Auth.app = app; - Auth.middleware = middleware; - }; - - Auth.getLoginStrategies = function() { - return loginStrategies; - }; - - Auth.reloadRoutes = function(callback) { - var router = express.Router(); - router.hotswapId = 'auth'; - - loginStrategies.length = 0; - - if (plugins.hasListeners('action:auth.overrideLogin')) { - winston.warn('[authentication] Login override detected, skipping local login strategy.'); - plugins.fireHook('action:auth.overrideLogin'); - } else { - passport.use(new passportLocal({passReqToCallback: true}, controllers.authentication.localLogin)); - } - - plugins.fireHook('filter:auth.init', loginStrategies, function(err) { - if (err) { - winston.error('filter:auth.init - plugin failure'); - return callback(err); - } - - loginStrategies.forEach(function(strategy) { - if (strategy.url) { - router.get(strategy.url, passport.authenticate(strategy.name, { - scope: strategy.scope - })); - } - - router.get(strategy.callbackURL, passport.authenticate(strategy.name, { - successReturnToOrRedirect: nconf.get('relative_path') + (strategy.successUrl !== undefined ? strategy.successUrl : '/'), - failureRedirect: nconf.get('relative_path') + (strategy.failureUrl !== undefined ? strategy.failureUrl : '/login') - })); - }); - - router.post('/register', Auth.middleware.applyCSRF, controllers.authentication.register); - router.post('/login', Auth.middleware.applyCSRF, controllers.authentication.login); - router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout); - - hotswap.replace('auth', router); - if (typeof callback === 'function') { - callback(); - } - }); - }; - - passport.serializeUser(function(user, done) { - done(null, user.uid); - }); - - passport.deserializeUser(function(uid, done) { - done(null, { - uid: uid - }); - }); - -}(exports)); +(function(Auth) { + "use strict"; + + var passport = require('passport'), + passportLocal = require('passport-local').Strategy, + nconf = require('nconf'), + winston = require('winston'), + express = require('express'), + + controllers = require('../controllers'), + plugins = require('../plugins'), + hotswap = require('../hotswap'), + + loginStrategies = []; + + Auth.initialize = function(app, middleware) { + app.use(passport.initialize()); + app.use(passport.session()); + + app.use(function(req, res, next) { + req.uid = req.user ? parseInt(req.user.uid, 10) : 0; + next(); + }); + + Auth.app = app; + Auth.middleware = middleware; + }; + + Auth.getLoginStrategies = function() { + return loginStrategies; + }; + + Auth.reloadRoutes = function(callback) { + var router = express.Router(); + router.hotswapId = 'auth'; + + loginStrategies.length = 0; + + if (plugins.hasListeners('action:auth.overrideLogin')) { + winston.warn('[authentication] Login override detected, skipping local login strategy.'); + plugins.fireHook('action:auth.overrideLogin'); + } else { + passport.use(new passportLocal({passReqToCallback: true}, controllers.authentication.localLogin)); + } + + plugins.fireHook('filter:auth.init', loginStrategies, function(err) { + if (err) { + winston.error('filter:auth.init - plugin failure'); + return callback(err); + } + + loginStrategies.forEach(function(strategy) { + if (strategy.url) { + router.get(strategy.url, passport.authenticate(strategy.name, { + scope: strategy.scope + })); + } + + router.get(strategy.callbackURL, passport.authenticate(strategy.name, { + successReturnToOrRedirect: nconf.get('relative_path') + (strategy.successUrl !== undefined ? strategy.successUrl : '/'), + failureRedirect: nconf.get('relative_path') + (strategy.failureUrl !== undefined ? strategy.failureUrl : '/login') + })); + }); + + router.post('/register', Auth.middleware.applyCSRF, controllers.authentication.register); + router.post('/login', Auth.middleware.applyCSRF, controllers.authentication.login); + router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout); + + hotswap.replace('auth', router); + if (typeof callback === 'function') { + callback(); + } + }); + }; + + passport.serializeUser(function(user, done) { + done(null, user.uid); + }); + + passport.deserializeUser(function(uid, done) { + done(null, { + uid: uid + }); + }); + +}(exports)); From 7e6703c18e6b6137fca26aaf99ae4c44b1eb1d7a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 21 Jul 2015 11:23:16 -0400 Subject: [PATCH 3/5] more line ending conversion #3343 --- README.md | 148 +- app.js | 832 +++++------ install/data/categories.json | 66 +- public/src/ajaxify.js | 622 ++++----- public/src/app.js | 1226 ++++++++--------- public/vendor/fontawesome/.gitignore | 54 +- .../timeago/locales/jquery.timeago.fa.js | 42 +- .../timeago/locales/jquery.timeago.uz.js | 38 +- src/routes/admin.js | 170 +-- src/topics.js | 738 +++++----- src/webserver.js | 460 +++---- 11 files changed, 2198 insertions(+), 2198 deletions(-) diff --git a/README.md b/README.md index 4fc6d9aeb9..9062b049ae 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,75 @@ -# NodeBB - -[![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) -[![Dependency Status](https://david-dm.org/nodebb/nodebb.svg)](https://david-dm.org/nodebb/nodebb) -[![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) - -**NodeBB Forum Software** is powered by Node.js and built on either a Redis or MongoDB database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB is compatible down to IE8 and has many modern features out of the box such as social network integration and streaming discussions. - -Additional functionality is enabled through the use of third-party plugins. - -* [Get NodeBB](http://www.nodebb.org/ "NodeBB") -* [Demo & Meta Discussion](http://community.nodebb.org) -* [Documentation & Installation Instructions](http://docs.nodebb.org) -* [Help translate NodeBB](https://www.transifex.com/projects/p/nodebb/) -* [NodeBB Blog](http://blog.nodebb.org) -* [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/nodebb) - #nodebb on Freenode -* [Follow us on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") -* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook") - -## Screenshots - -[![](http://i.imgur.com/VCoOFyqb.png)](http://i.imgur.com/VCoOFyq.png) -[![](http://i.imgur.com/FLOUuIqb.png)](http://i.imgur.com/FLOUuIq.png) -[![](http://i.imgur.com/Ud1LrfIb.png)](http://i.imgur.com/Ud1LrfI.png) -[![](http://i.imgur.com/h6yZ66sb.png)](http://i.imgur.com/h6yZ66s.png) -[![](http://i.imgur.com/o90kVPib.png)](http://i.imgur.com/o90kVPi.png) -[![](http://i.imgur.com/AaRRrU2b.png)](http://i.imgur.com/AaRRrU2.png) -[![](http://i.imgur.com/LmHtPhob.png)](http://i.imgur.com/LmHtPho.png) -[![](http://i.imgur.com/paiJPJkb.jpg)](http://i.imgur.com/paiJPJk.jpg) - -[![](http://i.imgur.com/8OLssij.png)](http://i.imgur.com/8OLssij.png) -[![](http://i.imgur.com/JKOc0LZ.png)](http://i.imgur.com/JKOc0LZ.png) - -## How can I follow along/contribute? - -* Our feature roadmap is hosted on the project wiki's [Version History / Roadmap](https://github.com/NodeBB/NodeBB/wiki/Version-History-%26-Roadmap) -* If you are a developer, feel free to check out the source and submit pull requests. We also have a wide array of [plugins](http://community.nodebb.org/category/7/nodebb-plugins) which would be a great starting point for learning the codebase. -* If you are a designer, [NodeBB needs themes](http://community.nodebb.org/category/10/nodebb-themes)! NodeBB's theming system allows extention of the base templates as well as styling via LESS or CSS. NodeBB's base theme utilizes [Bootstrap 3](http://getbootstrap.com/) but themes can choose to use a different framework altogether. -* If you know languages other than English you can help us translate NodeBB. We use [Transifex](https://www.transifex.com/projects/p/nodebb/) for internationalization. -* Please don't forget to **like**, **follow**, and **star our repo**! Join our growing [community](http://community.nodebb.org) to keep up to date with the latest NodeBB development. - -## Requirements - -NodeBB requires the following software to be installed: - -* A version of Node.js at least 0.10 or greater -* Redis, version 2.8.9 or greater **or** MongoDB, version 2.6 or greater -* nginx, version 1.3.13 or greater (**only if** intending to use nginx to proxy requests to a NodeBB) - -## Installation - -[Please refer to platform-specific installation documentation](http://docs.nodebb.org/en/latest/installing/os.html) - -## Securing NodeBB - -It is important to ensure that your NodeBB and database servers are secured. Bear these points in mind: - -1. While some distributions set up Redis with a more restrictive configuration, Redis by default listens to all interfaces, which is especially dangerous when a server is open to the public. Some suggestions: - * Set `bind_address` to `127.0.0.1` so as to restrict access to the local machine only - * Use `requirepass` to secure Redis behind a password (preferably a long one) - * Familiarise yourself with [Redis Security](http://redis.io/topics/security) -2. Use `iptables` to secure your server from unintended open ports. In Ubuntu, `ufw` provides a friendlier interface to working with `iptables`. - * e.g. If your NodeBB is proxied, no ports should be open except 80 (and possibly 22, for SSH access) - -## Upgrading NodeBB - -Detailed upgrade instructions are listed in [Upgrading NodeBB](https://docs.nodebb.org/en/latest/upgrading/index.html) - -## License - -NodeBB is licensed under the **GNU General Public License v3 (GPL-3)** (http://www.gnu.org/copyleft/gpl.html). - +# NodeBB + +[![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) +[![Dependency Status](https://david-dm.org/nodebb/nodebb.svg)](https://david-dm.org/nodebb/nodebb) +[![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) + +**NodeBB Forum Software** is powered by Node.js and built on either a Redis or MongoDB database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB is compatible down to IE8 and has many modern features out of the box such as social network integration and streaming discussions. + +Additional functionality is enabled through the use of third-party plugins. + +* [Get NodeBB](http://www.nodebb.org/ "NodeBB") +* [Demo & Meta Discussion](http://community.nodebb.org) +* [Documentation & Installation Instructions](http://docs.nodebb.org) +* [Help translate NodeBB](https://www.transifex.com/projects/p/nodebb/) +* [NodeBB Blog](http://blog.nodebb.org) +* [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/nodebb) - #nodebb on Freenode +* [Follow us on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") +* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook") + +## Screenshots + +[![](http://i.imgur.com/VCoOFyqb.png)](http://i.imgur.com/VCoOFyq.png) +[![](http://i.imgur.com/FLOUuIqb.png)](http://i.imgur.com/FLOUuIq.png) +[![](http://i.imgur.com/Ud1LrfIb.png)](http://i.imgur.com/Ud1LrfI.png) +[![](http://i.imgur.com/h6yZ66sb.png)](http://i.imgur.com/h6yZ66s.png) +[![](http://i.imgur.com/o90kVPib.png)](http://i.imgur.com/o90kVPi.png) +[![](http://i.imgur.com/AaRRrU2b.png)](http://i.imgur.com/AaRRrU2.png) +[![](http://i.imgur.com/LmHtPhob.png)](http://i.imgur.com/LmHtPho.png) +[![](http://i.imgur.com/paiJPJkb.jpg)](http://i.imgur.com/paiJPJk.jpg) + +[![](http://i.imgur.com/8OLssij.png)](http://i.imgur.com/8OLssij.png) +[![](http://i.imgur.com/JKOc0LZ.png)](http://i.imgur.com/JKOc0LZ.png) + +## How can I follow along/contribute? + +* Our feature roadmap is hosted on the project wiki's [Version History / Roadmap](https://github.com/NodeBB/NodeBB/wiki/Version-History-%26-Roadmap) +* If you are a developer, feel free to check out the source and submit pull requests. We also have a wide array of [plugins](http://community.nodebb.org/category/7/nodebb-plugins) which would be a great starting point for learning the codebase. +* If you are a designer, [NodeBB needs themes](http://community.nodebb.org/category/10/nodebb-themes)! NodeBB's theming system allows extention of the base templates as well as styling via LESS or CSS. NodeBB's base theme utilizes [Bootstrap 3](http://getbootstrap.com/) but themes can choose to use a different framework altogether. +* If you know languages other than English you can help us translate NodeBB. We use [Transifex](https://www.transifex.com/projects/p/nodebb/) for internationalization. +* Please don't forget to **like**, **follow**, and **star our repo**! Join our growing [community](http://community.nodebb.org) to keep up to date with the latest NodeBB development. + +## Requirements + +NodeBB requires the following software to be installed: + +* A version of Node.js at least 0.10 or greater +* Redis, version 2.8.9 or greater **or** MongoDB, version 2.6 or greater +* nginx, version 1.3.13 or greater (**only if** intending to use nginx to proxy requests to a NodeBB) + +## Installation + +[Please refer to platform-specific installation documentation](http://docs.nodebb.org/en/latest/installing/os.html) + +## Securing NodeBB + +It is important to ensure that your NodeBB and database servers are secured. Bear these points in mind: + +1. While some distributions set up Redis with a more restrictive configuration, Redis by default listens to all interfaces, which is especially dangerous when a server is open to the public. Some suggestions: + * Set `bind_address` to `127.0.0.1` so as to restrict access to the local machine only + * Use `requirepass` to secure Redis behind a password (preferably a long one) + * Familiarise yourself with [Redis Security](http://redis.io/topics/security) +2. Use `iptables` to secure your server from unintended open ports. In Ubuntu, `ufw` provides a friendlier interface to working with `iptables`. + * e.g. If your NodeBB is proxied, no ports should be open except 80 (and possibly 22, for SSH access) + +## Upgrading NodeBB + +Detailed upgrade instructions are listed in [Upgrading NodeBB](https://docs.nodebb.org/en/latest/upgrading/index.html) + +## License + +NodeBB is licensed under the **GNU General Public License v3 (GPL-3)** (http://www.gnu.org/copyleft/gpl.html). + Interested in a sublicense agreement for use of NodeBB in a non-free/restrictive environment? Contact us at sales@nodebb.org. \ No newline at end of file diff --git a/app.js b/app.js index 0a963230b0..0f5de4bfe9 100644 --- a/app.js +++ b/app.js @@ -1,416 +1,416 @@ -/* - NodeBB - A better forum platform for the modern web - https://github.com/NodeBB/NodeBB/ - Copyright (C) 2013-2014 NodeBB Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -"use strict"; -/*global require, global, process*/ - -var nconf = require('nconf'); -nconf.argv().env('__'); - -var fs = require('fs'), - os = require('os'), - url = require('url'), - async = require('async'), - semver = require('semver'), - winston = require('winston'), - colors = require('colors'), - path = require('path'), - pkg = require('./package.json'), - utils = require('./public/src/utils.js'); - -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 date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,5) + ' [' + global.process.pid + ']'; - }, - level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose') -}); - -if(os.platform() === 'linux') { - require('child_process').exec('/usr/bin/which convert', function(err, stdout, stderr) { - if(err || !stdout) { - winston.warn('Couldn\'t find convert. Did you install imagemagick?'); - } - }); -} - -// Alternate configuration file support -var configFile = path.join(__dirname, '/config.json'), - configExists; - -if (nconf.get('config')) { - configFile = path.resolve(__dirname, nconf.get('config')); -} -configExists = fs.existsSync(configFile); - -if (!nconf.get('setup') && !nconf.get('install') && !nconf.get('upgrade') && !nconf.get('reset') && configExists) { - start(); -} else if (nconf.get('setup') || nconf.get('install')) { - setup(); -} else if (!configExists) { - require('./install/web').install(nconf.get('port')); -} else if (nconf.get('upgrade')) { - upgrade(); -} else if (nconf.get('reset')) { - reset(); -} - -function loadConfig() { - nconf.file({ - file: configFile - }); - - nconf.defaults({ - base_dir: __dirname, - themes_path: path.join(__dirname, 'node_modules'), - views_dir: path.join(__dirname, '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-vanilla/templates')); - - if (!process.send) { - // If run using `node app`, log GNU copyright info along with server info - winston.info('NodeBB v' + nconf.get('version') + ' Copyright (C) 2013-2014 NodeBB Inc.'); - winston.info('This program comes with ABSOLUTELY NO WARRANTY.'); - winston.info('This is free software, and you are welcome to redistribute it under certain conditions.'); - winston.info(''); - } -} - -function start() { - loadConfig(); - var db = require('./src/database'); - - // nconf defaults, if not set in config - if (!nconf.get('upload_path')) { - nconf.set('upload_path', '/public/uploads'); - } - // Parse out the relative_url and other goodies from the configured URL - var urlObject = url.parse(nconf.get('url')); - var relativePath = urlObject.pathname !== '/' ? urlObject.pathname : ''; - nconf.set('base_url', urlObject.protocol + '//' + urlObject.host); - nconf.set('use_port', !!urlObject.port); - nconf.set('relative_path', relativePath); - nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || 4567); - nconf.set('upload_url', '/uploads/'); - - if (nconf.get('isPrimary') === 'true') { - winston.info('Time: %s', (new Date()).toString()); - winston.info('Initializing NodeBB v%s', nconf.get('version')); - winston.verbose('* using configuration stored in: %s', configFile); - - var host = nconf.get(nconf.get('database') + ':host'), - storeLocation = host ? 'at ' + host + (host.indexOf('/') === -1 ? ':' + nconf.get(nconf.get('database') + ':port') : '') : ''; - - winston.verbose('* using %s store %s', nconf.get('database'), storeLocation); - winston.verbose('* using themes stored in: %s', nconf.get('themes_path')); - } - - process.on('SIGTERM', shutdown); - process.on('SIGINT', shutdown); - process.on('SIGHUP', restart); - process.on('message', function(message) { - if (typeof message !== 'object') { - return; - } - var meta = require('./src/meta'); - var emitter = require('./src/emitter'); - switch (message.action) { - case 'reload': - meta.reload(); - break; - case 'js-propagate': - meta.js.cache = message.cache; - meta.js.map = message.map; - meta.js.hash = message.hash; - emitter.emit('meta:js.compiled'); - winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid); - break; - case 'css-propagate': - meta.css.cache = message.cache; - meta.css.acpCache = message.acpCache; - meta.css.hash = message.hash; - emitter.emit('meta:css.compiled'); - winston.verbose('[cluster] Stylesheets propagated to worker %s', process.pid); - break; - case 'templates:compiled': - emitter.emit('templates:compiled'); - break; - } - }); - - process.on('uncaughtException', function(err) { - winston.error(err.stack); - console.log(err.stack); - - require('./src/meta').js.killMinifier(); - shutdown(1); - }); - - async.waterfall([ - async.apply(db.init), - async.apply(db.checkCompatibility), - function(next) { - require('./src/meta').configs.init(next); - }, - function(next) { - require('./src/meta').dependencies.check(next); - }, - function(next) { - require('./src/upgrade').check(next); - }, - function(next) { - var webserver = require('./src/webserver'); - require('./src/socket.io').init(webserver.server); - - if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) { - require('./src/notifications').init(); - require('./src/user').startJobs(); - } - - webserver.listen(); - } - ], function(err) { - if (err) { - switch(err.message) { - case 'schema-out-of-date': - winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); - winston.warn(' ./nodebb upgrade'); - break; - case 'dependencies-out-of-date': - winston.warn('One or more of NodeBB\'s dependent packages are out-of-date. Please run the following command to update them:'); - winston.warn(' ./nodebb upgrade'); - break; - default: - if (err.stacktrace !== false) { - winston.error(err.stack); - } else { - winston.error(err.message); - } - break; - } - - // Either way, bad stuff happened. Abort start. - process.exit(); - } - }); -} - -function setup() { - loadConfig(); - - winston.info('NodeBB Setup Triggered via Command Line'); - - var install = require('./src/install'); - - 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'); - - install.setup(function (err, data) { - var separator = ' '; - if (process.stdout.columns > 10) { - for(var x=0,cols=process.stdout.columns-10;x. +*/ + +"use strict"; +/*global require, global, process*/ + +var nconf = require('nconf'); +nconf.argv().env('__'); + +var fs = require('fs'), + os = require('os'), + url = require('url'), + async = require('async'), + semver = require('semver'), + winston = require('winston'), + colors = require('colors'), + path = require('path'), + pkg = require('./package.json'), + utils = require('./public/src/utils.js'); + +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 date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,5) + ' [' + global.process.pid + ']'; + }, + level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose') +}); + +if(os.platform() === 'linux') { + require('child_process').exec('/usr/bin/which convert', function(err, stdout, stderr) { + if(err || !stdout) { + winston.warn('Couldn\'t find convert. Did you install imagemagick?'); + } + }); +} + +// Alternate configuration file support +var configFile = path.join(__dirname, '/config.json'), + configExists; + +if (nconf.get('config')) { + configFile = path.resolve(__dirname, nconf.get('config')); +} +configExists = fs.existsSync(configFile); + +if (!nconf.get('setup') && !nconf.get('install') && !nconf.get('upgrade') && !nconf.get('reset') && configExists) { + start(); +} else if (nconf.get('setup') || nconf.get('install')) { + setup(); +} else if (!configExists) { + require('./install/web').install(nconf.get('port')); +} else if (nconf.get('upgrade')) { + upgrade(); +} else if (nconf.get('reset')) { + reset(); +} + +function loadConfig() { + nconf.file({ + file: configFile + }); + + nconf.defaults({ + base_dir: __dirname, + themes_path: path.join(__dirname, 'node_modules'), + views_dir: path.join(__dirname, '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-vanilla/templates')); + + if (!process.send) { + // If run using `node app`, log GNU copyright info along with server info + winston.info('NodeBB v' + nconf.get('version') + ' Copyright (C) 2013-2014 NodeBB Inc.'); + winston.info('This program comes with ABSOLUTELY NO WARRANTY.'); + winston.info('This is free software, and you are welcome to redistribute it under certain conditions.'); + winston.info(''); + } +} + +function start() { + loadConfig(); + var db = require('./src/database'); + + // nconf defaults, if not set in config + if (!nconf.get('upload_path')) { + nconf.set('upload_path', '/public/uploads'); + } + // Parse out the relative_url and other goodies from the configured URL + var urlObject = url.parse(nconf.get('url')); + var relativePath = urlObject.pathname !== '/' ? urlObject.pathname : ''; + nconf.set('base_url', urlObject.protocol + '//' + urlObject.host); + nconf.set('use_port', !!urlObject.port); + nconf.set('relative_path', relativePath); + nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || 4567); + nconf.set('upload_url', '/uploads/'); + + if (nconf.get('isPrimary') === 'true') { + winston.info('Time: %s', (new Date()).toString()); + winston.info('Initializing NodeBB v%s', nconf.get('version')); + winston.verbose('* using configuration stored in: %s', configFile); + + var host = nconf.get(nconf.get('database') + ':host'), + storeLocation = host ? 'at ' + host + (host.indexOf('/') === -1 ? ':' + nconf.get(nconf.get('database') + ':port') : '') : ''; + + winston.verbose('* using %s store %s', nconf.get('database'), storeLocation); + winston.verbose('* using themes stored in: %s', nconf.get('themes_path')); + } + + process.on('SIGTERM', shutdown); + process.on('SIGINT', shutdown); + process.on('SIGHUP', restart); + process.on('message', function(message) { + if (typeof message !== 'object') { + return; + } + var meta = require('./src/meta'); + var emitter = require('./src/emitter'); + switch (message.action) { + case 'reload': + meta.reload(); + break; + case 'js-propagate': + meta.js.cache = message.cache; + meta.js.map = message.map; + meta.js.hash = message.hash; + emitter.emit('meta:js.compiled'); + winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid); + break; + case 'css-propagate': + meta.css.cache = message.cache; + meta.css.acpCache = message.acpCache; + meta.css.hash = message.hash; + emitter.emit('meta:css.compiled'); + winston.verbose('[cluster] Stylesheets propagated to worker %s', process.pid); + break; + case 'templates:compiled': + emitter.emit('templates:compiled'); + break; + } + }); + + process.on('uncaughtException', function(err) { + winston.error(err.stack); + console.log(err.stack); + + require('./src/meta').js.killMinifier(); + shutdown(1); + }); + + async.waterfall([ + async.apply(db.init), + async.apply(db.checkCompatibility), + function(next) { + require('./src/meta').configs.init(next); + }, + function(next) { + require('./src/meta').dependencies.check(next); + }, + function(next) { + require('./src/upgrade').check(next); + }, + function(next) { + var webserver = require('./src/webserver'); + require('./src/socket.io').init(webserver.server); + + if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) { + require('./src/notifications').init(); + require('./src/user').startJobs(); + } + + webserver.listen(); + } + ], function(err) { + if (err) { + switch(err.message) { + case 'schema-out-of-date': + winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); + winston.warn(' ./nodebb upgrade'); + break; + case 'dependencies-out-of-date': + winston.warn('One or more of NodeBB\'s dependent packages are out-of-date. Please run the following command to update them:'); + winston.warn(' ./nodebb upgrade'); + break; + default: + if (err.stacktrace !== false) { + winston.error(err.stack); + } else { + winston.error(err.message); + } + break; + } + + // Either way, bad stuff happened. Abort start. + process.exit(); + } + }); +} + +function setup() { + loadConfig(); + + winston.info('NodeBB Setup Triggered via Command Line'); + + var install = require('./src/install'); + + 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'); + + install.setup(function (err, data) { + var separator = ' '; + if (process.stdout.columns > 10) { + for(var x=0,cols=process.stdout.columns-10;x 0 ? this.pathname.indexOf(RELATIVE_PATH) === 0 : true)) // Subfolder installs need this additional check - ) { - // Internal link - var url = this.pathname.replace(RELATIVE_PATH + '/', ''); - - // Special handling for urls with hashes - if (window.location.pathname === this.pathname && this.hash.length) { - window.location.hash = this.hash; - } else { - window.location.hash = ''; - if (ajaxify.go(url)) { - e.preventDefault(); - } - } - } else if (window.location.pathname !== '/outgoing') { - // External Link - if (config.openOutgoingLinksInNewTab) { - window.open(this.href, '_blank'); - e.preventDefault(); - } else if (config.useOutgoingLinksPage) { - ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); - e.preventDefault(); - } - } - } - }); - } - - if (window.history && window.history.pushState) { - // Progressive Enhancement, ajaxify available only to modern browsers - ajaxifyAnchors(); - } - - app.load(); - templates.cache['500'] = $('.tpl-500').html(); - +"use strict"; + +var ajaxify = ajaxify || {}; + +$(document).ready(function() { + + /*global app, templates, utils, socket, config, RELATIVE_PATH*/ + + var location = document.location || window.location, + rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''), + apiXHR = null, + + translator; + + // Dumb hack to fool ajaxify into thinking translator is still a global + // When ajaxify is migrated to a require.js module, then this can be merged into the "define" call + require(['translator'], function(_translator) { + translator = _translator; + }); + + $(window).on('popstate', function (ev) { + ev = ev.originalEvent; + + if (ev !== null && ev.state && ev.state.url !== undefined) { + ajaxify.go(ev.state.url, function() { + $(window).trigger('action:popstate', {url: ev.state.url}); + }, true); + } + }); + + ajaxify.currentPage = null; + + ajaxify.go = function (url, callback, quiet, search) { + if (!socket.connected) { + if (ajaxify.reconnectAction) { + $(window).off('action:reconnected', ajaxify.reconnectAction); + } + ajaxify.reconnectAction = function(e) { + ajaxify.go(url, callback, quiet, search); + $(window).off(e); + } + $(window).on('action:reconnected', ajaxify.reconnectAction); + } + + if (ajaxify.handleRedirects(url)) { + return true; + } + + app.enterRoom(''); + + $(window).off('scroll'); + + if ($('#content').hasClass('ajaxifying') && apiXHR) { + apiXHR.abort(); + } + + url = ajaxify.start(url, quiet, search); + + $('#footer, #content').removeClass('hide').addClass('ajaxifying'); + + ajaxify.variables.flush(); + ajaxify.loadData(url, function(err, data) { + if (err) { + return onAjaxError(err, url, callback, quiet); + } + + app.template = data.template.name; + + require(['translator'], function(translator) { + translator.load(config.defaultLang, data.template.name); + renderTemplate(url, data.template.name, data, callback); + }); + }); + + return true; + }; + + ajaxify.handleRedirects = function(url) { + url = ajaxify.removeRelativePath(url.replace(/\/$/, '')).toLowerCase(); + var isAdminRoute = url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0; + var uploadsOrApi = url.startsWith('uploads') || url.startsWith('api'); + if (isAdminRoute || uploadsOrApi) { + window.open(RELATIVE_PATH + '/' + url, '_top'); + return true; + } + return false; + }; + + + ajaxify.start = function(url, quiet, search) { + url = ajaxify.removeRelativePath(url.replace(/^\/|\/$/g, '')); + var hash = window.location.hash; + search = search || ''; + + $(window).trigger('action:ajaxify.start', {url: url}); + + if (!window.location.pathname.match(/\/(403|404)$/g)) { + app.previousUrl = window.location.href; + } + + ajaxify.currentPage = url; + + if (window.history && window.history.pushState) { + window.history[!quiet ? 'pushState' : 'replaceState']({ + url: url + search + hash + }, url, RELATIVE_PATH + '/' + url + search + hash); + } + return url; + }; + + function onAjaxError(err, url, callback, quiet) { + var data = err.data, + textStatus = err.textStatus; + + if (data) { + var status = parseInt(data.status, 10); + if (status === 403 || status === 404 || status === 500 || status === 502) { + if (status === 502) { + status = 500; + } + + $('#footer, #content').removeClass('hide').addClass('ajaxifying'); + return renderTemplate(url, status.toString(), data.responseJSON, (new Date()).getTime(), callback); + } else if (status === 401) { + app.alertError('[[global:please_log_in]]'); + app.previousUrl = url; + return ajaxify.go('login'); + } else if (status === 302) { + if (data.responseJSON.external) { + window.location.href = data.responseJSON.external; + } else if (typeof data.responseJSON === 'string') { + ajaxify.go(data.responseJSON.slice(1), callback, quiet); + } + } + } else if (textStatus !== 'abort') { + app.alertError(data.responseJSON.error); + } + } + + function renderTemplate(url, tpl_url, data, callback) { + $(window).trigger('action:ajaxify.loadingTemplates', {}); + + templates.parse(tpl_url, data, function(template) { + translator.translate(template, function(translatedTemplate) { + $('#content').html(translatedTemplate); + + ajaxify.end(url, tpl_url); + + if (typeof callback === 'function') { + callback(); + } + + $('#content, #footer').removeClass('ajaxifying'); + + app.refreshTitle(url); + }); + }); + } + + ajaxify.end = function(url, tpl_url) { + function done() { + if (--count === 0) { + $(window).trigger('action:ajaxify.end', {url: url}); + } + } + var count = 2; + + ajaxify.variables.parse(); + + ajaxify.loadScript(tpl_url, done); + + ajaxify.widgets.render(tpl_url, url, done); + + $(window).trigger('action:ajaxify.contentLoaded', {url: url, tpl: tpl_url}); + + app.processPage(); + }; + + ajaxify.removeRelativePath = function(url) { + if (url.startsWith(RELATIVE_PATH.slice(1))) { + url = url.slice(RELATIVE_PATH.length); + } + return url; + }; + + ajaxify.refresh = function(e) { + if (e && e instanceof jQuery.Event) { + e.preventDefault(); + } + + ajaxify.go(ajaxify.currentPage, null, true); + }; + + ajaxify.loadScript = function(tpl_url, callback) { + var location = !app.inAdmin ? 'forum/' : ''; + + require([location + tpl_url], function(script) { + if (script && script.init) { + script.init(); + } + + if (callback) { + callback(); + } + }); + }; + + ajaxify.loadData = function(url, callback) { + url = ajaxify.removeRelativePath(url); + + $(window).trigger('action:ajaxify.loadingData', {url: url}); + + apiXHR = $.ajax({ + url: RELATIVE_PATH + '/api/' + url, + cache: false, + success: function(data) { + if (!data) { + return; + } + ajaxify.data = data; + data.relative_path = RELATIVE_PATH; + $(window).trigger('action:ajaxify.dataLoaded', {url: url, data: data}); + + if (callback) { + callback(null, data); + } + }, + error: function(data, textStatus) { + if (data.status === 0 && textStatus === 'error') { + data.status = 500; + } + callback({ + data: data, + textStatus: textStatus + }); + } + }); + }; + + ajaxify.loadTemplate = function(template, callback) { + if (templates.cache[template]) { + callback(templates.cache[template]); + } else { + $.ajax({ + url: RELATIVE_PATH + '/templates/' + template + '.tpl' + (config['cache-buster'] ? '?v=' + config['cache-buster'] : ''), + type: 'GET', + success: function(data) { + callback(data.toString()); + }, + error: function(error) { + throw new Error("Unable to load template: " + template + " (" + error.statusText + ")"); + } + }); + } + }; + + function ajaxifyAnchors() { + templates.registerLoader(ajaxify.loadTemplate); + + function hrefEmpty(href) { + return href === undefined || href === '' || href === 'javascript:;'; + } + + // Enhancing all anchors to ajaxify... + $(document.body).on('click', 'a', function (e) { + if (this.target !== '' || (this.protocol !== 'http:' && this.protocol !== 'https:')) { + return; + } else if (hrefEmpty(this.href) || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false' || $(this).attr('href') === '#') { + return e.preventDefault(); + } + + if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) { + if ( + this.host === '' || // Relative paths are always internal links... + (this.host === window.location.host && this.protocol === window.location.protocol && // Otherwise need to check that protocol and host match + (RELATIVE_PATH.length > 0 ? this.pathname.indexOf(RELATIVE_PATH) === 0 : true)) // Subfolder installs need this additional check + ) { + // Internal link + var url = this.pathname.replace(RELATIVE_PATH + '/', ''); + + // Special handling for urls with hashes + if (window.location.pathname === this.pathname && this.hash.length) { + window.location.hash = this.hash; + } else { + window.location.hash = ''; + if (ajaxify.go(url)) { + e.preventDefault(); + } + } + } else if (window.location.pathname !== '/outgoing') { + // External Link + if (config.openOutgoingLinksInNewTab) { + window.open(this.href, '_blank'); + e.preventDefault(); + } else if (config.useOutgoingLinksPage) { + ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); + e.preventDefault(); + } + } + } + }); + } + + if (window.history && window.history.pushState) { + // Progressive Enhancement, ajaxify available only to modern browsers + ajaxifyAnchors(); + } + + app.load(); + templates.cache['500'] = $('.tpl-500').html(); + }); \ No newline at end of file diff --git a/public/src/app.js b/public/src/app.js index 3cf6947073..3254c7a51f 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -1,613 +1,613 @@ -"use strict"; -/*global io, templates, ajaxify, utils, bootbox, RELATIVE_PATH, config, Visibility*/ - -var socket, - app = app || {}; - -app.isFocused = true; -app.isConnected = false; -app.currentRoom = null; -app.widgets = {}; -app.cacheBuster = null; - -(function () { - var showWelcomeMessage = false; - var reconnecting = false; - - function socketIOConnect() { - var ioParams = { - reconnectionAttempts: config.maxReconnectionAttempts, - reconnectionDelay: config.reconnectionDelay, - transports: config.socketioTransports, - path: config.relative_path + '/socket.io' - }; - - socket = io(config.websocketAddress, ioParams); - reconnecting = false; - - socket.on('event:connect', function () { - app.showLoginMessage(); - app.replaceSelfLinks(); - $(window).trigger('action:connected'); - app.isConnected = true; - }); - - socket.on('connect', onSocketConnect); - - socket.on('event:disconnect', function() { - $(window).trigger('action:disconnected'); - app.isConnected = false; - socket.connect(); - }); - - socket.on('reconnecting', function (attempt) { - reconnecting = true; - var reconnectEl = $('#reconnect'); - - if (!reconnectEl.hasClass('active')) { - reconnectEl.html(''); - } - - reconnectEl.addClass('active').removeClass("hide").tooltip({ - placement: 'bottom' - }); - }); - - socket.on('event:banned', function() { - app.alert({ - title: '[[global:alert.banned]]', - message: '[[global:alert.banned.message]]', - type: 'danger', - timeout: 1000 - }); - - setTimeout(function() { - window.location.href = config.relative_path + '/'; - }, 1000); - }); - - socket.on('event:logout', app.logout); - - socket.on('event:alert', function(data) { - app.alert(data); - }); - - socket.on('reconnect_failed', function() { - // Wait ten times the reconnection delay and then start over - setTimeout(socket.connect.bind(socket), parseInt(config.reconnectionDelay, 10) * 10); - }); - } - - function onSocketConnect(data) { - if (reconnecting) { - var reconnectEl = $('#reconnect'); - - reconnectEl.tooltip('destroy'); - reconnectEl.html(''); - reconnecting = false; - - // Rejoin room that was left when we disconnected - var url_parts = window.location.pathname.slice(RELATIVE_PATH.length).split('/').slice(1); - var room; - - switch(url_parts[0]) { - case 'user': - room = 'user/' + ajaxify.data.theirid; - break; - case 'topic': - room = 'topic_' + url_parts[1]; - break; - case 'category': - room = 'category_' + url_parts[1]; - break; - case 'recent': - room = 'recent_topics'; - break; - case 'unread': - room = 'unread_topics'; - break; - case 'popular': - room = 'popular_topics'; - break; - case 'admin': - room = 'admin'; - break; - case 'categories': - room = 'categories'; - break; - } - app.currentRoom = ''; - app.enterRoom(room); - - socket.emit('meta.reconnected'); - - app.isConnected = true; - $(window).trigger('action:reconnected'); - - setTimeout(function() { - reconnectEl.removeClass('active').addClass('hide'); - }, 3000); - } - } - - app.logout = function() { - require(['csrf'], function(csrf) { - $.ajax(RELATIVE_PATH + '/logout', { - type: 'POST', - headers: { - 'x-csrf-token': csrf.get() - }, - success: function() { - window.location.href = RELATIVE_PATH + '/'; - } - }); - }); - }; - - app.alert = function (params) { - require(['alerts'], function(alerts) { - alerts.alert(params); - }); - }; - - app.removeAlert = function(id) { - require(['alerts'], function(alerts) { - alerts.remove(id); - }); - }; - - app.alertSuccess = function (message, timeout) { - app.alert({ - title: '[[global:alert.success]]', - message: message, - type: 'success', - timeout: timeout ? timeout : 2000 - }); - }; - - app.alertError = function (message, timeout) { - app.alert({ - title: '[[global:alert.error]]', - message: message, - type: 'danger', - timeout: timeout ? timeout : 5000 - }); - }; - - app.enterRoom = function (room, callback) { - callback = callback || function() {}; - if (socket) { - if (app.currentRoom === room) { - return; - } - - socket.emit('meta.rooms.enter', { - enter: room, - username: app.user.username, - userslug: app.user.userslug, - picture: app.user.picture - }, function(err) { - if (err) { - app.alertError(err.message); - return; - } - app.currentRoom = room; - }); - } - }; - - function highlightNavigationLink() { - var path = window.location.pathname; - $('#main-nav li').removeClass('active'); - if (path) { - $('#main-nav li a').each(function () { - var href = $(this).attr('href'); - - if (href && path.startsWith(href)) { - $(this.parentNode).addClass('active'); - return false; - } - }); - } - } - - app.createUserTooltips = function() { - $('img[title].teaser-pic,img[title].user-img').each(function() { - $(this).tooltip({ - placement: 'top', - title: $(this).attr('title') - }); - }); - }; - - app.createStatusTooltips = function() { - $('body').tooltip({ - selector:'.fa-circle.status', - placement: 'top' - }); - }; - - app.replaceSelfLinks = function(selector) { - selector = selector || $('a'); - selector.each(function() { - var href = $(this).attr('href'); - if (href && app.user.userslug && href.indexOf('user/_self_') !== -1) { - $(this).attr('href', href.replace(/user\/_self_/g, 'user/' + app.user.userslug)); - } - }); - }; - - app.processPage = function () { - highlightNavigationLink(); - - $('.timeago').timeago(); - - utils.makeNumbersHumanReadable($('.human-readable-number')); - - utils.addCommasToNumbers($('.formatted-number')); - - app.createUserTooltips(); - - app.createStatusTooltips(); - - app.replaceSelfLinks(); - - // Scroll back to top of page - window.scrollTo(0, 0); - }; - - app.showLoginMessage = function () { - function showAlert() { - app.alert({ - type: 'success', - title: '[[global:welcome_back]] ' + app.user.username + '!', - message: '[[global:you_have_successfully_logged_in]]', - timeout: 5000 - }); - } - - if (showWelcomeMessage) { - showWelcomeMessage = false; - if (document.readyState !== 'complete') { - $(document).ready(showAlert); - } else { - showAlert(); - } - } - }; - - app.openChat = function (username, touid) { - if (username === app.user.username) { - return app.alertError('[[error:cant-chat-with-yourself]]'); - } - - if (!app.user.uid) { - return app.alertError('[[error:not-logged-in]]'); - } - - require(['chat'], function (chat) { - function loadAndCenter(chatModal) { - chat.load(chatModal.attr('UUID')); - chat.center(chatModal); - chat.focusInput(chatModal); - } - - if (!chat.modalExists(touid)) { - chat.createModal(username, touid, loadAndCenter); - } else { - loadAndCenter(chat.getModal(touid)); - } - }); - }; - - var titleObj = { - active: false, - interval: undefined, - titles: [] - }; - - app.alternatingTitle = function (title) { - if (typeof title !== 'string') { - return; - } - - if (title.length > 0 && !app.isFocused) { - if (!titleObj.titles[0]) { - titleObj.titles[0] = window.document.title; - } - - require(['translator'], function(translator) { - translator.translate(title, function(translated) { - titleObj.titles[1] = translated; - if (titleObj.interval) { - clearInterval(titleObj.interval); - } - - titleObj.interval = setInterval(function() { - var title = titleObj.titles[titleObj.titles.indexOf(window.document.title) ^ 1]; - if (title) { - window.document.title = $('
').html(title).text(); - } - }, 2000); - }); - }); - } else { - if (titleObj.interval) { - clearInterval(titleObj.interval); - } - if (titleObj.titles[0]) { - window.document.title = $('
').html(titleObj.titles[0]).text(); - } - } - }; - - app.refreshTitle = function(url) { - if (!url) { - var a = document.createElement('a'); - a.href = document.location; - url = a.pathname.slice(1); - } - - socket.emit('meta.buildTitle', url, function(err, title, numNotifications) { - if (err) { - return; - } - titleObj.titles[0] = (numNotifications > 0 ? '(' + numNotifications + ') ' : '') + title; - app.alternatingTitle(''); - }); - }; - - app.toggleNavbar = function(state) { - var navbarEl = $('.navbar'); - if (navbarEl) { - navbarEl.toggleClass('hidden', !!!state); - } - }; - - app.exposeConfigToTemplates = function() { - $(document).ready(function() { - templates.setGlobal('loggedIn', config.loggedIn); - templates.setGlobal('relative_path', RELATIVE_PATH); - for(var key in config) { - if (config.hasOwnProperty(key)) { - templates.setGlobal('config.' + key, config[key]); - } - } - }); - }; - - function createHeaderTooltips() { - if (utils.findBootstrapEnvironment() === 'xs') { - return; - } - $('#header-menu li a[title]').each(function() { - $(this).tooltip({ - placement: 'bottom', - title: $(this).attr('title') - }); - }); - - $('#search-form').parent().tooltip({ - placement: 'bottom', - title: $('#search-button i').attr('title') - }); - - $('#user_dropdown').tooltip({ - placement: 'bottom', - title: $('#user_dropdown').attr('title') - }); - } - - app.handleSearch = function () { - var searchButton = $("#search-button"), - searchFields = $("#search-fields"), - searchInput = $('#search-fields input'); - - $('#search-form').on('submit', dismissSearch); - searchInput.on('blur', dismissSearch); - - function dismissSearch(){ - searchFields.hide(); - searchButton.show(); - } - - searchButton.on('click', function(e) { - if (!config.loggedIn && !config.allowGuestSearching) { - app.alert({ - message:'[[error:search-requires-login]]', - timeout: 3000 - }); - ajaxify.go('login'); - return false; - } - e.stopPropagation(); - - app.prepareSearch(); - return false; - }); - - $('#search-form').on('submit', function () { - var input = $(this).find('input'); - require(['search'], function(search) { - search.query({term: input.val()}, function() { - input.val(''); - }); - }); - return false; - }); - }; - - app.prepareSearch = function() { - $("#search-fields").removeClass('hide').show(); - $("#search-button").hide(); - $('#search-fields input').focus(); - }; - - function handleStatusChange() { - $('#user-control-list .user-status').off('click').on('click', function(e) { - var status = $(this).attr('data-status'); - socket.emit('user.setStatus', status, function(err, data) { - if(err) { - return app.alertError(err.message); - } - $('#logged-in-menu #user_label #user-profile-link>i').attr('class', 'fa fa-circle status ' + status); - }); - e.preventDefault(); - }); - } - - app.updateUserStatus = function(el, status) { - if (!el.length) { - return; - } - - translator.translate('[[global:' + status + ']]', function(translated) { - el.removeClass('online offline dnd away') - .addClass(status) - .attr('title', translated) - .attr('data-original-title', translated); - }); - }; - - function handleNewTopic() { - $('#content').on('click', '#new_topic', function() { - var cid = ajaxify.data.cid; - if (cid) { - $(window).trigger('action:composer.topic.new', { - cid: cid - }); - } else { - socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { - if (err) { - return app.alertError(err.message); - } - if (categories.length) { - $(window).trigger('action:composer.topic.new', { - cid: categories[0].cid - }); - } - }); - } - }); - } - - app.load = function() { - $('document').ready(function () { - var url = ajaxify.start(window.location.pathname.slice(1), true, window.location.search); - ajaxify.end(url, app.template); - - handleStatusChange(); - - if (config.searchEnabled) { - app.handleSearch(); - } - - handleNewTopic(); - - $('#logout-link').on('click', app.logout); - - Visibility.change(function(e, state){ - if (state === 'visible') { - app.isFocused = true; - app.alternatingTitle(''); - } else if (state === 'hidden') { - app.isFocused = false; - } - }); - - createHeaderTooltips(); - app.showEmailConfirmWarning(); - - socket.removeAllListeners('event:nodebb.ready'); - socket.on('event:nodebb.ready', function(cacheBusters) { - if ( - !app.cacheBusters || - app.cacheBusters.general !== cacheBusters.general || - app.cacheBusters.css !== cacheBusters.css || - app.cacheBusters.js !== cacheBusters.js - ) { - app.cacheBusters = cacheBusters; - - app.alert({ - alert_id: 'forum_updated', - title: '[[global:updated.title]]', - message: '[[global:updated.message]]', - clickfn: function() { - window.location.reload(); - }, - type: 'warning' - }); - } - }); - - require(['taskbar', 'helpers'], function(taskbar, helpers) { - taskbar.init(); - - // templates.js helpers - helpers.register(); - - $(window).trigger('action:app.load'); - }); - }); - }; - - app.loadJQueryUI = function(callback) { - if (typeof $().autocomplete === 'function') { - return callback(); - } - - $.getScript(RELATIVE_PATH + '/vendor/jquery/js/jquery-ui-1.10.4.custom.js', callback); - }; - - app.showEmailConfirmWarning = function(err) { - if (!config.requireEmailConfirmation || !app.user.uid) { - return; - } - if (!app.user.email) { - app.alert({ - alert_id: 'email_confirm', - message: '[[error:no-email-to-confirm]]', - type: 'warning', - timeout: 0, - clickfn: function() { - app.removeAlert('email_confirm'); - ajaxify.go('user/' + app.user.userslug + '/edit'); - } - }); - } else if (!app.user['email:confirmed']) { - app.alert({ - alert_id: 'email_confirm', - message: err ? err.message : '[[error:email-not-confirmed]]', - type: 'warning', - timeout: 0, - clickfn: function() { - app.removeAlert('email_confirm'); - socket.emit('user.emailConfirm', {}, function(err) { - if (err) { - return app.alertError(err.message); - } - app.alertSuccess('[[notifications:email-confirm-sent]]'); - }); - } - }); - } - }; - - showWelcomeMessage = window.location.href.indexOf('loggedin') !== -1; - - app.exposeConfigToTemplates(); - - socketIOConnect(); - - app.cacheBuster = config['cache-buster']; - - require(['csrf'], function(csrf) { - csrf.set(config.csrf_token); - }); - - bootbox.setDefaults({ - locale: config.userLang - }); - - app.alternatingTitle(''); -}()); +"use strict"; +/*global io, templates, ajaxify, utils, bootbox, RELATIVE_PATH, config, Visibility*/ + +var socket, + app = app || {}; + +app.isFocused = true; +app.isConnected = false; +app.currentRoom = null; +app.widgets = {}; +app.cacheBuster = null; + +(function () { + var showWelcomeMessage = false; + var reconnecting = false; + + function socketIOConnect() { + var ioParams = { + reconnectionAttempts: config.maxReconnectionAttempts, + reconnectionDelay: config.reconnectionDelay, + transports: config.socketioTransports, + path: config.relative_path + '/socket.io' + }; + + socket = io(config.websocketAddress, ioParams); + reconnecting = false; + + socket.on('event:connect', function () { + app.showLoginMessage(); + app.replaceSelfLinks(); + $(window).trigger('action:connected'); + app.isConnected = true; + }); + + socket.on('connect', onSocketConnect); + + socket.on('event:disconnect', function() { + $(window).trigger('action:disconnected'); + app.isConnected = false; + socket.connect(); + }); + + socket.on('reconnecting', function (attempt) { + reconnecting = true; + var reconnectEl = $('#reconnect'); + + if (!reconnectEl.hasClass('active')) { + reconnectEl.html(''); + } + + reconnectEl.addClass('active').removeClass("hide").tooltip({ + placement: 'bottom' + }); + }); + + socket.on('event:banned', function() { + app.alert({ + title: '[[global:alert.banned]]', + message: '[[global:alert.banned.message]]', + type: 'danger', + timeout: 1000 + }); + + setTimeout(function() { + window.location.href = config.relative_path + '/'; + }, 1000); + }); + + socket.on('event:logout', app.logout); + + socket.on('event:alert', function(data) { + app.alert(data); + }); + + socket.on('reconnect_failed', function() { + // Wait ten times the reconnection delay and then start over + setTimeout(socket.connect.bind(socket), parseInt(config.reconnectionDelay, 10) * 10); + }); + } + + function onSocketConnect(data) { + if (reconnecting) { + var reconnectEl = $('#reconnect'); + + reconnectEl.tooltip('destroy'); + reconnectEl.html(''); + reconnecting = false; + + // Rejoin room that was left when we disconnected + var url_parts = window.location.pathname.slice(RELATIVE_PATH.length).split('/').slice(1); + var room; + + switch(url_parts[0]) { + case 'user': + room = 'user/' + ajaxify.data.theirid; + break; + case 'topic': + room = 'topic_' + url_parts[1]; + break; + case 'category': + room = 'category_' + url_parts[1]; + break; + case 'recent': + room = 'recent_topics'; + break; + case 'unread': + room = 'unread_topics'; + break; + case 'popular': + room = 'popular_topics'; + break; + case 'admin': + room = 'admin'; + break; + case 'categories': + room = 'categories'; + break; + } + app.currentRoom = ''; + app.enterRoom(room); + + socket.emit('meta.reconnected'); + + app.isConnected = true; + $(window).trigger('action:reconnected'); + + setTimeout(function() { + reconnectEl.removeClass('active').addClass('hide'); + }, 3000); + } + } + + app.logout = function() { + require(['csrf'], function(csrf) { + $.ajax(RELATIVE_PATH + '/logout', { + type: 'POST', + headers: { + 'x-csrf-token': csrf.get() + }, + success: function() { + window.location.href = RELATIVE_PATH + '/'; + } + }); + }); + }; + + app.alert = function (params) { + require(['alerts'], function(alerts) { + alerts.alert(params); + }); + }; + + app.removeAlert = function(id) { + require(['alerts'], function(alerts) { + alerts.remove(id); + }); + }; + + app.alertSuccess = function (message, timeout) { + app.alert({ + title: '[[global:alert.success]]', + message: message, + type: 'success', + timeout: timeout ? timeout : 2000 + }); + }; + + app.alertError = function (message, timeout) { + app.alert({ + title: '[[global:alert.error]]', + message: message, + type: 'danger', + timeout: timeout ? timeout : 5000 + }); + }; + + app.enterRoom = function (room, callback) { + callback = callback || function() {}; + if (socket) { + if (app.currentRoom === room) { + return; + } + + socket.emit('meta.rooms.enter', { + enter: room, + username: app.user.username, + userslug: app.user.userslug, + picture: app.user.picture + }, function(err) { + if (err) { + app.alertError(err.message); + return; + } + app.currentRoom = room; + }); + } + }; + + function highlightNavigationLink() { + var path = window.location.pathname; + $('#main-nav li').removeClass('active'); + if (path) { + $('#main-nav li a').each(function () { + var href = $(this).attr('href'); + + if (href && path.startsWith(href)) { + $(this.parentNode).addClass('active'); + return false; + } + }); + } + } + + app.createUserTooltips = function() { + $('img[title].teaser-pic,img[title].user-img').each(function() { + $(this).tooltip({ + placement: 'top', + title: $(this).attr('title') + }); + }); + }; + + app.createStatusTooltips = function() { + $('body').tooltip({ + selector:'.fa-circle.status', + placement: 'top' + }); + }; + + app.replaceSelfLinks = function(selector) { + selector = selector || $('a'); + selector.each(function() { + var href = $(this).attr('href'); + if (href && app.user.userslug && href.indexOf('user/_self_') !== -1) { + $(this).attr('href', href.replace(/user\/_self_/g, 'user/' + app.user.userslug)); + } + }); + }; + + app.processPage = function () { + highlightNavigationLink(); + + $('.timeago').timeago(); + + utils.makeNumbersHumanReadable($('.human-readable-number')); + + utils.addCommasToNumbers($('.formatted-number')); + + app.createUserTooltips(); + + app.createStatusTooltips(); + + app.replaceSelfLinks(); + + // Scroll back to top of page + window.scrollTo(0, 0); + }; + + app.showLoginMessage = function () { + function showAlert() { + app.alert({ + type: 'success', + title: '[[global:welcome_back]] ' + app.user.username + '!', + message: '[[global:you_have_successfully_logged_in]]', + timeout: 5000 + }); + } + + if (showWelcomeMessage) { + showWelcomeMessage = false; + if (document.readyState !== 'complete') { + $(document).ready(showAlert); + } else { + showAlert(); + } + } + }; + + app.openChat = function (username, touid) { + if (username === app.user.username) { + return app.alertError('[[error:cant-chat-with-yourself]]'); + } + + if (!app.user.uid) { + return app.alertError('[[error:not-logged-in]]'); + } + + require(['chat'], function (chat) { + function loadAndCenter(chatModal) { + chat.load(chatModal.attr('UUID')); + chat.center(chatModal); + chat.focusInput(chatModal); + } + + if (!chat.modalExists(touid)) { + chat.createModal(username, touid, loadAndCenter); + } else { + loadAndCenter(chat.getModal(touid)); + } + }); + }; + + var titleObj = { + active: false, + interval: undefined, + titles: [] + }; + + app.alternatingTitle = function (title) { + if (typeof title !== 'string') { + return; + } + + if (title.length > 0 && !app.isFocused) { + if (!titleObj.titles[0]) { + titleObj.titles[0] = window.document.title; + } + + require(['translator'], function(translator) { + translator.translate(title, function(translated) { + titleObj.titles[1] = translated; + if (titleObj.interval) { + clearInterval(titleObj.interval); + } + + titleObj.interval = setInterval(function() { + var title = titleObj.titles[titleObj.titles.indexOf(window.document.title) ^ 1]; + if (title) { + window.document.title = $('
').html(title).text(); + } + }, 2000); + }); + }); + } else { + if (titleObj.interval) { + clearInterval(titleObj.interval); + } + if (titleObj.titles[0]) { + window.document.title = $('
').html(titleObj.titles[0]).text(); + } + } + }; + + app.refreshTitle = function(url) { + if (!url) { + var a = document.createElement('a'); + a.href = document.location; + url = a.pathname.slice(1); + } + + socket.emit('meta.buildTitle', url, function(err, title, numNotifications) { + if (err) { + return; + } + titleObj.titles[0] = (numNotifications > 0 ? '(' + numNotifications + ') ' : '') + title; + app.alternatingTitle(''); + }); + }; + + app.toggleNavbar = function(state) { + var navbarEl = $('.navbar'); + if (navbarEl) { + navbarEl.toggleClass('hidden', !!!state); + } + }; + + app.exposeConfigToTemplates = function() { + $(document).ready(function() { + templates.setGlobal('loggedIn', config.loggedIn); + templates.setGlobal('relative_path', RELATIVE_PATH); + for(var key in config) { + if (config.hasOwnProperty(key)) { + templates.setGlobal('config.' + key, config[key]); + } + } + }); + }; + + function createHeaderTooltips() { + if (utils.findBootstrapEnvironment() === 'xs') { + return; + } + $('#header-menu li a[title]').each(function() { + $(this).tooltip({ + placement: 'bottom', + title: $(this).attr('title') + }); + }); + + $('#search-form').parent().tooltip({ + placement: 'bottom', + title: $('#search-button i').attr('title') + }); + + $('#user_dropdown').tooltip({ + placement: 'bottom', + title: $('#user_dropdown').attr('title') + }); + } + + app.handleSearch = function () { + var searchButton = $("#search-button"), + searchFields = $("#search-fields"), + searchInput = $('#search-fields input'); + + $('#search-form').on('submit', dismissSearch); + searchInput.on('blur', dismissSearch); + + function dismissSearch(){ + searchFields.hide(); + searchButton.show(); + } + + searchButton.on('click', function(e) { + if (!config.loggedIn && !config.allowGuestSearching) { + app.alert({ + message:'[[error:search-requires-login]]', + timeout: 3000 + }); + ajaxify.go('login'); + return false; + } + e.stopPropagation(); + + app.prepareSearch(); + return false; + }); + + $('#search-form').on('submit', function () { + var input = $(this).find('input'); + require(['search'], function(search) { + search.query({term: input.val()}, function() { + input.val(''); + }); + }); + return false; + }); + }; + + app.prepareSearch = function() { + $("#search-fields").removeClass('hide').show(); + $("#search-button").hide(); + $('#search-fields input').focus(); + }; + + function handleStatusChange() { + $('#user-control-list .user-status').off('click').on('click', function(e) { + var status = $(this).attr('data-status'); + socket.emit('user.setStatus', status, function(err, data) { + if(err) { + return app.alertError(err.message); + } + $('#logged-in-menu #user_label #user-profile-link>i').attr('class', 'fa fa-circle status ' + status); + }); + e.preventDefault(); + }); + } + + app.updateUserStatus = function(el, status) { + if (!el.length) { + return; + } + + translator.translate('[[global:' + status + ']]', function(translated) { + el.removeClass('online offline dnd away') + .addClass(status) + .attr('title', translated) + .attr('data-original-title', translated); + }); + }; + + function handleNewTopic() { + $('#content').on('click', '#new_topic', function() { + var cid = ajaxify.data.cid; + if (cid) { + $(window).trigger('action:composer.topic.new', { + cid: cid + }); + } else { + socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { + if (err) { + return app.alertError(err.message); + } + if (categories.length) { + $(window).trigger('action:composer.topic.new', { + cid: categories[0].cid + }); + } + }); + } + }); + } + + app.load = function() { + $('document').ready(function () { + var url = ajaxify.start(window.location.pathname.slice(1), true, window.location.search); + ajaxify.end(url, app.template); + + handleStatusChange(); + + if (config.searchEnabled) { + app.handleSearch(); + } + + handleNewTopic(); + + $('#logout-link').on('click', app.logout); + + Visibility.change(function(e, state){ + if (state === 'visible') { + app.isFocused = true; + app.alternatingTitle(''); + } else if (state === 'hidden') { + app.isFocused = false; + } + }); + + createHeaderTooltips(); + app.showEmailConfirmWarning(); + + socket.removeAllListeners('event:nodebb.ready'); + socket.on('event:nodebb.ready', function(cacheBusters) { + if ( + !app.cacheBusters || + app.cacheBusters.general !== cacheBusters.general || + app.cacheBusters.css !== cacheBusters.css || + app.cacheBusters.js !== cacheBusters.js + ) { + app.cacheBusters = cacheBusters; + + app.alert({ + alert_id: 'forum_updated', + title: '[[global:updated.title]]', + message: '[[global:updated.message]]', + clickfn: function() { + window.location.reload(); + }, + type: 'warning' + }); + } + }); + + require(['taskbar', 'helpers'], function(taskbar, helpers) { + taskbar.init(); + + // templates.js helpers + helpers.register(); + + $(window).trigger('action:app.load'); + }); + }); + }; + + app.loadJQueryUI = function(callback) { + if (typeof $().autocomplete === 'function') { + return callback(); + } + + $.getScript(RELATIVE_PATH + '/vendor/jquery/js/jquery-ui-1.10.4.custom.js', callback); + }; + + app.showEmailConfirmWarning = function(err) { + if (!config.requireEmailConfirmation || !app.user.uid) { + return; + } + if (!app.user.email) { + app.alert({ + alert_id: 'email_confirm', + message: '[[error:no-email-to-confirm]]', + type: 'warning', + timeout: 0, + clickfn: function() { + app.removeAlert('email_confirm'); + ajaxify.go('user/' + app.user.userslug + '/edit'); + } + }); + } else if (!app.user['email:confirmed']) { + app.alert({ + alert_id: 'email_confirm', + message: err ? err.message : '[[error:email-not-confirmed]]', + type: 'warning', + timeout: 0, + clickfn: function() { + app.removeAlert('email_confirm'); + socket.emit('user.emailConfirm', {}, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('[[notifications:email-confirm-sent]]'); + }); + } + }); + } + }; + + showWelcomeMessage = window.location.href.indexOf('loggedin') !== -1; + + app.exposeConfigToTemplates(); + + socketIOConnect(); + + app.cacheBuster = config['cache-buster']; + + require(['csrf'], function(csrf) { + csrf.set(config.csrf_token); + }); + + bootbox.setDefaults({ + locale: config.userLang + }); + + app.alternatingTitle(''); +}()); diff --git a/public/vendor/fontawesome/.gitignore b/public/vendor/fontawesome/.gitignore index 51d8053d8c..aaad45f3c8 100644 --- a/public/vendor/fontawesome/.gitignore +++ b/public/vendor/fontawesome/.gitignore @@ -1,29 +1,29 @@ -*.pyc -*.egg-info -*.db -*.db.old -*.swp -*.db-journal - -.coverage -.DS_Store -.installed.cfg - -.idea/* -.svn/* -src/website/static/* -src/website/media/* - -bin -build -cfcache -develop-eggs -dist -downloads -eggs -parts +*.pyc +*.egg-info +*.db +*.db.old +*.swp +*.db-journal + +.coverage +.DS_Store +.installed.cfg + +.idea/* +.svn/* +src/website/static/* +src/website/media/* + +bin +build +cfcache +develop-eggs +dist +downloads +eggs +parts tmp -.sass-cache - -src/website/settingslocal.py +.sass-cache + +src/website/settingslocal.py stunnel.log \ No newline at end of file diff --git a/public/vendor/jquery/timeago/locales/jquery.timeago.fa.js b/public/vendor/jquery/timeago/locales/jquery.timeago.fa.js index 0a70819d44..2bfbf53ccd 100644 --- a/public/vendor/jquery/timeago/locales/jquery.timeago.fa.js +++ b/public/vendor/jquery/timeago/locales/jquery.timeago.fa.js @@ -1,22 +1,22 @@ - -// Persian -// Use DIR attribute for RTL text in Persian Language for ABBR tag . -// By MB.seifollahi@gmail.com -jQuery.timeago.settings.strings = { - prefixAgo: null, - prefixFromNow: null, - suffixAgo: "پیش", - suffixFromNow: "از حال", - seconds: "کمتر از یک دقیقه", - minute: "حدود یک دقیقه", - minutes: "%d دقیقه", - hour: "حدود یک ساعت", - hours: "حدود %d ساعت", - day: "یک روز", - days: "%d روز", - month: "حدود یک ماه", - months: "%d ماه", - year: "حدود یک سال", - years: "%d سال", - wordSeparator: " " + +// Persian +// Use DIR attribute for RTL text in Persian Language for ABBR tag . +// By MB.seifollahi@gmail.com +jQuery.timeago.settings.strings = { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: "پیش", + suffixFromNow: "از حال", + seconds: "کمتر از یک دقیقه", + minute: "حدود یک دقیقه", + minutes: "%d دقیقه", + hour: "حدود یک ساعت", + hours: "حدود %d ساعت", + day: "یک روز", + days: "%d روز", + month: "حدود یک ماه", + months: "%d ماه", + year: "حدود یک سال", + years: "%d سال", + wordSeparator: " " }; \ No newline at end of file diff --git a/public/vendor/jquery/timeago/locales/jquery.timeago.uz.js b/public/vendor/jquery/timeago/locales/jquery.timeago.uz.js index 31c0c02af5..380f18dc04 100755 --- a/public/vendor/jquery/timeago/locales/jquery.timeago.uz.js +++ b/public/vendor/jquery/timeago/locales/jquery.timeago.uz.js @@ -1,19 +1,19 @@ -//Uzbek -jQuery.timeago.settings.strings = { - prefixAgo: null, - prefixFromNow: "keyin", - suffixAgo: "avval", - suffixFromNow: null, - seconds: "bir necha soniya", - minute: "1 daqiqa", - minutes: function(value) { return "%d daqiqa" }, - hour: "1 soat", - hours: function(value) { return "%d soat" }, - day: "1 kun", - days: function(value) { return "%d kun" }, - month: "1 oy", - months: function(value) { return "%d oy" }, - year: "1 yil", - years: function(value) { return "%d yil" }, - wordSeparator: " " -}; +//Uzbek +jQuery.timeago.settings.strings = { + prefixAgo: null, + prefixFromNow: "keyin", + suffixAgo: "avval", + suffixFromNow: null, + seconds: "bir necha soniya", + minute: "1 daqiqa", + minutes: function(value) { return "%d daqiqa" }, + hour: "1 soat", + hours: function(value) { return "%d soat" }, + day: "1 kun", + days: function(value) { return "%d kun" }, + month: "1 oy", + months: function(value) { return "%d oy" }, + year: "1 yil", + years: function(value) { return "%d yil" }, + wordSeparator: " " +}; diff --git a/src/routes/admin.js b/src/routes/admin.js index 40bb725e89..a8d95776ee 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1,85 +1,85 @@ -"use strict"; - -var express = require('express'); - - -function apiRoutes(router, middleware, controllers) { - router.get('/users/csv', middleware.authenticate, controllers.admin.users.getCSV); - - var multipart = require('connect-multiparty'); - var multipartMiddleware = multipart(); - - var middlewares = [multipartMiddleware, middleware.validateFiles, middleware.applyCSRF, middleware.authenticate]; - - router.post('/category/uploadpicture', middlewares, controllers.admin.uploads.uploadCategoryPicture); - router.post('/uploadfavicon', middlewares, controllers.admin.uploads.uploadFavicon); - router.post('/uploadlogo', middlewares, controllers.admin.uploads.uploadLogo); - router.post('/uploadgravatardefault', middlewares, controllers.admin.uploads.uploadGravatarDefault); -} - -function adminRouter(middleware, controllers) { - var router = express.Router(); - - router.use(middleware.admin.buildHeader); - - addRoutes(router, middleware, controllers); - - return router; -} - -function apiRouter(middleware, controllers) { - var router = express.Router(); - - addRoutes(router, middleware, controllers); - - apiRoutes(router, middleware, controllers); - - return router; -} - -function addRoutes(router, middleware, controllers) { - router.get('/', controllers.admin.home); - router.get('/general/dashboard', controllers.admin.home); - router.get('/general/languages', controllers.admin.languages.get); - router.get('/general/sounds', controllers.admin.sounds.get); - router.get('/general/navigation', controllers.admin.navigation.get); - router.get('/general/homepage', controllers.admin.homepage.get); - - router.get('/manage/categories', controllers.admin.categories.getAll); - router.get('/manage/categories/:category_id', controllers.admin.categories.get); - - router.get('/manage/tags', controllers.admin.tags.get); - - router.get('/manage/flags', controllers.admin.flags.get); - - router.get('/manage/users', controllers.admin.users.sortByJoinDate); - router.get('/manage/users/search', controllers.admin.users.search); - router.get('/manage/users/latest', controllers.admin.users.sortByJoinDate); - router.get('/manage/users/sort-posts', controllers.admin.users.sortByPosts); - router.get('/manage/users/sort-reputation', controllers.admin.users.sortByReputation); - router.get('/manage/users/banned', controllers.admin.users.banned); - router.get('/manage/users/registration', controllers.admin.users.registrationQueue); - - router.get('/manage/groups', controllers.admin.groups.list); - router.get('/manage/groups/:name', controllers.admin.groups.get); - - router.get('/settings/:term?', controllers.admin.settings.get); - - router.get('/appearance/:term?', controllers.admin.appearance.get); - - router.get('/extend/plugins', controllers.admin.plugins.get); - router.get('/extend/widgets', controllers.admin.extend.widgets); - router.get('/extend/rewards', controllers.admin.extend.rewards); - - router.get('/advanced/database', controllers.admin.database.get); - router.get('/advanced/events', controllers.admin.events.get); - router.get('/advanced/logs', controllers.admin.logs.get); - router.get('/advanced/post-cache', controllers.admin.postCache.get); - - router.get('/development/logger', controllers.admin.logger.get); -} - -module.exports = function(app, middleware, controllers) { - app.use('/admin/', adminRouter(middleware, controllers)); - app.use('/api/admin/', apiRouter(middleware, controllers)); -}; +"use strict"; + +var express = require('express'); + + +function apiRoutes(router, middleware, controllers) { + router.get('/users/csv', middleware.authenticate, controllers.admin.users.getCSV); + + var multipart = require('connect-multiparty'); + var multipartMiddleware = multipart(); + + var middlewares = [multipartMiddleware, middleware.validateFiles, middleware.applyCSRF, middleware.authenticate]; + + router.post('/category/uploadpicture', middlewares, controllers.admin.uploads.uploadCategoryPicture); + router.post('/uploadfavicon', middlewares, controllers.admin.uploads.uploadFavicon); + router.post('/uploadlogo', middlewares, controllers.admin.uploads.uploadLogo); + router.post('/uploadgravatardefault', middlewares, controllers.admin.uploads.uploadGravatarDefault); +} + +function adminRouter(middleware, controllers) { + var router = express.Router(); + + router.use(middleware.admin.buildHeader); + + addRoutes(router, middleware, controllers); + + return router; +} + +function apiRouter(middleware, controllers) { + var router = express.Router(); + + addRoutes(router, middleware, controllers); + + apiRoutes(router, middleware, controllers); + + return router; +} + +function addRoutes(router, middleware, controllers) { + router.get('/', controllers.admin.home); + router.get('/general/dashboard', controllers.admin.home); + router.get('/general/languages', controllers.admin.languages.get); + router.get('/general/sounds', controllers.admin.sounds.get); + router.get('/general/navigation', controllers.admin.navigation.get); + router.get('/general/homepage', controllers.admin.homepage.get); + + router.get('/manage/categories', controllers.admin.categories.getAll); + router.get('/manage/categories/:category_id', controllers.admin.categories.get); + + router.get('/manage/tags', controllers.admin.tags.get); + + router.get('/manage/flags', controllers.admin.flags.get); + + router.get('/manage/users', controllers.admin.users.sortByJoinDate); + router.get('/manage/users/search', controllers.admin.users.search); + router.get('/manage/users/latest', controllers.admin.users.sortByJoinDate); + router.get('/manage/users/sort-posts', controllers.admin.users.sortByPosts); + router.get('/manage/users/sort-reputation', controllers.admin.users.sortByReputation); + router.get('/manage/users/banned', controllers.admin.users.banned); + router.get('/manage/users/registration', controllers.admin.users.registrationQueue); + + router.get('/manage/groups', controllers.admin.groups.list); + router.get('/manage/groups/:name', controllers.admin.groups.get); + + router.get('/settings/:term?', controllers.admin.settings.get); + + router.get('/appearance/:term?', controllers.admin.appearance.get); + + router.get('/extend/plugins', controllers.admin.plugins.get); + router.get('/extend/widgets', controllers.admin.extend.widgets); + router.get('/extend/rewards', controllers.admin.extend.rewards); + + router.get('/advanced/database', controllers.admin.database.get); + router.get('/advanced/events', controllers.admin.events.get); + router.get('/advanced/logs', controllers.admin.logs.get); + router.get('/advanced/post-cache', controllers.admin.postCache.get); + + router.get('/development/logger', controllers.admin.logger.get); +} + +module.exports = function(app, middleware, controllers) { + app.use('/admin/', adminRouter(middleware, controllers)); + app.use('/api/admin/', apiRouter(middleware, controllers)); +}; diff --git a/src/topics.js b/src/topics.js index 13522aad00..d4e5b38597 100644 --- a/src/topics.js +++ b/src/topics.js @@ -1,369 +1,369 @@ -"use strict"; - -var async = require('async'), - validator = require('validator'), - - _ = require('underscore'), - db = require('./database'), - posts = require('./posts'), - utils = require('../public/src/utils'), - plugins = require('./plugins'), - user = require('./user'), - categories = require('./categories'), - privileges = require('./privileges'); - -(function(Topics) { - - require('./topics/create')(Topics); - require('./topics/delete')(Topics); - require('./topics/unread')(Topics); - require('./topics/recent')(Topics); - require('./topics/popular')(Topics); - require('./topics/user')(Topics); - require('./topics/fork')(Topics); - require('./topics/posts')(Topics); - require('./topics/follow')(Topics); - require('./topics/tags')(Topics); - require('./topics/teaser')(Topics); - require('./topics/suggested')(Topics); - - Topics.exists = function(tid, callback) { - db.isSortedSetMember('topics:tid', tid, callback); - }; - - Topics.getTopicData = function(tid, callback) { - db.getObject('topic:' + tid, function(err, topic) { - if (err || !topic) { - return callback(err); - } - modifyTopic(topic, callback); - }); - }; - - Topics.getTopicsData = function(tids, callback) { - var keys = []; - - for (var i=0; i Date: Tue, 21 Jul 2015 11:29:11 -0400 Subject: [PATCH 4/5] latest translations --- public/language/de/email.json | 8 ++++---- public/language/de/error.json | 8 ++++---- public/language/de/global.json | 2 +- public/language/de/groups.json | 14 +++++++------- public/language/de/notifications.json | 2 +- public/language/de/register.json | 2 +- public/language/de/unread.json | 2 +- public/language/de/user.json | 14 +++++++------- public/language/de/users.json | 18 +++++++++--------- public/language/fa_IR/email.json | 8 ++++---- public/language/fa_IR/notifications.json | 2 +- public/language/fa_IR/register.json | 2 +- public/language/fa_IR/topic.json | 2 +- public/language/fa_IR/unread.json | 2 +- public/language/fa_IR/user.json | 16 ++++++++-------- public/language/fa_IR/users.json | 18 +++++++++--------- public/language/fr/email.json | 8 ++++---- public/language/fr/error.json | 8 ++++---- public/language/fr/global.json | 2 +- public/language/fr/groups.json | 14 +++++++------- public/language/fr/notifications.json | 2 +- public/language/fr/register.json | 2 +- public/language/fr/unread.json | 2 +- public/language/fr/user.json | 12 ++++++------ public/language/fr/users.json | 18 +++++++++--------- public/language/it/notifications.json | 2 +- public/language/nl/category.json | 2 +- public/language/nl/email.json | 10 +++++----- public/language/nl/error.json | 8 ++++---- public/language/nl/global.json | 2 +- public/language/nl/groups.json | 22 +++++++++++----------- public/language/nl/notifications.json | 2 +- public/language/nl/recent.json | 2 +- public/language/nl/register.json | 2 +- public/language/nl/search.json | 4 ++-- public/language/nl/topic.json | 16 ++++++++-------- public/language/nl/unread.json | 2 +- public/language/nl/user.json | 12 ++++++------ public/language/nl/users.json | 14 +++++++------- public/language/zh_CN/category.json | 6 +++--- public/language/zh_CN/users.json | 18 +++++++++--------- 41 files changed, 156 insertions(+), 156 deletions(-) diff --git a/public/language/de/email.json b/public/language/de/email.json index 1427908754..923e3000e7 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -1,15 +1,15 @@ { "password-reset-requested": "Zurücksetzung des Passworts beantragt - %1!", "welcome-to": "Willkommen bei %1", - "invite": "Invitation from %1", + "invite": "Einladung von %1", "greeting_no_name": "Hallo", "greeting_with_name": "Hallo %1", "welcome.text1": "Vielen Dank für die Registrierung bei %1!", "welcome.text2": "Um dein Konto vollständig zu aktivieren, müssen wir überprüfen, ob du Besitzer der E-Mail-Adresse bist, mit der du dich registriert hast.", - "welcome.text3": "An administrator has accepted your registration application. You can login with your username/password now.", + "welcome.text3": "Ein Administrator hat deine Registration aktzeptiert. Du kannst dich jetzt mit deinem Benutzernamen/Passwort einloggen.", "welcome.cta": "Klicke hier, um deine E-Mail-Adresse zu bestätigen.", - "invitation.text1": "%1 has invited you to join %2", - "invitation.ctr": "Click here to create your account.", + "invitation.text1": "%1 hat dich eingeladen %2 beizutreten", + "invitation.ctr": "Klicke hier, um ein Konto zu erstellen.", "reset.text1": "Wir haben eine Anfrage auf Zurücksetzung deines Passworts erhalten, wahrscheinlich, weil du es vergessen hast. Falls dies nicht der Fall ist, ignoriere bitte diese E-Mail.", "reset.text2": "Klicke bitte auf den folgenden Link, um mit der Zurücksetzung deines Passworts fortzufahren:", "reset.cta": "Klicke hier, um dein Passwort zurückzusetzen", diff --git a/public/language/de/error.json b/public/language/de/error.json index ed8d482252..210d0067c9 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -51,7 +51,7 @@ "already-favourited": "Dieser Beitrag ist bereits in deinen Favoriten enthalten", "already-unfavourited": "Du hast diesen Beitrag bereits aus deinen Favoriten entfernt", "cant-ban-other-admins": "Du kannst andere Administratoren nicht sperren!", - "cant-remove-last-admin": "You are the only administrator. Add another user as an administrator before removing yourself as admin", + "cant-remove-last-admin": "Du bist der einzige Administrator. Füge zuerst einen anderen Administrator hinzu, bevor du dich selbst als Administrator entfernst", "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", @@ -60,8 +60,8 @@ "group-name-change-not-allowed": "Du kannst den Namen der Gruppe nicht ändern", "group-already-member": "Du bist bereits Teil dieser Gruppe", "group-needs-owner": "Diese Gruppe muss mindestens einen Besitzer vorweisen", - "group-already-invited": "This user has already been invited", - "group-already-requested": "Your membership request has already been submitted", + "group-already-invited": "Dieser Benutzer wurde bereits eingeladen", + "group-already-requested": "Deine Mitgliedsanfrage wurde bereits eingereicht", "post-already-deleted": "Dieser Beitrag ist bereits gelöscht worden", "post-already-restored": "Dieser Beitrag ist bereits wiederhergestellt worden", "topic-already-deleted": "Dieses Thema ist bereits gelöscht worden", @@ -79,7 +79,7 @@ "downvoting-disabled": "Downvotes sind deaktiviert.", "not-enough-reputation-to-downvote": "Deine Reputation ist zu niedrig, um diesen Beitrag negativ zu bewerten.", "not-enough-reputation-to-flag": "Deine Reputation ist nicht gut genug, um diesen Beitrag zu melden", - "already-flagged": "You have already flagged this post", + "already-flagged": "Du hast diesen Beitrag bereits gemeldet", "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", diff --git a/public/language/de/global.json b/public/language/de/global.json index 1b72874484..ace27161a1 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -50,7 +50,7 @@ "views": "Aufrufe", "reputation": "Reputation", "read_more": "weiterlesen", - "more": "More", + "more": "Mehr", "posted_ago_by_guest": "%1 von einem Gast geschrieben", "posted_ago_by": "%1 von %2 geschrieben", "posted_ago": "%1 geschrieben", diff --git a/public/language/de/groups.json b/public/language/de/groups.json index daa93a3e4f..a99d4ebc36 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -6,12 +6,12 @@ "no_groups_found": "Es sind keine Gruppen vorhanden", "pending.accept": "Annehmen", "pending.reject": "Abweisen", - "pending.accept_all": "Accept All", - "pending.reject_all": "Reject All", - "pending.none": "There are no pending members at this time", - "invited.none": "There are no invited members at this time", - "invited.uninvite": "Rescind Invitation", - "invited.search": "Search for a user to invite to this group", + "pending.accept_all": "Alle annehmen", + "pending.reject_all": "Alle ablehnen", + "pending.none": "Es sind zur Zeit keine unvearbeiteten Mitglieder vorhanden", + "invited.none": "Es sind zur Zeit keine weiteren Mitglieder eingeladen", + "invited.uninvite": "Einladung zurücknehmen", + "invited.search": "Suche nach einem Benutzer um ihn in diese Gruppe aufzunehmen", "cover-instructions": "Foto auf eine Position bewegen, und Speichern drücken", "cover-change": "Ändern", "cover-save": "Speichern", @@ -19,7 +19,7 @@ "details.title": "Gruppendetails", "details.members": "Mitgliederliste", "details.pending": "Mitglieder in Schwebe", - "details.invited": "Invited Members", + "details.invited": "Eingeladene Mitglieder", "details.has_no_posts": "Die Mitglieder dieser Gruppe haben keine Beiträge verfasst.", "details.latest_posts": "Neueste Beiträge", "details.private": "Privat", diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index 20303ea524..0dcc1b825d 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -20,7 +20,7 @@ "user_posted_topic": "%1 hat ein neues Thema erstellt: %2", "user_mentioned_you_in": "%1 erwähnte dich in %2", "user_started_following_you": "%1 folgt dir jetzt.", - "new_register": "%1 sent a registration request.", + "new_register": "%1 hat eine Registrationsanfrage geschickt.", "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.", diff --git a/public/language/de/register.json b/public/language/de/register.json index b567df9fe3..9314539d46 100644 --- a/public/language/de/register.json +++ b/public/language/de/register.json @@ -15,5 +15,5 @@ "alternative_registration": "Alternative Registrierung", "terms_of_use": "Nutzungsbedingungen", "agree_to_terms_of_use": "Ich stimme den Nutzungsbedingungen zu", - "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." + "registration-added-to-queue": "Deine Registration wurde abgeschickt. Du wirst eine E-Mail erhalten, sobald sie von einem Administrator akzeptiert wird." } \ No newline at end of file diff --git a/public/language/de/unread.json b/public/language/de/unread.json index cea3122475..b9796b7c41 100644 --- a/public/language/de/unread.json +++ b/public/language/de/unread.json @@ -5,6 +5,6 @@ "mark_as_read": "Als gelesen markieren", "selected": "Ausgewählte", "all": "Alle", - "all_categories": "All categories", + "all_categories": "Alle Kategorien", "topics_marked_as_read.success": "Themen als gelesen markiert!" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index 6a527b4768..8c96e203d3 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -6,12 +6,12 @@ "postcount": "Beiträge", "email": "E-Mail", "confirm_email": "E-Mail bestätigen", - "ban_account": "Ban Account", - "ban_account_confirm": "Do you really want to ban this user?", - "unban_account": "Unban Account", + "ban_account": "Konto sperren", + "ban_account_confirm": "Sind Sie sicher, dass Sie diesen Benutzer sperren möchten?", + "unban_account": "Konto entsperren", "delete_account": "Konto löschen", "delete_account_confirm": "Bist du sicher, dass du dein Konto löschen möchtest?
Diese Aktion kann nicht rückgängig gemacht werden und du kannst deine Daten nicht wiederherstellen

Gebe deinen Benutzernamen ein, um zu bestätigen, dass du dieses Konto löschen möchtest.", - "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

", + "delete_this_account_confirm": "Bist du sicher, dass du dieses Konto löschen möchtest?
Diese Aktion kann nicht rückgangig gemacht werden und du kannst die Daten nicht wiederherstellen

", "fullname": "Kompletter Name", "website": "Homepage", "location": "Wohnort", @@ -68,9 +68,9 @@ "settings-require-reload": "Manche Einstellungsänderung benötigt ein aktualisieren. Drücke hier um die Seite neu zu laden.", "has_no_follower": "Dieser User hat noch keine Follower.", "follows_no_one": "Dieser User folgt noch niemandem :(", - "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_posts": "Dieser Nutzer hat noch nichts gepostet.", + "has_no_topics": "Dieser Nutzer hat noch keine Themen gepostet.", + "has_no_watched_topics": "Dieser Nutzer beobachtet keine Themen.", "email_hidden": "E-Mail Adresse versteckt", "hidden": "versteckt", "paginate_description": "Themen und Beiträge in Seiten aufteilen, anstelle unendlich zu scrollen", diff --git a/public/language/de/users.json b/public/language/de/users.json index ff050ce4fc..ebc7f42727 100644 --- a/public/language/de/users.json +++ b/public/language/de/users.json @@ -9,13 +9,13 @@ "filter-by": "Filtern nach", "online-only": "Nur Online", "picture-only": "Nur mit Bildern", - "invite": "Invite", - "invitation-email-sent": "An invitation email has been sent to %1", - "user_list": "User List", - "recent_topics": "Recent Topics", - "popular_topics": "Popular Topics", - "unread_topics": "Unread Topics", - "categories": "Categories", - "tags": "Tags", - "map": "Map" + "invite": "Einladen", + "invitation-email-sent": "Eine Einladungsemail wurde an %1 verschickt", + "user_list": "Nutzerliste", + "recent_topics": "Neueste Themen", + "popular_topics": "Beliebte Themen", + "unread_topics": "Ungelesen Themen", + "categories": "Kategorien", + "tags": "Stichwörter", + "map": "Karte" } \ No newline at end of file diff --git a/public/language/fa_IR/email.json b/public/language/fa_IR/email.json index 0921411b52..4b0a656909 100644 --- a/public/language/fa_IR/email.json +++ b/public/language/fa_IR/email.json @@ -1,15 +1,15 @@ { "password-reset-requested": "درخواست بازیابی گذرواژه- %1!", "welcome-to": "به 1% خوش آمدید", - "invite": "Invitation from %1", + "invite": "دعوتنامه از %1", "greeting_no_name": "سلام", "greeting_with_name": "سلام 1%", "welcome.text1": "متشکر بابت ثبت نام در %1!", "welcome.text2": "برای فعال کردن کامل اکانت شما، ما نیاز داریم تا اطمینان حاصل کنیم که شما مالک ایمیلی که با ان ثبت نام کردید هستید.", - "welcome.text3": "An administrator has accepted your registration application. You can login with your username/password now.", + "welcome.text3": "ِک مدیر درخواست ثبت نام شما را قبول کرده. اکنون میتوانید با نام کاربری/رمز عبور خود وارد شوید", "welcome.cta": "برای تأیید آدرس ایمیل خود اینجا کلیک کنید", - "invitation.text1": "%1 has invited you to join %2", - "invitation.ctr": "Click here to create your account.", + "invitation.text1": "%1 شما را برای پیوستن به %2 دعوت کرده", + "invitation.ctr": "برای ساخت حسابتان اینجا را کلیک کنید", "reset.text1": "ما یک درخواست برای بازنشانی رمزعبور شما دریافت کرده ایم، احتمالا به این دلیل که شما آن را فراموش کرده اید. اگر این مورد نیست و شما رمز خود را به یاد دارید، لطفا این ایمیل را نادیده بگیرید.", "reset.text2": "برای ادامه بازنشانی رمز، لطفابر روی این لینک کلیک کنید:", "reset.cta": "برای تنظیم مجدد گذرواژه‌ی خود اینجا کلیک کنید", diff --git a/public/language/fa_IR/notifications.json b/public/language/fa_IR/notifications.json index f939f86e77..8a5cbf8863 100644 --- a/public/language/fa_IR/notifications.json +++ b/public/language/fa_IR/notifications.json @@ -20,7 +20,7 @@ "user_posted_topic": "%1 یک جستار جدید ارسال کرده: %2", "user_mentioned_you_in": "%1 در \n%1 mentioned you in %2 از شما نام برده", "user_started_following_you": "%1 شروع به دنبال کردن شما کرده", - "new_register": "%1 sent a registration request.", + "new_register": "%1 یک درخواست ثبت نام ارسال کرده است", "email-confirmed": "رایانامه تایید شد", "email-confirmed-message": "بابت تایید ایمیلتان سپاس‌گزاریم. حساب کاربری شما اکنون به صورت کامل فعال شده است.", "email-confirm-error-message": "خطایی در تایید آدرس ایمیل شما پیش آمده است. ممکن است کد نا‌معتبر و یا منقضی شده باشد.", diff --git a/public/language/fa_IR/register.json b/public/language/fa_IR/register.json index f5fb82bb5d..f1306c175b 100644 --- a/public/language/fa_IR/register.json +++ b/public/language/fa_IR/register.json @@ -15,5 +15,5 @@ "alternative_registration": "روش نام‌نویسی جایگزین", "terms_of_use": "شرایط استفاده", "agree_to_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." + "registration-added-to-queue": "ثبت نام شما به صف تایید اضافه شد. وقتی توسط یک مدیر تایید شد شما رایانامه ای دریافت خواهید کرد." } \ No newline at end of file diff --git a/public/language/fa_IR/topic.json b/public/language/fa_IR/topic.json index 3a26922060..849d261a67 100644 --- a/public/language/fa_IR/topic.json +++ b/public/language/fa_IR/topic.json @@ -5,7 +5,7 @@ "no_topics_found": "هیچ جستاری یافت نشد!", "no_posts_found": "دیدگاهی یافت نشد!", "post_is_deleted": "این دیدگاه پاک شده!", - "topic_is_deleted": "This topic is deleted!", + "topic_is_deleted": "جستار حذف شده است!", "profile": "نمایه", "posted_by": "ارسال شده توسط %1", "posted_by_guest": "ارسال شده توسط مهمان", diff --git a/public/language/fa_IR/unread.json b/public/language/fa_IR/unread.json index d7b2400778..ae9ce77968 100644 --- a/public/language/fa_IR/unread.json +++ b/public/language/fa_IR/unread.json @@ -5,6 +5,6 @@ "mark_as_read": "خوانده شده بگیر", "selected": "برگزیده", "all": "همه", - "all_categories": "All categories", + "all_categories": "تمام دسته ها", "topics_marked_as_read.success": "همه جستارها خوانده شدند" } \ No newline at end of file diff --git a/public/language/fa_IR/user.json b/public/language/fa_IR/user.json index 474671e365..3f6f0a27ee 100644 --- a/public/language/fa_IR/user.json +++ b/public/language/fa_IR/user.json @@ -25,7 +25,7 @@ "watched": "پاییده شده", "followers": "دنبال‌کننده‌ها", "following": "دنبال‌شونده‌ها", - "aboutme": "About me", + "aboutme": "درباره ی من", "signature": "امضا", "gravatar": "گراواتار", "birthday": "روز تولد", @@ -68,21 +68,21 @@ "settings-require-reload": "تغییر برخی تنظیمات مستلزم بارگذاری مجدد هستند. برای بارگذاری مجدد صفحه اینجا کلیک کنید.", "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_posts": "این کاربر تا به حال هیچ چیزی ارسال نکرده است.", + "has_no_topics": "این کاربر تا به حال هیچ جستاری ارسال نکرده است", + "has_no_watched_topics": "این کاربر تا به حال هیچ جستاری را نپاییده است", "email_hidden": "رایانامه پنهان شده", "hidden": "پنهان", "paginate_description": "Paginate topics and posts instead of using infinite scroll", "topics_per_page": "شمار جستارها در هر برگه", "posts_per_page": "شمار دیدگاه‌ها در هر برگه", - "notification_sounds": "Play a sound when you receive a notification", + "notification_sounds": "پخش صدا زمانی که یک آگاه سازی دریافت میکنید", "browsing": "تنظیمات مرور", - "open_links_in_new_tab": "Open outgoing links in new tab", + "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", - "follow_topics_you_reply_to": "Follow topics that you reply to", - "follow_topics_you_create": "Follow topics you create", + "follow_topics_you_reply_to": "تاپیک هایی که پاسخ داده ای را دنبال کن", + "follow_topics_you_create": "جستارهایی که ایجاد کرده ای را دنبال کن", "grouptitle": "عنوان گروهی که میخواهید نشان داده شود را انتخاب کنید.", "no-group-title": "عنوان گروه ای نیست" } \ No newline at end of file diff --git a/public/language/fa_IR/users.json b/public/language/fa_IR/users.json index f3f510679f..cb506c48bf 100644 --- a/public/language/fa_IR/users.json +++ b/public/language/fa_IR/users.json @@ -9,13 +9,13 @@ "filter-by": "غربال با", "online-only": "فقط آنلاین", "picture-only": "عکس فقط", - "invite": "Invite", - "invitation-email-sent": "An invitation email has been sent to %1", - "user_list": "User List", - "recent_topics": "Recent Topics", - "popular_topics": "Popular Topics", - "unread_topics": "Unread Topics", - "categories": "Categories", - "tags": "Tags", - "map": "Map" + "invite": "دعوت", + "invitation-email-sent": "رایانامه ی دعوتنامه به %1 ارسال شد", + "user_list": "فهرست کاربران", + "recent_topics": "جستارهای اخیر", + "popular_topics": "جستارهای محبوب", + "unread_topics": "جستارهای خوانده نشده", + "categories": "دسته ها", + "tags": "برچسب‌ها", + "map": "نقشه" } \ No newline at end of file diff --git a/public/language/fr/email.json b/public/language/fr/email.json index 7cf94d58ca..6786d4dee8 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -1,15 +1,15 @@ { "password-reset-requested": "Demande de réinitialisation du mot de passe - %1!", "welcome-to": "Bienvenue sur %1", - "invite": "Invitation from %1", + "invite": "Invitation de %1", "greeting_no_name": "Bonjour", "greeting_with_name": "Bonjour %1", "welcome.text1": "Merci de vous être inscrit sur %1!", "welcome.text2": "Pour activer totalement votre compte, nous devons vérifier que vous êtes bien propriétaire de l'adresse email que vous avez utilisé pour vous inscrire.", - "welcome.text3": "An administrator has accepted your registration application. You can login with your username/password now.", + "welcome.text3": "Un administrateur a accepté votre demande d'inscription. Vous pouvez maintenant vous connecter avec vos identifiants/mots de passe.", "welcome.cta": "Cliquez ici pour confirmer votre adresse email", - "invitation.text1": "%1 has invited you to join %2", - "invitation.ctr": "Click here to create your account.", + "invitation.text1": "%1 vous a invité à joindre %2", + "invitation.ctr": "Cliquer ici pour créer votre compte.", "reset.text1": "Nous avons reçu une demande de réinitialisation de votre mot de passe, probablement parce que vous l'avez oublié. Si ce n'est pas le cas, veuillez ignorer cet email.", "reset.text2": "Pour confirmer la réinitialisation de votre mot de passe, veuillez cliquer sur le lien suivant :", "reset.cta": "Cliquez ici pour réinitialiser votre mot de passe", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 097fb131c5..ac1ac582aa 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -51,7 +51,7 @@ "already-favourited": "Vous avez déjà mis ce message en favoris", "already-unfavourited": "Vous avez déjà retiré ce message des favoris", "cant-ban-other-admins": "Vous ne pouvez pas bannir les autres administrateurs !", - "cant-remove-last-admin": "You are the only administrator. Add another user as an administrator before removing yourself as admin", + "cant-remove-last-admin": "Vous seul êtes administrateur. Ajouter un autre utilisateur en tant qu'administrateur avant de vous en retirer.", "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", @@ -60,8 +60,8 @@ "group-name-change-not-allowed": "Modification du nom de groupe non permise", "group-already-member": "Vous faites déjà parti de ce groupe", "group-needs-owner": "Ce groupe nécessite au moins un propriétaire", - "group-already-invited": "This user has already been invited", - "group-already-requested": "Your membership request has already been submitted", + "group-already-invited": "Cet utilisateur a déjà été invité.", + "group-already-requested": "Votre demande d'adhésion a déjà été envoyée.", "post-already-deleted": "Message déjà supprimé", "post-already-restored": "Message déjà restauré", "topic-already-deleted": "Sujet déjà supprimé", @@ -79,7 +79,7 @@ "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", "not-enough-reputation-to-downvote": "Vous n'avez pas une réputation assez élevée pour noter négativement ce message", "not-enough-reputation-to-flag": "Vous n'avez pas une réputation assez élevée pour signaler ce message", - "already-flagged": "You have already flagged this post", + "already-flagged": "Vous avez déjà signalé ce message", "reload-failed": "NodeBB a rencontré un problème lors du rechargement : \"% 1\" . NodeBB continuera de fonctionner côté client, même si vous devez annuler ce que vous avez fait juste avant de recharger .", "registration-error": "Erreur d'enregistrement", "parse-error": "Une erreur est survenue en analysant la réponse du serveur", diff --git a/public/language/fr/global.json b/public/language/fr/global.json index e95402cbe3..713ae56634 100644 --- a/public/language/fr/global.json +++ b/public/language/fr/global.json @@ -50,7 +50,7 @@ "views": "Vues", "reputation": "Réputation", "read_more": "En lire plus", - "more": "More", + "more": "Plus", "posted_ago_by_guest": "posté %1 par un invité", "posted_ago_by": "posté %1 par %2", "posted_ago": "posté %1", diff --git a/public/language/fr/groups.json b/public/language/fr/groups.json index 0f3e0a2e80..0315245c6b 100644 --- a/public/language/fr/groups.json +++ b/public/language/fr/groups.json @@ -6,12 +6,12 @@ "no_groups_found": "Il n'y a aucun groupe", "pending.accept": "Accepter", "pending.reject": "Refuser", - "pending.accept_all": "Accept All", - "pending.reject_all": "Reject All", - "pending.none": "There are no pending members at this time", - "invited.none": "There are no invited members at this time", - "invited.uninvite": "Rescind Invitation", - "invited.search": "Search for a user to invite to this group", + "pending.accept_all": "Tout accepter", + "pending.reject_all": "Tout rejeter", + "pending.none": "Il n'y a aucun membre en attente pour le moment", + "invited.none": "Il n'y a aucun membre invité pour le moment", + "invited.uninvite": "Résilier l'invitation", + "invited.search": "Chercher un utilisateur a inviter dans ce groupe", "cover-instructions": "Glissez-déposez une image, ajustez la position, et cliquez sur Enregistrer", "cover-change": "Modifier", "cover-save": "Enregistrer", @@ -19,7 +19,7 @@ "details.title": "Informations du groupe", "details.members": "Liste des membres", "details.pending": "Membres en attente", - "details.invited": "Invited Members", + "details.invited": "Inviter des Membres", "details.has_no_posts": "Les membres de ce groupe n'ont envoyé aucun message.", "details.latest_posts": "Derniers messages", "details.private": "Privé", diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json index 369fe4e07d..217f84ecc6 100644 --- a/public/language/fr/notifications.json +++ b/public/language/fr/notifications.json @@ -20,7 +20,7 @@ "user_posted_topic": "%1 a posté un nouveau sujet: %2.", "user_mentioned_you_in": "%1 vous a mentionné dans %2", "user_started_following_you": "%1 vous suit.", - "new_register": "%1 sent a registration request.", + "new_register": "%1 a envoyé une demande d'incription.", "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é.", diff --git a/public/language/fr/register.json b/public/language/fr/register.json index 6609813907..82a8eb27f5 100644 --- a/public/language/fr/register.json +++ b/public/language/fr/register.json @@ -15,5 +15,5 @@ "alternative_registration": "Autres méthodes d'inscription", "terms_of_use": "Conditions d'utilisation", "agree_to_terms_of_use": "J'accepte les Conditions d'utilisation", - "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." + "registration-added-to-queue": "Votre inscription a été ajoutée à la liste d'approbation. Vous recevrez un email quand celle-ci sera acceptée par un administrateur." } \ No newline at end of file diff --git a/public/language/fr/unread.json b/public/language/fr/unread.json index dcd639229e..9432bf9d36 100644 --- a/public/language/fr/unread.json +++ b/public/language/fr/unread.json @@ -5,6 +5,6 @@ "mark_as_read": "Marquer comme lu", "selected": "Sélectionnés", "all": "Tous", - "all_categories": "All categories", + "all_categories": "Toutes Catégories", "topics_marked_as_read.success": "Sujets marqués comme lus !" } \ No newline at end of file diff --git a/public/language/fr/user.json b/public/language/fr/user.json index 7900ad31ed..c4f02fb5a3 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -6,12 +6,12 @@ "postcount": "Nombre de messages", "email": "Email", "confirm_email": "Confirmer l'adresse email", - "ban_account": "Bannir un compte", + "ban_account": "Bannir", "ban_account_confirm": "Êtes-vous sûr de bien vouloir bannir cet utilisateur ?", - "unban_account": "Unban Account", + "unban_account": "Restaurer le Compte", "delete_account": "Supprimer le compte", "delete_account_confirm": "Êtes-vous sûr de vouloir supprimer votre compte?
Cette action est irréversible et vous ne serez pas en mesure de récupérer vos données

Entrez votre nom d'utilisateur pour confirmer que vous souhaitez détruire votre compte.", - "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

", + "delete_this_account_confirm": "Etes-vous sûr de vouloir supprimer ce compte?
Cette action est irréversible et vous ne pourrez récupérer aucune donnée.", "fullname": "Nom", "website": "Site web", "location": "Emplacement", @@ -68,9 +68,9 @@ "settings-require-reload": "Certains réglages nécessitent un rechargement. Cliquez ici pour recharger la page.", "has_no_follower": "Cet utilisateur n'est suivi par personne :(", "follows_no_one": "Cet utilisateur ne suit personne :(", - "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_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 n'a encore consulté aucun sujet.", "email_hidden": "Email masqué", "hidden": "masqué", "paginate_description": "Utiliser la pagination des sujets et des messages à la place du défilement infini.", diff --git a/public/language/fr/users.json b/public/language/fr/users.json index 9dc4a46887..fdcd16a1d8 100644 --- a/public/language/fr/users.json +++ b/public/language/fr/users.json @@ -9,13 +9,13 @@ "filter-by": "Filtrer par", "online-only": "En ligne uniquement", "picture-only": "Avec image uniquement", - "invite": "Invite", - "invitation-email-sent": "An invitation email has been sent to %1", - "user_list": "User List", - "recent_topics": "Recent Topics", - "popular_topics": "Popular Topics", - "unread_topics": "Unread Topics", - "categories": "Categories", - "tags": "Tags", - "map": "Map" + "invite": "Invitation", + "invitation-email-sent": "Un email d'invitation a été envoyé à %1", + "user_list": "Liste d'Utilisateurs", + "recent_topics": "Sujets Récents", + "popular_topics": "Sujets Populaires", + "unread_topics": "Sujets Non-Lus", + "categories": "Catégories", + "tags": "Mots-clés", + "map": "Carte" } \ No newline at end of file diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index 46d380380e..7e40b19b11 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -20,7 +20,7 @@ "user_posted_topic": "%1 ha postato un nuovo Topic: %2", "user_mentioned_you_in": "%1 ti ha menzionato in %2", "user_started_following_you": "%1 ha iniziato a seguirti.", - "new_register": "%1 sent a registration request.", + "new_register": "%1 ha inviato una richiesta di registrazione.", "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.", diff --git a/public/language/nl/category.json b/public/language/nl/category.json index 9070eb6ba4..7421cee928 100644 --- a/public/language/nl/category.json +++ b/public/language/nl/category.json @@ -2,7 +2,7 @@ "new_topic_button": "Nieuw onderwerp", "guest-login-post": "Log in om een reactie te plaatsen", "no_topics": "Er zijn geen onderwerpen in deze categorie.
Waarom maak je er niet een aan?", - "browsing": "verkennen", + "browsing": "browsing", "no_replies": "Niemand heeft gereageerd", "share_this_category": "Deel deze categorie", "watch": "Volgen", diff --git a/public/language/nl/email.json b/public/language/nl/email.json index d9541ffefa..c147fdaf92 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -1,15 +1,15 @@ { - "password-reset-requested": "Om wachtwoordherstel verzocht - %1!", + "password-reset-requested": "Wachtwoord reset gevraagd - %1!", "welcome-to": "Welkom bij %1", - "invite": "Invitation from %1", + "invite": "Uitnodiging van %1 ", "greeting_no_name": "Hallo", "greeting_with_name": "Hallo %1", "welcome.text1": "Bedank voor het registreren bij %1!", "welcome.text2": "Om de account volledig te activeren, dienen de instructies uit het bevestigingsbericht opgevolgd te worden. Controleer daarom nu eerst de e-mail inbox voor de activeringscode en volg de link in het bericht.", - "welcome.text3": "An administrator has accepted your registration application. You can login with your username/password now.", + "welcome.text3": "Een administrator heeft uw registratie geaccepteerd. U kan nu inloggen met uw gebruikersnaam en wachtwoord.", "welcome.cta": "Klik hier voor bevestigen van het e-mailadres", - "invitation.text1": "%1 has invited you to join %2", - "invitation.ctr": "Click here to create your account.", + "invitation.text1": "%1 heeft u uitgenodigd voor %2 ", + "invitation.ctr": "Klik hier om uw account aan te maken.", "reset.text1": "Wij ontvingen zojuist een verzoek om het wachtwoord van de account, bij onze website bekend als gekoppeld aan dit e-mailadres, te herstellen. Is dit verzoek niet bekend en geautoriseerd, dan kan dit bericht genegeerd worden.", "reset.text2": "Om het wachtwoord opnieuw in te stellen, klik op deze link:", "reset.cta": "Klik hier voor wachtwoordherstel", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 878ac8a5eb..0c9de298df 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -51,7 +51,7 @@ "already-favourited": "Dit bericht staat al tussen de favorieten", "already-unfavourited": "Dit bericht is al uit favorieten verwijderd", "cant-ban-other-admins": "Het is niet toegestaan andere beheerders te verbannen!", - "cant-remove-last-admin": "You are the only administrator. Add another user as an administrator before removing yourself as admin", + "cant-remove-last-admin": "U bent de enigen administrator. Voeg een andere gebruiker toe als administrator voordat u uw zelf verweiderd als admin", "invalid-image-type": "Ongeldig bestandstype afbeelding. Deze afbeelding is van een bestandstype dat niet ondersteund wordt. Toegestane bestandstypes voor afbeeldingsbestanden zijn: %1", "invalid-image-extension": "Ongeldige bestandstype afbeelding", "invalid-file-type": "Dit bestandstype wordt niet ondersteund. Toegestane bestandstypen zijn: %1", @@ -60,8 +60,8 @@ "group-name-change-not-allowed": "Het veranderen van de groepsnaam is niet toegestaan!", "group-already-member": "Groepslidmaatschap al aanwezig", "group-needs-owner": "De groep vereist ten minste 1 eigenaar", - "group-already-invited": "This user has already been invited", - "group-already-requested": "Your membership request has already been submitted", + "group-already-invited": "Deze gebruiker is all uitgenodigt ", + "group-already-requested": "Uw lidmaatschap aanvraag is all verstuurd", "post-already-deleted": "Dit bericht is al verwijderd", "post-already-restored": "Dit bericht is al hersteld", "topic-already-deleted": "Dit onderwerp is al verwijderd", @@ -79,7 +79,7 @@ "downvoting-disabled": "Negatief stemmen staat uitgeschakeld.", "not-enough-reputation-to-downvote": "Deze gebruikersaccount beschikt over onvoldoende reputatie om een negatieve stem uit te mogen brengen.", "not-enough-reputation-to-flag": "Onvoldoende reputatie om dit bericht aan beheerders te mogen melden.", - "already-flagged": "You have already flagged this post", + "already-flagged": "U heeft deze post all gerapporteerd ", "reload-failed": "Tijdens het herladen van \"%1\" is NodeBB een fout of probleem tegen gekomen. 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 iets misgegaan.", diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 08634a4785..a12b42d659 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -50,7 +50,7 @@ "views": "Gezien", "reputation": "Reputatie", "read_more": "Lees meer", - "more": "More", + "more": "Meer", "posted_ago_by_guest": "geplaatst %1 door gast", "posted_ago_by": "geplaatst %1 door %2", "posted_ago": "geplaatst door %1", diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json index c24ba75a44..ac39b79886 100644 --- a/public/language/nl/groups.json +++ b/public/language/nl/groups.json @@ -6,12 +6,12 @@ "no_groups_found": "Geen groepen voor weergave", "pending.accept": "Accepteer", "pending.reject": "Afwijzen", - "pending.accept_all": "Accept All", - "pending.reject_all": "Reject All", - "pending.none": "There are no pending members at this time", - "invited.none": "There are no invited members at this time", - "invited.uninvite": "Rescind Invitation", - "invited.search": "Search for a user to invite to this group", + "pending.accept_all": "Iedereen accepteren", + "pending.reject_all": "Iedereen afwijzen", + "pending.none": "Er zijn geen afwachtende leden op het moment", + "invited.none": "Er zijn geen uitgenodigde leden op het moment", + "invited.uninvite": "Uitnodiging intrekken", + "invited.search": "Zoek naar een gebruiker om uit te nodigen voor deze groep", "cover-instructions": "Sleep een afbeelding, sleep om te positioneren en klik tenslotte op Opslaan", "cover-change": "Bewerken", "cover-save": "Opslaan", @@ -19,22 +19,22 @@ "details.title": "Groepsdetails", "details.members": "Ledenlijst", "details.pending": "Nog niet geaccepteerde leden", - "details.invited": "Invited Members", + "details.invited": "Uitgenodigde leden", "details.has_no_posts": "Deze groepleden hebben nog geen berichten geplaatst", "details.latest_posts": "Meest recente berichten", "details.private": "Prive", "details.grant": "Toekennen/herroepen van eigendom", - "details.kick": "Schoppen", + "details.kick": "Kick", "details.owner_options": "Groepsadministratie", "details.group_name": "Groepsnaam", "details.member_count": "Ledentelling", "details.creation_date": "Aangemaakt op", "details.description": "Beschrijving", - "details.badge_preview": "Draaginsigne voorvertoning", + "details.badge_preview": "Badge Voorbeeld", "details.change_icon": "Wijzig icoon", "details.change_colour": "Wijzig kleur", - "details.badge_text": "Draaginsigne tekst", - "details.userTitleEnabled": "Draaginsignes weergeven", + "details.badge_text": "Badge Tekst", + "details.userTitleEnabled": "Badge Weergeven", "details.private_help": "Wanneer ingeschakeld, zal eerst een groepseigenaar goedkeuring moeten verlenen voordat nieuwe leden kunnen toetreden", "details.hidden": "Niet getoond", "details.hidden_help": "Indien geactiveerd zal deze groep niet getoond worden in de groepslijst en zullen gebruikers handmatig uitgenodigd moeten worden.", diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index 9f0fa6fdee..f813085261 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -20,7 +20,7 @@ "user_posted_topic": "%1 heeft een nieuw onderwerp geplaatst: %2", "user_mentioned_you_in": "Onze naam is genoemd door %1 in %2.", "user_started_following_you": "%1 volgt ons nu.", - "new_register": "%1 sent a registration request.", + "new_register": "%1 heeft een registratie verzoek aangevraagd.", "email-confirmed": "E-mailadres bevestigd", "email-confirmed-message": "Bedankt voor het bevestigen van het e-mailadres. Deze account is nu volledig geactiveerd.", "email-confirm-error-message": "Er was een probleem met het bevestigen van dit e-mailadres. Misschien is de code niet goed ingevoerd of was de beschikbare tijd inmiddels verstreken.", diff --git a/public/language/nl/recent.json b/public/language/nl/recent.json index 887a149da0..229a8c5e69 100644 --- a/public/language/nl/recent.json +++ b/public/language/nl/recent.json @@ -4,7 +4,7 @@ "week": "Week", "month": "Maand", "year": "Jaar", - "alltime": "Intussen", + "alltime": "altijd", "no_recent_topics": "Er zijn geen recente reacties.", "no_popular_topics": "Er zijn geen populaire onderwerpen.", "there-is-a-new-topic": "Er is een nieuw onderwerp", diff --git a/public/language/nl/register.json b/public/language/nl/register.json index 0f48f90c58..ed4b13a411 100644 --- a/public/language/nl/register.json +++ b/public/language/nl/register.json @@ -15,5 +15,5 @@ "alternative_registration": "Alternatieve Registratie", "terms_of_use": "Gebruiksvoorwaarden", "agree_to_terms_of_use": "Ik ga akkoord van de Gebruiksvoorwaarden", - "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." + "registration-added-to-queue": "Uw registratie is toegevoegd aan de wachtrij. U krijgt een email wanneer uw registratie is geaccepteerd " } \ No newline at end of file diff --git a/public/language/nl/search.json b/public/language/nl/search.json index 7b558be954..da9e793e8b 100644 --- a/public/language/nl/search.json +++ b/public/language/nl/search.json @@ -9,8 +9,8 @@ "in-categories": "In categorieën", "search-child-categories": "Doorzoek subcategorieën ", "reply-count": "Aantal reacties", - "at-least": "Minimaal", - "at-most": "Maximaal", + "at-least": "op zijn minst", + "at-most": "op zijn meest", "post-time": "Geplaatst op", "newer-than": "Nieuwer dan", "older-than": "Ouder dan", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index ab67cf9cb5..90ac37510d 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -27,15 +27,15 @@ "locked": "Gesloten", "bookmark_instructions": "Klik hier om naar de vorige positie terug te keren of sluit af om te verwerpen.", "flag_title": "Bericht aan beheerders melden", - "flag_confirm": "Is het echt de bedoeling dit bericht aan beheerders te rapporteren?", + "flag_confirm": "Weet u het zeker dat u dit bericht wilt rapporteren?", "flag_success": "Het bericht is gerapporteerd aan beheer.", "deleted_message": "Dit onderwerp is verwijderd. Alleen gebruikers met beheerrechten op onderwerpniveau kunnen dit inzien.", "following_topic.message": "Vanaf nu worden meldingen ontvangen zodra iemand een reactie op dit onderwerp geeft.", - "not_following_topic.message": "Er worden niet langer meldingen ontvangen over dit onderwerp.", - "login_to_subscribe": "Aanmelden om op dit onderwerp te abonneren", + "not_following_topic.message": "U ontvangt geen notificaties over dit onderwerp.", + "login_to_subscribe": "Log in or registreer om dit onderwerp te volgen.", "markAsUnreadForAll.success": "Onderwerp is voor iedereen als 'gelezen' gemarkeerd.", "watch": "Volgen", - "unwatch": "Niet volgen", + "unwatch": "Unfollow", "watch.title": "Krijg meldingen van nieuwe reacties op dit onderwerp", "unwatch.title": "Dit onderwerp niet langer volgen", "share_this_post": "Deel dit bericht", @@ -49,8 +49,8 @@ "thread_tools.move_all": "Verplaats alles", "thread_tools.fork": "Onderwerp afsplitsen", "thread_tools.delete": "Onderwerp verwijderen", - "thread_tools.delete_confirm": "Is het echt de bedoeling dit onderwerp te verwijderen?", - "thread_tools.restore": "Onderwerp erstellen", + "thread_tools.delete_confirm": "Weet u het zeker dat u dit onderwerp wilt verwijderen?", + "thread_tools.restore": "Onderwerp herstellen", "thread_tools.restore_confirm": "Zeker weten dit onderwerp te herstellen?", "thread_tools.purge": "Wis onderwerp ", "thread_tools.purge_confirm": "Is het echt de bedoeling dit onderwerp definitief te wissen?", @@ -59,7 +59,7 @@ "post_restore_confirm": "Is het de bedoeling dit bericht te herstellen?", "post_purge_confirm": "Is het absoluut zeker dat dit bericht volledig verwijderd kan worden?", "load_categories": "Categorieën laden", - "disabled_categories_note": "Uitgeschakelde categorieën zijn grijs", + "disabled_categories_note": "Uitgeschakelde Categorieën zijn grijs", "confirm_move": "Verplaatsen", "confirm_fork": "Splits", "favourite": "Favoriet", @@ -86,7 +86,7 @@ "composer.thumb_title": "Voeg een miniatuurweergave toe aan dit onderwerp", "composer.thumb_url_placeholder": "http://example.com/thumb.png", "composer.thumb_file_label": "Of upload een bestand", - "composer.thumb_remove": "Velden legen", + "composer.thumb_remove": "Velden leegmaken", "composer.drag_and_drop_images": "Sleep en zet afbeeldingen hier", "more_users_and_guests": "%1 of meerdere gebruiker(s) en %2 gast(en)", "more_users": "%1 meer gebruiker(s)", diff --git a/public/language/nl/unread.json b/public/language/nl/unread.json index 8b22d56289..3624cddce6 100644 --- a/public/language/nl/unread.json +++ b/public/language/nl/unread.json @@ -5,6 +5,6 @@ "mark_as_read": "Markeer als gelezen", "selected": "Geselecteerd", "all": "Alles", - "all_categories": "All categories", + "all_categories": "Alle categorieën", "topics_marked_as_read.success": "Onderwerp gemarkeerd als gelezen!" } \ No newline at end of file diff --git a/public/language/nl/user.json b/public/language/nl/user.json index 763318ca9f..60b7a9b279 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -6,12 +6,12 @@ "postcount": "Aantal geplaatste berichten", "email": "E-mail", "confirm_email": "Bevestig e-mail", - "ban_account": "Ban Account", - "ban_account_confirm": "Do you really want to ban this user?", + "ban_account": "Verban Account", + "ban_account_confirm": "Weet u zeker dat u deze gebruiker wilt verbannen", "unban_account": "Unban Account", "delete_account": "Account verwijderen", "delete_account_confirm": "Controleer of dat het zeker is dat deze account verwijderd moet worden.
Deze actie kan niet ongedaan gemaakt worden en herstellen van gebruiker- of profielgegevens is niet mogelijk

Typ hier de gebruikersnaam als extra controle om te bevestigen dat deze account verwijderd moet worden.", - "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

", + "delete_this_account_confirm": "Weet u zeker dat u deze account wilt verwijderen?
Deze actie kan niet ongedaan worden en u kunt niet de informatie herstellen

", "fullname": "Volledige naam", "website": "Website", "location": "Locatie", @@ -68,9 +68,9 @@ "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 :(", - "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_posts": "Deze gebruiker heeft nog geen berichten geplaatst", + "has_no_topics": "Deze gebruiker heeft nog geen onderwerpen gestart.", + "has_no_watched_topics": "Deze gebruiker heeft nog geen onderwerpen gevolgd.", "email_hidden": "E-mail niet beschikbaar", "hidden": "verborgen", "paginate_description": "Blader door onderwerpen en berichten in plaats van oneindig scrollen.", diff --git a/public/language/nl/users.json b/public/language/nl/users.json index df5cef0e25..275b0b4d5f 100644 --- a/public/language/nl/users.json +++ b/public/language/nl/users.json @@ -9,13 +9,13 @@ "filter-by": "Filter op", "online-only": "Online ", "picture-only": "Alleen een afbeelding", - "invite": "Invite", - "invitation-email-sent": "An invitation email has been sent to %1", - "user_list": "User List", - "recent_topics": "Recent Topics", - "popular_topics": "Popular Topics", - "unread_topics": "Unread Topics", - "categories": "Categories", + "invite": "Uitnodigen", + "invitation-email-sent": "Een uitnodiging email is verstuurd naar %1 ", + "user_list": "Ledenlijst", + "recent_topics": "Recente onderwerpen", + "popular_topics": "Populaire onderwerpen", + "unread_topics": "Ongelezen onderwerpen", + "categories": "Categorieën", "tags": "Tags", "map": "Map" } \ No newline at end of file diff --git a/public/language/zh_CN/category.json b/public/language/zh_CN/category.json index f28e696cc7..8024d249a1 100644 --- a/public/language/zh_CN/category.json +++ b/public/language/zh_CN/category.json @@ -5,8 +5,8 @@ "browsing": "正在浏览", "no_replies": "尚无回复", "share_this_category": "分享此版块", - "watch": "订阅", + "watch": "关注", "ignore": "忽略", - "watch.message": "您现在已经订阅了此版块", - "ignore.message": "您现在已经取消订阅了此版块" + "watch.message": "您现在已经关注了此版块", + "ignore.message": "您现在已经取消了此版块的关注" } \ No newline at end of file diff --git a/public/language/zh_CN/users.json b/public/language/zh_CN/users.json index b7b2e24acb..9a4c25724e 100644 --- a/public/language/zh_CN/users.json +++ b/public/language/zh_CN/users.json @@ -9,13 +9,13 @@ "filter-by": "过滤选项", "online-only": "只看在线", "picture-only": "只看图片", - "invite": "Invite", - "invitation-email-sent": "An invitation email has been sent to %1", - "user_list": "User List", - "recent_topics": "Recent Topics", - "popular_topics": "Popular Topics", - "unread_topics": "Unread Topics", - "categories": "Categories", - "tags": "Tags", - "map": "Map" + "invite": "邀请注册", + "invitation-email-sent": "已发送邀请给 %1", + "user_list": "会员列表", + "recent_topics": "最新主题", + "popular_topics": "热门主题", + "unread_topics": "未读主题", + "categories": "版面", + "tags": "话题", + "map": "地图" } \ No newline at end of file From 1a562677913a0b398c3c7380847e00eb6d2318bf Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 21 Jul 2015 11:37:58 -0400 Subject: [PATCH 5/5] updated dev version on master branch --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1be6ec4f3..67445720dd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "0.7.1-dev", + "version": "0.7.2-dev", "homepage": "http://www.nodebb.org", "repository": { "type": "git",