Compare commits

..

12 Commits

Author SHA1 Message Date
Julian Lam
3c36d7303a fix: inability for admins with setting privilege to save plugin settings 2020-12-29 11:56:53 -05:00
Julian Lam
988e293f8d fix: tests 2020-12-29 11:56:18 -05:00
Julian Lam
d253ca6821 feat: allow multiple privileges to be defined for a given admin socket call 2020-12-29 11:56:07 -05:00
Barış Soner Uşaklı
fa4c993e6a fix: timestamp in queue, add post queue strings 2020-12-29 11:55:24 -05:00
Julian Lam
833eff4ea4 fix: use fireHook instead of hooks.fire 2020-12-23 09:33:22 -05:00
Barış Soner Uşaklı
a526fd860b fix: #9136, fix move topic/post timeout errors 2020-12-21 14:53:30 -05:00
Julian Lam
05a50abdd4 fix: bad assignment logic in middleware.renderHeader 2020-12-21 14:53:23 -05:00
Julian Lam
79696abfd1 feat: explicitly add filter:admin/header.build hook
As it is not fired during middleware.processRender
2020-12-21 14:53:15 -05:00
Barış Soner Uşaklı
8b7b6d5e82 feat: add new client side hooks 2020-12-16 11:49:00 -05:00
Barış Soner Uşaklı
075f57e728 fix: #9117, lower query before search 2020-12-16 11:48:56 -05:00
Barış Soner Uşaklı
de0a7dccea fix: default values, clamp postsPerPage/topicsPerPage to max 2020-12-07 13:02:52 -05:00
Barış Soner Uşaklı
69b1ab7009 fix: #9081, load raw settings before merging 2020-12-07 12:23:48 -05:00
3539 changed files with 53916 additions and 89694 deletions

View File

@@ -10,21 +10,13 @@ checks:
threshold: 500
method-lines:
config:
threshold: 75
threshold: 50
method-complexity:
config:
threshold: 10
similar-code:
config:
threshold: 65
plugins:
duplication:
enabled: true
config:
languages:
javascript:
mass_threshold: 110
count_threshold: 3
exclude_paths:
- "public/vendor/*"
- "test/*"

View File

@@ -18,12 +18,3 @@ logs/
.eslintrc
test/files
*.min.js
/public/src/app.js
/public/src/client.js
/public/src/admin/admin.js
/public/src/modules/translator.common.js
/public/src/modules/pictureCropper.js
/public/src/modules/ace-editor.js
/public/src/client/account/header.js
/public/src/client/test.js

139
.eslintrc
View File

@@ -1,3 +1,140 @@
{
"extends": "nodebb"
"extends": "airbnb-base",
"parserOptions": {
"sourceType": "script"
},
"rules": {
// Customized
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never"
}],
"no-return-await": "off",
"no-constant-condition": "off",
"no-empty": ["error", { "allowEmptyCatch": true }],
"no-underscore-dangle": "off",
"no-console": "off",
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
"strict": ["error", "global"],
"consistent-return": "off",
"func-names": "off",
"no-tabs": "off",
"indent": ["error", "tab", { "SwitchCase": 1 }],
"no-eq-null": "off",
"camelcase": "off",
"no-new": "off",
"no-shadow": "off",
"no-use-before-define": ["error", "nofunc"],
"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" ],
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
// ES6
"prefer-rest-params": "off",
"prefer-spread": "off",
"prefer-arrow-callback": "off",
"prefer-template": "off",
"no-var": "off",
"object-shorthand": "off",
"vars-on-top": "off",
"prefer-destructuring": "off",
// TODO
"import/no-extraneous-dependencies": "off",
"import/no-dynamic-require": "off",
"import/newline-after-import": "off",
"no-bitwise": "off",
"global-require": "off",
"max-len": "off",
"no-param-reassign": "off",
"no-restricted-syntax": "off",
"no-script-url": "off",
"default-case": "off",
"linebreak-style": "off",
// "no-multi-assign": "off",
// "one-var": "off",
// "no-undef": "off",
// "max-nested-callbacks": "off",
// "no-mixed-requires": "off",
// "brace-style": "off",
// "max-statements-per-line": "off",
// "no-unused-vars": "off",
// "no-mixed-spaces-and-tabs": "off",
// "no-useless-concat": "off",
// "require-jsdoc": "off",
// "eqeqeq": "off",
// "no-negated-condition": "off",
// "one-var-declaration-per-line": "off",
// "no-lonely-if": "off",
// "radix": "off",
// "no-else-return": "off",
// "no-useless-escape": "off",
// "block-scoped-var": "off",
// "operator-assignment": "off",
// "yoda": "off",
// "no-loop-func": "off",
// "no-void": "off",
// "valid-jsdoc": "off",
// "no-cond-assign": "off",
// "no-redeclare": "off",
// "no-unreachable": "off",
// "no-nested-ternary": "off",
// "operator-linebreak": "off",
// "guard-for-in": "off",
// "no-unneeded-ternary": "off",
// "no-sequences": "off",
// "no-extend-native": "off",
// "no-shadow-restricted-names": "off",
// "no-extra-boolean-cast": "off",
// "no-path-concat": "off",
// "no-unused-expressions": "off",
// "no-return-assign": "off",
// "no-restricted-modules": "off",
// "object-curly-spacing": "off",
// "indent": "off",
// "padded-blocks": "off",
// "eol-last": "off",
// "lines-around-directive": "off",
// "strict": "off",
// "comma-dangle": "off",
// "no-multi-spaces": "off",
// "quotes": "off",
// "keyword-spacing": "off",
// "no-mixed-operators": "off",
// "comma-spacing": "off",
// "no-trailing-spaces": "off",
// "key-spacing": "off",
"no-multiple-empty-lines": "off"
// "spaced-comment": "off",
// "space-in-parens": "off",
// "block-spacing": "off",
// "quote-props": "off",
// "space-unary-ops": "off",
// "no-empty": "off",
// "dot-notation": "off",
// "func-call-spacing": "off",
// "array-bracket-spacing": "off",
// "object-property-newline": "off",
// "no-continue": "off",
// "no-extra-semi": "off",
// "no-spaced-func": "off",
// "no-useless-return": "off"
}
}

29
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,29 @@
<!--
== 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 ++ -->
- **NodeBB version:**
- **NodeBB git hash:**
- **NodeJS version:**
<!-- (to find your git hash, execute `git rev-parse HEAD` from the main NodeBB directory) -->
- **Installed NodeBB Plugins:**
<!-- (to find installed plugins run ./nodebb plugins) -->
- **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! -->

View File

@@ -1,81 +0,0 @@
name: Bug Report
description: File a bug report
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
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 ←
- type: input
attributes:
label: NodeBB version
placeholder: e.g. v2.2.0
- type: input
attributes:
label: NodeBB git hash
description: to find your git hash, execute `git rev-parse HEAD` from the main NodeBB directory
placeholder: e.g. 783250ee6f8c51cdc243ce3b8d9f1a080517247e
- type: input
attributes:
label: NodeJS version
placeholder: e.g. v16.15.1
- type: textarea
attributes:
label: Installed NodeBB plugins
description: to find installed plugins run `./nodebb plugins`
placeholder: |
e.g.
* nodebb-plugin-2factor@5.0.1 (installed, disabled)
* nodebb-plugin-composer-default@8.0.0 (installed, enabled)
* nodebb-plugin-dbsearch@5.1.5 (installed, disabled)
* nodebb-plugin-emoji@4.0.4 (installed, enabled)
* nodebb-plugin-emoji-android@3.0.0 (installed, enabled)
* nodebb-plugin-markdown@10.0.0 (installed, enabled)
* nodebb-plugin-mentions@3.0.11 (installed, enabled)
* nodebb-plugin-spam-be-gone@1.0.0 (installed, disabled)
* nodebb-rewards-essentials@0.2.1 (installed, enabled)
* nodebb-theme-lavender@6.0.0 (installed, disabled)
* nodebb-theme-persona@12.0.11 (installed, enabled)
* nodebb-theme-slick@2.0.2 (installed, disabled)
* nodebb-theme-vanilla@12.1.18 (installed, disabled)
* nodebb-widget-essentials@6.0.0 (installed, enabled)
- type: dropdown
attributes:
label: Database type
multiple: true
options:
- MongoDB
- Redis
- PostgreSQL
- type: input
attributes:
label: Database version
description: "`mongod --version`, `redis-server --version`, or `postgres --version`"
placeholder: e.g. v5.0.9
- type: textarea
attributes:
label: Exact steps to cause this issue
placeholder: |
1. First I did this...
2. Then, I clicked on this item...
A quick note: MP4 and MOV formatted video files are now allowed to be uploaded to GH.
Please upload if reproduction steps are hard to describe or reproduce reliably.
- type: textarea
attributes:
label: What you expected
placeholder: e.g. I expected *abc* to *xyz*
- type: textarea
attributes:
label: What happened instead
placeholder: e.g. Instead, I got *zyx* and NodeBB set fire to my house
- type: textarea
attributes:
label: Anything else?
description: Any additional context about the issue you're encountering
- type: markdown
attributes:
value: "**Thank you!**"

View File

@@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Community Forum
url: https://community.nodebb.org
about: Github Issues are for bug reports and feature requests only, please use community forum for other support

View File

@@ -1,24 +0,0 @@
name: Feature Request
description: Suggest a new feature
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
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 ←
- type: textarea
attributes:
label: Description
validations:
required: true
- type: input
attributes:
label: Community forum reference
description: If this feature was already discussed on the Community Forum link it here
placeholder: https://community.nodebb.org/topic/0/example-feature-request
- type: markdown
attributes:
value: "**Thank you!**"

4
.github/SECURITY.md vendored
View File

@@ -2,8 +2,8 @@
NodeBB's security policy is based around a private bug bounty program. Users are invited to explore NodeBB for vulnerabilities, and report them to the NodeBB team so that they can be patched.
If you have found a security vulnerability, **do not post it onto our GitHub tracker**. Some security vulnerabilities are quite severe and discretion is recommended. Email the NodeBB Security Team at security@nodebb.org, instead, even if you are not sure whether something qualifies.
If you have found a security vulnerability, **do not post it onto our GitHub tracker**. Some security vulnerabilities are quite severe and discretion is recommended. Email the NodeBB Security Team at security@nodebb.org, instead.
# Bug Bounty Program
Security vulnerability reports may be eligible for a bounty based on severity and confirmation from NodeBB team members. For full details regarding our bug bounty program, including the bounty amounts, please consult the [dedicated page for our Bug Bounty Program](https://nodebb.org/bounty).
Security vulnerability reports may be eligible for a bounty based on severity and confirmation from NodeBB team members. For full details regarding our bug bounty program, including the bounty amounts, please consult the following page: https://blog.nodebb.org/bounty

View File

@@ -1,51 +0,0 @@
name: Run Docker
# Controls when the workflow will run
on:
push:
branches:
- 'master'
- 'v*.x'
tags:
- 'v*'
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: nodebb/docker
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
- name: Build and push Docker images
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}

View File

@@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
node: [14, 16, 18]
node: [10, 12, 14]
database: [mongo-dev, mongo, redis, postgres]
include:
# only run coverage once
@@ -69,7 +69,7 @@ jobs:
- 6379:6379
mongo:
image: 'mongo:3.6'
image: 'mongo:3.2'
ports:
# Maps port 27017 on service container to the host
- 27017:27017
@@ -80,7 +80,7 @@ jobs:
- run: cp install/package.json package.json
- name: Install Node
uses: actions/setup-node@v2
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
@@ -186,19 +186,19 @@ jobs:
run: npm run coverage
- name: Test coverage
uses: coverallsapp/github-action@1.1.3
uses: coverallsapp/github-action@v1.1.2
if: matrix.coverage
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: ${{ matrix.os }}-node-${{ matrix.node }}-db-${{ matrix.database }}
parallel: true
finish:
needs: test
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@1.1.3
uses: coverallsapp/github-action@v1.1.2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true

3
.gitignore vendored
View File

@@ -68,5 +68,4 @@ test/files/normalise-resized.jpg
package-lock.json
/package.json
*.mongodb
link-plugins.sh
test.sh
link-plugins.sh

1
.husky/.gitignore vendored
View File

@@ -1 +0,0 @@
_

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit $1

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged

17
.jsbeautifyrc Normal file
View File

@@ -0,0 +1,17 @@
{
"indent_size": 4,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"max_preserve_newlines": 10,
"jslint_happy": true,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": false,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 0
}

91
.jshintrc Normal file
View File

@@ -0,0 +1,91 @@
{
// JSHint Default Configuration File (as on JSHint website)
// See http://jshint.com/docs/ for more details
"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
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"indent" : 4, // {int} Number of spaces to use for indentation
"latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"noempty" : true, // true: Prohibit use of empty blocks
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
"plusplus" : false, // true: Prohibit use of `++` & `--`
"quotmark" : false, // Quotation mark consistency:
// false : do nothing (default)
// true : ensure whatever is used is consistent
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"trailing" : false, // true: Prohibit trailing whitespaces
"maxparams" : false, // {int} Max number of formal params allowed per function
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
"maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
"maxlen" : false, // {int} Max number of characters per line
// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : false, // true: Tolerate use of `== null`
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// (ex: `for each`, multiple try/catch, function expression…)
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
"funcscope" : false, // true: Tolerate defining variables inside control statements"
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
"iterator" : false, // true: Tolerate using the `__iterator__` property
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
"laxcomma" : false, // true: Tolerate comma-first style coding
"loopfunc" : false, // true: Tolerate functions being defined in loops
"multistr" : false, // true: Tolerate multi-line strings
"proto" : false, // true: Tolerate using the `__proto__` property
"scripturl" : false, // true: Tolerate script-targeted URLs
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
"validthis" : false, // true: Tolerate using this in a non-constructor function
// Environments
"browser" : true, // Web Browser (window, document, etc)
"couch" : false, // CouchDB
"devel" : true, // Development/debugging (alert, confirm, etc)
"dojo" : false, // Dojo Toolkit
"jquery" : true, // jQuery
"mootools" : false, // MooTools
"node" : true, // Node.js
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
"prototypejs" : false, // Prototype and Scriptaculous
"rhino" : false, // Rhino
"worker" : false, // Web Workers
"wsh" : false, // Windows Scripting Host
"yui" : false, // Yahoo User Interface
"mocha": true,
// Legacy
"nomen" : false, // true: Prohibit dangling `_` in variables
"onevar" : false, // true: Allow only one `var` statement per function
"passfail" : false, // true: Stop on first error
"white" : false, // true: Check against strict whitespace and indentation rules
// Custom Globals
"globals" : {
"Promise": true
} // additional predefined global variables
}

View File

