Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb2f857af2 | ||
|
|
7181bb4e1a | ||
|
|
d19e59f1e1 | ||
|
|
f5e8a40d79 | ||
|
|
4713e0d81a | ||
|
|
562b088423 | ||
|
|
92691782e6 | ||
|
|
fe582d8a7b | ||
|
|
98f2fd62a5 | ||
|
|
922620fe0a | ||
|
|
94b9d77118 | ||
|
|
b1b9174479 | ||
|
|
d5fb6dac38 | ||
|
|
deb9a9189d | ||
|
|
3309f2910d | ||
|
|
b600b9305e | ||
|
|
d120ee86cf | ||
|
|
f7ceace48f | ||
|
|
fbbd0deaea | ||
|
|
aabe1c3a16 | ||
|
|
94fb6b9823 | ||
|
|
d6af2ae13b | ||
|
|
4db89407c4 | ||
|
|
ef14511e24 | ||
|
|
37cdf9ce25 | ||
|
|
7454902678 | ||
|
|
d6a485a6cc | ||
|
|
301e62c3ba | ||
|
|
d6c2fc96f8 | ||
|
|
a9d69c4779 | ||
|
|
1cf07a6fc5 | ||
|
|
dfc8ceef9e | ||
|
|
b666261602 | ||
|
|
3c5d7f36b2 | ||
|
|
fda10ea194 | ||
|
|
9cc13aaf16 | ||
|
|
2dec354131 | ||
|
|
1fefc8d427 | ||
|
|
c3b6974779 | ||
|
|
fdd8514058 | ||
|
|
550fa4717d | ||
|
|
c0a4bf91f3 | ||
|
|
2cbdb886b1 | ||
|
|
ff70f36e1a | ||
|
|
60721ce75d | ||
|
|
296dc77c7b | ||
|
|
79cd9b1bcb | ||
|
|
a196c834d9 | ||
|
|
427500fc04 | ||
|
|
1a5b6d4839 | ||
|
|
61404be94b | ||
|
|
c40c64a9c5 | ||
|
|
b81e395a26 | ||
|
|
c12963593d | ||
|
|
1736b1c015 | ||
|
|
3d815fff72 | ||
|
|
f88b695d4c | ||
|
|
72940f7bdf | ||
|
|
ffc9da97e3 | ||
|
|
2be3054e94 | ||
|
|
fdf32a6ed4 | ||
|
|
19b3069ad0 | ||
|
|
5765313b63 | ||
|
|
cbbd254d33 | ||
|
|
8f8fcc8416 | ||
|
|
55b43dca23 | ||
|
|
c13aab39e7 | ||
|
|
072fa38927 | ||
|
|
0b35c81586 | ||
|
|
cc6d4f5d43 | ||
|
|
d9474d5de2 | ||
|
|
f6c60517db |
@@ -1,22 +1,8 @@
|
||||
# Save as .codeclimate.yml (note leading .) in project root directory
|
||||
version: "2"
|
||||
languages:
|
||||
Ruby: false
|
||||
Ruby: true
|
||||
JavaScript: true
|
||||
PHP: false
|
||||
checks:
|
||||
file-lines:
|
||||
config:
|
||||
threshold: 500
|
||||
method-lines:
|
||||
config:
|
||||
threshold: 50
|
||||
method-complexity:
|
||||
config:
|
||||
threshold: 10
|
||||
similar-code:
|
||||
config:
|
||||
threshold: 65
|
||||
PHP: true
|
||||
exclude_paths:
|
||||
- "public/vendor/*"
|
||||
- "test/*"
|
||||
@@ -17,5 +17,3 @@ logs/
|
||||
/coverage
|
||||
/build
|
||||
.eslintrc
|
||||
test/files
|
||||
*.min.js
|
||||
|
||||
13
.eslintrc
@@ -16,6 +16,7 @@
|
||||
}],
|
||||
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||
"no-underscore-dangle": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"no-console": "off",
|
||||
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
||||
"strict": ["error", "global"],
|
||||
@@ -31,16 +32,7 @@
|
||||
"no-prototype-builtins": "off",
|
||||
"new-cap": "off",
|
||||
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
||||
"object-curly-newline": "off",
|
||||
"no-restricted-globals": "off",
|
||||
"function-paren-newline": "off",
|
||||
"import/no-unresolved": "error",
|
||||
"quotes": ["error", "single", {
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}],
|
||||
"no-else-return": [ "error", { "allowElseIf": true } ],
|
||||
"operator-linebreak": [ "error", "after" ],
|
||||
|
||||
// ES6
|
||||
"prefer-rest-params": "off",
|
||||
@@ -50,7 +42,6 @@
|
||||
"no-var": "off",
|
||||
"object-shorthand": "off",
|
||||
"vars-on-top": "off",
|
||||
"prefer-destructuring": "off",
|
||||
|
||||
// TODO
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
@@ -63,9 +54,9 @@
|
||||
"no-restricted-syntax": "off",
|
||||
"no-script-url": "off",
|
||||
"default-case": "off",
|
||||
"linebreak-style": "off",
|
||||
|
||||
// "no-multi-assign": "off",
|
||||
// "linebreak-style": "off",
|
||||
// "one-var": "off",
|
||||
// "no-undef": "off",
|
||||
// "max-nested-callbacks": "off",
|
||||
|
||||
2
.github/CONTRIBUTING.md
vendored
@@ -15,7 +15,7 @@ If you are writing contributions as part of employment from another company / in
|
||||
|
||||
# Having problems installing NodeBB?
|
||||
|
||||
Chances are somebody has run into this problem before. After consulting our [documentation](https://docs.nodebb.org/installing/os/), please head over to our [community support forum](https://community.nodebb.org) for advice.
|
||||
Chances are somebody has run into this problem before. After consulting our [documentation](https://docs.nodebb.org/en/latest/installing/os.html), please head over to our [community support forum](https://community.nodebb.org) for advice.
|
||||
|
||||
# Found a Security Vulnerability?
|
||||
|
||||
|
||||
35
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,26 +1,13 @@
|
||||
<!--
|
||||
== Github Issues are for bug reports and feature requests only ==
|
||||
== Please visit https://community.nodebb.org for other support ==
|
||||
== Found a security exploit? Please email us at security@nodebb.org instead for immediate attention ==
|
||||
== → DO NOT SUBMIT VULNERABILITIES TO THE PUBLIC BUG TRACKER ==
|
||||
-->
|
||||
Please include the following information when submitting a bug report/issue:
|
||||
|
||||
<!-- ++ Please include the following information when submitting a bug report ++ -->
|
||||
* NodeBB version and git hash (to find your git hash, execute `git rev-parse HEAD` from the main NodeBB directory)
|
||||
* Database (mongo or redis) and it's version.
|
||||
* Exact steps to cause this issue
|
||||
1. First I did this...
|
||||
2. Then, I clicked on this item...
|
||||
* What you expected
|
||||
* e.g. I expected *abc* to *xyz*
|
||||
* What happened instead
|
||||
* e.g. Instead, I got *zyx* and NodeBB set fire to my house
|
||||
|
||||
- **NodeBB version:**
|
||||
- **NodeBB git hash:**
|
||||
<!-- (to find your git hash, execute `git rev-parse HEAD` from the main NodeBB directory) -->
|
||||
- **Database type:** mongo, redis, or postgres
|
||||
- **Database version:**
|
||||
<!-- `mongod --version`, `redis-server --version`, or `postgres --version` -->
|
||||
- **Exact steps to cause this issue:**
|
||||
<!--
|
||||
1. First I did this...
|
||||
2. Then, I clicked on this item...
|
||||
-->
|
||||
- **What you expected:**
|
||||
<!-- e.g. I expected *abc* to *xyz* -->
|
||||
- **What happened instead:**
|
||||
<!-- e.g. Instead, I got *zyx* and NodeBB set fire to my house -->
|
||||
|
||||
<!-- Thank you! -->
|
||||
Thank you!
|
||||
|
||||
10
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
yarn.lock
|
||||
npm-debug.log
|
||||
node_modules/
|
||||
sftp-config.json
|
||||
@@ -18,7 +17,6 @@ provision.sh
|
||||
.DS_Store
|
||||
feeds/recent.rss
|
||||
.eslintcache
|
||||
.svn
|
||||
|
||||
logs/
|
||||
|
||||
@@ -28,8 +26,6 @@ pidfile
|
||||
/public/templates
|
||||
|
||||
/public/sounds
|
||||
/public/uploads
|
||||
/test/uploads
|
||||
|
||||
# compiled files
|
||||
/public/stylesheet.css
|
||||
@@ -59,10 +55,6 @@ tx.exe
|
||||
|
||||
##Coverage output
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
build
|
||||
*.log
|
||||
test/files/normalise.jpg.png
|
||||
test/files/normalise-resized.jpg
|
||||
package-lock.json
|
||||
/package.json
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
"maxerr" : 50, // {int} Maximum error before stopping
|
||||
|
||||
"esversion": 6,
|
||||
|
||||
// Enforcing
|
||||
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
|
||||
"camelcase" : false, // true: Identifiers must be in camelCase
|
||||
|
||||
34
.travis.yml
@@ -1,37 +1,29 @@
|
||||
services:
|
||||
- mongodb
|
||||
- redis-server
|
||||
- postgresql
|
||||
before_install:
|
||||
- cp install/package.json package.json
|
||||
- "sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10"
|
||||
- "echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list"
|
||||
- "sudo apt-get update"
|
||||
- "sudo apt-get install mongodb-org-server"
|
||||
before_script:
|
||||
- sleep 15 # wait for mongodb to be ready
|
||||
- "mongo mydb_test --eval 'db.createUser({user:\"travis\", pwd: \"test\", roles: []});'"
|
||||
- sh -c "if [ '$DB' = 'mongodb' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"mongo\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"hAN3Eg8W\\\",\\\"admin:password:confirm\\\":\\\"hAN3Eg8W\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":27017,\\\"database\\\":0}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'redis' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567/forum\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"redis\\\",\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"hAN3Eg8W\\\",\\\"admin:password:confirm\\\":\\\"hAN3Eg8W\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":6379,\\\"database\\\":0}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'create database nodebb;' -U postgres; psql -c 'create database travis_ci_test;' -U postgres; node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"postgres\\\",\\\"postgres:host\\\":\\\"127.0.0.1\\\",\\\"postgres:port\\\":5432,\\\"postgres:password\\\":\\\"\\\",\\\"postgres:database\\\":\\\"nodebb\\\",\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"hAN3Eg8W\\\",\\\"admin:password:confirm\\\":\\\"hAN3Eg8W\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":5432,\\\"username\\\":\\\"postgres\\\",\\\"database\\\":\\\"travis_ci_test\\\"}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'mongodb' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"mongo\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":27017,\\\"database\\\":0}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'redis' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"redis\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":6379,\\\"database\\\":0}\"; fi"
|
||||
- "until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done"
|
||||
after_success:
|
||||
- "npm run coveralls"
|
||||
language: node_js
|
||||
sudo: false
|
||||
dist: trusty
|
||||
env:
|
||||
- CXX=g++-4.8 DB=mongodb TEST_ENV=production
|
||||
- CXX=g++-4.8 DB=mongodb TEST_ENV=development
|
||||
- CXX=g++-4.8 DB=redis TEST_ENV=production
|
||||
- CXX=g++-4.8 DB=postgres TEST_ENV=production
|
||||
- CXX=g++-4.8 DB=mongodb
|
||||
- CXX=g++-4.8 DB=redis
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- mongodb-3.4-trusty
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- mongodb-org-server
|
||||
postgresql: "9.5"
|
||||
- g++-4.8
|
||||
node_js:
|
||||
- "10"
|
||||
- "8"
|
||||
- "6"
|
||||
- "4"
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
812
.tx/config
177
CHANGELOG.md
@@ -1,177 +0,0 @@
|
||||
#### 1.11.0 (2018-12-14)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v1.11.1 (2104877c)
|
||||
* **deps:**
|
||||
* update dependency husky to v1.2.1 (63f4b569)
|
||||
* update node:8.14.0 docker digest to dd2381f (7449ae3e)
|
||||
* update node.js to v8.14.0 (8a5a031d)
|
||||
|
||||
##### New Features
|
||||
|
||||
* Allow getting logfile path from config (#7044) (f3e8e065)
|
||||
* remove uid:<uid>:ignored:cids (#7099) (263c9180)
|
||||
* cache category tag whitelist (78fa7340)
|
||||
* make user cards look less derpy (31bb2ae9)
|
||||
* added new middleware authenticateOrGuest (4fba1492)
|
||||
* closes #7070 (7ca62b83)
|
||||
* added README.md in languages folder (648964fa)
|
||||
* up composer (7eee8e1d)
|
||||
* allow array results (54c127d1)
|
||||
* #7023 (f581c052)
|
||||
* close #7002, console message if mismatched origins (89c025d1)
|
||||
* added changelog file to root of repo (e89b4fca)
|
||||
* **email:** don't escape html in notification bodies. (#7042) (d7c55bc3)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #7108 (81697390)
|
||||
* dont save data for non-positive uids (62f01a83)
|
||||
* #7103 (f103390a)
|
||||
* dont update cid:<cid>:tids:votes if topic is pinned (2f57a4b9)
|
||||
* #7102 (d117df77)
|
||||
* #7102 (85a07e99)
|
||||
* don't explode if there is no css el (74d0e88d)
|
||||
* db info page (26ccd8f6)
|
||||
* logAttempt conditional (a6c8e0ab)
|
||||
* #7087, server-side protection against guest blocks (33d4956b)
|
||||
* don't crash in flags.validate if user blocked target (81aa3a0b)
|
||||
* dont send empty strings (555c092f)
|
||||
* #7085 (fe0f95a2)
|
||||
* #7086 (e55fb437)
|
||||
* wrong variable #7085 (71163421)
|
||||
* admins&mods when there are mutliple lines of users (de437e36)
|
||||
* refreshing settings page on save if language changed (ed46c5e2)
|
||||
* not calling authenticate middleware on resource direct access routes (eeaee8cc)
|
||||
* #7038, autoLocale logic not playing nicely with no-refresh auths (#7059) (5f3d1c76)
|
||||
* #7074 (2604cf63)
|
||||
* #7071 buildSkinAsset won't rebuild continuously (a07d9898)
|
||||
* #7063, logout code should do hard page nav to / or data.next (6df5668e)
|
||||
* #7061 (eab297bd)
|
||||
* skin not changing after login or logout, #7038 (28a1fa78)
|
||||
* #7040 (a63ddbe2)
|
||||
* #7041 (ec0c50d4)
|
||||
* #7043 (8d7c3897)
|
||||
* add missing render function (cb7c2d8c)
|
||||
* #7033 (8808a033)
|
||||
* #7037 (b86f1556)
|
||||
* #6991, add timeout for version Github request (43c3bb02)
|
||||
* #7030 (58d4376f)
|
||||
* **deps:**
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.17 (3bcfd7fc)
|
||||
* update dependency nodebb-theme-persona to v9.1.4 (b6ad5fd4)
|
||||
* update dependency nodebb-plugin-markdown to v8.8.6 (#7079) (46fb365d)
|
||||
* update dependency nodebb-theme-persona to v9.1.3 (#7075) (d2aea57a)
|
||||
* update dependency nodebb-theme-persona to v9.1.2 (42e792ab)
|
||||
* update dependency nodebb-theme-persona to v9.1.1 (#7069) (bdb33056)
|
||||
* update dependency postcss to v7.0.6 (6b5428c5)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.14 (#7058) (e48ed6e0)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.13 (#7057) (ada1d6d0)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.12 (#7056) (9f9f72da)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.11 (#7055) (89acb896)
|
||||
* update dependency nodebb-theme-slick to v1.2.18 (#7049) (b6cb77c1)
|
||||
* update dependency nodebb-theme-slick to v1.2.17 (#7048) (7334c45b)
|
||||
* update dependency nodebb-theme-slick to v1.2.16 (#7047) (1cb1af0c)
|
||||
* update dependency connect-mongo to v2.0.3 (#7046) (d0d0c7f0)
|
||||
* update dependency nodebb-plugin-dbsearch to v3.0.3 (#7035) (adb1b5f3)
|
||||
* update dependency lru-cache to v4.1.5 (#7031) (887582eb)
|
||||
* update dependency socket.io to v2.2.0 (b9d49867)
|
||||
* update dependency socket.io-client to v2.2.0 (824bd541)
|
||||
* update dependency nodebb-plugin-dbsearch to v3.0.2 (#7028) (11f1b409)
|
||||
* update dependency nodebb-plugin-dbsearch to v3.0.1 (#7027) (e71f443c)
|
||||
* **i18n:** pushed notifications source to tx, pulled fallbacks (8dd8370b)
|
||||
|
||||
##### Code Style Changes
|
||||
|
||||
* **eslint:** match operator-linebreak preferences (ba619c7e)
|
||||
|
||||
### 1.11.0 (2018-11-28)
|
||||
|
||||
##### Chores
|
||||
|
||||
* **deps:**
|
||||
* update dependency lint-staged to v8.1.0 (dd7f8a14)
|
||||
* update dependency husky to v1.2.0 (aee21628)
|
||||
* update node:8.12.0 docker digest to 5dae8ea (0ef451dd)
|
||||
* update dependency husky to v1.1.4 (95d6ab06)
|
||||
* update dependency eslint to v5.9.0 (92441794)
|
||||
* pin dependencies (b0483f21)
|
||||
* update dependency eslint-config-airbnb-base to v13 (#6599) (64b9dabf)
|
||||
* update node.js to v8.12.0 (fa3afbd2)
|
||||
* update dependency husky to v1.1.3 (6cee5b8e)
|
||||
* update dependency lint-staged to v8.0.4 (9d258668)
|
||||
* update dependency lint-staged to v8.0.3 (aaa6fe9e)
|
||||
* update dependency lint-staged to v8 (95d7a5fa)
|
||||
* update dependency jsdom to v13 (52f141c9)
|
||||
* **husky:** setting up husky as recommended in docs (e8a3d929)
|
||||
|
||||
##### New Features
|
||||
|
||||
* enabling commitlint (c58a41ed)
|
||||
* allow disabling of GDPR features via ACP toggle, closes #6847 (4919e9ef)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* **deps:**
|
||||
* update dependency nodebb-theme-vanilla to v10.1.12 (cf928f44)
|
||||
* update dependency nodebb-theme-persona to v9.1.0 (179be9ed)
|
||||
* update dependency nodebb-theme-persona to v9.0.63 (#7019) (68ae3eb6)
|
||||
* update dependency nodebb-plugin-markdown to v8.8.5 (d3ab7d1b)
|
||||
* update dependency nodebb-theme-persona to v9.0.60 (#6984) (cbd50a80)
|
||||
* update dependency nodebb-theme-vanilla to v10.1.10 (#6982) (4c769487)
|
||||
* update dependency nodebb-theme-slick to v1.2.15 (#6981) (acaf1a05)
|
||||
* update dependency nodebb-theme-persona to v9.0.59 (#6980) (5863bb2c)
|
||||
* update dependency lru-cache to v4.1.4 (#6977) (375ab769)
|
||||
* update dependency connect-mongo to v2.0.2 (#6975) (e1597b83)
|
||||
* update dependency nodebb-plugin-markdown to v8.8.4 (84d1013d)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.8 (fee7e336)
|
||||
* update dependency nodebb-plugin-markdown to v8.8.3 (b182a195)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.7 (#6966) (1101f327)
|
||||
* update dependency nodebb-theme-persona to v9.0.58 (#6964) (6ade156b)
|
||||
* update dependency mongodb to v3.1.10 (#6962) (662215fa)
|
||||
* update dependency nodebb-theme-persona to v9.0.57 (#6956) (1bf1a439)
|
||||
* update dependency nodebb-theme-persona to v9.0.55 (#6955) (e06683f7)
|
||||
* update dependency nodebb-plugin-composer-default to v6.1.6 (c51ceaf0)
|
||||
* update dependency nodebb-theme-persona to v9.0.54 (bb940b01)
|
||||
* update dependency nodebb-plugin-mentions to v2.2.12 (#6936) (e12a803b)
|
||||
* update dependency nodebb-theme-vanilla to v10.1.9 (#6935) (b480c321)
|
||||
* update dependency nodebb-theme-slick to v1.2.14 (#6934) (9cdd5316)
|
||||
* update dependency nodebb-theme-persona to v9.0.53 (#6933) (9ee1c2f8)
|
||||
* update dependency nodebb-plugin-dbsearch to v2.0.23 (#6931) (dba1db9c)
|
||||
* update dependency jsesc to v2.5.2 (511b4edc)
|
||||
* update dependency validator to v10.9.0 (032caafa)
|
||||
* update dependency spdx-license-list to v5 (a639b6b8)
|
||||
* update dependency nodebb-theme-vanilla to v10.1.8 (eb0a322d)
|
||||
* update dependency nodebb-theme-persona to v9.0.52 (6566a0cb)
|
||||
* update dependency nodebb-plugin-dbsearch to v2.0.22 (#6916) (7808e58c)
|
||||
* update dependency mongodb to v3.1.9 (#6914) (9a9f2af9)
|
||||
* update dependency nodebb-theme-persona to v9.0.51 (e2274fe0)
|
||||
* update dependency nodebb-theme-slick to v1.2.13 (3005428d)
|
||||
* update dependency nodebb-theme-persona to v9.0.50 (#6902) (22140a20)
|
||||
* update dependency nodebb-plugin-markdown to v8.8.2 (0b4c9a80)
|
||||
* update dependency nodebb-theme-vanilla to v10.1.7 (3150a2fc)
|
||||
* update dependency nodebb-theme-slick to v1.2.12 (#6881) (9bcda7f7)
|
||||
* update dependency nodebb-theme-persona to v9.0.49 (#6880) (e0dc00da)
|
||||
* update dependency nodebb-theme-persona to v9.0.48 (2b6f5eec)
|
||||
* added admin/manage/uploads to tx config (7357926f)
|
||||
* #7013, add cache buster to js-enabled.css (f6b92c1d)
|
||||
* removal of scroll anchoring code in favour of browser handling (98c14e0e)
|
||||
* custom navigation item not showing groups (d9452bf3)
|
||||
* flags detail page crash if reporter blocks author (d027207f)
|
||||
* #6922, skin assets not including plugin LESS files (a5022ce4)
|
||||
* #6921, allow square brackets in usernames (da10ca08)
|
||||
* interstitial redirects failing if done via ajaxify (3c8939a8)
|
||||
* username trim on login, closes #6894 (157bea69)
|
||||
* **uploads:** ugly filenames on uploaded asset downloading (f96208a0)
|
||||
* **acp:**
|
||||
* small UI fixes for ACP privileges category selector (#6946) (57b39d5b)
|
||||
* hard-to-discover dropdown selector in ACP (b3f96d28)
|
||||
* **l10n:** some translations (34cbd1fc)
|
||||
|
||||
##### Code Style Changes
|
||||
|
||||
* **eslint:**
|
||||
* newlines in public/src as well (f7bd398e)
|
||||
* enforcing newline on chained calls (95cc27f1)
|
||||
|
||||
21
Dockerfile
@@ -1,20 +1,15 @@
|
||||
# The base image is the latest 8.x node (LTS)
|
||||
FROM node:8.15.0@sha256:cb66110c9c7d84bae9a6db8675f49d5c9e34d528023ef185b186e29ae5461051
|
||||
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ARG NODE_ENV
|
||||
ENV NODE_ENV $NODE_ENV
|
||||
COPY install/package.json /usr/src/app/package.json
|
||||
RUN npm install && npm cache clean --force
|
||||
COPY . /usr/src/app
|
||||
# The base image is the latest 4.x node (LTS) on jessie (debian)
|
||||
# -onbuild will install the node dependencies found in the project package.json
|
||||
# and copy its content in /usr/src/app, its WORKDIR
|
||||
FROM node:4-onbuild
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
daemon=false \
|
||||
silent=false
|
||||
|
||||
CMD ./nodebb start
|
||||
# nodebb setup will ask you for connection information to a redis (default), mongodb then run the forum
|
||||
# nodebb upgrade is not included and might be desired
|
||||
CMD node app --setup && npm start
|
||||
|
||||
# the default port for NodeBB is exposed outside the container
|
||||
EXPOSE 4567
|
||||
EXPOSE 4567
|
||||
|
||||
24
Gruntfile.js
@@ -8,8 +8,6 @@ var initWorker;
|
||||
var incomplete = [];
|
||||
var running = 0;
|
||||
|
||||
env.NODE_ENV = env.NODE_ENV || 'development';
|
||||
|
||||
module.exports = function (grunt) {
|
||||
var args = [];
|
||||
var initArgs = ['--build'];
|
||||
@@ -20,7 +18,7 @@ module.exports = function (grunt) {
|
||||
|
||||
function update(action, filepath, target) {
|
||||
var updateArgs = args.slice();
|
||||
var compiling;
|
||||
var compiling = '';
|
||||
var time = Date.now();
|
||||
|
||||
if (target === 'lessUpdated_Client') {
|
||||
@@ -37,7 +35,7 @@ module.exports = function (grunt) {
|
||||
// Do nothing, just restart
|
||||
}
|
||||
|
||||
if (compiling && !incomplete.includes(compiling)) {
|
||||
if (incomplete.indexOf(compiling) === -1) {
|
||||
incomplete.push(compiling);
|
||||
}
|
||||
|
||||
@@ -73,9 +71,8 @@ module.exports = function (grunt) {
|
||||
watch: {
|
||||
lessUpdated_Client: {
|
||||
files: [
|
||||
'public/less/*.less',
|
||||
'!public/less/admin/**/*.less',
|
||||
'node_modules/nodebb-*/**/*.less',
|
||||
'public/*.less',
|
||||
'node_modules/nodebb-*/*.less', 'node_modules/nodebb-*/**/*.less',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
@@ -84,12 +81,7 @@ module.exports = function (grunt) {
|
||||
},
|
||||
},
|
||||
lessUpdated_Admin: {
|
||||
files: [
|
||||
'public/less/admin/**/*.less',
|
||||
'node_modules/nodebb-*/**/*.less',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
files: ['public/**/*.less'],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
@@ -97,9 +89,9 @@ module.exports = function (grunt) {
|
||||
clientUpdated: {
|
||||
files: [
|
||||
'public/src/**/*.js',
|
||||
'node_modules/nodebb-*/**/*.js',
|
||||
'node_modules/nodebb-*/*.js', 'node_modules/nodebb-*/**/*.js',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'node_modules/benchpressjs/build/benchpress.js',
|
||||
'node_modules/templates.js/lib/templates.js',
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
options: {
|
||||
@@ -115,7 +107,7 @@ module.exports = function (grunt) {
|
||||
templatesUpdated: {
|
||||
files: [
|
||||
'src/views/**/*.tpl',
|
||||
'node_modules/nodebb-*/**/*.tpl',
|
||||
'node_modules/nodebb-*/*.tpl', 'node_modules/nodebb-*/**/*.tpl',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
|
||||
12
README.md
@@ -1,9 +1,11 @@
|
||||
# <img alt="NodeBB" src="http://i.imgur.com/mYxPPtB.png" />
|
||||
|
||||
[](https://gitter.im/NodeBB/NodeBB?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/NodeBB/NodeBB)
|
||||
[](https://coveralls.io/github/NodeBB/NodeBB?branch=master)
|
||||
[](https://david-dm.org/nodebb/nodebb?path=install)
|
||||
[](https://david-dm.org/nodebb/nodebb)
|
||||
[](https://codeclimate.com/github/NodeBB/NodeBB)
|
||||
[](https://readthedocs.org/projects/nodebb/?badge=latest)
|
||||
|
||||
[**NodeBB Forum Software**](https://nodebb.org) 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 has many modern features out of the box such as social network integration and streaming discussions, while still making sure to be compatible with older browsers.
|
||||
|
||||
@@ -40,7 +42,7 @@ Our minimalist "Persona" theme gets you going right away, no coding experience r
|
||||
## How can I follow along/contribute?
|
||||
|
||||
* 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 extension 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 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.
|
||||
|
||||
@@ -48,13 +50,13 @@ Our minimalist "Persona" theme gets you going right away, no coding experience r
|
||||
|
||||
NodeBB requires the following software to be installed:
|
||||
|
||||
* A version of Node.js at least 6 or greater ([installation/upgrade instructions](https://github.com/nodesource/distributions))
|
||||
* A version of Node.js at least 4 or greater ([installation/upgrade instructions](https://github.com/nodesource/distributions))
|
||||
* 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](https://docs.nodebb.org/installing/os)
|
||||
[Please refer to platform-specific installation documentation](http://docs.nodebb.org/en/latest/installing/os.html)
|
||||
|
||||
## Securing NodeBB
|
||||
|
||||
@@ -69,7 +71,7 @@ It is important to ensure that your NodeBB and database servers are secured. Bea
|
||||
|
||||
## Upgrading NodeBB
|
||||
|
||||
Detailed upgrade instructions are listed in [Upgrading NodeBB](https://docs.nodebb.org/configuring/upgrade/)
|
||||
Detailed upgrade instructions are listed in [Upgrading NodeBB](https://docs.nodebb.org/en/latest/upgrading/index.html)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
250
app.js
@@ -19,31 +19,48 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
require('./require-main');
|
||||
if (require.main !== module) {
|
||||
require.main.require = function (path) {
|
||||
return require(path);
|
||||
};
|
||||
}
|
||||
|
||||
var nconf = require('nconf');
|
||||
nconf.argv().env({
|
||||
separator: '__',
|
||||
});
|
||||
nconf.argv().env('__');
|
||||
|
||||
var url = require('url');
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
var path = require('path');
|
||||
|
||||
var pkg = require('./package.json');
|
||||
var file = require('./src/file');
|
||||
|
||||
global.env = process.env.NODE_ENV || 'production';
|
||||
|
||||
winston.remove(winston.transports.Console);
|
||||
winston.add(winston.transports.Console, {
|
||||
colorize: true,
|
||||
timestamp: function () {
|
||||
var date = new Date();
|
||||
return nconf.get('json-logging') ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 8) + ' [' + global.process.pid + ']';
|
||||
},
|
||||
level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'),
|
||||
json: (!!nconf.get('json-logging')),
|
||||
stringify: (!!nconf.get('json-logging')),
|
||||
});
|
||||
|
||||
|
||||
// Alternate configuration file support
|
||||
var configFile = path.resolve(__dirname, nconf.any(['config', 'CONFIG']) || 'config.json');
|
||||
var configFile = path.join(__dirname, '/config.json');
|
||||
|
||||
if (nconf.get('config')) {
|
||||
configFile = path.resolve(__dirname, nconf.get('config'));
|
||||
}
|
||||
|
||||
var configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));
|
||||
|
||||
var prestart = require('./src/prestart');
|
||||
prestart.loadConfig(configFile);
|
||||
prestart.setupWinston();
|
||||
prestart.versionCheck();
|
||||
winston.verbose('* using configuration stored in: %s', configFile);
|
||||
loadConfig();
|
||||
versionCheck();
|
||||
|
||||
if (!process.send) {
|
||||
// If run using `node app`, log GNU copyright info along with server info
|
||||
@@ -53,39 +70,206 @@ if (!process.send) {
|
||||
winston.info('');
|
||||
}
|
||||
|
||||
|
||||
if (nconf.get('setup') || nconf.get('install')) {
|
||||
require('./src/cli/setup').setup();
|
||||
setup();
|
||||
} else if (!configExists) {
|
||||
require('./install/web').install(nconf.get('port'));
|
||||
} else if (nconf.get('upgrade')) {
|
||||
require('./src/cli/upgrade').upgrade(true);
|
||||
upgrade();
|
||||
} else if (nconf.get('reset')) {
|
||||
var options = {
|
||||
theme: nconf.get('t'),
|
||||
plugin: nconf.get('p'),
|
||||
widgets: nconf.get('w'),
|
||||
settings: nconf.get('s'),
|
||||
all: nconf.get('a'),
|
||||
};
|
||||
|
||||
async.series([
|
||||
async.apply(require('./src/cli/reset').reset, options),
|
||||
require('./src/meta/build').buildAll,
|
||||
async.waterfall([
|
||||
async.apply(require('./src/reset').reset),
|
||||
async.apply(require('./src/meta/build').buildAll),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
process.exit(err ? 1 : 0);
|
||||
});
|
||||
} else if (nconf.get('activate')) {
|
||||
require('./src/cli/manage').activate(nconf.get('activate'));
|
||||
activate();
|
||||
} else if (nconf.get('plugins')) {
|
||||
require('./src/cli/manage').listPlugins();
|
||||
listPlugins();
|
||||
} else if (nconf.get('build')) {
|
||||
require('./src/meta/build').build(nconf.get('build'));
|
||||
} else if (nconf.get('events')) {
|
||||
require('./src/cli/manage').listEvents();
|
||||
} else {
|
||||
require('./src/start').start();
|
||||
}
|
||||
|
||||
function loadConfig(callback) {
|
||||
winston.verbose('* using configuration stored in: %s', configFile);
|
||||
|
||||
nconf.file({
|
||||
file: configFile,
|
||||
});
|
||||
|
||||
nconf.defaults({
|
||||
base_dir: __dirname,
|
||||
themes_path: path.join(__dirname, 'node_modules'),
|
||||
upload_path: 'public/uploads',
|
||||
views_dir: path.join(__dirname, 'build/public/templates'),
|
||||
version: pkg.version,
|
||||
});
|
||||
|
||||
if (!nconf.get('isCluster')) {
|
||||
nconf.set('isPrimary', 'true');
|
||||
nconf.set('isCluster', 'false');
|
||||
}
|
||||
|
||||
// Ensure themes_path is a full filepath
|
||||
nconf.set('themes_path', path.resolve(__dirname, nconf.get('themes_path')));
|
||||
nconf.set('core_templates_path', path.join(__dirname, 'src/views'));
|
||||
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
|
||||
|
||||
nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path')));
|
||||
|
||||
if (nconf.get('url')) {
|
||||
nconf.set('url_parsed', url.parse(nconf.get('url')));
|
||||
}
|
||||
|
||||
// Explicitly cast 'jobsDisabled' as Bool
|
||||
var castAsBool = ['jobsDisabled'];
|
||||
nconf.stores.env.readOnly = false;
|
||||
castAsBool.forEach(function (prop) {
|
||||
var value = nconf.get(prop);
|
||||
if (value) {
|
||||
nconf.set(prop, typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true');
|
||||
}
|
||||
});
|
||||
nconf.stores.env.readOnly = true;
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
function setup() {
|
||||
winston.info('NodeBB Setup Triggered via Command Line');
|
||||
|
||||
var install = require('./src/install');
|
||||
var build = require('./src/meta/build');
|
||||
|
||||
process.stdout.write('\nWelcome to NodeBB!\n');
|
||||
process.stdout.write('\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.\n');
|
||||
process.stdout.write('Press enter to accept the default setting (shown in brackets).\n');
|
||||
|
||||
async.series([
|
||||
async.apply(install.setup),
|
||||
async.apply(loadConfig),
|
||||
async.apply(build.buildAll),
|
||||
], function (err, data) {
|
||||
// Disregard build step data
|
||||
data = data[0];
|
||||
|
||||
var separator = ' ';
|
||||
if (process.stdout.columns > 10) {
|
||||
for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) {
|
||||
separator += '=';
|
||||
}
|
||||
}
|
||||
process.stdout.write('\n' + separator + '\n\n');
|
||||
|
||||
if (err) {
|
||||
winston.error('There was a problem completing NodeBB setup: ', err.message);
|
||||
} else {
|
||||
if (data.hasOwnProperty('password')) {
|
||||
process.stdout.write('An administrative user was automatically created for you:\n');
|
||||
process.stdout.write(' Username: ' + data.username + '\n');
|
||||
process.stdout.write(' Password: ' + data.password + '\n');
|
||||
process.stdout.write('\n');
|
||||
}
|
||||
process.stdout.write('NodeBB Setup Completed. Run \'./nodebb start\' to manually start your NodeBB server.\n');
|
||||
|
||||
// If I am a child process, notify the parent of the returned data before exiting (useful for notifying
|
||||
// hosts of auto-generated username/password during headless setups)
|
||||
if (process.send) {
|
||||
process.send(data);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
function upgrade() {
|
||||
var db = require('./src/database');
|
||||
var meta = require('./src/meta');
|
||||
var upgrade = require('./src/upgrade');
|
||||
var build = require('./src/meta/build');
|
||||
|
||||
async.series([
|
||||
async.apply(db.init),
|
||||
async.apply(meta.configs.init),
|
||||
async.apply(upgrade.upgrade),
|
||||
async.apply(build.buildAll),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function activate() {
|
||||
var db = require('./src/database');
|
||||
var plugins = require('./src/plugins');
|
||||
var plugin = nconf.get('activate');
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.init(next);
|
||||
},
|
||||
function (next) {
|
||||
if (plugin.indexOf('nodebb-') !== 0) {
|
||||
// Allow omission of `nodebb-plugin-`
|
||||
plugin = 'nodebb-plugin-' + plugin;
|
||||
}
|
||||
plugins.isInstalled(plugin, next);
|
||||
},
|
||||
function (isInstalled, next) {
|
||||
if (!isInstalled) {
|
||||
return next(new Error('plugin not installed'));
|
||||
}
|
||||
|
||||
winston.info('Activating plugin `%s`', plugin);
|
||||
db.sortedSetAdd('plugins:active', 0, plugin, next);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error(err.message);
|
||||
}
|
||||
process.exit(err ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
function listPlugins() {
|
||||
require('./src/database').init(function (err) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var db = require('./src/database');
|
||||
|
||||
db.getSortedSetRange('plugins:active', 0, -1, function (err, plugins) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
winston.info('Active plugins: \n\t - ' + plugins.join('\n\t - '));
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function versionCheck() {
|
||||
var version = process.version.slice(1);
|
||||
var range = pkg.engines.node;
|
||||
var semver = require('semver');
|
||||
var compatible = semver.satisfies(version, range);
|
||||
|
||||
if (!compatible) {
|
||||
winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.');
|
||||
winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset);
|
||||
}
|
||||
}
|
||||
|
||||
4
build/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
*
|
||||
*/
|
||||
!export
|
||||
!.gitignore
|
||||
3
build/export/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
.
|
||||
!.gitignore
|
||||
!README
|
||||
@@ -1,5 +0,0 @@
|
||||
This directory contains archives of user uploads that are prepared on-demand
|
||||
when a user wants to retrieve a copy of their uploaded content.
|
||||
|
||||
You can delete the files in here at will. They will just be regenerated if
|
||||
requested again.
|
||||
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = { extends: ['@commitlint/config-angular'] };
|
||||
@@ -1,23 +1,9 @@
|
||||
{
|
||||
"title": "NodeBB",
|
||||
"showSiteTitle": 1,
|
||||
"defaultLang": "en-GB",
|
||||
"loginDays": 14,
|
||||
"loginSeconds": 0,
|
||||
"loginAttempts": 5,
|
||||
"lockoutDuration": 60,
|
||||
"adminReloginDuration": 60,
|
||||
"postDelay": 10,
|
||||
"initialPostDelay": 10,
|
||||
"newbiePostDelay": 120,
|
||||
"postEditDuration": 0,
|
||||
"postDeleteDuration": 0,
|
||||
"enablePostHistory": 1,
|
||||
"postCacheSize": 10485760,
|
||||
"disableChat": 0,
|
||||
"chatEditDuration": 0,
|
||||
"chatDeleteDuration": 0,
|
||||
"chatMessageDelay": 200,
|
||||
"newbiePostDelayThreshold": 3,
|
||||
"minimumPostLength": 8,
|
||||
"maximumPostLength": 32767,
|
||||
@@ -25,97 +11,29 @@
|
||||
"maximumTagsPerTopic": 5,
|
||||
"minimumTagLength": 3,
|
||||
"maximumTagLength": 15,
|
||||
"allowGuestSearching": 0,
|
||||
"allowTopicsThumbnail": 0,
|
||||
"registrationType": "normal",
|
||||
"allowLocalLogin": 1,
|
||||
"allowAccountDelete": 1,
|
||||
"allowFileUploads": 0,
|
||||
"allowedFileExtensions": "png,jpg,bmp",
|
||||
"allowUserHomePage": 1,
|
||||
"allowMultipleBadges": 0,
|
||||
"maximumFileSize": 2048,
|
||||
"resizeImageWidthThreshold": 2000,
|
||||
"resizeImageWidth": 760,
|
||||
"rejectImageWidth": 5000,
|
||||
"rejectImageHeight": 5000,
|
||||
"resizeImageQuality": 80,
|
||||
"topicThumbSize": 120,
|
||||
"minimumTitleLength": 3,
|
||||
"maximumTitleLength": 255,
|
||||
"minimumUsernameLength": 2,
|
||||
"maximumUsernameLength": 16,
|
||||
"minimumPasswordLength": 6,
|
||||
"minimumPasswordStrength": 1,
|
||||
"maximumSignatureLength": 255,
|
||||
"maximumAboutMeLength": 1000,
|
||||
"maximumUsersInChatRoom": 0,
|
||||
"maximumChatMessageLength": 1000,
|
||||
"maximumProfileImageSize": 256,
|
||||
"maximumCoverImageSize": 2048,
|
||||
"profileImageDimension": 200,
|
||||
"profile:convertProfileImageToPNG": 0,
|
||||
"profile:keepAllUserImages": 0,
|
||||
"profileImageDimension": 128,
|
||||
"requireEmailConfirmation": 0,
|
||||
"gdpr_enabled": 1,
|
||||
"allowProfileImageUploads": 1,
|
||||
"teaserPost": "last-reply",
|
||||
"allowPrivateGroups": 1,
|
||||
"allowGroupCreation": 0,
|
||||
"unreadCutoff": 2,
|
||||
"bookmarkThreshold": 5,
|
||||
"autoDetectLang": 1,
|
||||
"reputation:disabled": 0,
|
||||
"downvote:disabled": 0,
|
||||
"disableSignatures": 0,
|
||||
"min:rep:downvote": 0,
|
||||
"min:rep:flag": 0,
|
||||
"min:rep:profile-picture": 0,
|
||||
"min:rep:cover-picture": 0,
|
||||
"min:rep:website": 0,
|
||||
"min:rep:aboutme": 0,
|
||||
"min:rep:signature": 0,
|
||||
"notificationType_upvote": "notification",
|
||||
"notificationType_new-topic": "notification",
|
||||
"notificationType_new-reply": "notification",
|
||||
"notificationType_follow": "notification",
|
||||
"notificationType_new-chat": "notification",
|
||||
"notificationType_group-invite": "notification",
|
||||
"notificationType_mention": "notification",
|
||||
"notificationType_new-register": "notification",
|
||||
"notificationType_post-queue": "notification",
|
||||
"notificationType_new-post-flag": "notification",
|
||||
"notificationType_new-user-flag": "notification",
|
||||
"topicStaleDays": 60,
|
||||
"maxTopicsPerPage": 20,
|
||||
"maxPostsPerPage": 20,
|
||||
"topicsPerPage": 20,
|
||||
"postsPerPage": 20,
|
||||
"userSearchResultsPerPage": 50,
|
||||
"maximumGroupNameLength": 255,
|
||||
"preventTopicDeleteAfterReplies": 0,
|
||||
"feeds:disableSitemap": 0,
|
||||
"sitemapTopics": 500,
|
||||
"maintenanceMode": 0,
|
||||
"votesArePublic": 0,
|
||||
"maximumInvites": 0,
|
||||
"username:disableEdit": 0,
|
||||
"email:disableEdit": 0,
|
||||
"hideFullname": 0,
|
||||
"allowGuestHandles": 0,
|
||||
"disableRecentCategoryFilter": 0,
|
||||
"maximumRelatedTopics": 0,
|
||||
"disableEmailSubscriptions": 0,
|
||||
"emailConfirmInterval": 10,
|
||||
"inviteExpiration": 7,
|
||||
"digestHour": 17,
|
||||
"passwordExpiryDays": 0,
|
||||
"hsts-maxage": 31536000,
|
||||
"hsts-subdomains": 0,
|
||||
"hsts-preload": 0,
|
||||
"hsts-enabled": 0,
|
||||
"eventLoopCheckEnabled": 1,
|
||||
"eventLoopLagThreshold": 100,
|
||||
"eventLoopInterval": 500,
|
||||
"onlineCutoff": 30,
|
||||
"timeagoCutoff": 30,
|
||||
"categoryWatchState": "watching"
|
||||
}
|
||||
"topicsPerList": 20
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"widget": "html",
|
||||
"data" : {
|
||||
"html": "<footer id=\"footer\" class=\"container footer\">\r\n\t<div>\r\n\t\tPowered by <a target=\"_blank\" href=\"https://nodebb.org\">NodeBB</a> | <a target=\"_blank\" href=\"//github.com/NodeBB/NodeBB/graphs/contributors\">Contributors</a>\r\n\t</div>\r\n</footer>",
|
||||
"html": "<footer id=\"footer\" class=\"container footer\">\r\n\t<div class=\"copyright\">\r\n\t\tCopyright © 2016 <a target=\"_blank\" href=\"https://nodebb.org\">NodeBB Forums</a> | <a target=\"_blank\" href=\"//github.com/NodeBB/NodeBB/graphs/contributors\">Contributors</a>\r\n\t</div>\r\n</footer>",
|
||||
"title":"",
|
||||
"container":""
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
"iconClass": "fa-inbox",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "[[global:header.unread]]",
|
||||
"groups": ["registered-users"]
|
||||
"properties": {
|
||||
"loggedIn": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "/recent",
|
||||
@@ -64,9 +66,20 @@
|
||||
"iconClass": "fa-cogs",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "[[global:header.admin]]",
|
||||
"groups": ["administrators"],
|
||||
"properties": {
|
||||
"targetBlank": false
|
||||
"targetBlank": false,
|
||||
"adminOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "/search",
|
||||
"title": "[[global:header.search]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-search",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "[[global:header.search]]",
|
||||
"properties": {
|
||||
"searchInstalled": true
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -7,13 +7,13 @@ var winston = require('winston');
|
||||
var questions = {
|
||||
redis: require('../src/database/redis').questions,
|
||||
mongo: require('../src/database/mongo').questions,
|
||||
postgres: require('../src/database/postgres').questions,
|
||||
};
|
||||
|
||||
module.exports = function (config, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
winston.info('\nNow configuring ' + config.database + ' database:');
|
||||
process.stdout.write('\n');
|
||||
winston.info('Now configuring ' + config.database + ' database:');
|
||||
getDatabaseConfig(config, next);
|
||||
},
|
||||
function (databaseConfig, next) {
|
||||
@@ -34,17 +34,11 @@ function getDatabaseConfig(config, callback) {
|
||||
prompt.get(questions.redis, callback);
|
||||
}
|
||||
} else if (config.database === 'mongo') {
|
||||
if ((config['mongo:host'] && config['mongo:port']) || config['mongo:uri']) {
|
||||
if (config['mongo:host'] && config['mongo:port']) {
|
||||
callback(null, config);
|
||||
} else {
|
||||
prompt.get(questions.mongo, callback);
|
||||
}
|
||||
} else if (config.database === 'postgres') {
|
||||
if (config['postgres:host'] && config['postgres:port']) {
|
||||
callback(null, config);
|
||||
} else {
|
||||
prompt.get(questions.postgres, callback);
|
||||
}
|
||||
} else {
|
||||
return callback(new Error('unknown database : ' + config.database));
|
||||
}
|
||||
@@ -74,21 +68,12 @@ function saveDatabaseConfig(config, databaseConfig, callback) {
|
||||
username: databaseConfig['mongo:username'],
|
||||
password: databaseConfig['mongo:password'],
|
||||
database: databaseConfig['mongo:database'],
|
||||
uri: databaseConfig['mongo:uri'],
|
||||
};
|
||||
} else if (config.database === 'postgres') {
|
||||
config.postgres = {
|
||||
host: databaseConfig['postgres:host'],
|
||||
port: databaseConfig['postgres:port'],
|
||||
username: databaseConfig['postgres:username'],
|
||||
password: databaseConfig['postgres:password'],
|
||||
database: databaseConfig['postgres:database'],
|
||||
};
|
||||
} else {
|
||||
return callback(new Error('unknown database : ' + config.database));
|
||||
}
|
||||
|
||||
var allQuestions = questions.redis.concat(questions.mongo).concat(questions.postgres);
|
||||
var allQuestions = questions.redis.concat(questions.mongo);
|
||||
for (var x = 0; x < allQuestions.length; x += 1) {
|
||||
delete config[allQuestions[x].name];
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
{
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.11.2",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NodeBB/NodeBB/"
|
||||
},
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node loader.js",
|
||||
"lint": "eslint --cache ./nodebb .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "nyc --reporter=html --reporter=text-summary mocha",
|
||||
"coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "^1.2.9",
|
||||
"archiver": "^3.0.0",
|
||||
"async": "2.6.1",
|
||||
"autoprefixer": "^9.4.6",
|
||||
"bcryptjs": "2.4.3",
|
||||
"benchpressjs": "^1.2.5",
|
||||
"body-parser": "^1.18.2",
|
||||
"bootstrap": "^3.4.0",
|
||||
"bootswatch": "^3",
|
||||
"chart.js": "^2.7.1",
|
||||
"cli-graph": "^3.2.2",
|
||||
"clipboard": "^2.0.1",
|
||||
"colors": "^1.1.2",
|
||||
"commander": "^2.12.2",
|
||||
"compression": "^1.7.1",
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"connect-mongo": "2.0.3",
|
||||
"connect-multiparty": "^2.1.0",
|
||||
"connect-pg-simple": "^5.0.0",
|
||||
"connect-redis": "3.4.0",
|
||||
"continuation-local-storage": "^3.2.1",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cron": "^1.3.0",
|
||||
"cropperjs": "^1.2.2",
|
||||
"csurf": "^1.9.0",
|
||||
"daemon": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"express": "^4.16.2",
|
||||
"express-session": "^1.15.6",
|
||||
"express-useragent": "^1.0.12",
|
||||
"graceful-fs": "^4.1.11",
|
||||
"helmet": "^3.11.0",
|
||||
"html-to-text": "^4.0.0",
|
||||
"ipaddr.js": "^1.5.4",
|
||||
"jquery": "^3.2.1",
|
||||
"jsesc": "2.5.2",
|
||||
"json-2-csv": "^3.0.0",
|
||||
"jsonwebtoken": "^8.4.0",
|
||||
"less": "^2.7.3",
|
||||
"lodash": "^4.17.10",
|
||||
"logrotate-stream": "^0.2.5",
|
||||
"lru-cache": "5.1.1",
|
||||
"material-design-lite": "^1.3.0",
|
||||
"mime": "^2.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mongodb": "3.1.13",
|
||||
"morgan": "^1.9.0",
|
||||
"mousetrap": "^1.6.1",
|
||||
"mubsub-nbb": "^1.5.0",
|
||||
"nconf": "^0.10.0",
|
||||
"nodebb-plugin-composer-default": "6.1.21",
|
||||
"nodebb-plugin-dbsearch": "3.0.4",
|
||||
"nodebb-plugin-emoji": "^2.2.5",
|
||||
"nodebb-plugin-emoji-android": "2.0.0",
|
||||
"nodebb-plugin-markdown": "8.8.7",
|
||||
"nodebb-plugin-mentions": "2.5.2",
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.5.5",
|
||||
"nodebb-rewards-essentials": "0.0.13",
|
||||
"nodebb-theme-lavender": "5.0.8",
|
||||
"nodebb-theme-persona": "9.1.13",
|
||||
"nodebb-theme-slick": "1.2.19",
|
||||
"nodebb-theme-vanilla": "10.1.18",
|
||||
"nodebb-widget-essentials": "4.0.13",
|
||||
"nodemailer": "^5.0.0",
|
||||
"passport": "^0.4.0",
|
||||
"passport-local": "1.0.0",
|
||||
"pg": "^7.4.0",
|
||||
"pg-cursor": "^2.0.0",
|
||||
"postcss": "7.0.14",
|
||||
"postcss-clean": "1.1.0",
|
||||
"promise-polyfill": "^8.0.0",
|
||||
"prompt": "^1.0.0",
|
||||
"redis": "2.8.0",
|
||||
"request": "2.88.0",
|
||||
"rimraf": "2.6.3",
|
||||
"rss": "^1.2.2",
|
||||
"sanitize-html": "^1.16.3",
|
||||
"semver": "^5.4.1",
|
||||
"serve-favicon": "^2.4.5",
|
||||
"sharp": "0.21.3",
|
||||
"sitemap": "^2.0.0",
|
||||
"socket.io": "2.2.0",
|
||||
"socket.io-adapter-cluster": "^1.0.1",
|
||||
"socket.io-adapter-mongo": "^2.0.1",
|
||||
"socket.io-adapter-postgres": "^1.0.1",
|
||||
"socket.io-client": "2.2.0",
|
||||
"socket.io-redis": "5.2.0",
|
||||
"socketio-wildcard": "2.0.0",
|
||||
"spdx-license-list": "^5.0.0",
|
||||
"spider-detector": "1.0.19",
|
||||
"toobusy-js": "^0.5.1",
|
||||
"uglify-es": "^3.3.9",
|
||||
"validator": "10.11.0",
|
||||
"winston": "3.1.0",
|
||||
"xml": "^1.0.1",
|
||||
"xregexp": "^4.1.1",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "7.3.2",
|
||||
"@commitlint/config-angular": "7.3.1",
|
||||
"coveralls": "3.0.2",
|
||||
"eslint": "5.12.1",
|
||||
"eslint-config-airbnb-base": "13.1.0",
|
||||
"eslint-plugin-import": "2.15.0",
|
||||
"grunt": "1.0.3",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"husky": "1.3.1",
|
||||
"jsdom": "13.1.0",
|
||||
"lint-staged": "8.1.0",
|
||||
"mocha": "5.2.0",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
"nyc": "13.1.0",
|
||||
"smtp-server": "3.5.0"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/NodeBB/NodeBB/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Andrew Rodrigues",
|
||||
"email": "andrew@nodebb.org",
|
||||
"url": "https://github.com/psychobunny"
|
||||
},
|
||||
{
|
||||
"name": "Julian Lam",
|
||||
"email": "julian@nodebb.org",
|
||||
"url": "https://github.com/julianlam"
|
||||
},
|
||||
{
|
||||
"name": "Barış Soner Uşaklı",
|
||||
"email": "baris@nodebb.org",
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
222
install/web.js
@@ -5,83 +5,44 @@ var express = require('express');
|
||||
var bodyParser = require('body-parser');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var childProcess = require('child_process');
|
||||
var less = require('less');
|
||||
var async = require('async');
|
||||
var uglify = require('uglify-es');
|
||||
var uglify = require('uglify-js');
|
||||
var nconf = require('nconf');
|
||||
var Benchpress = require('benchpressjs');
|
||||
|
||||
var app = express();
|
||||
var server;
|
||||
|
||||
var formats = [
|
||||
winston.format.colorize(),
|
||||
];
|
||||
|
||||
const timestampFormat = winston.format((info) => {
|
||||
var dateString = new Date().toISOString() + ' [' + global.process.pid + ']';
|
||||
info.level = dateString + ' - ' + info.level;
|
||||
return info;
|
||||
});
|
||||
formats.push(timestampFormat());
|
||||
formats.push(winston.format.splat());
|
||||
formats.push(winston.format.simple());
|
||||
|
||||
winston.configure({
|
||||
winston.add(winston.transports.File, {
|
||||
filename: 'logs/webinstall.log',
|
||||
colorize: true,
|
||||
timestamp: function () {
|
||||
var date = new Date();
|
||||
return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 5) + ' [' + global.process.pid + ']';
|
||||
},
|
||||
level: 'verbose',
|
||||
format: winston.format.combine.apply(null, formats),
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
handleExceptions: true,
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'logs/webinstall.log',
|
||||
handleExceptions: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
var web = module.exports;
|
||||
|
||||
var web = {};
|
||||
var scripts = [
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
'public/vendor/xregexp/xregexp.js',
|
||||
'public/vendor/xregexp/unicode/unicode-base.js',
|
||||
'public/src/utils.js',
|
||||
'public/src/installer/install.js',
|
||||
];
|
||||
|
||||
var installing = false;
|
||||
var success = false;
|
||||
var error = false;
|
||||
var launchUrl;
|
||||
|
||||
web.install = function (port) {
|
||||
port = port || 4567;
|
||||
winston.info('Launching web installer on port ' + port);
|
||||
winston.info('Launching web installer on port', port);
|
||||
|
||||
app.use(express.static('public', {}));
|
||||
app.engine('tpl', function (filepath, options, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
fs.readFile(filepath, 'utf-8', next);
|
||||
},
|
||||
function (buffer, next) {
|
||||
Benchpress.compileParse(buffer.toString(), options, next);
|
||||
},
|
||||
], callback);
|
||||
});
|
||||
app.engine('tpl', require('templates.js').__express);
|
||||
app.set('view engine', 'tpl');
|
||||
app.set('views', path.join(__dirname, '../src/views'));
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: true,
|
||||
}));
|
||||
|
||||
async.parallel([compileLess, compileJS, copyCSS, loadDefaults], function (err) {
|
||||
if (err) {
|
||||
winston.error(err);
|
||||
}
|
||||
async.parallel([compileLess, compileJS], function () {
|
||||
setupRoutes();
|
||||
launchExpress(port);
|
||||
});
|
||||
@@ -98,81 +59,46 @@ function setupRoutes() {
|
||||
app.get('/', welcome);
|
||||
app.post('/', install);
|
||||
app.post('/launch', launch);
|
||||
app.get('/ping', ping);
|
||||
app.get('/sping', ping);
|
||||
}
|
||||
|
||||
function ping(req, res) {
|
||||
res.status(200).send(req.path === '/sping' ? 'healthy' : '200');
|
||||
}
|
||||
|
||||
function welcome(req, res) {
|
||||
var dbs = ['redis', 'mongo', 'postgres'];
|
||||
var databases = dbs.map(function (databaseName) {
|
||||
var questions = require('../src/database/' + databaseName).questions.filter(function (question) {
|
||||
return question && !question.hideOnWebInstall;
|
||||
});
|
||||
|
||||
var dbs = ['redis', 'mongo'];
|
||||
var databases = dbs.map(function (el) {
|
||||
return {
|
||||
name: databaseName,
|
||||
questions: questions,
|
||||
name: el,
|
||||
questions: require('../src/database/' + el).questions,
|
||||
};
|
||||
});
|
||||
|
||||
var defaults = require('./data/defaults');
|
||||
|
||||
res.render('install/index', {
|
||||
url: nconf.get('url') || (req.protocol + '://' + req.get('host')),
|
||||
launchUrl: launchUrl,
|
||||
skipGeneralSetup: !!nconf.get('url'),
|
||||
databases: databases,
|
||||
skipDatabaseSetup: !!nconf.get('database'),
|
||||
error: error,
|
||||
success: success,
|
||||
error: !!res.locals.error,
|
||||
success: !!res.locals.success,
|
||||
values: req.body,
|
||||
minimumPasswordLength: defaults.minimumPasswordLength,
|
||||
installing: installing,
|
||||
});
|
||||
}
|
||||
|
||||
function install(req, res) {
|
||||
if (installing) {
|
||||
return welcome(req, res);
|
||||
}
|
||||
req.setTimeout(0);
|
||||
installing = true;
|
||||
var setupEnvVars = nconf.get();
|
||||
for (var i in req.body) {
|
||||
if (req.body.hasOwnProperty(i) && !process.env.hasOwnProperty(i)) {
|
||||
setupEnvVars[i.replace(':', '__')] = req.body[i];
|
||||
process.env[i.replace(':', '__')] = req.body[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Flatten any objects in setupEnvVars
|
||||
const pushToRoot = function (parentKey, key) {
|
||||
setupEnvVars[parentKey + '__' + key] = setupEnvVars[parentKey][key];
|
||||
};
|
||||
for (var j in setupEnvVars) {
|
||||
if (setupEnvVars.hasOwnProperty(j) && typeof setupEnvVars[j] === 'object' && setupEnvVars[j] !== null && !Array.isArray(setupEnvVars[j])) {
|
||||
Object.keys(setupEnvVars[j]).forEach(pushToRoot.bind(null, j));
|
||||
delete setupEnvVars[j];
|
||||
} else if (Array.isArray(setupEnvVars[j])) {
|
||||
setupEnvVars[j] = JSON.stringify(setupEnvVars[j]);
|
||||
}
|
||||
}
|
||||
|
||||
winston.info('Starting setup process');
|
||||
winston.info(setupEnvVars);
|
||||
launchUrl = setupEnvVars.url;
|
||||
|
||||
var child = require('child_process').fork('app', ['--setup'], {
|
||||
env: setupEnvVars,
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
child.on('close', function (data) {
|
||||
installing = false;
|
||||
success = data === 0;
|
||||
error = data !== 0;
|
||||
if (data === 0) {
|
||||
res.locals.success = true;
|
||||
} else {
|
||||
res.locals.error = true;
|
||||
}
|
||||
|
||||
welcome(req, res);
|
||||
});
|
||||
@@ -182,35 +108,20 @@ function launch(req, res) {
|
||||
res.json({});
|
||||
server.close();
|
||||
|
||||
var child;
|
||||
var child = require('child_process').spawn('node', ['loader.js'], {
|
||||
detached: true,
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
});
|
||||
|
||||
if (!nconf.get('launchCmd')) {
|
||||
child = childProcess.spawn('node', ['loader.js'], {
|
||||
detached: true,
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
});
|
||||
process.stdout.write('\nStarting NodeBB\n');
|
||||
process.stdout.write(' "./nodebb stop" to stop the NodeBB server\n');
|
||||
process.stdout.write(' "./nodebb log" to view server output\n');
|
||||
process.stdout.write(' "./nodebb restart" to restart NodeBB\n');
|
||||
|
||||
console.log('\nStarting NodeBB');
|
||||
console.log(' "./nodebb stop" to stop the NodeBB server');
|
||||
console.log(' "./nodebb log" to view server output');
|
||||
console.log(' "./nodebb restart" to restart NodeBB');
|
||||
} else {
|
||||
// Use launchCmd instead, if specified
|
||||
child = childProcess.exec(nconf.get('launchCmd'), {
|
||||
detached: true,
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
});
|
||||
}
|
||||
|
||||
var filesToDelete = [
|
||||
'installer.css',
|
||||
'installer.min.js',
|
||||
'bootstrap.min.css',
|
||||
];
|
||||
|
||||
async.each(filesToDelete, function (filename, next) {
|
||||
fs.unlink(path.join(__dirname, '../public', filename), next);
|
||||
}, function (err) {
|
||||
async.parallel([
|
||||
async.apply(fs.unlink(path.join(__dirname, '../public/installer.css'))),
|
||||
async.apply(fs.unlink(path.join(__dirname, '../public/installer.min.js'))),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.warn('Unable to remove installer files');
|
||||
}
|
||||
@@ -237,58 +148,13 @@ function compileLess(callback) {
|
||||
}
|
||||
|
||||
function compileJS(callback) {
|
||||
var code = '';
|
||||
async.eachSeries(scripts, function (srcPath, next) {
|
||||
fs.readFile(path.join(__dirname, '..', srcPath), function (err, buffer) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var scriptPath = path.join(__dirname, '..');
|
||||
var result = uglify.minify(scripts.map(function (script) {
|
||||
return path.join(scriptPath, script);
|
||||
}));
|
||||
|
||||
code += buffer.toString();
|
||||
next();
|
||||
});
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
try {
|
||||
var minified = uglify.minify(code, {
|
||||
compress: false,
|
||||
});
|
||||
if (!minified.code) {
|
||||
return callback(new Error('[[error:failed-to-minify]]'));
|
||||
}
|
||||
fs.writeFile(path.join(__dirname, '../public/installer.min.js'), minified.code, callback);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
});
|
||||
|
||||
fs.writeFile(path.join(__dirname, '../public/installer.min.js'), result.code, callback);
|
||||
}
|
||||
|
||||
function copyCSS(next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
fs.readFile(path.join(__dirname, '../node_modules/bootstrap/dist/css/bootstrap.min.css'), 'utf8', next);
|
||||
},
|
||||
function (src, next) {
|
||||
fs.writeFile(path.join(__dirname, '../public/bootstrap.min.css'), src, next);
|
||||
},
|
||||
], next);
|
||||
}
|
||||
|
||||
function loadDefaults(next) {
|
||||
var setupDefaultsPath = path.join(__dirname, '../setup.json');
|
||||
fs.access(setupDefaultsPath, fs.constants.F_OK | fs.constants.R_OK, function (err) {
|
||||
if (err) {
|
||||
// setup.json not found or inaccessible, proceed with no defaults
|
||||
return setImmediate(next);
|
||||
}
|
||||
|
||||
winston.info('[installer] Found setup.json, populating default values');
|
||||
nconf.file({
|
||||
file: setupDefaultsPath,
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
module.exports = web;
|
||||
|
||||
127
loader.js
@@ -7,26 +7,16 @@ var path = require('path');
|
||||
var fork = require('child_process').fork;
|
||||
var async = require('async');
|
||||
var logrotate = require('logrotate-stream');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
var file = require('./src/file');
|
||||
var pkg = require('./package.json');
|
||||
|
||||
var pathToConfig = path.resolve(__dirname, process.env.CONFIG || 'config.json');
|
||||
|
||||
nconf.argv().env().file({
|
||||
file: pathToConfig,
|
||||
file: path.join(__dirname, 'config.json'),
|
||||
});
|
||||
|
||||
var pidFilePath = path.join(__dirname, 'pidfile');
|
||||
|
||||
var outputLogFilePath = path.join(__dirname, nconf.get('logFile') || 'logs/output.log');
|
||||
|
||||
var logDir = path.dirname(outputLogFilePath);
|
||||
if (!fs.existsSync(logDir)) {
|
||||
mkdirp.sync(path.dirname(outputLogFilePath));
|
||||
}
|
||||
|
||||
var outputLogFilePath = path.join(__dirname, 'logs/output.log');
|
||||
var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
|
||||
var silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false;
|
||||
var numProcs;
|
||||
@@ -45,6 +35,7 @@ Loader.init = function (callback) {
|
||||
}
|
||||
|
||||
process.on('SIGHUP', Loader.restart);
|
||||
process.on('SIGUSR2', Loader.reload);
|
||||
process.on('SIGTERM', Loader.stop);
|
||||
callback();
|
||||
};
|
||||
@@ -91,17 +82,9 @@ Loader.addWorkerEvents = function (worker) {
|
||||
console.log('[cluster] Restarting...');
|
||||
Loader.restart();
|
||||
break;
|
||||
case 'pubsub':
|
||||
workers.forEach(function (w) {
|
||||
w.send(message);
|
||||
});
|
||||
break;
|
||||
case 'socket.io':
|
||||
workers.forEach(function (w) {
|
||||
if (w !== worker) {
|
||||
w.send(message);
|
||||
}
|
||||
});
|
||||
case 'reload':
|
||||
console.log('[cluster] Reloading...');
|
||||
Loader.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +113,7 @@ function forkWorker(index, isPrimary) {
|
||||
}
|
||||
|
||||
process.env.isPrimary = isPrimary;
|
||||
process.env.isCluster = nconf.get('isCluster') || ports.length > 1;
|
||||
process.env.isCluster = ports.length > 1;
|
||||
process.env.port = ports[index];
|
||||
|
||||
var worker = fork(appPath, args, {
|
||||
@@ -159,7 +142,7 @@ function getPorts() {
|
||||
process.exit();
|
||||
}
|
||||
var urlObject = url.parse(_url);
|
||||
var port = nconf.get('PORT') || nconf.get('port') || urlObject.port || 4567;
|
||||
var port = nconf.get('port') || nconf.get('PORT') || urlObject.port || 4567;
|
||||
if (!Array.isArray(port)) {
|
||||
port = [port];
|
||||
}
|
||||
@@ -169,13 +152,14 @@ function getPorts() {
|
||||
Loader.restart = function () {
|
||||
killWorkers();
|
||||
|
||||
var pathToConfig = path.join(__dirname, '/config.json');
|
||||
nconf.remove('file');
|
||||
nconf.use('file', { file: pathToConfig });
|
||||
|
||||
fs.readFile(pathToConfig, { encoding: 'utf-8' }, function (err, configFile) {
|
||||
if (err) {
|
||||
console.error('Error reading config');
|
||||
throw err;
|
||||
console.log('Error reading config : ' + err.message);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var conf = JSON.parse(configFile);
|
||||
@@ -184,20 +168,23 @@ Loader.restart = function () {
|
||||
nconf.set('url', conf.url);
|
||||
nconf.stores.env.readOnly = true;
|
||||
|
||||
if (process.env.url !== conf.url) {
|
||||
process.env.url = conf.url;
|
||||
}
|
||||
Loader.start();
|
||||
});
|
||||
};
|
||||
|
||||
Loader.reload = function () {
|
||||
workers.forEach(function (worker) {
|
||||
worker.send({
|
||||
action: 'reload',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Loader.stop = function () {
|
||||
killWorkers();
|
||||
|
||||
// Clean up the pidfile
|
||||
if (nconf.get('daemon') !== 'false' && nconf.get('daemon') !== false) {
|
||||
fs.unlinkSync(pidFilePath);
|
||||
}
|
||||
fs.unlinkSync(pidFilePath);
|
||||
};
|
||||
|
||||
function killWorkers() {
|
||||
@@ -207,41 +194,51 @@ function killWorkers() {
|
||||
});
|
||||
}
|
||||
|
||||
fs.open(pathToConfig, 'r', function (err) {
|
||||
if (err) {
|
||||
// No config detected, kickstart web installer
|
||||
fork('app');
|
||||
return;
|
||||
}
|
||||
|
||||
if (nconf.get('daemon') !== 'false' && nconf.get('daemon') !== false) {
|
||||
if (file.existsSync(pidFilePath)) {
|
||||
Loader.notifyWorkers = function (msg, worker_pid) {
|
||||
worker_pid = parseInt(worker_pid, 10);
|
||||
workers.forEach(function (worker) {
|
||||
if (parseInt(worker.pid, 10) !== worker_pid) {
|
||||
try {
|
||||
var pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' });
|
||||
process.kill(pid, 0);
|
||||
process.exit();
|
||||
worker.send(msg);
|
||||
} catch (e) {
|
||||
fs.unlinkSync(pidFilePath);
|
||||
console.log('[cluster/notifyWorkers] Failed to reach pid ' + worker_pid);
|
||||
}
|
||||
}
|
||||
|
||||
require('daemon')({
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
fs.writeFileSync(pidFilePath, process.pid);
|
||||
}
|
||||
|
||||
async.series([
|
||||
Loader.init,
|
||||
Loader.displayStartupMessages,
|
||||
Loader.start,
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.error('[loader] Error during startup');
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
fs.open(path.join(__dirname, 'config.json'), 'r', function (err) {
|
||||
if (!err) {
|
||||
if (nconf.get('daemon') !== 'false' && nconf.get('daemon') !== false) {
|
||||
if (file.existsSync(pidFilePath)) {
|
||||
try {
|
||||
var pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' });
|
||||
process.kill(pid, 0);
|
||||
process.exit();
|
||||
} catch (e) {
|
||||
fs.unlinkSync(pidFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
require('daemon')({
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr,
|
||||
});
|
||||
|
||||
fs.writeFileSync(pidFilePath, process.pid);
|
||||
}
|
||||
|
||||
async.series([
|
||||
Loader.init,
|
||||
Loader.displayStartupMessages,
|
||||
Loader.start,
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.log('[loader] Error during startup: ' + err.message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No config detected, kickstart web installer
|
||||
require('child_process').fork('app');
|
||||
}
|
||||
});
|
||||
|
||||
501
nodebb
@@ -2,4 +2,503 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
require('./src/cli');
|
||||
var cproc;
|
||||
var args;
|
||||
var fs;
|
||||
var path;
|
||||
var request;
|
||||
var semver;
|
||||
var prompt;
|
||||
var async;
|
||||
|
||||
try {
|
||||
require('colors');
|
||||
cproc = require('child_process');
|
||||
args = require('minimist')(process.argv.slice(2));
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
request = require('request');
|
||||
semver = require('semver');
|
||||
prompt = require('prompt');
|
||||
async = require('async');
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
process.stdout.write('NodeBB could not be started because it\'s dependencies have not been installed.\n');
|
||||
process.stdout.write('Please ensure that you have executed "npm install --production" prior to running NodeBB.\n\n');
|
||||
process.stdout.write('For more information, please see: https://docs.nodebb.org/en/latest/installing/os.html\n\n');
|
||||
process.stdout.write('Could not start: ' + e.code + '\n');
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
var loaderPath = path.join(__dirname, 'loader.js');
|
||||
var appPath = path.join(__dirname, 'app.js');
|
||||
|
||||
if (args.dev) {
|
||||
process.env.NODE_ENV = 'development';
|
||||
}
|
||||
|
||||
function getRunningPid(callback) {
|
||||
fs.readFile(path.join(__dirname, 'pidfile'), {
|
||||
encoding: 'utf-8',
|
||||
}, function (err, pid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
process.kill(parseInt(pid, 10), 0);
|
||||
callback(null, parseInt(pid, 10));
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getCurrentVersion(callback) {
|
||||
fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg);
|
||||
return callback(null, pkg.version);
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
function fork(args) {
|
||||
return cproc.fork(appPath, args, {
|
||||
cwd: __dirname,
|
||||
silent: false,
|
||||
});
|
||||
}
|
||||
function getInstalledPlugins(callback) {
|
||||
async.parallel({
|
||||
files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')),
|
||||
deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' }),
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/;
|
||||
var moduleName;
|
||||
var isGitRepo;
|
||||
|
||||
payload.files = payload.files.filter(function (file) {
|
||||
return isNbbModule.test(file);
|
||||
});
|
||||
|
||||
try {
|
||||
payload.deps = JSON.parse(payload.deps).dependencies;
|
||||
payload.bundled = [];
|
||||
payload.installed = [];
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
for (moduleName in payload.deps) {
|
||||
if (isNbbModule.test(moduleName)) {
|
||||
payload.bundled.push(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
// Whittle down deps to send back only extraneously installed plugins/themes/etc
|
||||
payload.files.forEach(function (moduleName) {
|
||||
try {
|
||||
fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git'));
|
||||
isGitRepo = true;
|
||||
} catch (e) {
|
||||
isGitRepo = false;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.files.indexOf(moduleName) !== -1 && // found in `node_modules/`
|
||||
payload.bundled.indexOf(moduleName) === -1 && // not found in `package.json`
|
||||
!fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() && // is not a symlink
|
||||
!isGitRepo // .git/ does not exist, so it is not a git repository
|
||||
) {
|
||||
payload.installed.push(moduleName);
|
||||
}
|
||||
});
|
||||
|
||||
getModuleVersions(payload.installed, callback);
|
||||
});
|
||||
}
|
||||
function getModuleVersions(modules, callback) {
|
||||
var versionHash = {};
|
||||
|
||||
async.eachLimit(modules, 50, function (module, next) {
|
||||
fs.readFile(path.join(__dirname, 'node_modules/' + module + '/package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg);
|
||||
versionHash[module] = pkg.version;
|
||||
next();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
}, function (err) {
|
||||
callback(err, versionHash);
|
||||
});
|
||||
}
|
||||
function checkPlugins(standalone, callback) {
|
||||
if (standalone) {
|
||||
process.stdout.write('Checking installed plugins and themes for updates... ');
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
async.apply(async.parallel, {
|
||||
plugins: async.apply(getInstalledPlugins),
|
||||
version: async.apply(getCurrentVersion),
|
||||
}),
|
||||
function (payload, next) {
|
||||
var toCheck = Object.keys(payload.plugins);
|
||||
|
||||
if (!toCheck.length) {
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
return next(null, []); // no extraneous plugins installed
|
||||
}
|
||||
|
||||
request({
|
||||
method: 'GET',
|
||||
url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='),
|
||||
json: true,
|
||||
}, function (err, res, body) {
|
||||
if (err) {
|
||||
process.stdout.write('error'.red + '\n'.reset);
|
||||
return next(err);
|
||||
}
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
|
||||
if (!Array.isArray(body) && toCheck.length === 1) {
|
||||
body = [body];
|
||||
}
|
||||
|
||||
var current;
|
||||
var suggested;
|
||||
var upgradable = body.map(function (suggestObj) {
|
||||
current = payload.plugins[suggestObj.package];
|
||||
suggested = suggestObj.version;
|
||||
|
||||
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
|
||||
return {
|
||||
name: suggestObj.package,
|
||||
current: current,
|
||||
suggested: suggested,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean);
|
||||
|
||||
next(null, upgradable);
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
function upgradePlugins(callback) {
|
||||
var standalone = false;
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function () {};
|
||||
standalone = true;
|
||||
}
|
||||
|
||||
checkPlugins(standalone, function (err, found) {
|
||||
if (err) {
|
||||
process.stdout.write('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (found && found.length) {
|
||||
process.stdout.write('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:\n');
|
||||
found.forEach(function (suggestObj) {
|
||||
process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset);
|
||||
});
|
||||
process.stdout.write('\n');
|
||||
} else {
|
||||
if (standalone) {
|
||||
process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset);
|
||||
}
|
||||
return callback();
|
||||
}
|
||||
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
|
||||
prompt.start();
|
||||
prompt.get({
|
||||
name: 'upgrade',
|
||||
description: 'Proceed with upgrade (y|n)?'.reset,
|
||||
type: 'string',
|
||||
}, function (err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) {
|
||||
process.stdout.write('\nUpgrading packages...');
|
||||
var args = ['i'];
|
||||
found.forEach(function (suggestObj) {
|
||||
args.push(suggestObj.name + '@' + suggestObj.suggested);
|
||||
});
|
||||
|
||||
cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', args, { stdio: 'ignore' }, function (err) {
|
||||
if (!err) {
|
||||
process.stdout.write(' OK\n'.green);
|
||||
}
|
||||
|
||||
callback(err);
|
||||
});
|
||||
} else {
|
||||
process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var commands = {
|
||||
status: {
|
||||
description: 'View the status of the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb status'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.stdout.write('\nNodeBB Running '.bold + '(pid '.cyan + pid.toString().cyan + ')\n'.cyan);
|
||||
process.stdout.write('\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write('\t"' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write('\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n\n');
|
||||
} else {
|
||||
process.stdout.write('\nNodeBB is not running\n'.bold);
|
||||
process.stdout.write('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n\n'.reset);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
start: {
|
||||
description: 'Start the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb start'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nStarting NodeBB\n'.bold);
|
||||
process.stdout.write(' "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write(' "' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset);
|
||||
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(loaderPath, {
|
||||
env: process.env,
|
||||
});
|
||||
},
|
||||
},
|
||||
stop: {
|
||||
description: 'Stop the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb stop'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGTERM');
|
||||
process.stdout.write('Stopping NodeBB. Goodbye!\n');
|
||||
} else {
|
||||
process.stdout.write('NodeBB is already stopped.\n');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
restart: {
|
||||
description: 'Restart the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb restart'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGHUP');
|
||||
process.stdout.write('\nRestarting NodeBB\n'.bold);
|
||||
} else {
|
||||
process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
log: {
|
||||
description: 'Open the output log (useful for debugging)',
|
||||
usage: 'Usage: ' + './nodebb log'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
},
|
||||
},
|
||||
slog: {
|
||||
description: 'Start the NodeBB server and view the live output log',
|
||||
usage: 'Usage: ' + './nodebb slog'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nStarting NodeBB with logging output\n'.bold);
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(loaderPath, {
|
||||
env: process.env,
|
||||
});
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
description: 'Start NodeBB in verbose development mode',
|
||||
usage: 'Usage: ' + './nodebb dev'.yellow,
|
||||
handler: function () {
|
||||
process.env.NODE_ENV = 'development';
|
||||
cproc.fork(loaderPath, ['--no-daemon', '--no-silent'], {
|
||||
env: process.env,
|
||||
});
|
||||
},
|
||||
},
|
||||
build: {
|
||||
description: 'Compile static assets (CSS, Javascript, etc)',
|
||||
usage: 'Usage: ' + './nodebb build'.yellow + ' [js,clientCSS,acpCSS,tpl,lang]'.red + '\n' +
|
||||
' e.g. ' + './nodebb build js,tpl'.yellow + '\tbuilds JS and templates\n' +
|
||||
' ' + './nodebb build'.yellow + '\t\tbuilds all targets\n',
|
||||
handler: function () {
|
||||
var arr = ['--build'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
setup: {
|
||||
description: 'Run the NodeBB setup script',
|
||||
usage: 'Usage: ' + './nodebb setup'.yellow,
|
||||
handler: function () {
|
||||
var arr = ['--setup'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
reset: {
|
||||
description: 'Disable plugins and restore the default theme',
|
||||
usage: 'Usage: ' + './nodebb reset '.yellow + '{-t|-p|-w|-s|-a}'.red + '\n' +
|
||||
' -t <theme>\tuse specified theme\n' +
|
||||
' -p <plugin>\tdisable specified plugin\n' +
|
||||
'\n' +
|
||||
' -t\t\tuse default theme\n' +
|
||||
' -p\t\tdisable all but core plugins\n' +
|
||||
' -w\t\twidgets\n' +
|
||||
' -s\t\tsettings\n' +
|
||||
' -a\t\tall of the above\n',
|
||||
handler: function () {
|
||||
var arr = ['--reset'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
activate: {
|
||||
description: 'Activate a plugin for the next startup of NodeBB',
|
||||
usage: 'Usage: ' + './nodebb activate <plugin>'.yellow,
|
||||
handler: function () {
|
||||
var name = args._[1];
|
||||
if (!name) {
|
||||
process.stdout.write(commands.activate.usage + '\n');
|
||||
process.exit();
|
||||
}
|
||||
if (name.startsWith('nodebb-theme')) {
|
||||
fork(['--reset', '-t', name]);
|
||||
return;
|
||||
}
|
||||
var arr = ['--activate=' + name].concat(process.argv.slice(4));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
description: 'List all installed plugins',
|
||||
usage: 'Usage: ' + './nodebb plugins'.yellow,
|
||||
handler: function () {
|
||||
var arr = ['--plugins'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
upgrade: {
|
||||
description: 'Run NodeBB upgrade scripts, ensure packages are up-to-date',
|
||||
usage: 'Usage: ' + './nodebb upgrade'.yellow,
|
||||
handler: function () {
|
||||
async.series([
|
||||
function (next) {
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow);
|
||||
cproc.exec('npm i --production', { cwd: __dirname, stdio: 'ignore' }, next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow);
|
||||
upgradePlugins(next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow);
|
||||
var arr = ['--upgrade'].concat(process.argv.slice(3));
|
||||
var upgradeProc = fork(arr);
|
||||
|
||||
upgradeProc.on('close', next);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
|
||||
} else {
|
||||
var message = 'NodeBB Upgrade Complete!';
|
||||
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||
var columns = process.stdout.columns;
|
||||
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
upgradePlugins: {
|
||||
hidden: true,
|
||||
description: '',
|
||||
handler: function () {
|
||||
upgradePlugins();
|
||||
},
|
||||
},
|
||||
help: {
|
||||
description: 'Display the help message for a given command',
|
||||
usage: 'Usage: ' + './nodebb help <command>'.yellow,
|
||||
handler: function () {
|
||||
var command = commands[args._[1]];
|
||||
if (command) {
|
||||
process.stdout.write(command.description + '\n'.reset);
|
||||
process.stdout.write(command.usage + '\n'.reset);
|
||||
|
||||
return;
|
||||
}
|
||||
var keys = Object.keys(commands).filter(function (key) {
|
||||
return !commands[key].hidden;
|
||||
});
|
||||
|
||||
process.stdout.write('\nWelcome to NodeBB\n\n'.bold);
|
||||
process.stdout.write('Usage: ./nodebb {' + keys.join('|') + '}\n\n');
|
||||
|
||||
var usage = keys.map(function (key) {
|
||||
var line = '\t' + key.yellow + (key.length < 8 ? '\t\t' : '\t');
|
||||
return line + commands[key].description;
|
||||
}).join('\n');
|
||||
|
||||
process.stdout.write(usage + '\n'.reset);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
commands['upgrade-plugins'] = commands.upgradePlugins;
|
||||
|
||||
if (!commands[args._[0]]) {
|
||||
commands.help.handler();
|
||||
} else {
|
||||
commands[args._[0]].handler();
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
@echo off && cd %~dp0 && node ./nodebb %*
|
||||
node ./nodebb %*
|
||||
|
||||
139
package.json
Normal file
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.4.6",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NodeBB/NodeBB/"
|
||||
},
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node loader.js",
|
||||
"lint": "eslint --cache ./nodebb .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
|
||||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "^1.2.6",
|
||||
"async": "~1.5.0",
|
||||
"autoprefixer": "^6.2.3",
|
||||
"bcryptjs": "~2.3.0",
|
||||
"body-parser": "^1.9.0",
|
||||
"bootstrap": "^3.3.7",
|
||||
"chart.js": "^2.4.0",
|
||||
"colors": "^1.1.0",
|
||||
"compression": "^1.1.0",
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"connect-mongo": "1.3.2",
|
||||
"connect-multiparty": "^2.0.0",
|
||||
"connect-redis": "~3.1.0",
|
||||
"cookie-parser": "^1.3.3",
|
||||
"cron": "^1.0.5",
|
||||
"cropperjs": "^0.8.1",
|
||||
"csurf": "^1.6.1",
|
||||
"daemon": "~1.1.0",
|
||||
"express": "^4.14.0",
|
||||
"express-session": "^1.8.2",
|
||||
"express-useragent": "1.0.7",
|
||||
"html-to-text": "2.1.3",
|
||||
"ip": "1.1.3",
|
||||
"jimp": "0.2.27",
|
||||
"jquery": "^3.1.0",
|
||||
"json-2-csv": "^2.0.22",
|
||||
"less": "^2.0.0",
|
||||
"logrotate-stream": "^0.2.3",
|
||||
"lru-cache": "4.0.1",
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.1.1",
|
||||
"mkdirp": "~0.5.0",
|
||||
"mongodb": "2.2.25",
|
||||
"morgan": "^1.3.2",
|
||||
"mousetrap": "^1.5.3",
|
||||
"nconf": "~0.8.2",
|
||||
"nodebb-plugin-composer-default": "4.4.6",
|
||||
"nodebb-plugin-dbsearch": "1.0.5",
|
||||
"nodebb-plugin-emoji-extended": "1.1.1",
|
||||
"nodebb-plugin-emoji-one": "1.1.5",
|
||||
"nodebb-plugin-markdown": "7.1.1",
|
||||
"nodebb-plugin-mentions": "1.1.3",
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.4.13",
|
||||
"nodebb-rewards-essentials": "0.0.9",
|
||||
"nodebb-theme-lavender": "4.0.0",
|
||||
"nodebb-theme-persona": "4.2.10",
|
||||
"nodebb-theme-vanilla": "5.2.1",
|
||||
"nodebb-widget-essentials": "2.0.13",
|
||||
"nodemailer": "2.6.4",
|
||||
"nodemailer-sendmail-transport": "1.0.0",
|
||||
"nodemailer-smtp-transport": "^2.4.1",
|
||||
"passport": "^0.3.0",
|
||||
"passport-local": "1.0.0",
|
||||
"postcss": "^5.0.13",
|
||||
"postcss-clean": "^1.0.0",
|
||||
"promise-polyfill": "^6.0.2",
|
||||
"prompt": "^1.0.0",
|
||||
"redis": "~2.6.2",
|
||||
"request": "^2.44.0",
|
||||
"rimraf": "~2.5.0",
|
||||
"rss": "^1.0.0",
|
||||
"sanitize-html": "^1.13.0",
|
||||
"semver": "^5.1.0",
|
||||
"serve-favicon": "^2.1.5",
|
||||
"sitemap": "^1.4.0",
|
||||
"socket.io": "1.7.2",
|
||||
"socket.io-client": "1.7.2",
|
||||
"socket.io-redis": "3.1.0",
|
||||
"socketio-wildcard": "~0.3.0",
|
||||
"string": "^3.0.0",
|
||||
"templates.js": "0.3.10",
|
||||
"toobusy-js": "^0.5.1",
|
||||
"uglify-js": "^2.6.0",
|
||||
"underscore": "^1.8.3",
|
||||
"underscore.deep": "^0.5.1",
|
||||
"validator": "^6.1.0",
|
||||
"winston": "^2.1.0",
|
||||
"xml": "^1.0.1",
|
||||
"xregexp": "~3.1.0",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.14",
|
||||
"eslint": "^3.12.0",
|
||||
"eslint-config-airbnb-base": "^11.1.0",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"grunt": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"istanbul": "^0.4.2",
|
||||
"mocha": "~3.2.0",
|
||||
"mocha-lcov-reporter": "^1.2.0",
|
||||
"xmlhttprequest": "1.8.0",
|
||||
"xmlhttprequest-ssl": "1.5.3"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/NodeBB/NodeBB/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Andrew Rodrigues",
|
||||
"email": "andrew@nodebb.org",
|
||||
"url": "https://github.com/psychobunny"
|
||||
},
|
||||
{
|
||||
"name": "Julian Lam",
|
||||
"email": "julian@nodebb.org",
|
||||
"url": "https://github.com/julianlam"
|
||||
},
|
||||
{
|
||||
"name": "Barış Soner Uşaklı",
|
||||
"email": "baris@nodebb.org",
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
"overrides": true,
|
||||
"componentHandler": true,
|
||||
"bootbox": true,
|
||||
"templates": true,
|
||||
"Visibility": true,
|
||||
"Tinycon": true,
|
||||
"Promise": true
|
||||
|
||||
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
The following stylesheet is only included on pages that can execute javascript
|
||||
*/
|
||||
|
||||
.page-topic [component="post/content"] img:not(.not-responsive):not([data-state]) {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
# Important note about localising NodeBB
|
||||
|
||||
The files here are read-only and overwritten daily (if there are changes) by the
|
||||
helper bot [Misty](https://github.com/nodebb-misty).
|
||||
|
||||
Our localisation efforts are handled via [our Transifex Project](https://www.transifex.com/nodebb/nodebb/),
|
||||
and any pull requests made to this directory will be automatically closed because
|
||||
localisations can go out-of-sync when edited directly.
|
||||
|
||||
If there are non-localised strings and you cannot find them in Transifex, please
|
||||
[open a new issue on our bug tracker](https://github.com/NodeBB/NodeBB/issues/new)
|
||||
so we can take a look.
|
||||
|
||||
Thank you for helping localise NodeBB!
|
||||
3
public/language/TODO
Normal file
@@ -0,0 +1,3 @@
|
||||
NPM INSTALL
|
||||
For now, language packs will be stored here. Eventually, will be moved to server side to allow for npm install-ability.
|
||||
When that happens, server code will generate compressed JSON language files in this folder.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"alert.confirm-rebuild-and-restart": "Are you sure you wish to rebuild and restart NodeBB?",
|
||||
"alert.confirm-restart": "هل تريد بالتأكيد إعادة تشغيل NodeBB؟",
|
||||
"alert.confirm-reload": "Are you sure you wish to reload NodeBB?",
|
||||
"alert.confirm-restart": "Are you sure you wish to restart NodeBB?",
|
||||
|
||||
"acp-title": "لوحة تحكم إدارة NodeBB | %1",
|
||||
"settings-header-contents": "محتويات"
|
||||
"acp-title": "%1 | NodeBB Admin Control Panel",
|
||||
"settings-header-contents": "Contents"
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"post-cache": "التخزين المؤقت للمشاركات",
|
||||
"posts-in-cache": "المشاركات المخزنة مؤقتاً",
|
||||
"average-post-size": "متوسط حجم المشاركة",
|
||||
"length-to-max": "الطول / أقصى حد",
|
||||
"post-cache": "Post Cache",
|
||||
"posts-in-cache": "Posts in Cache",
|
||||
"average-post-size": "Average Post Size",
|
||||
"length-to-max": "Length / Max",
|
||||
"percent-full": "%1% Full",
|
||||
"post-cache-size": "حجم التخزين المؤقت للمشاركات",
|
||||
"items-in-cache": "العناصر في التخزين المؤقت",
|
||||
"control-panel": "لوحة التحكم",
|
||||
"update-settings": "تحديث إعدادات التخزين المؤقت"
|
||||
"post-cache-size": "Post Cache Size",
|
||||
"items-in-cache": "Items in Cache",
|
||||
"control-panel": "Control Panel",
|
||||
"update-settings": "Update Cache Settings"
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"x-b": "%1 b",
|
||||
"x-mb": "%1 mb",
|
||||
"x-gb": "%1 gb",
|
||||
"uptime-seconds": "Uptime in Seconds",
|
||||
"uptime-days": "Uptime in Days",
|
||||
|
||||
@@ -16,36 +15,21 @@
|
||||
"mongo.index-size": "Index Size",
|
||||
"mongo.file-size": "File Size",
|
||||
"mongo.resident-memory": "Resident Memory",
|
||||
"mongo.virtual-memory": "الذاكرة الإفتراضية",
|
||||
"mongo.virtual-memory": "Virtual Memory",
|
||||
"mongo.mapped-memory": "Mapped Memory",
|
||||
"mongo.bytes-in": "Bytes In",
|
||||
"mongo.bytes-out": "Bytes Out",
|
||||
"mongo.num-requests": "Number of Requests",
|
||||
"mongo.raw-info": "MongoDB Raw Info",
|
||||
|
||||
"redis": "Redis",
|
||||
"redis.version": "Redis Version",
|
||||
"redis.keys": "Keys",
|
||||
"redis.expires": "Expires",
|
||||
"redis.avg-ttl": "Average TTL",
|
||||
"redis.connected-clients": "Connected Clients",
|
||||
"redis.connected-slaves": "Connected Slaves",
|
||||
"redis.blocked-clients": "Blocked Clients",
|
||||
"redis.used-memory": "الذاكرة المستخدمة",
|
||||
"redis.used-memory": "Used Memory",
|
||||
"redis.memory-frag-ratio": "Memory Fragmentation Ratio",
|
||||
"redis.total-connections-recieved": "إجمالي الاتصالات المستلمة",
|
||||
"redis.total-commands-processed": "إجمالي الأوامر التي تمت معالجتها",
|
||||
"redis.total-connections-recieved": "Total Connections Received",
|
||||
"redis.total-commands-processed": "Total Commands Processed",
|
||||
"redis.iops": "Instantaneous Ops. Per Second",
|
||||
"redis.iinput": "Instantaneous Input Per Second",
|
||||
"redis.ioutput": "Instantaneous Output Per Second",
|
||||
"redis.total-input": "Total Input",
|
||||
"redis.total-output": "Total Ouput",
|
||||
|
||||
"redis.keyspace-hits": "Keyspace Hits",
|
||||
"redis.keyspace-misses": "Keyspace Misses",
|
||||
"redis.raw-info": "Redis Raw Info",
|
||||
|
||||
"postgres": "Postgres",
|
||||
"postgres.version": "PostgreSQL Version",
|
||||
"postgres.raw-info": "Postgres Raw Info"
|
||||
}
|
||||
"redis.raw-info": "Redis Raw Info"
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"figure-x": "شكل %1",
|
||||
"error-events-per-day": "<code>%1</code> حدث كل يوم ",
|
||||
"error.404": "404 لم يتم العثور",
|
||||
"error.503": "503 الخدمة غير متوفرة",
|
||||
"manage-error-log": "إدارة سجل الأخطاء",
|
||||
"export-error-log": "تصدير سجل الأخطاء (CSV)",
|
||||
"clear-error-log": "محو سجل الأخطاء",
|
||||
"route": "مسار",
|
||||
"count": "عدد",
|
||||
"no-routes-not-found": "لا توجد اخطاء 404!",
|
||||
"clear404-confirm": "هل تريد بالتأكيد محو سجلات الخطأ 404؟",
|
||||
"clear404-success": "أخطاء \"404 لم يتم العثور\" تم محوها بنجاح"
|
||||
"figure-x": "Figure %1",
|
||||
"error-events-per-day": "<code>%1</code> events per day",
|
||||
"error.404": "404 Not Found",
|
||||
"error.503": "503 Service Unavailable",
|
||||
"manage-error-log": "Manage Error Log",
|
||||
"export-error-log": "Export Error Log (CSV)",
|
||||
"clear-error-log": "Clear Error Log",
|
||||
"route": "Route",
|
||||
"count": "Count",
|
||||
"no-routes-not-found": "Hooray! No 404 errors!",
|
||||
"clear404-confirm": "Are you sure you wish to clear the 404 error logs?",
|
||||
"clear404-success": "\"404 Not Found\" errors cleared"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"events": "أحداث",
|
||||
"no-events": "لا توجد أحداث",
|
||||
"control-panel": "لوحة تحكم الأحداث",
|
||||
"delete-events": "حذف الأحداث"
|
||||
"events": "Events",
|
||||
"no-events": "There are no events",
|
||||
"control-panel": "Events Control Panel",
|
||||
"delete-events": "Delete Events"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"logs": "السجلات",
|
||||
"control-panel": "لوحة تحكم السجلات",
|
||||
"reload": "إعادة تحميل السجلات",
|
||||
"clear": "محو السجلات",
|
||||
"clear-success": "تم محو السجلات!"
|
||||
"logs": "Logs",
|
||||
"control-panel": "Logs Control Panel",
|
||||
"reload": "Reload Logs",
|
||||
"clear": "Clear Logs",
|
||||
"clear-success": "Logs Cleared!"
|
||||
}
|
||||
@@ -1,16 +1,9 @@
|
||||
{
|
||||
"custom-css": "Custom CSS/LESS",
|
||||
"custom-css.description": "Enter your own CSS/LESS declarations here, which will be applied after all other styles.",
|
||||
"custom-css.enable": "Enable Custom CSS/LESS",
|
||||
"custom-css": "Custom CSS",
|
||||
"custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.",
|
||||
"custom-css.enable": "Enable Custom CSS",
|
||||
|
||||
"custom-js": "Javascript مخصصة",
|
||||
"custom-js.description": "أدخل Javascript الخاص بك هنا. سيتم تنفيذها بعد تحميل الصفحة بالكامل.",
|
||||
"custom-js.enable": "تفعيل Javascript المخصصة",
|
||||
|
||||
"custom-header": "ترويسة مخصصة",
|
||||
"custom-header.description": "أدخل HTML الخاصة بك هنا (مثل العلامات الوصفية، وما إلى ذلك)، والتي سيتم إلحاقها الى<code><head></code> في تصميم المنتدى. يسمح باستخدام علامات النص البرمجي، ولكن سيتم تعطيلها؛ لتوفر تبويبة\n<a href=\"#custom-header\" data-toggle=\"tab\">Javascript المخصصة</a>",
|
||||
"custom-header.enable": "تفعيل الترويسة المخصصة",
|
||||
|
||||
"custom-css.livereload": "تفعيل إعادة التحميل المباشرة",
|
||||
"custom-css.livereload.description": "فعل هذا الخيار لإجبار جميع الجلسات في الأجهزة التي قمت بتسجيل الدخول فيها بحسابك على التحديث عند النقر على زر الحفظ"
|
||||
"custom-header": "Custom Header",
|
||||
"custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <code><head></code> section of your forum's markup.",
|
||||
"custom-header.enable": "Enable Custom Header"
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"loading": "جاري تحميل السمات...",
|
||||
"homepage": "الصفحة الرئيسية",
|
||||
"select-skin": "إختيار السمة",
|
||||
"current-skin": "السمة الحالية",
|
||||
"skin-updated": "تم تحديث السمة",
|
||||
"applied-success": "تم تطبيق السمة %1 بنجاح",
|
||||
"revert-success": "تم إستعادة الألوان الاساسية للسمة"
|
||||
"loading": "Loading Skins...",
|
||||
"homepage": "Homepage",
|
||||
"select-skin": "Select Skin",
|
||||
"current-skin": "Current Skin",
|
||||
"skin-updated": "Skin Updated",
|
||||
"applied-success": "%1 skin was succesfully applied",
|
||||
"revert-success": "Skin reverted to base colours"
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"checking-for-installed": "جاري التحقق من القوالب المثبتة...",
|
||||
"homepage": "الصفحة الرئيسية",
|
||||
"select-theme": "إختيار القالب",
|
||||
"current-theme": "القالب المستخدم حالياً",
|
||||
"no-themes": "لم يتم العثور على قوالب مثبتة",
|
||||
"revert-confirm": "هل أنت متأكد من أنك ترغب في استعادة قااب NodeBB الافتراضي؟",
|
||||
"theme-changed": "تم تغيير القالب",
|
||||
"revert-success": "لقد قمت بنجاح بإستعادة القالب الأساسي لـNodeBB",
|
||||
"restart-to-activate": "Please rebuild and restart your NodeBB to fully activate this theme."
|
||||
"checking-for-installed": "Checking for installed themes...",
|
||||
"homepage": "Homepage",
|
||||
"select-theme": "Select Theme",
|
||||
"current-theme": "Current Theme",
|
||||
"no-themes": "No installed themes found",
|
||||
"revert-confirm": "Are you sure you wish to restore the default NodeBB theme?",
|
||||
"theme-changed": "Theme Changed",
|
||||
"revert-success": "You have successfully reverted your NodeBB back to it's default theme.",
|
||||
"restart-to-activate": "Please restart your NodeBB to fully activate this theme"
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
"you-are-on": "Info - You are on <strong>%1:%2</strong>",
|
||||
"nodes-responded": "%1 nodes responded within %2ms!",
|
||||
"host": "host",
|
||||
"pid": "pid",
|
||||
"nodejs": "nodejs",
|
||||
"online": "online",
|
||||
"git": "git",
|
||||
"memory": "memory",
|
||||
"load": "load",
|
||||
"uptime": "uptime",
|
||||
|
||||
|
||||
@@ -1,53 +1,47 @@
|
||||
{
|
||||
"installed": "منصبة",
|
||||
"active": "مفعلة",
|
||||
"inactive": "معطلة",
|
||||
"out-of-date": "غير محدثة",
|
||||
"none-found": "لم يتم العثور على إضافات",
|
||||
"none-active": "لا توجد إضافات مفعلة",
|
||||
"find-plugins": "العثور على الإضافات",
|
||||
"installed": "Installed",
|
||||
"active": "Active",
|
||||
"inactive": "Inactive",
|
||||
"out-of-date": "Out of Date",
|
||||
"none-found": "No plugins found.",
|
||||
"none-active": "No Active Plugins",
|
||||
"find-plugins": "Find Plugins",
|
||||
|
||||
"plugin-search": "البحث عن الإضافات",
|
||||
"plugin-search-placeholder": "جاري البحث عن الإضافات...",
|
||||
"reorder-plugins": "إعادة ترتيب الإضافات",
|
||||
"order-active": "ترتيب الإضافات المفعلة",
|
||||
"dev-interested": "هل انته مهتم ببرمجة إضافات لـNodeBB؟",
|
||||
"docs-info": "دليل كامل حول برمجة الإضافات بالإمكان العثور عليه في <a target=\"_blank\" href=\"https://docs.nodebb.org/development/plugins/\"> NodeBB Docs Portal</a>.",
|
||||
"plugin-search": "Plugin Search",
|
||||
"plugin-search-placeholder": "Search for plugin...",
|
||||
"reorder-plugins": "Re-order Plugins",
|
||||
"order-active": "Order Active Plugins",
|
||||
"dev-interested": "Interested in writing plugins for NodeBB?",
|
||||
"docs-info": "Full documentation regarding plugin authoring can be found in the <a target=\"_blank\" href=\"https://docs.nodebb.org/en/latest/plugins/create.html\">NodeBB Docs Portal</a>.",
|
||||
|
||||
"order.description": "بعض الإضافات تعمل بشكل مثالي عندما يتم تفعيلها قبل أو بعد الإضافات الأخرى.",
|
||||
"order.explanation": "يتم تحميل الإضافات حسب الترتيب المحدد هنا، من الأعلى إلى الأسفل",
|
||||
"order.description": "Certain plugins work ideally when they are initialised before/after other plugins.",
|
||||
"order.explanation": "Plugins load in the order specified here, from top to bottom",
|
||||
|
||||
"plugin-item.themes": "Themes",
|
||||
"plugin-item.deactivate": "Deactivate",
|
||||
"plugin-item.activate": "Activate",
|
||||
"plugin-item.install": "Install",
|
||||
"plugin-item.uninstall": "Uninstall",
|
||||
"plugin-item.settings": "Settings",
|
||||
"plugin-item.installed": "Installed",
|
||||
"plugin-item.latest": "Latest",
|
||||
"plugin-item.upgrade": "Upgrade",
|
||||
"plugin-item.more-info": "For more information:",
|
||||
"plugin-item.unknown": "Unknown",
|
||||
"plugin-item.unknown-explanation": "The state of this plugin could not be determined, possibly due to a misconfiguration error.",
|
||||
|
||||
"plugin-item.themes": "القوالب",
|
||||
"plugin-item.deactivate": "تعطيل",
|
||||
"plugin-item.activate": "تفعيل",
|
||||
"plugin-item.install": "تنصيب",
|
||||
"plugin-item.uninstall": "إلغاء التنصيب",
|
||||
"plugin-item.settings": "الإعدادات",
|
||||
"plugin-item.installed": "المنصبة",
|
||||
"plugin-item.latest": "الأحدث",
|
||||
"plugin-item.upgrade": "ترقية",
|
||||
"plugin-item.more-info": "لمزيد من المعلومات:",
|
||||
"plugin-item.unknown": "غير معروف",
|
||||
"plugin-item.unknown-explanation": "تعذر تحديد حالة هذه الإضافة، ربما بسبب خطأ في الإعدادات.",
|
||||
|
||||
"alert.enabled": "الإضافة مفعلة",
|
||||
"alert.disabled": "الإضافة معطلة",
|
||||
"alert.upgraded": "الإضافة مرقاة",
|
||||
"alert.installed": "الإضافة منصبة",
|
||||
"alert.uninstalled": "تم إلغاء تنصيب الإضافة",
|
||||
"alert.activate-success": "يرجى إعادة تشغيل NodeBB لتنشيط الإضافة بشكل بالكامل",
|
||||
"alert.deactivate-success": "تم تعطيل الإضافة بنجاح",
|
||||
"alert.upgrade-success": "Please rebuild and restart your NodeBB to fully upgrade this plugin.",
|
||||
"alert.install-success": "تم تثبيت الإضافة بنجاح، يرجى تفعيلها.",
|
||||
"alert.uninstall-success": "تم تعطيل الإضافة وإلغاء تنصيبها بنجاح.",
|
||||
"alert.enabled": "Plugin Enabled",
|
||||
"alert.disabled": "Plugin Disabled",
|
||||
"alert.upgraded": "Plugin Upgraded",
|
||||
"alert.installed": "Plugin Installed",
|
||||
"alert.uninstalled": "Plugin Uninstalled",
|
||||
"alert.activate-success": "Please restart your NodeBB to fully activate this plugin",
|
||||
"alert.deactivate-success": "Plugin successfully deactivated",
|
||||
"alert.upgrade-success": "Please reload your NodeBB to fully upgrade this plugin",
|
||||
"alert.install-success": "Plugin successfully installed, please activate the plugin.",
|
||||
"alert.uninstall-success": "The plugin has been successfully deactivated and uninstalled.",
|
||||
"alert.suggest-error": "<p>NodeBB could not reach the package manager, proceed with installation of latest version?</p><div class=\"alert alert-danger\"><strong>Server returned (%1)</strong>: %2</div>",
|
||||
"alert.package-manager-unreachable": "<p>NodeBB could not reach the package manager, an upgrade is not suggested at this time.</p>",
|
||||
"alert.incompatible": "<p>Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.</p>",
|
||||
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>",
|
||||
"alert.reorder": "Plugins Re-ordered",
|
||||
"alert.reorder-success": "Please rebuild and restart your NodeBB to fully complete the process.",
|
||||
|
||||
"license.title": "معلومات ترخيص الإضافة",
|
||||
"license.intro": "The plugin <strong>%1</strong> is licensed under the %2. Please read and understand the license terms prior to activating this plugin.",
|
||||
"license.cta": "هل ترغب بالاستمرار في تفعيل هذه الإضافة؟"
|
||||
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"available": "Available Widgets",
|
||||
"explanation": "Select a widget from the dropdown menu and then drag and drop it into a template's widget area on the left.",
|
||||
"none-installed": "No widgets found! Activate the essential widgets plugin in the <a href=\"%1\">plugins</a> control panel.",
|
||||
"clone-from": "Clone widgets from",
|
||||
"containers.available": "Available Containers",
|
||||
"containers.explanation": "Drag and drop on top of any active widget",
|
||||
"containers.none": "None",
|
||||
@@ -15,8 +14,6 @@
|
||||
|
||||
"alert.confirm-delete": "Are you sure you wish to delete this widget?",
|
||||
"alert.updated": "Widgets Updated",
|
||||
"alert.update-success": "Successfully updated widgets",
|
||||
"alert.clone-success": "Successfully cloned widgets",
|
||||
"alert.update-success": "Successfully updated widgets"
|
||||
|
||||
"error.select-clone": "Please select a page to clone from"
|
||||
}
|
||||
@@ -1,76 +1,64 @@
|
||||
{
|
||||
"forum-traffic": "Forum Traffic",
|
||||
"page-views": "مشاهدات الصفحات",
|
||||
"unique-visitors": "زائرين فريدين",
|
||||
"users": "أعضاء",
|
||||
"posts": "مشاركات",
|
||||
"topics": "مواضيع",
|
||||
"page-views-seven": "آخر 7 ايام",
|
||||
"page-views-thirty": "آخر 30 يوماً",
|
||||
"page-views-last-day": "آخر 24 ساعة",
|
||||
"page-views-custom": "مدة زمنية مخصصة",
|
||||
"page-views-custom-start": "بداية المدة",
|
||||
"page-views-custom-end": "نهاية المده",
|
||||
"page-views-custom-help": "أدخل نطاقا زمنيا لمرات مشاهدة الصفحات التي ترغب في عرضها. إذا لم يظهر منتقي التاريخ، فإن التنسيق المقبول هو <code>YYYY-MM-DD</code>",
|
||||
"page-views-custom-error": "الرجاء إدخال نطاق تاريخ صالح بالتنسيق <code>YYYY-MM-DD</code>",
|
||||
"page-views": "Page Views",
|
||||
"unique-visitors": "Unique Visitors",
|
||||
"users": "Users",
|
||||
"posts": "Posts",
|
||||
"topics": "Topics",
|
||||
"page-views-last-month": "Page views Last Month",
|
||||
"page-views-this-month": "Page views This Month",
|
||||
"page-views-last-day": "Page views in last 24 hours",
|
||||
|
||||
"stats.day": "يوم",
|
||||
"stats.week": "إسبوع",
|
||||
"stats.month": "شهر",
|
||||
"stats.all": "كل الوقت",
|
||||
"stats.day": "Day",
|
||||
"stats.week": "Week",
|
||||
"stats.month": "Month",
|
||||
"stats.all": "All Time",
|
||||
|
||||
"updates": "Updates",
|
||||
"running-version": "You are running <strong>NodeBB v<span id=\"version\">%1</span></strong>.",
|
||||
"keep-updated": "Always make sure that your NodeBB is up to date for the latest security patches and bug fixes.",
|
||||
"up-to-date": "<p>You are <strong>up-to-date</strong> <i class=\"fa fa-check\"></i></p>",
|
||||
"upgrade-available": "<p>A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-upgrade-available": "<p>This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-warning": "<p>This is a <strong>pre-release</strong> version of NodeBB. Unintended bugs may occur. <i class=\"fa fa-exclamation-triangle\"></i></p>",
|
||||
"running-in-development": "<span>Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator.</span>",
|
||||
|
||||
"updates": "تحديثات",
|
||||
"running-version": "المنتدى يعمل حاليا على <strong>NodeBB الإصدار<span id=\"version\">%1</span></strong>.",
|
||||
"keep-updated": "تأكد دائما من أن NodeBB يعمل على احدث إصدار للحصول على أحدث التصحيحات الأمنية وإصلاحات الأخطاء.",
|
||||
"up-to-date": "<p>المنتدى <strong>يعمل على أحدث إصدار</strong> <i class=\"fa fa-check\"></i></p>",
|
||||
"upgrade-available": "<p>A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-upgrade-available": "<p>This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-warning": "<p>هذه نسخة <strong>ماقبل الإصدار</strong> من NodeBB. قد تحدث أخطاء غير مقصودة. <i class=\"fa fa-exclamation-triangle\"></i></p>",
|
||||
"running-in-development": "المنتدى قيد التشغيل في وضع \"المطورين\". وقد تكون هناك ثغرات أمنية مفتوحة؛ من فضلك تواصل مع مسؤول نظامك.",
|
||||
"latest-lookup-failed": "<p>Failed to look up latest available version of NodeBB</p>",
|
||||
"notices": "Notices",
|
||||
"restart-not-required": "Restart not required",
|
||||
"restart-required": "Restart required",
|
||||
"search-plugin-installed": "Search Plugin installed",
|
||||
"search-plugin-not-installed": "Search Plugin not installed",
|
||||
"search-plugin-tooltip": "Install a search plugin from the plugin page in order to activate search functionality",
|
||||
|
||||
"notices": "إشعارات",
|
||||
"restart-not-required": "إعادة التشغيل غير مطلوب",
|
||||
"restart-required": "إعادة التشغيل مطلوبة",
|
||||
"search-plugin-installed": "إضافة البحث منصبة",
|
||||
"search-plugin-not-installed": "إضافة البحث غير منصبة",
|
||||
"search-plugin-tooltip": "نصب إضافة البحث من صفحة الإضافات البرمجية لتنشيط وظيفة البحث",
|
||||
|
||||
"control-panel": "التحكم بالنظام",
|
||||
"rebuild-and-restart": "Rebuild & Restart",
|
||||
"control-panel": "System Control",
|
||||
"reload": "Reload",
|
||||
"restart": "Restart",
|
||||
"restart-warning": "Rebuilding or Restarting your NodeBB will drop all existing connections for a few seconds.",
|
||||
"restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.",
|
||||
"maintenance-mode": "وضع الصيانة",
|
||||
"maintenance-mode-title": "انقر هنا لإعداد وضع الصيانة لـNodeBB",
|
||||
"realtime-chart-updates": "التحديث الفوري للرسم البياني",
|
||||
"restart-warning": "Reloading or Restarting your NodeBB will drop all existing connections for a few seconds.",
|
||||
"maintenance-mode": "Maintenance Mode",
|
||||
"maintenance-mode-title": "Click here to set up maintenance mode for NodeBB",
|
||||
"realtime-chart-updates": "Realtime Chart Updates",
|
||||
|
||||
"active-users": "المستخدمين النشطين",
|
||||
"active-users.users": "الأعضاء",
|
||||
"active-users.guests": "الزوار",
|
||||
"active-users.total": "المجموع",
|
||||
"active-users": "Active Users",
|
||||
"active-users.users": "Users",
|
||||
"active-users.guests": "Guests",
|
||||
"active-users.total": "Total",
|
||||
"active-users.connections": "Connections",
|
||||
|
||||
"anonymous-registered-users": "المجهولين مقابل المستخدمين المسجلين",
|
||||
"anonymous": "مجهول",
|
||||
"registered": "مسجل",
|
||||
"anonymous-registered-users": "Anonymous vs Registered Users",
|
||||
"anonymous": "Anonymous",
|
||||
"registered": "Registered",
|
||||
|
||||
"user-presence": "تواجد المستخدمين",
|
||||
"on-categories": "في قائمة الأقسام",
|
||||
"reading-posts": "قراءة المشاركات",
|
||||
"browsing-topics": "تصفح المواضيع",
|
||||
"recent": "الأخيرة",
|
||||
"unread": "غير مقروء",
|
||||
"user-presence": "User Presence",
|
||||
"on-categories": "On categories list",
|
||||
"reading-posts": "Reading posts",
|
||||
"browsing-topics": "Browsing topics",
|
||||
"recent": "Recent",
|
||||
"unread": "Unread",
|
||||
|
||||
"high-presence-topics": "مواضيع ذات حضور قوي",
|
||||
"high-presence-topics": "High Presence Topics",
|
||||
|
||||
"graphs.page-views": "مشاهدات الصفحة",
|
||||
"graphs.page-views-registered": "Page Views Registered",
|
||||
"graphs.page-views-guest": "Page Views Guest",
|
||||
"graphs.page-views-bot": "Page Views Bot",
|
||||
"graphs.unique-visitors": "زوار فريدين",
|
||||
"graphs.registered-users": "مستخدمين مسجلين",
|
||||
"graphs.anonymous-users": "مستخدمين مجهولين",
|
||||
"last-restarted-by": "Last restarted by",
|
||||
"no-users-browsing": "No users browsing"
|
||||
"graphs.page-views": "Page Views",
|
||||
"graphs.unique-visitors": "Unique Visitors",
|
||||
"graphs.registered-users": "Registered Users",
|
||||
"graphs.anonymous-users": "Anonymous Users"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,5 @@
|
||||
"description": "Choose what page is shown when users navigate to the root URL of your forum.",
|
||||
"home-page-route": "Home Page Route",
|
||||
"custom-route": "Custom Route",
|
||||
"allow-user-home-pages": "Allow User Home Pages",
|
||||
"home-page-title": "Title of the home page (default \"Home\")"
|
||||
"allow-user-home-pages": "Allow User Home Pages"
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"language-settings": "اعدادات اللغة",
|
||||
"description": "تُحدد اللغة الافتراضية إعدادات اللغة لجميع المستخدمين الذين يزورون المنتدى. <br />يمكن للأعضاء تجاوز اللغة الافتراضية من خلال صفحة إعدادات الحساب الخاصة بهم.",
|
||||
"default-language": "اللغة الافتراضية",
|
||||
"auto-detect": "الكشف عن إعدادات اللغة للزوار بشكل آلي"
|
||||
"language-settings": "Language Settings",
|
||||
"description": "The default language determines the language settings for all users who are visiting your forum. <br />Individual users can override the default language on their account settings page.",
|
||||
"default-language": "Default Language"
|
||||
}
|
||||
@@ -8,9 +8,14 @@
|
||||
"id": "ID: <small>optional</small>",
|
||||
|
||||
"properties": "Properties:",
|
||||
"groups": "Groups:",
|
||||
"only-admins": "Only display to Admins",
|
||||
"only-global-mods-and-admins": "Only display to Global Moderators and Admins",
|
||||
"only-logged-in": "Only display to logged in users",
|
||||
"open-new-window": "Open in a new window",
|
||||
|
||||
"installed-plugins-required": "Installed Plugins Required:",
|
||||
"search-plugin": "Search plugin",
|
||||
|
||||
"btn.delete": "Delete",
|
||||
"btn.disable": "Disable",
|
||||
"btn.enable": "Enable",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"notifications": "التنبيهات",
|
||||
"notifications": "Notifications",
|
||||
"chat-messages": "Chat Messages",
|
||||
"play-sound": "Play",
|
||||
"incoming-message": "Incoming Message",
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"administrators": "Administrators",
|
||||
"global-moderators": "Global Moderators",
|
||||
"no-global-moderators": "No Global Moderators",
|
||||
"moderators-of-category": "%1 Moderators",
|
||||
"no-moderators": "No Moderators",
|
||||
"add-administrator": "Add Administrator",
|
||||
"add-global-moderator": "Add Global Moderator",
|
||||
"add-moderator": "Add Moderator"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"settings": "اعدادات القسم",
|
||||
"privileges": "الصلاحيات",
|
||||
"settings": "Category Settings",
|
||||
"privileges": "Privileges",
|
||||
|
||||
"name": "Category Name",
|
||||
"description": "Category Description",
|
||||
@@ -10,7 +10,6 @@
|
||||
"custom-class": "Custom Class",
|
||||
"num-recent-replies": "# of Recent Replies",
|
||||
"ext-link": "External Link",
|
||||
"is-section": "Treat this category as a section",
|
||||
"upload-image": "Upload Image",
|
||||
"delete-image": "Remove",
|
||||
"category-image": "Category Image",
|
||||
@@ -19,7 +18,6 @@
|
||||
"parent-category-none": "(None)",
|
||||
"copy-settings": "Copy Settings From",
|
||||
"optional-clone-settings": "(Optional) Clone Settings From Category",
|
||||
"clone-children": "Clone Children Categories And Settings",
|
||||
"purge": "Purge Category",
|
||||
|
||||
"enable": "Enable",
|
||||
@@ -29,8 +27,7 @@
|
||||
"select-category": "Select Category",
|
||||
"set-parent-category": "Set Parent Category",
|
||||
|
||||
"privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. Select the domain of effect from the dropdown below.",
|
||||
"privileges.category-selector": "Configuring privileges for ",
|
||||
"privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. You can add a new user to this table by searching for them in the form below.",
|
||||
"privileges.warning": "<strong>Note</strong>: Privilege settings take effect immediately. It is not necessary to save the category after adjusting these settings.",
|
||||
"privileges.section-viewing": "Viewing Privileges",
|
||||
"privileges.section-posting": "Posting Privileges",
|
||||
@@ -67,8 +64,5 @@
|
||||
"alert.find-user": "Find a User",
|
||||
"alert.user-search": "Search for a user here...",
|
||||
"alert.find-group": "Find a Group",
|
||||
"alert.group-search": "Search for a group here...",
|
||||
"collapse-all": "Collapse All",
|
||||
"expand-all": "Expand All",
|
||||
"disable-on-create": "Disable on create"
|
||||
"alert.group-search": "Search for a group here..."
|
||||
}
|
||||
19
public/language/ar/admin/manage/flags.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"daily": "Daily flags",
|
||||
"by-user": "Flags by user",
|
||||
"by-user-search": "Search flagged posts by username",
|
||||
"category": "Category",
|
||||
"sort-by": "Sort By",
|
||||
"sort-by.most-flags": "Most Flags",
|
||||
"sort-by.most-recent": "Most Recent",
|
||||
"search": "Search",
|
||||
"dismiss-all": "Dismiss All",
|
||||
"none-flagged": "No flagged posts!",
|
||||
"posted-in": "Posted in %1",
|
||||
"read-more": "Read More",
|
||||
"flagged-x-times": "This post has been flagged %1 time(s):",
|
||||
"dismiss": "Dismiss this Flag",
|
||||
"delete-post": "Delete the Post",
|
||||
|
||||
"alerts.confirm-delete-post": "Do you really want to delete this post?"
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "اسم المجموعة",
|
||||
"name": "Group Name",
|
||||
"description": "Group Description",
|
||||
"member-count": "Member Count",
|
||||
"system": "System Group",
|
||||
"edit": "Edit",
|
||||
"search-placeholder": "Search",
|
||||
|
||||
@@ -11,9 +11,5 @@
|
||||
"validate.x-valid": "<strong>%1</strong> out of <strong>%2</strong> rule(s) valid.",
|
||||
"validate.x-invalid": "The following <strong>%1</strong> rules are invalid:",
|
||||
|
||||
"alerts.applied-success": "Blacklist Applied",
|
||||
|
||||
"analytics.blacklist-hourly": "<strong>Figure 1</strong> – Blacklist hits per hour",
|
||||
"analytics.blacklist-daily": "<strong>Figure 2</strong> – Blacklist hits per day",
|
||||
"ip-banned": "IP banned"
|
||||
"alerts.applied-success": "Blacklist Applied"
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"post-queue": "Post Queue",
|
||||
"description": "There are no posts in the post queue. <br> To enable this feature, go to <a href=\"%1\">Settings → Post → Posting Restrictions</a> and enable <strong>Post Queue</strong>.",
|
||||
"user": "User",
|
||||
"category": "Category",
|
||||
"title": "Title",
|
||||
"content": "Content",
|
||||
"posted": "Posted",
|
||||
"reply-to": "Reply to \"%1\"",
|
||||
"content-editable": "You can click on individual content to edit before posting."
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"global": "Global",
|
||||
"global.no-users": "No user-specific global privileges.",
|
||||
|
||||
"chat": "Chat",
|
||||
"upload-images": "Upload Images",
|
||||
"upload-files": "Upload Files",
|
||||
"signature": "Signature",
|
||||
"ban": "Ban",
|
||||
"search-content": "Search Content",
|
||||
"search-users": "Search Users",
|
||||
"search-tags": "Search Tags",
|
||||
"allow-local-login": "Local Login",
|
||||
|
||||
"find-category": "Find Category",
|
||||
"access-category": "Access Category",
|
||||
"access-topics": "Access Topics",
|
||||
"create-topics": "Create Topics",
|
||||
"reply-to-topics": "Reply to Topics",
|
||||
"tag-topics": "Tag Topics",
|
||||
"edit-posts": "Edit Posts",
|
||||
"view-edit-history": "View Edit History",
|
||||
"delete-posts": "Delete Posts",
|
||||
"view_deleted": "View Deleted Posts",
|
||||
"upvote-posts": "Upvote Posts",
|
||||
"downvote-posts": "Downvote Posts",
|
||||
"delete-topics": "Delete Topics",
|
||||
"purge": "Purge",
|
||||
"moderate": "Moderate"
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
"description": "Select tags via clicking and/or dragging, use shift to select multiple.",
|
||||
"create": "Create Tag",
|
||||
"modify": "Modify Tags",
|
||||
"rename": "Rename Tags",
|
||||
"delete": "Delete Selected Tags",
|
||||
"search": "Search for tags...",
|
||||
"settings": "Click <a href=\"%1\">here</a> to visit the tag settings page.",
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"upload-file": "Upload File",
|
||||
"filename": "Filename",
|
||||
"usage": "Post Usage",
|
||||
"orphaned": "Orphaned",
|
||||
"size/filecount": "Size / Filecount",
|
||||
"confirm-delete": "Do you really want to delete this file?",
|
||||
"filecount": "%1 files"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"users": "المستخدمين",
|
||||
"edit": "تحرير",
|
||||
"users": "Users",
|
||||
"edit": "Edit",
|
||||
"make-admin": "Make Admin",
|
||||
"remove-admin": "Remove Admin",
|
||||
"validate-email": "Validate Email",
|
||||
@@ -27,8 +27,6 @@
|
||||
"pills.banned": "Banned",
|
||||
"pills.search": "User Search",
|
||||
|
||||
"search.uid": "By User ID",
|
||||
"search.uid-placeholder": "Enter a user ID to search",
|
||||
"search.username": "By User Name",
|
||||
"search.username-placeholder": "Enter a username to search",
|
||||
"search.email": "By Email",
|
||||
@@ -71,15 +69,9 @@
|
||||
"alerts.lockout-reset-success": "Lockout(s) reset!",
|
||||
"alerts.flag-reset-success": "Flags(s) reset!",
|
||||
"alerts.no-remove-yourself-admin": "You can't remove yourself as Administrator!",
|
||||
"alerts.make-admin-success": "User is now administrator.",
|
||||
"alerts.confirm-remove-admin": "Do you really want to remove this administrator?",
|
||||
"alerts.remove-admin-success": "User is no longer administrator.",
|
||||
"alerts.make-global-mod-success": "User is now global moderator.",
|
||||
"alerts.confirm-remove-global-mod": "Do you really want to remove this global moderator?",
|
||||
"alerts.remove-global-mod-success": "User is no longer global moderator.",
|
||||
"alerts.make-moderator-success": "User is now moderator.",
|
||||
"alerts.confirm-remove-moderator": "Do you really want to remove this moderator?",
|
||||
"alerts.remove-moderator-success": "User is no longer moderator.",
|
||||
"alerts.make-admin-success": "User(s) are now administrators.",
|
||||
"alerts.confirm-remove-admin": "Do you really want to remove admins?",
|
||||
"alerts.remove-admin-success": "User(s) are no longer administrators.",
|
||||
"alerts.confirm-validate-email": "Do you want to validate email(s) of these user(s)?",
|
||||
"alerts.validate-email-success": "Emails validated",
|
||||
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
|
||||
@@ -93,7 +85,7 @@
|
||||
"alerts.error-x": "<strong>Error</strong><p>%1</p>",
|
||||
"alerts.create-success": "User created!",
|
||||
|
||||
"alerts.prompt-email": "Emails: ",
|
||||
"alerts.prompt-email": "Email: ",
|
||||
"alerts.email-sent-to": "An invitation email has been sent to %1",
|
||||
"alerts.x-users-found": "%1 user(s) found! Search took %2 ms."
|
||||
}
|
||||
@@ -1,37 +1,33 @@
|
||||
{
|
||||
"section-general": "عام",
|
||||
"general/dashboard": "اللوحة الرئيسية",
|
||||
"general/homepage": "الصفحة الرئيسية",
|
||||
"general/navigation": "التصفح",
|
||||
"general/languages": "اللغات",
|
||||
"general/sounds": "الأصوات",
|
||||
"general/social": "شبكات التواصل",
|
||||
"section-general": "General",
|
||||
"general/dashboard": "Dashboard",
|
||||
"general/homepage": "Home Page",
|
||||
"general/navigation": "Navigation",
|
||||
"general/languages": "Languages",
|
||||
"general/sounds": "Sounds",
|
||||
"general/social": "Social",
|
||||
|
||||
"section-manage": "إدارة",
|
||||
"manage/categories": "الأقسام",
|
||||
"manage/privileges": "Privileges",
|
||||
"manage/tags": "الكلمات المفتاحية",
|
||||
"manage/users": "الأعضاء",
|
||||
"manage/admins-mods": "Admins & Mods",
|
||||
"manage/registration": "قائمة انتظار التسجيل",
|
||||
"manage/post-queue": "قائمة انتظار المشاركة",
|
||||
"manage/groups": "المجموعات",
|
||||
"manage/ip-blacklist": "قائمة حظر عناوين IP",
|
||||
"manage/uploads": "Uploads",
|
||||
"section-manage": "Manage",
|
||||
"manage/categories": "Categories",
|
||||
"manage/tags": "Tags",
|
||||
"manage/users": "Users",
|
||||
"manage/registration": "Registration Queue",
|
||||
"manage/groups": "Groups",
|
||||
"manage/ip-blacklist": "IP Blacklist",
|
||||
|
||||
"section-settings": "إعدادات",
|
||||
"settings/general": "عامة",
|
||||
"settings/reputation": "السمعة",
|
||||
"settings/email": "البريد الإلكتروني",
|
||||
"settings/user": "الأعضاء",
|
||||
"settings/group": "المجموعات",
|
||||
"settings/guest": "الزوار",
|
||||
"settings/uploads": "الرفع",
|
||||
"settings/post": "المشاركة",
|
||||
"settings/chat": "الدردشة",
|
||||
"settings/pagination": "ترقيم الصفحات",
|
||||
"settings/tags": "الكلمات المفتاحية",
|
||||
"settings/notifications": "التنبيهات",
|
||||
"section-settings": "Settings",
|
||||
"settings/general": "General",
|
||||
"settings/reputation": "Reputation",
|
||||
"settings/email": "Email",
|
||||
"settings/user": "User",
|
||||
"settings/group": "Group",
|
||||
"settings/guest": "Guests",
|
||||
"settings/uploads": "Uploads",
|
||||
"settings/post": "Post",
|
||||
"settings/chat": "Chat",
|
||||
"settings/pagination": "Pagination",
|
||||
"settings/tags": "Tags",
|
||||
"settings/notifications": "Notifications",
|
||||
"settings/cookies": "Cookies",
|
||||
"settings/web-crawler": "Web Crawler",
|
||||
"settings/sockets": "Sockets",
|
||||
@@ -42,7 +38,7 @@
|
||||
"section-appearance": "Appearance",
|
||||
"appearance/themes": "Themes",
|
||||
"appearance/skins": "Skins",
|
||||
"appearance/customise": "Custom Content (HTML/JS/CSS)",
|
||||
"appearance/customise": "Custom HTML & CSS",
|
||||
|
||||
"section-extend": "Extend",
|
||||
"extend/plugins": "Plugins",
|
||||
@@ -57,26 +53,22 @@
|
||||
"section-advanced": "Advanced",
|
||||
"advanced/database": "Database",
|
||||
"advanced/events": "Events",
|
||||
"advanced/hooks": "Hooks",
|
||||
"advanced/logs": "Logs",
|
||||
"advanced/errors": "Errors",
|
||||
"advanced/cache": "Cache",
|
||||
"development/logger": "Logger",
|
||||
"development/info": "Info",
|
||||
|
||||
"rebuild-and-restart-forum": "Rebuild & Restart Forum",
|
||||
"reload-forum": "Reload Forum",
|
||||
"restart-forum": "Restart Forum",
|
||||
"logout": "Log out",
|
||||
"view-forum": "View Forum",
|
||||
|
||||
"search.placeholder": "Search for settings",
|
||||
"search.placeholder": "Search...",
|
||||
"search.no-results": "No results...",
|
||||
"search.search-forum": "Search the forum for <strong></strong>",
|
||||
"search.keep-typing": "Type more to see results...",
|
||||
"search.start-typing": "Start typing to see results...",
|
||||
|
||||
"connection-lost": "Connection to %1 has been lost, attempting to reconnect...",
|
||||
|
||||
"alerts.version": "Running <strong>NodeBB v%1</strong>",
|
||||
"alerts.upgrade": "Upgrade to v%1"
|
||||
"connection-lost": "Connection to %1 has been lost, attempting to reconnect..."
|
||||
}
|
||||
@@ -6,17 +6,9 @@
|
||||
"headers.allow-from": "Set ALLOW-FROM to Place NodeBB in an iFrame",
|
||||
"headers.powered-by": "Customise the \"Powered By\" header sent by NodeBB",
|
||||
"headers.acao": "Access-Control-Allow-Origin",
|
||||
"headers.acao-regex": "Access-Control-Allow-Origin Regular Expression",
|
||||
"headers.acao-help": "To deny access to all sites, leave empty",
|
||||
"headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty",
|
||||
"headers.acac": "Access-Control-Allow-Credentials",
|
||||
"headers.acao-help": "To deny access to all sites, leave empty or set to <code>null</code>",
|
||||
"headers.acam": "Access-Control-Allow-Methods",
|
||||
"headers.acah": "Access-Control-Allow-Headers",
|
||||
"hsts": "Strict Transport Security",
|
||||
"hsts.enabled": "Enabled HSTS (recommended)",
|
||||
"hsts.subdomains": "Include subdomains in HSTS header",
|
||||
"hsts.preload": "Allow preloading of HSTS header",
|
||||
"hsts.help": "If enabled, an HSTS header will be set for this site. You can elect to include subdomains and preloading flags in your header. If in doubt, you can leave these unchecked. <a href=\"%1\">More information <i class=\"fa fa-external-link\"></i></a>",
|
||||
"traffic-management": "Traffic Management",
|
||||
"traffic.help": "NodeBB deploys equipped with a module that automatically denies requests in high-traffic situations. You can tune these settings here, although the defaults are a good starting point.",
|
||||
"traffic.enable": "Enable Traffic Management",
|
||||
|
||||
@@ -5,7 +5,5 @@
|
||||
"disable-editing-help": "Administrators and global moderators are exempt from this restriction",
|
||||
"max-length": "Maximum length of chat messages",
|
||||
"max-room-size": "Maximum number of users in chat rooms",
|
||||
"delay": "Time between chat messages in milliseconds",
|
||||
"restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit chat messages after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete chat messages after posting. (0 disabled)"
|
||||
"delay": "Time between chat messages in milliseconds"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"eu-consent": "EU Consent",
|
||||
"consent.enabled": "تفعيل",
|
||||
"consent.enabled": "Enabled",
|
||||
"consent.message": "Notification message",
|
||||
"consent.acceptance": "Acceptance message",
|
||||
"consent.link-text": "Policy Link Text",
|
||||
|
||||
@@ -4,25 +4,13 @@
|
||||
"address-help": "The following email address refers to the email that the recipient will see in the \"From\" and \"Reply To\" fields.",
|
||||
"from": "From Name",
|
||||
"from-help": "The from name to display in the email.",
|
||||
|
||||
"smtp-transport": "SMTP Transport",
|
||||
"smtp-transport.enabled": "Use an external email server to send emails",
|
||||
"smtp-transport-help": "You can select from a list of well-known services or enter a custom one.",
|
||||
"smtp-transport.service": "Select a service",
|
||||
"smtp-transport.service-custom": "Custom Service",
|
||||
"smtp-transport.service-help": "Select a service name above in order to use the known information about it. Alternatively, select 'Custom Service' and enter the details below.",
|
||||
"smtp-transport.gmail-warning1": "There have been reports of the Gmail service not working on accounts with heightened security. In those scenarios, you will have to <a href=\"https://www.google.com/settings/security/lesssecureapps\">configure your GMail account to allow less secure apps</a>.",
|
||||
"smtp-transport.gmail-warning2": "For more information about this workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">please consult this NodeMailer article on the issue.</a> An alternative would be to utilise a third-party emailer plugin such as SendGrid, Mailgun, etc. <a href=\"../extend/plugins\">Browse available plugins here</a>.",
|
||||
"smtp-transport.host": "SMTP Host",
|
||||
"smtp-transport.port": "SMTP Port",
|
||||
"smtp-transport.security": "Connection security",
|
||||
"smtp-transport.security-encrypted": "Encrypted",
|
||||
"smtp-transport.security-starttls": "StartTLS",
|
||||
"smtp-transport.security-none": "None",
|
||||
"smtp-transport.username": "Username",
|
||||
"smtp-transport.username-help": "<b>For the Gmail service,</b> enter the full email address here, especially if you are using a Google Apps managed domain.",
|
||||
"smtp-transport.password": "Password",
|
||||
|
||||
"gmail-routing": "Gmail Routing",
|
||||
"gmail-routing-help1": "There have been reports of Gmail Routing not working on accounts with heightened security. In those scenarios, you will have to <a href=\"https://www.google.com/settings/security/lesssecureapps\">configure your GMail account to allow less secure apps</a>.",
|
||||
"gmail-routing-help2": "For more information about this workaround, <a href=\"https://nodemailer.com/using-gmail/\">please consult this NodeMailer article on the issue.</a> An alternative would be to utilise a third-party emailer plugin such as SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Browse available plugins here</a>.",
|
||||
"gmail-transport": "Route emails through a Gmail/Google Apps account",
|
||||
"gmail-transport.username": "Username",
|
||||
"gmail-transport.username-help": "Enter the full email address here, especially if you are using a Google Apps managed domain.",
|
||||
"gmail-transport.password": "Password",
|
||||
"template": "Edit Email Template",
|
||||
"template.select": "Select Email Template",
|
||||
"template.revert": "Revert to Original",
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"site-settings": "Site Settings",
|
||||
"title": "Site Title",
|
||||
"title.url": "URL",
|
||||
"title.url-placeholder": "The URL of the site title",
|
||||
"title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index.",
|
||||
"title.name": "Your Community Name",
|
||||
"title.show-in-header": "Show Site Title in Header",
|
||||
"browser-title": "Browser Title",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"private-groups.warning": "<strong>Beware!</strong> If this option is disabled and you have private groups, they automatically become public.",
|
||||
"allow-creation": "Allow Group Creation",
|
||||
"allow-creation-help": "If enabled, users can create groups <em>(Default: disabled)</em>",
|
||||
"allow-multiple-badges-help": "This flag can be used to allow users to select multiple group badges, requires theme support.",
|
||||
"max-name-length": "Maximum Group Name Length",
|
||||
"cover-image": "Group Cover Image",
|
||||
"default-cover": "Default Cover Images",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"handles": "Guest Handles",
|
||||
"handles.enabled": "Allow guest handles",
|
||||
"handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\""
|
||||
"handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"",
|
||||
"privileges": "Guest Privileges",
|
||||
"privileges.can-search": "Allow guests to search without logging in",
|
||||
"privileges.can-search-users": "Allow guests to search users without logging in"
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"notifications": "Notifications",
|
||||
"welcome-notification": "Welcome Notification",
|
||||
"welcome-notification-link": "Welcome Notification Link",
|
||||
"welcome-notification-uid": "Welcome Notification User (UID)",
|
||||
"notification-alert-timeout": "Notification Alert Timeout"
|
||||
"welcome-notification-link": "Welcome Notification Link"
|
||||
}
|
||||
@@ -3,8 +3,7 @@
|
||||
"enable": "Paginate topics and posts instead of using infinite scroll.",
|
||||
"topics": "Topic Pagination",
|
||||
"posts-per-page": "Posts per Page",
|
||||
"max-posts-per-page": "Maximum posts per page",
|
||||
"categories": "Category Pagination",
|
||||
"topics-per-page": "Topics per Page",
|
||||
"max-topics-per-page": "Maximum topics per page"
|
||||
"initial-num-load": "Initial Number of Topics to Load on Unread, Recent, and Popular"
|
||||
}
|
||||
@@ -4,27 +4,20 @@
|
||||
"sorting.oldest-to-newest": "Oldest to Newest",
|
||||
"sorting.newest-to-oldest": "Newest to Oldest",
|
||||
"sorting.most-votes": "Most Votes",
|
||||
"sorting.most-posts": "Most Posts",
|
||||
"sorting.topic-default": "Default Topic Sorting",
|
||||
"length": "Post Length",
|
||||
"restrictions": "Posting Restrictions",
|
||||
"restrictions-new": "New User Restrictions",
|
||||
"restrictions.post-queue": "Enable post queue",
|
||||
"restrictions-new.post-queue": "Enable new user restrictions",
|
||||
"restrictions.post-queue-help": "Enabling post queue will put the posts of new users in a queue for approval.",
|
||||
"restrictions-new.post-queue-help": "Enabling new user restrictions will set restrictions on posts created by new users.",
|
||||
"restrictions.seconds-between": "Seconds between posts",
|
||||
"restrictions.seconds-between-new": "Seconds between posts for new users",
|
||||
"restrictions.rep-threshold": "Reputation threshold before these restrictions are lifted",
|
||||
"restrictions.seconds-between": "Seconds between Posts",
|
||||
"restrictions.seconds-between-new": "Seconds between Posts for New Users",
|
||||
"restrictions.rep-threshold": "Reputation threshold before this restriction is lifted",
|
||||
"restrictions.seconds-defore-new": "Seconds before new user can post",
|
||||
"restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-edit-after": "Number of seconds users are allowed to edit posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds users are allowed to delete posts after posting. (0 disabled)",
|
||||
"restrictions.replies-no-delete": "Number of replies after users are disallowed to delete their own topics. (0 disabled)",
|
||||
"restrictions.min-title-length": "Minimum Title Length",
|
||||
"restrictions.max-title-length": "Maximum Title Length",
|
||||
"restrictions.min-post-length": "Minimum Post Length",
|
||||
"restrictions.max-post-length": "Maximum Post Length",
|
||||
"restrictions.days-until-stale": "Days until topic is considered stale",
|
||||
"restrictions.days-until-stale": "Days until Topic is considered stale",
|
||||
"restrictions.stale-help": "If a topic is considered \"stale\", then a warning will be shown to users who attempt to reply to that topic.",
|
||||
"timestamp": "Timestamp",
|
||||
"timestamp.cut-off": "Date cut-off (in days)",
|
||||
@@ -36,8 +29,6 @@
|
||||
"unread": "Unread Settings",
|
||||
"unread.cutoff": "Unread cutoff days",
|
||||
"unread.min-track-last": "Minimum posts in topic before tracking last read",
|
||||
"recent": "Recent Settings",
|
||||
"recent.categoryFilter.disable": "Disable filtering of topics in ignored categories on the /recent page",
|
||||
"signature": "Signature Settings",
|
||||
"signature.disable": "Disable signatures",
|
||||
"signature.no-links": "Disable links in signatures",
|
||||
@@ -49,6 +40,5 @@
|
||||
"composer.enable-plugin-help": "Allow plugins to add content to the help tab",
|
||||
"composer.custom-help": "Custom Help Text",
|
||||
"ip-tracking": "IP Tracking",
|
||||
"ip-tracking.each-post": "Track IP Address for each post",
|
||||
"enable-post-history": "Enable Post History"
|
||||
"ip-tracking.each-post": "Track IP Address for each post"
|
||||
}
|
||||
@@ -5,10 +5,5 @@
|
||||
"votes-are-public": "All Votes Are Public",
|
||||
"thresholds": "Activity Thresholds",
|
||||
"min-rep-downvote": "Minimum reputation to downvote posts",
|
||||
"min-rep-flag": "Minimum reputation to flag posts",
|
||||
"min-rep-website": "Minimum reputation to add \"Website\" to user profile",
|
||||
"min-rep-aboutme": "Minimum reputation to add \"About me\" to user profile",
|
||||
"min-rep-signature": "Minimum reputation to add \"Signature\" to user profile",
|
||||
"min-rep-profile-picture": "Minimum reputation to add \"Profile Picture\" to user profile",
|
||||
"min-rep-cover-picture": "Minimum reputation to add \"Cover Picture\" to user profile"
|
||||
"min-rep-flag": "Minimum reputation to flag posts"
|
||||
}
|
||||
@@ -1,38 +1,28 @@
|
||||
{
|
||||
"posts": "المشاركات",
|
||||
"allow-files": "السماح للأعضاء بتحميل الملفات الإعتيادية",
|
||||
"private": "جعل الملفات التي تم رفعها خاصة",
|
||||
"private-extensions": "File extensions to make private",
|
||||
"private-uploads-extensions-help": "Enter comma-separated list of file extensions to make private here (e.g. <code>pdf,xls,doc</code>). An empty list means all files are private.",
|
||||
"resize-image-width-threshold": "Resize images if they are wider than specified width",
|
||||
"resize-image-width-threshold-help": "(in pixels, default: 1520 pixels, set to 0 to disable)",
|
||||
"resize-image-width": "Resize images down to specified width",
|
||||
"resize-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)",
|
||||
"resize-image-quality": "Quality to use when resizing images",
|
||||
"resize-image-quality-help": "Use a lower quality setting to reduce the file size of resized images.",
|
||||
"max-file-size": "الحد الأقصى لحجم الملف (بالكيبيبايت)",
|
||||
"max-file-size-help": "(بالكيبيبايت، الافتراضي: 2048)",
|
||||
"reject-image-width": "Maximum Image Width (in pixels)",
|
||||
"reject-image-width-help": "Images wider than this value will be rejected.",
|
||||
"reject-image-height": "Maximum Image Height (in pixels)",
|
||||
"reject-image-height-help": "Images taller than this value will be rejected.",
|
||||
"allow-topic-thumbnails": "السماح للاعضاء برفع الصور المصغرة للموضوع",
|
||||
"topic-thumb-size": "حجم الصورة المصغرة للموضوع",
|
||||
"allowed-file-extensions": "إمتدادات الملفات المسموح بها",
|
||||
"allowed-file-extensions-help": "أدخل قائمة بامتدادات الملفات مفصولة بفواصل (مثال: <code>pdf,xls,doc</code>). القائمة الفارغة تعني أن كل الامتدادات مسموح بها.",
|
||||
"profile-avatars": "الصورة الرمزية للملف الشخصي",
|
||||
"allow-profile-image-uploads": "السماح للأعضاء برفع الصور الرمزية",
|
||||
"convert-profile-image-png": "تحويل إمتداد الصور الرمزية المرفوعه الى PNG",
|
||||
"default-avatar": "الصورة الرمزية الافتراضية",
|
||||
"upload": "رفع",
|
||||
"profile-image-dimension": "أبعاد الصورة الرمزية",
|
||||
"profile-image-dimension-help": "(بالبكسل، الافتراضي: 128 بكسل)",
|
||||
"max-profile-image-size": "الحد الأقصى لحجم الصورة الرمزية",
|
||||
"max-profile-image-size-help": "(بالكيبيبايت، الافتراضي: 256)",
|
||||
"max-cover-image-size": "الحد الأقصى لحجم صورة الغلاف",
|
||||
"max-cover-image-size-help": "(بالكيبيبايت، الافتراضي: 2,048)",
|
||||
"keep-all-user-images": "الاحتفاظ بالنسخ القديمة من الصور الرمزية وصور الغلاف في السيرفر",
|
||||
"profile-covers": "غلاف الملف الشخصي",
|
||||
"default-covers": "صورة الغلاف الافتراضية",
|
||||
"default-covers-help": "اضف صور الغلاف الافتراضية متبوعة بفواصل لاستخدامها في الحسابات التي لا تحتوي على صور غلاف مرفوعة"
|
||||
"posts": "Posts",
|
||||
"allow-files": "Allow users to upload regular files",
|
||||
"private": "Make uploaded files private",
|
||||
"max-image-width": "Resize images down to specified width (in pixels)",
|
||||
"max-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)",
|
||||
"max-file-size": "Maximum File Size (in KiB)",
|
||||
"max-file-size-help": "(in kilobytes, default: 2048 KiB)",
|
||||
"allow-topic-thumbnails": "Allow users to upload topic thumbnails",
|
||||
"topic-thumb-size": "Topic Thumb Size",
|
||||
"allowed-file-extensions": "Allowed File Extensions",
|
||||
"allowed-file-extensions-help": "Enter comma-separated list of file extensions here (e.g. <code>pdf,xls,doc</code>). An empty list means all extensions are allowed.",
|
||||
"profile-avatars": "Profile Avatars",
|
||||
"allow-profile-image-uploads": "Allow users to upload profile images",
|
||||
"convert-profile-image-png": "Convert profile image uploads to PNG",
|
||||
"default-avatar": "Custom Default Avatar",
|
||||
"upload": "Upload",
|
||||
"profile-image-dimension": "Profile Image Dimension",
|
||||
"profile-image-dimension-help": "(in pixels, default: 128 pixels)",
|
||||
"max-profile-image-size": "Maximum Profile Image File Size",
|
||||
"max-profile-image-size-help": "(in kilobytes, default: 256 KiB)",
|
||||
"max-cover-image-size": "Maximum Cover Image File Size",
|
||||
"max-cover-image-size-help": "(in kilobytes, default: 2,048 KiB)",
|
||||
"keep-all-user-images": "Keep old versions of avatars and profile covers on the server",
|
||||
"profile-covers": "Profile Covers",
|
||||
"default-covers": "Default Cover Images",
|
||||
"default-covers-help": "Add comma-separated default cover images for accounts that don't have an uploaded cover image"
|
||||
}
|
||||
|
||||
@@ -1,64 +1,50 @@
|
||||
{
|
||||
"authentication": "المصادقة",
|
||||
"require-email-confirmation": "يطلب تأكيد البريد الإلكتروني",
|
||||
"email-confirm-interval": "لا يمكن للمستخدم إعادة إرسال رسالة تأكيد البريد الالكتروني حتى مرور",
|
||||
"email-confirm-email2": "دقائق",
|
||||
"allow-login-with": "السماح بتسجيل الدخول باستخدام",
|
||||
"allow-login-with.username-email": "اسم المستخدم أو البريد الالكتروني",
|
||||
"allow-login-with.username": "اسم المستخدم فقط",
|
||||
"allow-login-with.email": "البريد الالكتروني فقط",
|
||||
"account-settings": "إعدادت الحساب",
|
||||
"gdpr_enabled": "Enable GDPR consent collection",
|
||||
"gdpr_enabled_help": "When enabled, all new registrants will be required to explicitly give consent for data collection and usage under the <a href=\"https://eugdpr.org/the-regulation/gdpr-faqs/\">General Data Protection Regulation (GDPR)</a>. <strong>Note</strong>: Enabling GDPR does not force pre-existing users to provide consent. To do so, you will need to install the GDPR plugin.",
|
||||
"disable-username-changes": "عدم السماح بتغيير اسم المستخدم",
|
||||
"disable-email-changes": "عدم السماح بتغيير البريد الالكتروني",
|
||||
"disable-password-changes": "عدم السماح بتغيير كلمة المرور",
|
||||
"allow-account-deletion": "السماح بحذف الحساب",
|
||||
"user-info-private": "إخفاء قائمة المستخدم والبيانات عن الزوار",
|
||||
"hide-fullname": "إخفاء الإسم الكامل عن المستخدمين",
|
||||
"hide-email": "إخفاء البريد الإلكتروني عن المستخدمين",
|
||||
"themes": "القوالب",
|
||||
"disable-user-skins": "منع المستخدمين من اختيار سمة مخصص",
|
||||
"account-protection": "حماية الحساب",
|
||||
"admin-relogin-duration": "المدة حتى طلب إعادة تسجيل الدخول للإدارة (دقائق)",
|
||||
"admin-relogin-duration-help": "بعد مرور وقت معين، يتوجب إعادة تسجيل الدخول للوصول إلى قسم الإدارة، قم بتعيين القيمة الى 0 لتعطيل الخيار",
|
||||
"login-attempts": "عدد محاولات تسجيل الدخول في الساعة",
|
||||
"login-attempts-help": "إذا تجاوزت محاولات تسجيل الدخول لمستخدم معين العدد المحدد، فسوف يتم تأمين الحساب ومنعه من الدخول لمدة من الوقت",
|
||||
"lockout-duration": "مدة تأمين الحساب (دقائق)",
|
||||
"login-days": "عدد الأيام لتذكر جلسات تسجيل دخول المستخدم",
|
||||
"password-expiry-days": "فرض عملية تغيير كلمة المرور بعد مرور عدد محدد من الأيام",
|
||||
"session-time": "Session Time",
|
||||
"session-time-days": "Days",
|
||||
"session-time-seconds": "Seconds",
|
||||
"session-time-help": "These values are used to govern how long a user stays logged in when they check "Remember Me" on login. Note that only one of these values will be used. If there is no <i>seconds</i> value we fall back to <i>days</i>. If there is no <i>days</i> value we default to <i>14 days</i>.",
|
||||
"online-cutoff": "Minutes after user is considered inactive",
|
||||
"online-cutoff-help": "If user performs no actions for this duration, they are considered inactive and they do not receive realtime updates.",
|
||||
"registration": "تسجيل المستخدم",
|
||||
"registration-type": "نوع التسجيل",
|
||||
"registration-type.normal": "عادي",
|
||||
"registration-type.admin-approval": "بموافقة الإدارة",
|
||||
"registration-type.admin-approval-ip": "بموافقة الإدارة لعناوين IP",
|
||||
"registration-type.invite-only": "بالدعوات فقط",
|
||||
"registration-type.admin-invite-only": "بالدعوات من قبل الإدارة فقط",
|
||||
"registration-type.disabled": "لا يوجد تسجيل",
|
||||
"registration-type.help": "عادي - بإمكان المستخدمين التسجيل من خلال صفحة /التسجيل.<br/>\nبموافقة الإدارة - يتم وضع قائمة تسجيلات المستخدمين في <a href=\"%1/admin/manage/registration\">قائمة إنتظار موافقة</a> الإدارة.<br/>\nبموافقة الإدارة لعناوين IP - عادي بالنسبة للمستخدمين الجدد، ويتطلب موافقة الإدارة للتسجيل من عناوين IP تم التسجيل بإستخدامها مسبقاً.<br/>\nبالدعوات فقط - بإمكان المستخدمين إرسال دعوات من خلال صفحة <a href=\"%1/users\" target=\"_blank\">الأعضاء</a>.<br/>\nبالدعوات من قبل الإدارة فقط - فقط المراء بإمكانهم إرسال الدعوات من خلال صفحة <a href=\"%1/users\" target=\"_blank\">الأعضاء</a> و صفحات <a href=\"%1/admin/manage/users\">الإدارة/المشرفين/الأعضاء</a>.<br/>\nلا يوجد تسجيل - إغلاق خيار التسجيل بالكامل.<br/>",
|
||||
"registration.max-invites": "الحد الأقصى للدعوات لكل عضو",
|
||||
"max-invites": "الحد الأقصى للدعوات لكل عضو",
|
||||
"max-invites-help": "0 لعدم تحديد قيود، الإدارة تحصل على دعوات لامحدودة <br> هذا الخيار يعمل فقط عند تحديد خيار \"بالدعوات فقط\"",
|
||||
"invite-expiration": "مدة صلاحية الدعوة",
|
||||
"invite-expiration-help": "عدد الأيام حتى انتهاء صلاحية الدعوة.",
|
||||
"min-username-length": "الحد الأدنى لطول اسم المستخدم",
|
||||
"max-username-length": "الحد الأقصى لطول اسم المستخدم",
|
||||
"min-password-length": "الحد الأدنى لطول كلمة المرور",
|
||||
"min-password-strength": "الحد الأدنى لقوة كلمة المرور",
|
||||
"max-about-me-length": "الحد الأعلى من الأحرف في حقل \"عني\"",
|
||||
"terms-of-use": "شروط استخدام المنتدى <small>(تترك فارغة لتعطيلها)</small>",
|
||||
"user-search": "بحث الأعضاء",
|
||||
"user-search-results-per-page": "عدد النتائج المراد عرضها",
|
||||
"default-user-settings": "إعدادات الأعضاء الافتراضية",
|
||||
"show-email": "عرض البريد الإلكتروني",
|
||||
"show-fullname": "عرض الاسم الكامل",
|
||||
"restrict-chat": "السماح فقط برسائل الدردشة من المستخدمين الذين أتبعهم",
|
||||
"authentication": "Authentication",
|
||||
"allow-local-login": "Allow local login",
|
||||
"require-email-confirmation": "Require Email Confirmation",
|
||||
"email-confirm-interval": "User may not resend a confirmation email until",
|
||||
"email-confirm-email2": "minutes have elapsed",
|
||||
"allow-login-with": "Allow login with",
|
||||
"allow-login-with.username-email": "Username or Email",
|
||||
"allow-login-with.username": "Username Only",
|
||||
"allow-login-with.email": "Email Only",
|
||||
"account-settings": "Account Settings",
|
||||
"disable-username-changes": "Disable username changes",
|
||||
"disable-email-changes": "Disable email changes",
|
||||
"disable-password-changes": "Disable password changes",
|
||||
"allow-account-deletion": "Allow account deletion",
|
||||
"user-info-private": "Make user info private",
|
||||
"themes": "Themes",
|
||||
"disable-user-skins": "Prevent users from choosing a custom skin",
|
||||
"account-protection": "Account Protection",
|
||||
"login-attempts": "Login attempts per hour",
|
||||
"login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time",
|
||||
"lockout-duration": "Account Lockout Duration (minutes)",
|
||||
"login-days": "Days to remember user login sessions",
|
||||
"password-expiry-days": "Force password reset after a set number of days",
|
||||
"registration": "User Registration",
|
||||
"registration-type": "Registration Type",
|
||||
"registration-type.normal": "Normal",
|
||||
"registration-type.admin-approval": "Admin Approval",
|
||||
"registration-type.admin-approval-ip": "Admin Approval for IPs",
|
||||
"registration-type.invite-only": "Invite Only",
|
||||
"registration-type.admin-invite-only": "Admin Invite Only",
|
||||
"registration-type.disabled": "No registration",
|
||||
"registration-type.help": "Normal - Users can register from the /register page.<br/>\nAdmin Approval - User registrations are placed in an <a href=\"%1/admin/manage/registration\">approval queue</a> for administrators.<br/>\nAdmin Approval for IPs - Normal for new users, Admin Approval for IP addresses that already have an account.<br/>\nInvite Only - Users can invite others from the <a href=\"%1/users\" target=\"_blank\">users</a> page.<br/>\nAdmin Invite Only - Only administrators can invite others from <a href=\"%1/users\" target=\"_blank\">users</a> and <a href=\"%1/admin/manage/users\">admin/manage/users</a> pages.<br/>\nNo registration - No user registration.<br/>",
|
||||
"registration.max-invites": "Maximum Invitations per User",
|
||||
"max-invites": "Maximum Invitations per User",
|
||||
"max-invites-help": "0 for no restriction. Admins get infinite invitations<br>Only applicable for \"Invite Only\"",
|
||||
"min-username-length": "Minimum Username Length",
|
||||
"max-username-length": "Maximum Username Length",
|
||||
"min-password-length": "Minimum Password Length",
|
||||
"max-about-me-length": "Maximum About Me Length",
|
||||
"terms-of-use": "Forum Terms of Use <small>(Leave blank to disable)</small>",
|
||||
"user-search": "User Search",
|
||||
"user-search-results-per-page": "Number of results to display",
|
||||
"default-user-settings": "Default User Settings",
|
||||
"show-email": "Show email",
|
||||
"show-fullname": "Show fullname",
|
||||
"restrict-chat": "Only allow chat messages from users I follow",
|
||||
"outgoing-new-tab": "Open outgoing links in new tab",
|
||||
"topic-search": "Enable In-Topic Searching",
|
||||
"digest-freq": "Subscribe to Digest",
|
||||
@@ -69,10 +55,5 @@
|
||||
"email-chat-notifs": "Send an email if a new chat message arrives and I am not online",
|
||||
"email-post-notif": "Send an email when replies are made to topics I am subscribed to",
|
||||
"follow-created-topics": "Follow topics you create",
|
||||
"follow-replied-topics": "Follow topics that you reply to",
|
||||
"default-notification-settings": "Default notification settings",
|
||||
"categoryWatchState": "Default category watch state",
|
||||
"categoryWatchState.watching": "Watching",
|
||||
"categoryWatchState.notwatching": "Not Watching",
|
||||
"categoryWatchState.ignoring": "Ignoring"
|
||||
"follow-replied-topics": "Follow topics that you reply to"
|
||||
}
|
||||
@@ -1,22 +1,20 @@
|
||||
{
|
||||
"category": "قسم",
|
||||
"subcategories": "قسم فرعي",
|
||||
"category": "فئة",
|
||||
"subcategories": "فئة فرعية",
|
||||
"new_topic_button": "موضوع جديد",
|
||||
"guest-login-post": "سجل الدخول للمشاركة",
|
||||
"no_topics": "<strong>لا توجد مواضيع في هذه القسم</strong>لم لا تحاول إنشاء موضوع؟<br />",
|
||||
"guest-login-post": "سجل بالدخول للرد",
|
||||
"no_topics": "<strong>لا توجد مواضيع في هذه الفئة</strong>لم لا تحاول إنشاء موضوع؟<br />",
|
||||
"browsing": "تصفح",
|
||||
"no_replies": "لم يرد أحد",
|
||||
"no_new_posts": "لا توجد مشاركات جديدة.",
|
||||
"share_this_category": "انشر هذه الفئة",
|
||||
"watch": "تابع",
|
||||
"ignore": "تجاهل",
|
||||
"watching": "متابع",
|
||||
"not-watching": "Not Watching",
|
||||
"ignoring": "متجاهل",
|
||||
"watching.description": "Show topics in unread and recent",
|
||||
"not-watching.description": "Do not show topics in unread, show in recent",
|
||||
"ignoring.description": "Do not show topics in unread and recent",
|
||||
"watching.message": "You are now watching updates from this category and all subcategories",
|
||||
"notwatching.message": "You are not watching updates from this category and all subcategories",
|
||||
"ignoring.message": "You are now ignoring updates from this category and all subcategories",
|
||||
"watched-categories": "الأقسام المُتابعة"
|
||||
"watching.description": "أظهر المواضيع في غير مقروء",
|
||||
"ignoring.description": "لا تظهر المواضيع في غير مقروء",
|
||||
"watch.message": "You are now watching updates from this category and all subcategories",
|
||||
"ignore.message": "You are now ignoring updates from this category and all subcategories",
|
||||
"watched-categories": "الفئات المتابعة"
|
||||
}
|
||||
@@ -1,18 +1,14 @@
|
||||
{
|
||||
"test-email.subject": "Test Email",
|
||||
"password-reset-requested": "Password Reset Requested!",
|
||||
"password-reset-requested": "تم طلب إعادة تعيين كلمة المرور - %1!",
|
||||
"welcome-to": "مرحبًا بك في %1",
|
||||
"invite": "دعوة من %1",
|
||||
"greeting_no_name": "مرحبًا",
|
||||
"greeting_with_name": "مرحبًا بك يا %1",
|
||||
"email.verify-your-email.subject": "Please verify your email",
|
||||
"email.verify.text1": "Your email address has changed!",
|
||||
"welcome.text1": "شكرًا على تسجيلك في %1!",
|
||||
"welcome.text2": "لتفعيل حسابك، نحتاج إلى التأكد من صحة عنوان البريد الإلكتروني الذي سجلت به.",
|
||||
"welcome.text3": "تم قبول نتسجيلك ، يمكنك الدخول باتسخدام اسم المستخدم و كلمة المرور.",
|
||||
"welcome.cta": "انقر هنا لتفعيل عنوان بريدك الإلكتروني",
|
||||
"invitation.text1": "%1 قام بدعوتك للانضمام لـ %2",
|
||||
"invitation.text2": "Your invitation will expire in %1 days.",
|
||||
"invitation.ctr": "إضغط هنا لإنشاء حسابك",
|
||||
"reset.text1": "لقد توصلنا بطلب إعادة تعيين كلمة المرور الخاصة بك، ربما لكونك قد نسيتها, إن لم يكن الأمر كذلك، المرجو تجاهل هذه الرسالة.",
|
||||
"reset.text2": "لمواصلة طلب إعاة تعيين كلمة المرور، الرجاء تتبع هذا الرابط.",
|
||||
@@ -34,12 +30,7 @@
|
||||
"notif.chat.unsub.info": "تم إرسال هذا الإشعار بوجودة محادثة جديدة وفقا لخيارات تسجيلك.",
|
||||
"notif.post.cta": "انقر هنا لقراءة الموضوع بأكمله",
|
||||
"notif.post.unsub.info": "تم إشعارك بهذه المشاركة بناءً على الخيارات التي سبق وأن حددتها.",
|
||||
"notif.cta": "Click here to go to forum",
|
||||
"test.text1": "هذه رسالة تجريبية للتأكد من صحة إعدادت الرسائل الإلكترونية في منتدى NodeBB خاصتك.",
|
||||
"unsub.cta": "انقر هنا لتغيير تلك الإعدادات",
|
||||
"banned.subject": "You have been banned from %1",
|
||||
"banned.text1": "The user %1 has been banned from %2.",
|
||||
"banned.text2": "This ban will last until %1.",
|
||||
"banned.text3": "This is the reason why you have been banned:",
|
||||
"closing": "شكرًا لك!"
|
||||
}
|
||||
@@ -1,24 +1,19 @@
|
||||
{
|
||||
"invalid-data": "بيانات غير صحيحة",
|
||||
"invalid-json": "Invalid JSON",
|
||||
"not-logged-in": "لم تقم بتسجيل الدخول",
|
||||
"account-locked": "تم حظر حسابك مؤقتًا.",
|
||||
"search-requires-login": "البحث في المنتدى يتطلب حساب - الرجاء تسجيل الدخول أو التسجيل",
|
||||
"goback": "Press back to return to the previous page",
|
||||
"invalid-cid": "قائمة غير موجودة",
|
||||
"invalid-tid": "موضوع غير متواجد",
|
||||
"invalid-pid": "رد غير موجود",
|
||||
"invalid-uid": "مستخدم غير موجود",
|
||||
"invalid-username": "اسم المستخدم غير مقبول",
|
||||
"invalid-email": "البريد الاكتروني غير مقبول",
|
||||
"invalid-title": "Invalid title",
|
||||
"invalid-title": "عنوان غير صحيح",
|
||||
"invalid-user-data": "بيانات المستخدم غير صحيحة",
|
||||
"invalid-password": "كلمة السر غير مقبولة",
|
||||
"invalid-login-credentials": "Invalid login credentials",
|
||||
"invalid-username-or-password": "المرجود تحديد اسم مستخدم و كلمة مرور",
|
||||
"invalid-search-term": "كلمة البحث غير صحيحة",
|
||||
"invalid-url": "Invalid URL",
|
||||
"local-login-disabled": "Local login system has been disabled for non-privileged accounts.",
|
||||
"csrf-invalid": "لم تتمكن من تسجيل الدخول. هنالك أحتمال ان جلستك انتهت. رجاءًا حاول مرة اخرى.",
|
||||
"invalid-pagination-value": "رقم الصفحة غير صحيح ، يجب أن يكون بين %1 و %2 .",
|
||||
"username-taken": "اسم المستخدم مأخوذ",
|
||||
@@ -35,7 +30,6 @@
|
||||
"password-too-long": "كلمة السر طويلة ",
|
||||
"user-banned": "المستخدم محظور",
|
||||
"user-banned-reason": "Sorry, this account has been banned (Reason: %1)",
|
||||
"user-banned-reason-until": "Sorry, this account has been banned until %1 (Reason: %2)",
|
||||
"user-too-new": "عذرا, يجب أن تنتظر 1% ثواني قبل قيامك بأول مشاركة",
|
||||
"blacklisted-ip": "نأسف، لقد تم حظرك من استخدام وتصفح المنتدى. إذا كنت تعتقد أن هذا خطأ رجاءًا اتصل بالإدارة. ",
|
||||
"ban-expiry-missing": "رجاءًا ضع تاريخ نهاية الحظر. ",
|
||||
@@ -78,17 +72,14 @@
|
||||
"still-uploading": "الرجاء الانتظار حتى يكتمل الرفع.",
|
||||
"file-too-big": "الحد الأقصى لرفع الملفات %1 كيلو بت. رجاءًا ارفع ملف أصغر",
|
||||
"guest-upload-disabled": "خاصية رفع الملفات غير مفعلة للزوار.",
|
||||
"cors-error": "Unable to upload image due to misconfigured CORS",
|
||||
"already-bookmarked": "You have already bookmarked this post",
|
||||
"already-unbookmarked": "You have already unbookmarked this post",
|
||||
"cant-ban-other-admins": "لايمكن حظر مدبر نظام آخر.",
|
||||
"cant-remove-last-admin": "رجاءًا ، أضف مدير أخر قبل حذف صلاحيات الإدارة من حسابك.",
|
||||
"cant-delete-admin": "رجاءًا أزل صلاحيات الإدارة قبل حذف الحساب. ",
|
||||
"invalid-image": "Invalid image",
|
||||
"invalid-image-type": "نوع الصورة غير مدعوم. الأنواع المدعومة هي : %1",
|
||||
"invalid-image-extension": "امتداد الصورة غير مدعوم.",
|
||||
"invalid-file-type": "صيغة الملف غير مدعومة. الأنواع المدعومة هي: %1",
|
||||
"invalid-image-dimensions": "Image dimensions are too big",
|
||||
"group-name-too-short": "اسم المجموعة قصير",
|
||||
"group-name-too-long": "اسم المجموعة طويل.",
|
||||
"group-already-exists": "المجموعة موجودة مسبقا",
|
||||
@@ -113,33 +104,21 @@
|
||||
"chat-disabled": "نظام المحادثة معطل.",
|
||||
"too-many-messages": "لقد أرسلت الكثير من الرسائل، الرجاء اﻹنتظار قليلاً",
|
||||
"invalid-chat-message": "الرسالة غير صالحة.",
|
||||
"chat-message-too-long": "Chat messages can not be longer than %1 characters.",
|
||||
"chat-message-too-long": "الرسالة طويلة.",
|
||||
"cant-edit-chat-message": "غير مصرح لك بتعديل الرسالة.",
|
||||
"cant-remove-last-user": "لأيمكنك إزالت اخر مستخدم.",
|
||||
"cant-delete-chat-message": "غير مصرح لك بحذف الرسالة.",
|
||||
"chat-edit-duration-expired": "You are only allowed to edit chat messages for %1 second(s) after posting",
|
||||
"chat-delete-duration-expired": "You are only allowed to delete chat messages for %1 second(s) after posting",
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"already-voting-for-this-post": "لقد شاركت بالتصويت ، ألا تذكر؟",
|
||||
"reputation-system-disabled": "نظام السمعة معطل",
|
||||
"downvoting-disabled": "التصويتات السلبية معطلة",
|
||||
"not-enough-reputation-to-downvote": "ليس لديك سمعة تكفي لإضافة صوت سلبي لهذا الموضوع",
|
||||
"not-enough-reputation-to-flag": "ليس لديك سمعة تكفي للإشعار بموضوع مخل",
|
||||
"not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website",
|
||||
"not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me",
|
||||
"not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature",
|
||||
"not-enough-reputation-min-rep-profile-picture": "You do not have enough reputation to add a profile picture",
|
||||
"not-enough-reputation-min-rep-cover-picture": "You do not have enough reputation to add a cover picture",
|
||||
"already-flagged": "لقد بلغت عن هذه المشاركة من قبل.",
|
||||
"self-vote": "You cannot vote on your own post",
|
||||
"reload-failed": "المنتدى واجه مشكلة أثناء إعادة التحميل: \"%1\". سيواصل المنتدى خدمة العملاء السابقين لكن يجب عليك إلغاء أي تغيير قمت به قبل إعادة التحميل.",
|
||||
"registration-error": "حدث خطأ أثناء التسجيل",
|
||||
"parse-error": "حدث خطأ ما أثناء تحليل استجابة الخادم",
|
||||
"wrong-login-type-email": "الرجاء استعمال بريدك اﻹلكتروني للدخول",
|
||||
"wrong-login-type-username": "الرجاء استعمال اسم المستخدم الخاص بك للدخول",
|
||||
"sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first",
|
||||
"sso-multiple-association": "You cannot associate multiple accounts from this service to your NodeBB account. Please dissociate your existing account and try again.",
|
||||
"invite-maximum-met": "لقد قمت بدعوة الحد الأقصى من الأشخاص (%1 من %2)",
|
||||
"no-session-found": "لم دخول مسجل!",
|
||||
"not-in-room": "المستخدم غير موجود في الغرفة.",
|
||||
@@ -148,13 +127,5 @@
|
||||
"no-users-selected": "لا يوجد مستخدم محدد.",
|
||||
"invalid-home-page-route": "Invalid home page route",
|
||||
"invalid-session": "Session Mismatch",
|
||||
"invalid-session-text": "يبدو أن فترة التسجيل لم تعد قائمة او هي غير مطابقة مع الخادم. يرجى إعادة تحميل هذه الصفحة.",
|
||||
"no-topics-selected": "No topics selected!",
|
||||
"cant-move-to-same-topic": "Can't move post to same topic!",
|
||||
"cannot-block-self": "You cannot block yourself!",
|
||||
"cannot-block-privileged": "You cannot block administrators or global moderators",
|
||||
"cannot-block-guest": "Guest are not able to block other users",
|
||||
"already-blocked": "This user is already blocked",
|
||||
"already-unblocked": "This user is already unblocked",
|
||||
"no-connection": "There seems to be a problem with your internet connection"
|
||||
"invalid-session-text": "يبدو أن فترة التسجيل لم تعد قائمة او هي غير مطابقة مع الخادم. يرجى إعادة تحميل هذه الصفحة."
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"state": "State",
|
||||
"reporter": "Reporter",
|
||||
"reported-at": "Reported At",
|
||||
"description": "Description",
|
||||
"no-flags": "Hooray! No flags found.",
|
||||
"assignee": "Assignee",
|
||||
"update": "Update",
|
||||
"updated": "Updated",
|
||||
"target-purged": "The content this flag referred to has been purged and is no longer available.",
|
||||
|
||||
"quick-filters": "Quick Filters",
|
||||
"filter-active": "There are one or more filters active in this list of flags",
|
||||
"filter-reset": "Remove Filters",
|
||||
"filters": "Filter Options",
|
||||
"filter-reporterId": "Reporter UID",
|
||||
"filter-targetUid": "Flagged UID",
|
||||
"filter-type": "Flag Type",
|
||||
"filter-type-all": "All Content",
|
||||
"filter-type-post": "Post",
|
||||
"filter-type-user": "User",
|
||||
"filter-state": "State",
|
||||
"filter-assignee": "Assignee UID",
|
||||
"filter-cid": "Category",
|
||||
"filter-quick-mine": "Assigned to me",
|
||||
"filter-cid-all": "All categories",
|
||||
"apply-filters": "Apply Filters",
|
||||
|
||||
"quick-links": "Quick Links",
|
||||
"flagged-user": "Flagged User",
|
||||
"view-profile": "View Profile",
|
||||
"start-new-chat": "Start New Chat",
|
||||
"go-to-target": "View Flag Target",
|
||||
|
||||
"user-view": "View Profile",
|
||||
"user-edit": "Edit Profile",
|
||||
|
||||
"notes": "Flag Notes",
|
||||
"add-note": "Add Note",
|
||||
"no-notes": "No shared notes.",
|
||||
|
||||
"history": "Flag History",
|
||||
"back": "Back to Flags List",
|
||||
"no-history": "No flag history.",
|
||||
|
||||
"state-all": "All states",
|
||||
"state-open": "New/Open",
|
||||
"state-wip": "Work in Progress",
|
||||
"state-resolved": "Resolved",
|
||||
"state-rejected": "Rejected",
|
||||
"no-assignee": "Not Assigned",
|
||||
"note-added": "Note Added",
|
||||
|
||||
"modal-title": "Report Inappropriate Content",
|
||||
"modal-body": "Please specify your reason for flagging %1 %2 for review. Alternatively, use one of the quick report buttons if applicable.",
|
||||
"modal-reason-spam": "Spam",
|
||||
"modal-reason-offensive": "Offensive",
|
||||
"modal-reason-other": "Other (specify below)",
|
||||
"modal-reason-custom": "Reason for reporting this content...",
|
||||
"modal-submit": "Submit Report",
|
||||
"modal-submit-success": "Content has been flagged for moderation.",
|
||||
"modal-submit-confirm": "Confirm Submission",
|
||||
"modal-submit-confirm-text": "You have a custom reason specified already. Are you sure you wish to submit via quick-report?",
|
||||
"modal-submit-confirm-text-help": "Submitting a quick report will overwrite any custom reasons defined."
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"buttons.close": "أغلق",
|
||||
"403.title": "غير مسموح بالدخول",
|
||||
"403.message": "يبدو أنك قد تعثرت على صفحة لا تمتلك الصلاحية للدخول إليها",
|
||||
"403.login": "ربما يجب عليك <a href='%1/login'>تسجل دخولك</a>.",
|
||||
"403.login": "حاول أن <a href='%1/login'>تسجل دخولك</a>.",
|
||||
"404.title": "لم يتم العثور",
|
||||
"404.message": "الصفحة غير موجودة. العودة لـ <a href='%1/'>الرئيسية</a>",
|
||||
"500.title": "خطأ داخلي",
|
||||
@@ -13,19 +13,19 @@
|
||||
"400.message": "الرابط غير صحيح. رجاءًا تأكد من الرابط أو ارجع لـ <a href='%1/'>الرئيسية</a>",
|
||||
"register": "تسجيل",
|
||||
"login": "دخول",
|
||||
"please_log_in": "الرجاء تسجيل الدخول",
|
||||
"please_log_in": "المرجو تسجيل الدخول",
|
||||
"logout": "تسجيل الخروج",
|
||||
"posting_restriction_info": "إضافة مشاركات جديد حكر على الأعضاء المسجلين، انقر هنا لتسجيل الدخول.",
|
||||
"welcome_back": "مرحبًا بعودتك",
|
||||
"you_have_successfully_logged_in": "تم سجيل الدخول بنجاح",
|
||||
"save_changes": "حفظ التغييرات",
|
||||
"save": "حفظ",
|
||||
"save": "Save",
|
||||
"close": "أغلق",
|
||||
"pagination": "الصفحات",
|
||||
"pagination.out_of": "%1 من %2",
|
||||
"pagination.enter_index": "أدخل الرقم التسلسلي",
|
||||
"header.admin": "مدير النظام",
|
||||
"header.categories": "الأقسام",
|
||||
"header.admin": "مدبر نظام",
|
||||
"header.categories": "الفئات",
|
||||
"header.recent": "حديث",
|
||||
"header.unread": "غير مقروء",
|
||||
"header.tags": "وسم",
|
||||
@@ -37,9 +37,9 @@
|
||||
"header.search": "بحث",
|
||||
"header.profile": "ملف",
|
||||
"header.navigation": "الاستكشاف",
|
||||
"notifications.loading": "تحميل التنبيهات",
|
||||
"notifications.loading": "تحميل التبليغات",
|
||||
"chats.loading": "تحميل الدردشات",
|
||||
"motd.welcome": "مرحبا بكم في NodeBB، منصة المناقشة المستقبلية.",
|
||||
"motd.welcome": "مرحبا بكم NodeBB، منصة مناقشة المستقبل",
|
||||
"previouspage": "الصفحة السابقة",
|
||||
"nextpage": "الصفحة التالية",
|
||||
"alert.success": "نجاح",
|
||||
@@ -53,7 +53,6 @@
|
||||
"topics": "المواضيع",
|
||||
"posts": "المشاركات",
|
||||
"best": "الأفضل",
|
||||
"votes": "Votes",
|
||||
"upvoters": "الموافقين",
|
||||
"upvoted": "مصوت بالموجب",
|
||||
"downvoters": "مصوتين بالسالب",
|
||||
@@ -76,7 +75,7 @@
|
||||
"norecenttopics": "لاوجود لمواضيع جديدة",
|
||||
"recentposts": "آخر المشاركات",
|
||||
"recentips": "آخر عناوين ال IP التي سجلت الدخول",
|
||||
"moderator_tools": "أدوات المشرف",
|
||||
"moderator_tools": "Moderator Tools",
|
||||
"away": "غير متواجد",
|
||||
"dnd": "عدم الإزعاج",
|
||||
"invisible": "مخفي",
|
||||
@@ -85,9 +84,8 @@
|
||||
"language": "اللغة",
|
||||
"guest": "زائر",
|
||||
"guests": "الزوار",
|
||||
"former_user": "A Former User",
|
||||
"updated.title": "تم تحديث المنتدى",
|
||||
"updated.message": "لقد تم تحديث المنتدى إلى آخر نسخة للتو. إضغط هنا لإعادة تحميل الصفحة.",
|
||||
"updated.message": "لقد تم تحديث المنتدى إلى آخر نسخة للتو. المرجو إعادة تحميل الصفحة.",
|
||||
"privacy": "الخصوصية",
|
||||
"follow": "متابعة",
|
||||
"unfollow": "إلغاء المتابعة",
|
||||
@@ -98,16 +96,12 @@
|
||||
"enter_page_number": "ادخل رقم الصفحة",
|
||||
"upload_file": "ارفع ملف",
|
||||
"upload": "ارفع",
|
||||
"uploads": "Uploads",
|
||||
"allowed-file-types": "صيغ الملفات المدعومة هي 1%",
|
||||
"unsaved-changes": "لديك تغييرات لم تحفظ. هل أنت متأكد من رغبتك بمغادرة الصفحة؟",
|
||||
"unsaved-changes": "لديك تغييرات لم تحفظ. هل أنت متأكد من تغيير الصفحة؟",
|
||||
"reconnecting-message": "يبدو أن اتصالك لـ %1 قد فقد. رجاءًا أنتظر ثم حاول الإتصال مرة اخرى.",
|
||||
"play": "تشغيل",
|
||||
"cookies.message": "هذا الموقع يستخدم ملفات تعريف الارتباط لضمان حصولك على أفضل تجربة على موقعنا.",
|
||||
"cookies.accept": "فهمت الأمر!",
|
||||
"cookies.learn_more": "أعرف المزيد",
|
||||
"edited": "حُرِر",
|
||||
"disabled": "معطل",
|
||||
"select": "تحديد",
|
||||
"user-search-prompt": "Type something here to find users..."
|
||||
"play": "Play",
|
||||
"cookies.message": "This website uses cookies to ensure you get the best experience on our website.",
|
||||
"cookies.accept": "Got it!",
|
||||
"cookies.learn_more": "Learn More",
|
||||
"edited": "Edited"
|
||||
}
|
||||
@@ -28,7 +28,6 @@
|
||||
"details.grant": "منح/سحب المِلكية",
|
||||
"details.kick": "طرد",
|
||||
"details.kick_confirm": "Are you sure you want to remove this member from the group?",
|
||||
"details.add-member": "Add Member",
|
||||
"details.owner_options": "إدارة المجموعة",
|
||||
"details.group_name": "اسم المجموعة",
|
||||
"details.member_count": "عدد اﻷعضاء",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"remember_me": "تذكرني؟",
|
||||
"forgot_password": "نسيت كلمة المرور؟",
|
||||
"alternative_logins": "تسجيلات الدخول البديلة",
|
||||
"failed_login_attempt": "تسجيل الدخول غير ناجح",
|
||||
"failed_login_attempt": "Login Unsuccessful",
|
||||
"login_successful": "قمت بتسجيل الدخول بنجاح!",
|
||||
"dont_have_account": "لا تملك حساب؟",
|
||||
"logged-out-due-to-inactivity": "لقد تم تسجيل خروجك من لوحة تحكم بسبب عدم نشاطك"
|
||||
"logged-out-due-to-inactivity": "You have been logged out of the Admin Control Panel due to inactivity"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"chat.chatting_with": "Chat with",
|
||||
"chat.chatting_with": "الدردشة مع <span id=\"chat-with-name\"></span>",
|
||||
"chat.placeholder": "أكتب رسالة دردشة هنا، اضغط ENTER للإرسال",
|
||||
"chat.send": "أرسل",
|
||||
"chat.no_active": "لا يوجد لديك دردشات نشطة.",
|
||||
@@ -12,7 +12,6 @@
|
||||
"chat.recent-chats": "آخر الدردشات",
|
||||
"chat.contacts": "الأصدقاء",
|
||||
"chat.message-history": "تاريخ الرسائل",
|
||||
"chat.options": "Chat options",
|
||||
"chat.pop-out": "افتح الدردشة في نافذة خاصة",
|
||||
"chat.minimize": "Minimize",
|
||||
"chat.maximize": "تكبير",
|
||||
@@ -20,20 +19,7 @@
|
||||
"chat.thirty_days": "30 يومًا",
|
||||
"chat.three_months": "3 أشهر",
|
||||
"chat.delete_message_confirm": "هل أنت متأكد من أنك تريد حذف هذه الرسالة؟",
|
||||
"chat.retrieving-users": "Retrieving users...",
|
||||
"chat.manage-room": "Manage Chat Room",
|
||||
"chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners (<i class=\"fa fa-star text-warning\"></i>) may remove users from chat rooms.",
|
||||
"chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?",
|
||||
"chat.rename-room": "Rename Room",
|
||||
"chat.rename-placeholder": "Enter your room name here",
|
||||
"chat.rename-help": "The room name set here will be viewable by all participants in the room.",
|
||||
"chat.leave": "Leave Chat",
|
||||
"chat.leave-prompt": "Are you sure you wish to leave this chat?",
|
||||
"chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.",
|
||||
"chat.in-room": "In this room",
|
||||
"chat.kick": "Kick",
|
||||
"chat.show-ip": "Show IP",
|
||||
"chat.owner": "Room Owner",
|
||||
"chat.add-users-to-room": "Add users to room",
|
||||
"composer.compose": "اكتب",
|
||||
"composer.show_preview": "عرض المعاينة",
|
||||
"composer.hide_preview": "إخفاء المعاينة",
|
||||
@@ -47,7 +33,6 @@
|
||||
"composer.formatting.italic": "Italic",
|
||||
"composer.formatting.list": "List",
|
||||
"composer.formatting.strikethrough": "Strikethrough",
|
||||
"composer.formatting.code": "Code",
|
||||
"composer.formatting.link": "Link",
|
||||
"composer.formatting.picture": "Picture",
|
||||
"composer.upload-picture": "Upload Image",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"outgoing_link_message": "You are now leaving %1",
|
||||
"continue_to": "استمر إلى %1",
|
||||
"return_to": "عودة إى %1",
|
||||
"new_notification": "You have a new notification",
|
||||
"new_notification": "تنبيه جديد",
|
||||
"you_have_unread_notifications": "لديك تنبيهات غير مقروءة.",
|
||||
"all": "All",
|
||||
"topics": "Topics",
|
||||
@@ -41,24 +41,8 @@
|
||||
"new_register": "<strong>%1</strong> sent a registration request.",
|
||||
"new_register_multiple": "There are <strong>%1</strong> registration requests awaiting review.",
|
||||
"flag_assigned_to_you": "<strong>Flag %1</strong> has been assigned to you",
|
||||
"post_awaiting_review": "Post awaiting review",
|
||||
"email-confirmed": "تم التحقق من عنوان البريد الإلكتروني",
|
||||
"email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.",
|
||||
"email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.",
|
||||
"email-confirm-sent": "تم إرسال بريد التفعيل.",
|
||||
"none": "None",
|
||||
"notification_only": "Notification Only",
|
||||
"email_only": "Email Only",
|
||||
"notification_and_email": "Notification & Email",
|
||||
"notificationType_upvote": "When someone upvotes your post",
|
||||
"notificationType_new-topic": "When someone you follow posts a topic",
|
||||
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
|
||||
"notificationType_follow": "When someone starts following you",
|
||||
"notificationType_new-chat": "When you receive a chat message",
|
||||
"notificationType_group-invite": "When you receive a group invite",
|
||||
"notificationType_group-request-membership": "When someone requests to join a group you own",
|
||||
"notificationType_new-register": "When someone gets added to registration queue",
|
||||
"notificationType_post-queue": "When a new post is queued",
|
||||
"notificationType_new-post-flag": "When a post is flagged",
|
||||
"notificationType_new-user-flag": "When a user is flagged"
|
||||
"email-confirm-sent": "تم إرسال بريد التفعيل."
|
||||
}
|
||||
@@ -6,14 +6,8 @@
|
||||
"popular-month": "المواضيع الشائعة هذا الشهر",
|
||||
"popular-alltime": "المواضيع الشائعة منذ القدم",
|
||||
"recent": "المواضيع الحديثة",
|
||||
"top-day": "Top voted topics today",
|
||||
"top-week": "Top voted topics this week",
|
||||
"top-month": "Top voted topics this month",
|
||||
"top-alltime": "Top Voted Topics",
|
||||
"moderator-tools": "Moderator Tools",
|
||||
"flagged-content": "Flagged Content",
|
||||
"ip-blacklist": "IP Blacklist",
|
||||
"post-queue": "Post Queue",
|
||||
"users/online": "اﻷعضاء المتصلون",
|
||||
"users/latest": "أحدث اﻷعضاء",
|
||||
"users/sort-posts": "الأعضاء الأكثر نشاطاً",
|
||||
@@ -23,7 +17,7 @@
|
||||
"users/search": "بحث عن مستخدم",
|
||||
"notifications": "التنبيهات",
|
||||
"tags": "الكلمات الدلالية",
|
||||
"tag": "Topics tagged under "%1"",
|
||||
"tag": "المواضيع المرتبطة بالوسم %1",
|
||||
"register": "تسجيل حساب",
|
||||
"registration-complete": "Registration complete",
|
||||
"login": "سجل الدخول الى حسابك",
|
||||
@@ -45,17 +39,12 @@
|
||||
"account/posts": "Posts made by %1",
|
||||
"account/topics": "Topics created by %1",
|
||||
"account/groups": "%1's Groups",
|
||||
"account/watched_categories": "%1's Watched Categories",
|
||||
"account/bookmarks": "%1's Bookmarked Posts",
|
||||
"account/settings": "خيارات المستخدم",
|
||||
"account/watched": "Topics watched by %1",
|
||||
"account/ignored": "Topics ignored by %1",
|
||||
"account/upvoted": "Posts upvoted by %1",
|
||||
"account/downvoted": "Posts downvoted by %1",
|
||||
"account/best": "Best posts made by %1",
|
||||
"account/blocks": "Blocked users for %1",
|
||||
"account/uploads": "Uploads by %1",
|
||||
"account/sessions": "Login Sessions",
|
||||
"confirm": "تم التحقق من عنوان البريد الإلكتروني",
|
||||
"maintenance.text": "جاري صيانة %1. المرجو العودة لاحقًا.",
|
||||
"maintenance.messageIntro": "بالإضافة إلى ذلك، قام مدبر النظام بترك هذه الرسالة:",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"register": "تسجيل",
|
||||
"cancel_registration": "إلغاء التسجيل",
|
||||
"help.email": "افتراضيا، سيتم إخفاء بريدك الإلكتروني من العامة.",
|
||||
"help.username_restrictions": "اسم مستخدم فريدة من نوعها بين 1% و 2% حرفا. بإمكان الآخرين مناداتك بـ @<span id='yourUsername'>اسم المستخدم</span>.",
|
||||
"help.minimum_password_length": "كلمة المرور يجب أن تتكون على الأقل من 1% أحرف/حروف",
|
||||
"help.username_restrictions": "اسم مستخدم فريدة من نوعها بين1% و2% حرفا. يمكن للآخرين ذكرك @ <'span id='your-username> اسم المستخدم </span>.",
|
||||
"help.minimum_password_length": "كلمة المرور يجب أن تكون على الأقل بها 1% أحرف",
|
||||
"email_address": "عنوان البريد الإلكتروني",
|
||||
"email_address_placeholder": "ادخل عنوان البريد الإلكتروني",
|
||||
"username": "اسم المستخدم",
|
||||
@@ -16,11 +16,8 @@
|
||||
"alternative_registration": "طريقة تسجيل بديلة",
|
||||
"terms_of_use": "شروط الاستخدام",
|
||||
"agree_to_terms_of_use": "أوافق على شروط الاستخدام",
|
||||
"terms_of_use_error": "يجب عليك الموافقة على شروط الاستخدام",
|
||||
"registration-added-to-queue": "تمت إضافتك في قائمة الإنتضار. ستتلقى رسالة إلكترونية عند الموافقة على تسجيلك من قبل الإدارة.",
|
||||
"interstitial.intro": "نحتاج إلى بعض المعلومات الإضافية قبل أن نتمكن من إنشاء حسابك.",
|
||||
"interstitial.errors-found": "تعذر علينا إتمام عملية التسجيل:",
|
||||
"gdpr_agree_data": "I consent to the collection and processing of my personal information on this website.",
|
||||
"gdpr_agree_email": "I consent to receive digest and notification emails from this website.",
|
||||
"gdpr_consent_denied": "You must give consent to this site to collect/process your information, and to send you emails."
|
||||
"terms_of_use_error": "You must agree to the Terms of Use",
|
||||
"registration-added-to-queue": "Your registration has been added to the approval queue. You will receive an email when it is accepted by an administrator.",
|
||||
"interstitial.intro": "We require some additional information before we can create your account.",
|
||||
"interstitial.errors-found": "We could not complete your registration:"
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"repeat_password": "تأكيد كلمة المرور",
|
||||
"enter_email": "يرجى إدخال <strong>عنوان البريد الإلكتروني</strong> الخاص بك وسوف نرسل لك رسالة بالبريد الالكتروني مع تعليمات حول كيفية إستعادة حسابك.",
|
||||
"enter_email_address": "ادخل عنوان البريد الإلكتروني",
|
||||
"password_reset_sent": "A password reset email has been sent to the specified address. Please note that only one email will be sent per minute.",
|
||||
"password_reset_sent": "إعادة تعيين كلمة السر أرسلت",
|
||||
"invalid_email": "بريد إلكتروني غير صالح أو غير موجود",
|
||||
"password_too_short": "كلمة المرور التي أدخلتها قصيرة، الرجاء اختر كلمة مرور مختلفة",
|
||||
"passwords_do_not_match": "كلمتا السر التي أدخلتهما غير متطابقتان",
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
"in": "في",
|
||||
"titles": "العناوين",
|
||||
"titles-posts": "العناوين والمشاركات",
|
||||
"match-words": "Match words",
|
||||
"all": "All",
|
||||
"any": "Any",
|
||||
"posted-by": "مشاركة من طرف",
|
||||
"in-categories": "في الفئات",
|
||||
"search-child-categories": "بحث في الفئات الفرعية",
|
||||
@@ -17,7 +14,6 @@
|
||||
"at-most": "على اﻷكثر",
|
||||
"relevance": "Relevance",
|
||||
"post-time": "تاريخ المشاركة",
|
||||
"votes": "Votes",
|
||||
"newer-than": "أحدث من",
|
||||
"older-than": "أقدم من",
|
||||
"any-date": "أي وقت",
|
||||
@@ -31,7 +27,6 @@
|
||||
"sort-by": "عرض حسب",
|
||||
"last-reply-time": "تاريخ آخر رد",
|
||||
"topic-title": "عنوان الموضوع",
|
||||
"topic-votes": "Topic votes",
|
||||
"number-of-replies": "عدد الردود",
|
||||
"number-of-views": "عدد المشاهدات",
|
||||
"topic-start-date": "تاريخ بدأ الموضوع",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"success": "نجاح",
|
||||
"topic-post": "لقد تمت الإضافة بنجاح.",
|
||||
"post-queued": "Your post is queued for approval.",
|
||||
"authentication-successful": "تم تسجيل الدخول بنجاح",
|
||||
"settings-saved": "تم حفظ التغييرات!"
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
"quote": "اقتبس",
|
||||
"reply": "رد",
|
||||
"replies_to_this_post": "%1 Replies",
|
||||
"one_reply_to_this_post": "1 Reply",
|
||||
"last_reply_time": "Last reply",
|
||||
"reply-as-topic": "رد بموضوع",
|
||||
"guest-login-reply": "يجب عليك تسجيل الدخول للرد",
|
||||
@@ -30,12 +29,8 @@
|
||||
"locked": "مقفل",
|
||||
"pinned": "مثبت",
|
||||
"moved": "منقول",
|
||||
"copy-ip": "Copy IP",
|
||||
"ban-ip": "Ban IP",
|
||||
"view-history": "Edit History",
|
||||
"bookmark_instructions": "اضغط هنا للعودة لأخر مشاركة مقروءة في الموضوع",
|
||||
"flag_title": "إشعار بمشاركة مخلة.",
|
||||
"merged_message": "This topic has been merged into <a href=\"/topic/%1\">%2</a>",
|
||||
"deleted_message": "هذه المشاركة محذوفة. فقط من لهم صلاحية الإشراف على ا لمشاركات يمكنهم معاينتها.",
|
||||
"following_topic.message": "ستستلم تنبيها عند كل مشاركة جديدة في هذا الموضوع.",
|
||||
"not_following_topic.message": "You will see this topic in the unread topics list, but you will not receive notifications when somebody posts to this topic.",
|
||||
@@ -56,15 +51,13 @@
|
||||
"not-watching.description": "Do not notify me of new replies.<br/>Show topic in unread if category is not ignored.",
|
||||
"ignoring.description": "Do not notify me of new replies.<br/>Do not show topic in unread.",
|
||||
"thread_tools.title": "أدوات الموضوع",
|
||||
"thread_tools.markAsUnreadForAll": "Mark Unread For All",
|
||||
"thread_tools.markAsUnreadForAll": "Mark unread for all",
|
||||
"thread_tools.pin": "علق الموضوع",
|
||||
"thread_tools.unpin": "إلغاء تعليق الموضوع",
|
||||
"thread_tools.lock": "أقفل الموضوع",
|
||||
"thread_tools.unlock": "إلغاء إقفال الموضوع",
|
||||
"thread_tools.move": "نقل الموضوع",
|
||||
"thread_tools.move-posts": "Move Posts",
|
||||
"thread_tools.move_all": "نقل الكل",
|
||||
"thread_tools.select_category": "Select Category",
|
||||
"thread_tools.fork": "إنشاء فرع الموضوع",
|
||||
"thread_tools.delete": "حذف الموضوع",
|
||||
"thread_tools.delete-posts": "مشاركات محذوفة",
|
||||
@@ -73,13 +66,12 @@
|
||||
"thread_tools.restore_confirm": "هل أنت متأكد أنك تريد استعادة هذا الموضوع؟",
|
||||
"thread_tools.purge": "تطهير الموضوع",
|
||||
"thread_tools.purge_confirm": "هل أنت متأكد أنك تريد تطهير هذا الموضوع؟",
|
||||
"thread_tools.merge_topics": "Merge Topics",
|
||||
"thread_tools.merge": "Merge",
|
||||
"topic_move_success": "تم نقل هذا الموضوع إلى %1 بنجاح",
|
||||
"post_delete_confirm": "هل أنت متأكد أنك تريد حذف هذه المشاركة؟",
|
||||
"post_restore_confirm": "هل أنت متأكد أنك تريد استعادة هذه المشاركة؟",
|
||||
"post_purge_confirm": "هل أنت متأكد أنك تريد تطهير هذه المشاركة؟",
|
||||
"load_categories": "تحميل الفئات",
|
||||
"disabled_categories_note": "الفئات المعطلة رمادية",
|
||||
"confirm_move": "انقل",
|
||||
"confirm_fork": "فرع",
|
||||
"bookmark": "Bookmark",
|
||||
@@ -91,13 +83,12 @@
|
||||
"move_post": "نقل المشاركة",
|
||||
"post_moved": "تم نقل المشاركة",
|
||||
"fork_topic": "فرع الموضوع",
|
||||
"topic_will_be_moved_to": "هذا الموضوع سوف ينقل إلى فئة",
|
||||
"fork_topic_instruction": "إضغط على المشاركات التي تريد تفريعها",
|
||||
"fork_no_pids": "لم تختر أي مشاركة",
|
||||
"fork_pid_count": "1% مشاركة محددة",
|
||||
"fork_success": "تم إنشاء فرع للموضوع بنجاح! إضغط هنا لمعاينة الفرع.",
|
||||
"delete_posts_instruction": "Click the posts you want to delete/purge",
|
||||
"merge_topics_instruction": "Click the topics you want to merge",
|
||||
"move_posts_instruction": "Click the posts you want to move",
|
||||
"composer.title_placeholder": "أدخل عنوان موضوعك هنا...",
|
||||
"composer.handle_placeholder": "اﻹسم",
|
||||
"composer.discard": "نبذ التغييرات",
|
||||
@@ -118,16 +109,11 @@
|
||||
"sort_by": "ترتيب حسب",
|
||||
"oldest_to_newest": "من الأقدم إلى الأحدث",
|
||||
"newest_to_oldest": "من الأحدث إلى الأقدم",
|
||||
"most_votes": "Most Votes",
|
||||
"most_posts": "Most Posts",
|
||||
"most_votes": "الأكثر تصويتًا",
|
||||
"most_posts": "اﻷكثر رداً",
|
||||
"stale.title": "Create new topic instead?",
|
||||
"stale.warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?",
|
||||
"stale.create": "موضوع جديد",
|
||||
"stale.reply_anyway": "الرد على هذا الموضوع ",
|
||||
"link_back": "رد: [%1](%2)",
|
||||
"diffs.title": "Post Edit History",
|
||||
"diffs.description": "This post has <strong>%1</strong> revisions. Click one of the revisions below to see the post content at that point in time.",
|
||||
"diffs.no-revisions-description": "This post has <strong>%1</strong> revisions.",
|
||||
"diffs.current-revision": "current revision",
|
||||
"diffs.original-revision": "original revision"
|
||||
"link_back": "رد: [%1](%2)"
|
||||
}
|
||||
@@ -9,7 +9,5 @@
|
||||
"topics_marked_as_read.success": "تم تحديد المواضيع على أنها مقروءة!",
|
||||
"all-topics": "كل المواضيع",
|
||||
"new-topics": "مواضيع جديدة",
|
||||
"watched-topics": "المواضيع المتابعة",
|
||||
"unreplied-topics": "Unreplied Topics",
|
||||
"multiple-categories-selected": "Multiple Selected"
|
||||
"watched-topics": "المواضيع المتابعة"
|
||||
}
|
||||
@@ -2,8 +2,5 @@
|
||||
"uploading-file": "جاري رفع الملف...",
|
||||
"select-file-to-upload": "إختر ملف لرفعه!",
|
||||
"upload-success": "تم رفع الملف بنجاح!",
|
||||
"maximum-file-size": "الحجم الأقصى %1 كيلوبت",
|
||||
"no-uploads-found": "No uploads found",
|
||||
"public-uploads-info": "Uploads are public, all visitors can see them.",
|
||||
"private-uploads-info": "Uploads are private, only logged in users can see them."
|
||||
"maximum-file-size": "الحجم الأقصى %1 كيلوبت"
|
||||
}
|
||||