mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-24 17:30:39 +01:00
Compare commits
658 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb2f857af2 | ||
|
|
7181bb4e1a | ||
|
|
de81a340ec | ||
|
|
73d934f5ae | ||
|
|
9e3d8a8090 | ||
|
|
27a76fcfc9 | ||
|
|
b33d25b0b8 | ||
|
|
bda3c2863b | ||
|
|
c14160a85b | ||
|
|
2827db3309 | ||
|
|
20eac0de94 | ||
|
|
6d7c70c911 | ||
|
|
fdee61b4f4 | ||
|
|
cf6c4667c8 | ||
|
|
65a65b19c0 | ||
|
|
185b6e5c8e | ||
|
|
9f8d80e3a4 | ||
|
|
678db343b4 | ||
|
|
37c4218184 | ||
|
|
6e5a79842f | ||
|
|
baa2a59f4c | ||
|
|
98047be9ce | ||
|
|
e382bca610 | ||
|
|
0e615e7b09 | ||
|
|
0fe10f5e86 | ||
|
|
ecfca21abe | ||
|
|
9670d7d762 | ||
|
|
2319af2904 | ||
|
|
c2ba1c270f | ||
|
|
1179dd9503 | ||
|
|
b1ee7cc5b4 | ||
|
|
1fb48ef7a7 | ||
|
|
c3febca9c8 | ||
|
|
a8add6477c | ||
|
|
a62a4e698f | ||
|
|
a117b559b8 | ||
|
|
980e9026f3 | ||
|
|
e9fb42eb03 | ||
|
|
f16a40d29e | ||
|
|
75d291183d | ||
|
|
9368e666d8 | ||
|
|
73b6b06294 | ||
|
|
08f001063c | ||
|
|
010473e5cc | ||
|
|
dc4f2be156 | ||
|
|
126237e2c9 | ||
|
|
1892492505 | ||
|
|
1ed571189c | ||
|
|
b53d3254dd | ||
|
|
2c418fd2af | ||
|
|
0ef30e91ba | ||
|
|
17ff8a4151 | ||
|
|
12a426b7b9 | ||
|
|
d4de345e87 | ||
|
|
4c89497cc4 | ||
|
|
da183e196a | ||
|
|
0fac75c055 | ||
|
|
07b9bb6fb8 | ||
|
|
5985a8a7a3 | ||
|
|
43f8678c7a | ||
|
|
8afdd71ef1 | ||
|
|
1deeaaeb39 | ||
|
|
bb0ec540bd | ||
|
|
60990f28ad | ||
|
|
8119b8c4ae | ||
|
|
03d432182b | ||
|
|
53dac97800 | ||
|
|
d88219b4d1 | ||
|
|
0bea922a12 | ||
|
|
60d35fdf05 | ||
|
|
2feb19aa2d | ||
|
|
b287c75e3c | ||
|
|
81696dd24a | ||
|
|
8a8bd23de9 | ||
|
|
57696b22f4 | ||
|
|
a450cb869d | ||
|
|
e9794224a8 | ||
|
|
5fbbe898d0 | ||
|
|
1594a84e1c | ||
|
|
a63459dc98 | ||
|
|
8d4a32dc27 | ||
|
|
15506c30a4 | ||
|
|
3876a88252 | ||
|
|
ff09d6e0dd | ||
|
|
c1c96668af | ||
|
|
6b0a907ede | ||
|
|
2a2ed96a07 | ||
|
|
42dc496572 | ||
|
|
114f87e78c | ||
|
|
14ed0be4f7 | ||
|
|
a1f87a5d7f | ||
|
|
a49e647de3 | ||
|
|
31b6d47f88 | ||
|
|
c84e54c6c6 | ||
|
|
a7677063de | ||
|
|
642306e69c | ||
|
|
3319a72679 | ||
|
|
6060b8e13b | ||
|
|
6682e048ea | ||
|
|
b6134b160e | ||
|
|
db84296373 | ||
|
|
9714e3c26b | ||
|
|
7f713ee822 | ||
|
|
da1858f674 | ||
|
|
d19e59f1e1 | ||
|
|
f5e8a40d79 | ||
|
|
449352d899 | ||
|
|
2ef71e22aa | ||
|
|
8f8babf90b | ||
|
|
23d4497c73 | ||
|
|
8c45411ccc | ||
|
|
33bf930bb9 | ||
|
|
8d7283e6c7 | ||
|
|
ff4c7ab3bb | ||
|
|
6a4b082080 | ||
|
|
6d444ccacf | ||
|
|
2106050bdc | ||
|
|
c199075d98 | ||
|
|
8a6665a26c | ||
|
|
4a33f45b1e | ||
|
|
0396e9300b | ||
|
|
90b8a3afd0 | ||
|
|
9f1a2b0cc9 | ||
|
|
0478e9c98c | ||
|
|
37be43a3c5 | ||
|
|
27b030a71c | ||
|
|
3e93975595 | ||
|
|
9dc54f801e | ||
|
|
286d0ab203 | ||
|
|
5ca9e5e14c | ||
|
|
62f445ad7f | ||
|
|
bb146e049c | ||
|
|
debe34b96c | ||
|
|
3b41c40b93 | ||
|
|
447b7b02ca | ||
|
|
f2eb4b8083 | ||
|
|
5aa45e9181 | ||
|
|
b3f8428691 | ||
|
|
dc4d394cd5 | ||
|
|
5e0de4b8fb | ||
|
|
8da8e4d8c3 | ||
|
|
fd8e647ef5 | ||
|
|
0c7dee05ef | ||
|
|
92fa9fecb6 | ||
|
|
0c8058ba9d | ||
|
|
4713e0d81a | ||
|
|
1c1d97dd54 | ||
|
|
74d2835a1f | ||
|
|
3d719eec99 | ||
|
|
8d493bf3b0 | ||
|
|
c619b850ce | ||
|
|
57691d9ad8 | ||
|
|
562b088423 | ||
|
|
9f2e5e9c4b | ||
|
|
364b819a42 | ||
|
|
fdb4766728 | ||
|
|
5359a14bac | ||
|
|
92ad6bb4e8 | ||
|
|
1102ca8ebb | ||
|
|
8a123f7c1c | ||
|
|
b7e6104bbc | ||
|
|
69c6ee5834 | ||
|
|
992e3128bd | ||
|
|
f732d6c1b9 | ||
|
|
33e474759b | ||
|
|
6420e22453 | ||
|
|
fcda832052 | ||
|
|
0f9530bbc0 | ||
|
|
f1b4a9b786 | ||
|
|
186c1f40e9 | ||
|
|
710377ceea | ||
|
|
603d45fbfa | ||
|
|
13edde2b30 | ||
|
|
8226fd6566 | ||
|
|
743a7e00b4 | ||
|
|
f6721c249f | ||
|
|
531df7bd09 | ||
|
|
4082ca40c1 | ||
|
|
0710c6488d | ||
|
|
eca150f392 | ||
|
|
431f5e1f0f | ||
|
|
f761191fca | ||
|
|
c517733e34 | ||
|
|
e85e35cf0c | ||
|
|
99dff11462 | ||
|
|
ab9f4ad636 | ||
|
|
324e5be7bd | ||
|
|
a3b4c83e8b | ||
|
|
ea871384d8 | ||
|
|
3b8d14bf12 | ||
|
|
54c951cc81 | ||
|
|
4369a6d290 | ||
|
|
bce1208e2f | ||
|
|
63b3c29a1a | ||
|
|
cd448f90cd | ||
|
|
202bafa3e3 | ||
|
|
5ca8456340 | ||
|
|
d60930a51d | ||
|
|
b060bda8a0 | ||
|
|
65cf7a01ec | ||
|
|
b1b87d339f | ||
|
|
bc8d297377 | ||
|
|
284485c885 | ||
|
|
2188036148 | ||
|
|
566ff95d3c | ||
|
|
3e396a8553 | ||
|
|
1bee91fa22 | ||
|
|
2ccf60a6ec | ||
|
|
b85dcb2570 | ||
|
|
5411b4c234 | ||
|
|
fecdbc969f | ||
|
|
c5f40e3cf5 | ||
|
|
6222b55dd8 | ||
|
|
ac84e447dc | ||
|
|
b96b983552 | ||
|
|
2e47cf4db3 | ||
|
|
8a0cf6c0ac | ||
|
|
bb1045c5a0 | ||
|
|
ef93ef3dd4 | ||
|
|
feb359f7d4 | ||
|
|
8166f30b90 | ||
|
|
039f80c5aa | ||
|
|
4d8bebcd81 | ||
|
|
da3cb0492c | ||
|
|
2bbf3c4f66 | ||
|
|
20d250bceb | ||
|
|
0213ca4bb1 | ||
|
|
007051c14c | ||
|
|
0e7740af32 | ||
|
|
347761173a | ||
|
|
a22909dbe8 | ||
|
|
6aa8c8aa94 | ||
|
|
fa08498a9e | ||
|
|
2a311d2ff6 | ||
|
|
09a1ed0869 | ||
|
|
00a67b97ce | ||
|
|
995f8296a4 | ||
|
|
b5f8fc815e | ||
|
|
e71bd7a27f | ||
|
|
92691782e6 | ||
|
|
fe582d8a7b | ||
|
|
048eb8a320 | ||
|
|
04b07e292c | ||
|
|
ca1fe557c7 | ||
|
|
3a87f2566a | ||
|
|
b7d5bc7dc8 | ||
|
|
3509e12748 | ||
|
|
f7a964474d | ||
|
|
dd2b930824 | ||
|
|
ee9d7584e4 | ||
|
|
cfc8884c9c | ||
|
|
8b533bb431 | ||
|
|
4163ce0218 | ||
|
|
1d5b3cc73f | ||
|
|
35ff71c37d | ||
|
|
14398a2d90 | ||
|
|
b4a32ee96f | ||
|
|
743f758f75 | ||
|
|
25f6293821 | ||
|
|
91d3ce1abc | ||
|
|
c168ed43d4 | ||
|
|
7b7565ee8e | ||
|
|
c1b1ff5c6e | ||
|
|
9079ee5b14 | ||
|
|
458cbfd603 | ||
|
|
a2847dc851 | ||
|
|
d4c2fc3bc8 | ||
|
|
ebe5ed7560 | ||
|
|
0de21cb3ff | ||
|
|
09d0ce4778 | ||
|
|
4cd4414d19 | ||
|
|
026c32f32b | ||
|
|
02cc988ae7 | ||
|
|
aea40902b0 | ||
|
|
f09f1f6ed8 | ||
|
|
dcb0f18422 | ||
|
|
e887dda37a | ||
|
|
2dac3d2292 | ||
|
|
5c01c7b1c7 | ||
|
|
e427f1663e | ||
|
|
89380824f8 | ||
|
|
f2a795a9b7 | ||
|
|
799f688503 | ||
|
|
4b21679d6f | ||
|
|
4ee7edad64 | ||
|
|
ef90702049 | ||
|
|
7d8477289d | ||
|
|
beb652ee43 | ||
|
|
3e562ceb83 | ||
|
|
aaec279d75 | ||
|
|
f302c0d739 | ||
|
|
631592b818 | ||
|
|
2e27ce640c | ||
|
|
9b1068e868 | ||
|
|
fd0f0beaf2 | ||
|
|
a99572fc48 | ||
|
|
23540afaeb | ||
|
|
b227297ef3 | ||
|
|
93f38d4f30 | ||
|
|
1b43faba1a | ||
|
|
4bb49a7171 | ||
|
|
c18808fdeb | ||
|
|
fdf4f873bf | ||
|
|
144fa8698c | ||
|
|
57f89663aa | ||
|
|
09e868ce5f | ||
|
|
11cb3a9554 | ||
|
|
a0a50677da | ||
|
|
04bb6513b0 | ||
|
|
5a45087fc8 | ||
|
|
32dc7c23ea | ||
|
|
c4bdb72941 | ||
|
|
64a6322002 | ||
|
|
239d7f84dd | ||
|
|
daa169c094 | ||
|
|
ac2f69f7af | ||
|
|
896c8c7343 | ||
|
|
7842c3411c | ||
|
|
b33d34f7cf | ||
|
|
23ed1af282 | ||
|
|
1493afee2a | ||
|
|
3b0dd2d1ef | ||
|
|
feb8405f95 | ||
|
|
41896e1fc7 | ||
|
|
f3a8256f35 | ||
|
|
a038c66549 | ||
|
|
604358ecc4 | ||
|
|
a5a3f3089a | ||
|
|
2e031f3759 | ||
|
|
277a7fb8b4 | ||
|
|
34e233fe1d | ||
|
|
532951c24f | ||
|
|
b1b486f729 | ||
|
|
3361a72725 | ||
|
|
d1101a7fb4 | ||
|
|
d7526b5e44 | ||
|
|
554075b312 | ||
|
|
d9c1f6f088 | ||
|
|
1cf25f57fc | ||
|
|
3d6bfa47c5 | ||
|
|
879470f417 | ||
|
|
52f2028206 | ||
|
|
b09b3aef7f | ||
|
|
2ba46808a1 | ||
|
|
bc1d70c126 | ||
|
|
bb3c8b910a | ||
|
|
5ca931a52c | ||
|
|
aacd8a2422 | ||
|
|
7f4e4c8e2e | ||
|
|
4d755bad0c | ||
|
|
8dab8864f6 | ||
|
|
aa64ec7db1 | ||
|
|
9f15008247 | ||
|
|
a379b03e71 | ||
|
|
5ee2aa8adb | ||
|
|
802878c371 | ||
|
|
e009ce5609 | ||
|
|
a427bba9cb | ||
|
|
4d05e492cc | ||
|
|
461ad301a1 | ||
|
|
c75391f9f5 | ||
|
|
2ca8f60e77 | ||
|
|
d784a8dce8 | ||
|
|
43f4d9819e | ||
|
|
484891472e | ||
|
|
3d56dc4857 | ||
|
|
fd88e9fdff | ||
|
|
9b3741bc63 | ||
|
|
dad5b135c3 | ||
|
|
c285eb7fcd | ||
|
|
2c428cdec1 | ||
|
|
8bf719b258 | ||
|
|
9e23d09e5e | ||
|
|
c25836b5fc | ||
|
|
867fd99fb6 | ||
|
|
4d8d23830d | ||
|
|
4bbf517af3 | ||
|
|
9f67142786 | ||
|
|
1e33a659ef | ||
|
|
30f35c42f6 | ||
|
|
a3cbe5e090 | ||
|
|
31ac72375f | ||
|
|
21eefb9760 | ||
|
|
8b006fb1ab | ||
|
|
3dc2a91990 | ||
|
|
5d4a0d7f05 | ||
|
|
c4a2babbf7 | ||
|
|
b553236620 | ||
|
|
21bc1fba3f | ||
|
|
6289f118ae | ||
|
|
9fb16e3520 | ||
|
|
6b2e40a8ce | ||
|
|
97c6da7d3f | ||
|
|
f4a6527ce6 | ||
|
|
503378e259 | ||
|
|
8f27d7810b | ||
|
|
7ba111acdd | ||
|
|
a8fd1440d4 | ||
|
|
a3e327301b | ||
|
|
d61665c20a | ||
|
|
4f5b9f3a42 | ||
|
|
cc160d77e7 | ||
|
|
667582744e | ||
|
|
ab7867d4b5 | ||
|
|
0409109faa | ||
|
|
0fffde67b5 | ||
|
|
aaacdb8413 | ||
|
|
a48c914a16 | ||
|
|
ce2bda0648 | ||
|
|
d5a45832c3 | ||
|
|
d966b52dc7 | ||
|
|
23d92c214d | ||
|
|
107abe3197 | ||
|
|
a122aad54d | ||
|
|
b530701cff | ||
|
|
bb1bfb0449 | ||
|
|
df1a1811f2 | ||
|
|
034f3f0268 | ||
|
|
2c5f8ed8e6 | ||
|
|
dbc3113940 | ||
|
|
b757f563df | ||
|
|
959315c8f7 | ||
|
|
f046ea012d | ||
|
|
b9ae02583e | ||
|
|
5ea5d11646 | ||
|
|
d43564dbbd | ||
|
|
fdad66f58e | ||
|
|
d31499a860 | ||
|
|
44a59ac435 | ||
|
|
9ceeff6f0a | ||
|
|
a3df9132f7 | ||
|
|
a41acead44 | ||
|
|
6a073277ac | ||
|
|
a808d1b4d9 | ||
|
|
a15aaaf389 | ||
|
|
06bf631445 | ||
|
|
76254942b2 | ||
|
|
d4e4b4bfa2 | ||
|
|
e3a2e13438 | ||
|
|
360a35d0a6 | ||
|
|
1012368acd | ||
|
|
5aa3e6b95b | ||
|
|
553567c3b2 | ||
|
|
700e2cf800 | ||
|
|
702561a6ab | ||
|
|
de28ff5d43 | ||
|
|
98f2fd62a5 | ||
|
|
70b20e3ff1 | ||
|
|
a70051b30c | ||
|
|
922620fe0a | ||
|
|
94b9d77118 | ||
|
|
adb66c71b8 | ||
|
|
5de67f9607 | ||
|
|
b08acd197c | ||
|
|
5c217e873e | ||
|
|
ae7f9bac98 | ||
|
|
48b8b6cf95 | ||
|
|
bc3f28e473 | ||
|
|
bf44ca20f2 | ||
|
|
975f2a669d | ||
|
|
51981ffb99 | ||
|
|
409b8d8ebc | ||
|
|
bb7a35b85c | ||
|
|
ff301aeaf7 | ||
|
|
988c71d9c9 | ||
|
|
b230dbaff4 | ||
|
|
bc9fa0a990 | ||
|
|
0aaa320913 | ||
|
|
0c6679ca9c | ||
|
|
b222dd653f | ||
|
|
da295bb5e6 | ||
|
|
3ddfa7715f | ||
|
|
debffe385f | ||
|
|
3ab631c82e | ||
|
|
7c7517d72b | ||
|
|
05c724de30 | ||
|
|
c81c756e57 | ||
|
|
e2b30d6329 | ||
|
|
9d069d76db | ||
|
|
c3f1129fe9 | ||
|
|
29b0552466 | ||
|
|
e3205cf950 | ||
|
|
8deeb0e7c0 | ||
|
|
49735c67e3 | ||
|
|
f4147f7922 | ||
|
|
44f83825f8 | ||
|
|
300816a6db | ||
|
|
a41bd73b30 | ||
|
|
4e9d5bbd8a | ||
|
|
372138c789 | ||
|
|
b2bb1a7c24 | ||
|
|
390c0ba788 | ||
|
|
374bc04cdb | ||
|
|
56f045e6b0 | ||
|
|
af4df8e197 | ||
|
|
da33f065cf | ||
|
|
001aa3d1a8 | ||
|
|
186209a0a3 | ||
|
|
a63ec0a265 | ||
|
|
fccd43e532 | ||
|
|
604206843e | ||
|
|
a86eefc5e3 | ||
|
|
df77890c2a | ||
|
|
694f2382bf | ||
|
|
7c88a55153 | ||
|
|
339845ff6b | ||
|
|
3d25c3e1c6 | ||
|
|
97fe86c916 | ||
|
|
80b4c6fa68 | ||
|
|
19c3f54a30 | ||
|
|
7b234c666f | ||
|
|
7f2ded17ab | ||
|
|
e94d47976d | ||
|
|
bcd2b5cc50 | ||
|
|
08af924873 | ||
|
|
9176f7e037 | ||
|
|
06a77143bd | ||
|
|
65b866192e | ||
|
|
a3c05b2ea4 | ||
|
|
aff53cccc5 | ||
|
|
762d660447 | ||
|
|
183fdf06cb | ||
|
|
7fb7a64c8d | ||
|
|
3f116e7636 | ||
|
|
b1f0f8fa8b | ||
|
|
691b46d38b | ||
|
|
f0add97cf9 | ||
|
|
3507e4ce0e | ||
|
|
a06e39528f | ||
|
|
c41a2f4b98 | ||
|
|
8c86b2e32c | ||
|
|
8ac40eb44c | ||
|
|
cbe8807ebd | ||
|
|
05b68391dd | ||
|
|
e1a29f4aa8 | ||
|
|
b4b3be3d97 | ||
|
|
c97764ee6f | ||
|
|
2f07c18c5a | ||
|
|
c99321a518 | ||
|
|
386284beb8 | ||
|
|
2a9088d571 | ||
|
|
9797f69324 | ||
|
|
759f1e2085 | ||
|
|
05053071fe | ||
|
|
04e5707143 | ||
|
|
ed19454eca | ||
|
|
4ec7200260 | ||
|
|
3b4d7b1d70 | ||
|
|
d248ef95cd | ||
|
|
ac03c2b270 | ||
|
|
2ab2486d3b | ||
|
|
6a591069c5 | ||
|
|
5522d0908e | ||
|
|
1296b7a72c | ||
|
|
64e4ef042b | ||
|
|
f6900f2500 | ||
|
|
50bd198ed9 | ||
|
|
f51b16d0de | ||
|
|
ffa2bd14f8 | ||
|
|
1dd8ed8c93 | ||
|
|
362fbd66e9 | ||
|
|
aec6a3b5ca | ||
|
|
c0a8fd7395 | ||
|
|
3f15dbdc54 | ||
|
|
5a3e1c99c1 | ||
|
|
65d17a07b7 | ||
|
|
b8d2d9c701 | ||
|
|
b4a3883d6b | ||
|
|
9ab69d3960 | ||
|
|
07f8ca5d6c | ||
|
|
8e7af0291a | ||
|
|
c42eaee30c | ||
|
|
736c1a4ad1 | ||
|
|
22d0e60f08 | ||
|
|
aa32e7b359 | ||
|
|
39723074c0 | ||
|
|
e225f318bb | ||
|
|
a86134cc5b | ||
|
|
949b4aaa1f | ||
|
|
ba1889f441 | ||
|
|
b1b9174479 | ||
|
|
6b2dde02b5 | ||
|
|
cb82824c13 | ||
|
|
a08474a9fd | ||
|
|
268f907a08 | ||
|
|
a0ff3734cf | ||
|
|
1c64e4e741 | ||
|
|
0ea477abde | ||
|
|
da8795f666 | ||
|
|
8ddf7eb922 | ||
|
|
8df47f333e | ||
|
|
8a68e1d918 | ||
|
|
22b9f5db92 | ||
|
|
5b646495af | ||
|
|
ab797b91a4 | ||
|
|
277f447f3e | ||
|
|
f225fc3e3d | ||
|
|
a8521d0349 | ||
|
|
d4a1542ba3 | ||
|
|
c78c4926df | ||
|
|
190b3759a0 | ||
|
|
827e4b4ffd | ||
|
|
a112655bd2 | ||
|
|
4943832dd8 | ||
|
|
306687ccaa | ||
|
|
e48f1dac2a | ||
|
|
c927eb15d7 | ||
|
|
c36e2aa13d | ||
|
|
e1253f693a | ||
|
|
b71ab64cf4 | ||
|
|
3935e35f5c | ||
|
|
cc435e75de | ||
|
|
cae5a9ac58 | ||
|
|
476ec6e4ee | ||
|
|
2a5b5a7b45 | ||
|
|
d5fb6dac38 | ||
|
|
deb9a9189d | ||
|
|
66d8c29d25 | ||
|
|
f505b47ac9 | ||
|
|
3add454289 | ||
|
|
fa12a3e7e6 | ||
|
|
f742c847e1 | ||
|
|
6d00d5f6a5 | ||
|
|
c4d4d2385b | ||
|
|
805cacb2af | ||
|
|
61a58f2607 | ||
|
|
29cf6f528c | ||
|
|
1b6d718dab | ||
|
|
79e78f19dd | ||
|
|
b5d1eb2d54 | ||
|
|
8229de5eaa | ||
|
|
a1af59def3 | ||
|
|
454ee2d801 | ||
|
|
d77f417cf3 | ||
|
|
b51fd4096b | ||
|
|
988c485874 | ||
|
|
a0c217446a | ||
|
|
caacae093d | ||
|
|
f8d958e065 | ||
|
|
926186108b | ||
|
|
460b830a96 | ||
|
|
daf3ab4db4 | ||
|
|
038c45f4b6 | ||
|
|
94eb74646c | ||
|
|
862908d0eb | ||
|
|
3008794797 | ||
|
|
95bef8f3f6 | ||
|
|
38eba81933 | ||
|
|
bae1daf5dc | ||
|
|
606de990e9 | ||
|
|
0b4c39338e | ||
|
|
20db4657b2 | ||
|
|
4eca23174a | ||
|
|
3cd6a8a94b | ||
|
|
50aed01c57 | ||
|
|
6c1b852d48 | ||
|
|
8931702136 | ||
|
|
ecdd57dda2 |
@@ -1,5 +1,4 @@
|
||||
node_modules/
|
||||
public/src/nodebb.min.js
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.project
|
||||
@@ -10,11 +9,11 @@ logs/
|
||||
/public/uploads
|
||||
/public/sounds
|
||||
/public/vendor
|
||||
/public/nodebb.min.js
|
||||
/public/acp.min.js
|
||||
/public/src/modules/string.js
|
||||
.idea/
|
||||
.vscode/
|
||||
*.ipr
|
||||
*.iws
|
||||
/coverage
|
||||
/build
|
||||
.eslintrc
|
||||
|
||||
128
.eslintrc
Normal file
128
.eslintrc
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"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-empty": ["error", { "allowEmptyCatch": true }],
|
||||
"no-underscore-dangle": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"no-console": "off",
|
||||
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
||||
"strict": ["error", "global"],
|
||||
"consistent-return": "off",
|
||||
"func-names": "off",
|
||||
"no-tabs": "off",
|
||||
"indent": ["error", "tab"],
|
||||
"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 }],
|
||||
"import/no-unresolved": "error",
|
||||
|
||||
// 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",
|
||||
|
||||
// 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",
|
||||
|
||||
// "no-multi-assign": "off",
|
||||
// "linebreak-style": "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"
|
||||
}
|
||||
}
|
||||
110
.eslintrc.json
110
.eslintrc.json
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
|
||||
"rules": {
|
||||
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
|
||||
"linebreak-style": "off",
|
||||
"import/no-unresolved": "off",
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"one-var": "off",
|
||||
"no-undef": "off",
|
||||
"max-len": "off",
|
||||
"no-new": "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",
|
||||
"camelcase": "off",
|
||||
"no-negated-condition": "off",
|
||||
"one-var-declaration-per-line": "off",
|
||||
"new-cap": "off",
|
||||
"no-lonely-if": "off",
|
||||
"radix": "off",
|
||||
"no-else-return": "off",
|
||||
"no-useless-escape": "off",
|
||||
"block-scoped-var": "off",
|
||||
"operator-assignment": "off",
|
||||
"default-case": "off",
|
||||
"yoda": "off",
|
||||
"no-use-before-define": "off",
|
||||
"no-loop-func": "off",
|
||||
"no-void": "off",
|
||||
"valid-jsdoc": "off",
|
||||
"o-eq-null": "off",
|
||||
"no-cond-assign": "off",
|
||||
"no-eq-null": "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-script-url": "off",
|
||||
"no-path-concat": "off",
|
||||
"no-unused-expressions": "off",
|
||||
"no-restricted-module": "off",
|
||||
"no-return-assign": "off",
|
||||
"no-restricted-modules": "off",
|
||||
"no-tabs": "off",
|
||||
"indent": "off",
|
||||
"func-names": "off",
|
||||
"prefer-arrow-callback": "off",
|
||||
"object-curly-spacing": "off",
|
||||
"no-var": "off",
|
||||
"no-shadow": "off",
|
||||
"prefer-template": "off",
|
||||
"padded-blocks": "off",
|
||||
"eol-last": "off",
|
||||
"lines-around-directive": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"vars-on-top": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"object-shorthand": "off",
|
||||
"no-param-reassign": "off",
|
||||
"consistent-return": "off",
|
||||
"strict": "off",
|
||||
"comma-dangle": "off",
|
||||
"no-multi-spaces": "off",
|
||||
"quotes": "off",
|
||||
"keyword-spacing": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-mixed-operators": "off",
|
||||
"comma-spacing": "off",
|
||||
"global-require": "off",
|
||||
"no-trailing-spaces": "off",
|
||||
"key-spacing": "off",
|
||||
"import/newline-after-import": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"prefer-spread": "off",
|
||||
"no-multiple-empty-lines": "off",
|
||||
"spaced-comment": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"space-in-parens": "off",
|
||||
"block-spacing": "off",
|
||||
"quote-props": "off",
|
||||
"no-console": "off",
|
||||
"space-unary-ops": "off",
|
||||
"import/no-dynamic-require": "off",
|
||||
"no-bitwise": "off",
|
||||
"no-empty": "off",
|
||||
"array-bracket-spacin": "off",
|
||||
"dot-notation": "off",
|
||||
"func-call-spacing": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"array-bracket-spacing": "off",
|
||||
"object-property-newline": "off",
|
||||
"no-continue": "off",
|
||||
"no-extra-semi": "off",
|
||||
"no-spaced-func": "off"
|
||||
}
|
||||
}
|
||||
23
.github/CONTRIBUTING.md
vendored
23
.github/CONTRIBUTING.md
vendored
@@ -1,6 +1,10 @@
|
||||
# Submitting a Pull Request to NodeBB?
|
||||
|
||||
First of all, thank you! Please consider this [style guide](https://docs.nodebb.org/en/latest/contributing/style-guide.html) when submitting your changes. Also, please join our [community](https://community.nodebb.org) to meet other NodeBB developers and designers :)
|
||||
First of all, thank you! Before submission, please run `npm test` to lint and run the automated NodeBB tests. If everything passes, you're good to go. If you have any errors, please fix them and re-run `npm test` to make sure there aren't any others.
|
||||
|
||||
## Styleguide and linting
|
||||
|
||||
NodeBB mostly conforms to the [AirBnB Javascript style guide](https://github.com/airbnb/javascript#readme). If you're running into a lot of ESlint errors, you may want to install an editor plugin to display them in real time.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
@@ -34,11 +38,9 @@ There is a chance that the issue you are experiencing may have already been fixe
|
||||
You can find the NodeBB version number in the Admin Control Panel (ACP), as well as the first line output to the shell when running NodeBB
|
||||
|
||||
``` plaintext
|
||||
info: NodeBB v0.5.2-dev Copyright (C) 2013-2014 NodeBB Inc.
|
||||
info: This program comes with ABSOLUTELY NO WARRANTY.
|
||||
info: This is free software, and you are welcome to redistribute it under certain conditions.
|
||||
info:
|
||||
info: Time: Tue Oct 07 2014 20:25:20 GMT-0400 (EDT)
|
||||
3/4 12:38:57 [10752] - info: NodeBB v1.4.5 Copyright (C) 2013-2017 NodeBB Inc.
|
||||
3/4 12:38:57 [10752] - info: This program comes with ABSOLUTELY NO WARRANTY.
|
||||
3/4 12:38:57 [10752] - info: This is free software, and you are welcome to redistribute it under certain conditions.
|
||||
```
|
||||
|
||||
If you are running NodeBB via git, it is also helpful to let the maintainers know what commit hash you are on. To find the commit hash, execute the following command:
|
||||
@@ -51,12 +53,13 @@ $ git rev-parse HEAD
|
||||
If you have downloaded the `.zip` or `.tar.gz` packages from GitHub (or elsewhere), please let us know.
|
||||
|
||||
## Provide theme versions if issue is related to the theme/display
|
||||
Use `npm ls` to list the versions of the theme you're using. In this example, we're running the Persona theme, which depends on the Vanilla theme.
|
||||
|
||||
``` bash
|
||||
$ npm ls nodebb-theme-vanilla nodebb-theme-lavender
|
||||
nodebb@0.7.0-dev /home/julian/Projects/nodebb/forum
|
||||
├── nodebb-theme-lavender@0.2.13
|
||||
└── nodebb-theme-vanilla@0.2.35
|
||||
$ npm ls nodebb-theme-vanilla nodebb-theme-persona
|
||||
nodebb@1.4.3 /path/to/nodebb
|
||||
+-- nodebb-theme-persona@4.2.4
|
||||
`-- nodebb-theme-vanilla@5.2.0
|
||||
```
|
||||
|
||||
## Attempt to use `git bisect`
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -34,6 +34,9 @@ pidfile
|
||||
/public/nodebb.min.js.map
|
||||
/public/acp.min.js
|
||||
/public/acp.min.js.map
|
||||
/public/installer.css
|
||||
/public/installer.min.js
|
||||
/public/logo.png
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
*.iml
|
||||
@@ -52,3 +55,6 @@ tx.exe
|
||||
|
||||
##Coverage output
|
||||
coverage
|
||||
|
||||
build
|
||||
*.log
|
||||
|
||||
2133
.tx/config
2133
.tx/config
File diff suppressed because it is too large
Load Diff
113
Gruntfile.js
113
Gruntfile.js
@@ -1,24 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
var fork = require('child_process').fork,
|
||||
env = process.env,
|
||||
worker, updateWorker,
|
||||
incomplete = [],
|
||||
running = 0;
|
||||
'use strict';
|
||||
|
||||
var fork = require('child_process').fork;
|
||||
var env = process.env;
|
||||
var worker;
|
||||
var updateWorker;
|
||||
var initWorker;
|
||||
var incomplete = [];
|
||||
var running = 0;
|
||||
|
||||
module.exports = function (grunt) {
|
||||
var args = [];
|
||||
var initArgs = ['--build'];
|
||||
if (!grunt.option('verbose')) {
|
||||
args.push('--log-level=info');
|
||||
initArgs.push('--log-level=info');
|
||||
}
|
||||
|
||||
function update(action, filepath, target) {
|
||||
var updateArgs = args.slice(),
|
||||
fromFile = '',
|
||||
compiling = '',
|
||||
time = Date.now();
|
||||
|
||||
var updateArgs = args.slice();
|
||||
var compiling = '';
|
||||
var time = Date.now();
|
||||
|
||||
if (target === 'lessUpdated_Client') {
|
||||
compiling = 'clientCSS';
|
||||
} else if (target === 'lessUpdated_Admin') {
|
||||
@@ -27,6 +29,8 @@ module.exports = function (grunt) {
|
||||
compiling = 'js';
|
||||
} else if (target === 'templatesUpdated') {
|
||||
compiling = 'tpl';
|
||||
} else if (target === 'langUpdated') {
|
||||
compiling = 'lang';
|
||||
} else if (target === 'serverUpdated') {
|
||||
// Do nothing, just restart
|
||||
}
|
||||
@@ -43,11 +47,13 @@ module.exports = function (grunt) {
|
||||
updateWorker.kill('SIGKILL');
|
||||
}
|
||||
updateWorker = fork('app.js', updateArgs, { env: env });
|
||||
++running;
|
||||
running += 1;
|
||||
updateWorker.on('exit', function () {
|
||||
--running;
|
||||
running -= 1;
|
||||
if (running === 0) {
|
||||
worker = fork('app.js', args, { env: env });
|
||||
worker = fork('app.js', args, {
|
||||
env: env,
|
||||
});
|
||||
worker.on('message', function () {
|
||||
if (incomplete.length) {
|
||||
incomplete = [];
|
||||
@@ -68,11 +74,17 @@ module.exports = function (grunt) {
|
||||
'public/*.less',
|
||||
'node_modules/nodebb-*/*.less', 'node_modules/nodebb-*/**/*.less',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**'
|
||||
]
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
lessUpdated_Admin: {
|
||||
files: ['public/**/*.less']
|
||||
files: ['public/**/*.less'],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
clientUpdated: {
|
||||
files: [
|
||||
@@ -80,34 +92,67 @@ module.exports = function (grunt) {
|
||||
'node_modules/nodebb-*/*.js', 'node_modules/nodebb-*/**/*.js',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'node_modules/templates.js/lib/templates.js',
|
||||
'!node_modules/nodebb-*/.git/**'
|
||||
]
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
serverUpdated: {
|
||||
files: ['*.js', 'install/*.js', 'src/**/*.js']
|
||||
files: ['*.js', 'install/*.js', 'src/**/*.js'],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
templatesUpdated: {
|
||||
files: [
|
||||
'src/views/**/*.tpl',
|
||||
'node_modules/nodebb-*/*.tpl', 'node_modules/nodebb-*/**/*.tpl',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**'
|
||||
]
|
||||
}
|
||||
}
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
langUpdated: {
|
||||
files: [
|
||||
'public/language/en-GB/*.json',
|
||||
'public/language/en-GB/**/*.json',
|
||||
'node_modules/nodebb-*/**/*.json',
|
||||
'!node_modules/nodebb-*/node_modules/**',
|
||||
'!node_modules/nodebb-*/.git/**',
|
||||
'!node_modules/nodebb-*/plugin.json',
|
||||
'!node_modules/nodebb-*/package.json',
|
||||
'!node_modules/nodebb-*/theme.json',
|
||||
],
|
||||
options: {
|
||||
interval: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
if (grunt.option('skip')) {
|
||||
grunt.registerTask('default', ['watch:serverUpdated']);
|
||||
} else {
|
||||
grunt.registerTask('default', ['watch']);
|
||||
}
|
||||
|
||||
|
||||
grunt.registerTask('default', ['watch']);
|
||||
env.NODE_ENV = 'development';
|
||||
|
||||
worker = fork('app.js', args, { env: env });
|
||||
if (grunt.option('skip')) {
|
||||
worker = fork('app.js', args, {
|
||||
env: env,
|
||||
});
|
||||
} else {
|
||||
initWorker = fork('app.js', initArgs, {
|
||||
env: env,
|
||||
});
|
||||
|
||||
initWorker.on('exit', function () {
|
||||
worker = fork('app.js', args, {
|
||||
env: env,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
grunt.event.on('watch', update);
|
||||
};
|
||||
};
|
||||
|
||||
237
app.js
237
app.js
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
NodeBB - A better forum platform for the modern web
|
||||
https://github.com/NodeBB/NodeBB/
|
||||
Copyright (C) 2013-2016 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
|
||||
@@ -17,8 +17,13 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*global require, global, process*/
|
||||
'use strict';
|
||||
|
||||
if (require.main !== module) {
|
||||
require.main.require = function (path) {
|
||||
return require(path);
|
||||
};
|
||||
}
|
||||
|
||||
var nconf = require('nconf');
|
||||
nconf.argv().env('__');
|
||||
@@ -37,11 +42,11 @@ winston.add(winston.transports.Console, {
|
||||
colorize: true,
|
||||
timestamp: function () {
|
||||
var date = new Date();
|
||||
return (!!nconf.get('json-logging')) ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,8) + ' [' + global.process.pid + ']';
|
||||
return nconf.get('json-logging') ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 8) + ' [' + global.process.pid + ']';
|
||||
},
|
||||
level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'),
|
||||
json: (!!nconf.get('json-logging')),
|
||||
stringify: (!!nconf.get('json-logging'))
|
||||
stringify: (!!nconf.get('json-logging')),
|
||||
});
|
||||
|
||||
|
||||
@@ -75,7 +80,7 @@ if (nconf.get('setup') || nconf.get('install')) {
|
||||
} else if (nconf.get('reset')) {
|
||||
async.waterfall([
|
||||
async.apply(require('./src/reset').reset),
|
||||
async.apply(require('./build').buildAll)
|
||||
async.apply(require('./src/meta/build').buildAll),
|
||||
], function (err) {
|
||||
process.exit(err ? 1 : 0);
|
||||
});
|
||||
@@ -84,23 +89,24 @@ if (nconf.get('setup') || nconf.get('install')) {
|
||||
} else if (nconf.get('plugins')) {
|
||||
listPlugins();
|
||||
} else if (nconf.get('build')) {
|
||||
require('./build').build(nconf.get('build'));
|
||||
require('./src/meta/build').build(nconf.get('build'));
|
||||
} else {
|
||||
start();
|
||||
require('./src/start').start();
|
||||
}
|
||||
|
||||
function loadConfig(callback) {
|
||||
winston.verbose('* using configuration stored in: %s', configFile);
|
||||
|
||||
nconf.file({
|
||||
file: configFile
|
||||
file: configFile,
|
||||
});
|
||||
|
||||
nconf.defaults({
|
||||
base_dir: __dirname,
|
||||
themes_path: path.join(__dirname, 'node_modules'),
|
||||
views_dir: path.join(__dirname, 'public/templates'),
|
||||
version: pkg.version
|
||||
upload_path: 'public/uploads',
|
||||
views_dir: path.join(__dirname, 'build/public/templates'),
|
||||
version: pkg.version,
|
||||
});
|
||||
|
||||
if (!nconf.get('isCluster')) {
|
||||
@@ -113,142 +119,33 @@ function loadConfig(callback) {
|
||||
nconf.set('core_templates_path', path.join(__dirname, 'src/views'));
|
||||
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
|
||||
|
||||
nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path')));
|
||||
|
||||
if (nconf.get('url')) {
|
||||
nconf.set('url_parsed', url.parse(nconf.get('url')));
|
||||
}
|
||||
|
||||
// Explicitly cast 'jobsDisabled' as Bool
|
||||
var castAsBool = ['jobsDisabled'];
|
||||
nconf.stores.env.readOnly = false;
|
||||
castAsBool.forEach(function (prop) {
|
||||
var value = nconf.get(prop);
|
||||
if (value) {
|
||||
nconf.set(prop, typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true');
|
||||
}
|
||||
});
|
||||
nconf.stores.env.readOnly = true;
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function start() {
|
||||
var db = require('./src/database');
|
||||
|
||||
// nconf defaults, if not set in config
|
||||
if (!nconf.get('upload_path')) {
|
||||
nconf.set('upload_path', '/public/uploads');
|
||||
}
|
||||
if (!nconf.get('sessionKey')) {
|
||||
nconf.set('sessionKey', 'express.sid');
|
||||
}
|
||||
// Parse out the relative_url and other goodies from the configured URL
|
||||
var urlObject = url.parse(nconf.get('url'));
|
||||
var relativePath = urlObject.pathname !== '/' ? urlObject.pathname : '';
|
||||
nconf.set('base_url', urlObject.protocol + '//' + urlObject.host);
|
||||
nconf.set('secure', urlObject.protocol === 'https:');
|
||||
nconf.set('use_port', !!urlObject.port);
|
||||
nconf.set('relative_path', relativePath);
|
||||
nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || (nconf.get('PORT_ENV_VAR') ? nconf.get(nconf.get('PORT_ENV_VAR')) : false) || 4567);
|
||||
nconf.set('upload_url', nconf.get('upload_path').replace(/^\/public/, ''));
|
||||
|
||||
if (nconf.get('isPrimary') === 'true') {
|
||||
winston.info('Time: %s', (new Date()).toString());
|
||||
winston.info('Initializing NodeBB v%s', nconf.get('version'));
|
||||
|
||||
|
||||
var host = nconf.get(nconf.get('database') + ':host'),
|
||||
storeLocation = host ? 'at ' + host + (host.indexOf('/') === -1 ? ':' + nconf.get(nconf.get('database') + ':port') : '') : '';
|
||||
|
||||
winston.verbose('* using %s store %s', nconf.get('database'), storeLocation);
|
||||
winston.verbose('* using themes stored in: %s', nconf.get('themes_path'));
|
||||
}
|
||||
|
||||
process.on('SIGTERM', shutdown);
|
||||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGHUP', restart);
|
||||
process.on('message', function (message) {
|
||||
if (typeof message !== 'object') {
|
||||
return;
|
||||
}
|
||||
var meta = require('./src/meta');
|
||||
|
||||
switch (message.action) {
|
||||
case 'reload':
|
||||
meta.reload();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
winston.error(err.stack);
|
||||
console.log(err.stack);
|
||||
|
||||
require('./src/meta').js.killMinifier();
|
||||
shutdown(1);
|
||||
});
|
||||
|
||||
async.waterfall([
|
||||
async.apply(db.init),
|
||||
function (next) {
|
||||
var meta = require('./src/meta');
|
||||
async.parallel([
|
||||
async.apply(db.checkCompatibility),
|
||||
async.apply(meta.configs.init),
|
||||
function (next) {
|
||||
if (nconf.get('dep-check') === undefined || nconf.get('dep-check') !== false) {
|
||||
meta.dependencies.check(next);
|
||||
} else {
|
||||
winston.warn('[init] Dependency checking skipped!');
|
||||
setImmediate(next);
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
require('./src/upgrade').check(next);
|
||||
}
|
||||
], function (err) {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
var webserver = require('./src/webserver');
|
||||
require('./src/socket.io').init(webserver.server);
|
||||
|
||||
if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) {
|
||||
require('./src/notifications').init();
|
||||
require('./src/user').startJobs();
|
||||
}
|
||||
|
||||
webserver.listen(next);
|
||||
}
|
||||
], function (err) {
|
||||
if (err) {
|
||||
switch(err.message) {
|
||||
case 'schema-out-of-date':
|
||||
winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:');
|
||||
winston.warn(' ./nodebb upgrade');
|
||||
break;
|
||||
case 'dependencies-out-of-date':
|
||||
winston.warn('One or more of NodeBB\'s dependent packages are out-of-date. Please run the following command to update them:');
|
||||
winston.warn(' ./nodebb upgrade');
|
||||
break;
|
||||
case 'dependencies-missing':
|
||||
winston.warn('One or more of NodeBB\'s dependent packages are missing. Please run the following command to update them:');
|
||||
winston.warn(' ./nodebb upgrade');
|
||||
break;
|
||||
default:
|
||||
winston.error(err);
|
||||
break;
|
||||
}
|
||||
|
||||
// Either way, bad stuff happened. Abort start.
|
||||
process.exit();
|
||||
}
|
||||
|
||||
if (process.send) {
|
||||
process.send({
|
||||
action: 'listening'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setup() {
|
||||
winston.info('NodeBB Setup Triggered via Command Line');
|
||||
|
||||
var install = require('./src/install');
|
||||
var build = require('./build');
|
||||
var build = require('./src/meta/build');
|
||||
|
||||
process.stdout.write('\nWelcome to NodeBB!\n');
|
||||
process.stdout.write('\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.\n');
|
||||
@@ -257,14 +154,14 @@ function setup() {
|
||||
async.series([
|
||||
async.apply(install.setup),
|
||||
async.apply(loadConfig),
|
||||
async.apply(build.buildAll)
|
||||
async.apply(build.buildAll),
|
||||
], function (err, data) {
|
||||
// Disregard build step data
|
||||
data = data[0];
|
||||
|
||||
var separator = ' ';
|
||||
if (process.stdout.columns > 10) {
|
||||
for(var x = 0,cols = process.stdout.columns - 10; x < cols; x++) {
|
||||
for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) {
|
||||
separator += '=';
|
||||
}
|
||||
}
|
||||
@@ -296,13 +193,13 @@ function upgrade() {
|
||||
var db = require('./src/database');
|
||||
var meta = require('./src/meta');
|
||||
var upgrade = require('./src/upgrade');
|
||||
var build = require('./build');
|
||||
var build = require('./src/meta/build');
|
||||
|
||||
async.series([
|
||||
async.apply(db.init),
|
||||
async.apply(meta.configs.init),
|
||||
async.apply(upgrade.upgrade),
|
||||
async.apply(build.buildAll)
|
||||
async.apply(build.buildAll),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
@@ -315,22 +212,32 @@ function upgrade() {
|
||||
|
||||
function activate() {
|
||||
var db = require('./src/database');
|
||||
db.init(function (err) {
|
||||
var plugins = require('./src/plugins');
|
||||
var plugin = nconf.get('activate');
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.init(next);
|
||||
},
|
||||
function (next) {
|
||||
if (plugin.indexOf('nodebb-') !== 0) {
|
||||
// Allow omission of `nodebb-plugin-`
|
||||
plugin = 'nodebb-plugin-' + plugin;
|
||||
}
|
||||
plugins.isInstalled(plugin, next);
|
||||
},
|
||||
function (isInstalled, next) {
|
||||
if (!isInstalled) {
|
||||
return next(new Error('plugin not installed'));
|
||||
}
|
||||
|
||||
winston.info('Activating plugin `%s`', plugin);
|
||||
db.sortedSetAdd('plugins:active', 0, plugin, next);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
process.exit(1);
|
||||
winston.error(err.message);
|
||||
}
|
||||
|
||||
var plugin = nconf.get('activate');
|
||||
if (plugin.indexOf('nodebb-') !== 0) {
|
||||
// Allow omission of `nodebb-plugin-`
|
||||
plugin = 'nodebb-plugin-' + plugin;
|
||||
}
|
||||
|
||||
winston.info('Activating plugin `%s`', plugin);
|
||||
db.sortedSetAdd('plugins:active', 0, plugin, function (err) {
|
||||
process.exit(err ? 1 : 0);
|
||||
});
|
||||
process.exit(err ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -355,30 +262,6 @@ function listPlugins() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function shutdown(code) {
|
||||
winston.info('[app] Shutdown (SIGTERM/SIGINT) Initialised.');
|
||||
require('./src/database').close();
|
||||
winston.info('[app] Database connection closed.');
|
||||
require('./src/webserver').server.close();
|
||||
winston.info('[app] Web server closed to connections.');
|
||||
|
||||
winston.info('[app] Shutdown complete.');
|
||||
process.exit(code || 0);
|
||||
}
|
||||
|
||||
function restart() {
|
||||
if (process.send) {
|
||||
winston.info('[app] Restarting...');
|
||||
process.send({
|
||||
action: 'restart'
|
||||
});
|
||||
} else {
|
||||
winston.error('[app] Could not restart server. Shutting down.');
|
||||
shutdown(1);
|
||||
}
|
||||
}
|
||||
|
||||
function versionCheck() {
|
||||
var version = process.version.slice(1);
|
||||
var range = pkg.engines.node;
|
||||
@@ -389,4 +272,4 @@ function versionCheck() {
|
||||
winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.');
|
||||
winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
115
build.js
115
build.js
@@ -1,115 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
var buildStart;
|
||||
|
||||
var valid = ['js', 'clientCSS', 'acpCSS', 'tpl'];
|
||||
|
||||
exports.buildAll = function (callback) {
|
||||
exports.build(valid.join(','), callback);
|
||||
};
|
||||
|
||||
exports.build = function build(targets, callback) {
|
||||
buildStart = Date.now();
|
||||
|
||||
var db = require('./src/database');
|
||||
var meta = require('./src/meta');
|
||||
var plugins = require('./src/plugins');
|
||||
|
||||
|
||||
targets = (targets === true ? valid : targets.split(',').filter(function (target) {
|
||||
return valid.indexOf(target) !== -1;
|
||||
}));
|
||||
|
||||
if (!targets) {
|
||||
winston.error('[build] No valid build targets found. Aborting.');
|
||||
return process.exit(0);
|
||||
}
|
||||
|
||||
async.series([
|
||||
async.apply(db.init),
|
||||
async.apply(meta.themes.setupPaths),
|
||||
async.apply(plugins.prepareForBuild)
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[build] Encountered error preparing for build: ' + err.message);
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
exports.buildTargets(targets, callback);
|
||||
});
|
||||
};
|
||||
|
||||
exports.buildTargets = function (targets, callback) {
|
||||
var meta = require('./src/meta');
|
||||
buildStart = buildStart || Date.now();
|
||||
|
||||
var step = function (startTime, target, next) {
|
||||
winston.info('[build] ' + target + ' => Completed in ' + ((Date.now() - startTime) / 1000) + 's');
|
||||
next();
|
||||
};
|
||||
|
||||
async.parallel([
|
||||
function (next) {
|
||||
if (targets.indexOf('js') !== -1) {
|
||||
winston.info('[build] Building javascript');
|
||||
var startTime = Date.now();
|
||||
async.series([
|
||||
async.apply(meta.js.minify, 'nodebb.min.js'),
|
||||
async.apply(meta.js.minify, 'acp.min.js')
|
||||
], step.bind(this, startTime, 'js', next));
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
async.eachSeries(targets, function (target, next) {
|
||||
var startTime;
|
||||
switch(target) {
|
||||
case 'js':
|
||||
setImmediate(next);
|
||||
break;
|
||||
case 'clientCSS':
|
||||
winston.info('[build] Building client-side CSS');
|
||||
startTime = Date.now();
|
||||
meta.css.minify('stylesheet.css', step.bind(this, startTime, target, next));
|
||||
break;
|
||||
|
||||
case 'acpCSS':
|
||||
winston.info('[build] Building admin control panel CSS');
|
||||
startTime = Date.now();
|
||||
meta.css.minify('admin.css', step.bind(this, startTime, target, next));
|
||||
break;
|
||||
|
||||
case 'tpl':
|
||||
winston.info('[build] Building templates');
|
||||
startTime = Date.now();
|
||||
meta.templates.compile(step.bind(this, startTime, target, next));
|
||||
break;
|
||||
|
||||
default:
|
||||
winston.warn('[build] Unknown build target: \'' + target + '\'');
|
||||
setImmediate(next);
|
||||
break;
|
||||
}
|
||||
}, next);
|
||||
}
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[build] Encountered error during build step: ' + err.message);
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
var time = (Date.now() - buildStart) / 1000;
|
||||
|
||||
winston.info('[build] Asset compilation successful. Completed in ' + time + 's.');
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,71 +1,71 @@
|
||||
[
|
||||
{
|
||||
"route": "/categories",
|
||||
"title": "\\[\\[global:header.categories\\]\\]",
|
||||
"title": "[[global:header.categories]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-list",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.categories\\]\\]"
|
||||
"text": "[[global:header.categories]]"
|
||||
},
|
||||
{
|
||||
"id": "unread-count",
|
||||
"route": "/unread",
|
||||
"title": "\\[\\[global:header.unread\\]\\]",
|
||||
"title": "[[global:header.unread]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-inbox",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.unread\\]\\]",
|
||||
"text": "[[global:header.unread]]",
|
||||
"properties": {
|
||||
"loggedIn": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "/recent",
|
||||
"title": "\\[\\[global:header.recent\\]\\]",
|
||||
"title": "[[global:header.recent]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-clock-o",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.recent\\]\\]"
|
||||
"text": "[[global:header.recent]]"
|
||||
},
|
||||
{
|
||||
"route": "/tags",
|
||||
"title": "\\[\\[global:header.tags\\]\\]",
|
||||
"title": "[[global:header.tags]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-tags",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.tags\\]\\]"
|
||||
"text": "[[global:header.tags]]"
|
||||
},
|
||||
{
|
||||
"route": "/popular",
|
||||
"title": "\\[\\[global:header.popular\\]\\]",
|
||||
"title": "[[global:header.popular]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-fire",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.popular\\]\\]"
|
||||
"text": "[[global:header.popular]]"
|
||||
},
|
||||
{
|
||||
"route": "/users",
|
||||
"title": "\\[\\[global:header.users\\]\\]",
|
||||
"title": "[[global:header.users]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-user",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.users\\]\\]"
|
||||
"text": "[[global:header.users]]"
|
||||
},
|
||||
{
|
||||
"route": "/groups",
|
||||
"title": "\\[\\[global:header.groups\\]\\]",
|
||||
"title": "[[global:header.groups]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-group",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.groups\\]\\]"
|
||||
"text": "[[global:header.groups]]"
|
||||
},
|
||||
{
|
||||
"route": "/admin",
|
||||
"title": "\\[\\[global:header.admin\\]\\]",
|
||||
"title": "[[global:header.admin]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-cogs",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.admin\\]\\]",
|
||||
"text": "[[global:header.admin]]",
|
||||
"properties": {
|
||||
"targetBlank": false,
|
||||
"adminOnly": true
|
||||
@@ -73,11 +73,11 @@
|
||||
},
|
||||
{
|
||||
"route": "/search",
|
||||
"title": "\\[\\[global:header.search\\]\\]",
|
||||
"title": "[[global:header.search]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-search",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "\\[\\[global:header.search\\]\\]",
|
||||
"text": "[[global:header.search]]",
|
||||
"properties": {
|
||||
"searchInstalled": true
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var prompt = require('prompt');
|
||||
@@ -6,7 +6,7 @@ var winston = require('winston');
|
||||
|
||||
var questions = {
|
||||
redis: require('../src/database/redis').questions,
|
||||
mongo: require('../src/database/mongo').questions
|
||||
mongo: require('../src/database/mongo').questions,
|
||||
};
|
||||
|
||||
module.exports = function (config, callback) {
|
||||
@@ -18,7 +18,7 @@ module.exports = function (config, callback) {
|
||||
},
|
||||
function (databaseConfig, next) {
|
||||
saveDatabaseConfig(config, databaseConfig, next);
|
||||
}
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ function saveDatabaseConfig(config, databaseConfig, callback) {
|
||||
host: databaseConfig['redis:host'],
|
||||
port: databaseConfig['redis:port'],
|
||||
password: databaseConfig['redis:password'],
|
||||
database: databaseConfig['redis:database']
|
||||
database: databaseConfig['redis:database'],
|
||||
};
|
||||
|
||||
if (config.redis.host.slice(0, 1) === '/') {
|
||||
@@ -67,16 +67,16 @@ function saveDatabaseConfig(config, databaseConfig, callback) {
|
||||
port: databaseConfig['mongo:port'],
|
||||
username: databaseConfig['mongo:username'],
|
||||
password: databaseConfig['mongo:password'],
|
||||
database: databaseConfig['mongo:database']
|
||||
database: databaseConfig['mongo:database'],
|
||||
};
|
||||
} else {
|
||||
return callback(new Error('unknown database : ' + config.database));
|
||||
}
|
||||
|
||||
var allQuestions = questions.redis.concat(questions.mongo);
|
||||
for (var x = 0; x < allQuestions.length; x++) {
|
||||
for (var x = 0; x < allQuestions.length; x += 1) {
|
||||
delete config[allQuestions[x].name];
|
||||
}
|
||||
|
||||
callback(null, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var winston = require('winston');
|
||||
var express = require('express');
|
||||
@@ -17,9 +17,9 @@ winston.add(winston.transports.File, {
|
||||
colorize: true,
|
||||
timestamp: function () {
|
||||
var date = new Date();
|
||||
return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,5) + ' [' + global.process.pid + ']';
|
||||
return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 5) + ' [' + global.process.pid + ']';
|
||||
},
|
||||
level: 'verbose'
|
||||
level: 'verbose',
|
||||
});
|
||||
|
||||
var web = {};
|
||||
@@ -27,7 +27,7 @@ var scripts = [
|
||||
'public/vendor/xregexp/xregexp.js',
|
||||
'public/vendor/xregexp/unicode/unicode-base.js',
|
||||
'public/src/utils.js',
|
||||
'public/src/installer/install.js'
|
||||
'public/src/installer/install.js',
|
||||
];
|
||||
|
||||
web.install = function (port) {
|
||||
@@ -39,7 +39,7 @@ web.install = function (port) {
|
||||
app.set('view engine', 'tpl');
|
||||
app.set('views', path.join(__dirname, '../src/views'));
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: true
|
||||
extended: true,
|
||||
}));
|
||||
|
||||
async.parallel([compileLess, compileJS], function () {
|
||||
@@ -66,7 +66,7 @@ function welcome(req, res) {
|
||||
var databases = dbs.map(function (el) {
|
||||
return {
|
||||
name: el,
|
||||
questions: require('../src/database/' + el).questions
|
||||
questions: require('../src/database/' + el).questions,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -75,10 +75,10 @@ function welcome(req, res) {
|
||||
res.render('install/index', {
|
||||
databases: databases,
|
||||
skipDatabaseSetup: !!nconf.get('database'),
|
||||
error: res.locals.error ? true : false,
|
||||
success: res.locals.success ? true : false,
|
||||
error: !!res.locals.error,
|
||||
success: !!res.locals.success,
|
||||
values: req.body,
|
||||
minimumPasswordLength: defaults.minimumPasswordLength
|
||||
minimumPasswordLength: defaults.minimumPasswordLength,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ function install(req, res) {
|
||||
}
|
||||
|
||||
var child = require('child_process').fork('app', ['--setup'], {
|
||||
env: process.env
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
child.on('close', function (data) {
|
||||
@@ -110,7 +110,7 @@ function launch(req, res) {
|
||||
|
||||
var child = require('child_process').spawn('node', ['loader.js'], {
|
||||
detached: true,
|
||||
stdio: ['ignore', 'ignore', 'ignore']
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
});
|
||||
|
||||
process.stdout.write('\nStarting NodeBB\n');
|
||||
@@ -118,9 +118,17 @@ function launch(req, res) {
|
||||
process.stdout.write(' "./nodebb log" to view server output\n');
|
||||
process.stdout.write(' "./nodebb restart" to restart NodeBB\n');
|
||||
|
||||
child.unref();
|
||||
process.exit(0);
|
||||
async.parallel([
|
||||
async.apply(fs.unlink(path.join(__dirname, '../public/installer.css'))),
|
||||
async.apply(fs.unlink(path.join(__dirname, '../public/installer.min.js'))),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.warn('Unable to remove installer files');
|
||||
}
|
||||
|
||||
child.unref();
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
function compileLess(callback) {
|
||||
@@ -130,11 +138,11 @@ function compileLess(callback) {
|
||||
}
|
||||
|
||||
less.render(style.toString(), function (err, css) {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return winston.error('Unable to compile LESS: ', err);
|
||||
}
|
||||
|
||||
fs.writeFile(path.join(__dirname, '../public/stylesheet.css'), css.css, callback);
|
||||
fs.writeFile(path.join(__dirname, '../public/installer.css'), css.css, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -146,7 +154,7 @@ function compileJS(callback) {
|
||||
}));
|
||||
|
||||
|
||||
fs.writeFile(path.join(__dirname, '../public/nodebb.min.js'), result.code, callback);
|
||||
fs.writeFile(path.join(__dirname, '../public/installer.min.js'), result.code, callback);
|
||||
}
|
||||
|
||||
module.exports = web;
|
||||
module.exports = web;
|
||||
|
||||
100
loader.js
100
loader.js
@@ -1,29 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
var nconf = require('nconf'),
|
||||
fs = require('fs'),
|
||||
url = require('url'),
|
||||
path = require('path'),
|
||||
fork = require('child_process').fork,
|
||||
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');
|
||||
|
||||
async = require('async'),
|
||||
logrotate = require('logrotate-stream'),
|
||||
file = require('./src/file'),
|
||||
pkg = require('./package.json');
|
||||
var file = require('./src/file');
|
||||
var pkg = require('./package.json');
|
||||
|
||||
nconf.argv().env().file({
|
||||
file: path.join(__dirname, '/config.json')
|
||||
file: path.join(__dirname, 'config.json'),
|
||||
});
|
||||
|
||||
var pidFilePath = __dirname + '/pidfile',
|
||||
output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }),
|
||||
silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false,
|
||||
numProcs,
|
||||
workers = [],
|
||||
|
||||
Loader = {
|
||||
timesStarted: 0
|
||||
};
|
||||
var pidFilePath = path.join(__dirname, 'pidfile');
|
||||
var outputLogFilePath = path.join(__dirname, 'logs/output.log');
|
||||
var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true });
|
||||
var silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false;
|
||||
var numProcs;
|
||||
var workers = [];
|
||||
var Loader = {
|
||||
timesStarted: 0,
|
||||
};
|
||||
var appPath = path.join(__dirname, 'app.js');
|
||||
|
||||
Loader.init = function (callback) {
|
||||
if (silent) {
|
||||
@@ -50,11 +51,10 @@ Loader.displayStartupMessages = function (callback) {
|
||||
};
|
||||
|
||||
Loader.addWorkerEvents = function (worker) {
|
||||
|
||||
worker.on('exit', function (code, signal) {
|
||||
if (code !== 0) {
|
||||
if (Loader.timesStarted < numProcs * 3) {
|
||||
Loader.timesStarted++;
|
||||
Loader.timesStarted += 1;
|
||||
if (Loader.crashTimer) {
|
||||
clearTimeout(Loader.crashTimer);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ Loader.addWorkerEvents = function (worker) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -78,13 +78,13 @@ Loader.addWorkerEvents = function (worker) {
|
||||
worker.on('message', function (message) {
|
||||
if (message && typeof message === 'object' && message.action) {
|
||||
switch (message.action) {
|
||||
case 'restart':
|
||||
console.log('[cluster] Restarting...');
|
||||
Loader.restart();
|
||||
case 'restart':
|
||||
console.log('[cluster] Restarting...');
|
||||
Loader.restart();
|
||||
break;
|
||||
case 'reload':
|
||||
console.log('[cluster] Reloading...');
|
||||
Loader.reload();
|
||||
case 'reload':
|
||||
console.log('[cluster] Reloading...');
|
||||
Loader.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ Loader.start = function (callback) {
|
||||
numProcs = getPorts().length;
|
||||
console.log('Clustering enabled: Spinning up ' + numProcs + ' process(es).\n');
|
||||
|
||||
for (var x = 0; x < numProcs; ++x) {
|
||||
for (var x = 0; x < numProcs; x += 1) {
|
||||
forkWorker(x, x === 0);
|
||||
}
|
||||
|
||||
@@ -108,17 +108,17 @@ function forkWorker(index, isPrimary) {
|
||||
var ports = getPorts();
|
||||
var args = [];
|
||||
|
||||
if(!ports[index]) {
|
||||
if (!ports[index]) {
|
||||
return console.log('[cluster] invalid port for worker : ' + index + ' ports: ' + ports.length);
|
||||
}
|
||||
|
||||
process.env.isPrimary = isPrimary;
|
||||
process.env.isCluster = ports.length > 1 ? true : false;
|
||||
process.env.isCluster = ports.length > 1;
|
||||
process.env.port = ports[index];
|
||||
|
||||
var worker = fork('app.js', args, {
|
||||
var worker = fork(appPath, args, {
|
||||
silent: silent,
|
||||
env: process.env
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
worker.index = index;
|
||||
@@ -129,7 +129,7 @@ function forkWorker(index, isPrimary) {
|
||||
Loader.addWorkerEvents(worker);
|
||||
|
||||
if (silent) {
|
||||
var output = logrotate({ file: __dirname + '/logs/output.log', 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);
|
||||
}
|
||||
@@ -151,15 +151,31 @@ function getPorts() {
|
||||
|
||||
Loader.restart = function () {
|
||||
killWorkers();
|
||||
|
||||
var pathToConfig = path.join(__dirname, '/config.json');
|
||||
nconf.remove('file');
|
||||
nconf.use('file', { file: path.join(__dirname, '/config.json') });
|
||||
Loader.start();
|
||||
nconf.use('file', { file: pathToConfig });
|
||||
|
||||
fs.readFile(pathToConfig, { encoding: 'utf-8' }, function (err, configFile) {
|
||||
if (err) {
|
||||
console.log('Error reading config : ' + err.message);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var conf = JSON.parse(configFile);
|
||||
|
||||
nconf.stores.env.readOnly = false;
|
||||
nconf.set('url', conf.url);
|
||||
nconf.stores.env.readOnly = true;
|
||||
|
||||
Loader.start();
|
||||
});
|
||||
};
|
||||
|
||||
Loader.reload = function () {
|
||||
workers.forEach(function (worker) {
|
||||
worker.send({
|
||||
action: 'reload'
|
||||
action: 'reload',
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -168,7 +184,7 @@ Loader.stop = function () {
|
||||
killWorkers();
|
||||
|
||||
// Clean up the pidfile
|
||||
fs.unlinkSync(__dirname + '/pidfile');
|
||||
fs.unlinkSync(pidFilePath);
|
||||
};
|
||||
|
||||
function killWorkers() {
|
||||
@@ -206,16 +222,16 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) {
|
||||
|
||||
require('daemon')({
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr
|
||||
stderr: process.stderr,
|
||||
});
|
||||
|
||||
fs.writeFile(__dirname + '/pidfile', process.pid);
|
||||
fs.writeFileSync(pidFilePath, process.pid);
|
||||
}
|
||||
|
||||
async.series([
|
||||
Loader.init,
|
||||
Loader.displayStartupMessages,
|
||||
Loader.start
|
||||
Loader.start,
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.log('[loader] Error during startup: ' + err.message);
|
||||
@@ -223,6 +239,6 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) {
|
||||
});
|
||||
} else {
|
||||
// No config detected, kickstart web installer
|
||||
var child = require('child_process').fork('app');
|
||||
require('child_process').fork('app');
|
||||
}
|
||||
});
|
||||
|
||||
811
nodebb
811
nodebb
@@ -1,15 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var cproc;
|
||||
var args;
|
||||
var fs;
|
||||
var path;
|
||||
var request;
|
||||
var semver;
|
||||
var prompt;
|
||||
var async;
|
||||
|
||||
try {
|
||||
var colors = require('colors'),
|
||||
cproc = require('child_process'),
|
||||
argv = require('minimist')(process.argv.slice(2)),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
request = require('request'),
|
||||
semver = require('semver'),
|
||||
prompt = require('prompt'),
|
||||
async = require('async');
|
||||
require('colors');
|
||||
cproc = require('child_process');
|
||||
args = require('minimist')(process.argv.slice(2));
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
request = require('request');
|
||||
semver = require('semver');
|
||||
prompt = require('prompt');
|
||||
async = require('async');
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
process.stdout.write('NodeBB could not be started because it\'s dependencies have not been installed.\n');
|
||||
@@ -21,407 +32,473 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
var getRunningPid = function (callback) {
|
||||
fs.readFile(__dirname + '/pidfile', {
|
||||
encoding: 'utf-8'
|
||||
}, function (err, pid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
var loaderPath = path.join(__dirname, 'loader.js');
|
||||
var appPath = path.join(__dirname, 'app.js');
|
||||
|
||||
if (args.dev) {
|
||||
process.env.NODE_ENV = 'development';
|
||||
}
|
||||
|
||||
function getRunningPid(callback) {
|
||||
fs.readFile(path.join(__dirname, 'pidfile'), {
|
||||
encoding: 'utf-8',
|
||||
}, function (err, pid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
process.kill(parseInt(pid, 10), 0);
|
||||
callback(null, parseInt(pid, 10));
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getCurrentVersion(callback) {
|
||||
fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg);
|
||||
return callback(null, pkg.version);
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
function fork(args) {
|
||||
return cproc.fork(appPath, args, {
|
||||
cwd: __dirname,
|
||||
silent: false,
|
||||
});
|
||||
}
|
||||
function getInstalledPlugins(callback) {
|
||||
async.parallel({
|
||||
files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')),
|
||||
deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' }),
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/;
|
||||
var moduleName;
|
||||
var isGitRepo;
|
||||
|
||||
payload.files = payload.files.filter(function (file) {
|
||||
return isNbbModule.test(file);
|
||||
});
|
||||
|
||||
try {
|
||||
payload.deps = JSON.parse(payload.deps).dependencies;
|
||||
payload.bundled = [];
|
||||
payload.installed = [];
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
for (moduleName in payload.deps) {
|
||||
if (isNbbModule.test(moduleName)) {
|
||||
payload.bundled.push(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
// Whittle down deps to send back only extraneously installed plugins/themes/etc
|
||||
payload.files.forEach(function (moduleName) {
|
||||
try {
|
||||
fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git'));
|
||||
isGitRepo = true;
|
||||
} catch (e) {
|
||||
isGitRepo = false;
|
||||
}
|
||||
|
||||
try {
|
||||
process.kill(parseInt(pid, 10), 0);
|
||||
callback(null, parseInt(pid, 10));
|
||||
} catch(e) {
|
||||
callback(e);
|
||||
if (
|
||||
payload.files.indexOf(moduleName) !== -1 && // found in `node_modules/`
|
||||
payload.bundled.indexOf(moduleName) === -1 && // not found in `package.json`
|
||||
!fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() && // is not a symlink
|
||||
!isGitRepo // .git/ does not exist, so it is not a git repository
|
||||
) {
|
||||
payload.installed.push(moduleName);
|
||||
}
|
||||
});
|
||||
},
|
||||
getCurrentVersion = function (callback) {
|
||||
fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
|
||||
getModuleVersions(payload.installed, callback);
|
||||
});
|
||||
}
|
||||
function getModuleVersions(modules, callback) {
|
||||
var versionHash = {};
|
||||
|
||||
async.eachLimit(modules, 50, function (module, next) {
|
||||
fs.readFile(path.join(__dirname, 'node_modules/' + module + '/package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return next(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg);
|
||||
return callback(null, pkg.version);
|
||||
} catch(err) {
|
||||
return callback(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
fork = function (args) {
|
||||
cproc.fork('app.js', args, {
|
||||
cwd: __dirname,
|
||||
silent: false
|
||||
});
|
||||
},
|
||||
getInstalledPlugins = function (callback) {
|
||||
async.parallel({
|
||||
files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')),
|
||||
deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' })
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w\-]+$/,
|
||||
moduleName, isGitRepo;
|
||||
|
||||
payload.files = payload.files.filter(function (file) {
|
||||
return isNbbModule.test(file);
|
||||
});
|
||||
|
||||
try {
|
||||
payload.deps = JSON.parse(payload.deps).dependencies;
|
||||
payload.bundled = [];
|
||||
payload.installed = [];
|
||||
versionHash[module] = pkg.version;
|
||||
next();
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
next(err);
|
||||
}
|
||||
|
||||
for (moduleName in payload.deps) {
|
||||
if (isNbbModule.test(moduleName)) {
|
||||
payload.bundled.push(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
// Whittle down deps to send back only extraneously installed plugins/themes/etc
|
||||
payload.files.forEach(function (moduleName) {
|
||||
try {
|
||||
fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git'));
|
||||
isGitRepo = true;
|
||||
} catch(e) {
|
||||
isGitRepo = false;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.files.indexOf(moduleName) !== -1 // found in `node_modules/`
|
||||
&& payload.bundled.indexOf(moduleName) === -1 // not found in `package.json`
|
||||
&& !fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() // is not a symlink
|
||||
&& !isGitRepo // .git/ does not exist, so it is not a git repository
|
||||
) {
|
||||
payload.installed.push(moduleName);
|
||||
}
|
||||
});
|
||||
|
||||
getModuleVersions(payload.installed, callback);
|
||||
});
|
||||
},
|
||||
getModuleVersions = function (modules, callback) {
|
||||
var versionHash = {};
|
||||
}, function (err) {
|
||||
callback(err, versionHash);
|
||||
});
|
||||
}
|
||||
function checkPlugins(standalone, callback) {
|
||||
if (standalone) {
|
||||
process.stdout.write('Checking installed plugins and themes for updates... ');
|
||||
}
|
||||
|
||||
async.eachLimit(modules, 50, function (module, next) {
|
||||
fs.readFile(path.join(__dirname, 'node_modules/' + module + '/package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||
async.waterfall([
|
||||
async.apply(async.parallel, {
|
||||
plugins: async.apply(getInstalledPlugins),
|
||||
version: async.apply(getCurrentVersion),
|
||||
}),
|
||||
function (payload, next) {
|
||||
var toCheck = Object.keys(payload.plugins);
|
||||
|
||||
if (!toCheck.length) {
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
return next(null, []); // no extraneous plugins installed
|
||||
}
|
||||
|
||||
request({
|
||||
method: 'GET',
|
||||
url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='),
|
||||
json: true,
|
||||
}, function (err, res, body) {
|
||||
if (err) {
|
||||
process.stdout.write('error'.red + '\n'.reset);
|
||||
return next(err);
|
||||
}
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
|
||||
try {
|
||||
pkg = JSON.parse(pkg);
|
||||
versionHash[module] = pkg.version;
|
||||
next();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
if (!Array.isArray(body) && toCheck.length === 1) {
|
||||
body = [body];
|
||||
}
|
||||
|
||||
var current;
|
||||
var suggested;
|
||||
var upgradable = body.map(function (suggestObj) {
|
||||
current = payload.plugins[suggestObj.package];
|
||||
suggested = suggestObj.version;
|
||||
|
||||
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
|
||||
return {
|
||||
name: suggestObj.package,
|
||||
current: current,
|
||||
suggested: suggested,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean);
|
||||
|
||||
next(null, upgradable);
|
||||
});
|
||||
}, function (err) {
|
||||
callback(err, versionHash);
|
||||
});
|
||||
},
|
||||
checkPlugins = function (standalone, callback) {
|
||||
if (standalone) {
|
||||
process.stdout.write('Checking installed plugins and themes for updates... ');
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
function upgradePlugins(callback) {
|
||||
var standalone = false;
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function () {};
|
||||
standalone = true;
|
||||
}
|
||||
|
||||
checkPlugins(standalone, function (err, found) {
|
||||
if (err) {
|
||||
process.stdout.write('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
async.apply(async.parallel, {
|
||||
plugins: async.apply(getInstalledPlugins),
|
||||
version: async.apply(getCurrentVersion)
|
||||
}),
|
||||
function (payload, next) {
|
||||
var toCheck = Object.keys(payload.plugins);
|
||||
|
||||
if (!toCheck.length) {
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
return next(null, []); // no extraneous plugins installed
|
||||
}
|
||||
|
||||
request({
|
||||
method: 'GET',
|
||||
url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='),
|
||||
json: true
|
||||
}, function (err, res, body) {
|
||||
if (err) {
|
||||
process.stdout.write('error'.red + '\n'.reset);
|
||||
return next(err);
|
||||
}
|
||||
process.stdout.write('OK'.green + '\n'.reset);
|
||||
|
||||
if (!Array.isArray(body) && toCheck.length === 1) {
|
||||
body = [body];
|
||||
}
|
||||
|
||||
var current, suggested,
|
||||
upgradable = body.map(function (suggestObj) {
|
||||
current = payload.plugins[suggestObj.package];
|
||||
suggested = suggestObj.version;
|
||||
|
||||
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
|
||||
return {
|
||||
name: suggestObj.package,
|
||||
current: current,
|
||||
suggested: suggested
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}).filter(Boolean);
|
||||
|
||||
next(null, upgradable);
|
||||
});
|
||||
if (found && found.length) {
|
||||
process.stdout.write('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:\n');
|
||||
found.forEach(function (suggestObj) {
|
||||
process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset);
|
||||
});
|
||||
process.stdout.write('\n');
|
||||
} else {
|
||||
if (standalone) {
|
||||
process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset);
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
upgradePlugins = function (callback) {
|
||||
var standalone = false;
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function () {};
|
||||
standalone = true;
|
||||
};
|
||||
return callback();
|
||||
}
|
||||
|
||||
checkPlugins(standalone, function (err, found) {
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
|
||||
prompt.start();
|
||||
prompt.get({
|
||||
name: 'upgrade',
|
||||
description: 'Proceed with upgrade (y|n)?'.reset,
|
||||
type: 'string',
|
||||
}, function (err, result) {
|
||||
if (err) {
|
||||
process.stdout.write('\Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (found && found.length) {
|
||||
process.stdout.write('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:\n');
|
||||
if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) {
|
||||
process.stdout.write('\nUpgrading packages...');
|
||||
var args = ['i'];
|
||||
found.forEach(function (suggestObj) {
|
||||
process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset);
|
||||
args.push(suggestObj.name + '@' + suggestObj.suggested);
|
||||
});
|
||||
|
||||
cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', args, { stdio: 'ignore' }, function (err) {
|
||||
if (!err) {
|
||||
process.stdout.write(' OK\n'.green);
|
||||
}
|
||||
|
||||
callback(err);
|
||||
});
|
||||
process.stdout.write('\n');
|
||||
} else {
|
||||
if (standalone) {
|
||||
process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset);
|
||||
}
|
||||
return callback();
|
||||
process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
|
||||
prompt.start();
|
||||
prompt.get({
|
||||
name: 'upgrade',
|
||||
description: 'Proceed with upgrade (y|n)?'.reset,
|
||||
type: 'string'
|
||||
}, function (err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) {
|
||||
process.stdout.write('\nUpgrading packages...');
|
||||
var args = ['npm', 'i'];
|
||||
found.forEach(function (suggestObj) {
|
||||
args.push(suggestObj.name + '@' + suggestObj.suggested);
|
||||
});
|
||||
|
||||
require('child_process').execFile('/usr/bin/env', args, { stdio: 'ignore' }, function (err) {
|
||||
if (!err) {
|
||||
process.stdout.write(' OK\n'.green);
|
||||
}
|
||||
|
||||
callback(err);
|
||||
});
|
||||
var commands = {
|
||||
status: {
|
||||
description: 'View the status of the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb status'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.stdout.write('\nNodeBB Running '.bold + '(pid '.cyan + pid.toString().cyan + ')\n'.cyan);
|
||||
process.stdout.write('\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write('\t"' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write('\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n\n');
|
||||
} else {
|
||||
process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset);
|
||||
callback();
|
||||
process.stdout.write('\nNodeBB is not running\n'.bold);
|
||||
process.stdout.write('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n\n'.reset);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
},
|
||||
},
|
||||
start: {
|
||||
description: 'Start the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb start'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nStarting NodeBB\n'.bold);
|
||||
process.stdout.write(' "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write(' "' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset);
|
||||
|
||||
switch(process.argv[2]) {
|
||||
case 'status':
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.stdout.write('\nNodeBB Running '.bold + '(pid '.cyan + pid.toString().cyan + ')\n'.cyan);
|
||||
process.stdout.write('\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write('\t"' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write('\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n\n');
|
||||
} else {
|
||||
process.stdout.write('\nNodeBB is not running\n'.bold);
|
||||
process.stdout.write('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n\n'.reset);
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(loaderPath, {
|
||||
env: process.env,
|
||||
});
|
||||
},
|
||||
},
|
||||
stop: {
|
||||
description: 'Stop the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb stop'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGTERM');
|
||||
process.stdout.write('Stopping NodeBB. Goodbye!\n');
|
||||
} else {
|
||||
process.stdout.write('NodeBB is already stopped.\n');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
restart: {
|
||||
description: 'Restart the NodeBB server',
|
||||
usage: 'Usage: ' + './nodebb restart'.yellow,
|
||||
handler: function () {
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGHUP');
|
||||
process.stdout.write('\nRestarting NodeBB\n'.bold);
|
||||
} else {
|
||||
process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
log: {
|
||||
description: 'Open the output log (useful for debugging)',
|
||||
usage: 'Usage: ' + './nodebb log'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
},
|
||||
},
|
||||
slog: {
|
||||
description: 'Start the NodeBB server and view the live output log',
|
||||
usage: 'Usage: ' + './nodebb slog'.yellow,
|
||||
handler: function () {
|
||||
process.stdout.write('\nStarting NodeBB with logging output\n'.bold);
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(loaderPath, {
|
||||
env: process.env,
|
||||
});
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
description: 'Start NodeBB in verbose development mode',
|
||||
usage: 'Usage: ' + './nodebb dev'.yellow,
|
||||
handler: function () {
|
||||
process.env.NODE_ENV = 'development';
|
||||
cproc.fork(loaderPath, ['--no-daemon', '--no-silent'], {
|
||||
env: process.env,
|
||||
});
|
||||
},
|
||||
},
|
||||
build: {
|
||||
description: 'Compile static assets (CSS, Javascript, etc)',
|
||||
usage: 'Usage: ' + './nodebb build'.yellow + ' [js,clientCSS,acpCSS,tpl,lang]'.red + '\n' +
|
||||
' e.g. ' + './nodebb build js,tpl'.yellow + '\tbuilds JS and templates\n' +
|
||||
' ' + './nodebb build'.yellow + '\t\tbuilds all targets\n',
|
||||
handler: function () {
|
||||
var arr = ['--build'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
setup: {
|
||||
description: 'Run the NodeBB setup script',
|
||||
usage: 'Usage: ' + './nodebb setup'.yellow,
|
||||
handler: function () {
|
||||
var arr = ['--setup'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
reset: {
|
||||
description: 'Disable plugins and restore the default theme',
|
||||
usage: 'Usage: ' + './nodebb reset '.yellow + '{-t|-p|-w|-s|-a}'.red + '\n' +
|
||||
' -t <theme>\tuse specified theme\n' +
|
||||
' -p <plugin>\tdisable specified plugin\n' +
|
||||
'\n' +
|
||||
' -t\t\tuse default theme\n' +
|
||||
' -p\t\tdisable all but core plugins\n' +
|
||||
' -w\t\twidgets\n' +
|
||||
' -s\t\tsettings\n' +
|
||||
' -a\t\tall of the above\n',
|
||||
handler: function () {
|
||||
var arr = ['--reset'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
activate: {
|
||||
description: 'Activate a plugin for the next startup of NodeBB',
|
||||
usage: 'Usage: ' + './nodebb activate <plugin>'.yellow,
|
||||
handler: function () {
|
||||
var name = args._[1];
|
||||
if (!name) {
|
||||
process.stdout.write(commands.activate.usage + '\n');
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'start':
|
||||
process.stdout.write('\nStarting NodeBB\n'.bold);
|
||||
process.stdout.write(' "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||
process.stdout.write(' "' + './nodebb log'.yellow + '" to view server output\n');
|
||||
process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset);
|
||||
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(__dirname + '/loader.js', {
|
||||
env: process.env
|
||||
});
|
||||
break;
|
||||
|
||||
case 'slog':
|
||||
process.stdout.write('\nStarting NodeBB with logging output\n'.bold);
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
|
||||
// Spawn a new NodeBB process
|
||||
cproc.fork(__dirname + '/loader.js', {
|
||||
env: process.env
|
||||
});
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
break;
|
||||
|
||||
case 'stop':
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGTERM');
|
||||
process.stdout.write('Stopping NodeBB. Goodbye!\n');
|
||||
} else {
|
||||
process.stdout.write('NodeBB is already stopped.\n');
|
||||
if (name.startsWith('nodebb-theme')) {
|
||||
fork(['--reset', '-t', name]);
|
||||
return;
|
||||
}
|
||||
});
|
||||
break;
|
||||
var arr = ['--activate=' + name].concat(process.argv.slice(4));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
description: 'List all installed plugins',
|
||||
usage: 'Usage: ' + './nodebb plugins'.yellow,
|
||||
handler: function () {
|
||||
var arr = ['--plugins'].concat(process.argv.slice(3));
|
||||
fork(arr);
|
||||
},
|
||||
},
|
||||
upgrade: {
|
||||
description: 'Run NodeBB upgrade scripts, ensure packages are up-to-date',
|
||||
usage: 'Usage: ' + './nodebb upgrade'.yellow,
|
||||
handler: function () {
|
||||
async.series([
|
||||
function (next) {
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow);
|
||||
cproc.exec('npm i --production', { cwd: __dirname, stdio: 'ignore' }, next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow);
|
||||
upgradePlugins(next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow);
|
||||
var arr = ['--upgrade'].concat(process.argv.slice(3));
|
||||
var upgradeProc = fork(arr);
|
||||
|
||||
case 'restart':
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGHUP');
|
||||
process.stdout.write('\nRestarting NodeBB\n'.bold);
|
||||
} else {
|
||||
process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n');
|
||||
upgradeProc.on('close', next);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
|
||||
} else {
|
||||
var message = 'NodeBB Upgrade Complete!';
|
||||
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||
var columns = process.stdout.columns;
|
||||
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
upgradePlugins: {
|
||||
hidden: true,
|
||||
description: '',
|
||||
handler: function () {
|
||||
upgradePlugins();
|
||||
},
|
||||
},
|
||||
help: {
|
||||
description: 'Display the help message for a given command',
|
||||
usage: 'Usage: ' + './nodebb help <command>'.yellow,
|
||||
handler: function () {
|
||||
var command = commands[args._[1]];
|
||||
if (command) {
|
||||
process.stdout.write(command.description + '\n'.reset);
|
||||
process.stdout.write(command.usage + '\n'.reset);
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
break;
|
||||
var keys = Object.keys(commands).filter(function (key) {
|
||||
return !commands[key].hidden;
|
||||
});
|
||||
|
||||
case 'reload':
|
||||
getRunningPid(function (err, pid) {
|
||||
if (!err) {
|
||||
process.kill(pid, 'SIGUSR2');
|
||||
} else {
|
||||
process.stdout.write('NodeBB could not be reloaded, as a running instance could not be found.\n');
|
||||
}
|
||||
});
|
||||
break;
|
||||
process.stdout.write('\nWelcome to NodeBB\n\n'.bold);
|
||||
process.stdout.write('Usage: ./nodebb {' + keys.join('|') + '}\n\n');
|
||||
|
||||
case 'dev':
|
||||
process.env.NODE_ENV = 'development';
|
||||
cproc.fork(__dirname + '/loader.js', ['--no-daemon', '--no-silent'], {
|
||||
env: process.env
|
||||
});
|
||||
break;
|
||||
var usage = keys.map(function (key) {
|
||||
var line = '\t' + key.yellow + (key.length < 8 ? '\t\t' : '\t');
|
||||
return line + commands[key].description;
|
||||
}).join('\n');
|
||||
|
||||
case 'log':
|
||||
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||
process.stdout.write('\n\n'.reset);
|
||||
cproc.spawn('tail', ['-F', './logs/output.log'], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
break;
|
||||
process.stdout.write(usage + '\n'.reset);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
case 'build':
|
||||
var args = process.argv.slice(0);
|
||||
args[2] = '--' + args[2];
|
||||
commands['upgrade-plugins'] = commands.upgradePlugins;
|
||||
|
||||
fork(args);
|
||||
break;
|
||||
|
||||
case 'setup':
|
||||
cproc.fork('app.js', ['--setup'], {
|
||||
cwd: __dirname,
|
||||
silent: false
|
||||
});
|
||||
break;
|
||||
|
||||
case 'reset':
|
||||
var args = process.argv.slice(0);
|
||||
args.unshift('--reset');
|
||||
fork(args);
|
||||
break;
|
||||
|
||||
case 'activate':
|
||||
var args = process.argv.slice(0);
|
||||
args.unshift('--activate=' + process.argv[3]);
|
||||
fork(args);
|
||||
break;
|
||||
|
||||
case 'plugins':
|
||||
var args = process.argv.slice(0);
|
||||
args.unshift('--plugins');
|
||||
fork(args);
|
||||
break;
|
||||
|
||||
case 'upgrade-plugins':
|
||||
upgradePlugins();
|
||||
break;
|
||||
|
||||
case 'upgrade':
|
||||
async.series([
|
||||
function (next) {
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow);
|
||||
require('child_process').execFile('/usr/bin/env', ['npm', 'i', '--production'], { stdio: 'ignore' }, next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow);
|
||||
upgradePlugins(next);
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow);
|
||||
var upgradeProc = cproc.fork('app.js', ['--upgrade'], {
|
||||
cwd: __dirname,
|
||||
silent: false
|
||||
});
|
||||
|
||||
upgradeProc.on('close', next);
|
||||
}
|
||||
], function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
|
||||
} else {
|
||||
var message = 'NodeBB Upgrade Complete!';
|
||||
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||
var columns = process.stdout.columns;
|
||||
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : " ";
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
process.stdout.write('\nWelcome to NodeBB\n\n'.bold);
|
||||
process.stdout.write('Usage: ./nodebb {start|slog|stop|reload|restart|log|build|setup|reset|upgrade|dev}\n\n');
|
||||
process.stdout.write('\t' + 'start'.yellow + '\t\tStart the NodeBB server\n');
|
||||
process.stdout.write('\t' + 'slog'.yellow + '\t\tStarts the NodeBB server and displays the live output log\n');
|
||||
process.stdout.write('\t' + 'stop'.yellow + '\t\tStops the NodeBB server\n');
|
||||
process.stdout.write('\t' + 'reload'.yellow + '\t\tRestarts NodeBB\n');
|
||||
process.stdout.write('\t' + 'restart'.yellow + '\t\tRestarts NodeBB\n');
|
||||
process.stdout.write('\t' + 'log'.yellow + '\t\tOpens the logging interface (useful for debugging)\n');
|
||||
process.stdout.write('\t' + 'build'.yellow + '\t\tCompiles javascript, css stylesheets, and templates\n');
|
||||
process.stdout.write('\t' + 'setup'.yellow + '\t\tRuns the NodeBB setup script\n');
|
||||
process.stdout.write('\t' + 'reset'.yellow + '\t\tDisables all plugins, restores the default theme.\n');
|
||||
process.stdout.write('\t' + 'activate'.yellow + '\tActivates a plugin for the next startup of NodeBB.\n');
|
||||
process.stdout.write('\t' + 'plugins'.yellow + '\t\tList all plugins that have been installed.\n');
|
||||
process.stdout.write('\t' + 'upgrade'.yellow + '\t\tRun NodeBB upgrade scripts, ensure packages are up-to-date\n');
|
||||
process.stdout.write('\t' + 'dev'.yellow + '\t\tStart NodeBB in interactive development mode\n');
|
||||
process.stdout.write('\n'.reset);
|
||||
break;
|
||||
if (!commands[args._[0]]) {
|
||||
commands.help.handler();
|
||||
} else {
|
||||
commands[args._[0]].handler();
|
||||
}
|
||||
|
||||
53
package.json
53
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.6",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -11,17 +11,19 @@
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node loader.js",
|
||||
"lint": "eslint --cache .",
|
||||
"lint": "eslint --cache ./nodebb .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
|
||||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "^1.2.6",
|
||||
"async": "~1.5.0",
|
||||
"autoprefixer": "^6.2.3",
|
||||
"bcryptjs": "~2.3.0",
|
||||
"body-parser": "^1.9.0",
|
||||
"chart.js": "^2.1.0",
|
||||
"bootstrap": "^3.3.7",
|
||||
"chart.js": "^2.4.0",
|
||||
"colors": "^1.1.0",
|
||||
"compression": "^1.1.0",
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
@@ -31,11 +33,12 @@
|
||||
"connect-redis": "~3.1.0",
|
||||
"cookie-parser": "^1.3.3",
|
||||
"cron": "^1.0.5",
|
||||
"cropperjs": "^0.8.1",
|
||||
"csurf": "^1.6.1",
|
||||
"daemon": "~1.1.0",
|
||||
"express": "^4.14.0",
|
||||
"express-session": "^1.8.2",
|
||||
"express-useragent": "1.0.4",
|
||||
"express-useragent": "1.0.7",
|
||||
"html-to-text": "2.1.3",
|
||||
"ip": "1.1.3",
|
||||
"jimp": "0.2.27",
|
||||
@@ -47,22 +50,22 @@
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.1.1",
|
||||
"mkdirp": "~0.5.0",
|
||||
"mongodb": "2.2.16",
|
||||
"mongodb": "2.2.25",
|
||||
"morgan": "^1.3.2",
|
||||
"mousetrap": "^1.5.3",
|
||||
"nconf": "~0.8.2",
|
||||
"nodebb-plugin-composer-default": "4.3.4",
|
||||
"nodebb-plugin-dbsearch": "1.0.4",
|
||||
"nodebb-plugin-composer-default": "4.4.6",
|
||||
"nodebb-plugin-dbsearch": "1.0.5",
|
||||
"nodebb-plugin-emoji-extended": "1.1.1",
|
||||
"nodebb-plugin-emoji-one": "1.1.5",
|
||||
"nodebb-plugin-markdown": "7.0.1",
|
||||
"nodebb-plugin-markdown": "7.1.1",
|
||||
"nodebb-plugin-mentions": "1.1.3",
|
||||
"nodebb-plugin-soundpack-default": "0.1.6",
|
||||
"nodebb-plugin-spam-be-gone": "0.4.10",
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.4.13",
|
||||
"nodebb-rewards-essentials": "0.0.9",
|
||||
"nodebb-theme-lavender": "3.0.15",
|
||||
"nodebb-theme-persona": "4.1.89",
|
||||
"nodebb-theme-vanilla": "5.1.57",
|
||||
"nodebb-theme-lavender": "4.0.0",
|
||||
"nodebb-theme-persona": "4.2.10",
|
||||
"nodebb-theme-vanilla": "5.2.1",
|
||||
"nodebb-widget-essentials": "2.0.13",
|
||||
"nodemailer": "2.6.4",
|
||||
"nodemailer-sendmail-transport": "1.0.0",
|
||||
@@ -81,31 +84,31 @@
|
||||
"semver": "^5.1.0",
|
||||
"serve-favicon": "^2.1.5",
|
||||
"sitemap": "^1.4.0",
|
||||
"socket.io": "1.7.1",
|
||||
"socket.io-client": "1.7.1",
|
||||
"socket.io-redis": "2.0.0",
|
||||
"socket.io": "1.7.2",
|
||||
"socket.io-client": "1.7.2",
|
||||
"socket.io-redis": "3.1.0",
|
||||
"socketio-wildcard": "~0.3.0",
|
||||
"string": "^3.0.0",
|
||||
"templates.js": "0.3.5",
|
||||
"templates.js": "0.3.10",
|
||||
"toobusy-js": "^0.5.1",
|
||||
"uglify-js": "^2.6.0",
|
||||
"underscore": "^1.8.3",
|
||||
"underscore.deep": "^0.5.1",
|
||||
"validator": "^6.1.0",
|
||||
"winston": "^2.1.0",
|
||||
"xregexp": "~3.1.0"
|
||||
"xml": "^1.0.1",
|
||||
"xregexp": "~3.1.0",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.14",
|
||||
"eslint": "^3.7.1",
|
||||
"eslint-config-airbnb": "^12.0.0",
|
||||
"eslint-plugin-import": "^1.16.0",
|
||||
"eslint-plugin-jsx-a11y": "^2.2.3",
|
||||
"eslint-plugin-react": "^6.4.1",
|
||||
"grunt": "~0.4.5",
|
||||
"eslint": "^3.12.0",
|
||||
"eslint-config-airbnb-base": "^11.1.0",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"grunt": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"istanbul": "^0.4.2",
|
||||
"mocha": "~3.1.0",
|
||||
"mocha": "~3.2.0",
|
||||
"mocha-lcov-reporter": "^1.2.0",
|
||||
"xmlhttprequest": "1.8.0",
|
||||
"xmlhttprequest-ssl": "1.5.3"
|
||||
|
||||
58
public/.eslintrc
Normal file
58
public/.eslintrc
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"globals": {
|
||||
"app": true,
|
||||
"io": true,
|
||||
"socket": true,
|
||||
"ajaxify": true,
|
||||
"config": true,
|
||||
"RELATIVE_PATH": true,
|
||||
"utils": true,
|
||||
"overrides": true,
|
||||
"componentHandler": true,
|
||||
"bootbox": true,
|
||||
"templates": true,
|
||||
"Visibility": true,
|
||||
"Tinycon": true,
|
||||
"Promise": true
|
||||
},
|
||||
"env": {
|
||||
"jquery": true,
|
||||
"amd": true,
|
||||
"browser": true,
|
||||
"es6": false
|
||||
},
|
||||
"rules": {
|
||||
"no-dupe-class-members": "off",
|
||||
"no-var": "off",
|
||||
"object-shorthand": "off",
|
||||
"prefer-arrow-callback": "off",
|
||||
"prefer-spread": "off",
|
||||
"prefer-reflect": "off",
|
||||
"prefer-template": "off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5,
|
||||
"ecmaFeatures": {
|
||||
"arrowFunctions": false,
|
||||
"classes": false,
|
||||
"defaultParams": false,
|
||||
"destructuring": 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,
|
||||
"spread": false,
|
||||
"superInFunctions": false,
|
||||
"templateStrings": false
|
||||
}
|
||||
}
|
||||
}
|
||||
84
public/.jshintrc
Normal file
84
public/.jshintrc
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"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,
|
||||
"RELATIVE_PATH": 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
|
||||
}
|
||||
7
public/language/ar/admin/admin.json
Normal file
7
public/language/ar/admin/admin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"alert.confirm-reload": "Are you sure you wish to reload NodeBB?",
|
||||
"alert.confirm-restart": "Are you sure you wish to restart NodeBB?",
|
||||
|
||||
"acp-title": "%1 | NodeBB Admin Control Panel",
|
||||
"settings-header-contents": "Contents"
|
||||
}
|
||||
11
public/language/ar/admin/advanced/cache.json
Normal file
11
public/language/ar/admin/advanced/cache.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"post-cache": "Post Cache",
|
||||
"posts-in-cache": "Posts in Cache",
|
||||
"average-post-size": "Average Post Size",
|
||||
"length-to-max": "Length / Max",
|
||||
"percent-full": "%1% Full",
|
||||
"post-cache-size": "Post Cache Size",
|
||||
"items-in-cache": "Items in Cache",
|
||||
"control-panel": "Control Panel",
|
||||
"update-settings": "Update Cache Settings"
|
||||
}
|
||||
35
public/language/ar/admin/advanced/database.json
Normal file
35
public/language/ar/admin/advanced/database.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"x-b": "%1 b",
|
||||
"x-mb": "%1 mb",
|
||||
"uptime-seconds": "Uptime in Seconds",
|
||||
"uptime-days": "Uptime in Days",
|
||||
|
||||
"mongo": "Mongo",
|
||||
"mongo.version": "MongoDB Version",
|
||||
"mongo.storage-engine": "Storage Engine",
|
||||
"mongo.collections": "Collections",
|
||||
"mongo.objects": "Objects",
|
||||
"mongo.avg-object-size": "Avg. Object Size",
|
||||
"mongo.data-size": "Data Size",
|
||||
"mongo.storage-size": "Storage Size",
|
||||
"mongo.index-size": "Index Size",
|
||||
"mongo.file-size": "File Size",
|
||||
"mongo.resident-memory": "Resident Memory",
|
||||
"mongo.virtual-memory": "Virtual Memory",
|
||||
"mongo.mapped-memory": "Mapped Memory",
|
||||
"mongo.raw-info": "MongoDB Raw Info",
|
||||
|
||||
"redis": "Redis",
|
||||
"redis.version": "Redis Version",
|
||||
"redis.connected-clients": "Connected Clients",
|
||||
"redis.connected-slaves": "Connected Slaves",
|
||||
"redis.blocked-clients": "Blocked Clients",
|
||||
"redis.used-memory": "Used Memory",
|
||||
"redis.memory-frag-ratio": "Memory Fragmentation Ratio",
|
||||
"redis.total-connections-recieved": "Total Connections Received",
|
||||
"redis.total-commands-processed": "Total Commands Processed",
|
||||
"redis.iops": "Instantaneous Ops. Per Second",
|
||||
"redis.keyspace-hits": "Keyspace Hits",
|
||||
"redis.keyspace-misses": "Keyspace Misses",
|
||||
"redis.raw-info": "Redis Raw Info"
|
||||
}
|
||||
14
public/language/ar/admin/advanced/errors.json
Normal file
14
public/language/ar/admin/advanced/errors.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"figure-x": "Figure %1",
|
||||
"error-events-per-day": "<code>%1</code> events per day",
|
||||
"error.404": "404 Not Found",
|
||||
"error.503": "503 Service Unavailable",
|
||||
"manage-error-log": "Manage Error Log",
|
||||
"export-error-log": "Export Error Log (CSV)",
|
||||
"clear-error-log": "Clear Error Log",
|
||||
"route": "Route",
|
||||
"count": "Count",
|
||||
"no-routes-not-found": "Hooray! No 404 errors!",
|
||||
"clear404-confirm": "Are you sure you wish to clear the 404 error logs?",
|
||||
"clear404-success": "\"404 Not Found\" errors cleared"
|
||||
}
|
||||
6
public/language/ar/admin/advanced/events.json
Normal file
6
public/language/ar/admin/advanced/events.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"events": "Events",
|
||||
"no-events": "There are no events",
|
||||
"control-panel": "Events Control Panel",
|
||||
"delete-events": "Delete Events"
|
||||
}
|
||||
7
public/language/ar/admin/advanced/logs.json
Normal file
7
public/language/ar/admin/advanced/logs.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"logs": "Logs",
|
||||
"control-panel": "Logs Control Panel",
|
||||
"reload": "Reload Logs",
|
||||
"clear": "Clear Logs",
|
||||
"clear-success": "Logs Cleared!"
|
||||
}
|
||||
9
public/language/ar/admin/appearance/customise.json
Normal file
9
public/language/ar/admin/appearance/customise.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"custom-css": "Custom CSS",
|
||||
"custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.",
|
||||
"custom-css.enable": "Enable Custom CSS",
|
||||
|
||||
"custom-header": "Custom Header",
|
||||
"custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <code><head></code> section of your forum's markup.",
|
||||
"custom-header.enable": "Enable Custom Header"
|
||||
}
|
||||
9
public/language/ar/admin/appearance/skins.json
Normal file
9
public/language/ar/admin/appearance/skins.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"loading": "Loading Skins...",
|
||||
"homepage": "Homepage",
|
||||
"select-skin": "Select Skin",
|
||||
"current-skin": "Current Skin",
|
||||
"skin-updated": "Skin Updated",
|
||||
"applied-success": "%1 skin was succesfully applied",
|
||||
"revert-success": "Skin reverted to base colours"
|
||||
}
|
||||
11
public/language/ar/admin/appearance/themes.json
Normal file
11
public/language/ar/admin/appearance/themes.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"checking-for-installed": "Checking for installed themes...",
|
||||
"homepage": "Homepage",
|
||||
"select-theme": "Select Theme",
|
||||
"current-theme": "Current Theme",
|
||||
"no-themes": "No installed themes found",
|
||||
"revert-confirm": "Are you sure you wish to restore the default NodeBB theme?",
|
||||
"theme-changed": "Theme Changed",
|
||||
"revert-success": "You have successfully reverted your NodeBB back to it's default theme.",
|
||||
"restart-to-activate": "Please restart your NodeBB to fully activate this theme"
|
||||
}
|
||||
16
public/language/ar/admin/development/info.json
Normal file
16
public/language/ar/admin/development/info.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"you-are-on": "Info - You are on <strong>%1:%2</strong>",
|
||||
"host": "host",
|
||||
"pid": "pid",
|
||||
"nodejs": "nodejs",
|
||||
"online": "online",
|
||||
"git": "git",
|
||||
"load": "load",
|
||||
"uptime": "uptime",
|
||||
|
||||
"registered": "Registered",
|
||||
"sockets": "Sockets",
|
||||
"guests": "Guests",
|
||||
|
||||
"info": "Info"
|
||||
}
|
||||
12
public/language/ar/admin/development/logger.json
Normal file
12
public/language/ar/admin/development/logger.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"logger-settings": "Logger Settings",
|
||||
"description": "By enabling the check boxes, you will receive logs to your terminal. If you specify a path, logs will then be saved to a file instead. HTTP logging is useful for collecting statistics about who, when, and what people access on your forum. In addition to logging HTTP requests, we can also log socket.io events. Socket.io logging, in combination with redis-cli monitor, can be very helpful for learning NodeBB's internals.",
|
||||
"explanation": "Simply check/uncheck the logging settings to enable or disable logging on the fly. No restart needed.",
|
||||
"enable-http": "Enable HTTP logging",
|
||||
"enable-socket": "Enable socket.io event logging",
|
||||
"file-path": "Path to log file",
|
||||
"file-path-placeholder": "/path/to/log/file.log ::: leave blank to log to your terminal",
|
||||
|
||||
"control-panel": "Logger Control Panel",
|
||||
"update-settings": "Update Logger Settings"
|
||||
}
|
||||
47
public/language/ar/admin/extend/plugins.json
Normal file
47
public/language/ar/admin/extend/plugins.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"installed": "Installed",
|
||||
"active": "Active",
|
||||
"inactive": "Inactive",
|
||||
"out-of-date": "Out of Date",
|
||||
"none-found": "No plugins found.",
|
||||
"none-active": "No Active Plugins",
|
||||
"find-plugins": "Find Plugins",
|
||||
|
||||
"plugin-search": "Plugin Search",
|
||||
"plugin-search-placeholder": "Search for plugin...",
|
||||
"reorder-plugins": "Re-order Plugins",
|
||||
"order-active": "Order Active Plugins",
|
||||
"dev-interested": "Interested in writing plugins for NodeBB?",
|
||||
"docs-info": "Full documentation regarding plugin authoring can be found in the <a target=\"_blank\" href=\"https://docs.nodebb.org/en/latest/plugins/create.html\">NodeBB Docs Portal</a>.",
|
||||
|
||||
"order.description": "Certain plugins work ideally when they are initialised before/after other plugins.",
|
||||
"order.explanation": "Plugins load in the order specified here, from top to bottom",
|
||||
|
||||
"plugin-item.themes": "Themes",
|
||||
"plugin-item.deactivate": "Deactivate",
|
||||
"plugin-item.activate": "Activate",
|
||||
"plugin-item.install": "Install",
|
||||
"plugin-item.uninstall": "Uninstall",
|
||||
"plugin-item.settings": "Settings",
|
||||
"plugin-item.installed": "Installed",
|
||||
"plugin-item.latest": "Latest",
|
||||
"plugin-item.upgrade": "Upgrade",
|
||||
"plugin-item.more-info": "For more information:",
|
||||
"plugin-item.unknown": "Unknown",
|
||||
"plugin-item.unknown-explanation": "The state of this plugin could not be determined, possibly due to a misconfiguration error.",
|
||||
|
||||
"alert.enabled": "Plugin Enabled",
|
||||
"alert.disabled": "Plugin Disabled",
|
||||
"alert.upgraded": "Plugin Upgraded",
|
||||
"alert.installed": "Plugin Installed",
|
||||
"alert.uninstalled": "Plugin Uninstalled",
|
||||
"alert.activate-success": "Please restart your NodeBB to fully activate this plugin",
|
||||
"alert.deactivate-success": "Plugin successfully deactivated",
|
||||
"alert.upgrade-success": "Please reload your NodeBB to fully upgrade this plugin",
|
||||
"alert.install-success": "Plugin successfully installed, please activate the plugin.",
|
||||
"alert.uninstall-success": "The plugin has been successfully deactivated and uninstalled.",
|
||||
"alert.suggest-error": "<p>NodeBB could not reach the package manager, proceed with installation of latest version?</p><div class=\"alert alert-danger\"><strong>Server returned (%1)</strong>: %2</div>",
|
||||
"alert.package-manager-unreachable": "<p>NodeBB could not reach the package manager, an upgrade is not suggested at this time.</p>",
|
||||
"alert.incompatible": "<p>Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.</p>",
|
||||
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>"
|
||||
}
|
||||
17
public/language/ar/admin/extend/rewards.json
Normal file
17
public/language/ar/admin/extend/rewards.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"rewards": "Rewards",
|
||||
"condition-if-users": "If User's",
|
||||
"condition-is": "Is:",
|
||||
"condition-then": "Then:",
|
||||
"max-claims": "Amount of times reward is claimable",
|
||||
"zero-infinite": "Enter 0 for infinite",
|
||||
"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!",
|
||||
"alert.save-success": "Successfully saved rewards"
|
||||
}
|
||||
19
public/language/ar/admin/extend/widgets.json
Normal file
19
public/language/ar/admin/extend/widgets.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"available": "Available Widgets",
|
||||
"explanation": "Select a widget from the dropdown menu and then drag and drop it into a template's widget area on the left.",
|
||||
"none-installed": "No widgets found! Activate the essential widgets plugin in the <a href=\"%1\">plugins</a> control panel.",
|
||||
"containers.available": "Available Containers",
|
||||
"containers.explanation": "Drag and drop on top of any active widget",
|
||||
"containers.none": "None",
|
||||
"container.well": "Well",
|
||||
"container.jumbotron": "Jumbotron",
|
||||
"container.panel": "Panel",
|
||||
"container.panel-header": "Panel Header",
|
||||
"container.panel-body": "Panel Body",
|
||||
"container.alert": "Alert",
|
||||
|
||||
"alert.confirm-delete": "Are you sure you wish to delete this widget?",
|
||||
"alert.updated": "Widgets Updated",
|
||||
"alert.update-success": "Successfully updated widgets"
|
||||
|
||||
}
|
||||
64
public/language/ar/admin/general/dashboard.json
Normal file
64
public/language/ar/admin/general/dashboard.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"forum-traffic": "Forum Traffic",
|
||||
"page-views": "Page Views",
|
||||
"unique-visitors": "Unique Visitors",
|
||||
"users": "Users",
|
||||
"posts": "Posts",
|
||||
"topics": "Topics",
|
||||
"page-views-last-month": "Page views Last Month",
|
||||
"page-views-this-month": "Page views This Month",
|
||||
"page-views-last-day": "Page views in last 24 hours",
|
||||
|
||||
"stats.day": "Day",
|
||||
"stats.week": "Week",
|
||||
"stats.month": "Month",
|
||||
"stats.all": "All Time",
|
||||
|
||||
"updates": "Updates",
|
||||
"running-version": "You are running <strong>NodeBB v<span id=\"version\">%1</span></strong>.",
|
||||
"keep-updated": "Always make sure that your NodeBB is up to date for the latest security patches and bug fixes.",
|
||||
"up-to-date": "<p>You are <strong>up-to-date</strong> <i class=\"fa fa-check\"></i></p>",
|
||||
"upgrade-available": "<p>A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-upgrade-available": "<p>This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
|
||||
"prerelease-warning": "<p>This is a <strong>pre-release</strong> version of NodeBB. Unintended bugs may occur. <i class=\"fa fa-exclamation-triangle\"></i></p>",
|
||||
"running-in-development": "<span>Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator.</span>",
|
||||
|
||||
"notices": "Notices",
|
||||
"restart-not-required": "Restart not required",
|
||||
"restart-required": "Restart required",
|
||||
"search-plugin-installed": "Search Plugin installed",
|
||||
"search-plugin-not-installed": "Search Plugin not installed",
|
||||
"search-plugin-tooltip": "Install a search plugin from the plugin page in order to activate search functionality",
|
||||
|
||||
"control-panel": "System Control",
|
||||
"reload": "Reload",
|
||||
"restart": "Restart",
|
||||
"restart-warning": "Reloading or Restarting your NodeBB will drop all existing connections for a few seconds.",
|
||||
"maintenance-mode": "Maintenance Mode",
|
||||
"maintenance-mode-title": "Click here to set up maintenance mode for NodeBB",
|
||||
"realtime-chart-updates": "Realtime Chart Updates",
|
||||
|
||||
"active-users": "Active Users",
|
||||
"active-users.users": "Users",
|
||||
"active-users.guests": "Guests",
|
||||
"active-users.total": "Total",
|
||||
"active-users.connections": "Connections",
|
||||
|
||||
"anonymous-registered-users": "Anonymous vs Registered Users",
|
||||
"anonymous": "Anonymous",
|
||||
"registered": "Registered",
|
||||
|
||||
"user-presence": "User Presence",
|
||||
"on-categories": "On categories list",
|
||||
"reading-posts": "Reading posts",
|
||||
"browsing-topics": "Browsing topics",
|
||||
"recent": "Recent",
|
||||
"unread": "Unread",
|
||||
|
||||
"high-presence-topics": "High Presence Topics",
|
||||
|
||||
"graphs.page-views": "Page Views",
|
||||
"graphs.unique-visitors": "Unique Visitors",
|
||||
"graphs.registered-users": "Registered Users",
|
||||
"graphs.anonymous-users": "Anonymous Users"
|
||||
}
|
||||
7
public/language/ar/admin/general/homepage.json
Normal file
7
public/language/ar/admin/general/homepage.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"home-page": "Home Page",
|
||||
"description": "Choose what page is shown when users navigate to the root URL of your forum.",
|
||||
"home-page-route": "Home Page Route",
|
||||
"custom-route": "Custom Route",
|
||||
"allow-user-home-pages": "Allow User Home Pages"
|
||||
}
|
||||
5
public/language/ar/admin/general/languages.json
Normal file
5
public/language/ar/admin/general/languages.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"language-settings": "Language Settings",
|
||||
"description": "The default language determines the language settings for all users who are visiting your forum. <br />Individual users can override the default language on their account settings page.",
|
||||
"default-language": "Default Language"
|
||||
}
|
||||
27
public/language/ar/admin/general/navigation.json
Normal file
27
public/language/ar/admin/general/navigation.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"icon": "Icon:",
|
||||
"change-icon": "change",
|
||||
"route": "Route:",
|
||||
"tooltip": "Tooltip:",
|
||||
"text": "Text:",
|
||||
"text-class": "Text Class: <small>optional</small>",
|
||||
"id": "ID: <small>optional</small>",
|
||||
|
||||
"properties": "Properties:",
|
||||
"only-admins": "Only display to Admins",
|
||||
"only-global-mods-and-admins": "Only display to Global Moderators and Admins",
|
||||
"only-logged-in": "Only display to logged in users",
|
||||
"open-new-window": "Open in a new window",
|
||||
|
||||
"installed-plugins-required": "Installed Plugins Required:",
|
||||
"search-plugin": "Search plugin",
|
||||
|
||||
"btn.delete": "Delete",
|
||||
"btn.disable": "Disable",
|
||||
"btn.enable": "Enable",
|
||||
|
||||
"available-menu-items": "Available Menu Items",
|
||||
"custom-route": "Custom Route",
|
||||
"core": "core",
|
||||
"plugin": "plugin"
|
||||
}
|
||||
5
public/language/ar/admin/general/social.json
Normal file
5
public/language/ar/admin/general/social.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"post-sharing": "Post Sharing",
|
||||
"info-plugins-additional": "Plugins can add additional networks for sharing posts.",
|
||||
"save-success": "Successfully saved Post Sharing Networks!"
|
||||
}
|
||||
9
public/language/ar/admin/general/sounds.json
Normal file
9
public/language/ar/admin/general/sounds.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"notifications": "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"
|
||||
}
|
||||
68
public/language/ar/admin/manage/categories.json
Normal file
68
public/language/ar/admin/manage/categories.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"settings": "Category Settings",
|
||||
"privileges": "Privileges",
|
||||
|
||||
"name": "Category Name",
|
||||
"description": "Category Description",
|
||||
"bg-color": "Background Colour",
|
||||
"text-color": "Text Colour",
|
||||
"bg-image-size": "Background Image Size",
|
||||
"custom-class": "Custom Class",
|
||||
"num-recent-replies": "# of Recent Replies",
|
||||
"ext-link": "External Link",
|
||||
"upload-image": "Upload Image",
|
||||
"delete-image": "Remove",
|
||||
"category-image": "Category Image",
|
||||
"parent-category": "Parent Category",
|
||||
"optional-parent-category": "(Optional) Parent Category",
|
||||
"parent-category-none": "(None)",
|
||||
"copy-settings": "Copy Settings From",
|
||||
"optional-clone-settings": "(Optional) Clone Settings From Category",
|
||||
"purge": "Purge Category",
|
||||
|
||||
"enable": "Enable",
|
||||
"disable": "Disable",
|
||||
"edit": "Edit",
|
||||
|
||||
"select-category": "Select Category",
|
||||
"set-parent-category": "Set Parent Category",
|
||||
|
||||
"privileges.description": "You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or a per-group basis. You can add a new user to this table by searching for them in the form below.",
|
||||
"privileges.warning": "<strong>Note</strong>: Privilege settings take effect immediately. It is not necessary to save the category after adjusting these settings.",
|
||||
"privileges.section-viewing": "Viewing Privileges",
|
||||
"privileges.section-posting": "Posting Privileges",
|
||||
"privileges.section-moderation": "Moderation Privileges",
|
||||
"privileges.section-user": "User",
|
||||
"privileges.search-user": "Add User",
|
||||
"privileges.no-users": "No user-specific privileges in this category.",
|
||||
"privileges.section-group": "Group",
|
||||
"privileges.group-private": "This group is private",
|
||||
"privileges.search-group": "Add Group",
|
||||
"privileges.copy-to-children": "Copy to Children",
|
||||
"privileges.copy-from-category": "Copy from Category",
|
||||
"privileges.inherit": "If the <code>registered-users</code> group is granted a specific privilege, all other groups receive an <strong>implicit privilege</strong>, even if they are not explicitly defined/checked. This implicit privilege is shown to you because all users are part of the <code>registered-users</code> user group, and so, privileges for additional groups need not be explicitly granted.",
|
||||
|
||||
"analytics.back": "Back to Categories List",
|
||||
"analytics.title": "Analytics for \"%1\" category",
|
||||
"analytics.pageviews-hourly": "<strong>Figure 1</strong> – Hourly page views for this category</small>",
|
||||
"analytics.pageviews-daily": "<strong>Figure 2</strong> – Daily page views for this category</small>",
|
||||
"analytics.topics-daily": "<strong>Figure 3</strong> – Daily topics created in this category</small>",
|
||||
"analytics.posts-daily": "<strong>Figure 4</strong> – Daily posts made in this category</small>",
|
||||
|
||||
"alert.created": "Created",
|
||||
"alert.create-success": "Category successfully created!",
|
||||
"alert.none-active": "You have no active categories.",
|
||||
"alert.create": "Create a Category",
|
||||
"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-purge": "<p class=\"lead\">Do you really want to purge this category \"%1\"?</p><h5><strong class=\"text-danger\">Warning!</strong> All topics and posts in this category will be purged!</h5> <p class=\"help-block\">Purging a category will remove all topics and posts, and delete the category from the database. If you want to remove a category <em>temporarily</em>, you'll want to \"disable\" the category instead.</p>",
|
||||
"alert.purge-success": "Category purged!",
|
||||
"alert.copy-success": "Settings Copied!",
|
||||
"alert.set-parent-category": "Set Parent Category",
|
||||
"alert.updated": "Updated Categories",
|
||||
"alert.updated-success": "Category IDs %1 successfully updated.",
|
||||
"alert.upload-image": "Upload category image",
|
||||
"alert.find-user": "Find a User",
|
||||
"alert.user-search": "Search for a user here...",
|
||||
"alert.find-group": "Find a Group",
|
||||
"alert.group-search": "Search for a group here..."
|
||||
}
|
||||
19
public/language/ar/admin/manage/flags.json
Normal file
19
public/language/ar/admin/manage/flags.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"daily": "Daily flags",
|
||||
"by-user": "Flags by user",
|
||||
"by-user-search": "Search flagged posts by username",
|
||||
"category": "Category",
|
||||
"sort-by": "Sort By",
|
||||
"sort-by.most-flags": "Most Flags",
|
||||
"sort-by.most-recent": "Most Recent",
|
||||
"search": "Search",
|
||||
"dismiss-all": "Dismiss All",
|
||||
"none-flagged": "No flagged posts!",
|
||||
"posted-in": "Posted in %1",
|
||||
"read-more": "Read More",
|
||||
"flagged-x-times": "This post has been flagged %1 time(s):",
|
||||
"dismiss": "Dismiss this Flag",
|
||||
"delete-post": "Delete the Post",
|
||||
|
||||
"alerts.confirm-delete-post": "Do you really want to delete this post?"
|
||||
}
|
||||
34
public/language/ar/admin/manage/groups.json
Normal file
34
public/language/ar/admin/manage/groups.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Group Name",
|
||||
"description": "Group Description",
|
||||
"system": "System Group",
|
||||
"edit": "Edit",
|
||||
"search-placeholder": "Search",
|
||||
"create": "Create Group",
|
||||
"description-placeholder": "A short description about your group",
|
||||
"create-button": "Create",
|
||||
|
||||
"alerts.create-failure": "<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>",
|
||||
"alerts.confirm-delete": "Are you sure you wish to delete this group?",
|
||||
|
||||
"edit.name": "Name",
|
||||
"edit.description": "Description",
|
||||
"edit.user-title": "Title of Members",
|
||||
"edit.icon": "Group Icon",
|
||||
"edit.label-color": "Group Label Color",
|
||||
"edit.show-badge": "Show Badge",
|
||||
"edit.private-details": "If enabled, joining of groups requires approval from a group owner.",
|
||||
"edit.private-override": "Warning: Private groups is disabled at system level, which overrides this option.",
|
||||
"edit.disable-requests": "Disable join requests",
|
||||
"edit.hidden": "Hidden",
|
||||
"edit.hidden-details": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually",
|
||||
"edit.add-user": "Add User to Group",
|
||||
"edit.add-user-search": "Search Users",
|
||||
"edit.members": "Member List",
|
||||
"control-panel": "Groups Control Panel",
|
||||
"revert": "Revert",
|
||||
|
||||
"edit.no-users-found": "No Users Found",
|
||||
"edit.confirm-remove-user": "Are you sure you want to remove this user?",
|
||||
"edit.save-success": "Changes saved!"
|
||||
}
|
||||
15
public/language/ar/admin/manage/ip-blacklist.json
Normal file
15
public/language/ar/admin/manage/ip-blacklist.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"lead": "Configure your IP blacklist here.",
|
||||
"description": "Occasionally, a user account ban is not enough of a deterrant. Other times, restricting access to the forum to a specific IP or a range of IPs is the best way to protect a forum. In these scenarios, you can add troublesome IP addresses or entire CIDR blocks to this blacklist, and they will be prevented from logging in to or registering a new account.",
|
||||
"active-rules": "Active Rules",
|
||||
"validate": "Validate Blacklist",
|
||||
"apply": "Apply Blacklist",
|
||||
"hints": "Syntax Hints",
|
||||
"hint-1": "Define a single IP addresses per line. You can add IP blocks as long as they follow the CIDR format (e.g. <code>192.168.100.0/22</code>).",
|
||||
"hint-2": "You can add in comments by starting lines with the <code>#</code> symbol.",
|
||||
|
||||
"validate.x-valid": "<strong>%1</strong> out of <strong>%2</strong> rule(s) valid.",
|
||||
"validate.x-invalid": "The following <strong>%1</strong> rules are invalid:",
|
||||
|
||||
"alerts.applied-success": "Blacklist Applied"
|
||||
}
|
||||
20
public/language/ar/admin/manage/registration.json
Normal file
20
public/language/ar/admin/manage/registration.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"queue": "Queue",
|
||||
"description": "There are no users in the registration queue. <br> To enable this feature, go to <a href=\"%1\">Settings → User → User Registration</a> and set <strong>Registration Type</strong> to \"Admin Approval\".",
|
||||
|
||||
"list.name": "Name",
|
||||
"list.email": "Email",
|
||||
"list.ip": "IP",
|
||||
"list.time": "Time",
|
||||
"list.username-spam": "Frequency: %1 Appears: %2 Confidence: %3",
|
||||
"list.email-spam": "Frequency: %1 Appears: %2",
|
||||
"list.ip-spam": "Frequency: %1 Appears: %2",
|
||||
|
||||
"invitations": "Invitations",
|
||||
"invitations.description": "Below is a complete list of invitations sent. Use ctrl-f to search through the list by email or username. <br><br>The username will be displayed to the right of the emails for users who have redeemed their invitations.",
|
||||
"invitations.inviter-username": "Inviter Username",
|
||||
"invitations.invitee-email": "Invitee Email",
|
||||
"invitations.invitee-username": "Invitee Username (if registered)",
|
||||
|
||||
"invitations.confirm-delete": "Are you sure you wish to delete this invitation?"
|
||||
}
|
||||
18
public/language/ar/admin/manage/tags.json
Normal file
18
public/language/ar/admin/manage/tags.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"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 via clicking and/or dragging, use shift to select multiple.",
|
||||
"create": "Create Tag",
|
||||
"modify": "Modify Tags",
|
||||
"delete": "Delete Selected Tags",
|
||||
"search": "Search for tags...",
|
||||
"settings": "Click <a href=\"%1\">here</a> to visit the tag settings page.",
|
||||
"name": "Tag Name",
|
||||
|
||||
"alerts.editing-multiple": "Editing multiple tags",
|
||||
"alerts.editing-x": "Editing \"%1\" tag",
|
||||
"alerts.confirm-delete": "Do you want to delete the selected tags?",
|
||||
"alerts.update-success": "Tag Updated!"
|
||||
}
|
||||
91
public/language/ar/admin/manage/users.json
Normal file
91
public/language/ar/admin/manage/users.json
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"users": "Users",
|
||||
"edit": "Edit",
|
||||
"make-admin": "Make Admin",
|
||||
"remove-admin": "Remove Admin",
|
||||
"validate-email": "Validate Email",
|
||||
"send-validation-email": "Send Validation Email",
|
||||
"password-reset-email": "Send Password Reset Email",
|
||||
"ban": "Ban User(s)",
|
||||
"temp-ban": "Ban User(s) Temporarily",
|
||||
"unban": "Unban User(s)",
|
||||
"reset-lockout": "Reset Lockout",
|
||||
"reset-flags": "Reset Flags",
|
||||
"delete": "Delete User(s)",
|
||||
"purge": "Delete User(s) and Content",
|
||||
"download-csv": "Download CSV",
|
||||
"invite": "Invite",
|
||||
"new": "New User",
|
||||
|
||||
"pills.latest": "Latest Users",
|
||||
"pills.unvalidated": "Not Validated",
|
||||
"pills.no-posts": "No Posts",
|
||||
"pills.top-posters": "Top Posters",
|
||||
"pills.top-rep": "Most Reputation",
|
||||
"pills.inactive": "Inactive",
|
||||
"pills.flagged": "Most Flagged",
|
||||
"pills.banned": "Banned",
|
||||
"pills.search": "User Search",
|
||||
|
||||
"search.username": "By User Name",
|
||||
"search.username-placeholder": "Enter a username to search",
|
||||
"search.email": "By Email",
|
||||
"search.email-placeholder": "Enter a email to search",
|
||||
"search.ip": "By IP Address",
|
||||
"search.ip-placeholder": "Enter an IP Address to search",
|
||||
"search.not-found": "User not found!",
|
||||
|
||||
"inactive.3-months": "3 months",
|
||||
"inactive.6-months": "6 months",
|
||||
"inactive.12-months": "12 months",
|
||||
|
||||
"users.uid": "uid",
|
||||
"users.username": "username",
|
||||
"users.email": "email",
|
||||
"users.postcount": "postcount",
|
||||
"users.reputation": "reputation",
|
||||
"users.flags": "flags",
|
||||
"users.joined": "joined",
|
||||
"users.last-online": "last online",
|
||||
"users.banned": "banned",
|
||||
|
||||
"create.username": "User Name",
|
||||
"create.email": "Email",
|
||||
"create.email-placeholder": "Email of this user",
|
||||
"create.password": "Password",
|
||||
"create.password-confirm": "Confirm Password",
|
||||
|
||||
"temp-ban.length": "Ban Length",
|
||||
"temp-ban.reason": "Reason <span class=\"text-muted\">(Optional)</span>",
|
||||
"temp-ban.hours": "Hours",
|
||||
"temp-ban.days": "Days",
|
||||
"temp-ban.explanation": "Enter the length of time for the ban. Note that a time of 0 will be a considered a permanent ban.",
|
||||
|
||||
"alerts.confirm-ban": "Do you really want to ban this user <strong>permanently</strong>?",
|
||||
"alerts.confirm-ban-multi": "Do you really want to ban these users <strong>permanently</strong>?",
|
||||
"alerts.ban-success": "User(s) banned!",
|
||||
"alerts.button-ban-x": "Ban %1 user(s)",
|
||||
"alerts.unban-success": "User(s) unbanned!",
|
||||
"alerts.lockout-reset-success": "Lockout(s) reset!",
|
||||
"alerts.flag-reset-success": "Flags(s) reset!",
|
||||
"alerts.no-remove-yourself-admin": "You can't remove yourself as Administrator!",
|
||||
"alerts.make-admin-success": "User(s) are now administrators.",
|
||||
"alerts.confirm-remove-admin": "Do you really want to remove admins?",
|
||||
"alerts.remove-admin-success": "User(s) are no longer administrators.",
|
||||
"alerts.confirm-validate-email": "Do you want to validate email(s) of these user(s)?",
|
||||
"alerts.validate-email-success": "Emails validated",
|
||||
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
|
||||
"alerts.confirm-delete": "<b>Warning!</b><br/>Do you really want to delete user(s)?<br/> This action is not reversable! Only the user account will be deleted, their posts and topics will remain.",
|
||||
"alerts.delete-success": "User(s) Deleted!",
|
||||
"alerts.confirm-purge": "<b>Warning!</b><br/>Do you really want to delete user(s) and their content?<br/> This action is not reversable! All user data and content will be erased!",
|
||||
"alerts.create": "Create User",
|
||||
"alerts.button-create": "Create",
|
||||
"alerts.button-cancel": "Cancel",
|
||||
"alerts.error-passwords-different": "Passwords must match!",
|
||||
"alerts.error-x": "<strong>Error</strong><p>%1</p>",
|
||||
"alerts.create-success": "User created!",
|
||||
|
||||
"alerts.prompt-email": "Email: ",
|
||||
"alerts.email-sent-to": "An invitation email has been sent to %1",
|
||||
"alerts.x-users-found": "%1 user(s) found! Search took %2 ms."
|
||||
}
|
||||
74
public/language/ar/admin/menu.json
Normal file
74
public/language/ar/admin/menu.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"section-general": "General",
|
||||
"general/dashboard": "Dashboard",
|
||||
"general/homepage": "Home Page",
|
||||
"general/navigation": "Navigation",
|
||||
"general/languages": "Languages",
|
||||
"general/sounds": "Sounds",
|
||||
"general/social": "Social",
|
||||
|
||||
"section-manage": "Manage",
|
||||
"manage/categories": "Categories",
|
||||
"manage/tags": "Tags",
|
||||
"manage/users": "Users",
|
||||
"manage/registration": "Registration Queue",
|
||||
"manage/groups": "Groups",
|
||||
"manage/ip-blacklist": "IP Blacklist",
|
||||
|
||||
"section-settings": "Settings",
|
||||
"settings/general": "General",
|
||||
"settings/reputation": "Reputation",
|
||||
"settings/email": "Email",
|
||||
"settings/user": "User",
|
||||
"settings/group": "Group",
|
||||
"settings/guest": "Guests",
|
||||
"settings/uploads": "Uploads",
|
||||
"settings/post": "Post",
|
||||
"settings/chat": "Chat",
|
||||
"settings/pagination": "Pagination",
|
||||
"settings/tags": "Tags",
|
||||
"settings/notifications": "Notifications",
|
||||
"settings/cookies": "Cookies",
|
||||
"settings/web-crawler": "Web Crawler",
|
||||
"settings/sockets": "Sockets",
|
||||
"settings/advanced": "Advanced",
|
||||
|
||||
"settings.page-title": "%1 Settings",
|
||||
|
||||
"section-appearance": "Appearance",
|
||||
"appearance/themes": "Themes",
|
||||
"appearance/skins": "Skins",
|
||||
"appearance/customise": "Custom HTML & CSS",
|
||||
|
||||
"section-extend": "Extend",
|
||||
"extend/plugins": "Plugins",
|
||||
"extend/widgets": "Widgets",
|
||||
"extend/rewards": "Rewards",
|
||||
|
||||
"section-social-auth": "Social Authentication",
|
||||
|
||||
"section-plugins": "Plugins",
|
||||
"extend/plugins.install": "Install Plugins",
|
||||
|
||||
"section-advanced": "Advanced",
|
||||
"advanced/database": "Database",
|
||||
"advanced/events": "Events",
|
||||
"advanced/logs": "Logs",
|
||||
"advanced/errors": "Errors",
|
||||
"advanced/cache": "Cache",
|
||||
"development/logger": "Logger",
|
||||
"development/info": "Info",
|
||||
|
||||
"reload-forum": "Reload Forum",
|
||||
"restart-forum": "Restart Forum",
|
||||
"logout": "Log out",
|
||||
"view-forum": "View Forum",
|
||||
|
||||
"search.placeholder": "Search...",
|
||||
"search.no-results": "No results...",
|
||||
"search.search-forum": "Search the forum for <strong></strong>",
|
||||
"search.keep-typing": "Type more to see results...",
|
||||
"search.start-typing": "Start typing to see results...",
|
||||
|
||||
"connection-lost": "Connection to %1 has been lost, attempting to reconnect..."
|
||||
}
|
||||
19
public/language/ar/admin/settings/advanced.json
Normal file
19
public/language/ar/admin/settings/advanced.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"maintenance-mode": "Maintenance Mode",
|
||||
"maintenance-mode.help": "When the forum is in maintenance mode, all requests will be redirected to a static holding page. Administrators are exempt from this redirection, and are able to access the site normally.",
|
||||
"maintenance-mode.message": "Maintenance Message",
|
||||
"headers": "Headers",
|
||||
"headers.allow-from": "Set ALLOW-FROM to Place NodeBB in an iFrame",
|
||||
"headers.powered-by": "Customise the \"Powered By\" header sent by NodeBB",
|
||||
"headers.acao": "Access-Control-Allow-Origin",
|
||||
"headers.acao-help": "To deny access to all sites, leave empty or set to <code>null</code>",
|
||||
"headers.acam": "Access-Control-Allow-Methods",
|
||||
"headers.acah": "Access-Control-Allow-Headers",
|
||||
"traffic-management": "Traffic Management",
|
||||
"traffic.help": "NodeBB deploys equipped with a module that automatically denies requests in high-traffic situations. You can tune these settings here, although the defaults are a good starting point.",
|
||||
"traffic.enable": "Enable Traffic Management",
|
||||
"traffic.event-lag": "Event Loop Lag Threshold (in milliseconds)",
|
||||
"traffic.event-lag-help": "Lowering this value decreases wait times for page loads, but will also show the \"excessive load\" message to more users. (Restart required)",
|
||||
"traffic.lag-check-interval": "Check Interval (in milliseconds)",
|
||||
"traffic.lag-check-interval-help": "Lowering this value causes NodeBB to become more sensitive to spikes in load, but may also cause the check to become too sensitive. (Restart required)"
|
||||
}
|
||||
9
public/language/ar/admin/settings/chat.json
Normal file
9
public/language/ar/admin/settings/chat.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"chat-settings": "Chat Settings",
|
||||
"disable": "Disable chat",
|
||||
"disable-editing": "Disable chat message editing/deletion",
|
||||
"disable-editing-help": "Administrators and global moderators are exempt from this restriction",
|
||||
"max-length": "Maximum length of chat messages",
|
||||
"max-room-size": "Maximum number of users in chat rooms",
|
||||
"delay": "Time between chat messages in milliseconds"
|
||||
}
|
||||
11
public/language/ar/admin/settings/cookies.json
Normal file
11
public/language/ar/admin/settings/cookies.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"eu-consent": "EU Consent",
|
||||
"consent.enabled": "Enabled",
|
||||
"consent.message": "Notification message",
|
||||
"consent.acceptance": "Acceptance message",
|
||||
"consent.link-text": "Policy Link Text",
|
||||
"consent.blank-localised-default": "Leave blank to use NodeBB localised defaults",
|
||||
"settings": "Settings",
|
||||
"cookie-domain": "Session cookie domain",
|
||||
"blank-default": "Leave blank for default"
|
||||
}
|
||||
25
public/language/ar/admin/settings/email.json
Normal file
25
public/language/ar/admin/settings/email.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"email-settings": "Email Settings",
|
||||
"address": "Email Address",
|
||||
"address-help": "The following email address refers to the email that the recipient will see in the \"From\" and \"Reply To\" fields.",
|
||||
"from": "From Name",
|
||||
"from-help": "The from name to display in the email.",
|
||||
"gmail-routing": "Gmail Routing",
|
||||
"gmail-routing-help1": "There have been reports of Gmail Routing not working on accounts with heightened security. In those scenarios, you will have to <a href=\"https://www.google.com/settings/security/lesssecureapps\">configure your GMail account to allow less secure apps</a>.",
|
||||
"gmail-routing-help2": "For more information about this workaround, <a href=\"https://nodemailer.com/using-gmail/\">please consult this NodeMailer article on the issue.</a> An alternative would be to utilise a third-party emailer plugin such as SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Browse available plugins here</a>.",
|
||||
"gmail-transport": "Route emails through a Gmail/Google Apps account",
|
||||
"gmail-transport.username": "Username",
|
||||
"gmail-transport.username-help": "Enter the full email address here, especially if you are using a Google Apps managed domain.",
|
||||
"gmail-transport.password": "Password",
|
||||
"template": "Edit Email Template",
|
||||
"template.select": "Select Email Template",
|
||||
"template.revert": "Revert to Original",
|
||||
"testing": "Email Testing",
|
||||
"testing.select": "Select Email Template",
|
||||
"testing.send": "Send Test Email",
|
||||
"testing.send-help": "The test email will be sent to the currently logged in user's email address.",
|
||||
"subscriptions": "Email Subscriptions",
|
||||
"subscriptions.disable": "Disable subscriber notification emails",
|
||||
"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>"
|
||||
}
|
||||
32
public/language/ar/admin/settings/general.json
Normal file
32
public/language/ar/admin/settings/general.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"site-settings": "Site Settings",
|
||||
"title": "Site Title",
|
||||
"title.name": "Your Community Name",
|
||||
"title.show-in-header": "Show Site Title in Header",
|
||||
"browser-title": "Browser Title",
|
||||
"browser-title-help": "If no browser title is specified, the site title will be used",
|
||||
"title-layout": "Title Layout",
|
||||
"title-layout-help": "Define how the browser title will be structured ie. {pageTitle} | {browserTitle}",
|
||||
"description.placeholder": "A short description about your community",
|
||||
"description": "Site Description",
|
||||
"keywords": "Site Keywords",
|
||||
"keywords-placeholder": "Keywords describing your community, comma-separated",
|
||||
"logo": "Site Logo",
|
||||
"logo.image": "Image",
|
||||
"logo.image-placeholder": "Path to a logo to display on forum header",
|
||||
"logo.upload": "Upload",
|
||||
"logo.url": "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.",
|
||||
"logo.alt-text": "Alt Text",
|
||||
"log.alt-text-placeholder": "Alternative text for accessibility",
|
||||
"favicon": "Favicon",
|
||||
"favicon.upload": "Upload",
|
||||
"touch-icon": "Homescreen/Touch Icon",
|
||||
"touch-icon.upload": "Upload",
|
||||
"touch-icon.help": "Recommended size and format: 192x192, PNG format only. If no touch icon is specified, NodeBB will fall back to using the favicon.",
|
||||
"outgoing-links": "Outgoing Links",
|
||||
"outgoing-links.warning-page": "Use Outgoing Links Warning Page",
|
||||
"search-default-sort-by": "Search default sort by",
|
||||
"outgoing-links.whitelist": "Domains to whitelist for bypassing the warning page"
|
||||
}
|
||||
12
public/language/ar/admin/settings/group.json
Normal file
12
public/language/ar/admin/settings/group.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"general": "General",
|
||||
"private-groups": "Private Groups",
|
||||
"private-groups.help": "If enabled, joining of groups requires the approval of the group owner <em>(Default: enabled)</em>",
|
||||
"private-groups.warning": "<strong>Beware!</strong> If this option is disabled and you have private groups, they automatically become public.",
|
||||
"allow-creation": "Allow Group Creation",
|
||||
"allow-creation-help": "If enabled, users can create groups <em>(Default: disabled)</em>",
|
||||
"max-name-length": "Maximum Group Name Length",
|
||||
"cover-image": "Group Cover Image",
|
||||
"default-cover": "Default Cover Images",
|
||||
"default-cover-help": "Add comma-separated default cover images for groups that don't have an uploaded cover image"
|
||||
}
|
||||
8
public/language/ar/admin/settings/guest.json
Normal file
8
public/language/ar/admin/settings/guest.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"handles": "Guest Handles",
|
||||
"handles.enabled": "Allow guest handles",
|
||||
"handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"",
|
||||
"privileges": "Guest Privileges",
|
||||
"privileges.can-search": "Allow guests to search without logging in",
|
||||
"privileges.can-search-users": "Allow guests to search users without logging in"
|
||||
}
|
||||
5
public/language/ar/admin/settings/notifications.json
Normal file
5
public/language/ar/admin/settings/notifications.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"notifications": "Notifications",
|
||||
"welcome-notification": "Welcome Notification",
|
||||
"welcome-notification-link": "Welcome Notification Link"
|
||||
}
|
||||
9
public/language/ar/admin/settings/pagination.json
Normal file
9
public/language/ar/admin/settings/pagination.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"pagination": "Pagination Settings",
|
||||
"enable": "Paginate topics and posts instead of using infinite scroll.",
|
||||
"topics": "Topic Pagination",
|
||||
"posts-per-page": "Posts per Page",
|
||||
"categories": "Category Pagination",
|
||||
"topics-per-page": "Topics per Page",
|
||||
"initial-num-load": "Initial Number of Topics to Load on Unread, Recent, and Popular"
|
||||
}
|
||||
44
public/language/ar/admin/settings/post.json
Normal file
44
public/language/ar/admin/settings/post.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"sorting": "Post Sorting",
|
||||
"sorting.post-default": "Default Post Sorting",
|
||||
"sorting.oldest-to-newest": "Oldest to Newest",
|
||||
"sorting.newest-to-oldest": "Newest to Oldest",
|
||||
"sorting.most-votes": "Most Votes",
|
||||
"sorting.topic-default": "Default Topic Sorting",
|
||||
"restrictions": "Posting Restrictions",
|
||||
"restrictions.seconds-between": "Seconds between Posts",
|
||||
"restrictions.seconds-between-new": "Seconds between Posts for New Users",
|
||||
"restrictions.rep-threshold": "Reputation threshold before this restriction is lifted",
|
||||
"restrictions.seconds-defore-new": "Seconds before new user can post",
|
||||
"restrictions.seconds-edit-after": "Number of seconds users are allowed to edit posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds users are allowed to delete posts after posting. (0 disabled)",
|
||||
"restrictions.replies-no-delete": "Number of replies after users are disallowed to delete their own topics. (0 disabled)",
|
||||
"restrictions.min-title-length": "Minimum Title Length",
|
||||
"restrictions.max-title-length": "Maximum Title Length",
|
||||
"restrictions.min-post-length": "Minimum Post Length",
|
||||
"restrictions.max-post-length": "Maximum Post Length",
|
||||
"restrictions.days-until-stale": "Days until Topic is considered stale",
|
||||
"restrictions.stale-help": "If a topic is considered \"stale\", then a warning will be shown to users who attempt to reply to that topic.",
|
||||
"timestamp": "Timestamp",
|
||||
"timestamp.cut-off": "Date cut-off (in days)",
|
||||
"timestamp.cut-off-help": "Dates & times will be shown in a relative manner (e.g. \"3 hours ago\" / \"5 days ago\"), and localised into various\n\t\t\t\t\tlanguages. After a certain point, this text can be switched to display the localised date itself\n\t\t\t\t\t(e.g. 5 Nov 2016 15:30).<br /><em>(Default: <code>30</code>, or one month). Set to 0 to always display dates, leave blank to always display relative times.</em>",
|
||||
"teaser": "Teaser Post",
|
||||
"teaser.last-post": "Last – Show the latest post, including the original post, if no replies",
|
||||
"teaser.last-reply": "Last – Show the latest reply, or a \"No replies\" placeholder if no replies",
|
||||
"teaser.first": "First",
|
||||
"unread": "Unread Settings",
|
||||
"unread.cutoff": "Unread cutoff days",
|
||||
"unread.min-track-last": "Minimum posts in topic before tracking last read",
|
||||
"signature": "Signature Settings",
|
||||
"signature.disable": "Disable signatures",
|
||||
"signature.no-links": "Disable links in signatures",
|
||||
"signature.no-images": "Disable images in signatures",
|
||||
"signature.max-length": "Maximum Signature Length",
|
||||
"composer": "Composer Settings",
|
||||
"composer-help": "The following settings govern the functionality and/or appearance of the post composer shown\n\t\t\t\tto users when they create new topics, or reply to existing topics.",
|
||||
"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",
|
||||
"ip-tracking": "IP Tracking",
|
||||
"ip-tracking.each-post": "Track IP Address for each post"
|
||||
}
|
||||
9
public/language/ar/admin/settings/reputation.json
Normal file
9
public/language/ar/admin/settings/reputation.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"reputation": "Reputation Settings",
|
||||
"disable": "Disable Reputation System",
|
||||
"disable-down-voting": "Disable Down Voting",
|
||||
"votes-are-public": "All Votes Are Public",
|
||||
"thresholds": "Activity Thresholds",
|
||||
"min-rep-downvote": "Minimum reputation to downvote posts",
|
||||
"min-rep-flag": "Minimum reputation to flag posts"
|
||||
}
|
||||
6
public/language/ar/admin/settings/sockets.json
Normal file
6
public/language/ar/admin/settings/sockets.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"reconnection": "Reconnection Settings",
|
||||
"max-attempts": "Max Reconnection Attempts",
|
||||
"default-placeholder": "Default: %1",
|
||||
"delay": "Reconnection Delay"
|
||||
}
|
||||
12
public/language/ar/admin/settings/tags.json
Normal file
12
public/language/ar/admin/settings/tags.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"tag": "Tag Settings",
|
||||
"min-per-topic": "Minimum Tags per Topic",
|
||||
"max-per-topic": "Maximum Tags per Topic",
|
||||
"min-length": "Minimum Tag Length",
|
||||
"max-length": "Maximum Tag Length",
|
||||
"goto-manage": "Click here to visit the tag management page.",
|
||||
"privacy": "Privacy",
|
||||
"list-private": "Make the tags list private",
|
||||
"related-topics": "Related Topics",
|
||||
"max-related-topics": "Maximum related topics to display (if supported by theme)"
|
||||
}
|
||||
28
public/language/ar/admin/settings/uploads.json
Normal file
28
public/language/ar/admin/settings/uploads.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"posts": "Posts",
|
||||
"allow-files": "Allow users to upload regular files",
|
||||
"private": "Make uploaded files private",
|
||||
"max-image-width": "Resize images down to specified width (in pixels)",
|
||||
"max-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)",
|
||||
"max-file-size": "Maximum File Size (in KiB)",
|
||||
"max-file-size-help": "(in kilobytes, default: 2048 KiB)",
|
||||
"allow-topic-thumbnails": "Allow users to upload topic thumbnails",
|
||||
"topic-thumb-size": "Topic Thumb Size",
|
||||
"allowed-file-extensions": "Allowed File Extensions",
|
||||
"allowed-file-extensions-help": "Enter comma-separated list of file extensions here (e.g. <code>pdf,xls,doc</code>). An empty list means all extensions are allowed.",
|
||||
"profile-avatars": "Profile Avatars",
|
||||
"allow-profile-image-uploads": "Allow users to upload profile images",
|
||||
"convert-profile-image-png": "Convert profile image uploads to PNG",
|
||||
"default-avatar": "Custom Default Avatar",
|
||||
"upload": "Upload",
|
||||
"profile-image-dimension": "Profile Image Dimension",
|
||||
"profile-image-dimension-help": "(in pixels, default: 128 pixels)",
|
||||
"max-profile-image-size": "Maximum Profile Image File Size",
|
||||
"max-profile-image-size-help": "(in kilobytes, default: 256 KiB)",
|
||||
"max-cover-image-size": "Maximum Cover Image File Size",
|
||||
"max-cover-image-size-help": "(in kilobytes, default: 2,048 KiB)",
|
||||
"keep-all-user-images": "Keep old versions of avatars and profile covers on the server",
|
||||
"profile-covers": "Profile Covers",
|
||||
"default-covers": "Default Cover Images",
|
||||
"default-covers-help": "Add comma-separated default cover images for accounts that don't have an uploaded cover image"
|
||||
}
|
||||
59
public/language/ar/admin/settings/user.json
Normal file
59
public/language/ar/admin/settings/user.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"authentication": "Authentication",
|
||||
"allow-local-login": "Allow local login",
|
||||
"require-email-confirmation": "Require Email Confirmation",
|
||||
"email-confirm-interval": "User may not resend a confirmation email until",
|
||||
"email-confirm-email2": "minutes have elapsed",
|
||||
"allow-login-with": "Allow login with",
|
||||
"allow-login-with.username-email": "Username or Email",
|
||||
"allow-login-with.username": "Username Only",
|
||||
"allow-login-with.email": "Email Only",
|
||||
"account-settings": "Account Settings",
|
||||
"disable-username-changes": "Disable username changes",
|
||||
"disable-email-changes": "Disable email changes",
|
||||
"disable-password-changes": "Disable password changes",
|
||||
"allow-account-deletion": "Allow account deletion",
|
||||
"user-info-private": "Make user info private",
|
||||
"themes": "Themes",
|
||||
"disable-user-skins": "Prevent users from choosing a custom skin",
|
||||
"account-protection": "Account Protection",
|
||||
"login-attempts": "Login attempts per hour",
|
||||
"login-attempts-help": "If login attempts to a user's account exceeds this threshold, that account will be locked for a pre-configured amount of time",
|
||||
"lockout-duration": "Account Lockout Duration (minutes)",
|
||||
"login-days": "Days to remember user login sessions",
|
||||
"password-expiry-days": "Force password reset after a set number of days",
|
||||
"registration": "User Registration",
|
||||
"registration-type": "Registration Type",
|
||||
"registration-type.normal": "Normal",
|
||||
"registration-type.admin-approval": "Admin Approval",
|
||||
"registration-type.admin-approval-ip": "Admin Approval for IPs",
|
||||
"registration-type.invite-only": "Invite Only",
|
||||
"registration-type.admin-invite-only": "Admin Invite Only",
|
||||
"registration-type.disabled": "No registration",
|
||||
"registration-type.help": "Normal - Users can register from the /register page.<br/>\nAdmin Approval - User registrations are placed in an <a href=\"%1/admin/manage/registration\">approval queue</a> for administrators.<br/>\nAdmin Approval for IPs - Normal for new users, Admin Approval for IP addresses that already have an account.<br/>\nInvite Only - Users can invite others from the <a href=\"%1/users\" target=\"_blank\">users</a> page.<br/>\nAdmin Invite Only - Only administrators can invite others from <a href=\"%1/users\" target=\"_blank\">users</a> and <a href=\"%1/admin/manage/users\">admin/manage/users</a> pages.<br/>\nNo registration - No user registration.<br/>",
|
||||
"registration.max-invites": "Maximum Invitations per User",
|
||||
"max-invites": "Maximum Invitations per User",
|
||||
"max-invites-help": "0 for no restriction. Admins get infinite invitations<br>Only applicable for \"Invite Only\"",
|
||||
"min-username-length": "Minimum Username Length",
|
||||
"max-username-length": "Maximum Username Length",
|
||||
"min-password-length": "Minimum Password Length",
|
||||
"max-about-me-length": "Maximum About Me Length",
|
||||
"terms-of-use": "Forum Terms of Use <small>(Leave blank to disable)</small>",
|
||||
"user-search": "User Search",
|
||||
"user-search-results-per-page": "Number of results to display",
|
||||
"default-user-settings": "Default User Settings",
|
||||
"show-email": "Show email",
|
||||
"show-fullname": "Show fullname",
|
||||
"restrict-chat": "Only allow chat messages from users I follow",
|
||||
"outgoing-new-tab": "Open outgoing links in new tab",
|
||||
"topic-search": "Enable In-Topic Searching",
|
||||
"digest-freq": "Subscribe to Digest",
|
||||
"digest-freq.off": "Off",
|
||||
"digest-freq.daily": "Daily",
|
||||
"digest-freq.weekly": "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",
|
||||
"follow-created-topics": "Follow topics you create",
|
||||
"follow-replied-topics": "Follow topics that you reply to"
|
||||
}
|
||||
10
public/language/ar/admin/settings/web-crawler.json
Normal file
10
public/language/ar/admin/settings/web-crawler.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"crawlability-settings": "Crawlability Settings",
|
||||
"robots-txt": "Custom Robots.txt <small>Leave blank for default</small>",
|
||||
"sitemap-feed-settings": "Sitemap & Feed Settings",
|
||||
"disable-rss-feeds": "Disable RSS Feeds",
|
||||
"disable-sitemap-xml": "Disable Sitemap.xml",
|
||||
"sitemap-topics": "Number of Topics to display in the Sitemap",
|
||||
"clear-sitemap-cache": "Clear Sitemap Cache",
|
||||
"view-sitemap": "View Sitemap"
|
||||
}
|
||||
@@ -102,5 +102,6 @@
|
||||
"play": "Play",
|
||||
"cookies.message": "This website uses cookies to ensure you get the best experience on our website.",
|
||||
"cookies.accept": "Got it!",
|
||||
"cookies.learn_more": "Learn More"
|
||||
"cookies.learn_more": "Learn More",
|
||||
"edited": "Edited"
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
"details.disableJoinRequests": "Disable join requests",
|
||||
"details.grant": "منح/سحب المِلكية",
|
||||
"details.kick": "طرد",
|
||||
"details.kick_confirm": "Are you sure you want to remove this member from the group?",
|
||||
"details.owner_options": "إدارة المجموعة",
|
||||
"details.group_name": "اسم المجموعة",
|
||||
"details.member_count": "عدد اﻷعضاء",
|
||||
@@ -52,5 +53,6 @@
|
||||
"new-group.group_name": "اسم المجموعة",
|
||||
"upload-group-cover": "Upload group cover",
|
||||
"bulk-invite-instructions": "Enter a list of comma separated usernames to invite to this group",
|
||||
"bulk-invite": "Bulk Invite"
|
||||
"bulk-invite": "Bulk Invite",
|
||||
"remove_group_cover_confirm": "Are you sure you want to remove the cover picture?"
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
"chat.contacts": "الأصدقاء",
|
||||
"chat.message-history": "تاريخ الرسائل",
|
||||
"chat.pop-out": "افتح الدردشة في نافذة خاصة",
|
||||
"chat.minimize": "Minimize",
|
||||
"chat.maximize": "تكبير",
|
||||
"chat.seven_days": "7 أيام",
|
||||
"chat.thirty_days": "30 يومًا",
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
"return_to": "عودة إى %1",
|
||||
"new_notification": "تنبيه جديد",
|
||||
"you_have_unread_notifications": "لديك تنبيهات غير مقروءة.",
|
||||
"all": "All",
|
||||
"topics": "Topics",
|
||||
"replies": "Replies",
|
||||
"chat": "Chats",
|
||||
"follows": "Follows",
|
||||
"upvote": "Upvotes",
|
||||
"new-flags": "New Flags",
|
||||
"my-flags": "Flags assigned to me",
|
||||
"bans": "Bans",
|
||||
"new_message_from": "رسالة جديدة من <strong>%1</strong>",
|
||||
"upvoted_your_post_in": "<strong>%1</strong> أضاف صوتًا إيجابيا إلى مشاركتك في <strong>%2</strong>.",
|
||||
"upvoted_your_post_in_dual": "<strong>%1</strong> and <strong>%2</strong> have upvoted your post in <strong>%3</strong>.",
|
||||
@@ -19,6 +28,9 @@
|
||||
"user_flagged_post_in": "<strong>%1</strong> أشعَرَ بمشاركة مخلة في <strong>%2</strong>",
|
||||
"user_flagged_post_in_dual": "<strong>%1</strong> and <strong>%2</strong> flagged a post in <strong>%3</strong>",
|
||||
"user_flagged_post_in_multiple": "<strong>%1</strong> and %2 others flagged a post in <strong>%3</strong>",
|
||||
"user_flagged_user": "<strong>%1</strong> flagged a user profile (%2)",
|
||||
"user_flagged_user_dual": "<strong>%1</strong> and <strong>%2</strong> flagged a user profile (%3)",
|
||||
"user_flagged_user_multiple": "<strong>%1</strong> and %2 others flagged a user profile (%3)",
|
||||
"user_posted_to": "<strong>%1</strong> أضاف ردا إلى: <strong>%2</strong>",
|
||||
"user_posted_to_dual": "<strong>%1</strong> and <strong>%2</strong> have posted replies to: <strong>%3</strong>",
|
||||
"user_posted_to_multiple": "<strong>%1</strong> and %2 others have posted replies to: <strong>%3</strong>",
|
||||
@@ -28,6 +40,7 @@
|
||||
"user_started_following_you_multiple": "<strong>%1</strong> and %2 others started following you.",
|
||||
"new_register": "<strong>%1</strong> sent a registration request.",
|
||||
"new_register_multiple": "There are <strong>%1</strong> registration requests awaiting review.",
|
||||
"flag_assigned_to_you": "<strong>Flag %1</strong> has been assigned to you",
|
||||
"email-confirmed": "تم التحقق من عنوان البريد الإلكتروني",
|
||||
"email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.",
|
||||
"email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"popular-month": "المواضيع الشائعة هذا الشهر",
|
||||
"popular-alltime": "المواضيع الشائعة منذ القدم",
|
||||
"recent": "المواضيع الحديثة",
|
||||
"flagged-posts": "Flagged Posts",
|
||||
"flagged-content": "Flagged Content",
|
||||
"ip-blacklist": "IP Blacklist",
|
||||
"users/online": "اﻷعضاء المتصلون",
|
||||
"users/latest": "أحدث اﻷعضاء",
|
||||
@@ -27,6 +27,8 @@
|
||||
"group": "%1 مجموعة",
|
||||
"chats": "محادثات",
|
||||
"chat": "Chatting with %1",
|
||||
"flags": "Flags",
|
||||
"flag-details": "Flag %1 Details",
|
||||
"account/edit": "Editing \"%1\"",
|
||||
"account/edit/password": "Editing password of \"%1\"",
|
||||
"account/edit/username": "Editing username of \"%1\"",
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
"posted-by": "مشاركة من طرف",
|
||||
"in-categories": "في الفئات",
|
||||
"search-child-categories": "بحث في الفئات الفرعية",
|
||||
"has-tags": "Has tags",
|
||||
"reply-count": "عدد المشاركات",
|
||||
"at-least": "على اﻷقل",
|
||||
"at-most": "على اﻷكثر",
|
||||
"relevance": "Relevance",
|
||||
"post-time": "تاريخ المشاركة",
|
||||
"newer-than": "أحدث من",
|
||||
"older-than": "أقدم من",
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"notify_me": "تلق تنبيهات بالردود الجديدة في هذا الموضوع",
|
||||
"quote": "اقتبس",
|
||||
"reply": "رد",
|
||||
"replies_to_this_post": "Replies: %1",
|
||||
"replies_to_this_post": "%1 Replies",
|
||||
"last_reply_time": "Last reply",
|
||||
"reply-as-topic": "رد بموضوع",
|
||||
"guest-login-reply": "يجب عليك تسجيل الدخول للرد",
|
||||
"edit": "تعديل",
|
||||
@@ -25,28 +26,11 @@
|
||||
"link": "رابط",
|
||||
"share": "نشر",
|
||||
"tools": "أدوات",
|
||||
"flag": "تبليغ",
|
||||
"locked": "مقفل",
|
||||
"pinned": "مثبت",
|
||||
"moved": "منقول",
|
||||
"bookmark_instructions": "اضغط هنا للعودة لأخر مشاركة مقروءة في الموضوع",
|
||||
"flag_title": "إشعار بمشاركة مخلة.",
|
||||
"flag_success": "تم الإشعار بهذه المشاركة على أنها مخلة",
|
||||
"flag_manage_title": "Flagged post in %1",
|
||||
"flag_manage_history": "Action History",
|
||||
"flag_manage_no_history": "No event history to report",
|
||||
"flag_manage_assignee": "Assignee",
|
||||
"flag_manage_state": "State",
|
||||
"flag_manage_state_open": "New/Open",
|
||||
"flag_manage_state_wip": "Work in Progress",
|
||||
"flag_manage_state_resolved": "Resolved",
|
||||
"flag_manage_state_rejected": "Rejected",
|
||||
"flag_manage_notes": "Shared Notes",
|
||||
"flag_manage_update": "Update Flag Status",
|
||||
"flag_manage_history_assignee": "Assigned to %1",
|
||||
"flag_manage_history_state": "Updated state to %1",
|
||||
"flag_manage_history_notes": "Updated flag notes",
|
||||
"flag_manage_saved": "Flag Details Updated",
|
||||
"deleted_message": "هذه المشاركة محذوفة. فقط من لهم صلاحية الإشراف على ا لمشاركات يمكنهم معاينتها.",
|
||||
"following_topic.message": "ستستلم تنبيها عند كل مشاركة جديدة في هذا الموضوع.",
|
||||
"not_following_topic.message": "You will see this topic in the unread topics list, but you will not receive notifications when somebody posts to this topic.",
|
||||
@@ -131,8 +115,5 @@
|
||||
"stale.warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?",
|
||||
"stale.create": "موضوع جديد",
|
||||
"stale.reply_anyway": "الرد على هذا الموضوع ",
|
||||
"link_back": "رد: [%1](%2)",
|
||||
"spam": "سبام",
|
||||
"offensive": "مسيئ",
|
||||
"custom-flag-reason": "أدخل سبب التبليغ"
|
||||
"link_back": "رد: [%1](%2)"
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
"chat": "محادثة",
|
||||
"chat_with": "Continue chat with %1",
|
||||
"new_chat_with": "Start new chat with %1",
|
||||
"flag-profile": "Flag Profile",
|
||||
"follow": "تابع",
|
||||
"unfollow": "إلغاء المتابعة",
|
||||
"more": "المزيد",
|
||||
@@ -63,6 +64,9 @@
|
||||
"upload_a_picture": "رفع صورة",
|
||||
"remove_uploaded_picture": "Remove Uploaded Picture",
|
||||
"upload_cover_picture": "Upload cover picture",
|
||||
"remove_cover_picture_confirm": "Are you sure you want to remove the cover picture?",
|
||||
"crop_picture": "Crop picture",
|
||||
"upload_cropped_picture": "Crop and upload",
|
||||
"settings": "خيارات",
|
||||
"show_email": "أظهر بريدي الإلكتروني",
|
||||
"show_fullname": "أظهر اسمي الكامل",
|
||||
@@ -126,5 +130,6 @@
|
||||
"info.username-history": "Username History",
|
||||
"info.email-history": "Email History",
|
||||
"info.moderation-note": "Moderation Note",
|
||||
"info.moderation-note.success": "Moderation note saved"
|
||||
"info.moderation-note.success": "Moderation note saved",
|
||||
"info.moderation-note.add": "Add note"
|
||||
}
|
||||
7
public/language/bg/admin/admin.json
Normal file
7
public/language/bg/admin/admin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"alert.confirm-reload": "Наистина ли искате да презаредите NodeBB?",
|
||||
"alert.confirm-restart": "Наистина ли искате да рестартирате NodeBB?",
|
||||
|
||||
"acp-title": "%1 | Контролен панел за администратори на NodeBB",
|
||||
"settings-header-contents": "Съдържание"
|
||||
}
|
||||
11
public/language/bg/admin/advanced/cache.json
Normal file
11
public/language/bg/admin/advanced/cache.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"post-cache": "Кеш за публикации",
|
||||
"posts-in-cache": "Публикации в кеша",
|
||||
"average-post-size": "Среден обем на публикация",
|
||||
"length-to-max": "Дължина / максимум",
|
||||
"percent-full": "Запълненост: %1%",
|
||||
"post-cache-size": "Размер на кеша за публикации",
|
||||
"items-in-cache": "Елементи в кеша",
|
||||
"control-panel": "Контролен панел",
|
||||
"update-settings": "Обновяване на настройките на кеша"
|
||||
}
|
||||
35
public/language/bg/admin/advanced/database.json
Normal file
35
public/language/bg/admin/advanced/database.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"x-b": "%1 Б",
|
||||
"x-mb": "%1 МБ",
|
||||
"uptime-seconds": "Активно време в секунди",
|
||||
"uptime-days": "Активно време в дни",
|
||||
|
||||
"mongo": "Mongo",
|
||||
"mongo.version": "Версия на MongoDB",
|
||||
"mongo.storage-engine": "Система за съхранение",
|
||||
"mongo.collections": "Колекции",
|
||||
"mongo.objects": "Обекти",
|
||||
"mongo.avg-object-size": "Среден размер на обект",
|
||||
"mongo.data-size": "Размер на данните",
|
||||
"mongo.storage-size": "Размер на съхраненото",
|
||||
"mongo.index-size": "Размер на индексите",
|
||||
"mongo.file-size": "Размер на файловете",
|
||||
"mongo.resident-memory": "Текущо активна памет",
|
||||
"mongo.virtual-memory": "Виртуална памет",
|
||||
"mongo.mapped-memory": "Заделена памет",
|
||||
"mongo.raw-info": "Сурови данни от MongoDB",
|
||||
|
||||
"redis": "Redis",
|
||||
"redis.version": "Версия на Redis",
|
||||
"redis.connected-clients": "Свързани клиенти",
|
||||
"redis.connected-slaves": "Свързани второстепенни сървъри",
|
||||
"redis.blocked-clients": "Блокирани клиенти",
|
||||
"redis.used-memory": "Използвана памет",
|
||||
"redis.memory-frag-ratio": "Коефициент на фрагментиране на паметта",
|
||||
"redis.total-connections-recieved": "Общо получени свързвания",
|
||||
"redis.total-commands-processed": "Общо обработени команди",
|
||||
"redis.iops": "Едновременни операции в секунда",
|
||||
"redis.keyspace-hits": "Успешни търсения на ключове",
|
||||
"redis.keyspace-misses": "Неуспешни търсения на ключове",
|
||||
"redis.raw-info": "Сурови данни от Redis"
|
||||
}
|
||||
14
public/language/bg/admin/advanced/errors.json
Normal file
14
public/language/bg/admin/advanced/errors.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"figure-x": "Фигура %1",
|
||||
"error-events-per-day": "<code>%1</code> събития на ден",
|
||||
"error.404": "Страницата не е намерена (Грешка 404)",
|
||||
"error.503": "Услугата е недостъпна (Грешка 503)",
|
||||
"manage-error-log": "Управление на журнала за грешки",
|
||||
"export-error-log": "Изнасяне на журнала за грешки (CSV)",
|
||||
"clear-error-log": "Изчистване на журнала за грешки",
|
||||
"route": "Маршрут",
|
||||
"count": "Брой",
|
||||
"no-routes-not-found": "Ура! Няма грешки от вида „404“!",
|
||||
"clear404-confirm": "Наистина ли искате да изчистите журналите за грешки от вида 404?",
|
||||
"clear404-success": "Грешките от вида „Страницата не е намерена (Грешка 404)“ бяха изчистени."
|
||||
}
|
||||
6
public/language/bg/admin/advanced/events.json
Normal file
6
public/language/bg/admin/advanced/events.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"events": "Събития",
|
||||
"no-events": "Няма събития",
|
||||
"control-panel": "Контролен панел за събитията",
|
||||
"delete-events": "Изтриване на събитията"
|
||||
}
|
||||
7
public/language/bg/admin/advanced/logs.json
Normal file
7
public/language/bg/admin/advanced/logs.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"logs": "Журнали",
|
||||
"control-panel": "Контролен панел за журналите",
|
||||
"reload": "Презареждане на журналите",
|
||||
"clear": "Изчистване на журналите",
|
||||
"clear-success": "Журналите са изчистени!"
|
||||
}
|
||||
9
public/language/bg/admin/appearance/customise.json
Normal file
9
public/language/bg/admin/appearance/customise.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"custom-css": "Персонализиран CSS",
|
||||
"custom-css.description": "Въведете своите собствени декларации за стилове, те ще бъдат приложени след всички останали стилове.",
|
||||
"custom-css.enable": "Включване на персонализиран CSS",
|
||||
|
||||
"custom-header": "Персонализирана заглавна част",
|
||||
"custom-header.description": "Въведете своя персонализиран код HTML тук (напр. JavaScript, елементи „meta“ и т.н.), те ще бъдат добавени към секцията <code><head></code> в кода на Вашия форум.",
|
||||
"custom-header.enable": "Включване на персонализирана заглавна част"
|
||||
}
|
||||
9
public/language/bg/admin/appearance/skins.json
Normal file
9
public/language/bg/admin/appearance/skins.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"loading": "Зареждане на облиците…",
|
||||
"homepage": "Начална страница",
|
||||
"select-skin": "Изберете облик",
|
||||
"current-skin": "Текущ облик",
|
||||
"skin-updated": "Обликът е променен",
|
||||
"applied-success": "Обликът „%1“ беше успешно приложен",
|
||||
"revert-success": "Обликът е върнат към основните цветове."
|
||||
}
|
||||
11
public/language/bg/admin/appearance/themes.json
Normal file
11
public/language/bg/admin/appearance/themes.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"checking-for-installed": "Проверяване за инсталирани теми…",
|
||||
"homepage": "Начална страница",
|
||||
"select-theme": "Изберете тема",
|
||||
"current-theme": "Текуща тема",
|
||||
"no-themes": "Няма намерени инсталирани теми",
|
||||
"revert-confirm": "Наистина ли искате да възстановите стандартната тема на NodeBB?",
|
||||
"theme-changed": "Темата е променена",
|
||||
"revert-success": "Вие възстановихте успешно стандартната тема на NodeBB.",
|
||||
"restart-to-activate": "Моля, рестартирайте NodeBB, за да може тази тема да влезе в сила напълно."
|
||||
}
|
||||
16
public/language/bg/admin/development/info.json
Normal file
16
public/language/bg/admin/development/info.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"you-are-on": "Информация — Вие сте на <strong>%1:%2</strong>",
|
||||
"host": "сървър",
|
||||
"pid": "ид. на процеса",
|
||||
"nodejs": "nodejs",
|
||||
"online": "на линия",
|
||||
"git": "git",
|
||||
"load": "натоварване",
|
||||
"uptime": "активно време",
|
||||
|
||||
"registered": "Регистрирани",
|
||||
"sockets": "Сокети",
|
||||
"guests": "Гости",
|
||||
|
||||
"info": "Информация"
|
||||
}
|
||||
12
public/language/bg/admin/development/logger.json
Normal file
12
public/language/bg/admin/development/logger.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"logger-settings": "Настройки на журнала",
|
||||
"description": "Ако поставите отметки тук, Вие ще виждате журнала в терминала си. Ако посочите пътечка, то вместо това журналите ще бъдат записвани във файл. Журналът чрез HTTP е удобен за получаване на статистика за това кога, кои и какви хора посещават форума Ви. В допълнение към следенето на заявките чрез HTTP, можем също да следим и събитията на socket.io. Журналът на Socket.io, в комбинация с redis-cli, може да Ви бъде много полезно, ако искате да разучите как работи NodeBB.",
|
||||
"explanation": "За да включите или изключите журналите в реално време, просто поставете или премахнете отметките в настройките на журнала. Няма нужда от рестартиране.",
|
||||
"enable-http": "Включване на журнала чрез HTTP",
|
||||
"enable-socket": "Включване на журналите за събития на socket.io",
|
||||
"file-path": "Път до файла на журнала",
|
||||
"file-path-placeholder": "/път/до/файла/на/журнала.log ::: ако е празно, журналът ще се извежда в терминала",
|
||||
|
||||
"control-panel": "Контролен панел за журнала",
|
||||
"update-settings": "Промяна на настройките на журнала"
|
||||
}
|
||||
47
public/language/bg/admin/extend/plugins.json
Normal file
47
public/language/bg/admin/extend/plugins.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"installed": "Инсталирани",
|
||||
"active": "Включени",
|
||||
"inactive": "Изключени",
|
||||
"out-of-date": "Остарели",
|
||||
"none-found": "Няма намерени добавки.",
|
||||
"none-active": "Няма включени добавки.",
|
||||
"find-plugins": "Търсене на добавки",
|
||||
|
||||
"plugin-search": "Търсене на добавки",
|
||||
"plugin-search-placeholder": "Търсене на добавка…",
|
||||
"reorder-plugins": "Пренареждане на добавките",
|
||||
"order-active": "Подреждане на включените добавки",
|
||||
"dev-interested": "Искате ли да пишете добавки за NodeBB?",
|
||||
"docs-info": "Документацията за създаване на добавки може да бъде открита в <a target=\"_blank\" href=\"https://docs.nodebb.org/en/latest/plugins/create.html\">страницата с документация на NodeBB</a>.",
|
||||
|
||||
"order.description": "Някои добавки работят най-добре, ако бъдат инсталирани преди или след други добавки.",
|
||||
"order.explanation": "Добавките се зареждат в реда, посочен тук, от горе надолу.",
|
||||
|
||||
"plugin-item.themes": "Теми",
|
||||
"plugin-item.deactivate": "Изключване",
|
||||
"plugin-item.activate": "Включване",
|
||||
"plugin-item.install": "Инсталиране",
|
||||
"plugin-item.uninstall": "Деинсталиране",
|
||||
"plugin-item.settings": "Настройки",
|
||||
"plugin-item.installed": "Инсталирани",
|
||||
"plugin-item.latest": "Най-нови",
|
||||
"plugin-item.upgrade": "Обновяване",
|
||||
"plugin-item.more-info": "За повече информация",
|
||||
"plugin-item.unknown": "Неизвестно",
|
||||
"plugin-item.unknown-explanation": "Състоянието на тази добавка не може да бъде определено, може би поради грешка в конфигурацията.",
|
||||
|
||||
"alert.enabled": "Добавката е включена",
|
||||
"alert.disabled": "Добавката е изключена",
|
||||
"alert.upgraded": "Добавката е обновена",
|
||||
"alert.installed": "Добавката е инсталирана",
|
||||
"alert.uninstalled": "Добавката е деинсталирана",
|
||||
"alert.activate-success": "Моля, рестартирайте NodeBB, за да включите тази добавка напълно.",
|
||||
"alert.deactivate-success": "Добавката е изключена успешно.",
|
||||
"alert.upgrade-success": "Моля, презаредете NodeBB, за да обновите тази добавка напълно.",
|
||||
"alert.install-success": "Добавката е инсталирана успешно, моля, включете я",
|
||||
"alert.uninstall-success": "Добавката беше изключена и деинсталирана успешно.",
|
||||
"alert.suggest-error": "<p>NodeBB не може да се свърже с пакетния мениджър. Искате ли да продължите с инсталацията на най-новата версия?</p><div class=\"alert alert-danger\"><strong>Сървърът върна (%1)</strong>: %2</div>",
|
||||
"alert.package-manager-unreachable": "<p>NodeBB не може да се свърже с пакетния мениджър. Не се препоръчва обновяване в момента.</p>",
|
||||
"alert.incompatible": "<p>Вашата версия на NodeBB (версия %1) може да използва най-много версия %2 на тази добавка. Моля, обновете NodeBB, ако искате да инсталирате по-нова версия на тази добавка.</p>",
|
||||
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>Няма информация за съвместимостта</strong></p><p>Тази добавка не е посочила конкретна версия за инсталация, съвместима с Вашата версия на NodeBB. Не можем да гарантираме пълна съвместимост и има възможност Вашият NodeBB да не може да стартира правилно.</p></div><p>Ако NodeBB не може да стартира, използвайте следната команда:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Искате ли да продължите с инсталацията на най-новата версия на тази добавка?</p>"
|
||||
}
|
||||
17
public/language/bg/admin/extend/rewards.json
Normal file
17
public/language/bg/admin/extend/rewards.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"rewards": "Награди",
|
||||
"condition-if-users": "Ако потребителският(ата/ото)",
|
||||
"condition-is": "Е:",
|
||||
"condition-then": "Тогава:",
|
||||
"max-claims": "Колко пъти може да бъде получавана наградата",
|
||||
"zero-infinite": "0 = безкраен брой пъти",
|
||||
"delete": "Изтриване",
|
||||
"enable": "Включване",
|
||||
"disable": "Изключване",
|
||||
"control-panel": "Управление на наградите",
|
||||
"new-reward": "Нова награда",
|
||||
|
||||
"alert.delete-success": "Наградата е изтрита успешно",
|
||||
"alert.no-inputs-found": "Неправомерна награда — няма нищо въведено!",
|
||||
"alert.save-success": "Наградите са запазени успешно"
|
||||
}
|
||||
19
public/language/bg/admin/extend/widgets.json
Normal file
19
public/language/bg/admin/extend/widgets.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"available": "Налични джаджи",
|
||||
"explanation": "Изберете джаджа от падащото меню, а след това я завлачете и пуснете в областта за джаджи в някой от шаблоните вляво.",
|
||||
"none-installed": "Няма намерени джаджи! Включете добавката с основните джаджи в контролния панел за <a href=\"%1\">добавките</a>.",
|
||||
"containers.available": "Налични контейнери",
|
||||
"containers.explanation": "Завлачете и пуснете върху някоя активна джаджа",
|
||||
"containers.none": "Няма",
|
||||
"container.well": "Кладенец",
|
||||
"container.jumbotron": "Джъмботрон",
|
||||
"container.panel": "Панел",
|
||||
"container.panel-header": "Заглавна част на панел",
|
||||
"container.panel-body": "Основна част на панел",
|
||||
"container.alert": "Предупреждение",
|
||||
|
||||
"alert.confirm-delete": "Наистина ли искате да изтриете джаджата?",
|
||||
"alert.updated": "Джаджите са обновени",
|
||||
"alert.update-success": "Джаджите са обновени успешно"
|
||||
|
||||
}
|
||||
64
public/language/bg/admin/general/dashboard.json
Normal file
64
public/language/bg/admin/general/dashboard.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"forum-traffic": "Трафик на форума",
|
||||
"page-views": "Преглеждания на страниците",
|
||||
"unique-visitors": "Уникални посетители",
|
||||
"users": "Потребители",
|
||||
"posts": "Публикации",
|
||||
"topics": "Теми",
|
||||
"page-views-last-month": "Преглеждания на страниците през последния месец",
|
||||
"page-views-this-month": "Преглеждания на страниците този месец",
|
||||
"page-views-last-day": "Преглеждания на страниците през последните 24 часа",
|
||||
|
||||
"stats.day": "Ден",
|
||||
"stats.week": "Седмица",
|
||||
"stats.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/en/latest/upgrading/index.html\">обновете NodeBB</a>.</p>",
|
||||
"prerelease-upgrade-available": "<p>Това е остаряла версия за предварителен преглед на NodeBB. Има нова версия (версия %1). Ако имате възможност, <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">обновете NodeBB</a>.</p>",
|
||||
"prerelease-warning": "<p>Това е версия за <strong>предварителен преглед</strong> на NodeBB. Възможно е да има неочаквани неизправности. <i class=\"fa fa-exclamation-triangle\"></i></p>",
|
||||
"running-in-development": "<span>Форумът работи в режим за разработчици, така че може да бъде уязвим. Моля, свържете се със системния си администратор.</span>",
|
||||
|
||||
"notices": "Забележки",
|
||||
"restart-not-required": "Не се изисква рестартиране",
|
||||
"restart-required": "Изисква се рестартиране",
|
||||
"search-plugin-installed": "Добавката за търсене е инсталирана",
|
||||
"search-plugin-not-installed": "Добавката за търсене не е инсталирана",
|
||||
"search-plugin-tooltip": "Инсталирайте добавка за търсене от страницата с добавките, за да включите функционалността за търсене",
|
||||
|
||||
"control-panel": "Системен контрол",
|
||||
"reload": "Презареждане",
|
||||
"restart": "Рестартиране",
|
||||
"restart-warning": "Презареждането и рестартирането на 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.unique-visitors": "Уникални посетители",
|
||||
"graphs.registered-users": "Регистрирани потребители",
|
||||
"graphs.anonymous-users": "Анонимни потребители"
|
||||
}
|
||||
7
public/language/bg/admin/general/homepage.json
Normal file
7
public/language/bg/admin/general/homepage.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"home-page": "Начална страница",
|
||||
"description": "Изберете коя страница да бъде показана, когато потребителите отидат на главния адрес на форума.",
|
||||
"home-page-route": "Път на началната страница",
|
||||
"custom-route": "Персонализиран път",
|
||||
"allow-user-home-pages": "Разрешаване на потребителските начални страници"
|
||||
}
|
||||
5
public/language/bg/admin/general/languages.json
Normal file
5
public/language/bg/admin/general/languages.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"language-settings": "Езикови настройки",
|
||||
"description": "Езикът по подразбиране определя езиковите настройки за всички потребители, които посещават Вашия форум. <br />Отделните потребители могат да сменят езика си от страницата с настройки на профила си.",
|
||||
"default-language": "Език по подразбиране"
|
||||
}
|
||||
27
public/language/bg/admin/general/navigation.json
Normal file
27
public/language/bg/admin/general/navigation.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"icon": "Иконка:",
|
||||
"change-icon": "промяна",
|
||||
"route": "Маршрут:",
|
||||
"tooltip": "Подсказка:",
|
||||
"text": "Текст:",
|
||||
"text-class": "Текстов клас: <small>незадължително</small>",
|
||||
"id": "Идентификатор: <small>незадължително</small>",
|
||||
|
||||
"properties": "Свойства:",
|
||||
"only-admins": "Да е видимо само за администраторите",
|
||||
"only-global-mods-and-admins": "Да е видимо само за глобалните модератори и администраторите",
|
||||
"only-logged-in": "Да е видимо само за вписаните потребители",
|
||||
"open-new-window": "Отваряне в нов прозорец",
|
||||
|
||||
"installed-plugins-required": "Нужни инсталирани добавки:",
|
||||
"search-plugin": "Търсене на добавката",
|
||||
|
||||
"btn.delete": "Изтриване",
|
||||
"btn.disable": "Изключване",
|
||||
"btn.enable": "Включване",
|
||||
|
||||
"available-menu-items": "Налични елементи за менюто",
|
||||
"custom-route": "Персонализиран маршрут",
|
||||
"core": "ядро",
|
||||
"plugin": "добавка"
|
||||
}
|
||||
5
public/language/bg/admin/general/social.json
Normal file
5
public/language/bg/admin/general/social.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"post-sharing": "Споделяне на публикации",
|
||||
"info-plugins-additional": "Добавките могат да добавят допълнителни мрежи за споделяне на публикации.",
|
||||
"save-success": "Мрежите за споделяне на публикации са запазени успешно!"
|
||||
}
|
||||
9
public/language/bg/admin/general/sounds.json
Normal file
9
public/language/bg/admin/general/sounds.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"notifications": "Известия",
|
||||
"chat-messages": "Съобщения в разговори",
|
||||
"play-sound": "Пускане",
|
||||
"incoming-message": "Входящо съобщение",
|
||||
"outgoing-message": "Изходящо съобщение",
|
||||
"upload-new-sound": "Качване на нов звук",
|
||||
"saved": "Настройките са запазени"
|
||||
}
|
||||
68
public/language/bg/admin/manage/categories.json
Normal file
68
public/language/bg/admin/manage/categories.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"settings": "Настройки на категорията",
|
||||
"privileges": "Правомощия",
|
||||
|
||||
"name": "Име на категорията",
|
||||
"description": "Описание на категорията",
|
||||
"bg-color": "Цвят на фона",
|
||||
"text-color": "Цвят на текста",
|
||||
"bg-image-size": "Размер на фоновото изображение",
|
||||
"custom-class": "Персонализиран клас",
|
||||
"num-recent-replies": "Брой на скорошните отговори",
|
||||
"ext-link": "Външна връзка",
|
||||
"upload-image": "Качване на изображение",
|
||||
"delete-image": "Премахване",
|
||||
"category-image": "Изображение на категорията",
|
||||
"parent-category": "Базова категория",
|
||||
"optional-parent-category": "(Незадължително) Базова категория",
|
||||
"parent-category-none": "(Няма)",
|
||||
"copy-settings": "Копиране на настройките от",
|
||||
"optional-clone-settings": "(Незадължително) Копиране на настройките от категория",
|
||||
"purge": "Изтриване на категорията",
|
||||
|
||||
"enable": "Включване",
|
||||
"disable": "Изключване",
|
||||
"edit": "Редактиране",
|
||||
|
||||
"select-category": "Изберете категория",
|
||||
"set-parent-category": "Задайте базова категория",
|
||||
|
||||
"privileges.description": "В тази секция можете да настроите правомощията за достъп до тази категория. Правомощията могат да бъдат давани на отделни потребители или на цели групи. Можете да добавите нов потребител в тази таблица като го потърсите чрез формуляра по-долу.",
|
||||
"privileges.warning": "<strong>Забележка</strong>: Настройките за правомощията влизат в сила моментално. Не е нужно да запазвате категорията след като промените тези настройки.",
|
||||
"privileges.section-viewing": "Правомощия за преглед",
|
||||
"privileges.section-posting": "Правомощия за публикуване",
|
||||
"privileges.section-moderation": "Правомощия за модериране",
|
||||
"privileges.section-user": "Потребител",
|
||||
"privileges.search-user": "Добавяне на потребител",
|
||||
"privileges.no-users": "В тази категория няма правомощия за отделни потребители.",
|
||||
"privileges.section-group": "Група",
|
||||
"privileges.group-private": "Тази група е частна",
|
||||
"privileges.search-group": "Добавяне на група",
|
||||
"privileges.copy-to-children": "Копиране в наследниците",
|
||||
"privileges.copy-from-category": "Копиране от категория",
|
||||
"privileges.inherit": "Ако групата на <code>регистрираните потребители</code> получи дадено правомощие, всички останали групи го получават като <strong>подразбиращо се правомощие</strong>, дори то да не им е специално дадено. Вие виждате това подразбиращо се правомощие, защото всички потребители са членове на групата на <code>регистрираните потребители</code>, така че няма нужда да се дават едни и същи правомощия на още групи.",
|
||||
|
||||
"analytics.back": "Назад към списъка с категориите",
|
||||
"analytics.title": "Аналитични данни за категорията „%1“",
|
||||
"analytics.pageviews-hourly": "<strong>Фигура 1</strong> – Преглеждания на час за тази категория</small>",
|
||||
"analytics.pageviews-daily": "<strong>Фигура 2</strong> – Преглеждания на ден за тази категория</small>",
|
||||
"analytics.topics-daily": "<strong>Фигура 3</strong> – Брой теми в тази категория на ден</small>",
|
||||
"analytics.posts-daily": "<strong>Фигура 4</strong> – Брой публикации в тази категория на ден</small>",
|
||||
|
||||
"alert.created": "Създадена",
|
||||
"alert.create-success": "Категорията е създадена успешно!",
|
||||
"alert.none-active": "Нямате активни категории.",
|
||||
"alert.create": "Създаване на категория",
|
||||
"alert.confirm-moderate": "<strong>Наистина ли искате да дадете правомощието за модериране на тази потребителска група?</strong> Тази група е публична и всеки може свободно да се присъедини към нея.",
|
||||
"alert.confirm-purge": "<p class=\"lead\">Наистина ли искате да изтриете категорията „%1“?</p><h5><strong class=\"text-danger\">Внимание!</strong> Всички теми и публикации в тази категория ще бъдат изтрити!</h5> <p class=\"help-block\">Изтриването на категорията ще премахне всички теми и публикации, и ще изтрие категорията от базата данни. Ако искате да премахнете категорията <em>временно</em>, можете просто да я „изключите“.</p>",
|
||||
"alert.purge-success": "Категорията е изтрита!",
|
||||
"alert.copy-success": "Настройките са копирани!",
|
||||
"alert.set-parent-category": "Задаване на базова категория",
|
||||
"alert.updated": "Обновени категории",
|
||||
"alert.updated-success": "Категориите с идентификатори %1 са обновени успешно.",
|
||||
"alert.upload-image": "Качване на изображение за категорията",
|
||||
"alert.find-user": "Търсене на потребител",
|
||||
"alert.user-search": "Потърсете потребител тук…",
|
||||
"alert.find-group": "Търсене на група",
|
||||
"alert.group-search": "Потърсете група тук…"
|
||||
}
|
||||
19
public/language/bg/admin/manage/flags.json
Normal file
19
public/language/bg/admin/manage/flags.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"daily": "Дневни доклади",
|
||||
"by-user": "Доклади по потребител",
|
||||
"by-user-search": "Търсене на докладвани публикации по потребителско име",
|
||||
"category": "Категория",
|
||||
"sort-by": "Подреждане по",
|
||||
"sort-by.most-flags": "Най-много доклади",
|
||||
"sort-by.most-recent": "Най-скорошни",
|
||||
"search": "Търсене",
|
||||
"dismiss-all": "Премахване на всички",
|
||||
"none-flagged": "Няма докладвани публикации!",
|
||||
"posted-in": "Публикувано в %1",
|
||||
"read-more": "Прочетете повече",
|
||||
"flagged-x-times": "Тази публикация е докладвана %1 път(и):",
|
||||
"dismiss": "Премахване на този доклад",
|
||||
"delete-post": "Изтриване на публикацията",
|
||||
|
||||
"alerts.confirm-delete-post": "Наистина ли искате да изтриете тази публикация?"
|
||||
}
|
||||
34
public/language/bg/admin/manage/groups.json
Normal file
34
public/language/bg/admin/manage/groups.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Име на групата",
|
||||
"description": "Описание на групата",
|
||||
"system": "Системна група",
|
||||
"edit": "Редактиране",
|
||||
"search-placeholder": "Търсене",
|
||||
"create": "Създаване на група",
|
||||
"description-placeholder": "Кратко описание на групата",
|
||||
"create-button": "Създаване",
|
||||
|
||||
"alerts.create-failure": "<strong>Опа!</strong><p>Възникна проблем при създаването на групата. Моля, опитайте отново по-късно!</p>",
|
||||
"alerts.confirm-delete": "Наистина ли искате да изтриете тази група?",
|
||||
|
||||
"edit.name": "Име",
|
||||
"edit.description": "Описание",
|
||||
"edit.user-title": "Звание на членовете",
|
||||
"edit.icon": "Иконка на групата",
|
||||
"edit.label-color": "Цвята за етикета на групата",
|
||||
"edit.show-badge": "Показване на емблема",
|
||||
"edit.private-details": "Ако е включено, присъединяването към група ще изисква одобрение от собственик на групата.",
|
||||
"edit.private-override": "Внимание: Частните групи са изключени на системно ниво, това пренебрегва тази настройка.",
|
||||
"edit.disable-requests": "Изключване на заявките за присъединяване",
|
||||
"edit.hidden": "Скрита",
|
||||
"edit.hidden-details": "Ако е включено, групата няма да е видима в списъка с групи и ще трябва потребителите да бъдат поканени специално.",
|
||||
"edit.add-user": "Добавяне на потребител към групата",
|
||||
"edit.add-user-search": "Търсене на потребители",
|
||||
"edit.members": "Списък на членовете",
|
||||
"control-panel": "Контролен панел за групите",
|
||||
"revert": "Отмяна",
|
||||
|
||||
"edit.no-users-found": "Няма намерени потребители",
|
||||
"edit.confirm-remove-user": "Наистина ли искате да премахнете този потребител?",
|
||||
"edit.save-success": "Промените са запазени!"
|
||||
}
|
||||
15
public/language/bg/admin/manage/ip-blacklist.json
Normal file
15
public/language/bg/admin/manage/ip-blacklist.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"lead": "Тук можете да настроите своя черен списък за IP адреси.",
|
||||
"description": "Понякога блокирането на даден потребителски профил не е достатъчно. В такива случаи, най-добрият начин за защитаване на форума е ограничаването на достъпа до форума за конкретен IP адрес или група от адреси. В този черен списък можете да добавите проблемните IP адреси или цял блок CIDR, и тези адреси няма да могат да влизат в системата или да регистрират нови профили.",
|
||||
"active-rules": "Активни правила",
|
||||
"validate": "Проверка на черния списък",
|
||||
"apply": "Прилагане на черния списък",
|
||||
"hints": "Съвети за синтактиса",
|
||||
"hint-1": "Въвеждайте по един IP адрес на ред. Можете да добавяте групи от IP адреси, ако спазват формата на CIDR (напр. <code>192.168.100.0/22</code>).",
|
||||
"hint-2": "Можете да добавяте коментари, като в началото на реда поставите знака <code>#</code>.",
|
||||
|
||||
"validate.x-valid": "Правилни правила: <strong>%1</strong> от <strong>%2</strong>.",
|
||||
"validate.x-invalid": "Следните <strong>%1</strong> правила са грешни:",
|
||||
|
||||
"alerts.applied-success": "Черният списък е приложен"
|
||||
}
|
||||
20
public/language/bg/admin/manage/registration.json
Normal file
20
public/language/bg/admin/manage/registration.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"queue": "Опашка",
|
||||
"description": "Няма потребители в регистрационната опашка. <br> За да включите тази функционалност, отидете в <a href=\"%1\">Настройки → Потребител → Регистриране на потребителите</a> и задайте <strong>Вид регистриране</strong> на „Одобрение от администратор“.",
|
||||
|
||||
"list.name": "Няма",
|
||||
"list.email": "Е-поща",
|
||||
"list.ip": "IP адрес",
|
||||
"list.time": "Време",
|
||||
"list.username-spam": "Честота: %1 Появяване: %2 Увереност: %3",
|
||||
"list.email-spam": "Честота: %1 Появяване: %2",
|
||||
"list.ip-spam": "Честота: %1 Появяване: %2",
|
||||
|
||||
"invitations": "Покани",
|
||||
"invitations.description": "По-долу ще намерите пълен списък от изпратените покани. Използвайте „Ctrl-F“, за да търсите е-поща или потребителско име в списъка. <br><br>Потребителското име ще бъде показано вдясно от е-пощата за потребителите, които са приели поканата си.",
|
||||
"invitations.inviter-username": "Потребителско име на канещия",
|
||||
"invitations.invitee-email": "Е-поща на поканения",
|
||||
"invitations.invitee-username": "Потребителско име на поканения (ако е регистриран)",
|
||||
|
||||
"invitations.confirm-delete": "Наистина ли искате да изтриете тази покана?"
|
||||
}
|
||||
18
public/language/bg/admin/manage/tags.json
Normal file
18
public/language/bg/admin/manage/tags.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"none": "Форумът все още няма теми с етикети.",
|
||||
"bg-color": "Цвят на фона",
|
||||
"text-color": "Цвят на текста",
|
||||
"create-modify": "Създаване и редактиране на етикети",
|
||||
"description": "Изберете етикетите чрез щракване и/или влачене. Използвайте „Shift“, за да изберете няколко етикета.",
|
||||
"create": "Създаване на етикет",
|
||||
"modify": "Редактиране на етикети",
|
||||
"delete": "Изтриване на избраните етикети",
|
||||
"search": "Търсене на етикети…",
|
||||
"settings": "Натиснете <a href=\"%1\">тук</a>, за да отворите страницата с настройки на етикета.",
|
||||
"name": "Име на етикета",
|
||||
|
||||
"alerts.editing-multiple": "Редактиране на множество етикети",
|
||||
"alerts.editing-x": "Редактиране на етикета „%1“",
|
||||
"alerts.confirm-delete": "Наистина ли искате да изтриете избраните етикети?",
|
||||
"alerts.update-success": "Етикетът е променен!"
|
||||
}
|
||||
91
public/language/bg/admin/manage/users.json
Normal file
91
public/language/bg/admin/manage/users.json
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"users": "Потребители",
|
||||
"edit": "Редактиране",
|
||||
"make-admin": "Даване на администраторски права",
|
||||
"remove-admin": "Отнемане на администраторски права",
|
||||
"validate-email": "Проверка на е-пощата",
|
||||
"send-validation-email": "Изпращане на е-писмо за потвърждение",
|
||||
"password-reset-email": "Изпращане на е-писмо за възстановяване на паролата",
|
||||
"ban": "Блокиране на потребителя/ите",
|
||||
"temp-ban": "Блокиране на потребителя/ите временно",
|
||||
"unban": "Деблокиране на потребителя/ите",
|
||||
"reset-lockout": "Нулиране на заключването",
|
||||
"reset-flags": "Анулиране на докладите",
|
||||
"delete": "Изтриване на потребителя/ите",
|
||||
"purge": "Изтриване на потребителя/ите и съдържанието",
|
||||
"download-csv": "Сваляне във формат „CSV“",
|
||||
"invite": "Покана",
|
||||
"new": "Нов потребител",
|
||||
|
||||
"pills.latest": "Последни потребители",
|
||||
"pills.unvalidated": "Няма потвърдена е-поща",
|
||||
"pills.no-posts": "Няма публикации",
|
||||
"pills.top-posters": "С най-много публикации",
|
||||
"pills.top-rep": "С най-много репутация",
|
||||
"pills.inactive": "Недеен",
|
||||
"pills.flagged": "С най-много доклади",
|
||||
"pills.banned": "Блокиран",
|
||||
"pills.search": "Търсене на потребители",
|
||||
|
||||
"search.username": "По име на потребител",
|
||||
"search.username-placeholder": "Въведете потребителско име, което да потърсите",
|
||||
"search.email": "По е-поща",
|
||||
"search.email-placeholder": "Въведете е-поща, която да потърсите",
|
||||
"search.ip": "По IP адрес",
|
||||
"search.ip-placeholder": "Въведете IP адрес, който да потърсите",
|
||||
"search.not-found": "Потребителят не е намерен!",
|
||||
|
||||
"inactive.3-months": "3 месеца",
|
||||
"inactive.6-months": "6 месеца",
|
||||
"inactive.12-months": "12 месеца",
|
||||
|
||||
"users.uid": "потр. ид.",
|
||||
"users.username": "потребителско име",
|
||||
"users.email": "е-поща",
|
||||
"users.postcount": "брой публикации",
|
||||
"users.reputation": "репутация",
|
||||
"users.flags": "доклади",
|
||||
"users.joined": "присъединил се",
|
||||
"users.last-online": "последно на линия",
|
||||
"users.banned": "блокиран",
|
||||
|
||||
"create.username": "Потребителско име",
|
||||
"create.email": "Е-поща",
|
||||
"create.email-placeholder": "Е-поща на този потребител",
|
||||
"create.password": "Парола",
|
||||
"create.password-confirm": "Потвърдете паролата",
|
||||
|
||||
"temp-ban.length": "Продължителност на блокирането",
|
||||
"temp-ban.reason": "Причина <span class=\"text-muted\">(незадължително)</span>",
|
||||
"temp-ban.hours": "Часове",
|
||||
"temp-ban.days": "Дни",
|
||||
"temp-ban.explanation": "Въведете продължителността на блокирането. Стойност от 0 ще направи блокирането за постоянно.",
|
||||
|
||||
"alerts.confirm-ban": "Наистина ли искате да блокирате този потребител <strong>за постоянно</strong>?",
|
||||
"alerts.confirm-ban-multi": "Наистина ли искате да блокирате тези потребители <strong>за постоянно</strong>?",
|
||||
"alerts.ban-success": "Потребителят/ите е/са блокиран(и)!",
|
||||
"alerts.button-ban-x": "Блокиране на %1 потребител(и)",
|
||||
"alerts.unban-success": "Потребителят/ите е/са деблокиран(и)!",
|
||||
"alerts.lockout-reset-success": "Заключването/ията е/са нулирано/и!",
|
||||
"alerts.flag-reset-success": "Докладът/ите е/са анулиран(и)!",
|
||||
"alerts.no-remove-yourself-admin": "Не можете да отнемете собствените си права на администратор!",
|
||||
"alerts.make-admin-success": "Потребителят/ите вече е/са администратор(и).",
|
||||
"alerts.confirm-remove-admin": "Наистина ли искате да премахнете администраторите?",
|
||||
"alerts.remove-admin-success": "Потребителят/ите вече не е/са администратор(и)",
|
||||
"alerts.confirm-validate-email": "Искате ли да проверите е-пощата/ите на този/тези потребител(и)?",
|
||||
"alerts.validate-email-success": "Е-пощите са проверени",
|
||||
"alerts.password-reset-confirm": "Искате ли да изпратите е-писмо/а за възстановяване на паролата на този/тези потребител(и)?",
|
||||
"alerts.confirm-delete": "<b>ВНИМАНИЕ!</b><br/>Наистина ли искате да изтриете потребителя/ите?<br/> Това действие е необратимо! Ще бъде изтрит само профилът на потребителя/ите, неговите/техните публикациите и теми ще останат.",
|
||||
"alerts.delete-success": "Потребителят/ите е/са изтрит(и)!",
|
||||
"alerts.confirm-purge": "<b>ВНИМАНИЕ!</b><br/>Наистина ли искате да изтриете потребителя/ите?<br/> Това действие е необратимо! Всички потребителски данни и съдържание ще бъдат заличени!",
|
||||
"alerts.create": "Създаване на потребител",
|
||||
"alerts.button-create": "Създаване",
|
||||
"alerts.button-cancel": "Отказ",
|
||||
"alerts.error-passwords-different": "Паролите са различни!",
|
||||
"alerts.error-x": "<strong>Грешка</strong><p>%1</p>",
|
||||
"alerts.create-success": "Потребителят е създаден!",
|
||||
|
||||
"alerts.prompt-email": "Е-поща:",
|
||||
"alerts.email-sent-to": "Беше изпратено е-писмо за потвърждение до %1",
|
||||
"alerts.x-users-found": "Намерени потребители: %1! Търсенето отне %2 милисекунди."
|
||||
}
|
||||
74
public/language/bg/admin/menu.json
Normal file
74
public/language/bg/admin/menu.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"section-general": "Общи",
|
||||
"general/dashboard": "Табло",
|
||||
"general/homepage": "Начало",
|
||||
"general/navigation": "Навигация",
|
||||
"general/languages": "Езици",
|
||||
"general/sounds": "Звуци",
|
||||
"general/social": "Обществени",
|
||||
|
||||
"section-manage": "Управление",
|
||||
"manage/categories": "Категории",
|
||||
"manage/tags": "Етикети",
|
||||
"manage/users": "Потребители",
|
||||
"manage/registration": "Регистрационна опашка",
|
||||
"manage/groups": "Групи",
|
||||
"manage/ip-blacklist": "Черен списък за IP адреси",
|
||||
|
||||
"section-settings": "Настройки",
|
||||
"settings/general": "Общи",
|
||||
"settings/reputation": "Репутация",
|
||||
"settings/email": "Е-поща",
|
||||
"settings/user": "Потребител",
|
||||
"settings/group": "Група",
|
||||
"settings/guest": "Гости",
|
||||
"settings/uploads": "Качвания",
|
||||
"settings/post": "Публикация",
|
||||
"settings/chat": "Разговор",
|
||||
"settings/pagination": "Странициране",
|
||||
"settings/tags": "Етикети",
|
||||
"settings/notifications": "Известия",
|
||||
"settings/cookies": "Бисквитки",
|
||||
"settings/web-crawler": "Обхождач на уеб страници",
|
||||
"settings/sockets": "Сокети",
|
||||
"settings/advanced": "Разширени",
|
||||
|
||||
"settings.page-title": "Настройки на %1",
|
||||
|
||||
"section-appearance": "Външен вид",
|
||||
"appearance/themes": "Теми",
|
||||
"appearance/skins": "Облици",
|
||||
"appearance/customise": "Персонализиран HTML и CSS",
|
||||
|
||||
"section-extend": "Разширяване",
|
||||
"extend/plugins": "Добавки",
|
||||
"extend/widgets": "Джаджи",
|
||||
"extend/rewards": "Награди",
|
||||
|
||||
"section-social-auth": "Обществено удостоверяване",
|
||||
|
||||
"section-plugins": "Добавки",
|
||||
"extend/plugins.install": "Инсталиране на добавки",
|
||||
|
||||
"section-advanced": "Разширени",
|
||||
"advanced/database": "База данни",
|
||||
"advanced/events": "Събития",
|
||||
"advanced/logs": "Журнали",
|
||||
"advanced/errors": "Грешки",
|
||||
"advanced/cache": "Кеш",
|
||||
"development/logger": "Система на журнала",
|
||||
"development/info": "Информация",
|
||||
|
||||
"reload-forum": "Презареждане на форума",
|
||||
"restart-forum": "Рестартиране на форума",
|
||||
"logout": "Изход",
|
||||
"view-forum": "Преглед на форума",
|
||||
|
||||
"search.placeholder": "Търсене…",
|
||||
"search.no-results": "Няма резултати…",
|
||||
"search.search-forum": "Търсене във форума за <strong></strong>",
|
||||
"search.keep-typing": "Продължете да пишете, за да видите още резултати…",
|
||||
"search.start-typing": "Започнете да пишете, за да получите резултати…",
|
||||
|
||||
"connection-lost": "Връзката към %1 беше прекъсната. опитваме се да Ви свържем отново…"
|
||||
}
|
||||
19
public/language/bg/admin/settings/advanced.json
Normal file
19
public/language/bg/admin/settings/advanced.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"maintenance-mode": "Режим на профилактика",
|
||||
"maintenance-mode.help": "Когато форумът е в режим на профилактика, всички заявки ще бъдат пренасочвани към статична страница за изчакване, с изключение на администраторите, които ще могат да използват уеб сайта нормално.",
|
||||
"maintenance-mode.message": "Съобщение за профилактиката",
|
||||
"headers": "Заглавни части",
|
||||
"headers.allow-from": "Задайте „ALLOW-FROM“, за да поставите NodeBB в „iFrame“",
|
||||
"headers.powered-by": "Персонализиране на заглавната част „Захранван от“, която се изпраща от NodeBB",
|
||||
"headers.acao": "Произход за разрешаване на управлението на достъпа",
|
||||
"headers.acao-help": "За да забраните достъпа до всички уеб сайтове, оставете празно или задайте <code>null</code>",
|
||||
"headers.acam": "Методи за разрешаване на управлението на достъпа",
|
||||
"headers.acah": "Заглавки за разрешаване на управлението на достъпа",
|
||||
"traffic-management": "Управление на трафика",
|
||||
"traffic.help": "NodeBB има вграден модул, който автоматично отказва заявките в натоварените моменти. Можете да настроите поведението тук, въпреки че стойностите по подразбиране са добра отправна точка.",
|
||||
"traffic.enable": "Включване на управлението на трафика",
|
||||
"traffic.event-lag": "Граница на забавяне в цикъла на събитията (в милисекунди)",
|
||||
"traffic.event-lag-help": "Намаляването на тази стойност ще намали времето за изчакване при зареждане на страници, но също така ще предизвика по-често показване на съобщението „прекомерно натоварване“ на повече потребители. (Нужно е рестартиране.)",
|
||||
"traffic.lag-check-interval": "Интервал на проверка (в милисекунди)",
|
||||
"traffic.lag-check-interval-help": "Намаляването на тази стойност ще направи NodeBB по-чувствителен към скоковете в натовареността, но може и да направи проверката твърде чувствителна. (Нужно е рестартиране.)"
|
||||
}
|
||||
9
public/language/bg/admin/settings/chat.json
Normal file
9
public/language/bg/admin/settings/chat.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"chat-settings": "Настройки на разговорите",
|
||||
"disable": "Изключване на разговорите",
|
||||
"disable-editing": "Изключване на редактирането и изтриването на съобщения в разговорите",
|
||||
"disable-editing-help": "Това ограничение не засяга администраторите и глобалните модератори",
|
||||
"max-length": "Максимална дължина на съобщенията в разговорите",
|
||||
"max-room-size": "Максимален брой потребители в стая за разговор",
|
||||
"delay": "Време между съобщеният в разговорите (в милисекунди)"
|
||||
}
|
||||
11
public/language/bg/admin/settings/cookies.json
Normal file
11
public/language/bg/admin/settings/cookies.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"eu-consent": "Съглашение на ЕС",
|
||||
"consent.enabled": "Включено",
|
||||
"consent.message": "Съобщение за известие",
|
||||
"consent.acceptance": "Съобщение за приемане",
|
||||
"consent.link-text": "Връзка към текста на политиката",
|
||||
"consent.blank-localised-default": "Оставете това празно, за да използвате данните по подразбиране на NodeBB, които са преведени",
|
||||
"settings": "Настройки",
|
||||
"cookie-domain": "Домейн на бисквитката за сесията",
|
||||
"blank-default": "Оставете празно, за да използвате стойността по подразбиране"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user