@@ -41,7 +41,6 @@ trans.rw = public/language/rw/category.json
trans.sc = public/language/sc/category.json
trans.sk = public/language/sk/category.json
trans.sl = public/language/sl/category.json
trans.sq_AL = public/language/sq-AL/category.json
trans.sr = public/language/sr/category.json
trans.sv = public/language/sv/category.json
trans.th = public/language/th/category.json
@@ -92,7 +91,6 @@ trans.rw = public/language/rw/login.json
trans.sc = public/language/sc/login.json
trans.sk = public/language/sk/login.json
trans.sl = public/language/sl/login.json
trans.sq_AL = public/language/sq-AL/login.json
trans.sr = public/language/sr/login.json
trans.sv = public/language/sv/login.json
trans.th = public/language/th/login.json
@@ -143,7 +141,6 @@ trans.rw = public/language/rw/recent.json
trans.sc = public/language/sc/recent.json
trans.sk = public/language/sk/recent.json
trans.sl = public/language/sl/recent.json
trans.sq_AL = public/language/sq-AL/recent.json
trans.sr = public/language/sr/recent.json
trans.sv = public/language/sv/recent.json
trans.th = public/language/th/recent.json
@@ -194,7 +191,6 @@ trans.rw = public/language/rw/unread.json
trans.sc = public/language/sc/unread.json
trans.sk = public/language/sk/unread.json
trans.sl = public/language/sl/unread.json
trans.sq_AL = public/language/sq-AL/unread.json
trans.sr = public/language/sr/unread.json
trans.sv = public/language/sv/unread.json
trans.th = public/language/th/unread.json
@@ -245,7 +241,6 @@ trans.rw = public/language/rw/modules.json
trans.sc = public/language/sc/modules.json
trans.sk = public/language/sk/modules.json
trans.sl = public/language/sl/modules.json
trans.sq_AL = public/language/sq-AL/modules.json
trans.sr = public/language/sr/modules.json
trans.sv = public/language/sv/modules.json
trans.th = public/language/th/modules.json
@@ -296,7 +291,6 @@ trans.rw = public/language/rw/post-queue.json
trans.sc = public/language/sc/post-queue.json
trans.sk = public/language/sk/post-queue.json
trans.sl = public/language/sl/post-queue.json
trans.sq_AL = public/language/sq-AL/post-queue.json
trans.sr = public/language/sr/post-queue.json
trans.sv = public/language/sv/post-queue.json
trans.th = public/language/th/post-queue.json
@@ -347,7 +341,6 @@ trans.rw = public/language/rw/ip-blacklist.json
trans.sc = public/language/sc/ip-blacklist.json
trans.sk = public/language/sk/ip-blacklist.json
trans.sl = public/language/sl/ip-blacklist.json
trans.sq_AL = public/language/sq-AL/ip-blacklist.json
trans.sr = public/language/sr/ip-blacklist.json
trans.sv = public/language/sv/ip-blacklist.json
trans.th = public/language/th/ip-blacklist.json
@@ -398,7 +391,6 @@ trans.rw = public/language/rw/register.json
trans.sc = public/language/sc/register.json
trans.sk = public/language/sk/register.json
trans.sl = public/language/sl/register.json
trans.sq_AL = public/language/sq-AL/register.json
trans.sr = public/language/sr/register.json
trans.sv = public/language/sv/register.json
trans.th = public/language/th/register.json
@@ -449,7 +441,6 @@ trans.rw = public/language/rw/user.json
trans.sc = public/language/sc/user.json
trans.sk = public/language/sk/user.json
trans.sl = public/language/sl/user.json
trans.sq_AL = public/language/sq-AL/user.json
trans.sr = public/language/sr/user.json
trans.sv = public/language/sv/user.json
trans.th = public/language/th/user.json
@@ -500,7 +491,6 @@ trans.rw = public/language/rw/global.json
trans.sc = public/language/sc/global.json
trans.sk = public/language/sk/global.json
trans.sl = public/language/sl/global.json
trans.sq_AL = public/language/sq-AL/global.json
trans.sr = public/language/sr/global.json
trans.sv = public/language/sv/global.json
trans.th = public/language/th/global.json
@@ -551,7 +541,6 @@ trans.rw = public/language/rw/notifications.json
trans.sc = public/language/sc/notifications.json
trans.sk = public/language/sk/notifications.json
trans.sl = public/language/sl/notifications.json
trans.sq_AL = public/language/sq-AL/notifications.json
trans.sr = public/language/sr/notifications.json
trans.sv = public/language/sv/notifications.json
trans.th = public/language/th/notifications.json
@@ -602,7 +591,6 @@ trans.rw = public/language/rw/reset_password.json
trans.sc = public/language/sc/reset_password.json
trans.sk = public/language/sk/reset_password.json
trans.sl = public/language/sl/reset_password.json
trans.sq_AL = public/language/sq-AL/reset_password.json
trans.sr = public/language/sr/reset_password.json
trans.sv = public/language/sv/reset_password.json
trans.th = public/language/th/reset_password.json
@@ -653,7 +641,6 @@ trans.rw = public/language/rw/users.json
trans.sc = public/language/sc/users.json
trans.sk = public/language/sk/users.json
trans.sl = public/language/sl/users.json
trans.sq_AL = public/language/sq-AL/users.json
trans.sr = public/language/sr/users.json
trans.sv = public/language/sv/users.json
trans.th = public/language/th/users.json
@@ -704,7 +691,6 @@ trans.rw = public/language/rw/language.json
trans.sc = public/language/sc/language.json
trans.sk = public/language/sk/language.json
trans.sl = public/language/sl/language.json
trans.sq_AL = public/language/sq-AL/language.json
trans.sr = public/language/sr/language.json
trans.sv = public/language/sv/language.json
trans.th = public/language/th/language.json
@@ -755,7 +741,6 @@ trans.rw = public/language/rw/pages.json
trans.sc = public/language/sc/pages.json
trans.sk = public/language/sk/pages.json
trans.sl = public/language/sl/pages.json
trans.sq_AL = public/language/sq-AL/pages.json
trans.sr = public/language/sr/pages.json
trans.sv = public/language/sv/pages.json
trans.th = public/language/th/pages.json
@@ -806,7 +791,6 @@ trans.rw = public/language/rw/topic.json
trans.sc = public/language/sc/topic.json
trans.sk = public/language/sk/topic.json
trans.sl = public/language/sl/topic.json
trans.sq_AL = public/language/sq-AL/topic.json
trans.sr = public/language/sr/topic.json
trans.sv = public/language/sv/topic.json
trans.th = public/language/th/topic.json
@@ -857,7 +841,6 @@ trans.rw = public/language/rw/success.json
trans.sc = public/language/sc/success.json
trans.sk = public/language/sk/success.json
trans.sl = public/language/sl/success.json
trans.sq_AL = public/language/sq-AL/success.json
trans.sr = public/language/sr/success.json
trans.sv = public/language/sv/success.json
trans.th = public/language/th/success.json
@@ -908,7 +891,6 @@ trans.rw = public/language/rw/error.json
trans.sc = public/language/sc/error.json
trans.sk = public/language/sk/error.json
trans.sl = public/language/sl/error.json
trans.sq_AL = public/language/sq-AL/error.json
trans.sr = public/language/sr/error.json
trans.sv = public/language/sv/error.json
trans.th = public/language/th/error.json
@@ -959,7 +941,6 @@ trans.rw = public/language/rw/flags.json
trans.sc = public/language/sc/flags.json
trans.sk = public/language/sk/flags.json
trans.sl = public/language/sl/flags.json
trans.sq_AL = public/language/sq-AL/flags.json
trans.sr = public/language/sr/flags.json
trans.sv = public/language/sv/flags.json
trans.th = public/language/th/flags.json
@@ -1009,7 +990,6 @@ trans.rw = public/language/rw/tags.json
trans.sc = public/language/sc/tags.json
trans.sk = public/language/sk/tags.json
trans.sl = public/language/sl/tags.json
trans.sq_AL = public/language/sq-AL/tags.json
trans.sr = public/language/sr/tags.json
trans.sv = public/language/sv/tags.json
trans.th = public/language/th/tags.json
@@ -1020,57 +1000,6 @@ trans.zh_CN = public/language/zh-CN/tags.json
trans.zh_TW = public/language/zh-TW/tags.json
type = KEYVALUEJSON
[nodebb.top]
file_filter = public/language/<lang>/top.json
source_file = public/language/en-GB/top.json
source_lang = en_GB
trans.ar = public/language/ar/top.json
trans.bg = public/language/bg/top.json
trans.bn = public/language/bn/top.json
trans.cs = public/language/cs/top.json
trans.da = public/language/da/top.json
trans.de = public/language/de/top.json
trans.el = public/language/el/top.json
trans.en@pirate = public/language/en-x-pirate/top.json
trans.en_US = public/language/en-US/top.json
trans.es = public/language/es/top.json
trans.et = public/language/et/top.json
trans.fa_IR = public/language/fa-IR/top.json
trans.fi = public/language/fi/top.json
trans.fr = public/language/fr/top.json
trans.gl = public/language/gl/top.json
trans.he = public/language/he/top.json
trans.hr = public/language/hr/top.json
trans.hu = public/language/hu/top.json
trans.id = public/language/id/top.json
trans.it = public/language/it/top.json
trans.ja = public/language/ja/top.json
trans.ko = public/language/ko/top.json
trans.lt = public/language/lt/top.json
trans.lv = public/language/lv/top.json
trans.ms = public/language/ms/top.json
trans.nb = public/language/nb/top.json
trans.nl = public/language/nl/top.json
trans.pl = public/language/pl/top.json
trans.pt_BR = public/language/pt-BR/top.json
trans.pt_PT = public/language/pt-PT/top.json
trans.ro = public/language/ro/top.json
trans.ru = public/language/ru/top.json
trans.rw = public/language/rw/top.json
trans.sc = public/language/sc/top.json
trans.sk = public/language/sk/top.json
trans.sl = public/language/sl/top.json
trans.sq_AL = public/language/sq-AL/top.json
trans.sr = public/language/sr/top.json
trans.sv = public/language/sv/top.json
trans.th = public/language/th/top.json
trans.tr = public/language/tr/top.json
trans.uk = public/language/uk/top.json
trans.vi = public/language/vi/top.json
trans.zh_CN = public/language/zh-CN/top.json
trans.zh_TW = public/language/zh-TW/top.json
type = KEYVALUEJSON
[nodebb.email]
file_filter = public/language/<lang>/email.json
source_file = public/language/en-GB/email.json
@@ -1111,7 +1040,6 @@ trans.rw = public/language/rw/email.json
trans.sc = public/language/sc/email.json
trans.sk = public/language/sk/email.json
trans.sl = public/language/sl/email.json
trans.sq_AL = public/language/sq-AL/email.json
trans.sr = public/language/sr/email.json
trans.sv = public/language/sv/email.json
trans.th = public/language/th/email.json
@@ -1162,7 +1090,6 @@ trans.rw = public/language/rw/search.json
trans.sc = public/language/sc/search.json
trans.sk = public/language/sk/search.json
trans.sl = public/language/sl/search.json
trans.sq_AL = public/language/sq-AL/search.json
trans.sr = public/language/sr/search.json
trans.sv = public/language/sv/search.json
trans.th = public/language/th/search.json
@@ -1213,7 +1140,6 @@ trans.rw = public/language/rw/groups.json
trans.sc = public/language/sc/groups.json
trans.sk = public/language/sk/groups.json
trans.sl = public/language/sl/groups.json
trans.sq_AL = public/language/sq-AL/groups.json
trans.sr = public/language/sr/groups.json
trans.sv = public/language/sv/groups.json
trans.th = public/language/th/groups.json
@@ -1264,7 +1190,6 @@ trans.rw = public/language/rw/uploads.json
trans.sc = public/language/sc/uploads.json
trans.sk = public/language/sk/uploads.json
trans.sl = public/language/sl/uploads.json
trans.sq_AL = public/language/sq-AL/uploads.json
trans.sr = public/language/sr/uploads.json
trans.sv = public/language/sv/uploads.json
trans.th = public/language/th/uploads.json
@@ -1315,7 +1240,6 @@ trans.rw = public/language/rw/admin/admin.json
trans.sc = public/language/sc/admin/admin.json
trans.sk = public/language/sk/admin/admin.json
trans.sl = public/language/sl/admin/admin.json
trans.sq_AL = public/language/sq-AL/admin/admin.json
trans.sr = public/language/sr/admin/admin.json
trans.sv = public/language/sv/admin/admin.json
trans.th = public/language/th/admin/admin.json
@@ -1366,7 +1290,6 @@ trans.rw = public/language/rw/admin/menu.json
trans.sc = public/language/sc/admin/menu.json
trans.sk = public/language/sk/admin/menu.json
trans.sl = public/language/sl/admin/menu.json
trans.sq_AL = public/language/sq-AL/admin/menu.json
trans.sr = public/language/sr/admin/menu.json
trans.sv = public/language/sv/admin/menu.json
trans.th = public/language/th/admin/menu.json
@@ -1417,7 +1340,6 @@ trans.rw = public/language/rw/admin/advanced/cache.json
trans.sc = public/language/sc/admin/advanced/cache.json
trans.sk = public/language/sk/admin/advanced/cache.json
trans.sl = public/language/sl/admin/advanced/cache.json
trans.sq_AL = public/language/sq-AL/admin/advanced/cache.json
trans.sr = public/language/sr/admin/advanced/cache.json
trans.sv = public/language/sv/admin/advanced/cache.json
trans.th = public/language/th/admin/advanced/cache.json
@@ -1468,7 +1390,6 @@ trans.rw = public/language/rw/admin/advanced/database.json
trans.sc = public/language/sc/admin/advanced/database.json
trans.sk = public/language/sk/admin/advanced/database.json
trans.sl = public/language/sl/admin/advanced/database.json
trans.sq_AL = public/language/sq-AL/admin/advanced/database.json
trans.sr = public/language/sr/admin/advanced/database.json
trans.sv = public/language/sv/admin/advanced/database.json
trans.th = public/language/th/admin/advanced/database.json
@@ -1519,7 +1440,6 @@ trans.rw = public/language/rw/admin/advanced/errors.json
trans.sc = public/language/sc/admin/advanced/errors.json
trans.sk = public/language/sk/admin/advanced/errors.json
trans.sl = public/language/sl/admin/advanced/errors.json
trans.sq_AL = public/language/sq-AL/admin/advanced/errors.json
trans.sr = public/language/sr/admin/advanced/errors.json
trans.sv = public/language/sv/admin/advanced/errors.json
trans.th = public/language/th/admin/advanced/errors.json
@@ -1570,7 +1490,6 @@ trans.rw = public/language/rw/admin/advanced/events.json
trans.sc = public/language/sc/admin/advanced/events.json
trans.sk = public/language/sk/admin/advanced/events.json
trans.sl = public/language/sl/admin/advanced/events.json
trans.sq_AL = public/language/sq-AL/admin/advanced/events.json
trans.sr = public/language/sr/admin/advanced/events.json
trans.sv = public/language/sv/admin/advanced/events.json
trans.th = public/language/th/admin/advanced/events.json
@@ -1621,7 +1540,6 @@ trans.rw = public/language/rw/admin/advanced/logs.json
trans.sc = public/language/sc/admin/advanced/logs.json
trans.sk = public/language/sk/admin/advanced/logs.json
trans.sl = public/language/sl/admin/advanced/logs.json
trans.sq_AL = public/language/sq-AL/admin/advanced/logs.json
trans.sr = public/language/sr/admin/advanced/logs.json
trans.sv = public/language/sv/admin/advanced/logs.json
trans.th = public/language/th/admin/advanced/logs.json
@@ -1672,7 +1590,6 @@ trans.rw = public/language/rw/admin/appearance/customise.json
trans.sc = public/language/sc/admin/appearance/customise.json
trans.sk = public/language/sk/admin/appearance/customise.json
trans.sl = public/language/sl/admin/appearance/customise.json
trans.sq_AL = public/language/sq-AL/admin/appearance/customise.json
trans.sr = public/language/sr/admin/appearance/customise.json
trans.sv = public/language/sv/admin/appearance/customise.json
trans.th = public/language/th/admin/appearance/customise.json
@@ -1723,7 +1640,6 @@ trans.rw = public/language/rw/admin/appearance/skins.json
trans.sc = public/language/sc/admin/appearance/skins.json
trans.sk = public/language/sk/admin/appearance/skins.json
trans.sl = public/language/sl/admin/appearance/skins.json
trans.sq_AL = public/language/sq-AL/admin/appearance/skins.json
trans.sr = public/language/sr/admin/appearance/skins.json
trans.sv = public/language/sv/admin/appearance/skins.json
trans.th = public/language/th/admin/appearance/skins.json
@@ -1774,7 +1690,6 @@ trans.rw = public/language/rw/admin/appearance/themes.json
trans.sc = public/language/sc/admin/appearance/themes.json
trans.sk = public/language/sk/admin/appearance/themes.json
trans.sl = public/language/sl/admin/appearance/themes.json
trans.sq_AL = public/language/sq-AL/admin/appearance/themes.json
trans.sr = public/language/sr/admin/appearance/themes.json
trans.sv = public/language/sv/admin/appearance/themes.json
trans.th = public/language/th/admin/appearance/themes.json
@@ -1825,7 +1740,6 @@ trans.rw = public/language/rw/admin/development/info.json
trans.sc = public/language/sc/admin/development/info.json
trans.sk = public/language/sk/admin/development/info.json
trans.sl = public/language/sl/admin/development/info.json
trans.sq_AL = public/language/sq-AL/admin/development/info.json
trans.sr = public/language/sr/admin/development/info.json
trans.sv = public/language/sv/admin/development/info.json
trans.th = public/language/th/admin/development/info.json
@@ -1876,7 +1790,6 @@ trans.rw = public/language/rw/admin/development/logger.json
trans.sc = public/language/sc/admin/development/logger.json
trans.sk = public/language/sk/admin/development/logger.json
trans.sl = public/language/sl/admin/development/logger.json
trans.sq_AL = public/language/sq-AL/admin/development/logger.json
trans.sr = public/language/sr/admin/development/logger.json
trans.sv = public/language/sv/admin/development/logger.json
trans.th = public/language/th/admin/development/logger.json
@@ -1927,7 +1840,6 @@ trans.rw = public/language/rw/admin/extend/plugins.json
trans.sc = public/language/sc/admin/extend/plugins.json
trans.sk = public/language/sk/admin/extend/plugins.json
trans.sl = public/language/sl/admin/extend/plugins.json
trans.sq_AL = public/language/sq-AL/admin/extend/plugins.json
trans.sr = public/language/sr/admin/extend/plugins.json
trans.sv = public/language/sv/admin/extend/plugins.json
trans.th = public/language/th/admin/extend/plugins.json
@@ -1978,7 +1890,6 @@ trans.rw = public/language/rw/admin/extend/rewards.json
trans.sc = public/language/sc/admin/extend/rewards.json
trans.sk = public/language/sk/admin/extend/rewards.json
trans.sl = public/language/sl/admin/extend/rewards.json
trans.sq_AL = public/language/sq-AL/admin/extend/rewards.json
trans.sr = public/language/sr/admin/extend/rewards.json
trans.sv = public/language/sv/admin/extend/rewards.json
trans.th = public/language/th/admin/extend/rewards.json
@@ -2029,7 +1940,6 @@ trans.rw = public/language/rw/admin/extend/widgets.json
trans.sc = public/language/sc/admin/extend/widgets.json
trans.sk = public/language/sk/admin/extend/widgets.json
trans.sl = public/language/sl/admin/extend/widgets.json
trans.sq_AL = public/language/sq-AL/admin/extend/widgets.json
trans.sr = public/language/sr/admin/extend/widgets.json
trans.sv = public/language/sv/admin/extend/widgets.json
trans.th = public/language/th/admin/extend/widgets.json
@@ -2080,7 +1990,6 @@ trans.rw = public/language/rw/admin/dashboard.json
trans.sc = public/language/sc/admin/dashboard.json
trans.sk = public/language/sk/admin/dashboard.json
trans.sl = public/language/sl/admin/dashboard.json
trans.sq_AL = public/language/sq-AL/admin/dashboard.json
trans.sr = public/language/sr/admin/dashboard.json
trans.sv = public/language/sv/admin/dashboard.json
trans.th = public/language/th/admin/dashboard.json
@@ -2131,7 +2040,6 @@ trans.rw = public/language/rw/admin/settings/homepage.json
trans.sc = public/language/sc/admin/settings/homepage.json
trans.sk = public/language/sk/admin/settings/homepage.json
trans.sl = public/language/sl/admin/settings/homepage.json
trans.sq_AL = public/language/sq-AL/admin/settings/homepage.json
trans.sr = public/language/sr/admin/settings/homepage.json
trans.sv = public/language/sv/admin/settings/homepage.json
trans.th = public/language/th/admin/settings/homepage.json
@@ -2182,7 +2090,6 @@ trans.rw = public/language/rw/admin/settings/languages.json
trans.sc = public/language/sc/admin/settings/languages.json
trans.sk = public/language/sk/admin/settings/languages.json
trans.sl = public/language/sl/admin/settings/languages.json
trans.sq_AL = public/language/sq-AL/admin/settings/languages.json
trans.sr = public/language/sr/admin/settings/languages.json
trans.sv = public/language/sv/admin/settings/languages.json
trans.th = public/language/th/admin/settings/languages.json
@@ -2233,7 +2140,6 @@ trans.rw = public/language/rw/admin/settings/navigation.json
trans.sc = public/language/sc/admin/settings/navigation.json
trans.sk = public/language/sk/admin/settings/navigation.json
trans.sl = public/language/sl/admin/settings/navigation.json
trans.sq_AL = public/language/sq-AL/admin/settings/navigation.json
trans.sr = public/language/sr/admin/settings/navigation.json
trans.sv = public/language/sv/admin/settings/navigation.json
trans.th = public/language/th/admin/settings/navigation.json
@@ -2284,7 +2190,6 @@ trans.rw = public/language/rw/admin/settings/social.json
trans.sc = public/language/sc/admin/settings/social.json
trans.sk = public/language/sk/admin/settings/social.json
trans.sl = public/language/sl/admin/settings/social.json
trans.sq_AL = public/language/sq-AL/admin/settings/social.json
trans.sr = public/language/sr/admin/settings/social.json
trans.sv = public/language/sv/admin/settings/social.json
trans.th = public/language/th/admin/settings/social.json
@@ -2335,7 +2240,6 @@ trans.rw = public/language/rw/admin/settings/sounds.json
trans.sc = public/language/sc/admin/settings/sounds.json
trans.sk = public/language/sk/admin/settings/sounds.json
trans.sl = public/language/sl/admin/settings/sounds.json
trans.sq_AL = public/language/sq-AL/admin/settings/sounds.json
trans.sr = public/language/sr/admin/settings/sounds.json
trans.sv = public/language/sv/admin/settings/sounds.json
trans.th = public/language/th/admin/settings/sounds.json
@@ -2386,7 +2290,6 @@ trans.rw = public/language/rw/admin/manage/admins-mods.json
trans.sc = public/language/sc/admin/manage/admins-mods.json
trans.sk = public/language/sk/admin/manage/admins-mods.json
trans.sl = public/language/sl/admin/manage/admins-mods.json
trans.sq_AL = public/language/sq-AL/admin/manage/admins-mods.json
trans.sr = public/language/sr/admin/manage/admins-mods.json
trans.sv = public/language/sv/admin/manage/admins-mods.json
trans.th = public/language/th/admin/manage/admins-mods.json
@@ -2437,7 +2340,6 @@ trans.rw = public/language/rw/admin/manage/categories.json
trans.sc = public/language/sc/admin/manage/categories.json
trans.sk = public/language/sk/admin/manage/categories.json
trans.sl = public/language/sl/admin/manage/categories.json
trans.sq_AL = public/language/sq-AL/admin/manage/categories.json
trans.sr = public/language/sr/admin/manage/categories.json
trans.sv = public/language/sv/admin/manage/categories.json
trans.th = public/language/th/admin/manage/categories.json
@@ -2488,7 +2390,6 @@ trans.rw = public/language/rw/admin/manage/groups.json
trans.sc = public/language/sc/admin/manage/groups.json
trans.sk = public/language/sk/admin/manage/groups.json
trans.sl = public/language/sl/admin/manage/groups.json
trans.sq_AL = public/language/sq-AL/admin/manage/groups.json
trans.sr = public/language/sr/admin/manage/groups.json
trans.sv = public/language/sv/admin/manage/groups.json
trans.th = public/language/th/admin/manage/groups.json
@@ -2539,7 +2440,6 @@ trans.rw = public/language/rw/admin/manage/privileges.json
trans.sc = public/language/sc/admin/manage/privileges.json
trans.sk = public/language/sk/admin/manage/privileges.json
trans.sl = public/language/sl/admin/manage/privileges.json
trans.sq_AL = public/language/sq-AL/admin/manage/privileges.json
trans.sr = public/language/sr/admin/manage/privileges.json
trans.sv = public/language/sv/admin/manage/privileges.json
trans.th = public/language/th/admin/manage/privileges.json
@@ -2590,7 +2490,6 @@ trans.rw = public/language/rw/admin/manage/registration.json
trans.sc = public/language/sc/admin/manage/registration.json
trans.sk = public/language/sk/admin/manage/registration.json
trans.sl = public/language/sl/admin/manage/registration.json
trans.sq_AL = public/language/sq-AL/admin/manage/registration.json
trans.sr = public/language/sr/admin/manage/registration.json
trans.sv = public/language/sv/admin/manage/registration.json
trans.th = public/language/th/admin/manage/registration.json
@@ -2641,7 +2540,6 @@ trans.rw = public/language/rw/admin/manage/tags.json
trans.sc = public/language/sc/admin/manage/tags.json
trans.sk = public/language/sk/admin/manage/tags.json
trans.sl = public/language/sl/admin/manage/tags.json
trans.sq_AL = public/language/sq-AL/admin/manage/tags.json
trans.sr = public/language/sr/admin/manage/tags.json
trans.sv = public/language/sv/admin/manage/tags.json
trans.th = public/language/th/admin/manage/tags.json
@@ -2692,7 +2590,6 @@ trans.rw = public/language/rw/admin/manage/uploads.json
trans.sc = public/language/sc/admin/manage/uploads.json
trans.sk = public/language/sk/admin/manage/uploads.json
trans.sl = public/language/sl/admin/manage/uploads.json
trans.sq_AL = public/language/sq-AL/admin/manage/uploads.json
trans.sr = public/language/sr/admin/manage/uploads.json
trans.sv = public/language/sv/admin/manage/uploads.json
trans.th = public/language/th/admin/manage/uploads.json
@@ -2743,7 +2640,6 @@ trans.rw = public/language/rw/admin/manage/users.json
trans.sc = public/language/sc/admin/manage/users.json
trans.sk = public/language/sk/admin/manage/users.json
trans.sl = public/language/sl/admin/manage/users.json
trans.sq_AL = public/language/sq-AL/admin/manage/users.json
trans.sr = public/language/sr/admin/manage/users.json
trans.sv = public/language/sv/admin/manage/users.json
trans.th = public/language/th/admin/manage/users.json
@@ -2794,7 +2690,6 @@ trans.rw = public/language/rw/admin/manage/digest.json
trans.sc = public/language/sc/admin/manage/digest.json
trans.sk = public/language/sk/admin/manage/digest.json
trans.sl = public/language/sl/admin/manage/digest.json
trans.sq_AL = public/language/sq-AL/admin/manage/digest.json
trans.sr = public/language/sr/admin/manage/digest.json
trans.sv = public/language/sv/admin/manage/digest.json
trans.th = public/language/th/admin/manage/digest.json
@@ -2845,7 +2740,6 @@ trans.rw = public/language/rw/admin/settings/advanced.json
trans.sc = public/language/sc/admin/settings/advanced.json
trans.sk = public/language/sk/admin/settings/advanced.json
trans.sl = public/language/sl/admin/settings/advanced.json
trans.sq_AL = public/language/sq-AL/admin/settings/advanced.json
trans.sr = public/language/sr/admin/settings/advanced.json
trans.sv = public/language/sv/admin/settings/advanced.json
trans.th = public/language/th/admin/settings/advanced.json
@@ -2896,7 +2790,6 @@ trans.rw = public/language/rw/admin/settings/cookies.json
trans.sc = public/language/sc/admin/settings/cookies.json
trans.sk = public/language/sk/admin/settings/cookies.json
trans.sl = public/language/sl/admin/settings/cookies.json
trans.sq_AL = public/language/sq-AL/admin/settings/cookies.json
trans.sr = public/language/sr/admin/settings/cookies.json
trans.sv = public/language/sv/admin/settings/cookies.json
trans.th = public/language/th/admin/settings/cookies.json
@@ -2947,7 +2840,6 @@ trans.rw = public/language/rw/admin/settings/general.json
trans.sc = public/language/sc/admin/settings/general.json
trans.sk = public/language/sk/admin/settings/general.json
trans.sl = public/language/sl/admin/settings/general.json
trans.sq_AL = public/language/sq-AL/admin/settings/general.json
trans.sr = public/language/sr/admin/settings/general.json
trans.sv = public/language/sv/admin/settings/general.json
trans.th = public/language/th/admin/settings/general.json
@@ -2998,7 +2890,6 @@ trans.rw = public/language/rw/admin/settings/guest.json
trans.sc = public/language/sc/admin/settings/guest.json
trans.sk = public/language/sk/admin/settings/guest.json
trans.sl = public/language/sl/admin/settings/guest.json
trans.sq_AL = public/language/sq-AL/admin/settings/guest.json
trans.sr = public/language/sr/admin/settings/guest.json
trans.sv = public/language/sv/admin/settings/guest.json
trans.th = public/language/th/admin/settings/guest.json
@@ -3049,7 +2940,6 @@ trans.rw = public/language/rw/admin/settings/pagination.json
trans.sc = public/language/sc/admin/settings/pagination.json
trans.sk = public/language/sk/admin/settings/pagination.json
trans.sl = public/language/sl/admin/settings/pagination.json
trans.sq_AL = public/language/sq-AL/admin/settings/pagination.json
trans.sr = public/language/sr/admin/settings/pagination.json
trans.sv = public/language/sv/admin/settings/pagination.json
trans.th = public/language/th/admin/settings/pagination.json
@@ -3100,7 +2990,6 @@ trans.rw = public/language/rw/admin/settings/reputation.json
trans.sc = public/language/sc/admin/settings/reputation.json
trans.sk = public/language/sk/admin/settings/reputation.json
trans.sl = public/language/sl/admin/settings/reputation.json
trans.sq_AL = public/language/sq-AL/admin/settings/reputation.json
trans.sr = public/language/sr/admin/settings/reputation.json
trans.sv = public/language/sv/admin/settings/reputation.json
trans.th = public/language/th/admin/settings/reputation.json
@@ -3151,7 +3040,6 @@ trans.rw = public/language/rw/admin/settings/tags.json
trans.sc = public/language/sc/admin/settings/tags.json
trans.sk = public/language/sk/admin/settings/tags.json
trans.sl = public/language/sl/admin/settings/tags.json
trans.sq_AL = public/language/sq-AL/admin/settings/tags.json
trans.sr = public/language/sr/admin/settings/tags.json
trans.sv = public/language/sv/admin/settings/tags.json
trans.th = public/language/th/admin/settings/tags.json
@@ -3202,7 +3090,6 @@ trans.rw = public/language/rw/admin/settings/user.json
trans.sc = public/language/sc/admin/settings/user.json
trans.sk = public/language/sk/admin/settings/user.json
trans.sl = public/language/sl/admin/settings/user.json
trans.sq_AL = public/language/sq-AL/admin/settings/user.json
trans.sr = public/language/sr/admin/settings/user.json
trans.sv = public/language/sv/admin/settings/user.json
trans.th = public/language/th/admin/settings/user.json
@@ -3253,7 +3140,6 @@ trans.rw = public/language/rw/admin/settings/chat.json
trans.sc = public/language/sc/admin/settings/chat.json
trans.sk = public/language/sk/admin/settings/chat.json
trans.sl = public/language/sl/admin/settings/chat.json
trans.sq_AL = public/language/sq-AL/admin/settings/chat.json
trans.sr = public/language/sr/admin/settings/chat.json
trans.sv = public/language/sv/admin/settings/chat.json
trans.th = public/language/th/admin/settings/chat.json
@@ -3304,7 +3190,6 @@ trans.rw = public/language/rw/admin/settings/email.json
trans.sc = public/language/sc/admin/settings/email.json
trans.sk = public/language/sk/admin/settings/email.json
trans.sl = public/language/sl/admin/settings/email.json
trans.sq_AL = public/language/sq-AL/admin/settings/email.json
trans.sr = public/language/sr/admin/settings/email.json
trans.sv = public/language/sv/admin/settings/email.json
trans.th = public/language/th/admin/settings/email.json
@@ -3355,7 +3240,6 @@ trans.rw = public/language/rw/admin/settings/group.json
trans.sc = public/language/sc/admin/settings/group.json
trans.sk = public/language/sk/admin/settings/group.json
trans.sl = public/language/sl/admin/settings/group.json
trans.sq_AL = public/language/sq-AL/admin/settings/group.json
trans.sr = public/language/sr/admin/settings/group.json
trans.sv = public/language/sv/admin/settings/group.json
trans.th = public/language/th/admin/settings/group.json
@@ -3406,7 +3290,6 @@ trans.rw = public/language/rw/admin/settings/notifications.json
trans.sc = public/language/sc/admin/settings/notifications.json
trans.sk = public/language/sk/admin/settings/notifications.json
trans.sl = public/language/sl/admin/settings/notifications.json
trans.sq_AL = public/language/sq-AL/admin/settings/notifications.json
trans.sr = public/language/sr/admin/settings/notifications.json
trans.sv = public/language/sv/admin/settings/notifications.json
trans.th = public/language/th/admin/settings/notifications.json
@@ -3457,7 +3340,6 @@ trans.rw = public/language/rw/admin/settings/api.json
trans.sc = public/language/sc/admin/settings/api.json
trans.sk = public/language/sk/admin/settings/api.json
trans.sl = public/language/sl/admin/settings/api.json
trans.sq_AL = public/language/sq-AL/admin/settings/api.json
trans.sr = public/language/sr/admin/settings/api.json
trans.sv = public/language/sv/admin/settings/api.json
trans.th = public/language/th/admin/settings/api.json
@@ -3508,7 +3390,6 @@ trans.rw = public/language/rw/admin/settings/post.json
trans.sc = public/language/sc/admin/settings/post.json
trans.sk = public/language/sk/admin/settings/post.json
trans.sl = public/language/sl/admin/settings/post.json
trans.sq_AL = public/language/sq-AL/admin/settings/post.json
trans.sr = public/language/sr/admin/settings/post.json
trans.sv = public/language/sv/admin/settings/post.json
trans.th = public/language/th/admin/settings/post.json
@@ -3559,7 +3440,6 @@ trans.rw = public/language/rw/admin/settings/sockets.json
trans.sc = public/language/sc/admin/settings/sockets.json
trans.sk = public/language/sk/admin/settings/sockets.json
trans.sl = public/language/sl/admin/settings/sockets.json
trans.sq_AL = public/language/sq-AL/admin/settings/sockets.json
trans.sr = public/language/sr/admin/settings/sockets.json
trans.sv = public/language/sv/admin/settings/sockets.json
trans.th = public/language/th/admin/settings/sockets.json
@@ -3610,7 +3490,6 @@ trans.rw = public/language/rw/admin/settings/uploads.json
trans.sc = public/language/sc/admin/settings/uploads.json
trans.sk = public/language/sk/admin/settings/uploads.json
trans.sl = public/language/sl/admin/settings/uploads.json
trans.sq_AL = public/language/sq-AL/admin/settings/uploads.json
trans.sr = public/language/sr/admin/settings/uploads.json
trans.sv = public/language/sv/admin/settings/uploads.json
trans.th = public/language/th/admin/settings/uploads.json
@@ -3661,7 +3540,6 @@ trans.rw = public/language/rw/admin/settings/web-crawler.json
trans.sc = public/language/sc/admin/settings/web-crawler.json
trans.sk = public/language/sk/admin/settings/web-crawler.json
trans.sl = public/language/sl/admin/settings/web-crawler.json
trans.sq_AL = public/language/sq-AL/admin/settings/web-crawler.json
trans.sr = public/language/sr/admin/settings/web-crawler.json
trans.sv = public/language/sv/admin/settings/web-crawler.json
trans.th = public/language/th/admin/settings/web-crawler.json

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,17 @@
FROM node:lts
RUN mkdir -p /usr/src/app && \
chown -R node:node /usr/src/app
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
COPY --chown=node:node install/package.json /usr/src/app/package.json
USER node
COPY install/package.json /usr/src/app/package.json
RUN npm install --only=prod && \
npm cache clean --force
COPY --chown=node:node . /usr/src/app
COPY . /usr/src/app
ENV NODE_ENV=production \
daemon=false \
@@ -22,4 +19,4 @@ ENV NODE_ENV=production \
EXPOSE 4567
CMD test -n "${SETUP}" && ./nodebb setup || node ./nodebb build; node ./nodebb start
CMD node ./nodebb build ; node ./nodebb start

View File

@@ -2,28 +2,24 @@
const path = require('path');
const nconf = require('nconf');
nconf.argv().env({
separator: '__',
});
const winston = require('winston');
const { fork } = require('child_process');
const { env } = process;
let worker;
const fork = require('child_process').fork;
const env = process.env;
var worker;
env.NODE_ENV = env.NODE_ENV || 'development';
const configFile = path.resolve(__dirname, nconf.any(['config', 'CONFIG']) || 'config.json');
const prestart = require('./src/prestart');
prestart.loadConfig(configFile);
const db = require('./src/database');
const plugins = require('./src/plugins');
var db = require('./src/database');
module.exports = function (grunt) {
const args = [];
var args = [];
if (!grunt.option('verbose')) {
args.push('--log-level=info');
@@ -40,36 +36,36 @@ module.exports = function (grunt) {
grunt.registerTask('default', ['watch']);
grunt.registerTask('init', async function () {
const done = this.async();
let pluginList = [];
var done = this.async();
let plugins = [];
if (!process.argv.includes('--core')) {
await db.init();
pluginList = await plugins.getActive();
addBaseThemes(pluginList);
if (!pluginList.includes('nodebb-plugin-composer-default')) {
pluginList.push('nodebb-plugin-composer-default');
plugins = await db.getSortedSetRange('plugins:active', 0, -1);
addBaseThemes(plugins);
if (!plugins.includes('nodebb-plugin-composer-default')) {
plugins.push('nodebb-plugin-composer-default');
}
if (!pluginList.includes('nodebb-theme-persona')) {
pluginList.push('nodebb-theme-persona');
if (!plugins.includes('nodebb-theme-persona')) {
plugins.push('nodebb-theme-persona');
}
}
const styleUpdated_Client = pluginList.map(p => `node_modules/${p}/*.less`)
.concat(pluginList.map(p => `node_modules/${p}/*.css`))
.concat(pluginList.map(p => `node_modules/${p}/+(public|static|less)/**/*.less`))
.concat(pluginList.map(p => `node_modules/${p}/+(public|static)/**/*.css`));
const styleUpdated_Client = plugins.map(p => 'node_modules/' + p + '/*.less')
.concat(plugins.map(p => 'node_modules/' + p + '/*.css'))
.concat(plugins.map(p => 'node_modules/' + p + '/+(public|static|less)/**/*.less'))
.concat(plugins.map(p => 'node_modules/' + p + '/+(public|static)/**/*.css'));
const styleUpdated_Admin = pluginList.map(p => `node_modules/${p}/*.less`)
.concat(pluginList.map(p => `node_modules/${p}/*.css`))
.concat(pluginList.map(p => `node_modules/${p}/+(public|static|less)/**/*.less`))
.concat(pluginList.map(p => `node_modules/${p}/+(public|static)/**/*.css`));
const styleUpdated_Admin = plugins.map(p => 'node_modules/' + p + '/*.less')
.concat(plugins.map(p => 'node_modules/' + p + '/*.css'))
.concat(plugins.map(p => 'node_modules/' + p + '/+(public|static|less)/**/*.less'))
.concat(plugins.map(p => 'node_modules/' + p + '/+(public|static)/**/*.css'));
const clientUpdated = pluginList.map(p => `node_modules/${p}/+(public|static)/**/*.js`);
const serverUpdated = pluginList.map(p => `node_modules/${p}/*.js`)
.concat(pluginList.map(p => `node_modules/${p}/+(lib|src)/**/*.js`));
const clientUpdated = plugins.map(p => 'node_modules/' + p + '/+(public|static)/**/*.js');
const serverUpdated = plugins.map(p => 'node_modules/' + p + '/*.js')
.concat(plugins.map(p => 'node_modules/' + p + '/+(lib|src)/**/*.js'));
const templatesUpdated = pluginList.map(p => `node_modules/${p}/+(public|static|templates)/**/*.tpl`);
const langUpdated = pluginList.map(p => `node_modules/${p}/+(public|static|languages)/**/*.json`);
const templatesUpdated = plugins.map(p => 'node_modules/' + p + '/+(public|static|templates)/**/*.tpl');
const langUpdated = plugins.map(p => 'node_modules/' + p + '/+(public|static|languages)/**/*.json');
grunt.config(['watch'], {
styleUpdated_Client: {
@@ -93,7 +89,6 @@ module.exports = function (grunt) {
clientUpdated: {
files: [
'public/src/**/*.js',
'public/vendor/**/*.js',
...clientUpdated,
'node_modules/benchpressjs/build/benchpress.js',
],
@@ -106,9 +101,9 @@ module.exports = function (grunt) {
'app.js',
'install/*.js',
'src/**/*.js',
'public/src/modules/translator.common.js',
'public/src/modules/helpers.common.js',
'public/src/utils.common.js',
'public/src/modules/translator.js',
'public/src/modules/helpers.js',
'public/src/utils.js',
serverUpdated,
'!src/upgrades/**',
],
@@ -138,10 +133,9 @@ module.exports = function (grunt) {
});
const build = require('./src/meta/build');
if (!grunt.option('skip')) {
await build.build(true, { webpack: false });
await build.build(true);
}
run();
await build.webpack({ watch: true });
done();
});
@@ -166,8 +160,8 @@ module.exports = function (grunt) {
grunt.task.run('init');
grunt.event.removeAllListeners('watch');
grunt.event.on('watch', (action, filepath, target) => {
let compiling;
grunt.event.on('watch', function update(action, filepath, target) {
var compiling;
if (target === 'styleUpdated_Client') {
compiling = 'clientCSS';
} else if (target === 'styleUpdated_Admin') {
@@ -185,7 +179,7 @@ module.exports = function (grunt) {
return run();
}
require('./src/meta/build').build([compiling], { webpack: false }, (err) => {
require('./src/meta/build').build([compiling], function (err) {
if (err) {
winston.error(err.stack);
}
@@ -196,23 +190,23 @@ module.exports = function (grunt) {
});
};
function addBaseThemes(pluginList) {
let themeId = pluginList.find(p => p.includes('nodebb-theme-'));
function addBaseThemes(plugins) {
let themeId = plugins.find(p => p.includes('nodebb-theme-'));
if (!themeId) {
return pluginList;
return plugins;
}
let baseTheme;
do {
try {
baseTheme = require(`${themeId}/theme`).baseTheme;
baseTheme = require(themeId + '/theme').baseTheme;
} catch (err) {
console.log(err);
}
if (baseTheme) {
pluginList.push(baseTheme);
plugins.push(baseTheme);
themeId = baseTheme;
}
} while (baseTheme);
return pluginList;
return plugins;
}

View File

@@ -1,14 +1,22 @@
# ![NodeBB](public/images/sm-card.png)
# ![NodeBB](public/images/logo.svg)
[![Workflow](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml/badge.svg)](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml)
[![Build Status](https://travis-ci.org/NodeBB/NodeBB.svg?branch=master)](https://travis-ci.org/NodeBB/NodeBB)
[![Coverage Status](https://coveralls.io/repos/github/NodeBB/NodeBB/badge.svg?branch=master)](https://coveralls.io/github/NodeBB/NodeBB?branch=master)
[![Dependency Status](https://david-dm.org/nodebb/nodebb.svg?path=install)](https://david-dm.org/nodebb/nodebb?path=install)
[![Code Climate](https://codeclimate.com/github/NodeBB/NodeBB/badges/gpa.svg)](https://codeclimate.com/github/NodeBB/NodeBB)
[**NodeBB Forum Software**](https://nodebb.org) is powered by Node.js and supports either Redis, MongoDB, or a PostgreSQL database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB takes the best of the modern web: real-time streaming discussions, mobile responsiveness, and rich RESTful read/write APIs, while staying true to the original bulletin board/forum format &rarr; categorical hierarchies, local user accounts, and asynchronous messaging.
[**NodeBB Forum Software**](https://nodebb.org) is powered by Node.js and supports either Redis, MongoDB, or a PostgreSQL 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.
NodeBB by itself contains a "common core" of basic functionality, while additional functionality and integrations are enabled through the use of third-party plugins.
Additional functionality is enabled through the use of third-party plugins.
### [Try it now](//try.nodebb.org) | [Documentation](//docs.nodebb.org)
* [Demo](https://try.nodebb.org)
* [Developer Community](http://community.nodebb.org)
* [Documentation & Installation Instructions](http://docs.nodebb.org)
* [Help translate NodeBB](https://www.transifex.com/projects/p/nodebb/)
* [NodeBB Blog](http://blog.nodebb.org)
* [Premium Hosting for NodeBB](http://www.nodebb.org/ "NodeBB")
* [Follow us on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter")
* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
## Screenshots
@@ -34,7 +42,7 @@ Our minimalist "Persona" theme gets you going right away, no coding experience r
* 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 know languages other than English you can help us translate NodeBB. We use [Transifex](https://explore.transifex.com/nodebb/nodebb/) for internationalization.
* If you know languages other than English you can help us translate NodeBB. We use [Transifex](https://www.transifex.com/projects/p/nodebb/) for internationalization.
* Please don't forget to **like**, **follow**, and **star our repo**! Join our growing [community](http://community.nodebb.org) to keep up to date with the latest NodeBB development.
## Requirements
@@ -42,8 +50,7 @@ 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 12 or greater ([installation/upgrade instructions](https://github.com/nodesource/distributions))
* MongoDB, version 3.6 or greater **or** Redis, version 2.8.9 or greater
* If you are using [clustering](https://docs.nodebb.org/configuring/scaling/) you need Redis installed and configured.
* MongoDB, version 2.6 or greater **or** Redis, version 2.8.9 or greater
* nginx, version 1.3.13 or greater (**only if** intending to use nginx to proxy requests to a NodeBB)
## Installation
@@ -70,15 +77,3 @@ Detailed upgrade instructions are listed in [Upgrading NodeBB](https://docs.node
NodeBB is licensed under the **GNU General Public License v3 (GPL-3)** (http://www.gnu.org/copyleft/gpl.html).
Interested in a sublicense agreement for use of NodeBB in a non-free/restrictive environment? Contact us at sales@nodebb.org.
## More Information/Links
* [Demo](https://try.nodebb.org)
* [Developer Community](http://community.nodebb.org)
* [Documentation & Installation Instructions](http://docs.nodebb.org)
* [Help translate NodeBB](https://explore.transifex.com/nodebb/nodebb/)
* [NodeBB Blog](http://blog.nodebb.org)
* [Premium Hosting for NodeBB](http://www.nodebb.org/ "NodeBB")
* Unofficial IRC community &ndash; channel `#nodebb` on Libera.chat
* [Follow us on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter")
* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")

8
app.js
View File

@@ -1,7 +1,7 @@
/*
NodeBB - A better forum platform for the modern web
https://github.com/NodeBB/NodeBB/
Copyright (C) 2013-2021 NodeBB Inc.
Copyright (C) 2013-2017 NodeBB Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
require('./require-main');
const nconf = require('nconf');
nconf.argv().env({
separator: '__',
});
@@ -41,7 +40,6 @@ const configFile = path.resolve(__dirname, nconf.any(['config', 'CONFIG']) || 'c
const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));
const prestart = require('./src/prestart');
prestart.loadConfig(configFile);
prestart.setupWinston();
prestart.versionCheck();
@@ -49,7 +47,7 @@ winston.verbose('* using configuration stored in: %s', configFile);
if (!process.send) {
// If run using `node app`, log GNU copyright info along with server info
winston.info(`NodeBB v${nconf.get('version')} Copyright (C) 2013-${(new Date()).getFullYear()} NodeBB Inc.`);
winston.info('NodeBB v' + nconf.get('version') + ' Copyright (C) 2013-' + (new Date()).getFullYear() + ' NodeBB Inc.');
winston.info('This program comes with ABSOLUTELY NO WARRANTY.');
winston.info('This is free software, and you are welcome to redistribute it under certain conditions.');
winston.info('');
@@ -71,7 +69,7 @@ if (nconf.get('setup') || nconf.get('install')) {
});
} else if (nconf.get('activate')) {
require('./src/cli/manage').activate(nconf.get('activate'));
} else if (nconf.get('plugins') && typeof nconf.get('plugins') !== 'object') {
} else if (nconf.get('plugins')) {
require('./src/cli/manage').listPlugins();
} else if (nconf.get('build')) {
require('./src/cli/manage').build(nconf.get('build'));

View File

@@ -4,7 +4,7 @@
"description": "Announcements regarding our community",
"descriptionParsed": "<p>Announcements regarding our community</p>\n",
"bgColor": "#fda34b",
"color": "#ffffff",
"color": "#fff",
"icon" : "fa-bullhorn",
"order": 1
},
@@ -13,7 +13,7 @@
"description": "A place to talk about whatever you want",
"descriptionParsed": "<p>A place to talk about whatever you want</p>\n",
"bgColor": "#59b3d0",
"color": "#ffffff",
"color": "#fff",
"icon" : "fa-comments-o",
"order": 2
},
@@ -22,7 +22,7 @@
"description": "Blog posts from individual members",
"descriptionParsed": "<p>Blog posts from individual members</p>\n",
"bgColor": "#86ba4b",
"color": "#ffffff",
"color": "#fff",
"icon" : "fa-newspaper-o",
"order": 4
},
@@ -31,7 +31,7 @@
"description": "Got a question? Ask away!",
"descriptionParsed": "<p>Got a question? Ask away!</p>\n",
"bgColor": "#e95c5a",
"color": "#ffffff",
"color": "#fff",
"icon" : "fa-question",
"order": 3
}

View File

@@ -14,44 +14,36 @@
"newbiePostEditDuration": 3600,
"postDeleteDuration": 0,
"enablePostHistory": 1,
"topicBacklinks": 1,
"postCacheSize": 10485760,
"disableChat": 0,
"chatEditDuration": 0,
"chatDeleteDuration": 0,
"chatMessageDelay": 200,
"notificationSendDelay": 60,
"newbiePostDelayThreshold": 3,
"postQueue": 0,
"postQueueReputationThreshold": 0,
"groupsExemptFromPostQueue": ["administrators", "Global Moderators"],
"minimumPostLength": 8,
"maximumPostLength": 32767,
"systemTags": "",
"minimumTagsPerTopic": 0,
"maximumTagsPerTopic": 5,
"minimumTagLength": 3,
"maximumTagLength": 15,
"undoTimeout": 10000,
"allowTopicsThumbnail": 1,
"allowTopicsThumbnail": 0,
"registrationType": "normal",
"registrationApprovalType": "normal",
"allowAccountDelete": 1,
"privateUploads": 0,
"allowedFileExtensions": "png,jpg,bmp,txt",
"uploadRateLimitThreshold": 10,
"uploadRateLimitCooldown": 60,
"allowUserHomePage": 1,
"allowMultipleBadges": 0,
"maximumFileSize": 2048,
"stripEXIFData": 1,
"orphanExpiryDays": 0,
"resizeImageWidthThreshold": 2000,
"resizeImageWidth": 760,
"rejectImageWidth": 5000,
"rejectImageHeight": 5000,
"resizeImageQuality": 80,
"topicThumbSize": 512,
"topicThumbSize": 120,
"minimumTitleLength": 3,
"maximumTitleLength": 255,
"minimumUsernameLength": 2,
@@ -67,10 +59,10 @@
"profileImageDimension": 200,
"profile:convertProfileImageToPNG": 0,
"profile:keepAllUserImages": 0,
"requireEmailConfirmation": 0,
"gdpr_enabled": 1,
"allowProfileImageUploads": 1,
"teaserPost": "last-reply",
"showPostPreviewsOnHover": 1,
"allowPrivateGroups": 1,
"unreadCutoff": 2,
"bookmarkThreshold": 5,
@@ -78,13 +70,9 @@
"reputation:disabled": 0,
"downvote:disabled": 0,
"disableSignatures": 0,
"upvotesPerDay": 20,
"upvotesPerUserPerDay": 6,
"downvotesPerDay": 10,
"downvotesPerUserPerDay": 3,
"min:rep:chat": 0,
"min:rep:downvote": 0,
"min:rep:upvote": 0,
"min:rep:flag": 0,
"min:rep:profile-picture": 0,
"min:rep:cover-picture": 0,
@@ -92,7 +80,6 @@
"min:rep:aboutme": 0,
"min:rep:signature": 0,
"flags:limitPerTarget": 0,
"flags:autoFlagOnDownvoteThreshold": 0,
"notificationType_upvote": "notification",
"notificationType_new-topic": "notification",
"notificationType_new-reply": "notification",
@@ -101,7 +88,6 @@
"notificationType_new-chat": "notification",
"notificationType_new-group-chat": "notification",
"notificationType_group-invite": "notification",
"notificationType_group-leave": "notification",
"notificationType_group-request-membership": "notification",
"notificationType_mention": "notification",
"notificationType_new-register": "notification",
@@ -113,16 +99,11 @@
"maxPostsPerPage": 20,
"topicsPerPage": 20,
"postsPerPage": 20,
"categoriesPerPage": 50,
"userSearchResultsPerPage": 50,
"searchDefaultSortBy": "relevance",
"searchDefaultIn": "titlesposts",
"searchDefaultInQuick": "titles",
"maximumGroupNameLength": 255,
"maximumGroupTitleLength": 40,
"preventTopicDeleteAfterReplies": 0,
"feeds:disableSitemap": 0,
"feeds:disableRSS": 0,
"sitemapTopics": 500,
"maintenanceMode": 0,
"maintenanceModeStatus": 503,
@@ -130,7 +111,7 @@
"maximumInvites": 0,
"username:disableEdit": 0,
"email:disableEdit": 0,
"email:smtpTransport:pool": 0,
"email:smtpTransport:pool": false,
"hideFullname": 0,
"hideEmail": 0,
"showFullnameAsDisplayName": 0,
@@ -144,18 +125,9 @@
"disableEmailSubscriptions": 0,
"emailConfirmInterval": 10,
"removeEmailNotificationImages": 0,
"sendValidationEmail": 1,
"includeUnverifiedEmails": 0,
"emailPrompt": 1,
"sendEmailToBanned": 0,
"requireEmailAddress": 0,
"inviteExpiration": 7,
"dailyDigestFreq": "off",
"digestHour": 17,
"passwordExpiryDays": 0,
"cross-origin-embedder-policy": 0,
"cross-origin-opener-policy": "same-origin",
"cross-origin-resource-policy": "same-origin",
"hsts-maxage": 31536000,
"hsts-subdomains": 0,
"hsts-preload": 0,
@@ -168,13 +140,9 @@
"necroThreshold": 7,
"categoryWatchState": "watching",
"submitPluginUsage": 1,
"showAverageApprovalTime": 1,
"showAverageApprovalTime": true,
"autoApproveTime": 0,
"maxUserSessions": 10,
"useCompression": 0,
"updateUrlWithPostIndex": 1,
"composer:showHelpTab": 1,
"composer:allowPluginHelp": 1,
"maxReconnectionAttempts": 5,
"reconnectionDelay": 1500
"updateUrlWithPostIndex": 1
}

View File

@@ -64,6 +64,9 @@
"iconClass": "fa-cogs",
"textClass": "visible-xs-inline",
"text": "[[global:header.admin]]",
"groups": ["administrators"]
"groups": ["administrators"],
"properties": {
"targetBlank": false
}
}
]

View File

@@ -3,6 +3,10 @@
const prompt = require('prompt');
const winston = require('winston');
const util = require('util');
const promptGet = util.promisify((schema, callback) => prompt.get(schema, callback));
const questions = {
redis: require('../src/database/redis').questions,
mongo: require('../src/database/mongo').questions,
@@ -10,7 +14,7 @@ const questions = {
};
module.exports = async function (config) {
winston.info(`\nNow configuring ${config.database} database:`);
winston.info('\nNow configuring ' + config.database + ' database:');
const databaseConfig = await getDatabaseConfig(config);
return saveDatabaseConfig(config, databaseConfig);
};
@@ -24,19 +28,19 @@ async function getDatabaseConfig(config) {
if (config['redis:host'] && config['redis:port']) {
return config;
}
return await prompt.get(questions.redis);
return await promptGet(questions.redis);
} else if (config.database === 'mongo') {
if ((config['mongo:host'] && config['mongo:port']) || config['mongo:uri']) {
return config;
}
return await prompt.get(questions.mongo);
return await promptGet(questions.mongo);
} else if (config.database === 'postgres') {
if (config['postgres:host'] && config['postgres:port']) {
return config;
}
return await prompt.get(questions.postgres);
return await promptGet(questions.postgres);
}
throw new Error(`unknown database : ${config.database}`);
throw new Error('unknown database : ' + config.database);
}
function saveDatabaseConfig(config, databaseConfig) {
@@ -75,11 +79,11 @@ function saveDatabaseConfig(config, databaseConfig) {
ssl: databaseConfig['postgres:ssl'],
};
} else {
throw new Error(`unknown database : ${config.database}`);
throw new Error('unknown database : ' + config.database);
}
const allQuestions = questions.redis.concat(questions.mongo).concat(questions.postgres);
for (let x = 0; x < allQuestions.length; x += 1) {
for (var x = 0; x < allQuestions.length; x += 1) {
delete config[allQuestions[x].name];
}

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
"version": "2.4.0",
"version": "1.15.3-beta.0",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@@ -11,8 +11,8 @@
"main": "app.js",
"scripts": {
"start": "node loader.js",
"lint": "eslint --cache ./nodebb .",
"test": "nyc --reporter=html --reporter=text-summary mocha",
"lint": "npx eslint --cache ./nodebb .",
"test": "npx nyc --reporter=html --reporter=text-summary npx mocha",
"coverage": "nyc report --reporter=text-lcov > ./coverage/lcov.info",
"coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage"
},
@@ -22,153 +22,159 @@
"test/*"
]
},
"husky": {
"hooks": {
"pre-commit": "npx lint-staged",
"commit-msg": "npx commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.js": [
"eslint --fix"
"eslint --fix",
"git add"
]
},
"dependencies": {
"@adactive/bootstrap-tagsinput": "0.8.2",
"@isaacs/ttlcache": "^1.2.0",
"ace-builds": "1.8.1",
"archiver": "5.3.1",
"async": "3.2.4",
"autoprefixer": "10.4.8",
"@adactive/bootstrap-tagsinput": "^0.8.2",
"ace-builds": "^1.4.9",
"archiver": "^5.0.0",
"async": "^3.2.0",
"autoprefixer": "^10.0.0",
"bcryptjs": "2.4.3",
"benchpressjs": "2.4.3",
"body-parser": "1.20.0",
"bootbox": "5.5.3",
"bootstrap": "3.4.1",
"chalk": "4.1.2",
"chart.js": "2.9.4",
"cli-graph": "3.2.2",
"clipboard": "2.0.11",
"colors": "1.4.0",
"commander": "9.4.0",
"compare-versions": "4.1.3",
"compression": "1.7.4",
"connect-flash": "0.1.1",
"connect-mongo": "4.6.0",
"connect-multiparty": "2.2.0",
"connect-pg-simple": "7.0.0",
"connect-redis": "6.1.3",
"cookie-parser": "1.4.6",
"cron": "2.1.0",
"cropperjs": "1.5.12",
"csurf": "1.11.0",
"daemon": "1.1.0",
"diff": "5.1.0",
"express": "4.18.1",
"express-session": "1.17.3",
"express-useragent": "1.0.15",
"file-loader": "6.2.0",
"fs-extra": "10.1.0",
"graceful-fs": "4.2.10",
"helmet": "5.1.1",
"html-to-text": "8.2.1",
"ipaddr.js": "2.0.1",
"jquery": "3.6.0",
"jquery-deserialize": "2.0.0",
"benchpressjs": "2.2.2",
"body-parser": "^1.19.0",
"bootbox": "4.4.0",
"bootstrap": "^3.4.1",
"chart.js": "^2.9.3",
"cli-graph": "^3.2.2",
"clipboard": "^2.0.6",
"colors": "^1.4.0",
"commander": "^6.0.0",
"compare-versions": "3.6.0",
"compression": "^1.7.4",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
"connect-mongo": "3.2.0",
"connect-multiparty": "^2.2.0",
"connect-pg-simple": "^6.1.0",
"connect-redis": "5.0.0",
"cookie-parser": "^1.4.5",
"cron": "^1.8.2",
"cropperjs": "^1.5.6",
"csurf": "^1.11.0",
"daemon": "^1.1.0",
"diff": "^5.0.0",
"express": "^4.17.1",
"express-session": "^1.17.0",
"express-useragent": "^1.0.13",
"graceful-fs": "^4.2.3",
"helmet": "^4.0.0",
"html-to-text": "^5.1.1",
"ipaddr.js": "^2.0.0",
"jquery": "3.5.1",
"jquery-deserialize": "2.0.0-rc1",
"jquery-form": "4.3.0",
"jquery-serializeobject": "1.0.0",
"jquery-ui": "1.13.2",
"jquery-ui": "1.12.1",
"jsesc": "3.0.2",
"json2csv": "5.0.7",
"jsonwebtoken": "8.5.1",
"less": "4.1.3",
"lodash": "4.17.21",
"logrotate-stream": "0.2.8",
"lru-cache": "7.13.1",
"material-design-lite": "1.3.0",
"mime": "3.0.0",
"mkdirp": "1.0.4",
"mongodb": "4.8.1",
"morgan": "1.10.0",
"mousetrap": "1.6.5",
"multiparty": "4.2.3",
"json2csv": "5.0.5",
"jsonwebtoken": "^8.5.1",
"less": "^3.11.1",
"lodash": "^4.17.15",
"logrotate-stream": "^0.2.6",
"lru-cache": "6.0.0",
"material-design-lite": "^1.3.0",
"mime": "^2.4.4",
"mkdirp": "^1.0.4",
"mongodb": "3.6.3",
"morgan": "^1.10.0",
"mousetrap": "^1.6.5",
"@nodebb/bootswatch": "3.4.2",
"nconf": "0.12.0",
"nodebb-plugin-2factor": "5.0.2",
"nodebb-plugin-composer-default": "8.0.0",
"nodebb-plugin-dbsearch": "5.1.5",
"nodebb-plugin-emoji": "4.0.4",
"nodebb-plugin-emoji-android": "3.0.0",
"nodebb-plugin-markdown": "10.1.0",
"nodebb-plugin-mentions": "3.0.11",
"nodebb-plugin-spam-be-gone": "1.0.0",
"nodebb-rewards-essentials": "0.2.1",
"nodebb-theme-lavender": "6.0.0",
"nodebb-theme-persona": "12.1.0",
"nodebb-theme-slick": "2.0.2",
"nodebb-theme-vanilla": "12.1.18",
"nodebb-widget-essentials": "6.0.0",
"nodemailer": "6.7.7",
"@nodebb/mubsub": "1.7.1",
"@nodebb/socket.io-adapter-mongo": "3.1.1",
"nconf": "^0.10.0",
"nodebb-plugin-composer-default": "6.4.7",
"nodebb-plugin-dbsearch": "4.1.2",
"nodebb-plugin-emoji": "^3.3.0",
"nodebb-plugin-emoji-android": "2.0.0",
"nodebb-plugin-markdown": "8.12.1",
"nodebb-plugin-mentions": "2.13.5",
"nodebb-plugin-soundpack-default": "1.0.0",
"nodebb-plugin-spam-be-gone": "0.7.6",
"nodebb-rewards-essentials": "0.1.4",
"nodebb-theme-lavender": "5.0.14",
"nodebb-theme-persona": "10.2.81",
"nodebb-theme-slick": "1.3.3",
"nodebb-theme-vanilla": "11.3.4",
"nodebb-widget-essentials": "4.1.2",
"nodemailer": "^6.4.6",
"nprogress": "0.2.0",
"passport": "0.5.2",
"passport-http-bearer": "1.0.1",
"passport": "^0.4.1",
"passport-http-bearer": "^1.0.1",
"passport-local": "1.0.0",
"pg": "8.7.3",
"pg-cursor": "2.7.3",
"postcss": "8.4.14",
"postcss-clean": "1.2.0",
"prompt": "1.3.0",
"ioredis": "5.2.2",
"pg": "^8.0.2",
"pg-cursor": "^2.1.9",
"postcss": "8.1.7",
"postcss-clean": "1.1.0",
"promise-polyfill": "^8.1.3",
"prompt": "^1.0.0",
"redis": "3.0.2",
"request": "2.88.2",
"request-promise-native": "1.0.9",
"request-promise-native": "^1.0.8",
"requirejs": "2.3.6",
"rimraf": "3.0.2",
"rss": "1.2.2",
"sanitize-html": "2.7.1",
"semver": "7.3.7",
"serve-favicon": "2.5.0",
"sharp": "0.30.7",
"sitemap": "7.1.1",
"rss": "^1.2.2",
"sanitize-html": "^2.0.0",
"semver": "^7.2.1",
"serve-favicon": "^2.5.0",
"sharp": "0.26.3",
"sitemap": "^6.1.0",
"slideout": "1.0.1",
"socket.io": "4.5.1",
"socket.io-client": "4.5.1",
"@socket.io/redis-adapter": "7.2.0",
"sortablejs": "1.15.0",
"spdx-license-list": "6.6.0",
"socket.io": "2.3.0",
"socket.io-adapter-cluster": "^1.0.1",
"socket.io-adapter-postgres": "^1.2.1",
"socket.io-client": "2.3.1",
"socket.io-redis": "5.4.0",
"socketio-wildcard": "2.0.0",
"sortablejs": "1.10.2",
"spdx-license-list": "^6.1.0",
"spider-detector": "2.0.0",
"textcomplete": "0.18.2",
"textcomplete.contenteditable": "0.1.1",
"timeago": "1.6.7",
"textcomplete": "^0.17.1",
"textcomplete.contenteditable": "^0.1.1",
"timeago": "^1.6.7",
"tinycon": "0.6.8",
"toobusy-js": "0.5.1",
"uglify-es": "3.3.9",
"validator": "13.7.0",
"toobusy-js": "^0.5.1",
"uglify-es": "^3.3.9",
"validator": "13.1.17",
"visibilityjs": "2.0.2",
"webpack": "5.74.0",
"webpack-merge": "5.8.0",
"winston": "3.8.1",
"xml": "1.0.1",
"xregexp": "5.1.1",
"yargs": "17.5.1",
"zxcvbn": "4.4.2"
"winston": "3.3.3",
"xml": "^1.0.1",
"xregexp": "^4.3.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@apidevtools/swagger-parser": "10.0.3",
"@commitlint/cli": "17.0.3",
"@commitlint/config-angular": "17.0.3",
"coveralls": "3.1.1",
"eslint": "8.21.0",
"eslint-config-nodebb": "0.1.1",
"eslint-plugin-import": "2.26.0",
"grunt": "1.5.3",
"@apidevtools/swagger-parser": "10.0.2",
"@commitlint/cli": "11.0.0",
"@commitlint/config-angular": "11.0.0",
"coveralls": "3.1.0",
"eslint": "7.13.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-plugin-import": "2.22.1",
"grunt": "1.3.0",
"grunt-contrib-watch": "1.1.0",
"husky": "8.0.1",
"jsdom": "20.0.0",
"lint-staged": "13.0.3",
"mocha": "10.0.0",
"husky": "4.3.0",
"jsdom": "16.4.0",
"lint-staged": "10.5.1",
"mocha": "8.2.1",
"mocha-lcov-reporter": "1.3.0",
"mockdate": "3.0.5",
"nyc": "15.1.0",
"smtp-server": "3.11.0"
"smtp-server": "3.8.0"
},
"bugs": {
"url": "https://github.com/NodeBB/NodeBB/issues"
},
"engines": {
"node": ">=12"
"node": ">=10"
},
"maintainers": [
{

View File

@@ -7,8 +7,11 @@ const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const less = require('less');
const webpack = require('webpack');
const util = require('util');
const lessRenderAsync = util.promisify(
(style, opts, cb) => less.render(String(style), opts, cb)
);
const uglify = require('uglify-es');
const nconf = require('nconf');
const Benchpress = require('benchpressjs');
@@ -23,8 +26,8 @@ const formats = [
];
const timestampFormat = winston.format((info) => {
const dateString = `${new Date().toISOString()} [${global.process.pid}]`;
info.level = `${dateString} - ${info.level}`;
var dateString = new Date().toISOString() + ' [' + global.process.pid + ']';
info.level = dateString + ' - ' + info.level;
return info;
});
formats.push(timestampFormat());
@@ -46,6 +49,16 @@ winston.configure({
});
const web = module.exports;
const scripts = [
'node_modules/jquery/dist/jquery.js',
'node_modules/xregexp/xregexp-all.js',
'public/src/modules/slugify.js',
'public/src/utils.js',
'public/src/installer/install.js',
'node_modules/zxcvbn/dist/zxcvbn.js',
];
let installing = false;
let success = false;
let error = false;
@@ -55,12 +68,10 @@ const viewsDir = path.join(paths.baseDir, 'build/public/templates');
web.install = async 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.use('/assets', express.static(path.join(__dirname, '../build/public'), {}));
app.engine('tpl', (filepath, options, callback) => {
app.engine('tpl', function (filepath, options, callback) {
filepath = filepath.replace(/\.tpl$/, '.js');
Benchpress.__express(filepath, options, callback);
@@ -74,7 +85,7 @@ web.install = async function (port) {
await Promise.all([
compileTemplate(),
compileLess(),
runWebpack(),
compileJS(),
copyCSS(),
loadDefaults(),
]);
@@ -85,16 +96,9 @@ web.install = async function (port) {
}
};
async function runWebpack() {
const util = require('util');
const webpackCfg = require('../webpack.installer');
const compiler = webpack(webpackCfg);
const webpackRun = util.promisify(compiler.run).bind(compiler);
await webpackRun();
}
function launchExpress(port) {
server = app.listen(port, () => {
server = app.listen(port, function () {
winston.info('Web installer listening on http://%s:%s', '0.0.0.0', port);
});
}
@@ -112,9 +116,11 @@ function ping(req, res) {
}
function welcome(req, res) {
const dbs = ['mongo', 'redis', 'postgres'];
const databases = dbs.map((databaseName) => {
const questions = require(`../src/database/${databaseName}`).questions.filter(question => question && !question.hideOnWebInstall);
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;
});
return {
name: databaseName,
@@ -122,10 +128,10 @@ function welcome(req, res) {
};
});
const defaults = require('./data/defaults.json');
var defaults = require('./data/defaults');
res.render('install/index', {
url: nconf.get('url') || (`${req.protocol}://${req.get('host')}`),
url: nconf.get('url') || (req.protocol + '://' + req.get('host')),
launchUrl: launchUrl,
skipGeneralSetup: !!nconf.get('url'),
databases: databases,
@@ -145,33 +151,35 @@ function install(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];
}
}
const database = nconf.get('database') || req.body.database || 'mongo';
const setupEnvVars = {
...process.env,
NODEBB_URL: nconf.get('url') || req.body.url || (`${req.protocol}://${req.get('host')}`),
NODEBB_PORT: nconf.get('port') || 4567,
NODEBB_ADMIN_USERNAME: nconf.get('admin:username') || req.body['admin:username'],
NODEBB_ADMIN_PASSWORD: nconf.get('admin:password') || req.body['admin:password'],
NODEBB_ADMIN_EMAIL: nconf.get('admin:email') || req.body['admin:email'],
NODEBB_DB: database,
NODEBB_DB_HOST: nconf.get(`${database}:host`) || req.body[`${database}:host`],
NODEBB_DB_PORT: nconf.get(`${database}:port`) || req.body[`${database}:port`],
NODEBB_DB_USER: nconf.get(`${database}:username`) || req.body[`${database}:username`],
NODEBB_DB_PASSWORD: nconf.get(`${database}:password`) || req.body[`${database}:password`],
NODEBB_DB_NAME: nconf.get(`${database}:database`) || req.body[`${database}:database`],
NODEBB_DB_SSL: nconf.get(`${database}:ssl`) || req.body[`${database}:ssl`],
defaultPlugins: JSON.stringify(nconf.get('defaultplugins') || nconf.get('defaultPlugins') || []),
// 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');
launchUrl = setupEnvVars.NODEBB_URL;
winston.info(setupEnvVars);
launchUrl = setupEnvVars.url;
const child = require('child_process').fork('app', ['--setup'], {
var child = require('child_process').fork('app', ['--setup'], {
env: setupEnvVars,
});
child.on('close', (data) => {
child.on('close', function (data) {
installing = false;
success = data === 0;
error = data !== 0;
@@ -185,7 +193,7 @@ async function launch(req, res) {
res.json({});
server.close();
req.setTimeout(0);
let child;
var child;
if (!nconf.get('launchCmd')) {
child = childProcess.spawn('node', ['loader.js'], {
@@ -206,20 +214,15 @@ async function launch(req, res) {
}
const filesToDelete = [
path.join(__dirname, '../public', 'installer.css'),
path.join(__dirname, '../public', 'bootstrap.min.css'),
path.join(__dirname, '../build/public', 'installer.min.js'),
'installer.css',
'installer.min.js',
'bootstrap.min.css',
];
try {
await Promise.all(
filesToDelete.map(
filename => fs.promises.unlink(filename)
)
);
} catch (err) {
console.log(err.stack);
}
await Promise.all(
filesToDelete.map(
filename => fs.promises.unlink(path.join(__dirname, '../public', filename))
)
);
child.unref();
process.exit(0);
} catch (err) {
@@ -251,14 +254,31 @@ async function compileLess() {
try {
const installSrc = path.join(__dirname, '../public/less/install.less');
const style = await fs.promises.readFile(installSrc);
const css = await less.render(String(style), { filename: path.resolve(installSrc) });
const css = await lessRenderAsync(style, { filename: path.resolve(installSrc) });
await fs.promises.writeFile(path.join(__dirname, '../public/installer.css'), css.css);
} catch (err) {
winston.error(`Unable to compile LESS: \n${err.stack}`);
winston.error('Unable to compile LESS: \n' + err.stack);
throw err;
}
}
async function compileJS() {
let code = '';
for (const srcPath of scripts) {
// eslint-disable-next-line no-await-in-loop
const buffer = await fs.promises.readFile(path.join(__dirname, '..', srcPath));
code += buffer.toString();
}
const minified = uglify.minify(code, {
compress: false,
});
if (!minified.code) {
throw new Error('[[error:failed-to-minify]]');
}
await fs.promises.writeFile(path.join(__dirname, '../public/installer.min.js'), minified.code);
}
async function copyCSS() {
const src = await fs.promises.readFile(
path.join(__dirname, '../node_modules/bootstrap/dist/css/bootstrap.min.css'), 'utf8'
@@ -269,15 +289,12 @@ async function copyCSS() {
async function loadDefaults() {
const setupDefaultsPath = path.join(__dirname, '../setup.json');
try {
// eslint-disable-next-line no-bitwise
await fs.promises.access(setupDefaultsPath, fs.constants.F_OK | fs.constants.R_OK);
} catch (err) {
// setup.json not found or inaccessible, proceed with no defaults
if (err.code !== 'ENOENT') {
throw err;
}
return;
}
winston.info('[installer] Found setup.json, populating default values');
nconf.file({

142
loader.js
View File

@@ -1,78 +1,82 @@
'use strict';
const nconf = require('nconf');
const fs = require('fs');
const url = require('url');
const path = require('path');
const { fork } = require('child_process');
const logrotate = require('logrotate-stream');
const mkdirp = require('mkdirp');
var nconf = require('nconf');
var fs = require('fs');
var url = require('url');
var path = require('path');
var fork = require('child_process').fork;
var async = require('async');
var logrotate = require('logrotate-stream');
var mkdirp = require('mkdirp');
const file = require('./src/file');
const pkg = require('./package.json');
var file = require('./src/file');
var pkg = require('./package.json');
const pathToConfig = path.resolve(__dirname, process.env.CONFIG || 'config.json');
var pathToConfig = path.resolve(__dirname, process.env.CONFIG || 'config.json');
nconf.argv().env().file({
file: pathToConfig,
});
const pidFilePath = path.join(__dirname, 'pidfile');
var pidFilePath = path.join(__dirname, 'pidfile');
const outputLogFilePath = path.join(__dirname, nconf.get('logFile') || 'logs/output.log');
var outputLogFilePath = path.join(__dirname, nconf.get('logFile') || 'logs/output.log');
const logDir = path.dirname(outputLogFilePath);
var logDir = path.dirname(outputLogFilePath);
if (!fs.existsSync(logDir)) {
mkdirp.sync(path.dirname(outputLogFilePath));
}
const output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
const silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false;
let numProcs;
const workers = [];
const Loader = {
var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
var silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false;
var numProcs;
var workers = [];
var Loader = {
timesStarted: 0,
};
const appPath = path.join(__dirname, 'app.js');
var appPath = path.join(__dirname, 'app.js');
Loader.init = function () {
Loader.init = function (callback) {
if (silent) {
console.log = (...args) => {
output.write(`${args.join(' ')}\n`);
console.log = function () {
var args = Array.prototype.slice.call(arguments);
output.write(args.join(' ') + '\n');
};
}
process.on('SIGHUP', Loader.restart);
process.on('SIGTERM', Loader.stop);
callback();
};
Loader.displayStartupMessages = function () {
Loader.displayStartupMessages = function (callback) {
console.log('');
console.log(`NodeBB v${pkg.version} Copyright (C) 2013-${(new Date()).getFullYear()} NodeBB Inc.`);
console.log('NodeBB v' + pkg.version + ' Copyright (C) 2013-2014 NodeBB Inc.');
console.log('This program comes with ABSOLUTELY NO WARRANTY.');
console.log('This is free software, and you are welcome to redistribute it under certain conditions.');
console.log('For the full license, please visit: http://www.gnu.org/copyleft/gpl.html');
console.log('');
callback();
};
Loader.addWorkerEvents = function (worker) {
worker.on('exit', (code, signal) => {
worker.on('exit', function (code, signal) {
if (code !== 0) {
if (Loader.timesStarted < numProcs * 3) {
Loader.timesStarted += 1;
if (Loader.crashTimer) {
clearTimeout(Loader.crashTimer);
}
Loader.crashTimer = setTimeout(() => {
Loader.crashTimer = setTimeout(function () {
Loader.timesStarted = 0;
}, 10000);
} else {
console.log(`${numProcs * 3} restarts in 10 seconds, most likely an error on startup. Halting.`);
console.log((numProcs * 3) + ' restarts in 10 seconds, most likely an error on startup. Halting.');
process.exit();
}
}
console.log(`[cluster] Child Process (${worker.pid}) has exited (code: ${code}, signal: ${signal})`);
console.log('[cluster] Child Process (' + worker.pid + ') has exited (code: ' + code + ', signal: ' + signal + ')');
if (!(worker.suicide || code === 0)) {
console.log('[cluster] Spinning up another process...');
@@ -80,7 +84,7 @@ Loader.addWorkerEvents = function (worker) {
}
});
worker.on('message', (message) => {
worker.on('message', function (message) {
if (message && typeof message === 'object' && message.action) {
switch (message.action) {
case 'restart':
@@ -88,12 +92,12 @@ Loader.addWorkerEvents = function (worker) {
Loader.restart();
break;
case 'pubsub':
workers.forEach((w) => {
workers.forEach(function (w) {
w.send(message);
});
break;
case 'socket.io':
workers.forEach((w) => {
workers.forEach(function (w) {
if (w !== worker) {
w.send(message);
}
@@ -104,28 +108,32 @@ Loader.addWorkerEvents = function (worker) {
});
};
Loader.start = function () {
Loader.start = function (callback) {
numProcs = getPorts().length;
console.log(`Clustering enabled: Spinning up ${numProcs} process(es).\n`);
console.log('Clustering enabled: Spinning up ' + numProcs + ' process(es).\n');
for (let x = 0; x < numProcs; x += 1) {
for (var x = 0; x < numProcs; x += 1) {
forkWorker(x, x === 0);
}
if (callback) {
callback();
}
};
function forkWorker(index, isPrimary) {
const ports = getPorts();
const args = [];
var ports = getPorts();
var args = [];
if (!ports[index]) {
return console.log(`[cluster] invalid port for worker : ${index} ports: ${ports.length}`);
return console.log('[cluster] invalid port for worker : ' + index + ' ports: ' + ports.length);
}
process.env.isPrimary = isPrimary;
process.env.isCluster = nconf.get('isCluster') || ports.length > 1;
process.env.port = ports[index];
const worker = fork(appPath, args, {
var worker = fork(appPath, args, {
silent: silent,
env: process.env,
});
@@ -138,20 +146,20 @@ function forkWorker(index, isPrimary) {
Loader.addWorkerEvents(worker);
if (silent) {
const output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
worker.stdout.pipe(output);
worker.stderr.pipe(output);
}
}
function getPorts() {
const _url = nconf.get('url');
var _url = nconf.get('url');
if (!_url) {
console.log('[cluster] url is undefined, please check your config.json');
process.exit();
}
const urlObject = url.parse(_url);
let port = nconf.get('PORT') || nconf.get('port') || urlObject.port || 4567;
var urlObject = url.parse(_url);
var port = nconf.get('PORT') || nconf.get('port') || urlObject.port || 4567;
if (!Array.isArray(port)) {
port = [port];
}
@@ -164,13 +172,13 @@ Loader.restart = function () {
nconf.remove('file');
nconf.use('file', { file: pathToConfig });
fs.readFile(pathToConfig, { encoding: 'utf-8' }, (err, configFile) => {
fs.readFile(pathToConfig, { encoding: 'utf-8' }, function (err, configFile) {
if (err) {
console.error('Error reading config');
throw err;
}
const conf = JSON.parse(configFile);
var conf = JSON.parse(configFile);
nconf.stores.env.readOnly = false;
nconf.set('url', conf.url);
@@ -193,13 +201,13 @@ Loader.stop = function () {
};
function killWorkers() {
workers.forEach((worker) => {
workers.forEach(function (worker) {
worker.suicide = true;
worker.kill();
});
}
fs.open(pathToConfig, 'r', (err) => {
fs.open(pathToConfig, 'r', function (err) {
if (err) {
// No config detected, kickstart web installer
fork('app');
@@ -208,25 +216,12 @@ fs.open(pathToConfig, 'r', (err) => {
if (nconf.get('daemon') !== 'false' && nconf.get('daemon') !== false) {
if (file.existsSync(pidFilePath)) {
let pid = 0;
try {
pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' });
if (pid) {
process.kill(pid, 0);
console.info(`Process "${pid}" from pidfile already running, exiting`);
process.exit();
} else {
console.info(`Invalid pid "${pid}" from pidfile, deleting pidfile`);
fs.unlinkSync(pidFilePath);
}
} catch (err) {
if (err.code === 'ESRCH') {
console.info(`Process "${pid}" from pidfile not found, deleting pidfile`);
fs.unlinkSync(pidFilePath);
} else {
console.error(err.stack);
throw err;
}
var pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' });
process.kill(pid, 0);
process.exit();
} catch (e) {
fs.unlinkSync(pidFilePath);
}
}
@@ -238,12 +233,15 @@ fs.open(pathToConfig, 'r', (err) => {
fs.writeFileSync(pidFilePath, String(process.pid));
}
try {
Loader.init();
Loader.displayStartupMessages();
Loader.start();
} catch (err) {
console.error('[loader] Error during startup');
throw err;
}
async.series([
Loader.init,
Loader.displayStartupMessages,
Loader.start,
], function (err) {
if (err) {
console.error('[loader] Error during startup');
throw err;
}
});
});

View File

@@ -1,3 +1,54 @@
{
"extends": "nodebb/public"
"globals": {
"app": true,
"io": true,
"socket": true,
"ajaxify": true,
"config": true,
"utils": true,
"overrides": true,
"componentHandler": true,
"bootbox": true,
"Visibility": true,
"Tinycon": true,
"Promise": true
},
"env": {
"jquery": true,
"amd": true,
"browser": true,
"es6": true
},
"rules": {
"block-scoped-var": "off",
"no-dupe-class-members": "off",
"no-var": "off",
"object-shorthand": "off",
"prefer-arrow-callback": "off",
"prefer-spread": "off",
"prefer-object-spread": "off",
"prefer-reflect": "off",
"prefer-template": "off"
},
"parserOptions": {
"ecmaVersion": 6,
"ecmaFeatures": {
"classes": false,
"defaultParams": false,
"experimentalObjectRestSpread": false,
"blockBindings": false,
"forOf": false,
"generators": false,
"globalReturn": false,
"jsx": false,
"modules": false,
"objectLiteralComputedProperties": false,
"objectLiteralDuplicateProperties": false,
"objectLiteralShorthandMethods": false,
"objectLiteralShorthandProperties": false,
"impliedStrict": false,
"restParams": false,
"superInFunctions": false
}
}
}

83
public/.jshintrc Normal file
View File

@@ -0,0 +1,83 @@
{
"maxerr" : 50, // {int} Maximum error before stopping
// Enforcing
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
"camelcase" : false, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"indent" : 4, // {int} Number of spaces to use for indentation
"latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"noempty" : true, // true: Prohibit use of empty blocks
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
"plusplus" : false, // true: Prohibit use of `++` & `--`
"quotmark" : false, // Quotation mark consistency:
// false : do nothing (default)
// true : ensure whatever is used is consistent
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"trailing" : false, // true: Prohibit trailing whitespaces
"maxparams" : false, // {int} Max number of formal params allowed per function
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
"maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
"maxlen" : false, // {int} Max number of characters per line
// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : false, // true: Tolerate use of `== null`
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// (ex: `for each`, multiple try/catch, function expression…)
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
"funcscope" : false, // true: Tolerate defining variables inside control statements"
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
"iterator" : false, // true: Tolerate using the `__iterator__` property
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
"laxcomma" : false, // true: Tolerate comma-first style coding
"loopfunc" : false, // true: Tolerate functions being defined in loops
"multistr" : false, // true: Tolerate multi-line strings
"proto" : false, // true: Tolerate using the `__proto__` property
"scripturl" : false, // true: Tolerate script-targeted URLs
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
"validthis" : false, // true: Tolerate using this in a non-constructor function
"globals": {
"app": true,
"io": true,
"socket": true,
"ajaxify": true,
"config": true,
"utils": true,
"overrides": true,
"componentHandler": true,
"bootbox": true,
"templates": true,
"Visibility": true,
"Tinycon": true,
"require": true,
"define": true,
"ace": true,
"Sortable": true,
"Slideout": true,
"NProgress": true
},
"jquery": true,
"browser": true
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

View File

@@ -3,7 +3,7 @@
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://explore.transifex.com/nodebb/nodebb/),
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.

View File

@@ -1,3 +0,0 @@
# The files here are not meant to be edited directly
Please see the &rarr; [Internalization README](../README.md).

View File

@@ -3,9 +3,5 @@
"alert.confirm-restart": "هل تريد بالتأكيد إعادة تشغيل NodeBB؟",
"acp-title": "لوحة تحكم إدارة NodeBB | %1",
"settings-header-contents": "محتويات",
"changes-saved": "Changes Saved",
"changes-saved-message": "Your changes to the NodeBB configuration have been saved.",
"changes-not-saved": "Changes Not Saved",
"changes-not-saved-message": "NodeBB encountered a problem saving your changes. (%1)"
"settings-header-contents": "محتويات"
}

View File

@@ -2,12 +2,11 @@
"events": "أحداث",
"no-events": "لا توجد أحداث",
"control-panel": "لوحة تحكم الأحداث",
"delete-events": "حذف الاحداث",
"confirm-delete-all-events": "Are you sure you want to delete all logged events?",
"filters": "تصفية",
"filters-apply": "تطبيق التصفية",
"filter-type": "نوع الحدث",
"filter-start": "تاريخ البدء",
"filter-end": "تاريخ الانتهاء",
"filter-perPage": "لكل صفحة"
"delete-events": "Delete Events",
"filters": "Filters",
"filters-apply": "Apply Filters",
"filter-type": "Event Type",
"filter-start": "Start Date",
"filter-end": "End Date",
"filter-perPage": "Per Page"
}

View File

@@ -2,7 +2,6 @@
"forum-traffic": "Forum Traffic",
"page-views": "مشاهدات الصفحات",
"unique-visitors": "زائرين فريدين",
"logins": "Logins",
"new-users": "New Users",
"posts": "مشاركات",
"topics": "مواضيع",
@@ -30,7 +29,6 @@
"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>",
"fallback-emailer-not-found": "Fallback emailer not found!",
"running-in-development": "المنتدى قيد التشغيل في وضع \"المطورين\". وقد تكون هناك ثغرات أمنية مفتوحة؛ من فضلك تواصل مع مسؤول نظامك.",
"latest-lookup-failed": "<p>Failed to look up latest available version of NodeBB</p>",
@@ -56,8 +54,8 @@
"active-users.total": "المجموع",
"active-users.connections": "Connections",
"guest-registered-users": "Guest vs Registered Users",
"guest": "Guest",
"anonymous-registered-users": "المجهولين مقابل المستخدمين المسجلين",
"anonymous": "مجهول",
"registered": "مسجل",
"user-presence": "تواجد المستخدمين",
@@ -68,7 +66,6 @@
"unread": "غير مقروء",
"high-presence-topics": "مواضيع ذات حضور قوي",
"popular-searches": "Popular Searches",
"graphs.page-views": "مشاهدات الصفحة",
"graphs.page-views-registered": "Page Views Registered",
@@ -76,15 +73,7 @@
"graphs.page-views-bot": "Page Views Bot",
"graphs.unique-visitors": "زوار فريدين",
"graphs.registered-users": "مستخدمين مسجلين",
"graphs.guest-users": "Guest Users",
"graphs.anonymous-users": "مستخدمين مجهولين",
"last-restarted-by": "Last restarted by",
"no-users-browsing": "No users browsing",
"back-to-dashboard": "Back to Dashboard",
"details.no-users": "No users have joined within the selected timeframe",
"details.no-topics": "No topics have been posted within the selected timeframe",
"details.no-searches": "No searches have been made yet",
"details.no-logins": "No logins have been recorded within the selected timeframe",
"details.logins-static": "NodeBB only saves session data for %1 days, and so this table below will only show the most recently active sessions",
"details.logins-login-time": "Login Time"
"no-users-browsing": "No users browsing"
}

View File

@@ -8,11 +8,7 @@
"nodejs": "nodejs",
"online": "online",
"git": "git",
"process-memory": "process memory",
"system-memory": "system memory",
"used-memory-process": "Used memory by process",
"used-memory-os": "Used system memory",
"total-memory-os": "Total system memory",
"memory": "memory",
"load": "system load",
"cpu-usage": "cpu usage",
"uptime": "uptime",

View File

@@ -39,7 +39,7 @@
"alert.upgraded": "الإضافة مرقاة",
"alert.installed": "الإضافة منصبة",
"alert.uninstalled": "تم إلغاء تنصيب الإضافة",
"alert.activate-success": "Please rebuild and restart your NodeBB to fully activate this plugin",
"alert.activate-success": "يرجى إعادة تشغيل NodeBB لتنشيط الإضافة بشكل بالكامل",
"alert.deactivate-success": "تم تعطيل الإضافة بنجاح",
"alert.upgrade-success": "Please rebuild and restart your NodeBB to fully upgrade this plugin.",
"alert.install-success": "تم تثبيت الإضافة بنجاح، يرجى تفعيلها.",

View File

@@ -8,6 +8,8 @@
"delete": "Delete",
"enable": "Enable",
"disable": "Disable",
"control-panel": "Rewards Control",
"new-reward": "New Reward",
"alert.delete-success": "Successfully deleted reward",
"alert.no-inputs-found": "Illegal reward - no inputs found!",

View File

@@ -0,0 +1,79 @@
{
"forum-traffic": "Forum Traffic",
"page-views": "مشاهدات الصفحات",
"unique-visitors": "زائرين فريدين",
"new-users": "New 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>",
"stats.yesterday": "Yesterday",
"stats.today": "Today",
"stats.last-week": "Last Week",
"stats.this-week": "This Week",
"stats.last-month": "Last Month",
"stats.this-month": "This Month",
"stats.all": "كل الوقت",
"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": "إشعارات",
"restart-not-required": "إعادة التشغيل غير مطلوب",
"restart-required": "إعادة التشغيل مطلوبة",
"search-plugin-installed": "إضافة البحث منصبة",
"search-plugin-not-installed": "إضافة البحث غير منصبة",
"search-plugin-tooltip": "نصب إضافة البحث من صفحة الإضافات البرمجية لتنشيط وظيفة البحث",
"control-panel": "التحكم بالنظام",
"rebuild-and-restart": "Rebuild &amp; Restart",
"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": "التحديث الفوري للرسم البياني",
"active-users": "المستخدمين النشطين",
"active-users.users": "الأعضاء",
"active-users.guests": "الزوار",
"active-users.total": "المجموع",
"active-users.connections": "Connections",
"anonymous-registered-users": "المجهولين مقابل المستخدمين المسجلين",
"anonymous": "مجهول",
"registered": "مسجل",
"user-presence": "تواجد المستخدمين",
"on-categories": "في قائمة الأقسام",
"reading-posts": "قراءة المشاركات",
"browsing-topics": "تصفح المواضيع",
"recent": "الأخيرة",
"unread": "غير مقروء",
"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"
}

View File

@@ -0,0 +1,6 @@
{
"language-settings": "اعدادات اللغة",
"description": "تُحدد اللغة الافتراضية إعدادات اللغة لجميع المستخدمين الذين يزورون المنتدى. <br />يمكن للأعضاء تجاوز اللغة الافتراضية من خلال صفحة إعدادات الحساب الخاصة بهم.",
"default-language": "اللغة الافتراضية",
"auto-detect": "الكشف عن إعدادات اللغة للزوار بشكل آلي"
}

View File

@@ -11,8 +11,6 @@
"properties": "Properties:",
"groups": "Groups:",
"open-new-window": "Open in a new window",
"dropdown": "Dropdown",
"dropdown-placeholder": "Place your dropdown menu items below, ie: <br/>&lt;li&gt;&lt;a href&#x3D;&quot;https://myforum.com&quot;&gt;Link 1&lt;/a&gt;&lt;/li&gt;",
"btn.delete": "Delete",
"btn.disable": "Disable",
@@ -22,4 +20,4 @@
"custom-route": "Custom Route",
"core": "core",
"plugin": "plugin"
}
}

View File

@@ -0,0 +1,9 @@
{
"notifications": "التنبيهات",
"chat-messages": "Chat Messages",
"play-sound": "Play",
"incoming-message": "Incoming Message",
"outgoing-message": "Outgoing Message",
"upload-new-sound": "Upload New Sound",
"saved": "Settings Saved"
}

View File

@@ -1,10 +1,8 @@
{
"administrators": "Administrators",
"global-moderators": "Global Moderators",
"moderators": "Moderators",
"no-global-moderators": "No Global Moderators",
"no-sub-categories": "No subcategories",
"subcategories": "%1 subcategories",
"moderators-of-category": "%1 Moderators",
"no-moderators": "No Moderators",
"add-administrator": "Add Administrator",
"add-global-moderator": "Add Global Moderator",

View File

@@ -10,16 +10,13 @@
"custom-class": "Custom Class",
"num-recent-replies": "# of Recent Replies",
"ext-link": "External Link",
"subcategories-per-page": "Subcategories per page",
"is-section": "Treat this category as a section",
"post-queue": "Post queue",
"tag-whitelist": "Tag Whitelist",
"upload-image": "Upload Image",
"delete-image": "Remove",
"category-image": "Category Image",
"parent-category": "Parent Category",
"optional-parent-category": "(Optional) Parent Category",
"top-level": "Top Level",
"parent-category-none": "(None)",
"copy-parent": "Copy Parent",
"copy-settings": "Copy Settings From",
@@ -32,8 +29,6 @@
"edit": "Edit",
"analytics": "Analytics",
"view-category": "View category",
"set-order": "Set order",
"set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.",
"select-category": "Select Category",
"set-parent-category": "Set Parent Category",
@@ -50,8 +45,6 @@
"privileges.no-users": "No user-specific privileges in this category.",
"privileges.section-group": "Group",
"privileges.group-private": "This group is private",
"privileges.inheritance-exception": "This group does not inherit privileges from registered-users group",
"privileges.banned-user-inheritance": "Banned users inherit privileges from banned-users group",
"privileges.search-group": "Add Group",
"privileges.copy-to-children": "Copy to Children",
"privileges.copy-from-category": "Copy from Category",

View File

@@ -13,7 +13,6 @@
"resent-single": "Manual digest resend completed",
"resent-day": "Daily digest resent",
"resent-week": "Weekly digest resent",
"resent-biweek": "Bi-Weekly digest resent",
"resent-month": "Monthly digest resent",
"null": "<em>Never</em>",
"manual-run": "Manual digest run:",

View File

@@ -4,13 +4,11 @@
"group-privileges": "Group Privileges",
"user-privileges": "User Privileges",
"edit-privileges": "Edit Privileges",
"select-clear-all": "Select/Clear All",
"chat": "Chat",
"upload-images": "Upload Images",
"upload-files": "Upload Files",
"signature": "Signature",
"ban": "Ban",
"mute": "Mute",
"invite": "Invite",
"search-content": "Search Content",
"search-users": "Search Users",
@@ -26,7 +24,6 @@
"access-topics": "Access Topics",
"create-topics": "Create Topics",
"reply-to-topics": "Reply to Topics",
"schedule-topics": "Schedule Topics",
"tag-topics": "Tag Topics",
"edit-posts": "Edit Posts",
"view-edit-history": "View Edit History",
@@ -41,24 +38,17 @@
"admin-categories": "Categories",
"admin-privileges": "Privileges",
"admin-users": "Users",
"admin-admins-mods": "Admins &amp; Mods",
"admin-groups": "Groups",
"admin-tags": "Tags",
"admin-settings": "Settings",
"alert.confirm-moderate": "<strong>Are you sure you wish to grant the moderation privilege to this user group?</strong> This group is public, and any users can join at will.",
"alert.confirm-admins-mods": "<strong>Are you sure you wish to grant the &quot;Admins &amp; Mods&quot; privilege to this user/group?</strong> Users with this privilege are able to promote and demote other users into privileged positions, <em>including super administrator</em>",
"alert.confirm-save": "Please confirm your intention to save these privileges",
"alert.saved": "Privilege changes saved and applied",
"alert.confirm-discard": "Are you sure you wish to discard your privilege changes?",
"alert.discarded": "Privilege changes discarded",
"alert.confirm-copyToAll": "Are you sure you wish to apply this set of <strong>%1</strong> to <strong>all categories</strong>?",
"alert.confirm-copyToAllGroup": "Are you sure you wish to apply this group's set of <strong>%1</strong> to <strong>all categories</strong>?",
"alert.confirm-copyToChildren": "Are you sure you wish to apply this set of <strong>%1</strong> to <strong>all descendant (child) categories</strong>?",
"alert.confirm-copyToChildrenGroup": "Are you sure you wish to apply this group's set of <strong>%1</strong> to <strong>all descendant (child) categories</strong>?",
"alert.confirm-copyToAll": "Are you sure you wish to apply this privilege set to <strong>all categories</strong>?",
"alert.confirm-copyToAllGroup": "Are you sure you wish to apply this group's privilege set to <strong>all categories</strong>?",
"alert.confirm-copyToChildren": "Are you sure you wish to apply this privilege set to <strong>all descendant (child) categories</strong>?",
"alert.confirm-copyToChildrenGroup": "Are you sure you wish to apply this group's privilege set to <strong>all descendant (child) categories</strong>?",
"alert.no-undo": "<em>This action cannot be undone.</em>",
"alert.admin-warning": "Administrators implicitly get all privileges",
"alert.copyPrivilegesFrom-title": "Select a category to copy from",
"alert.copyPrivilegesFrom-warning": "This will copy <strong>%1</strong> from the selected category.",
"alert.copyPrivilegesFromGroup-warning": "This will copy this group's set of <strong>%1</strong> from the selected category."
"alert.admin-warning": "Administrators implicitly get all privileges"
}

View File

@@ -2,6 +2,7 @@
"none": "Your forum does not have any topics with tags yet.",
"bg-color": "Background Colour",
"text-color": "Text Colour",
"create-modify": "Create & Modify Tags",
"description": "Select tags by clicking or dragging, use <code>CTRL</code> to select multiple tags.",
"create": "Create Tag",
"modify": "Modify Tags",
@@ -13,6 +14,5 @@
"alerts.editing": "Editing tag(s)",
"alerts.confirm-delete": "Do you want to delete the selected tags?",
"alerts.update-success": "Tag Updated!",
"reset-colors": "Reset colors"
"alerts.update-success": "Tag Updated!"
}

View File

@@ -5,7 +5,5 @@
"orphaned": "Orphaned",
"size/filecount": "Size / Filecount",
"confirm-delete": "Do you really want to delete this file?",
"filecount": "%1 files",
"new-folder": "New Folder",
"name-new-folder": "Enter a name for new the folder"
"filecount": "%1 files"
}

View File

@@ -1,6 +1,6 @@
{
"users": "المستخدمين",
"edit": "Actions",
"edit": "تحرير",
"make-admin": "Make Admin",
"remove-admin": "Remove Admin",
"validate-email": "Validate Email",
@@ -18,8 +18,7 @@
"download-csv": "Download CSV",
"manage-groups": "Manage Groups",
"add-group": "Add Group",
"create": "Create User",
"invite": "Invite by Email",
"invite": "Invite",
"new": "New User",
"filter-by": "Filter by",
"pills.unvalidated": "Not Validated",
@@ -48,8 +47,6 @@
"users.uid": "uid",
"users.username": "username",
"users.email": "email",
"users.no-email": "(no email)",
"users.ip": "IP",
"users.postcount": "postcount",
"users.reputation": "reputation",
"users.flags": "flags",
@@ -63,7 +60,7 @@
"create.password": "Password",
"create.password-confirm": "Confirm Password",
"temp-ban.length": "Length",
"temp-ban.length": "Ban Length",
"temp-ban.reason": "Reason <span class=\"text-muted\">(Optional)</span>",
"temp-ban.hours": "Hours",
"temp-ban.days": "Days",
@@ -91,7 +88,6 @@
"alerts.validate-email-success": "Emails validated",
"alerts.validate-force-password-reset-success": "User(s) passwords have been reset and their existing sessions have been revoked.",
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
"alerts.password-reset-email-sent": "Password reset email sent.",
"alerts.confirm-delete": "<strong>Warning!</strong><p>Do you really want to delete <strong>user(s)</strong>?</p><p>This action is not reversible! Only the user account will be deleted, their posts and topics will remain.</p>",
"alerts.delete-success": "User(s) Deleted!",
"alerts.confirm-delete-content": "<strong>Warning!</strong><p>Do you really want to delete these user(s) <strong>content</strong>?</p><p>This action is not reversible! The users' accounts will remain, but their posts and topics will be deleted.</p>",
@@ -106,7 +102,5 @@
"alerts.prompt-email": "Emails: ",
"alerts.email-sent-to": "An invitation email has been sent to %1",
"alerts.x-users-found": "%1 user(s) found, (%2 seconds)",
"export-users-started": "Exporting users as csv, this might take a while. You will receive a notification when it is complete.",
"export-users-completed": "Users exported as csv, click here to download."
"alerts.x-users-found": "%1 user(s) found, (%2 seconds)"
}

View File

@@ -1,10 +1,5 @@
{
"section-dashboard": "Dashboards",
"dashboard/overview": "Overview",
"dashboard/logins": "Logins",
"dashboard/users": "Users",
"dashboard/topics": "Topics",
"dashboard/searches": "Searches",
"dashboard": "Dashboard",
"section-general": "عام",
"section-manage": "إدارة",
@@ -76,7 +71,7 @@
"logout": "Log out",
"view-forum": "View Forum",
"search.placeholder": "Search settings",
"search.placeholder": "Press &quot;/&quot; to search for settings",
"search.no-results": "No results...",
"search.search-forum": "Search the forum for <strong></strong>",
"search.keep-typing": "Type more to see results...",

View File

@@ -15,10 +15,6 @@
"headers.acac": "Access-Control-Allow-Credentials",
"headers.acam": "Access-Control-Allow-Methods",
"headers.acah": "Access-Control-Allow-Headers",
"headers.coep": "Cross-Origin-Embedder-Policy",
"headers.coep-help": "When enabled (default), will set the header to <code>require-corp</code>",
"headers.coop": "Cross-Origin-Opener-Policy",
"headers.corp": "Cross-Origin-Resource-Policy",
"hsts": "Strict Transport Security",
"hsts.enabled": "Enabled HSTS (recommended)",
"hsts.maxAge": "HSTS Max Age",

View File

@@ -1,13 +1,9 @@
{
"tokens": "Tokens",
"settings": "Settings",
"lead-text": "From this page you can configure access to the Write API in NodeBB.",
"intro": "By default, the Write API authenticates users based on their session cookie, but NodeBB also supports Bearer authentication via tokens generated via this page.",
"docs": "Click here to access the full API specification",
"require-https": "Require API usage via HTTPS only",
"require-https-caveat": "<strong>Note</strong>: Some installations involving load balancers may proxy their requests to NodeBB using HTTP, in which case this option should remain disabled.",
"uid": "User ID",
"uid-help-text": "Specify a User ID to associate with this token. If the user ID is <code>0</code>, it will be considered a <em>master</em> token, which can assume the identity of other users based on the <code>_uid</code> parameter",
"description": "Description",

View File

@@ -6,14 +6,13 @@
"from-help": "The from name to display in the email.",
"smtp-transport": "SMTP Transport",
"smtp-transport.enabled": "Enable 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 &quot;Custom Service&quot; and enter the details below.",
"smtp-transport.gmail-warning1": "If you are using GMail as your email provider, you will have to generate an &quot;App Password&quot; in order for NodeBB to authenticate successfully. You can generate one at the <a href=\"https://myaccount.google.com/apppasswords\">App Passwords <i class=\"fa fa-external-link\"></i></a> page.",
"smtp-transport.gmail-warning2": "For more information about this workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">please consult this NodeMailer article <i class=\"fa fa-external-link\"></i></a> on the issue. 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.auto-enable-toast": "It looks like you&apos;re configuring an SMTP transport. We enabled the \"SMTP Transport\" option for you.",
"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",
@@ -37,13 +36,6 @@
"subscriptions.disable": "Disable email digests",
"subscriptions.hour": "Digest Hour",
"subscriptions.hour-help": "Please enter a number representing the hour to send scheduled email digests (e.g. <code>0</code> for midnight, <code>17</code> for 5:00pm). Keep in mind that this is the hour according to the server itself, and may not exactly match your system clock.<br /> The approximate server time is: <span id=\"serverTime\"></span><br /> The next daily digest is scheduled to be sent <span id=\"nextDigestTime\"></span>",
"notifications.remove-images": "Remove images from email notifications",
"require-email-address": "Require new users to specify an email address",
"require-email-address-warning": "By default, users can opt-out of entering an email address by leaving the field blank. Enabling this option means they have to enter an email address in order to proceed with registration. <strong>It does not ensure user will enter a real email address, nor even an address they own.</strong>",
"send-validation-email": "Send validation emails when an email is added or changed",
"include-unverified-emails": "Send emails to recipients who have not explicitly confirmed their emails",
"include-unverified-warning": "By default, users with emails associated with their account have already been verified, but there are situations where this is not the case (e.g. SSO logins, grandfathered users, etc). <strong>Enable this setting at your own risk</strong> &ndash; sending emails to unverified addresses may be a violation of regional anti-spam laws.",
"prompt": "Prompt users to enter or confirm their emails",
"prompt-help": "If a user does not have an email set, or their email is not confirmed, a warning will be shown on screen.",
"sendEmailToBanned": "Send emails to users even if they have been banned"
}
"notifications.settings": "Email notification settings",
"notifications.remove-images": "Remove images from email notifications"
}

View File

@@ -3,9 +3,9 @@
"title": "عنوان الموقع",
"title.short": "عنوان قصير",
"title.short-placeholder": "ان لم تقم بكتابة عنوان مختصر, سيتم استخدام عنوان الموقع الكلي",
"title.url": "Title Link URL",
"title.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. <br> Note: This is not the external URL used in emails, etc. That is set by the <code>url</code> property in config.json",
"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": "اسم المنتدي",
"title.show-in-header": "Show Site Title in Header",
"browser-title": "عنوان المتصفح",
@@ -20,9 +20,9 @@
"logo.image": "صورة",
"logo.image-placeholder": "Path to a logo to display on forum header",
"logo.upload": "رفع",
"logo.url": "Logo Link URL",
"logo.url": "الرابط",
"logo.url-placeholder": "The URL of the site logo",
"logo.url-help": "When the logo is clicked, send users to this address. If left blank, user will be sent to the forum index. <br> Note: This is not the external URL used in emails, etc. That is set by the <code>url</code> property in config.json",
"logo.url-help": "When the logo is clicked, send users to this address. If left blank, user will be sent to the forum index.",
"logo.alt-text": "نص بديل",
"log.alt-text-placeholder": "Alternative text for accessibility",
"favicon": "صورة المفضله",
@@ -35,16 +35,10 @@
"maskable-icon.help": "Recommended size and format: 512x512, PNG format only. If no maskable icon is specified, NodeBB will fall back to the Touch Icon.",
"outgoing-links": "Outgoing Links",
"outgoing-links.warning-page": "Use Outgoing Links Warning Page",
"search": "Search",
"search-default-in": "Search In",
"search-default-in-quick": "Quick Search In",
"search-default-sort-by": "Sort by",
"search-default-sort-by": "الترتيب الافتراضي للبحث",
"outgoing-links.whitelist": "Domains to whitelist for bypassing the warning page",
"site-colors": "Site Color Metadata",
"theme-color": "لون الثيم",
"background-color": "لون الخلفية",
"background-color-help": "Color used for splash screen background when website is installed as a PWA",
"undo-timeout": "Undo Timeout",
"undo-timeout-help": "Some operations such as moving topics will allow for the moderator to undo their action within a certain timeframe. Set to 0 to disable undo completely.",
"topic-tools": "Topic Tools"
}
"background-color-help": "Color used for splash screen background when website is installed as a PWA"
}

View File

@@ -11,8 +11,6 @@
"properties": "Properties:",
"groups": "Groups:",
"open-new-window": "Open in a new window",
"dropdown": "Dropdown",
"dropdown-placeholder": "Place your dropdown menu items below, ie: <br/>&lt;li&gt;&lt;a href&#x3D;&quot;https://myforum.com&quot;&gt;Link 1&lt;/a&gt;&lt;/li&gt;",
"btn.delete": "Delete",
"btn.disable": "Disable",
@@ -22,4 +20,4 @@
"custom-route": "Custom Route",
"core": "core",
"plugin": "plugin"
}
}

View File

@@ -2,6 +2,5 @@
"notifications": "Notifications",
"welcome-notification": "Welcome Notification",
"welcome-notification-link": "Welcome Notification Link",
"welcome-notification-uid": "Welcome Notification User (UID)",
"post-queue-notification-uid": "Post Queue User (UID)"
"welcome-notification-uid": "Welcome Notification User (UID)"
}

View File

@@ -1,12 +1,10 @@
{
"pagination": "Pagination Settings",
"enable": "Paginate topics and posts instead of using infinite scroll.",
"posts": "Post Pagination",
"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",
"categories-per-page": "Categories per page"
"max-topics-per-page": "Maximum topics per page"
}

View File

@@ -40,7 +40,6 @@
"teaser.last-post": "Last &ndash; Show the latest post, including the original post, if no replies",
"teaser.last-reply": "Last &ndash; Show the latest reply, or a \"No replies\" placeholder if no replies",
"teaser.first": "First",
"showPostPreviewsOnHover": "Show a preview of posts when mouse overed",
"unread": "Unread Settings",
"unread.cutoff": "Unread cutoff days",
"unread.min-track-last": "Minimum posts in topic before tracking last read",
@@ -57,9 +56,6 @@
"composer.show-help": "Show \"Help\" tab",
"composer.enable-plugin-help": "Allow plugins to add content to the help tab",
"composer.custom-help": "Custom Help Text",
"backlinks": "Backlinks",
"backlinks.enabled": "Enable topic backlinks",
"backlinks.help": "If a post references another topic, a link back to the post will be inserted into the referenced topic at that point in time.",
"ip-tracking": "IP Tracking",
"ip-tracking.each-post": "Track IP Address for each post",
"enable-post-history": "Enable Post History"

View File

@@ -4,13 +4,9 @@
"disable-down-voting": "Disable Down Voting",
"votes-are-public": "All Votes Are Public",
"thresholds": "Activity Thresholds",
"min-rep-upvote": "Minimum reputation to upvote posts",
"upvotes-per-day": "Upvotes per day (set to 0 for unlimited upvotes)",
"upvotes-per-user-per-day": "Upvotes per user per day (set to 0 for unlimited upvotes)",
"min-rep-downvote": "Minimum reputation to downvote posts",
"downvotes-per-day": "Downvotes per day (set to 0 for unlimited downvotes)",
"downvotes-per-user-per-day": "Downvotes per user per day (set to 0 for unlimited downvotes)",
"min-rep-chat": "Minimum reputation to send chat messages",
"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",
@@ -20,8 +16,5 @@
"flags": "Flag Settings",
"flags.limit-per-target": "Maximum number of times something can be flagged",
"flags.limit-per-target-placeholder": "Default: 0",
"flags.limit-per-target-help": "When a post or user is flagged multiple times, each additional flag is considered a &quot;report&quot; and added to the original flag. Set this option to a number other than zero to limit the number of reports an item can receive.",
"flags.auto-flag-on-downvote-threshold": "Number of downvotes to auto flag posts (Set to 0 to disable, default: 0)",
"flags.auto-resolve-on-ban": "Automatically resolve all of a user's tickets when they are banned"
"flags.limit-per-target-placeholder": "Default: 0"
}

View File

@@ -1,8 +1,6 @@
{
"tag": "Tag Settings",
"link-to-manage": "Manage Tags",
"system-tags": "System Tags",
"system-tags-help": "Only privileged users will be able to use these tags.",
"min-per-topic": "Minimum Tags per Topic",
"max-per-topic": "Maximum Tags per Topic",
"min-length": "Minimum Tag Length",

View File

@@ -1,11 +1,8 @@
{
"posts": "المشاركات",
"orphans": "Orphaned Files",
"allow-files": "السماح للأعضاء بتحميل الملفات الإعتيادية",
"private": "جعل الملفات التي تم رفعها خاصة",
"strip-exif-data": "Strip EXIF Data",
"preserve-orphaned-uploads": "Keep uploaded files on disk after a post is purged",
"orphanExpiryDays": "Days to keep orphaned files",
"orphanExpiryDays-help": "After this many days, orphaned uploads will be deleted from the file system.<br />Set 0 or leave blank to disable.",
"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",
@@ -24,9 +21,6 @@
"topic-thumb-size": "حجم الصورة المصغرة للموضوع",
"allowed-file-extensions": "إمتدادات الملفات المسموح بها",
"allowed-file-extensions-help": "أدخل قائمة بامتدادات الملفات مفصولة بفواصل (مثال: <code>pdf,xls,doc</code>). القائمة الفارغة تعني أن كل الامتدادات مسموح بها.",
"upload-limit-threshold": "Rate limit user uploads to:",
"upload-limit-threshold-per-minute": "Per %1 Minute",
"upload-limit-threshold-per-minutes": "Per %1 Minutes",
"profile-avatars": "الصورة الرمزية للملف الشخصي",
"allow-profile-image-uploads": "السماح للأعضاء برفع الصور الرمزية",
"convert-profile-image-png": "تحويل إمتداد الصور الرمزية المرفوعه الى PNG",

View File

@@ -1,10 +1,12 @@
{
"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://ec.europa.eu/info/priorities/justice-and-fundamental-rights/data-protection/2018-reform-eu-data-protection-rules/eu-data-protection-rules_en\">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.",
@@ -69,7 +71,6 @@
"digest-freq.off": "Off",
"digest-freq.daily": "Daily",
"digest-freq.weekly": "Weekly",
"digest-freq.biweekly": "Bi-Weekly",
"digest-freq.monthly": "Monthly",
"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",

View File

@@ -18,6 +18,5 @@
"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": "الأقسام المُتابعة",
"x-more-categories": "%1 more categories"
"watched-categories": "الأقسام المُتابعة"
}

View File

@@ -6,9 +6,7 @@
"greeting_no_name": "مرحبًا",
"greeting_with_name": "مرحبًا بك يا %1",
"email.verify-your-email.subject": "Please verify your email",
"email.verify.text1": "You've requested that we change or confirm your email address",
"email.verify.text2": "For security purposes, we only change or confirm the email address on file once its ownership has been confirmed via email. <strong>If you did not request this, no action is required on your part.</strong>",
"email.verify.text3": "Once you confirm this email address, we will replace your current email address with this one (%1).",
"email.verify.text1": "Your email address has changed!",
"welcome.text1": "شكرًا على تسجيلك في %1!",
"welcome.text2": "لتفعيل حسابك، نحتاج إلى التأكد من صحة عنوان البريد الإلكتروني الذي سجلت به.",
"welcome.text3": "تم قبول نتسجيلك ، يمكنك الدخول باتسخدام اسم المستخدم و كلمة المرور.",
@@ -48,8 +46,6 @@
"unsub.cta": "انقر هنا لتغيير تلك الإعدادات",
"unsubscribe": "unsubscribe",
"unsub.success": "You will no longer receive emails from the <strong>%1</strong> mailing list",
"unsub.failure.title": "Unable to unsubscribe",
"unsub.failure.message": "Unfortunately, we were not able to unsubscribe you from the mailing list, as there was an issue with the link. However, you can alter your email preferences by going to <a href=\"%2\">your user settings</a>.<br /><br />(error: <code>%1</code>)",
"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.",

View File

@@ -1,8 +1,6 @@
{
"invalid-data": "بيانات غير صحيحة",
"invalid-json": "Invalid JSON",
"wrong-parameter-type": "A value of type %3 was expected for property `%1`, but %2 was received instead",
"required-parameters-missing": "Required parameters were missing from this API call: %1",
"not-logged-in": "لم تقم بتسجيل الدخول",
"account-locked": "تم حظر حسابك مؤقتًا.",
"search-requires-login": "البحث في المنتدى يتطلب حساب - الرجاء تسجيل الدخول أو التسجيل",
@@ -11,8 +9,6 @@
"invalid-tid": "موضوع غير متواجد",
"invalid-pid": "رد غير موجود",
"invalid-uid": "مستخدم غير موجود",
"invalid-mid": "Invalid Chat Message ID",
"invalid-date": "A valid date must be provided",
"invalid-username": "اسم المستخدم غير مقبول",
"invalid-email": "البريد الاكتروني غير مقبول",
"invalid-fullname": "Invalid Fullname",
@@ -25,21 +21,16 @@
"invalid-username-or-password": "المرجود تحديد اسم مستخدم و كلمة مرور",
"invalid-search-term": "كلمة البحث غير صحيحة",
"invalid-url": "Invalid URL",
"invalid-event": "Invalid event: %1",
"local-login-disabled": "Local login system has been disabled for non-privileged accounts.",
"csrf-invalid": "لم تتمكن من تسجيل الدخول. هنالك أحتمال ان جلستك انتهت. رجاءًا حاول مرة اخرى.",
"invalid-path": "Invalid path",
"folder-exists": "Folder exists",
"invalid-pagination-value": "رقم الصفحة غير صحيح ، يجب أن يكون بين %1 و %2 .",
"username-taken": "اسم المستخدم مأخوذ",
"email-taken": "البريد الالكتروني مأخوذ",
"email-nochange": "The email entered is the same as the email already on file.",
"email-invited": "Email was already invited",
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
"email-not-confirmed": "You are unable to post until your email is confirmed, please click here to confirm your email.",
"email-not-confirmed-chat": "لا يمكنك الدردشة حتى تقوم بتأكيد بريدك الإلكتروني، الرجاء إضغط هنا لتأكيد بريدك اﻹلكتروني.",
"email-not-confirmed-email-sent": "Your email has not been confirmed yet, please check your inbox for the confirmation email. You may not be able to post in some categories or chat until your email is confirmed.",
"no-email-to-confirm": "Your account does not have an email set. An email is necessary for account recovery, and may be necessary for chatting and posting in some categories. Please click here to enter an email.",
"user-doesnt-have-email": "User \"%1\" does not have an email set.",
"email-not-confirmed-email-sent": "Your email has not been confirmed yet, please check your inbox for the confirmation email. You won't be able to post or chat until your email is confirmed.",
"no-email-to-confirm": "هذا المنتدى يستلزم تفعيل بريدك الإلكتروني، انقر هنا من فضلك لإدخاله.",
"email-confirm-failed": "لم نستطع تفعيل بريدك الإلكتروني، المرجو المحاولة لاحقًا.",
"confirm-email-already-sent": "لقد تم ارسال بريد التأكيد، الرجاء اﻹنتظار 1% دقائق لإعادة اﻹرسال",
"sendmail-not-found": "The sendmail executable could not be found, please ensure it is installed and executable by the user running NodeBB.",
@@ -48,7 +39,6 @@
"username-too-long": "اسم المستخدم طويل",
"password-too-long": "كلمة السر طويلة ",
"reset-rate-limited": "Too many password reset requests (rate limited)",
"reset-same-password": "Please use a password that is different from your current one",
"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)",
@@ -61,7 +51,6 @@
"no-group": "مجموعة غير موجودة",
"no-user": "اسم مستخدم غير موجود",
"no-teaser": "مقتطف غير موجود",
"no-flag": "Flag does not exist",
"no-privileges": "لاتملك الصلاحيات اللازمة للقيام بهذه العملية",
"category-disabled": "قائمة معطلة",
"topic-locked": "الموضوع مقفول",
@@ -92,30 +81,15 @@
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
"too-many-tags": "Too many tags. Topics can't have more than %1 tag(s)",
"cant-use-system-tag": "You can not use this system tag.",
"cant-remove-system-tag": "You can not remove this system tag.",
"still-uploading": "الرجاء الانتظار حتى يكتمل الرفع.",
"file-too-big": "الحد الأقصى لرفع الملفات %1 كيلو بت. رجاءًا ارفع ملف أصغر",
"guest-upload-disabled": "خاصية رفع الملفات غير مفعلة للزوار.",
"cors-error": "Unable to upload image due to misconfigured CORS",
"upload-ratelimit-reached": "You have uploaded too many files at one time. Please try again later.",
"scheduling-to-past": "Please select a date in the future.",
"invalid-schedule-date": "Please enter a valid date and time.",
"cant-pin-scheduled": "Scheduled topics cannot be (un)pinned.",
"cant-merge-scheduled": "Scheduled topics cannot be merged.",
"cant-move-posts-to-scheduled": "Can't move posts to a scheduled topic.",
"cant-move-from-scheduled-to-existing": "Can't move posts from a scheduled topic to an existing topic.",
"already-bookmarked": "You have already bookmarked this post",
"already-unbookmarked": "You have already unbookmarked this post",
"cant-ban-other-admins": "لايمكن حظر مدبر نظام آخر.",
"cant-mute-other-admins": "You can't mute other admins!",
"user-muted-for-hours": "You have been muted, you will be able to post in %1 hour(s)",
"user-muted-for-minutes": "You have been muted, you will be able to post in %1 minute(s)",
"cant-make-banned-users-admin": "You can't make banned users admin.",
"cant-remove-last-admin": "رجاءًا ، أضف مدير أخر قبل حذف صلاحيات الإدارة من حسابك.",
"account-deletion-disabled": "Account deletion is disabled",
"cant-delete-admin": "رجاءًا أزل صلاحيات الإدارة قبل حذف الحساب. ",
"already-deleting": "Already deleting",
"invalid-image": "Invalid image",
"invalid-image-type": "نوع الصورة غير مدعوم. الأنواع المدعومة هي : %1",
"invalid-image-extension": "امتداد الصورة غير مدعوم.",
@@ -149,32 +123,27 @@
"invalid-chat-message": "الرسالة غير صالحة.",
"chat-message-too-long": "Chat messages can not be longer than %1 characters.",
"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.",
"chat-room-does-not-exist": "Chat room does not exist.",
"already-voting-for-this-post": "لقد شاركت بالتصويت ، ألا تذكر؟",
"reputation-system-disabled": "نظام السمعة معطل",
"downvoting-disabled": "التصويتات السلبية معطلة",
"not-enough-reputation-to-chat": "You need %1 reputation to chat",
"not-enough-reputation-to-upvote": "You need %1 reputation to upvote",
"not-enough-reputation-to-downvote": "You need %1 reputation to downvote",
"not-enough-reputation-to-flag": "You need %1 reputation to flag this post",
"not-enough-reputation-min-rep-website": "You need %1 reputation to add a website",
"not-enough-reputation-min-rep-aboutme": "You need %1 reputation to add an about me",
"not-enough-reputation-min-rep-signature": "You need %1 reputation to add a signature",
"not-enough-reputation-min-rep-profile-picture": "You need %1 reputation to add a profile picture",
"not-enough-reputation-min-rep-cover-picture": "You need %1 reputation to add a cover picture",
"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",
"post-already-flagged": "You have already flagged this post",
"user-already-flagged": "You have already flagged this user",
"post-flagged-too-many-times": "This post has been flagged by others already",
"user-flagged-too-many-times": "This user has been flagged by others already",
"cant-flag-privileged": "You are not allowed to flag the profiles or content of privileged users (moderators/global moderators/admins)",
"self-vote": "You cannot vote on your own post",
"too-many-upvotes-today": "You can only upvote %1 times a day",
"too-many-upvotes-today-user": "You can only upvote a user %1 times a day",
"too-many-downvotes-today": "You can only downvote %1 times a day",
"too-many-downvotes-today-user": "You can only downvote a user %1 times a day",
"reload-failed": "المنتدى واجه مشكلة أثناء إعادة التحميل: \"%1\". سيواصل المنتدى خدمة العملاء السابقين لكن يجب عليك إلغاء أي تغيير قمت به قبل إعادة التحميل.",
@@ -190,10 +159,8 @@
"cant-kick-self": "لا يمكنك طرد نفسك من المجموعة.",
"no-users-selected": "لا يوجد مستخدم محدد.",
"invalid-home-page-route": "Invalid home page route",
"invalid-session": "Invalid Session",
"invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.",
"session-mismatch": "Session Mismatch",
"session-mismatch-text": "It looks like your login session no longer matches with the server. Please refresh this page.",
"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!",
"cant-move-topic-to-same-category": "Can't move topic to the same category!",
@@ -203,21 +170,5 @@
"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",
"socket-reconnect-failed": "Unable to reach the server at this time. Click here to try again, or try again later",
"plugin-not-whitelisted": "Unable to install plugin &ndash; only plugins whitelisted by the NodeBB Package Manager can be installed via the ACP",
"plugins-set-in-configuration": "You are not allowed to change plugin state as they are defined at runtime (config.json, environmental variables or terminal arguments), please modify the configuration instead.",
"theme-not-set-in-configuration": "When defining active plugins in configuration, changing themes requires adding the new theme to the list of active plugins before updating it in the ACP",
"topic-event-unrecognized": "Topic event '%1' unrecognized",
"cant-set-child-as-parent": "Can't set child as parent category",
"cant-set-self-as-parent": "Can't set self as parent category",
"api.master-token-no-uid": "A master token was received without a corresponding `_uid` in the request body",
"api.400": "Something was wrong with the request payload you passed in.",
"api.401": "A valid login session was not found. Please log in and try again.",
"api.403": "You are not authorised to make this call",
"api.404": "Invalid API call",
"api.426": "HTTPS is required for requests to the write api, please re-send your request via HTTPS",
"api.429": "You have made too many requests, please try again later",
"api.500": "An unexpected error was encountered while attempting to service your request.",
"api.501": "The route you are trying to call is not implemented yet, please try again tomorrow",
"api.503": "The route you are trying to call is not currently available due to a server configuration"
"plugin-not-whitelisted": "Unable to install plugin &ndash; only plugins whitelisted by the NodeBB Package Manager can be installed via the ACP"
}

View File

@@ -6,7 +6,6 @@
"assignee": "المحال إليه",
"update": "تحديث",
"updated": "تم التحديث",
"resolved": "Resolved",
"target-purged": "The content this flag referred to has been purged and is no longer available.",
"graph-label": "Daily Flags",
@@ -27,7 +26,6 @@
"filter-cid-all": "All categories",
"apply-filters": "Apply Filters",
"more-filters": "More Filters",
"fewer-filters": "Fewer Filters",
"quick-actions": "اجراءات سريعه",
"flagged-user": "Flagged User",
@@ -38,7 +36,6 @@
"delete-post": "حذف المشاركة",
"purge-post": "Purge Post",
"restore-post": "استرجاع المشاركة",
"delete": "Delete Flag",
"user-view": "مشاهدة الملف الشخصي",
"user-edit": "تعديل الملف الشخصي",
@@ -47,10 +44,8 @@
"add-note": "اضافة ملاحظة",
"no-notes": "No shared notes.",
"delete-note-confirm": "Are you sure you want to delete this flag note?",
"delete-flag-confirm": "Are you sure you want to delete this flag?",
"note-added": "Note Added",
"note-deleted": "Note Deleted",
"flag-deleted": "Flag Deleted",
"history": "Account &amp; Flag History",
"no-history": "No flag history.",
@@ -80,10 +75,11 @@
"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.",
"bulk-actions": "Bulk Actions",
"bulk-resolve": "Resolve Flag(s)",
"bulk-success": "%1 flags updated",
"flagged-timeago-readable": "Flagged <span class=\"timeago\" title=\"%1\"></span> (%2)",
"auto-flagged": "[Auto Flagged] Received %1 downvotes."
"bulk-success": "%1 flags updated"
}

View File

@@ -23,7 +23,7 @@
"close": "أغلق",
"pagination": "الصفحات",
"pagination.out_of": "%1 من %2",
"pagination.enter_index": "Go to post index",
"pagination.enter_index": "أدخل الرقم التسلسلي",
"header.admin": "مدير النظام",
"header.categories": "الأقسام",
"header.recent": "حديث",
@@ -46,9 +46,7 @@
"alert.success": "نجاح",
"alert.error": "خطأ",
"alert.banned": "محظور",
"alert.banned.message": "You have just been banned, your access is now restricted.",
"alert.unbanned": "Unbanned",
"alert.unbanned.message": "Your ban has been lifted.",
"alert.banned.message": "لقد تم حظر حسابك. سيتم تسجيل الخروج.",
"alert.unfollow": "أنت لا تتابع %1 بعد الآن!",
"alert.follow": "أنت الآن تتابع %1!",
"users": "الأعضاء",
@@ -56,7 +54,6 @@
"posts": "المشاركات",
"x-posts": "%1 posts",
"best": "الأفضل",
"controversial": "Controversial",
"votes": "Votes",
"x-votes": "%1 votes",
"voters": "Voters",
@@ -71,7 +68,6 @@
"firstpost": "First post",
"read_more": "اقرأ المزيد",
"more": "المزيد",
"none": "None",
"posted_ago_by_guest": "كتب %1 بواسطة زائر",
"posted_ago_by": "كتب %1 بواسطة %2",
"posted_ago": "كتب %1",
@@ -97,8 +93,6 @@
"guest": "زائر",
"guests": "الزوار",
"former_user": "A Former User",
"system-user": "System",
"unknown-user": "Unknown user",
"updated.title": "تم تحديث المنتدى",
"updated.message": "لقد تم تحديث المنتدى إلى آخر نسخة للتو. إضغط هنا لإعادة تحميل الصفحة.",
"privacy": "الخصوصية",

View File

@@ -35,7 +35,8 @@
"details.member_count": "عدد اﻷعضاء",
"details.creation_date": "تاريخ الإنشاء",
"details.description": "الوصف",
"details.member-post-cids": "Category IDs to display posts from",
"details.member-post-cids": "Categories to display posts from",
"details.member-post-cids-help": "<strong>Note</strong>: Selecting no categories will assume all categories are included. Use <code>ctrl</code> and <code>shift</code> to select multiple options.",
"details.badge_preview": "معاينة الوسام",
"details.change_icon": "تغيير الأيقونة",
"details.change_label_colour": "Change Label Colour",

View File

@@ -1,12 +1,12 @@
{
"username-email": "اسم المستخدم / البريد الإلكتروني",
"username": "اسم المستخدم",
"email": "البريد الإلكتروني",
"remember_me": "تذكرني؟",
"forgot_password": "نسيت كلمة المرور؟",
"alternative_logins": "تسجيلات الدخول البديلة",
"failed_login_attempt": "تسجيل الدخول غير ناجح",
"login_successful": "قمت بتسجيل الدخول بنجاح!",
"dont_have_account": "لا تملك حساب؟",
"logged-out-due-to-inactivity": "لقد تم تسجيل خروجك من لوحة تحكم بسبب عدم نشاطك",
"caps-lock-enabled": "Caps Lock is enabled"
"logged-out-due-to-inactivity": "لقد تم تسجيل خروجك من لوحة تحكم بسبب عدم نشاطك"
}

View File

@@ -1,13 +1,13 @@
{
"chat.chatting_with": "Chat with",
"chat.placeholder": "Type chat message here, drag & drop images, press enter to send",
"chat.placeholder": "أكتب رسالة دردشة هنا، اضغط ENTER للإرسال",
"chat.scroll-up-alert": "You are looking at older messages, click here to go to most recent message.",
"chat.send": "أرسل",
"chat.no_active": "لا يوجد لديك دردشات نشطة.",
"chat.user_typing": "%1 يكتب رسالة...",
"chat.user_has_messaged_you": "%1 أرسل لك رسالة.",
"chat.see_all": "All chats",
"chat.mark_all_read": "Mark all read",
"chat.see_all": "عرض كل المحادثات",
"chat.mark_all_read": "Mark all chats read",
"chat.no-messages": "المرجو اختيار مرسل إليه لمعاينة تاريخ الدردشات",
"chat.no-users-in-room": "No users in this room",
"chat.recent-chats": "آخر الدردشات",
@@ -54,29 +54,16 @@
"composer.formatting.strikethrough": "Strikethrough",
"composer.formatting.code": "Code",
"composer.formatting.link": "Link",
"composer.formatting.picture": "Image Link",
"composer.formatting.picture": "Picture",
"composer.upload-picture": "Upload Image",
"composer.upload-file": "Upload File",
"composer.zen_mode": "Zen Mode",
"composer.select_category": "Select a category",
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
"composer.schedule-for": "Schedule topic for",
"composer.schedule-date": "Date",
"composer.schedule-time": "Time",
"composer.cancel-scheduling": "Cancel Scheduling",
"composer.set-schedule-date": "Set Date",
"bootbox.ok": "OK",
"bootbox.cancel": "إلغاء",
"bootbox.confirm": "تأكيد",
"bootbox.submit": "Submit",
"bootbox.send": "Send",
"cover.dragging_title": "Cover Photo Positioning",
"cover.dragging_message": "Drag the cover photo to the desired position and click \"Save\"",
"cover.saved": "Cover photo image and position saved",
"thumbs.modal.title": "Manage topic thumbnails",
"thumbs.modal.no-thumbs": "No thumbnails found.",
"thumbs.modal.resize-note": "<strong>Note</strong>: This forum is configured to resize topic thumbnails down to a maximum width of %1px",
"thumbs.modal.add": "Add thumbnail",
"thumbs.modal.remove": "Remove thumbnail",
"thumbs.modal.confirm-remove": "Are you sure you want to remove this thumbnail?"
"cover.saved": "Cover photo image and position saved"
}

View File

@@ -1,8 +1,8 @@
{
"title": "التنبيهات",
"no_notifs": "ليس لديك أية تنبيهات جديدة",
"see_all": "All notifications",
"mark_all_read": "Mark all read",
"see_all": "عرض كل التنبيهات",
"mark_all_read": "اجعل كل التنبيهات مقروءة",
"back_to_home": "عودة إلى %1",
"outgoing_link": "رابط خارجي",
"outgoing_link_message": "أنت تغادر اﻻن %1",
@@ -14,7 +14,6 @@
"topics": "مواضيع",
"replies": "ردود",
"chat": "محادثات",
"group-chat": "Group Chats",
"follows": "متابعون",
"upvote": "الموافقين",
"new-flags": "New Flags",
@@ -47,10 +46,6 @@
"profile-exported": "<strong>%1</strong> profile exported, click to download",
"posts-exported": "<strong>%1</strong> posts exported, click to download",
"uploads-exported": "<strong>%1</strong> uploads exported, click to download",
"users-csv-exported": "Users csv exported, click to download",
"post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
"post-queue-rejected": "Your queued post has been rejected.",
"post-queue-notify": "Queued post received a notification:<br/>\"%1\"",
"email-confirmed": "تم التحقق من عنوان البريد الإلكتروني",
"email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.",
"email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.",
@@ -67,7 +62,6 @@
"notificationType_new-chat": "When you receive a chat message",
"notificationType_new-group-chat": "When you receive a group chat message",
"notificationType_group-invite": "When you receive a group invite",
"notificationType_group-leave": "When a user leaves your group",
"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",

View File

@@ -54,7 +54,6 @@
"account/upvoted": "Posts upvoted by %1",
"account/downvoted": "Posts downvoted by %1",
"account/best": "Best posts made by %1",
"account/controversial": "Controversial posts made by %1",
"account/blocks": "Blocked users for %1",
"account/uploads": "Uploads by %1",
"account/sessions": "Login Sessions",

View File

@@ -1,4 +1,3 @@
{
"post-queue": "Post Queue",
"description": "There are no posts in the post queue. <br> To enable this feature, go to <a href=\"%1\">Settings &rarr; Post &rarr; Post Queue</a> and enable <strong>Post Queue</strong>.",
@@ -8,24 +7,5 @@
"content": "Content",
"posted": "Posted",
"reply-to": "Reply to \"%1\"",
"content-editable": "Click on content to edit",
"category-editable": "Click on category to edit",
"title-editable": "Click on title to edit",
"reply": "Reply",
"topic": "Topic",
"accept": "Accept",
"reject": "Reject",
"remove": "Remove",
"notify": "Notify",
"notify-user": "Notify User",
"confirm-reject": "Do you want to reject this post?",
"bulk-actions": "Bulk Actions",
"accept-all": "Accept All",
"accept-selected": "Accept Selected",
"reject-all": "Reject All",
"reject-all-confirm": "Do you want to reject all posts?",
"reject-selected": "Reject Selected",
"reject-selected-confirm": "Do you want to reject %1 selected posts?",
"bulk-accept-success": "%1 posts accepted",
"bulk-reject-success": "%1 posts rejected"
"content-editable": "You can click on individual content to edit before posting."
}

View File

@@ -20,13 +20,9 @@
"registration-added-to-queue": "تمت إضافتك في قائمة الإنتضار. ستتلقى رسالة إلكترونية عند الموافقة على تسجيلك من قبل الإدارة.",
"registration-queue-average-time": "Our average time for approving memberships is %1 hours %2 minutes.",
"registration-queue-auto-approve-time": "Your membership to this forum will be fully activated in up to %1 hours.",
"interstitial.intro": "We'd like some additional information in order to update your account&hellip;",
"interstitial.intro-new": "We'd like some additional information before we can create your account&hellip;",
"interstitial.errors-found": "Please review the entered information:",
"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.",
"invite.error-admin-only": "Direct user registration has been disabled. Please contact an administrator for more details.",
"invite.error-invite-only": "Direct user registration has been disabled. You must be invited by an existing user in order to access this forum.",
"invite.error-invalid-data": "The registration data received does not correspond to our records. Please contact an administrator for more details"
"gdpr_consent_denied": "You must give consent to this site to collect/process your information, and to send you emails."
}

View File

@@ -1,7 +1,7 @@
{
"success": "نجاح",
"topic-post": "لقد تمت الإضافة بنجاح.",
"post-queued": "Your post is queued for approval. You will get a notification when it is accepted or rejected.",
"post-queued": "Your post is queued for approval.",
"authentication-successful": "تم تسجيل الدخول بنجاح",
"settings-saved": "تم حفظ التغييرات!"
}

View File

@@ -1,4 +0,0 @@
{
"title": "Top",
"no_top_topics": "No top topics"
}

View File

@@ -1,6 +1,5 @@
{
"topic": "موضوع",
"title": "Title",
"no_topics_found": "لا توجد مواضيع !",
"no_posts_found": "لا توجد مشاركات!",
"post_is_deleted": "هذه المشاركة محذوفة!",
@@ -20,8 +19,6 @@
"login-to-view": "🔒 Log in to view",
"edit": "تعديل",
"delete": "حذف",
"delete-event": "Delete Event",
"delete-event-confirm": "Are you sure you want to delete this event?",
"purge": "تطهير",
"restore": "استعادة",
"move": "نقل",
@@ -32,29 +29,16 @@
"tools": "أدوات",
"locked": "مقفل",
"pinned": "مثبت",
"pinned-with-expiry": "Pinned until %1",
"scheduled": "Scheduled",
"moved": "منقول",
"moved-from": "Moved from %1",
"copy-ip": "Copy IP",
"ban-ip": "Ban IP",
"view-history": "Edit History",
"locked-by": "Locked by",
"unlocked-by": "Unlocked by",
"pinned-by": "Pinned by",
"unpinned-by": "Unpinned by",
"deleted-by": "Deleted by",
"restored-by": "Restored by",
"moved-from-by": "Moved from %1 by",
"queued-by": "Post queued for approval &rarr;",
"backlink": "Referenced by",
"forked-by": "Forked by",
"bookmark_instructions": "اضغط هنا للعودة لأخر مشاركة مقروءة في الموضوع",
"flag-post": "Flag this post",
"flag-user": "Flag this user",
"already-flagged": "Already Flagged",
"view-flag-report": "View Flag Report",
"resolve-flag": "Resolve Flag",
"merged_message": "This topic has been merged into <a href=\"%1\">%2</a>",
"deleted_message": "هذه المشاركة محذوفة. فقط من لهم صلاحية الإشراف على ا لمشاركات يمكنهم معاينتها.",
"following_topic.message": "ستستلم تنبيها عند كل مشاركة جديدة في هذا الموضوع.",
@@ -105,22 +89,18 @@
"post_delete_confirm": "هل أنت متأكد أنك تريد حذف هذه المشاركة؟",
"post_restore_confirm": "هل أنت متأكد أنك تريد استعادة هذه المشاركة؟",
"post_purge_confirm": "هل أنت متأكد أنك تريد تطهير هذه المشاركة؟",
"pin-modal-expiry": "Expiration Date",
"pin-modal-help": "You can optionally set an expiration date for the pinned topic(s) here. Alternatively, you can leave this field blank to have the topic stay pinned until it is manually unpinned.",
"load_categories": "تحميل الفئات",
"confirm_move": "انقل",
"confirm_fork": "فرع",
"bookmark": "Bookmark",
"bookmarks": "Bookmarks",
"bookmarks.has_no_bookmarks": "You haven't bookmarked any posts yet.",
"copy-permalink": "Copy Permalink",
"loading_more_posts": "تحميل المزيد من المشاركات",
"move_topic": "نقل الموضوع",
"move_topics": "نقل المواضيع",
"move_post": "نقل المشاركة",
"post_moved": "تم نقل المشاركة",
"fork_topic": "فرع الموضوع",
"enter-new-topic-title": "Enter new topic title",
"fork_topic_instruction": "إضغط على المشاركات التي تريد تفريعها",
"fork_no_pids": "لم تختر أي مشاركة",
"no-posts-selected": "No posts selected!",
@@ -134,18 +114,14 @@
"merge-options": "Merge options",
"merge-select-main-topic": "Select the main topic",
"merge-new-title-for-topic": "New title for topic",
"topic-id": "Topic ID",
"move_posts_instruction": "Click the posts you want to move then enter a topic ID or go to the target topic",
"move_posts_instruction": "Click the posts you want to move then go to target topic and click move.",
"change_owner_instruction": "Click the posts you want to assign to another user",
"composer.title_placeholder": "أدخل عنوان موضوعك هنا...",
"composer.handle_placeholder": "Enter your name/handle here",
"composer.discard": "نبذ التغييرات",
"composer.submit": "حفظ",
"composer.additional-options": "Additional Options",
"composer.schedule": "Schedule",
"composer.replying_to": "الرد على %1",
"composer.new_topic": "موضوع جديد",
"composer.editing": "Editing",
"composer.uploading": "جاري الرفع",
"composer.thumb_url_label": "ألصق رابط الصورة المصغرة للموضوع",
"composer.thumb_title": "إضافة صورة مصغرة للموضوع",
@@ -162,7 +138,6 @@
"newest_to_oldest": "من الأحدث إلى الأقدم",
"most_votes": "Most Votes",
"most_posts": "Most Posts",
"most_views": "Most Views",
"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": "موضوع جديد",
@@ -174,15 +149,8 @@
"diffs.current-revision": "current revision",
"diffs.original-revision": "original revision",
"diffs.restore": "Restore this revision",
"diffs.restore-description": "A new revision will be appended to this post's edit history after restoring.",
"diffs.restore-description": "A new revision will be appended to this post's edit history.",
"diffs.post-restored": "Post successfully restored to earlier revision",
"diffs.delete": "Delete this revision",
"diffs.deleted": "Revision deleted",
"timeago_later": "%1 later",
"timeago_earlier": "%1 earlier",
"first-post": "First post",
"last-post": "Last post",
"go-to-my-next-post": "Go to my next post",
"no-more-next-post": "You don't have more posts in this topic",
"post-quick-reply": "Post quick reply"
"timeago_earlier": "%1 earlier"
}

View File

@@ -1,6 +1,5 @@
{
"banned": "محظور",
"muted": "Muted",
"offline": "غير متصل",
"deleted": "محذوف",
"username": "إسم المستخدم",
@@ -13,8 +12,6 @@
"ban_account": "حظر الحساب",
"ban_account_confirm": "هل تريد حقاً حظر هاذا العضو؟",
"unban_account": "إزالة حظر الحساب",
"mute_account": "Mute Account",
"unmute_account": "Unmute Account",
"delete_account": "حذف الحساب",
"delete_account_as_admin": "Delete <strong>Account</strong>",
"delete_content": "Delete Account <strong>Content</strong>",
@@ -87,7 +84,6 @@
"remove_cover_picture_confirm": "هل تريد بالتأكيد إزالة صورة الغلاف؟",
"crop_picture": "إقتصاص الصورة",
"upload_cropped_picture": "إقتصاص ورفع",
"avatar-background-colour": "Avatar background colour",
"settings": "خيارات",
"show_email": "أظهر بريدي الإلكتروني",
"show_fullname": "أظهر اسمي الكامل",
@@ -97,18 +93,16 @@
"digest_off": "غير مفعل",
"digest_daily": "يوميا",
"digest_weekly": "أسبوعيًّا",
"digest_biweekly": "Bi-Weekly",
"digest_monthly": "شهريًّا",
"has_no_follower": "هذا المستخدم ليس لديه أية متابعين :(",
"follows_no_one": "هذا المستخدم لا يتابع أحد :(",
"has_no_posts": "هذا المستخدم لم يشارك حتى الآن.",
"has_no_best_posts": "This user does not have any upvoted posts yet.",
"has_no_topics": "هذا المستخدم لم يكتب أي موضوع حتى الآن.",
"has_no_watched_topics": "هذا المستخدم لم يقم بمراقبة اية مواضيع حتى الآن.",
"has_no_ignored_topics": "هذا المستخدم لم يقم بتجاهل اية مواضيع حتى الآن.",
"has_no_upvoted_posts": "هذا المستخدم لم يقم بالتصويت للأعلى لأي مشاركة حتى الآن.",
"has_no_downvoted_posts": "هذا المستخدم لم يقم بالتصويت للأسفل لأي مشاركة حتى الآن.",
"has_no_controversial_posts": "This user does not have any downvoted posts yet.",
"has_no_voted_posts": "هذا المستخدم لا يمتلك اية مشاركات تم التصويت عليها",
"has_no_blocks": "You have blocked no users.",
"email_hidden": "البريد الإلكتروني مخفي",
"hidden": "مخفي",
@@ -141,7 +135,7 @@
"homepage": "الصفحة الرئيسية",
"homepage_description": "حدد صفحة لاستخدامها كصفحة رئيسية للمنتدى أو \"لا شيء\" لاستخدام الصفحة الرئيسية الافتراضية.",
"custom_route": "مسار الصفحة الرئيسية المخصصة",
"custom_route_help": "Enter a route name here, without any preceding slash (e.g. \"recent\" or \"category/2/general-discussion\")",
"custom_route_help": "أدخل اسم مسار هنا، بدون أي شرطة مائلة (على سبيل المثال \"حديثة\" أو \"شائعة\")",
"sso.title": "خدمات تسجيل الدخول الموحد",
"sso.associated": "مرتبط مع",
"sso.not-associated": "انقر هنا لربط مع",
@@ -157,11 +151,6 @@
"info.banned-permanently": "محظور بشكل دائم",
"info.banned-reason-label": "سبب",
"info.banned-no-reason": "لم يتم إعطاء سبب.",
"info.mute-history": "Recent Mute History",
"info.no-mute-history": "This user has never been muted",
"info.muted-until": "Muted until %1",
"info.muted-expiry": "Expiry",
"info.muted-no-reason": "No reason given.",
"info.username-history": "سجل اسم المستخدم",
"info.email-history": "سجل البريد الإلكتروني",
"info.moderation-note": "ملاحظة الإشراف",
@@ -190,10 +179,5 @@
"consent.export_uploads": "Export Uploaded Content (.zip)",
"consent.export-uploads-success": "Exporting uploads, you will get a notification when it is complete.",
"consent.export_posts": "Export Posts (.csv)",
"consent.export-posts-success": "Exporting posts, you will get a notification when it is complete.",
"emailUpdate.intro": "Please enter your email address below. This forum uses your email address for scheduled digest and notifications, as well as for account recovery in the event of a lost password.",
"emailUpdate.optional": "<strong>This field is optional</strong>. You are not obligated to provide your email address, but without a validated email you will not be able to recover your account or login with your email.",
"emailUpdate.required": "<strong>This field is required</strong>.",
"emailUpdate.change-instructions": "A confirmation email will be sent to the entered email address with a unique link. Accessing that link will confirm your ownership of the email address and it will become active on your account. At any time, you are able to update your email on file from within your account page.",
"emailUpdate.password-challenge": "Please enter your password in order to verify account ownership."
"consent.export-posts-success": "Exporting posts, you will get a notification when it is complete."
}

View File

@@ -5,7 +5,6 @@
"most_flags": "Most Flags",
"search": "بحث",
"enter_username": "أدخل اسم مستخدم للبحث",
"search-user-for-chat": "ابحث عن مستخدم لبدء محادثة ",
"load_more": "حمل المزيد",
"users-found-search-took": "تم إيجاد %1 مستخدمـ(ين)! استغرق البحث %2 ثانية.",
"filter-by": "Filter By",

View File

@@ -1,3 +0,0 @@
# The files here are not meant to be edited directly
Please see the &rarr; [Internalization README](../README.md).

View File

@@ -3,9 +3,5 @@
"alert.confirm-restart": "Наистина ли искате да рестартирате NodeBB?",
"acp-title": "%1 | Контролен панел за администратори на NodeBB",
"settings-header-contents": "Съдържание",
"changes-saved": "Промените са запазени",
"changes-saved-message": "Промените Ви в настройките на NodeBB бяха запазени.",
"changes-not-saved": "Промените не са запазени",
"changes-not-saved-message": "Възникна проблем при запазването на промените Ви по NodeBB. (%1)"
"settings-header-contents": "Съдържание"
}

View File

@@ -3,7 +3,6 @@
"no-events": "Няма събития",
"control-panel": "Контролен панел за събитията",
"delete-events": "Изтриване на събитията",
"confirm-delete-all-events": "Наистина ли искате да изтриете всички събития в журнала?",
"filters": "Филтри",
"filters-apply": "Прилагане на филтрите",
"filter-type": "Вид събитие",

View File

@@ -2,7 +2,6 @@
"forum-traffic": "Трафик на форума",
"page-views": "Преглеждания на страниците",
"unique-visitors": "Уникални посетители",
"logins": "Вписвания",
"new-users": "Нови потребители",
"posts": "Публикации",
"topics": "Теми",
@@ -30,7 +29,6 @@
"upgrade-available": "<p>Има нова версия (версия %1). Ако имате възможност, <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">обновете NodeBB</a>.</p>",
"prerelease-upgrade-available": "<p>Това е остаряла предварителна версия на NodeBB. Има нова версия (версия %1). Ако имате възможност, <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">обновете NodeBB</a>.</p>",
"prerelease-warning": "<p>Това е версия за <strong>предварителен преглед</strong> на NodeBB. Възможно е да има неочаквани неизправности. <i class=\"fa fa-exclamation-triangle\"></i></p>",
"fallback-emailer-not-found": "Не е намерен резервен изпращач на е-поща",
"running-in-development": "<span>Форумът работи в режим за разработчици, така че може да бъде уязвим. Моля, свържете се със системния си администратор.</span>",
"latest-lookup-failed": "<p>Не може да бъде извършена проверка за последната налична версия на NodeBB</p>",
@@ -56,8 +54,8 @@
"active-users.total": "Общо",
"active-users.connections": "Връзки",
"guest-registered-users": "Гости към регистрирани потребители",
"guest": "Гост",
"anonymous-registered-users": "Анонимни към регистрирани потребители",
"anonymous": "Анонимни",
"registered": "Регистрирани",
"user-presence": "Присъствие на потребителите ",
@@ -68,7 +66,6 @@
"unread": "Непрочетени",
"high-presence-topics": "Теми с най-голяма присъственост",
"popular-searches": "Популярни търсения",
"graphs.page-views": "Преглеждания на страниците",
"graphs.page-views-registered": "Преглеждания на страниците от регистрирани потребители",
@@ -76,15 +73,7 @@
"graphs.page-views-bot": "Преглеждания на страниците от ботове",
"graphs.unique-visitors": "Уникални посетители",
"graphs.registered-users": "Регистрирани потребители",
"graphs.guest-users": "Гости",
"graphs.anonymous-users": "Анонимни потребители",
"last-restarted-by": "Последно рестартиране от",
"no-users-browsing": "Няма разглеждащи потребители",
"back-to-dashboard": "Назад към таблото",
"details.no-users": "В избрания период не са се регистрирали нови потребители",
"details.no-topics": "В избрания период не са публикувани нови теми",
"details.no-searches": "Все още не са правени търсения",
"details.no-logins": "В избрания период не са отчетени вписвания",
"details.logins-static": "NodeBB запазва данни за сесията в продължение на %1 дни, така че в следната таблица могат да се видят само последните активни сесии",
"details.logins-login-time": "Време на вписване"
"no-users-browsing": "Няма разглеждащи потребители"
}

View File

@@ -8,11 +8,7 @@
"nodejs": "nodejs",
"online": "на линия",
"git": "git",
"process-memory": "памет на процеса",
"system-memory": "системна памет",
"used-memory-process": "Използвана памет от процеса",
"used-memory-os": "Използвана системна памет",
"total-memory-os": "Обща системна памет",
"memory": "памет",
"load": "натоварване на системата",
"cpu-usage": "използване на процесора",
"uptime": "активно време",

View File

@@ -39,7 +39,7 @@
"alert.upgraded": "Добавката е обновена",
"alert.installed": "Добавката е инсталирана",
"alert.uninstalled": "Добавката е деинсталирана",
"alert.activate-success": "Моля, изградете повторно и презаредете NodeBB, за да активирате напълно тази добавка.",
"alert.activate-success": "Моля, рестартирайте NodeBB, за да включите тази добавка напълно.",
"alert.deactivate-success": "Добавката е изключена успешно.",
"alert.upgrade-success": "Моля, изградете повторно и презаредете NodeBB, за да обновите тази добавка напълно.",
"alert.install-success": "Добавката е инсталирана успешно, моля, включете я",

View File

@@ -8,6 +8,8 @@
"delete": "Изтриване",
"enable": "Включване",
"disable": "Изключване",
"control-panel": "Управление на наградите",
"new-reward": "Нова награда",
"alert.delete-success": "Наградата е изтрита успешно",
"alert.no-inputs-found": "Неправомерна награда — няма нищо въведено!",

View File

@@ -0,0 +1,79 @@
{
"forum-traffic": "Трафик на форума",
"page-views": "Преглеждания на страниците",
"unique-visitors": "Уникални посетители",
"new-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>ГГГГ-ММ-ДД</code>",
"page-views-custom-error": "Моля, въведете правилен интервал от дати във формата: <code>ГГГГ-ММ-ДД</code>",
"stats.yesterday": "Вчера",
"stats.today": "Днес",
"stats.last-week": "Миналата седмица",
"stats.this-week": "Тази седмица",
"stats.last-month": "Миналия месец",
"stats.this-month": "Този месец",
"stats.all": "От началото",
"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>Има нова версия (версия %1). Ако имате възможност, <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">обновете NodeBB</a>.</p>",
"prerelease-upgrade-available": "<p>Това е остаряла предварителна версия на NodeBB. Има нова версия (версия %1). Ако имате възможност, <a href=\"https://docs.nodebb.org/configuring/upgrade/\" target=\"_blank\">обновете NodeBB</a>.</p>",
"prerelease-warning": "<p>Това е версия за <strong>предварителен преглед</strong> на NodeBB. Възможно е да има неочаквани неизправности. <i class=\"fa fa-exclamation-triangle\"></i></p>",
"running-in-development": "<span>Форумът работи в режим за разработчици, така че може да бъде уязвим. Моля, свържете се със системния си администратор.</span>",
"latest-lookup-failed": "<p>Не може да бъде извършена проверка за последната налична версия на NodeBB</p>",
"notices": "Забележки",
"restart-not-required": "Не се изисква рестартиране",
"restart-required": "Изисква се рестартиране",
"search-plugin-installed": "Добавката за търсене е инсталирана",
"search-plugin-not-installed": "Добавката за търсене не е инсталирана",
"search-plugin-tooltip": "Инсталирайте добавка за търсене от страницата с добавките, за да включите функционалността за търсене",
"control-panel": "Системен контрол",
"rebuild-and-restart": "Повторно изграждане и рестартиране",
"restart": "Рестартиране",
"restart-warning": "Повторното изграждане и рестартирането на NodeBB ще прекъснат всички връзки за няколко секунди.",
"restart-disabled": "Възможностите за повторно изграждане и рестартиране на NodeBB са изключени, тъй като изглежда, че NodeBB не се изпълнява чрез подходящия демон.",
"maintenance-mode": "Режим на профилактика",
"maintenance-mode-title": "Щракнете тук, за да зададете режим на профилактика на NodeBB",
"realtime-chart-updates": "Актуализации на таблиците в реално време",
"active-users": "Дейни потребители",
"active-users.users": "Потребители",
"active-users.guests": "Гости",
"active-users.total": "Общо",
"active-users.connections": "Връзки",
"anonymous-registered-users": "Анонимни към регистрирани потребители",
"anonymous": "Анонимни",
"registered": "Регистрирани",
"user-presence": "Присъствие на потребителите ",
"on-categories": "В списъка с категории",
"reading-posts": "Четящи публикации",
"browsing-topics": "Разглеждащи теми",
"recent": "Скорошни",
"unread": "Непрочетени",
"high-presence-topics": "Теми с най-голяма присъственост",
"graphs.page-views": "Преглеждания на страниците",
"graphs.page-views-registered": "Преглеждания на страниците от регистрирани потребители",
"graphs.page-views-guest": "Преглеждания на страниците от гости",
"graphs.page-views-bot": "Преглеждания на страниците от ботове",
"graphs.unique-visitors": "Уникални посетители",
"graphs.registered-users": "Регистрирани потребители",
"graphs.anonymous-users": "Анонимни потребители",
"last-restarted-by": "Последно рестартиране от",
"no-users-browsing": "Няма разглеждащи потребители"
}

View File

@@ -0,0 +1,8 @@
{
"home-page": "Начална страница",
"description": "Изберете коя страница да бъде показана, когато потребителите отидат на главния адрес на форума.",
"home-page-route": "Път на началната страница",
"custom-route": "Персонализиран път",
"allow-user-home-pages": "Разрешаване на потребителските начални страници",
"home-page-title": "Заглавие на началната страница (по подразбиране: „Начало“)"
}

View File

@@ -0,0 +1,6 @@
{
"language-settings": "Езикови настройки",
"description": "Езикът по подразбиране определя езиковите настройки за всички потребители, които посещават Вашия форум. <br />Отделните потребители могат да сменят езика си от страницата с настройки на профила си.",
"default-language": "Език по подразбиране",
"auto-detect": "Автоматично разпознаване на езика за гостите"
}

View File

@@ -0,0 +1,23 @@
{
"icon": "Иконка:",
"change-icon": "промяна",
"route": "Маршрут:",
"tooltip": "Подсказка:",
"text": "Текст:",
"text-class": "Текстов клас: <small>незадължително</small>",
"class": "Клас: <small>незадължително</small>",
"id": "Идентификатор: <small>незадължително</small>",
"properties": "Свойства:",
"groups": "Групи:",
"open-new-window": "Отваряне в нов прозорец",
"btn.delete": "Изтриване",
"btn.disable": "Изключване",
"btn.enable": "Включване",
"available-menu-items": "Налични елементи за менюто",
"custom-route": "Персонализиран маршрут",
"core": "ядро",
"plugin": "добавка"
}

View File

@@ -0,0 +1,5 @@
{
"post-sharing": "Споделяне на публикации",
"info-plugins-additional": "Добавките могат да добавят допълнителни мрежи за споделяне на публикации.",
"save-success": "Мрежите за споделяне на публикации са запазени успешно!"
}

View File

@@ -0,0 +1,9 @@
{
"notifications": "Известия",
"chat-messages": "Съобщения в разговори",
"play-sound": "Пускане",
"incoming-message": "Входящо съобщение",
"outgoing-message": "Изходящо съобщение",
"upload-new-sound": "Качване на нов звук",
"saved": "Настройките са запазени"
}

View File

@@ -1,10 +1,8 @@
{
"administrators": "Администратори",
"global-moderators": "Глобални модератори",
"moderators": "Модератори",
"no-global-moderators": "Няма глобални модератори",
"no-sub-categories": "Няма подкатегории",
"subcategories": "%1 подкатегории",
"moderators-of-category": "%1 модератори",
"no-moderators": "Няма модератори",
"add-administrator": "Добавяне на администратор",
"add-global-moderator": "Добавяне на глобален модератор",

View File

@@ -10,16 +10,13 @@
"custom-class": "Персонализиран клас",
"num-recent-replies": "Брой на скорошните отговори",
"ext-link": "Външна връзка",
"subcategories-per-page": "Брой подкатегории на страница",
"is-section": "Използване на тази категория като раздел",
"post-queue": "Опашка за публикации",
"tag-whitelist": "Списък от разрешени етикети",
"upload-image": "Качване на изображение",
"delete-image": "Премахване",
"category-image": "Изображение на категорията",
"parent-category": "Базова категория",
"optional-parent-category": "(Незадължително) Базова категория",
"top-level": "Най-горно ниво",
"parent-category-none": "(Няма)",
"copy-parent": "Копиране на базовата",
"copy-settings": "Копиране на настройките от",
@@ -32,8 +29,6 @@
"edit": "Редактиране",
"analytics": "Анализи",
"view-category": "Преглед на категорията",
"set-order": "Запазване на реда",
"set-order-help": "Задаването на позиция за категорията ще я премести на желаното място и ще промени местата на другите категории, ако е необходимо. Най-малкият възможен номер е 1, което ще постави категорията най-отгоре.",
"select-category": "Изберете категория",
"set-parent-category": "Задайте базова категория",
@@ -50,8 +45,6 @@
"privileges.no-users": "В тази категория няма правомощия за отделни потребители.",
"privileges.section-group": "Група",
"privileges.group-private": "Тази група е частна",
"privileges.inheritance-exception": "Тази група не наследява правомощията от групата на регистрираните потребители",
"privileges.banned-user-inheritance": "Блокираните потребители наследяват правомощията от групата на блокираните потребители",
"privileges.search-group": "Добавяне на група",
"privileges.copy-to-children": "Копиране в наследниците",
"privileges.copy-from-category": "Копиране от категория",

View File

@@ -13,7 +13,6 @@
"resent-single": "Ръчното повторно разпращане на резюмето е завършено",
"resent-day": "Дневното резюме беше изпратено повторно",
"resent-week": "Седмичното резюме беше изпратено повторно",
"resent-biweek": "Двуседмичното резюме беше изпратено повторно",
"resent-month": "Месечното резюме беше изпратено повторно",
"null": "<em>Никога</em>",
"manual-run": "Ръчно разпращане на резюмето:",

View File

@@ -4,13 +4,11 @@
"group-privileges": "Правомощия за групите",
"user-privileges": "Правомощия за потребителите",
"edit-privileges": "Редактиране на правомощията",
"select-clear-all": "Избиране/изчистване на всичко",
"chat": "Разговор",
"upload-images": "Качване на изображения",
"upload-files": "Качване на файлове",
"signature": "Подпис",
"ban": "Блокиране",
"mute": "Заглушаване",
"invite": "Пращане на покана",
"search-content": "Търсене на съдържание",
"search-users": "Търсене на потребители",
@@ -26,7 +24,6 @@
"access-topics": "Достъп до теми",
"create-topics": "Създаване на теми",
"reply-to-topics": "Отговаряне в теми",
"schedule-topics": "Насрочване на теми",
"tag-topics": "Поставяне на етикети на теми",
"edit-posts": "Редактиране на публикации",
"view-edit-history": "Преглед на историята на редакциите",
@@ -41,24 +38,17 @@
"admin-categories": "Категории",
"admin-privileges": "Правомощия",
"admin-users": "Потребители",
"admin-admins-mods": "Администратори и модератори",
"admin-groups": "Групи",
"admin-tags": "Етикети",
"admin-settings": "Настройки",
"alert.confirm-moderate": "<strong>Наистина ли искате да дадете правомощието за модериране на тази потребителска група?</strong> Тази група е публична и всеки може свободно да се присъедини към нея.",
"alert.confirm-admins-mods": "<strong>Наистина ли искате да дадете правото „Администратори и модератори“ на този потребител/група?</strong> Потребителите с това право могат да променят правомощията на други групи, <em>включително да им дават правото на супер администратори</em>",
"alert.confirm-save": "Моля, потвърдете желанието си да запазите тези правомощия",
"alert.saved": "Промените по правомощията са запазени и приложени",
"alert.confirm-discard": "Наистина ли искате да отхвърлите промените по правомощията?",
"alert.discarded": "Промените по правомощията са отхвърлени",
"alert.confirm-copyToAll": "Наистина ли искате да приложите този набор от <strong>%1</strong> към <strong>всички категории</strong>?",
"alert.confirm-copyToAllGroup": "Наистина ли искате да приложите набора от <strong>%1</strong> на тази група към <strong>всички категории</strong>?",
"alert.confirm-copyToChildren": "Наистина ли искате да приложите този набор от <strong>%1</strong> към <strong>всички по-долни (дъщерни) категории</strong>?",
"alert.confirm-copyToChildrenGroup": "Наистина ли искате да приложите набора от <strong>%1</strong> на тази група към <strong>всички по-долни (дъщерни) категории</strong>?",
"alert.confirm-copyToAll": "Наистина ли искате да приложите този набор от правомощия към <strong>всички категории</strong>?",
"alert.confirm-copyToAllGroup": "Наистина ли искате да приложите набора от правомощия на таи група към <strong>всички категории</strong>?",
"alert.confirm-copyToChildren": "Наистина ли искате да приложите този набор от правомощия към <strong>всички по-долни (дъщерни) категории</strong>?",
"alert.confirm-copyToChildrenGroup": "Наистина ли искате да приложите набора от правомощия на таи група към <strong>всички по-долни (дъщерни) категории</strong>?",
"alert.no-undo": "<em>Това действие е необратимо.</em>",
"alert.admin-warning": "Администраторите имат всички правомощия по подразбиране",
"alert.copyPrivilegesFrom-title": "Изберете категория, от която да се копира",
"alert.copyPrivilegesFrom-warning": "Това ще копира <strong>%1</strong> от избраната категория.",
"alert.copyPrivilegesFromGroup-warning": "Това ще копира набора от <strong>%1</strong> на тези група от избраната категория."
"alert.admin-warning": "Администраторите имат всички правомощия по подразбиране"
}

Some files were not shown because too many files have changed in this diff Show More