Compare commits
1097 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9f3fdede | ||
|
|
a778109214 | ||
|
|
cb7fa9375b | ||
|
|
515ecb09e7 | ||
|
|
a12a620697 | ||
|
|
0c3b2bc2f5 | ||
|
|
78ba27dc63 | ||
|
|
dc20b863ed | ||
|
|
c9a211d5cf | ||
|
|
95f94cffd2 | ||
|
|
0da95cbdb8 | ||
|
|
dadd1e3101 | ||
|
|
d523ae3ffa | ||
|
|
9a41cac6e1 | ||
|
|
5d3c5ab7cc | ||
|
|
e94ded920b | ||
|
|
c882fbd59a | ||
|
|
46b50a042e | ||
|
|
fda9e95786 | ||
|
|
ea1ad23bff | ||
|
|
7ffc5e0212 | ||
|
|
acba9444f4 | ||
|
|
f7e3671801 | ||
|
|
a1b2e36a5d | ||
|
|
44e96942b3 | ||
|
|
f2efa760ff | ||
|
|
256df9042b | ||
|
|
6d7091fb5c | ||
|
|
0d1f88a368 | ||
|
|
2ae601717d | ||
|
|
c7c8b463b4 | ||
|
|
282f839211 | ||
|
|
b2eb846b69 | ||
|
|
62cf925dcf | ||
|
|
e699f84c4d | ||
|
|
c1189dadc5 | ||
|
|
76bc080a6d | ||
|
|
7f989f77ac | ||
|
|
b916f768fe | ||
|
|
e4509c5714 | ||
|
|
ddb6893a64 | ||
|
|
248751ba1d | ||
|
|
b4b74ed53a | ||
|
|
76903cd67f | ||
|
|
e4f2eac703 | ||
|
|
3aa45007a7 | ||
|
|
f452892c88 | ||
|
|
a0fece8a0e | ||
|
|
e3d493209b | ||
|
|
2e8b63553d | ||
|
|
fb8f4b95b7 | ||
|
|
83e107c713 | ||
|
|
e97642a790 | ||
|
|
426d8684bf | ||
|
|
5e7409a4f0 | ||
|
|
c225a4cd48 | ||
|
|
24df9e1ce6 | ||
|
|
eab1fd3722 | ||
|
|
93bd041693 | ||
|
|
665ebe993c | ||
|
|
4086130371 | ||
|
|
29aacf5238 | ||
|
|
497e6a8422 | ||
|
|
af8572add9 | ||
|
|
d6aea96400 | ||
|
|
17e26ff1a6 | ||
|
|
f5f223348d | ||
|
|
e4f90fd7ea | ||
|
|
96dff20760 | ||
|
|
d639f7f6de | ||
|
|
5b35ec2ea2 | ||
|
|
bc78b95265 | ||
|
|
97f22eccbb | ||
|
|
a4fe86e38a | ||
|
|
4bc1e10ecb | ||
|
|
5b840d73bb | ||
|
|
afa9acfb1e | ||
|
|
7b7f65da39 | ||
|
|
806da59f47 | ||
|
|
9a009a4ea3 | ||
|
|
083d890053 | ||
|
|
e693a8aeb8 | ||
|
|
831b46d7b5 | ||
|
|
8dd3022b94 | ||
|
|
b278eb7110 | ||
|
|
7a66163216 | ||
|
|
dda2043401 | ||
|
|
08d6183c9b | ||
|
|
eea0b86d6d | ||
|
|
58c04fd196 | ||
|
|
09de6f6b5f | ||
|
|
d0bbd2b539 | ||
|
|
134595a6b7 | ||
|
|
4ff46f1650 | ||
|
|
4779201d4c | ||
|
|
3a8643d83c | ||
|
|
806a49b822 | ||
|
|
95d74825ee | ||
|
|
e4960909ed | ||
|
|
6cb36aaf13 | ||
|
|
cb06e93650 | ||
|
|
e3a2f7a514 | ||
|
|
01b1e817d8 | ||
|
|
c3a5195575 | ||
|
|
99765c7bd5 | ||
|
|
8929f389f4 | ||
|
|
4141d91f1b | ||
|
|
90272c84d2 | ||
|
|
3006a8e58c | ||
|
|
52a9dbd45d | ||
|
|
b2fb55d2c1 | ||
|
|
a1c16d22d8 | ||
|
|
0e9504ee4d | ||
|
|
e8cad6fc20 | ||
|
|
bc261f7739 | ||
|
|
0b8983a86b | ||
|
|
5a61da3c53 | ||
|
|
800fe6244c | ||
|
|
9e1fec812c | ||
|
|
61632f9c97 | ||
|
|
f5e44129d8 | ||
|
|
3eaca924da | ||
|
|
da1c706334 | ||
|
|
3b726dfb1e | ||
|
|
d51e7f7e40 | ||
|
|
2551e0c291 | ||
|
|
2efd5c31ab | ||
|
|
1eacb8ff36 | ||
|
|
612446c3c9 | ||
|
|
e121e16ad9 | ||
|
|
23616b41be | ||
|
|
1778ba49b2 | ||
|
|
b6f2bd4703 | ||
|
|
5fd67224f6 | ||
|
|
c9d21dde0c | ||
|
|
de2c5aa068 | ||
|
|
ad01cecae6 | ||
|
|
75ef14c75b | ||
|
|
03a5a0eddb | ||
|
|
66befd35eb | ||
|
|
3cbad16c30 | ||
|
|
3bba7c5956 | ||
|
|
0daa84c583 | ||
|
|
92358a52c0 | ||
|
|
faf17e9e86 | ||
|
|
ef6efe94b4 | ||
|
|
819d7ea23e | ||
|
|
61ff192cfd | ||
|
|
ceb1b07ce2 | ||
|
|
90188d4358 | ||
|
|
35aa0ab4e7 | ||
|
|
14dd76db8b | ||
|
|
fb26dfad65 | ||
|
|
bedc5adb75 | ||
|
|
800b1f1520 | ||
|
|
a4571a80ae | ||
|
|
a0a612618e | ||
|
|
db94728a5b | ||
|
|
04352a670a | ||
|
|
fe6e3b013e | ||
|
|
a947a74194 | ||
|
|
06055ff62b | ||
|
|
45cb1562e5 | ||
|
|
2f89a16852 | ||
|
|
86956b8cac | ||
|
|
84fb3add33 | ||
|
|
56ee68d9f3 | ||
|
|
e81fd3bb31 | ||
|
|
938ca29777 | ||
|
|
122902968f | ||
|
|
b55c30065f | ||
|
|
92ac2dbac2 | ||
|
|
d3e6decef9 | ||
|
|
579cd9d338 | ||
|
|
9e2a58dd46 | ||
|
|
64722617c1 | ||
|
|
5845ddbdda | ||
|
|
bf9ce0df9b | ||
|
|
8aee2ec3a1 | ||
|
|
3292eafe4a | ||
|
|
9ad31b2c81 | ||
|
|
374ed79a18 | ||
|
|
3d5f73e344 | ||
|
|
6761428a96 | ||
|
|
0a9b463eaa | ||
|
|
c219256fff | ||
|
|
7e48803dc5 | ||
|
|
d496b8a414 | ||
|
|
4825129560 | ||
|
|
adc54b2582 | ||
|
|
863567c9b6 | ||
|
|
102555023b | ||
|
|
f1a9eef531 | ||
|
|
5f007a5b0f | ||
|
|
9455141262 | ||
|
|
37e1379c88 | ||
|
|
55d597e519 | ||
|
|
da5ee5c951 | ||
|
|
b0bd9279fc | ||
|
|
90456339ca | ||
|
|
a653c8bad7 | ||
|
|
c4fa6cf458 | ||
|
|
268fc7b923 | ||
|
|
02604f5290 | ||
|
|
1dad7e86a0 | ||
|
|
838e3efbca | ||
|
|
3e353717f5 | ||
|
|
0a4b74b91a | ||
|
|
e69fbf3ccf | ||
|
|
0b2349d6bf | ||
|
|
3a8f04cf14 | ||
|
|
e941cf956f | ||
|
|
29f7bcf6f5 | ||
|
|
1cf1e0dc57 | ||
|
|
175283805e | ||
|
|
063c0405e8 | ||
|
|
947cb77753 | ||
|
|
28b3b305ea | ||
|
|
df85f13aea | ||
|
|
042e2c1390 | ||
|
|
e6314bee35 | ||
|
|
4292d3262e | ||
|
|
35d070ad29 | ||
|
|
cd79e77576 | ||
|
|
1f1c20d637 | ||
|
|
e87b3b1b54 | ||
|
|
a6f7b65625 | ||
|
|
722fa47132 | ||
|
|
f83e290b4c | ||
|
|
11b4047283 | ||
|
|
69b2032a86 | ||
|
|
636298569f | ||
|
|
ed8a282d35 | ||
|
|
3bd5e850e0 | ||
|
|
070f1f9159 | ||
|
|
195644cca5 | ||
|
|
8092c86ecd | ||
|
|
28f33702da | ||
|
|
570632b8be | ||
|
|
f2881e1b31 | ||
|
|
dad35e37ef | ||
|
|
39afabd60e | ||
|
|
dc7e14a34b | ||
|
|
1dca71a779 | ||
|
|
e9494efa8e | ||
|
|
8159a0f13d | ||
|
|
ee9101e738 | ||
|
|
b670e6e3dc | ||
|
|
5e5754fa62 | ||
|
|
5fcf76066f | ||
|
|
601645fa72 | ||
|
|
12765ad675 | ||
|
|
ad3383d23d | ||
|
|
7d5961cf50 | ||
|
|
864aa052f1 | ||
|
|
be16196058 | ||
|
|
8a62f12e8b | ||
|
|
78f464f6ca | ||
|
|
f37eda4739 | ||
|
|
4e106e9e5a | ||
|
|
ccf8e5e6f4 | ||
|
|
9455adf61f | ||
|
|
970ab9818a | ||
|
|
7848cf7141 | ||
|
|
8e5aa9c195 | ||
|
|
a03e9ba7dd | ||
|
|
9e646ba385 | ||
|
|
d9a4f20fe6 | ||
|
|
e659f0e75d | ||
|
|
8891d6239f | ||
|
|
e3bd3fb985 | ||
|
|
54764dfacd | ||
|
|
b156b5ff2d | ||
|
|
d8e547c9a0 | ||
|
|
a0b93377a4 | ||
|
|
e8a6efd079 | ||
|
|
18bb6caf8f | ||
|
|
bc335d15c0 | ||
|
|
2a0d440a34 | ||
|
|
b0500fac29 | ||
|
|
af16e6423a | ||
|
|
ff90471f0f | ||
|
|
bcc501c524 | ||
|
|
c4ef211a3e | ||
|
|
592c0eb7ab | ||
|
|
880a000865 | ||
|
|
a9571f6adf | ||
|
|
ca91f313bc | ||
|
|
76b9753916 | ||
|
|
cd8bbe28bf | ||
|
|
9550c11594 | ||
|
|
7ac21cad25 | ||
|
|
2008a3955a | ||
|
|
f1641c9f3e | ||
|
|
bec5bbd033 | ||
|
|
ae11f72e28 | ||
|
|
6b88cb3920 | ||
|
|
38772111e8 | ||
|
|
14f50c3e66 | ||
|
|
b89a2c9e49 | ||
|
|
2d2eda988c | ||
|
|
432033969b | ||
|
|
1fbf74e1f7 | ||
|
|
93648ff00b | ||
|
|
9513136610 | ||
|
|
43a2a39f8d | ||
|
|
218351de9a | ||
|
|
b92b922eee | ||
|
|
91be4937ee | ||
|
|
19b36a5fae | ||
|
|
bb9ee7dfd2 | ||
|
|
ac0351b525 | ||
|
|
405f5ad7cc | ||
|
|
8cc2712da3 | ||
|
|
c02ac8d1bf | ||
|
|
a1802add19 | ||
|
|
218a6642a2 | ||
|
|
21a83a5755 | ||
|
|
bec75e51f6 | ||
|
|
6c9b445be6 | ||
|
|
06b17fa941 | ||
|
|
e1d4c029e7 | ||
|
|
293fd70ccb | ||
|
|
4ee863db5a | ||
|
|
2717be0fed | ||
|
|
1f312e146f | ||
|
|
b91557ebb0 | ||
|
|
465380b5a3 | ||
|
|
60af901feb | ||
|
|
ea78a654ff | ||
|
|
f28b6ad0a5 | ||
|
|
a3bdab1318 | ||
|
|
f8c5d01e3c | ||
|
|
3ebe218b7f | ||
|
|
7d039ab729 | ||
|
|
b2b6c8c268 | ||
|
|
4950f25063 | ||
|
|
524d6b48d9 | ||
|
|
29fb5735e2 | ||
|
|
247fc85440 | ||
|
|
2b4302572c | ||
|
|
9b28780e62 | ||
|
|
8656f68008 | ||
|
|
15651b6919 | ||
|
|
78d3861382 | ||
|
|
72f19274cd | ||
|
|
adbcd1a2e0 | ||
|
|
5b7727fab4 | ||
|
|
9627dfa90c | ||
|
|
50022c9fc8 | ||
|
|
e0b76ffebc | ||
|
|
be5a9a840c | ||
|
|
6e5f429e0a | ||
|
|
e9d9d6e2f4 | ||
|
|
b4a57e630c | ||
|
|
1062e33dc8 | ||
|
|
0e14441f73 | ||
|
|
a6a909ae4f | ||
|
|
2b4a39e64c | ||
|
|
82b4921602 | ||
|
|
4229324a5d | ||
|
|
34d3ca9c51 | ||
|
|
9bd7002917 | ||
|
|
ebed9f7a68 | ||
|
|
5d34bd82c0 | ||
|
|
8bcb2b3b0f | ||
|
|
32ba17cf91 | ||
|
|
704ded4410 | ||
|
|
88277976c6 | ||
|
|
cb95f02912 | ||
|
|
928b406359 | ||
|
|
4757c7db8c | ||
|
|
5df87641a1 | ||
|
|
04077c53fd | ||
|
|
574be52b84 | ||
|
|
a66613c5ca | ||
|
|
01b3b19715 | ||
|
|
fb1481c69c | ||
|
|
9557f755a5 | ||
|
|
60d8831399 | ||
|
|
5ff5660db3 | ||
|
|
d62c359452 | ||
|
|
ec0b6b64fe | ||
|
|
c53eac76f8 | ||
|
|
49cb2ae260 | ||
|
|
77796e8a75 | ||
|
|
49f0f6ec7d | ||
|
|
2c273a85d8 | ||
|
|
8273554a1c | ||
|
|
ad8ab63fd5 | ||
|
|
7de0761329 | ||
|
|
907dab7d05 | ||
|
|
2907f22200 | ||
|
|
7bbe1b2dbe | ||
|
|
099513072c | ||
|
|
7de8bb00e7 | ||
|
|
12d44696e8 | ||
|
|
25cef26251 | ||
|
|
dceb398695 | ||
|
|
f60599abd3 | ||
|
|
44f8098e4a | ||
|
|
747979f939 | ||
|
|
b3083ae779 | ||
|
|
67580a8b69 | ||
|
|
291c7aaf0b | ||
|
|
1a098eecf6 | ||
|
|
0a05bdba1d | ||
|
|
37bfc07ffb | ||
|
|
eae3ab2dc1 | ||
|
|
1665bf6515 | ||
|
|
0383ffb7f3 | ||
|
|
a0d6646e49 | ||
|
|
254b3a0fc8 | ||
|
|
21743e5a23 | ||
|
|
0550924e08 | ||
|
|
7867302be5 | ||
|
|
14815b388d | ||
|
|
92cc82220e | ||
|
|
da1fae6016 | ||
|
|
34002470a5 | ||
|
|
49f84bccad | ||
|
|
4bcb4a1590 | ||
|
|
378de19f41 | ||
|
|
ffe2512734 | ||
|
|
b4be620a5b | ||
|
|
ac8b546393 | ||
|
|
9bdf31ee97 | ||
|
|
c29cd05db8 | ||
|
|
cd34820138 | ||
|
|
d207318494 | ||
|
|
117062f1d1 | ||
|
|
9d561ba94d | ||
|
|
97fcaed9b4 | ||
|
|
5e53ea3607 | ||
|
|
7dc74cb61b | ||
|
|
fbefcfedb9 | ||
|
|
36c0d9aba2 | ||
|
|
8c8a981452 | ||
|
|
7dd586e31d | ||
|
|
366a31b41b | ||
|
|
f09557d73c | ||
|
|
33a2ac402c | ||
|
|
632333c49f | ||
|
|
c8bea4d7de | ||
|
|
c1d75d32c2 | ||
|
|
b805daec51 | ||
|
|
af2088df4e | ||
|
|
3b8d1f40a7 | ||
|
|
8355d3664e | ||
|
|
83a696f743 | ||
|
|
7ca507b1ce | ||
|
|
609435328e | ||
|
|
d771317e3f | ||
|
|
d548563e65 | ||
|
|
f07cd8aee3 | ||
|
|
48963f24df | ||
|
|
7bf98c0c40 | ||
|
|
e73383cc79 | ||
|
|
79ce93d578 | ||
|
|
200a7fcd40 | ||
|
|
e043d0e654 | ||
|
|
21ce678e5b | ||
|
|
5c94887949 | ||
|
|
69a9bcb3da | ||
|
|
2fea091e1f | ||
|
|
24314a103f | ||
|
|
b56db41d0b | ||
|
|
825bff5d60 | ||
|
|
f9184cf489 | ||
|
|
5c04b1e14a | ||
|
|
2c96eb7851 | ||
|
|
67ba225003 | ||
|
|
04ecf41c5a | ||
|
|
6600de7320 | ||
|
|
f7b82f0a7a | ||
|
|
65bdb232f4 | ||
|
|
200e3af384 | ||
|
|
aabfa91f80 | ||
|
|
e5468a7391 | ||
|
|
d5a11edd0c | ||
|
|
fcc86b07ba | ||
|
|
74d2527af5 | ||
|
|
50cf284273 | ||
|
|
aaddde0a9b | ||
|
|
ac87345b7a | ||
|
|
23079d9ac0 | ||
|
|
b573d63648 | ||
|
|
34d705a54e | ||
|
|
eeb1d4954d | ||
|
|
b638adedff | ||
|
|
285e24cdc7 | ||
|
|
396e643b06 | ||
|
|
dc50190dc3 | ||
|
|
2c8bf4f18c | ||
|
|
1f6379a7e6 | ||
|
|
ddd8eb1da0 | ||
|
|
4c463de45f | ||
|
|
1f4a7a7f6f | ||
|
|
e7df29104e | ||
|
|
9987b35b60 | ||
|
|
16e876ab68 | ||
|
|
50fc2fc74e | ||
|
|
c244dc9c0c | ||
|
|
0f50981573 | ||
|
|
0c1cb20936 | ||
|
|
192617a884 | ||
|
|
297991ef5f | ||
|
|
75f97c4a31 | ||
|
|
40f520086c | ||
|
|
c8dda4f90d | ||
|
|
5f09f97032 | ||
|
|
168056d595 | ||
|
|
c70eaa0096 | ||
|
|
5f36b13408 | ||
|
|
9dc73efa3a | ||
|
|
e9c2868998 | ||
|
|
0a13b04c55 | ||
|
|
cf12d3ee56 | ||
|
|
cea7190453 | ||
|
|
c6d78680fb | ||
|
|
0bf302e013 | ||
|
|
1351fb6689 | ||
|
|
af638d666c | ||
|
|
e4fe601d9d | ||
|
|
4f3cd71e1e | ||
|
|
9c0295db9f | ||
|
|
3fc2d1df80 | ||
|
|
4a6747dcc7 | ||
|
|
54b3c92953 | ||
|
|
a4d460e850 | ||
|
|
3d8869066a | ||
|
|
880a123149 | ||
|
|
39e35bc1d6 | ||
|
|
f219f1e36b | ||
|
|
25ed3d65f8 | ||
|
|
30dbabd73d | ||
|
|
ea2e5bf486 | ||
|
|
ae52fcc757 | ||
|
|
b6c2f123e8 | ||
|
|
15f900317a | ||
|
|
22545cac8b | ||
|
|
03c8d82471 | ||
|
|
14d7a138a5 | ||
|
|
a829eb949b | ||
|
|
fd605d9c81 | ||
|
|
55b4a9eddb | ||
|
|
9ccf77b99c | ||
|
|
ea27075bab | ||
|
|
c3723d0fce | ||
|
|
0edb3cd316 | ||
|
|
e9e6b0bc4f | ||
|
|
4701da201d | ||
|
|
d6d2e052dd | ||
|
|
d3d1dcfe1d | ||
|
|
918ebf5e65 | ||
|
|
67184b88a8 | ||
|
|
fb0f4c3939 | ||
|
|
aae5343543 | ||
|
|
51e9762ca8 | ||
|
|
330dafc652 | ||
|
|
7ddf9fa54e | ||
|
|
f2ca09eedd | ||
|
|
f0e2c8416d | ||
|
|
338b7a8c13 | ||
|
|
b4284f82f3 | ||
|
|
0ce430cab5 | ||
|
|
95c0f6c093 | ||
|
|
387dbc360e | ||
|
|
a88be89c2f | ||
|
|
8bc353442f | ||
|
|
b3502bd627 | ||
|
|
56da7c242d | ||
|
|
fa8f49e87d | ||
|
|
6e08a70afc | ||
|
|
bd4be2b05c | ||
|
|
6b6ff0a95e | ||
|
|
4755cae5cb | ||
|
|
b2384ccc06 | ||
|
|
e6589308dd | ||
|
|
879b25be9f | ||
|
|
d3ad941b30 | ||
|
|
f077fbc3f5 | ||
|
|
4679ce968b | ||
|
|
101e462649 | ||
|
|
5d93ab9b9e | ||
|
|
d557832509 | ||
|
|
fe5c91db29 | ||
|
|
b2947193ec | ||
|
|
f6440753b6 | ||
|
|
17cf903804 | ||
|
|
dcf530d237 | ||
|
|
6b1808dab1 | ||
|
|
5889efd74a | ||
|
|
1a9de1e5c5 | ||
|
|
d1404a2b07 | ||
|
|
664dbf3f4c | ||
|
|
f32a8e26b6 | ||
|
|
b1a92fd4e0 | ||
|
|
1ea9fd2d49 | ||
|
|
f31e4e3176 | ||
|
|
e3287a7e9f | ||
|
|
ec21153d4b | ||
|
|
917e7a8c1d | ||
|
|
8e0a8dc272 | ||
|
|
91bac29ea3 | ||
|
|
3e333769bb | ||
|
|
b4bde6660a | ||
|
|
917f752081 | ||
|
|
915d561286 | ||
|
|
01ef809fd3 | ||
|
|
19902092ce | ||
|
|
39603b6e53 | ||
|
|
9c85a09d3e | ||
|
|
69baa6785f | ||
|
|
bb84d01e14 | ||
|
|
616dae2d8b | ||
|
|
3fbfe50e09 | ||
|
|
c0c8edb9d1 | ||
|
|
84268e484d | ||
|
|
c473c2fa81 | ||
|
|
7402590f49 | ||
|
|
529d1c9f66 | ||
|
|
e85b772ca5 | ||
|
|
f75169fc26 | ||
|
|
07b86521a5 | ||
|
|
961008bbe1 | ||
|
|
6d359b6bb9 | ||
|
|
ea6f803e78 | ||
|
|
0151f8a6a9 | ||
|
|
39c5101957 | ||
|
|
9b1cd5f79c | ||
|
|
36d0b83ed3 | ||
|
|
f0138fad4f | ||
|
|
69802e78f8 | ||
|
|
92e69f561f | ||
|
|
b351520e92 | ||
|
|
481714f095 | ||
|
|
d38656e026 | ||
|
|
69b28b9b02 | ||
|
|
35a68703c2 | ||
|
|
c49fe04750 | ||
|
|
31feabbec7 | ||
|
|
bc3cb2c3c9 | ||
|
|
5ec4481c92 | ||
|
|
be5cb48dfe | ||
|
|
48ff1ece16 | ||
|
|
ed20ed592f | ||
|
|
4fb3435c29 | ||
|
|
37eb14a01a | ||
|
|
d403bc86e3 | ||
|
|
0e2f0f2a4d | ||
|
|
1a4d34a802 | ||
|
|
bb15af9954 | ||
|
|
8a250d1011 | ||
|
|
2f9994f600 | ||
|
|
1cca06a274 | ||
|
|
8fdb3ea631 | ||
|
|
35823d5751 | ||
|
|
66f90a542a | ||
|
|
49981c4bee | ||
|
|
d732c1a845 | ||
|
|
4d7e25f97b | ||
|
|
80656f48e0 | ||
|
|
ebde149980 | ||
|
|
adc0a81592 | ||
|
|
b596f00ce5 | ||
|
|
448442f92b | ||
|
|
8518201562 | ||
|
|
17586c4559 | ||
|
|
f8622da7d4 | ||
|
|
b1a27e9060 | ||
|
|
3c6423d444 | ||
|
|
91b03160ea | ||
|
|
0c1e20ba48 | ||
|
|
1dcac85c0d | ||
|
|
3fc72dbec2 | ||
|
|
494329f568 | ||
|
|
a1e8211ba7 | ||
|
|
80aa7502af | ||
|
|
67bae76048 | ||
|
|
bda2aa46b6 | ||
|
|
27ac204bb6 | ||
|
|
a2526ea244 | ||
|
|
6d9ba8dd2f | ||
|
|
2ca8febff7 | ||
|
|
e105a523e4 | ||
|
|
28f8b05dbc | ||
|
|
d95286db0e | ||
|
|
8e45c34e8e | ||
|
|
9e87c42d0c | ||
|
|
0b52cd002e | ||
|
|
39c43c0c09 | ||
|
|
350485612e | ||
|
|
df31c13912 | ||
|
|
15adfcca8c | ||
|
|
1466788f77 | ||
|
|
760fe3aca9 | ||
|
|
5f75813e84 | ||
|
|
59cb06acf4 | ||
|
|
6349406523 | ||
|
|
bcc2c59f08 | ||
|
|
52d46f9879 | ||
|
|
0b50a5474d | ||
|
|
2259879595 | ||
|
|
4f5091ed7f | ||
|
|
b5afd73024 | ||
|
|
5c929badeb | ||
|
|
3f2de333fb | ||
|
|
7c12b8ae25 | ||
|
|
b54ccbfa2f | ||
|
|
114ce8997f | ||
|
|
f1bba3b958 | ||
|
|
053acef728 | ||
|
|
9f2710185b | ||
|
|
d000879c01 | ||
|
|
25ae169fee | ||
|
|
4443dda0f6 | ||
|
|
c484e989a9 | ||
|
|
86a4656651 | ||
|
|
f25aefeb11 | ||
|
|
228643c7d7 | ||
|
|
072d6d7094 | ||
|
|
de3ce672b8 | ||
|
|
6f5c191998 | ||
|
|
bbaea4def0 | ||
|
|
54f9282166 | ||
|
|
a39b1db266 | ||
|
|
2ddb4ec905 | ||
|
|
7a59e3acf7 | ||
|
|
b34c3db956 | ||
|
|
afea958aca | ||
|
|
dca2a29865 | ||
|
|
97b8e84143 | ||
|
|
23eb0da7d7 | ||
|
|
2edda471e7 | ||
|
|
676aa1358d | ||
|
|
87a36d6ae3 | ||
|
|
b67611094e | ||
|
|
2e986def78 | ||
|
|
d16a05959d | ||
|
|
7e58e0b490 | ||
|
|
9b01aecf3c | ||
|
|
86043fd5f8 | ||
|
|
372a1758e9 | ||
|
|
0a2b1d9e53 | ||
|
|
e562946308 | ||
|
|
398e15b3c6 | ||
|
|
c225a54dbe | ||
|
|
5148988dcc | ||
|
|
28b57ba652 | ||
|
|
9c7e74ef37 | ||
|
|
330b28ad9c | ||
|
|
da7166a7ea | ||
|
|
e8793c5d8d | ||
|
|
c63d45e344 | ||
|
|
1159a79410 | ||
|
|
5b5e65ac08 | ||
|
|
417811e94f | ||
|
|
9c40057c51 | ||
|
|
a6409c16c3 | ||
|
|
ba4667528c | ||
|
|
a2368d7c3f | ||
|
|
e90b203a7d | ||
|
|
b7389d74db | ||
|
|
24321521c7 | ||
|
|
f85497d446 | ||
|
|
1f9e92fdb7 | ||
|
|
b66d2b95c5 | ||
|
|
6f013b3bc4 | ||
|
|
cdf8a01c14 | ||
|
|
547923bbb4 | ||
|
|
a8c3c1bece | ||
|
|
0f47a5d51e | ||
|
|
9f9196427f | ||
|
|
341d688e79 | ||
|
|
92c5d1ed46 | ||
|
|
55d8579b1a | ||
|
|
51a74c5045 | ||
|
|
64f1af4d0b | ||
|
|
8dd5daf495 | ||
|
|
0ee87d736c | ||
|
|
ba822af355 | ||
|
|
78c1990b42 | ||
|
|
768179a664 | ||
|
|
1268c46f02 | ||
|
|
d870a49381 | ||
|
|
8e476cc07e | ||
|
|
ea54fd6e98 | ||
|
|
ea001cc0db | ||
|
|
2378343c74 | ||
|
|
018b3346bb | ||
|
|
d104829a6d | ||
|
|
0035460712 | ||
|
|
cae57ffcd8 | ||
|
|
b587ff663c | ||
|
|
531a888592 | ||
|
|
a13b167c41 | ||
|
|
c1f9195a38 | ||
|
|
e1ea7c6986 | ||
|
|
bd21927069 | ||
|
|
f1f4f7e5f3 | ||
|
|
ccdcda7f1d | ||
|
|
e9586b7336 | ||
|
|
da36a218df | ||
|
|
1723089844 | ||
|
|
e99eb04e2f | ||
|
|
5fddd71fc2 | ||
|
|
c682b03736 | ||
|
|
4008767e1b | ||
|
|
74c768e2fb | ||
|
|
03b883c320 | ||
|
|
807ddaa0bb | ||
|
|
da9d555168 | ||
|
|
05ba2c0103 | ||
|
|
de96b722d5 | ||
|
|
afde493040 | ||
|
|
cce440cf49 | ||
|
|
e96dbdb026 | ||
|
|
f4cd163c34 | ||
|
|
0af9bdc964 | ||
|
|
71bb1105f7 | ||
|
|
84c28645be | ||
|
|
665ef08733 | ||
|
|
b3e63a5f8a | ||
|
|
92c09b8843 | ||
|
|
7b726a41ef | ||
|
|
a1a0587a2b | ||
|
|
98be9cee83 | ||
|
|
0646934c9d | ||
|
|
f0f68632ff | ||
|
|
e557bda48e | ||
|
|
2992de5139 | ||
|
|
779532b1c9 | ||
|
|
300175ac67 | ||
|
|
a356147164 | ||
|
|
d1489a9a78 | ||
|
|
021bc073a2 | ||
|
|
4e571e1e4d | ||
|
|
1dff9baa61 | ||
|
|
19d54778f5 | ||
|
|
99d0fa974b | ||
|
|
84ca275f1e | ||
|
|
963bc5f0bc | ||
|
|
b446c2ce4b | ||
|
|
65a4f7af28 | ||
|
|
f6b2c5bbf3 | ||
|
|
e99905e3c9 | ||
|
|
5c0b42446d | ||
|
|
a3be0d4655 | ||
|
|
47729c2348 | ||
|
|
78bfcf5b1c | ||
|
|
f1291d4d7d | ||
|
|
ff809416f5 | ||
|
|
83a4677026 | ||
|
|
ffe8593a07 | ||
|
|
60e4db16ff | ||
|
|
2e510778be | ||
|
|
c492559010 | ||
|
|
a8dc36b6d2 | ||
|
|
379d31aac6 | ||
|
|
28fc1ab063 | ||
|
|
75e01018a5 | ||
|
|
b7df0b122d | ||
|
|
f9798a8d86 | ||
|
|
7691bdd181 | ||
|
|
3dc79da2fa | ||
|
|
83b00c1cfa | ||
|
|
d6fdb38c22 | ||
|
|
3505342a8d | ||
|
|
78661799f2 | ||
|
|
ec57996b01 | ||
|
|
0a97d91aed | ||
|
|
753027ffc7 | ||
|
|
d3383f0f1a | ||
|
|
9075ecb007 | ||
|
|
4b8cc7c4d3 | ||
|
|
2f20397c60 | ||
|
|
7f227932da | ||
|
|
69d253fba3 | ||
|
|
b75800c583 | ||
|
|
a35add3fc6 | ||
|
|
b17ff57582 | ||
|
|
915ccdc007 | ||
|
|
98a261e38c | ||
|
|
c9f5ffae42 | ||
|
|
342675276b | ||
|
|
590296e64d | ||
|
|
17b39d16a3 | ||
|
|
515a621eb4 | ||
|
|
ca0e950cdf | ||
|
|
cec9e4101d | ||
|
|
862fabf6ad | ||
|
|
128a9aae4e | ||
|
|
1983d0067d | ||
|
|
bdaf48da20 | ||
|
|
09024a93e9 | ||
|
|
064e7071b2 | ||
|
|
2b2fedb380 | ||
|
|
5ff7c216b9 | ||
|
|
c476ac7bc5 | ||
|
|
e83e8c2ee4 | ||
|
|
607b168b56 | ||
|
|
e0cf0916dd | ||
|
|
0f3a5ce8ba | ||
|
|
2a6298e9eb | ||
|
|
f97b133c8c | ||
|
|
f11fa4f32d | ||
|
|
f0a1c10ec5 | ||
|
|
08fed8fe93 | ||
|
|
813992141a | ||
|
|
f90129213e | ||
|
|
838af30a38 | ||
|
|
13ff15311a | ||
|
|
56e237c479 | ||
|
|
ff1e10a025 | ||
|
|
c259037dbf | ||
|
|
7b4878620f | ||
|
|
38fd58c173 | ||
|
|
d1185d43f7 | ||
|
|
a093c54b16 | ||
|
|
30cc85b793 | ||
|
|
5009906385 | ||
|
|
6ccc05b183 | ||
|
|
3994b25a71 | ||
|
|
5130071a60 | ||
|
|
d5e67835aa | ||
|
|
bf8078ed66 | ||
|
|
1559a2a943 | ||
|
|
e2d5301376 | ||
|
|
f31717145f | ||
|
|
db76558944 | ||
|
|
1bcb027e05 | ||
|
|
719d75f8a6 | ||
|
|
8c164c410d | ||
|
|
8c6a4a90aa | ||
|
|
c679875273 | ||
|
|
1e5141c27c | ||
|
|
e56330be47 | ||
|
|
764a63d784 | ||
|
|
6f280c4664 | ||
|
|
9b29f38d10 | ||
|
|
6b60410791 | ||
|
|
dffaceba6f | ||
|
|
4ffdd6f74f | ||
|
|
3499dd4f56 | ||
|
|
7004820326 | ||
|
|
24a17235ae | ||
|
|
a0381eb2c6 | ||
|
|
3b6a44e683 | ||
|
|
cc930ebf53 | ||
|
|
809a135721 | ||
|
|
073c318f12 | ||
|
|
8f1cfd8037 | ||
|
|
7bf9cccbf6 | ||
|
|
d194e230de | ||
|
|
bd3d9d2da3 | ||
|
|
e694817b57 | ||
|
|
66191a9610 | ||
|
|
9bb4d8b2a3 | ||
|
|
34180ca454 | ||
|
|
fb5010a2b5 | ||
|
|
0e87b6e48b | ||
|
|
d45443258b | ||
|
|
f3b44a3085 | ||
|
|
9680260104 | ||
|
|
317a15b649 | ||
|
|
2fd8134a57 | ||
|
|
494b54ac32 | ||
|
|
377eb2b851 | ||
|
|
bd7e96b8af | ||
|
|
acf25e8ad7 | ||
|
|
a0ac757982 | ||
|
|
3b3d7b134a | ||
|
|
b84b78a34d | ||
|
|
17ac5a5e81 | ||
|
|
a24431bc3b | ||
|
|
cdfeb2ff86 | ||
|
|
8199202dc3 | ||
|
|
7fd1fb89f1 | ||
|
|
32e54d0f94 | ||
|
|
21e9edd201 | ||
|
|
a0001aaa74 | ||
|
|
753307bb99 | ||
|
|
970feb75dd | ||
|
|
08556789f9 | ||
|
|
72d8ad3204 | ||
|
|
6cdf53e262 | ||
|
|
f6d81c3a23 | ||
|
|
4d7b905e98 | ||
|
|
8c42dee5de | ||
|
|
23d529bb31 | ||
|
|
7bbb687047 | ||
|
|
b39708700d | ||
|
|
d46b9eaf87 | ||
|
|
3e60a2bd6f | ||
|
|
4e2e434947 | ||
|
|
af32dfbbcd | ||
|
|
83c10166e2 | ||
|
|
8bb0401c25 | ||
|
|
139c9d2ce3 | ||
|
|
21f4623e3e | ||
|
|
8266c26ef1 | ||
|
|
a59222cabb | ||
|
|
459bc32f9d | ||
|
|
9a2022a4fe | ||
|
|
0537992603 | ||
|
|
1c18b2bffb | ||
|
|
d523ebe0e0 | ||
|
|
d3b9363392 | ||
|
|
285b99f1b7 | ||
|
|
8ad8f98f48 | ||
|
|
160a7ff3db | ||
|
|
a76dd9c9d1 | ||
|
|
752c474983 | ||
|
|
02ccb029ae | ||
|
|
b01fa82627 | ||
|
|
0c370e4299 | ||
|
|
d737fda8bc | ||
|
|
475a431859 | ||
|
|
490ddfcd88 | ||
|
|
fa6fc9e80d | ||
|
|
f960fb7d67 | ||
|
|
f6a19631dc | ||
|
|
e2efd0e65a | ||
|
|
361f487384 | ||
|
|
dc49027b30 | ||
|
|
581fdd67b1 | ||
|
|
d664aa204f | ||
|
|
db0328fa71 | ||
|
|
569635f3ed | ||
|
|
b7ae712b63 | ||
|
|
8398f7b7c0 | ||
|
|
e57574ba9c | ||
|
|
68ebdda1ff | ||
|
|
410207f3ca | ||
|
|
7faf1fba8b | ||
|
|
8c267489c7 | ||
|
|
fb5c428147 | ||
|
|
5ff4215bde | ||
|
|
96d6ad8142 | ||
|
|
875fa215c5 | ||
|
|
bcd80e19d4 | ||
|
|
56e1684e2e | ||
|
|
1baa02de89 | ||
|
|
11cdfa7557 | ||
|
|
8fbd8a905f | ||
|
|
cd059728fd | ||
|
|
473b5bd3db | ||
|
|
81c7954e0c | ||
|
|
a665e3aae9 | ||
|
|
4b6985718a | ||
|
|
619cfef1c7 | ||
|
|
15eb666394 | ||
|
|
dac49f7fdc | ||
|
|
926ec831e2 | ||
|
|
87012c47ea | ||
|
|
fbe7e0a427 | ||
|
|
779a1c303f | ||
|
|
14e6136683 | ||
|
|
1f11a1df02 | ||
|
|
8e4bccffbf | ||
|
|
733e0e07c3 | ||
|
|
8ee6a3f134 | ||
|
|
bacc5e4213 | ||
|
|
afd87d07a3 | ||
|
|
bebe40c8e8 | ||
|
|
e4c5be4350 | ||
|
|
a9a9391b39 | ||
|
|
9f54f4d81a | ||
|
|
1a63669805 | ||
|
|
fcf6abd36e | ||
|
|
b9080a1ec1 | ||
|
|
450b0bf4fa | ||
|
|
a4d3a5ad4d | ||
|
|
6c22a2aeb4 | ||
|
|
2e36c97d1c | ||
|
|
f99efbb1e9 | ||
|
|
6cf3bf0255 | ||
|
|
a0abe41c8a | ||
|
|
3830ad65fc | ||
|
|
204403da67 | ||
|
|
098723b88d | ||
|
|
b21e758eb8 | ||
|
|
b1f4971f25 | ||
|
|
6e1bfdac58 | ||
|
|
11920ca997 | ||
|
|
255e29d9c8 | ||
|
|
35ccdd3014 | ||
|
|
757d628bc8 | ||
|
|
a57d32d05d | ||
|
|
ef69bf9256 | ||
|
|
bec303821b | ||
|
|
346f2db5fb | ||
|
|
b9de0f8e38 | ||
|
|
e112fcba29 | ||
|
|
41983ce356 | ||
|
|
fb49fb8ddd |
@@ -27,3 +27,5 @@ bruno/
|
||||
LICENSE
|
||||
CONTRIBUTING.md
|
||||
dist
|
||||
.git
|
||||
config/
|
||||
27
.github/dependabot.yml
vendored
@@ -33,3 +33,30 @@ updates:
|
||||
minor-updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/install"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
dev-patch-updates:
|
||||
dependency-type: "development"
|
||||
update-types:
|
||||
- "patch"
|
||||
dev-minor-updates:
|
||||
dependency-type: "development"
|
||||
update-types:
|
||||
- "minor"
|
||||
prod-patch-updates:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "patch"
|
||||
prod-minor-updates:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "minor"
|
||||
10
.github/workflows/cicd.yml
vendored
@@ -12,13 +12,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: 1.23.0
|
||||
go-version: 1.24
|
||||
|
||||
- name: Update version in package.json
|
||||
run: |
|
||||
|
||||
6
.github/workflows/linting.yml
vendored
@@ -18,12 +18,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '20'
|
||||
node-version: '22'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
2
.github/workflows/stale-bot.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
days-before-stale: 14
|
||||
days-before-close: 14
|
||||
|
||||
16
.github/workflows/test.yml
vendored
@@ -11,11 +11,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '20'
|
||||
node-version: '22'
|
||||
|
||||
- name: Copy config file
|
||||
run: cp config/config.example.yml config/config.yml
|
||||
@@ -23,6 +23,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Create database index.ts
|
||||
run: echo 'export * from "./sqlite";' > server/db/index.ts
|
||||
|
||||
- name: Generate database migrations
|
||||
run: npm run db:sqlite:generate
|
||||
|
||||
@@ -45,5 +48,8 @@ jobs:
|
||||
echo "App failed to start"
|
||||
exit 1
|
||||
|
||||
- name: Build Docker image
|
||||
run: make build
|
||||
- name: Build Docker image sqlite
|
||||
run: make build-sqlite
|
||||
|
||||
- name: Build Docker image pg
|
||||
run: make build-pg
|
||||
|
||||
10
.gitignore
vendored
@@ -18,6 +18,7 @@ yarn-error.log*
|
||||
next-env.d.ts
|
||||
*.db
|
||||
*.sqlite
|
||||
!Dockerfile.sqlite
|
||||
*.sqlite3
|
||||
*.log
|
||||
.machinelogs*.json
|
||||
@@ -25,6 +26,10 @@ next-env.d.ts
|
||||
migrations
|
||||
tsconfig.tsbuildinfo
|
||||
config/config.yml
|
||||
config/postgres
|
||||
config/postgres*
|
||||
config/openapi.yaml
|
||||
config/key
|
||||
dist
|
||||
.dist
|
||||
installer
|
||||
@@ -33,4 +38,9 @@ bin
|
||||
.secrets
|
||||
test_event.json
|
||||
.idea/
|
||||
public/branding
|
||||
server/db/index.ts
|
||||
server/build.ts
|
||||
postgres/
|
||||
dynamic/
|
||||
certificates/
|
||||
|
||||
@@ -4,11 +4,7 @@ Contributions are welcome!
|
||||
|
||||
Please see the contribution and local development guide on the docs page before getting started:
|
||||
|
||||
https://docs.fossorial.io/development
|
||||
|
||||
For ideas about what features to work on and our future plans, please see the roadmap:
|
||||
|
||||
https://docs.fossorial.io/roadmap
|
||||
https://docs.digpangolin.com/development/contributing
|
||||
|
||||
### Licensing Considerations
|
||||
|
||||
|
||||
17
Dockerfile
@@ -1,21 +1,26 @@
|
||||
FROM node:20-alpine AS builder
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG BUILD=oss
|
||||
ARG DATABASE=sqlite
|
||||
|
||||
# COPY package.json package-lock.json ./
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN echo 'export * from "./sqlite";' > server/db/index.ts
|
||||
RUN echo "export * from \"./$DATABASE\";" > server/db/index.ts
|
||||
|
||||
RUN npx drizzle-kit generate --dialect sqlite --schema ./server/db/sqlite/schema.ts --out init
|
||||
RUN echo "export const build = \"$BUILD\" as any;" > server/build.ts
|
||||
|
||||
RUN npm run build:sqlite
|
||||
RUN if [ "$DATABASE" = "pg" ]; then npx drizzle-kit generate --dialect postgresql --schema ./server/db/pg/schema.ts --out init; else npx drizzle-kit generate --dialect $DATABASE --schema ./server/db/$DATABASE/schema.ts --out init; fi
|
||||
|
||||
RUN npm run build:$DATABASE
|
||||
RUN npm run build:cli
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
FROM node:22-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -38,4 +43,4 @@ COPY server/db/names.json ./dist/names.json
|
||||
|
||||
COPY public ./public
|
||||
|
||||
CMD ["npm", "run", "start:sqlite"]
|
||||
CMD ["npm", "run", "start"]
|
||||
|
||||
14
Dockerfile.dev
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Use tsx watch for development with hot reload
|
||||
CMD ["npm", "run", "dev"]
|
||||
@@ -1,41 +0,0 @@
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# COPY package.json package-lock.json ./
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN echo 'export * from "./pg";' > server/db/index.ts
|
||||
|
||||
RUN npx drizzle-kit generate --dialect postgresql --schema ./server/db/pg/schema.ts --out init
|
||||
|
||||
RUN npm run build:pg
|
||||
RUN npm run build:cli
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Curl used for the health checks
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# COPY package.json package-lock.json ./
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev && npm cache clean --force
|
||||
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/init ./dist/init
|
||||
|
||||
COPY ./cli/wrapper.sh /usr/local/bin/pangctl
|
||||
RUN chmod +x /usr/local/bin/pangctl ./dist/cli.mjs
|
||||
|
||||
COPY server/db/names.json ./dist/names.json
|
||||
|
||||
COPY public ./public
|
||||
|
||||
CMD ["npm", "run", "start:pg"]
|
||||
17
Makefile
@@ -1,14 +1,14 @@
|
||||
.PHONY: build build-release build-arm build-x86 test clean
|
||||
.PHONY: build build-pg build-release build-arm build-x86 test clean
|
||||
|
||||
build-release:
|
||||
@if [ -z "$(tag)" ]; then \
|
||||
echo "Error: tag is required. Usage: make build-release tag=<tag>"; \
|
||||
exit 1; \
|
||||
fi
|
||||
docker buildx build --platform linux/arm64,linux/amd64 -t fosrl/pangolin:latest -f Dockerfile --push .
|
||||
docker buildx build --platform linux/arm64,linux/amd64 -t fosrl/pangolin:$(tag) -f Dockerfile --push .
|
||||
docker buildx build --platform linux/arm64,linux/amd64 -t fosrl/pangolin:postgresql-latest -f Dockerfile.pg --push .
|
||||
docker buildx build --platform linux/arm64,linux/amd64 -t fosrl/pangolin:postgresql-$(tag) -f Dockerfile.pg --push .
|
||||
docker buildx build --build-arg DATABASE=sqlite --platform linux/arm64,linux/amd64 -t fosrl/pangolin:latest --push .
|
||||
docker buildx build --build-arg DATABASE=sqlite --platform linux/arm64,linux/amd64 -t fosrl/pangolin:$(tag) --push .
|
||||
docker buildx build --build-arg DATABASE=pg --platform linux/arm64,linux/amd64 -t fosrl/pangolin:postgresql-latest --push .
|
||||
docker buildx build --build-arg DATABASE=pg --platform linux/arm64,linux/amd64 -t fosrl/pangolin:postgresql-$(tag) --push .
|
||||
|
||||
build-arm:
|
||||
docker buildx build --platform linux/arm64 -t fosrl/pangolin:latest .
|
||||
@@ -16,8 +16,11 @@ build-arm:
|
||||
build-x86:
|
||||
docker buildx build --platform linux/amd64 -t fosrl/pangolin:latest .
|
||||
|
||||
build:
|
||||
docker build -t fosrl/pangolin:latest .
|
||||
build-sqlite:
|
||||
docker build --build-arg DATABASE=sqlite -t fosrl/pangolin:latest .
|
||||
|
||||
build-pg:
|
||||
docker build --build-arg DATABASE=pg -t fosrl/pangolin:postgresql-latest .
|
||||
|
||||
test:
|
||||
docker run -it -p 3000:3000 -p 3001:3001 -p 3002:3002 -v ./config:/app/config fosrl/pangolin:latest
|
||||
|
||||
122
README.md
@@ -7,51 +7,69 @@
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<h4 align="center">Tunneled Reverse Proxy Server with Access Control</h4>
|
||||
<h4 align="center">Secure gateway to your private networks</h4>
|
||||
<div align="center">
|
||||
|
||||
_Your own self-hosted zero trust tunnel._
|
||||
_Pangolin tunnels your services to the internet so you can access anything from anywhere._
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<h5>
|
||||
<a href="https://fossorial.io">
|
||||
<a href="https://digpangolin.com">
|
||||
Website
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://docs.fossorial.io/Getting%20Started/quick-install">
|
||||
Install Guide
|
||||
<a href="https://docs.digpangolin.com/self-host/quick-install-managed">
|
||||
Quick Install Guide
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="mailto:numbat@fossorial.io">
|
||||
<a href="mailto:contact@fossorial.io">
|
||||
Contact Us
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://digpangolin.com/slack">
|
||||
Slack
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://discord.gg/HCJR8Xhme4">
|
||||
Discord
|
||||
</a>
|
||||
</h5>
|
||||
|
||||
[](https://digpangolin.com/slack)
|
||||
[](https://hub.docker.com/r/fosrl/pangolin)
|
||||

|
||||
[](https://discord.gg/HCJR8Xhme4)
|
||||
[](https://www.youtube.com/@fossorial-app)
|
||||
[](https://www.youtube.com/@fossorial-app)
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<strong>
|
||||
Start testing Pangolin at <a href="https://pangolin.fossorial.io/auth/signup">pangolin.fossorial.io</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
Pangolin is a self-hosted tunneled reverse proxy server with identity and access control, designed to securely expose private resources on distributed networks. Acting as a central hub, it connects isolated networks — even those behind restrictive firewalls — through encrypted tunnels, enabling easy access to remote services without opening ports.
|
||||
|
||||
<img src="public/screenshots/hero.png" alt="Preview"/>
|
||||
|
||||
_Resources page of Pangolin dashboard (dark mode) showing multiple resources available to connect._
|
||||

|
||||
|
||||
## Key Features
|
||||
|
||||
### Reverse Proxy Through WireGuard Tunnel
|
||||
|
||||
- Expose private resources on your network **without opening ports** (firewall punching).
|
||||
- Secure and easy to configure site-to-site connectivity via a custom **user space WireGuard client**, [Newt](https://github.com/fosrl/newt).
|
||||
- Secure and easy to configure private connectivity via a custom **user space WireGuard client**, [Newt](https://github.com/fosrl/newt).
|
||||
- Built-in support for any WireGuard client.
|
||||
- Automated **SSL certificates** (https) via [LetsEncrypt](https://letsencrypt.org/).
|
||||
- Support for HTTP/HTTPS and **raw TCP/UDP services**.
|
||||
- Load balancing.
|
||||
- Extend functionality with existing [Traefik](https://github.com/traefik/traefik) plugins, such as [CrowdSec](https://plugins.traefik.io/plugins/6335346ca4caa9ddeffda116/crowdsec-bouncer-traefik-plugin) and [Geoblock](https://github.com/PascalMinder/geoblock).
|
||||
- **Automatically install and configure Crowdsec via Pangolin's installer script.**
|
||||
- Attach as many sites to the central server as you wish.
|
||||
|
||||
### Identity & Access Management
|
||||
|
||||
@@ -65,89 +83,73 @@ _Resources page of Pangolin dashboard (dark mode) showing multiple resources ava
|
||||
- **Temporary, self-destructing share links.**
|
||||
- Resource specific pin codes.
|
||||
- Resource specific passwords.
|
||||
- Passkeys
|
||||
- External identity provider (IdP) support with OAuth2/OIDC, such as Authentik, Keycloak, Okta, and others.
|
||||
- Auto-provision users and roles from your IdP.
|
||||
|
||||
### Simple Dashboard UI
|
||||
<img src="public/auth-diagram1.png" alt="Auth and diagram"/>
|
||||
|
||||
- Manage sites, users, and roles with a clean and intuitive UI.
|
||||
- Monitor site usage and connectivity.
|
||||
- Light and dark mode options.
|
||||
- Mobile friendly.
|
||||
## Use Cases
|
||||
|
||||
### Easy Deployment
|
||||
### Manage Access to Internal Apps
|
||||
|
||||
- Run on any cloud provider or on-premises.
|
||||
- **Docker Compose based setup** for simplified deployment.
|
||||
- Future-proof installation script for streamlined setup and feature additions.
|
||||
- Use any WireGuard client to connect, or use **Newt, our custom user space client** for the best experience.
|
||||
- Use the API to create custom integrations and scripts.
|
||||
- Fine-grained access control to the API via scoped API keys.
|
||||
- Comprehensive Swagger documentation for the API.
|
||||
- Grant users access to your apps from anywhere using just a web browser. No client software required.
|
||||
|
||||
### Modular Design
|
||||
### Developers and DevOps
|
||||
|
||||
- Extend functionality with existing [Traefik](https://github.com/traefik/traefik) plugins, such as [CrowdSec](https://plugins.traefik.io/plugins/6335346ca4caa9ddeffda116/crowdsec-bouncer-traefik-plugin) and [Geoblock](https://github.com/PascalMinder/geoblock).
|
||||
- **Automatically install and configure Crowdsec via Pangolin's installer script.**
|
||||
- Attach as many sites to the central server as you wish.
|
||||
- Expose and test internal tools and dashboards like **Grafana**. Bring localhost or private IPs online for easy access.
|
||||
|
||||
<img src="public/screenshots/collage.png" alt="Collage"/>
|
||||
### Secure API Gateway
|
||||
|
||||
## Deployment and Usage Example
|
||||
- One application load balancer across multiple clouds and on-premises.
|
||||
|
||||
1. **Deploy the Central Server**:
|
||||
### IoT and Edge Devices
|
||||
|
||||
- Deploy the Docker Compose stack onto a VPS hosted on a cloud platform like RackNerd, Amazon EC2, DigitalOcean Droplet, or similar. There are many cheap VPS hosting options available to suit your needs.
|
||||
- Easily expose **IoT devices**, **edge servers**, or **Raspberry Pi** to the internet for field equipment monitoring.
|
||||
|
||||
<img src="public/screenshots/sites.png" alt="Sites"/>
|
||||
|
||||
## Deployment Options
|
||||
|
||||
### Fully Self Hosted
|
||||
|
||||
Host the full application on your own server or on the cloud with a VPS. Take a look at the [documentation](https://docs.digpangolin.com/self-host/quick-install) to get started.
|
||||
|
||||
> [!TIP]
|
||||
> Many of our users have had a great experience with [RackNerd](https://my.racknerd.com/aff.php?aff=13788). Depending on promotions, you can get a [**VPS with 1 vCPU, 1GB RAM, and ~20GB SSD for just around $12/year**](https://my.racknerd.com/aff.php?aff=13788&pid=912). That's a great deal!
|
||||
> We are part of the [RackNerd](https://my.racknerd.com/aff.php?aff=13788) affiliate program, so if you purchase through [our link](https://my.racknerd.com/aff.php?aff=13788), we receive a small commission which helps us maintain the project and keep it free for everyone.
|
||||
|
||||
1. **Domain Configuration**:
|
||||
### Pangolin Cloud
|
||||
|
||||
- Point your domain name to the VPS and configure Pangolin with your preferred settings.
|
||||
Easy to use with simple [pay as you go pricing](https://digpangolin.com/pricing). [Check it out here](https://pangolin.fossorial.io/auth/signup).
|
||||
|
||||
2. **Connect Private Sites**:
|
||||
- Everything you get with self hosted Pangolin, but fully managed for you.
|
||||
|
||||
- Install Newt or use another WireGuard client on private sites.
|
||||
- Automatically establish a connection from these sites to the central server.
|
||||
### Managed & High Availability
|
||||
|
||||
3. **Expose Resources**:
|
||||
Managed control plane, your infrastructure
|
||||
|
||||
- Add resources to the central server and configure access control rules.
|
||||
- Access these resources securely from anywhere.
|
||||
- We manage database and control plane.
|
||||
- You self-host lightweight exit-node.
|
||||
- Traffic flows through your infra.
|
||||
- We coordinate failover between your nodes or to Cloud when things go bad.
|
||||
|
||||
**Use Case Example - Bypassing Port Restrictions in Home Lab**:
|
||||
Imagine private sites where the ISP restricts port forwarding. By connecting these sites to Pangolin via WireGuard, you can securely expose HTTP and HTTPS resources on the private network without any networking complexity.
|
||||
Try it out using [Pangolin Cloud](https://pangolin.fossorial.io)
|
||||
|
||||
**Use Case Example - Deploying Services For Your Business**:
|
||||
You can use Pangolin as an easy way to expose your business applications to your users behind a safe authentication portal you can integrate into your IdP solution. Expose resources on prem and on the cloud.
|
||||
### Full Enterprise On-Premises
|
||||
|
||||
**Use Case Example - IoT Networks**:
|
||||
IoT networks are often fragmented and difficult to manage. By deploying Pangolin on a central server, you can connect all your IoT sites via Newt or another WireGuard client. This creates a simple, secure, and centralized way to access IoT resources without the need for intricate networking setups.
|
||||
|
||||
## Similar Projects and Inspirations
|
||||
|
||||
**Cloudflare Tunnels**:
|
||||
A similar approach to proxying private resources securely, but Pangolin is a self-hosted alternative, giving you full control over your infrastructure.
|
||||
|
||||
**Authelia**:
|
||||
This inspired Pangolin’s centralized authentication system for proxies, enabling robust user and role management.
|
||||
[Contact us](mailto:numbat@fossorial.io) for a full distributed and enterprise deployments on your infrastructure controlled by your team.
|
||||
|
||||
## Project Development / Roadmap
|
||||
|
||||
> [!NOTE]
|
||||
> Pangolin is under heavy development. The roadmap is subject to change as we fix bugs, add new features, and make improvements.
|
||||
|
||||
View the [project board](https://github.com/orgs/fosrl/projects/1) for more detailed info.
|
||||
We want to hear your feature requests! Add them to the [discussion board](https://github.com/orgs/fosrl/discussions/categories/feature-requests).
|
||||
|
||||
## Licensing
|
||||
|
||||
Pangolin is dual licensed under the AGPL-3 and the Fossorial Commercial license. Please see the [LICENSE](./LICENSE) file in the repository for details. For inquiries about commercial licensing, please contact us at [numbat@fossorial.io](mailto:numbat@fossorial.io).
|
||||
Pangolin is dual licensed under the AGPL-3 and the Fossorial Commercial license. For inquiries about commercial licensing, please contact us at [numbat@fossorial.io](mailto:numbat@fossorial.io).
|
||||
|
||||
## Contributions
|
||||
|
||||
Looking for something to contribute? Take a look at issues marked with [help wanted](https://github.com/fosrl/pangolin/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22). Also take a look through the freature requests in Discussions - any are available and some are marked as a good first issue.
|
||||
|
||||
Please see [CONTRIBUTING](./CONTRIBUTING.md) in the repository for guidelines and best practices.
|
||||
|
||||
Please post bug reports and other functional issues in the [Issues](https://github.com/fosrl/pangolin/issues) section of the repository.
|
||||
For all feature requests, or other ideas, please use the [Discussions](https://github.com/orgs/fosrl/discussions) section.
|
||||
|
||||
72
blueprint.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import requests
|
||||
import yaml
|
||||
import json
|
||||
import base64
|
||||
|
||||
# The file path for the YAML file to be read
|
||||
# You can change this to the path of your YAML file
|
||||
YAML_FILE_PATH = 'blueprint.yaml'
|
||||
|
||||
# The API endpoint and headers from the curl request
|
||||
API_URL = 'http://api.pangolin.fossorial.io/v1/org/test/blueprint'
|
||||
HEADERS = {
|
||||
'accept': '*/*',
|
||||
'Authorization': 'Bearer <your_token_here>',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
def convert_and_send(file_path, url, headers):
|
||||
"""
|
||||
Reads a YAML file, converts its content to a JSON payload,
|
||||
and sends it via a PUT request to a specified URL.
|
||||
"""
|
||||
try:
|
||||
# Read the YAML file content
|
||||
with open(file_path, 'r') as file:
|
||||
yaml_content = file.read()
|
||||
|
||||
# Parse the YAML string to a Python dictionary
|
||||
# This will be used to ensure the YAML is valid before sending
|
||||
parsed_yaml = yaml.safe_load(yaml_content)
|
||||
|
||||
# convert the parsed YAML to a JSON string
|
||||
json_payload = json.dumps(parsed_yaml)
|
||||
print("Converted JSON payload:")
|
||||
print(json_payload)
|
||||
|
||||
# Encode the JSON string to Base64
|
||||
encoded_json = base64.b64encode(json_payload.encode('utf-8')).decode('utf-8')
|
||||
|
||||
# Create the final payload with the base64 encoded data
|
||||
final_payload = {
|
||||
"blueprint": encoded_json
|
||||
}
|
||||
|
||||
print("Sending the following Base64 encoded JSON payload:")
|
||||
print(final_payload)
|
||||
print("-" * 20)
|
||||
|
||||
# Make the PUT request with the base64 encoded payload
|
||||
response = requests.put(url, headers=headers, json=final_payload)
|
||||
|
||||
# Print the API response for debugging
|
||||
print(f"API Response Status Code: {response.status_code}")
|
||||
print("API Response Content:")
|
||||
print(response.text)
|
||||
|
||||
# Raise an exception for bad status codes (4xx or 5xx)
|
||||
response.raise_for_status()
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: The file '{file_path}' was not found.")
|
||||
except yaml.YAMLError as e:
|
||||
print(f"Error parsing YAML file: {e}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An error occurred during the API request: {e}")
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
|
||||
# Run the function
|
||||
if __name__ == "__main__":
|
||||
convert_and_send(YAML_FILE_PATH, API_URL, HEADERS)
|
||||
|
||||
69
blueprint.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
client-resources:
|
||||
client-resource-nice-id-uno:
|
||||
name: this is my resource
|
||||
protocol: tcp
|
||||
proxy-port: 3001
|
||||
hostname: localhost
|
||||
internal-port: 3000
|
||||
site: lively-yosemite-toad
|
||||
client-resource-nice-id-duce:
|
||||
name: this is my resource
|
||||
protocol: udp
|
||||
proxy-port: 3000
|
||||
hostname: localhost
|
||||
internal-port: 3000
|
||||
site: lively-yosemite-toad
|
||||
|
||||
proxy-resources:
|
||||
resource-nice-id-uno:
|
||||
name: this is my resource
|
||||
protocol: http
|
||||
full-domain: duce.test.example.com
|
||||
host-header: example.com
|
||||
tls-server-name: example.com
|
||||
# auth:
|
||||
# pincode: 123456
|
||||
# password: sadfasdfadsf
|
||||
# sso-enabled: true
|
||||
# sso-roles:
|
||||
# - Member
|
||||
# sso-users:
|
||||
# - owen@fossorial.io
|
||||
# whitelist-users:
|
||||
# - owen@fossorial.io
|
||||
headers:
|
||||
- name: X-Example-Header
|
||||
value: example-value
|
||||
- name: X-Another-Header
|
||||
value: another-value
|
||||
rules:
|
||||
- action: allow
|
||||
match: ip
|
||||
value: 1.1.1.1
|
||||
- action: deny
|
||||
match: cidr
|
||||
value: 2.2.2.2/32
|
||||
- action: pass
|
||||
match: path
|
||||
value: /admin
|
||||
targets:
|
||||
- site: lively-yosemite-toad
|
||||
path: /path
|
||||
pathMatchType: prefix
|
||||
hostname: localhost
|
||||
method: http
|
||||
port: 8000
|
||||
- site: slim-alpine-chipmunk
|
||||
hostname: localhost
|
||||
path: /yoman
|
||||
pathMatchType: exact
|
||||
method: http
|
||||
port: 8001
|
||||
resource-nice-id-duce:
|
||||
name: this is other resource
|
||||
protocol: tcp
|
||||
proxy-port: 3000
|
||||
targets:
|
||||
- site: lively-yosemite-toad
|
||||
hostname: localhost
|
||||
port: 3000
|
||||
22
bruno/Clients/createClient.bru
Normal file
@@ -0,0 +1,22 @@
|
||||
meta {
|
||||
name: createClient
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:3000/api/v1/site/1/client
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"siteId": 1,
|
||||
"name": "test",
|
||||
"type": "olm",
|
||||
"subnet": "100.90.129.4/30",
|
||||
"olmId": "029yzunhx6nh3y5",
|
||||
"secret": "l0ymp075y3d4rccb25l6sqpgar52k09etunui970qq5gj7x6"
|
||||
}
|
||||
}
|
||||
11
bruno/Clients/pickClientDefaults.bru
Normal file
@@ -0,0 +1,11 @@
|
||||
meta {
|
||||
name: pickClientDefaults
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:3000/api/v1/site/1/pick-client-defaults
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
72
cli/commands/resetUserSecurityKeys.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { CommandModule } from "yargs";
|
||||
import { db, users, securityKeys } from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
type ResetUserSecurityKeysArgs = {
|
||||
email: string;
|
||||
};
|
||||
|
||||
export const resetUserSecurityKeys: CommandModule<
|
||||
{},
|
||||
ResetUserSecurityKeysArgs
|
||||
> = {
|
||||
command: "reset-user-security-keys",
|
||||
describe:
|
||||
"Reset a user's security keys (passkeys) by deleting all their webauthn credentials",
|
||||
builder: (yargs) => {
|
||||
return yargs.option("email", {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
describe: "User email address"
|
||||
});
|
||||
},
|
||||
handler: async (argv: { email: string }) => {
|
||||
try {
|
||||
const { email } = argv;
|
||||
|
||||
console.log(`Looking for user with email: ${email}`);
|
||||
|
||||
// Find the user by email
|
||||
const [user] = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email))
|
||||
.limit(1);
|
||||
|
||||
if (!user) {
|
||||
console.error(`User with email '${email}' not found`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Found user: ${user.email} (ID: ${user.userId})`);
|
||||
|
||||
// Check if user has any security keys
|
||||
const userSecurityKeys = await db
|
||||
.select()
|
||||
.from(securityKeys)
|
||||
.where(eq(securityKeys.userId, user.userId));
|
||||
|
||||
if (userSecurityKeys.length === 0) {
|
||||
console.log(`User '${email}' has no security keys to reset`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Found ${userSecurityKeys.length} security key(s) for user '${email}'`
|
||||
);
|
||||
|
||||
// Delete all security keys for the user
|
||||
await db
|
||||
.delete(securityKeys)
|
||||
.where(eq(securityKeys.userId, user.userId));
|
||||
|
||||
console.log(`Successfully reset security keys for user '${email}'`);
|
||||
console.log(`Deleted ${userSecurityKeys.length} security key(s)`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -32,7 +32,9 @@ export const setAdminCredentials: CommandModule<{}, SetAdminCredentialsArgs> = {
|
||||
},
|
||||
handler: async (argv: { email: string; password: string }) => {
|
||||
try {
|
||||
const { email, password } = argv;
|
||||
const { password } = argv;
|
||||
let { email } = argv;
|
||||
email = email.trim().toLowerCase();
|
||||
|
||||
const parsed = passwordSchema.safeParse(password);
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import { setAdminCredentials } from "@cli/commands/setAdminCredentials";
|
||||
import { resetUserSecurityKeys } from "@cli/commands/resetUserSecurityKeys";
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.scriptName("pangctl")
|
||||
.command(setAdminCredentials)
|
||||
.command(resetUserSecurityKeys)
|
||||
.demandCommand()
|
||||
.help().argv;
|
||||
|
||||
@@ -1,49 +1,28 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.fossorial.io/Pangolin/Configuration/config
|
||||
# https://docs.digpangolin.com/self-host/advanced/config-file
|
||||
|
||||
app:
|
||||
dashboard_url: "http://localhost:3002"
|
||||
log_level: "info"
|
||||
save_logs: false
|
||||
dashboard_url: http://localhost:3002
|
||||
log_level: debug
|
||||
|
||||
domains:
|
||||
domain1:
|
||||
base_domain: "example.com"
|
||||
cert_resolver: "letsencrypt"
|
||||
domain1:
|
||||
base_domain: example.com
|
||||
|
||||
server:
|
||||
external_port: 3000
|
||||
internal_port: 3001
|
||||
next_port: 3002
|
||||
internal_hostname: "pangolin"
|
||||
session_cookie_name: "p_session_token"
|
||||
resource_access_token_param: "p_token"
|
||||
secret: "your_secret_key_here"
|
||||
resource_access_token_headers:
|
||||
id: "P-Access-Token-Id"
|
||||
token: "P-Access-Token"
|
||||
resource_session_request_param: "p_session_request"
|
||||
|
||||
traefik:
|
||||
http_entrypoint: "web"
|
||||
https_entrypoint: "websecure"
|
||||
secret: my_secret_key
|
||||
|
||||
gerbil:
|
||||
start_port: 51820
|
||||
base_endpoint: "localhost"
|
||||
block_size: 24
|
||||
site_block_size: 30
|
||||
subnet_group: 100.89.137.0/20
|
||||
use_subdomain: true
|
||||
base_endpoint: example.com
|
||||
|
||||
rate_limits:
|
||||
global:
|
||||
window_minutes: 1
|
||||
max_requests: 500
|
||||
orgs:
|
||||
block_size: 24
|
||||
subnet_group: 100.90.137.0/20
|
||||
|
||||
flags:
|
||||
require_email_verification: false
|
||||
disable_signup_without_invite: true
|
||||
disable_user_create_org: true
|
||||
allow_raw_resources: true
|
||||
allow_base_domain_resources: true
|
||||
require_email_verification: false
|
||||
disable_signup_without_invite: true
|
||||
disable_user_create_org: true
|
||||
allow_raw_resources: true
|
||||
enable_integration_api: true
|
||||
enable_clients: true
|
||||
|
||||
46
config/traefik/dynamic_config.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
http:
|
||||
middlewares:
|
||||
redirect-to-https:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
|
||||
routers:
|
||||
# HTTP to HTTPS redirect router
|
||||
main-app-router-redirect:
|
||||
rule: "Host(`{{.DashboardDomain}}`)"
|
||||
service: next-service
|
||||
entryPoints:
|
||||
- web
|
||||
middlewares:
|
||||
- redirect-to-https
|
||||
|
||||
# Next.js router (handles everything except API and WebSocket paths)
|
||||
next-router:
|
||||
rule: "Host(`{{.DashboardDomain}}`)"
|
||||
service: next-service
|
||||
priority: 10
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
# API router (handles /api/v1 paths)
|
||||
api-router:
|
||||
rule: "Host(`{{.DashboardDomain}}`) && PathPrefix(`/api/v1`)"
|
||||
service: api-service
|
||||
priority: 100
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
services:
|
||||
next-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://pangolin:3002" # Next.js server
|
||||
|
||||
api-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://pangolin:3000" # API/WebSocket server
|
||||
34
config/traefik/traefik_config.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
api:
|
||||
insecure: true
|
||||
dashboard: true
|
||||
|
||||
providers:
|
||||
file:
|
||||
directory: "/var/dynamic"
|
||||
watch: true
|
||||
|
||||
experimental:
|
||||
plugins:
|
||||
badger:
|
||||
moduleName: "github.com/fosrl/badger"
|
||||
version: "v1.2.0"
|
||||
|
||||
log:
|
||||
level: "DEBUG"
|
||||
format: "common"
|
||||
maxSize: 100
|
||||
maxBackups: 3
|
||||
maxAge: 3
|
||||
compress: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":9443"
|
||||
transport:
|
||||
respondingTimeouts:
|
||||
readTimeout: "30m"
|
||||
|
||||
serversTransport:
|
||||
insecureSkipVerify: true
|
||||
@@ -22,8 +22,7 @@ services:
|
||||
command:
|
||||
- --reachableAt=http://gerbil:3003
|
||||
- --generateAndSaveKeyTo=/var/config/key
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
|
||||
- --reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/
|
||||
volumes:
|
||||
- ./config/:/var/config
|
||||
cap_add:
|
||||
@@ -31,11 +30,12 @@ services:
|
||||
- SYS_MODULE
|
||||
ports:
|
||||
- 51820:51820/udp
|
||||
- 21820:21820/udp
|
||||
- 443:443 # Port for traefik because of the network_mode
|
||||
- 80:80 # Port for traefik because of the network_mode
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.4.0
|
||||
image: traefik:v3.5
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
network_mode: service:gerbil # Ports appear on the gerbil service
|
||||
@@ -51,4 +51,5 @@ services:
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
name: pangolin
|
||||
name: pangolin
|
||||
enable_ipv6: true
|
||||
14
docker-compose.pg.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
# PostgreSQL Service
|
||||
db:
|
||||
image: postgres:17 # Use the PostgreSQL 17 image
|
||||
container_name: dev_postgres # Name your PostgreSQL container
|
||||
environment:
|
||||
POSTGRES_DB: postgres # Default database name
|
||||
POSTGRES_USER: postgres # Default user
|
||||
POSTGRES_PASSWORD: password # Default password (change for production!)
|
||||
volumes:
|
||||
- ./config/postgres:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432" # Map host port 5432 to container port 5432
|
||||
restart: no
|
||||
32
docker-compose.t.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
name: pangolin
|
||||
services:
|
||||
gerbil:
|
||||
image: gerbil
|
||||
container_name: gerbil
|
||||
network_mode: host
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --reachableAt=http://localhost:3003
|
||||
- --generateAndSaveKeyTo=/var/config/key
|
||||
- --remoteConfig=http://localhost:3001/api/v1/
|
||||
- --sni-port=443
|
||||
volumes:
|
||||
- ./config/:/var/config
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_MODULE
|
||||
|
||||
traefik:
|
||||
image: docker.io/traefik:v3.4.1
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
command:
|
||||
- --configFile=/etc/traefik/traefik_config.yml
|
||||
volumes:
|
||||
- ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
|
||||
- ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
|
||||
- ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs
|
||||
- ./certificates:/var/certificates:ro
|
||||
- ./dynamic:/var/dynamic:ro
|
||||
|
||||
29
docker-compose.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
services:
|
||||
# Development application service
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: dev_pangolin
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3001:3001"
|
||||
- "3002:3002"
|
||||
- "3003:3003"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- ENVIRONMENT=dev
|
||||
volumes:
|
||||
# Mount source code for hot reload
|
||||
- ./src:/app/src
|
||||
- ./server:/app/server
|
||||
- ./public:/app/public
|
||||
- ./messages:/app/messages
|
||||
- ./components.json:/app/components.json
|
||||
- ./next.config.mjs:/app/next.config.mjs
|
||||
- ./tsconfig.json:/app/tsconfig.json
|
||||
- ./tailwind.config.js:/app/tailwind.config.js
|
||||
- ./postcss.config.mjs:/app/postcss.config.mjs
|
||||
- ./eslint.config.js:/app/eslint.config.js
|
||||
- ./config:/app/config
|
||||
restart: no
|
||||
@@ -3,7 +3,7 @@ import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "postgresql",
|
||||
schema: path.join("server", "db", "pg", "schema.ts"),
|
||||
schema: [path.join("server", "db", "pg", "schema.ts")],
|
||||
out: path.join("server", "migrations"),
|
||||
verbose: true,
|
||||
dbCredentials: {
|
||||
|
||||
@@ -52,7 +52,7 @@ esbuild
|
||||
bundle: true,
|
||||
outfile: argv.out,
|
||||
format: "esm",
|
||||
minify: true,
|
||||
minify: false,
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
@@ -63,8 +63,8 @@ esbuild
|
||||
packagePath: getPackagePaths(),
|
||||
}),
|
||||
],
|
||||
sourcemap: true,
|
||||
target: "node20",
|
||||
sourcemap: "inline",
|
||||
target: "node22",
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Build completed successfully");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
all: update-versions go-build-release put-back
|
||||
dev-all: dev-update-versions dev-build dev-clean
|
||||
|
||||
go-build-release:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/installer_linux_amd64
|
||||
@@ -11,6 +12,12 @@ clean:
|
||||
update-versions:
|
||||
@echo "Fetching latest versions..."
|
||||
cp main.go main.go.bak && \
|
||||
$(MAKE) dev-update-versions
|
||||
|
||||
put-back:
|
||||
mv main.go.bak main.go
|
||||
|
||||
dev-update-versions:
|
||||
PANGOLIN_VERSION=$$(curl -s https://api.github.com/repos/fosrl/pangolin/tags | jq -r '.[0].name') && \
|
||||
GERBIL_VERSION=$$(curl -s https://api.github.com/repos/fosrl/gerbil/tags | jq -r '.[0].name') && \
|
||||
BADGER_VERSION=$$(curl -s https://api.github.com/repos/fosrl/badger/tags | jq -r '.[0].name') && \
|
||||
@@ -20,5 +27,11 @@ update-versions:
|
||||
sed -i "s/config.BadgerVersion = \".*\"/config.BadgerVersion = \"$$BADGER_VERSION\"/" main.go && \
|
||||
echo "Updated main.go with latest versions"
|
||||
|
||||
put-back:
|
||||
mv main.go.bak main.go
|
||||
dev-build: go-build-release
|
||||
|
||||
dev-clean:
|
||||
@echo "Restoring version values ..."
|
||||
sed -i "s/config.PangolinVersion = \".*\"/config.PangolinVersion = \"replaceme\"/" main.go && \
|
||||
sed -i "s/config.GerbilVersion = \".*\"/config.GerbilVersion = \"replaceme\"/" main.go && \
|
||||
sed -i "s/config.BadgerVersion = \".*\"/config.BadgerVersion = \"replaceme\"/" main.go
|
||||
@echo "Restored version strings in main.go"
|
||||
|
||||
@@ -37,15 +37,28 @@ type DynamicConfig struct {
|
||||
} `yaml:"http"`
|
||||
}
|
||||
|
||||
// ConfigValues holds the extracted configuration values
|
||||
type ConfigValues struct {
|
||||
// TraefikConfigValues holds the extracted configuration values
|
||||
type TraefikConfigValues struct {
|
||||
DashboardDomain string
|
||||
LetsEncryptEmail string
|
||||
BadgerVersion string
|
||||
}
|
||||
|
||||
// AppConfig represents the app section of the config.yml
|
||||
type AppConfig struct {
|
||||
App struct {
|
||||
DashboardURL string `yaml:"dashboard_url"`
|
||||
LogLevel string `yaml:"log_level"`
|
||||
} `yaml:"app"`
|
||||
}
|
||||
|
||||
type AppConfigValues struct {
|
||||
DashboardURL string
|
||||
LogLevel string
|
||||
}
|
||||
|
||||
// ReadTraefikConfig reads and extracts values from Traefik configuration files
|
||||
func ReadTraefikConfig(mainConfigPath, dynamicConfigPath string) (*ConfigValues, error) {
|
||||
func ReadTraefikConfig(mainConfigPath string) (*TraefikConfigValues, error) {
|
||||
// Read main config file
|
||||
mainConfigData, err := os.ReadFile(mainConfigPath)
|
||||
if err != nil {
|
||||
@@ -57,48 +70,33 @@ func ReadTraefikConfig(mainConfigPath, dynamicConfigPath string) (*ConfigValues,
|
||||
return nil, fmt.Errorf("error parsing main config file: %w", err)
|
||||
}
|
||||
|
||||
// Read dynamic config file
|
||||
dynamicConfigData, err := os.ReadFile(dynamicConfigPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading dynamic config file: %w", err)
|
||||
}
|
||||
|
||||
var dynamicConfig DynamicConfig
|
||||
if err := yaml.Unmarshal(dynamicConfigData, &dynamicConfig); err != nil {
|
||||
return nil, fmt.Errorf("error parsing dynamic config file: %w", err)
|
||||
}
|
||||
|
||||
// Extract values
|
||||
values := &ConfigValues{
|
||||
values := &TraefikConfigValues{
|
||||
BadgerVersion: mainConfig.Experimental.Plugins.Badger.Version,
|
||||
LetsEncryptEmail: mainConfig.CertificatesResolvers.LetsEncrypt.Acme.Email,
|
||||
}
|
||||
|
||||
// Extract DashboardDomain from router rules
|
||||
// Look for it in the main router rules
|
||||
for _, router := range dynamicConfig.HTTP.Routers {
|
||||
if router.Rule != "" {
|
||||
// Extract domain from Host(`mydomain.com`)
|
||||
if domain := extractDomainFromRule(router.Rule); domain != "" {
|
||||
values.DashboardDomain = domain
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// extractDomainFromRule extracts the domain from a router rule
|
||||
func extractDomainFromRule(rule string) string {
|
||||
// Look for the Host(`mydomain.com`) pattern
|
||||
if start := findPattern(rule, "Host(`"); start != -1 {
|
||||
end := findPattern(rule[start:], "`)")
|
||||
if end != -1 {
|
||||
return rule[start+6 : start+end]
|
||||
}
|
||||
func ReadAppConfig(configPath string) (*AppConfigValues, error) {
|
||||
// Read config file
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading config file: %w", err)
|
||||
}
|
||||
return ""
|
||||
|
||||
var appConfig AppConfig
|
||||
if err := yaml.Unmarshal(configData, &appConfig); err != nil {
|
||||
return nil, fmt.Errorf("error parsing config file: %w", err)
|
||||
}
|
||||
|
||||
values := &AppConfigValues{
|
||||
DashboardURL: appConfig.App.DashboardURL,
|
||||
LogLevel: appConfig.App.LogLevel,
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// findPattern finds the start of a pattern in a string
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.fossorial.io/Pangolin/Configuration/config
|
||||
# https://docs.digpangolin.com/self-host/advanced/config-file
|
||||
|
||||
gerbil:
|
||||
start_port: 51820
|
||||
base_endpoint: "{{.DashboardDomain}}"
|
||||
{{if .HybridMode}}
|
||||
managed:
|
||||
id: "{{.HybridId}}"
|
||||
secret: "{{.HybridSecret}}"
|
||||
|
||||
{{else}}
|
||||
app:
|
||||
dashboard_url: "https://{{.DashboardDomain}}"
|
||||
log_level: "info"
|
||||
telemetry:
|
||||
anonymous_usage: true
|
||||
|
||||
domains:
|
||||
domain1:
|
||||
@@ -17,11 +28,6 @@ server:
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
||||
allowed_headers: ["X-CSRF-Token", "Content-Type"]
|
||||
credentials: false
|
||||
|
||||
gerbil:
|
||||
start_port: 51820
|
||||
base_endpoint: "{{.DashboardDomain}}"
|
||||
|
||||
{{if .EnableEmail}}
|
||||
email:
|
||||
smtp_host: "{{.EmailSMTPHost}}"
|
||||
@@ -30,10 +36,9 @@ email:
|
||||
smtp_pass: "{{.EmailSMTPPass}}"
|
||||
no_reply: "{{.EmailNoReply}}"
|
||||
{{end}}
|
||||
|
||||
flags:
|
||||
require_email_verification: {{.EnableEmail}}
|
||||
disable_signup_without_invite: true
|
||||
disable_user_create_org: false
|
||||
allow_raw_resources: true
|
||||
allow_base_domain_resources: true
|
||||
{{end}}
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
crowdsec:
|
||||
image: crowdsecurity/crowdsec:latest
|
||||
image: docker.io/crowdsecurity/crowdsec:latest
|
||||
container_name: crowdsec
|
||||
environment:
|
||||
GID: "1000"
|
||||
|
||||
@@ -22,4 +22,4 @@ filters:
|
||||
decisions:
|
||||
- type: ban
|
||||
duration: 4h
|
||||
on_success: break
|
||||
on_success: break
|
||||
|
||||
@@ -16,7 +16,7 @@ experimental:
|
||||
version: "{{.BadgerVersion}}"
|
||||
crowdsec: # CrowdSec plugin configuration added
|
||||
moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
|
||||
version: "v1.4.2"
|
||||
version: "v1.4.4"
|
||||
|
||||
log:
|
||||
level: "INFO"
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
name: pangolin
|
||||
services:
|
||||
pangolin:
|
||||
image: fosrl/pangolin:{{.PangolinVersion}}
|
||||
image: docker.io/fosrl/pangolin:{{.PangolinVersion}}
|
||||
container_name: pangolin
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./config:/app/config
|
||||
- pangolin-data:/var/certificates
|
||||
- pangolin-data:/var/dynamic
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
|
||||
interval: "10s"
|
||||
@@ -13,7 +15,7 @@ services:
|
||||
retries: 15
|
||||
{{if .InstallGerbil}}
|
||||
gerbil:
|
||||
image: fosrl/gerbil:{{.GerbilVersion}}
|
||||
image: docker.io/fosrl/gerbil:{{.GerbilVersion}}
|
||||
container_name: gerbil
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -22,8 +24,7 @@ services:
|
||||
command:
|
||||
- --reachableAt=http://gerbil:3003
|
||||
- --generateAndSaveKeyTo=/var/config/key
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
|
||||
- --reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/
|
||||
volumes:
|
||||
- ./config/:/var/config
|
||||
cap_add:
|
||||
@@ -31,11 +32,12 @@ services:
|
||||
- SYS_MODULE
|
||||
ports:
|
||||
- 51820:51820/udp
|
||||
- 443:443 # Port for traefik because of the network_mode
|
||||
- 80:80 # Port for traefik because of the network_mode
|
||||
- 21820:21820/udp
|
||||
- 443:{{if .HybridMode}}8443{{else}}443{{end}}
|
||||
- 80:80
|
||||
{{end}}
|
||||
traefik:
|
||||
image: traefik:v3.4.1
|
||||
image: docker.io/traefik:v3.5
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
{{if .InstallGerbil}}
|
||||
@@ -54,8 +56,15 @@ services:
|
||||
- ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
|
||||
- ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
|
||||
- ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs
|
||||
# Shared volume for certificates and dynamic config in file mode
|
||||
- pangolin-data:/var/certificates:ro
|
||||
- pangolin-data:/var/dynamic:ro
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
name: pangolin
|
||||
{{if .EnableIPv6}} enable_ipv6: true{{end}}
|
||||
|
||||
volumes:
|
||||
pangolin-data:
|
||||
|
||||
@@ -3,12 +3,17 @@ api:
|
||||
dashboard: true
|
||||
|
||||
providers:
|
||||
{{if not .HybridMode}}
|
||||
http:
|
||||
endpoint: "http://pangolin:3001/api/v1/traefik-config"
|
||||
pollInterval: "5s"
|
||||
file:
|
||||
filename: "/etc/traefik/dynamic_config.yml"
|
||||
|
||||
{{else}}
|
||||
file:
|
||||
directory: "/var/dynamic"
|
||||
watch: true
|
||||
{{end}}
|
||||
experimental:
|
||||
plugins:
|
||||
badger:
|
||||
@@ -22,7 +27,7 @@ log:
|
||||
maxBackups: 3
|
||||
maxAge: 3
|
||||
compress: true
|
||||
|
||||
{{if not .HybridMode}}
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
@@ -31,18 +36,25 @@ certificatesResolvers:
|
||||
email: "{{.LetsEncryptEmail}}"
|
||||
storage: "/letsencrypt/acme.json"
|
||||
caServer: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
|
||||
{{end}}
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
{{if .HybridMode}} proxyProtocol:
|
||||
trustedIPs:
|
||||
- 0.0.0.0/0
|
||||
- ::1/128{{end}}
|
||||
transport:
|
||||
respondingTimeouts:
|
||||
readTimeout: "30m"
|
||||
http:
|
||||
{{if not .HybridMode}} http:
|
||||
tls:
|
||||
certResolver: "letsencrypt"
|
||||
certResolver: "letsencrypt"{{end}}
|
||||
|
||||
serversTransport:
|
||||
insecureSkipVerify: true
|
||||
|
||||
ping:
|
||||
entryPoint: "web"
|
||||
332
install/containers.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func waitForContainer(containerName string, containerType SupportedContainer) error {
|
||||
maxAttempts := 30
|
||||
retryInterval := time.Second * 2
|
||||
|
||||
for attempt := 0; attempt < maxAttempts; attempt++ {
|
||||
// Check if container is running
|
||||
cmd := exec.Command(string(containerType), "container", "inspect", "-f", "{{.State.Running}}", containerName)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
// If the container doesn't exist or there's another error, wait and retry
|
||||
time.Sleep(retryInterval)
|
||||
continue
|
||||
}
|
||||
|
||||
isRunning := strings.TrimSpace(out.String()) == "true"
|
||||
if isRunning {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container exists but isn't running yet, wait and retry
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
|
||||
return fmt.Errorf("container %s did not start within %v seconds", containerName, maxAttempts*int(retryInterval.Seconds()))
|
||||
}
|
||||
|
||||
func installDocker() error {
|
||||
// Detect Linux distribution
|
||||
cmd := exec.Command("cat", "/etc/os-release")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to detect Linux distribution: %v", err)
|
||||
}
|
||||
osRelease := string(output)
|
||||
|
||||
// Detect system architecture
|
||||
archCmd := exec.Command("uname", "-m")
|
||||
archOutput, err := archCmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to detect system architecture: %v", err)
|
||||
}
|
||||
arch := strings.TrimSpace(string(archOutput))
|
||||
|
||||
// Map architecture to Docker's architecture naming
|
||||
var dockerArch string
|
||||
switch arch {
|
||||
case "x86_64":
|
||||
dockerArch = "amd64"
|
||||
case "aarch64":
|
||||
dockerArch = "arm64"
|
||||
default:
|
||||
return fmt.Errorf("unsupported architecture: %s", arch)
|
||||
}
|
||||
|
||||
var installCmd *exec.Cmd
|
||||
switch {
|
||||
case strings.Contains(osRelease, "ID=ubuntu"):
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
apt-get update &&
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg &&
|
||||
echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list &&
|
||||
apt-get update &&
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, dockerArch))
|
||||
case strings.Contains(osRelease, "ID=debian"):
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
apt-get update &&
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg &&
|
||||
echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list &&
|
||||
apt-get update &&
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, dockerArch))
|
||||
case strings.Contains(osRelease, "ID=fedora"):
|
||||
// Detect Fedora version to handle DNF 5 changes
|
||||
versionCmd := exec.Command("bash", "-c", "grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '\"'")
|
||||
versionOutput, err := versionCmd.Output()
|
||||
var fedoraVersion int
|
||||
if err == nil {
|
||||
if v, parseErr := strconv.Atoi(strings.TrimSpace(string(versionOutput))); parseErr == nil {
|
||||
fedoraVersion = v
|
||||
}
|
||||
}
|
||||
|
||||
// Use appropriate DNF syntax based on version
|
||||
var repoCmd string
|
||||
if fedoraVersion >= 41 {
|
||||
// DNF 5 syntax for Fedora 41+
|
||||
repoCmd = "dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo"
|
||||
} else {
|
||||
// DNF 4 syntax for Fedora < 41
|
||||
repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo"
|
||||
}
|
||||
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
dnf -y install dnf-plugins-core &&
|
||||
%s &&
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, repoCmd))
|
||||
case strings.Contains(osRelease, "ID=opensuse") || strings.Contains(osRelease, "ID=\"opensuse-"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
zypper install -y docker docker-compose &&
|
||||
systemctl enable docker
|
||||
`)
|
||||
case strings.Contains(osRelease, "ID=rhel") || strings.Contains(osRelease, "ID=\"rhel"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
dnf remove -y runc &&
|
||||
dnf -y install yum-utils &&
|
||||
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo &&
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin &&
|
||||
systemctl enable docker
|
||||
`)
|
||||
case strings.Contains(osRelease, "ID=amzn"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
yum update -y &&
|
||||
yum install -y docker &&
|
||||
systemctl enable docker &&
|
||||
usermod -a -G docker ec2-user
|
||||
`)
|
||||
default:
|
||||
return fmt.Errorf("unsupported Linux distribution")
|
||||
}
|
||||
|
||||
installCmd.Stdout = os.Stdout
|
||||
installCmd.Stderr = os.Stderr
|
||||
return installCmd.Run()
|
||||
}
|
||||
|
||||
func startDockerService() error {
|
||||
if runtime.GOOS == "linux" {
|
||||
cmd := exec.Command("systemctl", "enable", "--now", "docker")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
// On macOS, Docker is usually started via the Docker Desktop application
|
||||
fmt.Println("Please start Docker Desktop manually on macOS.")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unsupported operating system for starting Docker service")
|
||||
}
|
||||
|
||||
func isDockerInstalled() bool {
|
||||
return isContainerInstalled("docker")
|
||||
}
|
||||
|
||||
func isPodmanInstalled() bool {
|
||||
return isContainerInstalled("podman") && isContainerInstalled("podman-compose")
|
||||
}
|
||||
|
||||
func isContainerInstalled(container string) bool {
|
||||
cmd := exec.Command(container, "--version")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isUserInDockerGroup() bool {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Docker group is not applicable on macOS
|
||||
// So we assume that the user can run Docker commands
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Geteuid() == 0 {
|
||||
return true // Root user can run Docker commands anyway
|
||||
}
|
||||
|
||||
// Check if the current user is in the docker group
|
||||
if dockerGroup, err := user.LookupGroup("docker"); err == nil {
|
||||
if currentUser, err := user.Current(); err == nil {
|
||||
if currentUserGroupIds, err := currentUser.GroupIds(); err == nil {
|
||||
for _, groupId := range currentUserGroupIds {
|
||||
if groupId == dockerGroup.Gid {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eventually, if any of the checks fail, we assume the user cannot run Docker commands
|
||||
return false
|
||||
}
|
||||
|
||||
// isDockerRunning checks if the Docker daemon is running by using the `docker info` command.
|
||||
func isDockerRunning() bool {
|
||||
cmd := exec.Command("docker", "info")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied
|
||||
func executeDockerComposeCommandWithArgs(args ...string) error {
|
||||
var cmd *exec.Cmd
|
||||
var useNewStyle bool
|
||||
|
||||
if !isDockerInstalled() {
|
||||
return fmt.Errorf("docker is not installed")
|
||||
}
|
||||
|
||||
checkCmd := exec.Command("docker", "compose", "version")
|
||||
if err := checkCmd.Run(); err == nil {
|
||||
useNewStyle = true
|
||||
} else {
|
||||
checkCmd = exec.Command("docker-compose", "version")
|
||||
if err := checkCmd.Run(); err == nil {
|
||||
useNewStyle = false
|
||||
} else {
|
||||
return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available")
|
||||
}
|
||||
}
|
||||
|
||||
if useNewStyle {
|
||||
cmd = exec.Command("docker", append([]string{"compose"}, args...)...)
|
||||
} else {
|
||||
cmd = exec.Command("docker-compose", args...)
|
||||
}
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// pullContainers pulls the containers using the appropriate command.
|
||||
func pullContainers(containerType SupportedContainer) error {
|
||||
fmt.Println("Pulling the container images...")
|
||||
if containerType == Podman {
|
||||
if err := run("podman-compose", "-f", "docker-compose.yml", "pull"); err != nil {
|
||||
return fmt.Errorf("failed to pull the containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if containerType == Docker {
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "pull", "--policy", "always"); err != nil {
|
||||
return fmt.Errorf("failed to pull the containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unsupported container type: %s", containerType)
|
||||
}
|
||||
|
||||
// startContainers starts the containers using the appropriate command.
|
||||
func startContainers(containerType SupportedContainer) error {
|
||||
fmt.Println("Starting containers...")
|
||||
|
||||
if containerType == Podman {
|
||||
if err := run("podman-compose", "-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil {
|
||||
return fmt.Errorf("failed start containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if containerType == Docker {
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil {
|
||||
return fmt.Errorf("failed to start containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unsupported container type: %s", containerType)
|
||||
}
|
||||
|
||||
// stopContainers stops the containers using the appropriate command.
|
||||
func stopContainers(containerType SupportedContainer) error {
|
||||
fmt.Println("Stopping containers...")
|
||||
if containerType == Podman {
|
||||
if err := run("podman-compose", "-f", "docker-compose.yml", "down"); err != nil {
|
||||
return fmt.Errorf("failed to stop containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if containerType == Docker {
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil {
|
||||
return fmt.Errorf("failed to stop containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unsupported container type: %s", containerType)
|
||||
}
|
||||
|
||||
// restartContainer restarts a specific container using the appropriate command.
|
||||
func restartContainer(container string, containerType SupportedContainer) error {
|
||||
fmt.Println("Restarting containers...")
|
||||
if containerType == Podman {
|
||||
if err := run("podman-compose", "-f", "docker-compose.yml", "restart"); err != nil {
|
||||
return fmt.Errorf("failed to stop the container \"%s\": %v", container, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if containerType == Docker {
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil {
|
||||
return fmt.Errorf("failed to stop the container \"%s\": %v", container, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unsupported container type: %s", containerType)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
func installCrowdsec(config Config) error {
|
||||
|
||||
if err := stopContainers(); err != nil {
|
||||
if err := stopContainers(config.InstallationContainerType); err != nil {
|
||||
return fmt.Errorf("failed to stop containers: %v", err)
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ func installCrowdsec(config Config) error {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := startContainers(); err != nil {
|
||||
if err := startContainers(config.InstallationContainerType); err != nil {
|
||||
return fmt.Errorf("failed to start containers: %v", err)
|
||||
}
|
||||
|
||||
// get API key
|
||||
apiKey, err := GetCrowdSecAPIKey()
|
||||
apiKey, err := GetCrowdSecAPIKey(config.InstallationContainerType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get API key: %v", err)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func installCrowdsec(config Config) error {
|
||||
return fmt.Errorf("failed to replace bouncer key: %v", err)
|
||||
}
|
||||
|
||||
if err := restartContainer("traefik"); err != nil {
|
||||
if err := restartContainer("traefik", config.InstallationContainerType); err != nil {
|
||||
return fmt.Errorf("failed to restart containers: %v", err)
|
||||
}
|
||||
|
||||
@@ -110,9 +110,9 @@ func checkIsCrowdsecInstalledInCompose() bool {
|
||||
return bytes.Contains(content, []byte("crowdsec:"))
|
||||
}
|
||||
|
||||
func GetCrowdSecAPIKey() (string, error) {
|
||||
func GetCrowdSecAPIKey(containerType SupportedContainer) (string, error) {
|
||||
// First, ensure the container is running
|
||||
if err := waitForContainer("crowdsec"); err != nil {
|
||||
if err := waitForContainer("crowdsec", containerType); err != nil {
|
||||
return "", fmt.Errorf("waiting for container: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module installer
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
golang.org/x/term v0.28.0
|
||||
golang.org/x/term v0.35.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.29.0 // indirect
|
||||
require golang.org/x/sys v0.36.0 // indirect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
74
install/input.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func readString(reader *bufio.Reader, prompt string, defaultValue string) string {
|
||||
if defaultValue != "" {
|
||||
fmt.Printf("%s (default: %s): ", prompt, defaultValue)
|
||||
} else {
|
||||
fmt.Print(prompt + ": ")
|
||||
}
|
||||
input, _ := reader.ReadString('\n')
|
||||
input = strings.TrimSpace(input)
|
||||
if input == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
func readStringNoDefault(reader *bufio.Reader, prompt string) string {
|
||||
fmt.Print(prompt + ": ")
|
||||
input, _ := reader.ReadString('\n')
|
||||
return strings.TrimSpace(input)
|
||||
}
|
||||
|
||||
func readPassword(prompt string, reader *bufio.Reader) string {
|
||||
if term.IsTerminal(int(syscall.Stdin)) {
|
||||
fmt.Print(prompt + ": ")
|
||||
// Read password without echo if we're in a terminal
|
||||
password, err := term.ReadPassword(int(syscall.Stdin))
|
||||
fmt.Println() // Add a newline since ReadPassword doesn't add one
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
input := strings.TrimSpace(string(password))
|
||||
if input == "" {
|
||||
return readPassword(prompt, reader)
|
||||
}
|
||||
return input
|
||||
} else {
|
||||
// Fallback to reading from stdin if not in a terminal
|
||||
return readString(reader, prompt, "")
|
||||
}
|
||||
}
|
||||
|
||||
func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool {
|
||||
defaultStr := "no"
|
||||
if defaultValue {
|
||||
defaultStr = "yes"
|
||||
}
|
||||
input := readString(reader, prompt+" (yes/no)", defaultStr)
|
||||
return strings.ToLower(input) == "yes"
|
||||
}
|
||||
|
||||
func readBoolNoDefault(reader *bufio.Reader, prompt string) bool {
|
||||
input := readStringNoDefault(reader, prompt+" (yes/no)")
|
||||
return strings.ToLower(input) == "yes"
|
||||
}
|
||||
|
||||
func readInt(reader *bufio.Reader, prompt string, defaultValue int) int {
|
||||
input := readString(reader, prompt, fmt.Sprintf("%d", defaultValue))
|
||||
if input == "" {
|
||||
return defaultValue
|
||||
}
|
||||
value := defaultValue
|
||||
fmt.Sscanf(input, "%d", &value)
|
||||
return value
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
docker
|
||||
example.com
|
||||
pangolin.example.com
|
||||
yes
|
||||
admin@example.com
|
||||
yes
|
||||
admin@example.com
|
||||
|
||||
843
install/main.go
@@ -7,67 +7,81 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"text/template"
|
||||
"time"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// DO NOT EDIT THIS FUNCTION; IT MATCHED BY REGEX IN CICD
|
||||
func loadVersions(config *Config) {
|
||||
config.PangolinVersion = "replaceme"
|
||||
config.GerbilVersion = "replaceme"
|
||||
config.BadgerVersion = "replaceme"
|
||||
config.PangolinVersion = "1.9.4"
|
||||
config.GerbilVersion = "1.2.1"
|
||||
config.BadgerVersion = "1.2.0"
|
||||
}
|
||||
|
||||
//go:embed config/*
|
||||
var configFiles embed.FS
|
||||
|
||||
type Config struct {
|
||||
PangolinVersion string
|
||||
GerbilVersion string
|
||||
BadgerVersion string
|
||||
BaseDomain string
|
||||
DashboardDomain string
|
||||
LetsEncryptEmail string
|
||||
EnableEmail bool
|
||||
EmailSMTPHost string
|
||||
EmailSMTPPort int
|
||||
EmailSMTPUser string
|
||||
EmailSMTPPass string
|
||||
EmailNoReply string
|
||||
InstallGerbil bool
|
||||
TraefikBouncerKey string
|
||||
DoCrowdsecInstall bool
|
||||
Secret string
|
||||
InstallationContainerType SupportedContainer
|
||||
PangolinVersion string
|
||||
GerbilVersion string
|
||||
BadgerVersion string
|
||||
BaseDomain string
|
||||
DashboardDomain string
|
||||
EnableIPv6 bool
|
||||
LetsEncryptEmail string
|
||||
EnableEmail bool
|
||||
EmailSMTPHost string
|
||||
EmailSMTPPort int
|
||||
EmailSMTPUser string
|
||||
EmailSMTPPass string
|
||||
EmailNoReply string
|
||||
InstallGerbil bool
|
||||
TraefikBouncerKey string
|
||||
DoCrowdsecInstall bool
|
||||
Secret string
|
||||
HybridMode bool
|
||||
HybridId string
|
||||
HybridSecret string
|
||||
}
|
||||
|
||||
func main() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
type SupportedContainer string
|
||||
|
||||
// check if docker is not installed and the user is root
|
||||
if !isDockerInstalled() {
|
||||
if os.Geteuid() != 0 {
|
||||
fmt.Println("Docker is not installed. Please install Docker manually or run this installer as root.")
|
||||
os.Exit(1)
|
||||
const (
|
||||
Docker SupportedContainer = "docker"
|
||||
Podman SupportedContainer = "podman"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// print a banner about prerequisites - opening port 80, 443, 51820, and 21820 on the VPS and firewall and pointing your domain to the VPS IP with a records. Docs are at http://localhost:3000/Getting%20Started/dns-networking
|
||||
|
||||
fmt.Println("Welcome to the Pangolin installer!")
|
||||
fmt.Println("This installer will help you set up Pangolin on your server.")
|
||||
fmt.Println("\nPlease make sure you have the following prerequisites:")
|
||||
fmt.Println("- Open TCP ports 80 and 443 and UDP ports 51820 and 21820 on your VPS and firewall.")
|
||||
fmt.Println("\nLets get started!")
|
||||
|
||||
if os.Geteuid() == 0 { // WE NEED TO BE SUDO TO CHECK THIS
|
||||
for _, p := range []int{80, 443} {
|
||||
if err := checkPortsAvailable(p); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
fmt.Printf("Please close any services on ports 80/443 in order to run the installation smoothly. If you already have the Pangolin stack running, shut them down before proceeding.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the user is in the docker group (linux only)
|
||||
if !isUserInDockerGroup() {
|
||||
fmt.Println("You are not in the docker group.")
|
||||
fmt.Println("The installer will not be able to run docker commands without running it as root.")
|
||||
os.Exit(1)
|
||||
}
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
var config Config
|
||||
|
||||
@@ -79,6 +93,26 @@ func main() {
|
||||
config.DoCrowdsecInstall = false
|
||||
config.Secret = generateRandomSecretKey()
|
||||
|
||||
fmt.Println("\n=== Generating Configuration Files ===")
|
||||
|
||||
// If the secret and id are not generated then generate them
|
||||
if config.HybridMode && (config.HybridId == "" || config.HybridSecret == "") {
|
||||
// fmt.Println("Requesting hybrid credentials from cloud...")
|
||||
credentials, err := requestHybridCredentials()
|
||||
if err != nil {
|
||||
fmt.Printf("Error requesting hybrid credentials: %v\n", err)
|
||||
fmt.Println("Please obtain credentials manually from the dashboard and run the installer again.")
|
||||
os.Exit(1)
|
||||
}
|
||||
config.HybridId = credentials.RemoteExitNodeId
|
||||
config.HybridSecret = credentials.Secret
|
||||
fmt.Printf("Your managed credentials have been obtained successfully.\n")
|
||||
fmt.Printf(" ID: %s\n", config.HybridId)
|
||||
fmt.Printf(" Secret: %s\n", config.HybridSecret)
|
||||
fmt.Println("Take these to the Pangolin dashboard https://pangolin.fossorial.io to adopt your node.")
|
||||
readBool(reader, "Have you adopted your node?", true)
|
||||
}
|
||||
|
||||
if err := createConfigFiles(config); err != nil {
|
||||
fmt.Printf("Error creating config files: %v\n", err)
|
||||
os.Exit(1)
|
||||
@@ -86,65 +120,77 @@ func main() {
|
||||
|
||||
moveFile("config/docker-compose.yml", "docker-compose.yml")
|
||||
|
||||
if !isDockerInstalled() && runtime.GOOS == "linux" {
|
||||
if readBool(reader, "Docker is not installed. Would you like to install it?", true) {
|
||||
installDocker()
|
||||
// try to start docker service but ignore errors
|
||||
if err := startDockerService(); err != nil {
|
||||
fmt.Println("Error starting Docker service:", err)
|
||||
} else {
|
||||
fmt.Println("Docker service started successfully!")
|
||||
}
|
||||
// wait 10 seconds for docker to start checking if docker is running every 2 seconds
|
||||
fmt.Println("Waiting for Docker to start...")
|
||||
for i := 0; i < 5; i++ {
|
||||
if isDockerRunning() {
|
||||
fmt.Println("Docker is running!")
|
||||
break
|
||||
}
|
||||
fmt.Println("Docker is not running yet, waiting...")
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
if !isDockerRunning() {
|
||||
fmt.Println("Docker is still not running after 10 seconds. Please check the installation.")
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Docker installed successfully!")
|
||||
}
|
||||
}
|
||||
fmt.Println("\nConfiguration files created successfully!")
|
||||
|
||||
fmt.Println("\n=== Starting installation ===")
|
||||
|
||||
if isDockerInstalled() {
|
||||
if readBool(reader, "Would you like to install and start the containers?", true) {
|
||||
if err := pullContainers(); err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
return
|
||||
}
|
||||
if readBool(reader, "Would you like to install and start the containers?", true) {
|
||||
|
||||
if err := startContainers(); err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
return
|
||||
config.InstallationContainerType = podmanOrDocker(reader)
|
||||
|
||||
if !isDockerInstalled() && runtime.GOOS == "linux" && config.InstallationContainerType == Docker {
|
||||
if readBool(reader, "Docker is not installed. Would you like to install it?", true) {
|
||||
installDocker()
|
||||
// try to start docker service but ignore errors
|
||||
if err := startDockerService(); err != nil {
|
||||
fmt.Println("Error starting Docker service:", err)
|
||||
} else {
|
||||
fmt.Println("Docker service started successfully!")
|
||||
}
|
||||
// wait 10 seconds for docker to start checking if docker is running every 2 seconds
|
||||
fmt.Println("Waiting for Docker to start...")
|
||||
for i := 0; i < 5; i++ {
|
||||
if isDockerRunning() {
|
||||
fmt.Println("Docker is running!")
|
||||
break
|
||||
}
|
||||
fmt.Println("Docker is not running yet, waiting...")
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
if !isDockerRunning() {
|
||||
fmt.Println("Docker is still not running after 10 seconds. Please check the installation.")
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Docker installed successfully!")
|
||||
}
|
||||
}
|
||||
|
||||
if err := pullContainers(config.InstallationContainerType); err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := startContainers(config.InstallationContainerType); err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
fmt.Println("Looks like you already installed, so I am going to do the setup...")
|
||||
fmt.Println("Looks like you already installed Pangolin!")
|
||||
}
|
||||
|
||||
if !checkIsCrowdsecInstalledInCompose() {
|
||||
if !checkIsCrowdsecInstalledInCompose() && !checkIsPangolinInstalledWithHybrid() {
|
||||
fmt.Println("\n=== CrowdSec Install ===")
|
||||
// check if crowdsec is installed
|
||||
if readBool(reader, "Would you like to install CrowdSec?", false) {
|
||||
fmt.Println("This installer constitutes a minimal viable CrowdSec deployment. CrowdSec will add extra complexity to your Pangolin installation and may not work to the best of its abilities out of the box. Users are expected to implement configuration adjustments on their own to achieve the best security posture. Consult the CrowdSec documentation for detailed configuration instructions.")
|
||||
|
||||
// BUG: crowdsec installation will be skipped if the user chooses to install on the first installation.
|
||||
if readBool(reader, "Are you willing to manage CrowdSec?", false) {
|
||||
if config.DashboardDomain == "" {
|
||||
traefikConfig, err := ReadTraefikConfig("config/traefik/traefik_config.yml", "config/traefik/dynamic_config.yml")
|
||||
traefikConfig, err := ReadTraefikConfig("config/traefik/traefik_config.yml")
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading config: %v\n", err)
|
||||
return
|
||||
}
|
||||
config.DashboardDomain = traefikConfig.DashboardDomain
|
||||
appConfig, err := ReadAppConfig("config/config.yml")
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading config: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
config.DashboardDomain = appConfig.DashboardURL
|
||||
config.LetsEncryptEmail = traefikConfig.LetsEncryptEmail
|
||||
config.BadgerVersion = traefikConfig.BadgerVersion
|
||||
|
||||
@@ -159,67 +205,112 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
config.InstallationContainerType = podmanOrDocker(reader)
|
||||
|
||||
config.DoCrowdsecInstall = true
|
||||
installCrowdsec(config)
|
||||
err := installCrowdsec(config)
|
||||
if (err != nil) {
|
||||
fmt.Printf("Error installing CrowdSec: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("CrowdSec installed successfully!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Installation complete!")
|
||||
fmt.Printf("\nTo complete the initial setup, please visit:\nhttps://%s/auth/initial-setup\n", config.DashboardDomain)
|
||||
}
|
||||
if !config.HybridMode {
|
||||
// Setup Token Section
|
||||
fmt.Println("\n=== Setup Token ===")
|
||||
|
||||
func readString(reader *bufio.Reader, prompt string, defaultValue string) string {
|
||||
if defaultValue != "" {
|
||||
fmt.Printf("%s (default: %s): ", prompt, defaultValue)
|
||||
} else {
|
||||
fmt.Print(prompt + ": ")
|
||||
}
|
||||
input, _ := reader.ReadString('\n')
|
||||
input = strings.TrimSpace(input)
|
||||
if input == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
func readPassword(prompt string, reader *bufio.Reader) string {
|
||||
if term.IsTerminal(int(syscall.Stdin)) {
|
||||
fmt.Print(prompt + ": ")
|
||||
// Read password without echo if we're in a terminal
|
||||
password, err := term.ReadPassword(int(syscall.Stdin))
|
||||
fmt.Println() // Add a newline since ReadPassword doesn't add one
|
||||
if err != nil {
|
||||
return ""
|
||||
// Check if containers were started during this installation
|
||||
containersStarted := false
|
||||
if (isDockerInstalled() && config.InstallationContainerType == Docker) ||
|
||||
(isPodmanInstalled() && config.InstallationContainerType == Podman) {
|
||||
// Try to fetch and display the token if containers are running
|
||||
containersStarted = true
|
||||
printSetupToken(config.InstallationContainerType, config.DashboardDomain)
|
||||
}
|
||||
input := strings.TrimSpace(string(password))
|
||||
if input == "" {
|
||||
return readPassword(prompt, reader)
|
||||
|
||||
// If containers weren't started or token wasn't found, show instructions
|
||||
if !containersStarted {
|
||||
showSetupTokenInstructions(config.InstallationContainerType, config.DashboardDomain)
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
fmt.Println("\nInstallation complete!")
|
||||
|
||||
if !config.HybridMode && !checkIsPangolinInstalledWithHybrid() {
|
||||
fmt.Printf("\nTo complete the initial setup, please visit:\nhttps://%s/auth/initial-setup\n", config.DashboardDomain)
|
||||
}
|
||||
}
|
||||
|
||||
func podmanOrDocker(reader *bufio.Reader) SupportedContainer {
|
||||
inputContainer := readString(reader, "Would you like to run Pangolin as Docker or Podman containers?", "docker")
|
||||
|
||||
chosenContainer := Docker
|
||||
if strings.EqualFold(inputContainer, "docker") {
|
||||
chosenContainer = Docker
|
||||
} else if strings.EqualFold(inputContainer, "podman") {
|
||||
chosenContainer = Podman
|
||||
} else {
|
||||
// Fallback to reading from stdin if not in a terminal
|
||||
return readString(reader, prompt, "")
|
||||
fmt.Printf("Unrecognized container type: %s. Valid options are 'docker' or 'podman'.\n", inputContainer)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool {
|
||||
defaultStr := "no"
|
||||
if defaultValue {
|
||||
defaultStr = "yes"
|
||||
}
|
||||
input := readString(reader, prompt+" (yes/no)", defaultStr)
|
||||
return strings.ToLower(input) == "yes"
|
||||
}
|
||||
if chosenContainer == Podman {
|
||||
if !isPodmanInstalled() {
|
||||
fmt.Println("Podman or podman-compose is not installed. Please install both manually. Automated installation will be available in a later release.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func readInt(reader *bufio.Reader, prompt string, defaultValue int) int {
|
||||
input := readString(reader, prompt, fmt.Sprintf("%d", defaultValue))
|
||||
if input == "" {
|
||||
return defaultValue
|
||||
if err := exec.Command("bash", "-c", "cat /etc/sysctl.conf | grep 'net.ipv4.ip_unprivileged_port_start='").Run(); err != nil {
|
||||
fmt.Println("Would you like to configure ports >= 80 as unprivileged ports? This enables podman containers to listen on low-range ports.")
|
||||
fmt.Println("Pangolin will experience startup issues if this is not configured, because it needs to listen on port 80/443 by default.")
|
||||
approved := readBool(reader, "The installer is about to execute \"echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf && sysctl -p\". Approve?", true)
|
||||
if approved {
|
||||
if os.Geteuid() != 0 {
|
||||
fmt.Println("You need to run the installer as root for such a configuration.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Podman containers are not able to listen on privileged ports. The official recommendation is to
|
||||
// container low-range ports as unprivileged ports.
|
||||
// Linux only.
|
||||
|
||||
if err := run("bash", "-c", "echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf && sysctl -p"); err != nil {
|
||||
fmt.Sprintf("failed to configure unprivileged ports: %v.\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
fmt.Println("You need to configure port forwarding or adjust the listening ports before running pangolin.")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Unprivileged ports have been configured.")
|
||||
}
|
||||
|
||||
} else if chosenContainer == Docker {
|
||||
// check if docker is not installed and the user is root
|
||||
if !isDockerInstalled() {
|
||||
if os.Geteuid() != 0 {
|
||||
fmt.Println("Docker is not installed. Please install Docker manually or run this installer as root.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// check if the user is in the docker group (linux only)
|
||||
if !isUserInDockerGroup() {
|
||||
fmt.Println("You are not in the docker group.")
|
||||
fmt.Println("The installer will not be able to run docker commands without running it as root.")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
// This shouldn't happen unless there's a third container runtime.
|
||||
os.Exit(1)
|
||||
}
|
||||
value := defaultValue
|
||||
fmt.Sscanf(input, "%d", &value)
|
||||
return value
|
||||
|
||||
return chosenContainer
|
||||
}
|
||||
|
||||
func collectUserInput(reader *bufio.Reader) Config {
|
||||
@@ -227,36 +318,78 @@ func collectUserInput(reader *bufio.Reader) Config {
|
||||
|
||||
// Basic configuration
|
||||
fmt.Println("\n=== Basic Configuration ===")
|
||||
config.BaseDomain = readString(reader, "Enter your base domain (no subdomain e.g. example.com)", "")
|
||||
config.DashboardDomain = readString(reader, "Enter the domain for the Pangolin dashboard", "pangolin."+config.BaseDomain)
|
||||
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
|
||||
config.InstallGerbil = readBool(reader, "Do you want to use Gerbil to allow tunneled connections", true)
|
||||
|
||||
// Email configuration
|
||||
fmt.Println("\n=== Email Configuration ===")
|
||||
config.EnableEmail = readBool(reader, "Enable email functionality (SMTP)", false)
|
||||
|
||||
if config.EnableEmail {
|
||||
config.EmailSMTPHost = readString(reader, "Enter SMTP host", "")
|
||||
config.EmailSMTPPort = readInt(reader, "Enter SMTP port (default 587)", 587)
|
||||
config.EmailSMTPUser = readString(reader, "Enter SMTP username", "")
|
||||
config.EmailSMTPPass = readString(reader, "Enter SMTP password", "")
|
||||
config.EmailNoReply = readString(reader, "Enter no-reply email address", "")
|
||||
for {
|
||||
response := readString(reader, "Do you want to install Pangolin as a cloud-managed (beta) node? (yes/no)", "")
|
||||
if strings.EqualFold(response, "yes") || strings.EqualFold(response, "y") {
|
||||
config.HybridMode = true
|
||||
break
|
||||
} else if strings.EqualFold(response, "no") || strings.EqualFold(response, "n") {
|
||||
config.HybridMode = false
|
||||
break
|
||||
}
|
||||
fmt.Println("Please answer 'yes' or 'no'")
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if config.BaseDomain == "" {
|
||||
fmt.Println("Error: Domain name is required")
|
||||
os.Exit(1)
|
||||
if config.HybridMode {
|
||||
alreadyHaveCreds := readBool(reader, "Do you already have credentials from the dashboard? If not, we will create them later", false)
|
||||
|
||||
if alreadyHaveCreds {
|
||||
config.HybridId = readString(reader, "Enter your ID", "")
|
||||
config.HybridSecret = readString(reader, "Enter your secret", "")
|
||||
}
|
||||
|
||||
// Try to get public IP as default
|
||||
publicIP := getPublicIP()
|
||||
if publicIP != "" {
|
||||
fmt.Printf("Detected public IP: %s\n", publicIP)
|
||||
}
|
||||
config.DashboardDomain = readString(reader, "The public addressable IP address for this node or a domain pointing to it", publicIP)
|
||||
config.InstallGerbil = true
|
||||
} else {
|
||||
config.BaseDomain = readString(reader, "Enter your base domain (no subdomain e.g. example.com)", "")
|
||||
|
||||
// Set default dashboard domain after base domain is collected
|
||||
defaultDashboardDomain := ""
|
||||
if config.BaseDomain != "" {
|
||||
defaultDashboardDomain = "pangolin." + config.BaseDomain
|
||||
}
|
||||
config.DashboardDomain = readString(reader, "Enter the domain for the Pangolin dashboard", defaultDashboardDomain)
|
||||
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
|
||||
config.InstallGerbil = readBool(reader, "Do you want to use Gerbil to allow tunneled connections", true)
|
||||
|
||||
// Email configuration
|
||||
fmt.Println("\n=== Email Configuration ===")
|
||||
config.EnableEmail = readBool(reader, "Enable email functionality (SMTP)", false)
|
||||
|
||||
if config.EnableEmail {
|
||||
config.EmailSMTPHost = readString(reader, "Enter SMTP host", "")
|
||||
config.EmailSMTPPort = readInt(reader, "Enter SMTP port (default 587)", 587)
|
||||
config.EmailSMTPUser = readString(reader, "Enter SMTP username", "")
|
||||
config.EmailSMTPPass = readString(reader, "Enter SMTP password", "") // Should this be readPassword?
|
||||
config.EmailNoReply = readString(reader, "Enter no-reply email address", "")
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if config.BaseDomain == "" {
|
||||
fmt.Println("Error: Domain name is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
if config.LetsEncryptEmail == "" {
|
||||
fmt.Println("Error: Let's Encrypt email is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Advanced configuration
|
||||
|
||||
fmt.Println("\n=== Advanced Configuration ===")
|
||||
|
||||
config.EnableIPv6 = readBool(reader, "Is your server IPv6 capable?", true)
|
||||
|
||||
if config.DashboardDomain == "" {
|
||||
fmt.Println("Error: Dashboard Domain name is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
if config.LetsEncryptEmail == "" {
|
||||
fmt.Println("Error: Let's Encrypt email is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
@@ -286,6 +419,11 @@ func createConfigFiles(config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// the hybrid does not need the dynamic config
|
||||
if config.HybridMode && strings.Contains(path, "dynamic_config.yml") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// skip .DS_Store
|
||||
if strings.Contains(path, ".DS_Store") {
|
||||
return nil
|
||||
@@ -330,7 +468,6 @@ func createConfigFiles(config Config) error {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error walking config files: %v", err)
|
||||
}
|
||||
@@ -338,243 +475,6 @@ func createConfigFiles(config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func installDocker() error {
|
||||
// Detect Linux distribution
|
||||
cmd := exec.Command("cat", "/etc/os-release")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to detect Linux distribution: %v", err)
|
||||
}
|
||||
osRelease := string(output)
|
||||
|
||||
// Detect system architecture
|
||||
archCmd := exec.Command("uname", "-m")
|
||||
archOutput, err := archCmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to detect system architecture: %v", err)
|
||||
}
|
||||
arch := strings.TrimSpace(string(archOutput))
|
||||
|
||||
// Map architecture to Docker's architecture naming
|
||||
var dockerArch string
|
||||
switch arch {
|
||||
case "x86_64":
|
||||
dockerArch = "amd64"
|
||||
case "aarch64":
|
||||
dockerArch = "arm64"
|
||||
default:
|
||||
return fmt.Errorf("unsupported architecture: %s", arch)
|
||||
}
|
||||
|
||||
var installCmd *exec.Cmd
|
||||
switch {
|
||||
case strings.Contains(osRelease, "ID=ubuntu"):
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
apt-get update &&
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg &&
|
||||
echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list &&
|
||||
apt-get update &&
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, dockerArch))
|
||||
case strings.Contains(osRelease, "ID=debian"):
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
apt-get update &&
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg &&
|
||||
echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list &&
|
||||
apt-get update &&
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, dockerArch))
|
||||
case strings.Contains(osRelease, "ID=fedora"):
|
||||
// Detect Fedora version to handle DNF 5 changes
|
||||
versionCmd := exec.Command("bash", "-c", "grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '\"'")
|
||||
versionOutput, err := versionCmd.Output()
|
||||
var fedoraVersion int
|
||||
if err == nil {
|
||||
if v, parseErr := strconv.Atoi(strings.TrimSpace(string(versionOutput))); parseErr == nil {
|
||||
fedoraVersion = v
|
||||
}
|
||||
}
|
||||
|
||||
// Use appropriate DNF syntax based on version
|
||||
var repoCmd string
|
||||
if fedoraVersion >= 41 {
|
||||
// DNF 5 syntax for Fedora 41+
|
||||
repoCmd = "dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo"
|
||||
} else {
|
||||
// DNF 4 syntax for Fedora < 41
|
||||
repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo"
|
||||
}
|
||||
|
||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||
dnf -y install dnf-plugins-core &&
|
||||
%s &&
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`, repoCmd))
|
||||
case strings.Contains(osRelease, "ID=opensuse") || strings.Contains(osRelease, "ID=\"opensuse-"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
zypper install -y docker docker-compose &&
|
||||
systemctl enable docker
|
||||
`)
|
||||
case strings.Contains(osRelease, "ID=rhel") || strings.Contains(osRelease, "ID=\"rhel"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
dnf remove -y runc &&
|
||||
dnf -y install yum-utils &&
|
||||
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo &&
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin &&
|
||||
systemctl enable docker
|
||||
`)
|
||||
case strings.Contains(osRelease, "ID=amzn"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
yum update -y &&
|
||||
yum install -y docker &&
|
||||
systemctl enable docker &&
|
||||
usermod -a -G docker ec2-user
|
||||
`)
|
||||
default:
|
||||
return fmt.Errorf("unsupported Linux distribution")
|
||||
}
|
||||
|
||||
installCmd.Stdout = os.Stdout
|
||||
installCmd.Stderr = os.Stderr
|
||||
return installCmd.Run()
|
||||
}
|
||||
|
||||
func startDockerService() error {
|
||||
if runtime.GOOS == "linux" {
|
||||
cmd := exec.Command("systemctl", "enable", "--now", "docker")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
// On macOS, Docker is usually started via the Docker Desktop application
|
||||
fmt.Println("Please start Docker Desktop manually on macOS.")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unsupported operating system for starting Docker service")
|
||||
}
|
||||
|
||||
func isDockerInstalled() bool {
|
||||
cmd := exec.Command("docker", "--version")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isUserInDockerGroup() bool {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Docker group is not applicable on macOS
|
||||
// So we assume that the user can run Docker commands
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Geteuid() == 0 {
|
||||
return true // Root user can run Docker commands anyway
|
||||
}
|
||||
|
||||
// Check if the current user is in the docker group
|
||||
if dockerGroup, err := user.LookupGroup("docker"); err == nil {
|
||||
if currentUser, err := user.Current(); err == nil {
|
||||
if currentUserGroupIds, err := currentUser.GroupIds(); err == nil {
|
||||
for _, groupId := range currentUserGroupIds {
|
||||
if groupId == dockerGroup.Gid {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eventually, if any of the checks fail, we assume the user cannot run Docker commands
|
||||
return false
|
||||
}
|
||||
|
||||
// isDockerRunning checks if the Docker daemon is running by using the `docker info` command.
|
||||
func isDockerRunning() bool {
|
||||
cmd := exec.Command("docker", "info")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied
|
||||
func executeDockerComposeCommandWithArgs(args ...string) error {
|
||||
var cmd *exec.Cmd
|
||||
var useNewStyle bool
|
||||
|
||||
if !isDockerInstalled() {
|
||||
return fmt.Errorf("docker is not installed")
|
||||
}
|
||||
|
||||
checkCmd := exec.Command("docker", "compose", "version")
|
||||
if err := checkCmd.Run(); err == nil {
|
||||
useNewStyle = true
|
||||
} else {
|
||||
checkCmd = exec.Command("docker-compose", "version")
|
||||
if err := checkCmd.Run(); err == nil {
|
||||
useNewStyle = false
|
||||
} else {
|
||||
return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available")
|
||||
}
|
||||
}
|
||||
|
||||
if useNewStyle {
|
||||
cmd = exec.Command("docker", append([]string{"compose"}, args...)...)
|
||||
} else {
|
||||
cmd = exec.Command("docker-compose", args...)
|
||||
}
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// pullContainers pulls the containers using the appropriate command.
|
||||
func pullContainers() error {
|
||||
fmt.Println("Pulling the container images...")
|
||||
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "pull", "--policy", "always"); err != nil {
|
||||
return fmt.Errorf("failed to pull the containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// startContainers starts the containers using the appropriate command.
|
||||
func startContainers() error {
|
||||
fmt.Println("Starting containers...")
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil {
|
||||
return fmt.Errorf("failed to start containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopContainers stops the containers using the appropriate command.
|
||||
func stopContainers() error {
|
||||
fmt.Println("Stopping containers...")
|
||||
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil {
|
||||
return fmt.Errorf("failed to stop containers: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// restartContainer restarts a specific container using the appropriate command.
|
||||
func restartContainer(container string) error {
|
||||
fmt.Println("Restarting containers...")
|
||||
|
||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil {
|
||||
return fmt.Errorf("failed to stop the container \"%s\": %v", container, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
@@ -600,32 +500,89 @@ func moveFile(src, dst string) error {
|
||||
return os.Remove(src)
|
||||
}
|
||||
|
||||
func waitForContainer(containerName string) error {
|
||||
maxAttempts := 30
|
||||
retryInterval := time.Second * 2
|
||||
func printSetupToken(containerType SupportedContainer, dashboardDomain string) {
|
||||
fmt.Println("Waiting for Pangolin to generate setup token...")
|
||||
|
||||
for attempt := 0; attempt < maxAttempts; attempt++ {
|
||||
// Check if container is running
|
||||
cmd := exec.Command("docker", "container", "inspect", "-f", "{{.State.Running}}", containerName)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
// If the container doesn't exist or there's another error, wait and retry
|
||||
time.Sleep(retryInterval)
|
||||
continue
|
||||
}
|
||||
|
||||
isRunning := strings.TrimSpace(out.String()) == "true"
|
||||
if isRunning {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container exists but isn't running yet, wait and retry
|
||||
time.Sleep(retryInterval)
|
||||
// Wait for Pangolin to be healthy
|
||||
if err := waitForContainer("pangolin", containerType); err != nil {
|
||||
fmt.Println("Warning: Pangolin container did not become healthy in time.")
|
||||
return
|
||||
}
|
||||
|
||||
return fmt.Errorf("container %s did not start within %v seconds", containerName, maxAttempts*int(retryInterval.Seconds()))
|
||||
// Give a moment for the setup token to be generated
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Fetch logs
|
||||
var cmd *exec.Cmd
|
||||
if containerType == Docker {
|
||||
cmd = exec.Command("docker", "logs", "pangolin")
|
||||
} else {
|
||||
cmd = exec.Command("podman", "logs", "pangolin")
|
||||
}
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Println("Warning: Could not fetch Pangolin logs to find setup token.")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse for setup token
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for i, line := range lines {
|
||||
if strings.Contains(line, "=== SETUP TOKEN GENERATED ===") || strings.Contains(line, "=== SETUP TOKEN EXISTS ===") {
|
||||
// Look for "Token: ..." in the next few lines
|
||||
for j := i + 1; j < i+5 && j < len(lines); j++ {
|
||||
trimmedLine := strings.TrimSpace(lines[j])
|
||||
if strings.Contains(trimmedLine, "Token:") {
|
||||
// Extract token after "Token:"
|
||||
tokenStart := strings.Index(trimmedLine, "Token:")
|
||||
if tokenStart != -1 {
|
||||
token := strings.TrimSpace(trimmedLine[tokenStart+6:])
|
||||
fmt.Printf("Setup token: %s\n", token)
|
||||
fmt.Println("")
|
||||
fmt.Println("This token is required to register the first admin account in the web UI at:")
|
||||
fmt.Printf("https://%s/auth/initial-setup\n", dashboardDomain)
|
||||
fmt.Println("")
|
||||
fmt.Println("Save this token securely. It will be invalid after the first admin is created.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("Warning: Could not find a setup token in Pangolin logs.")
|
||||
}
|
||||
|
||||
func showSetupTokenInstructions(containerType SupportedContainer, dashboardDomain string) {
|
||||
fmt.Println("\n=== Setup Token Instructions ===")
|
||||
fmt.Println("To get your setup token, you need to:")
|
||||
fmt.Println("")
|
||||
fmt.Println("1. Start the containers:")
|
||||
if containerType == Docker {
|
||||
fmt.Println(" docker-compose up -d")
|
||||
} else {
|
||||
fmt.Println(" podman-compose up -d")
|
||||
}
|
||||
fmt.Println("")
|
||||
fmt.Println("2. Wait for the Pangolin container to start and generate the token")
|
||||
fmt.Println("")
|
||||
fmt.Println("3. Check the container logs for the setup token:")
|
||||
if containerType == Docker {
|
||||
fmt.Println(" docker logs pangolin | grep -A 2 -B 2 'SETUP TOKEN'")
|
||||
} else {
|
||||
fmt.Println(" podman logs pangolin | grep -A 2 -B 2 'SETUP TOKEN'")
|
||||
}
|
||||
fmt.Println("")
|
||||
fmt.Println("4. Look for output like:")
|
||||
fmt.Println(" === SETUP TOKEN GENERATED ===")
|
||||
fmt.Println(" Token: [your-token-here]")
|
||||
fmt.Println(" Use this token on the initial setup page")
|
||||
fmt.Println("")
|
||||
fmt.Println("5. Use the token to complete initial setup at:")
|
||||
fmt.Printf(" https://%s/auth/initial-setup\n", dashboardDomain)
|
||||
fmt.Println("")
|
||||
fmt.Println("The setup token is required to register the first admin account.")
|
||||
fmt.Println("Save it securely - it will be invalid after the first admin is created.")
|
||||
fmt.Println("================================")
|
||||
}
|
||||
|
||||
func generateRandomSecretKey() string {
|
||||
@@ -641,3 +598,71 @@ func generateRandomSecretKey() string {
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func getPublicIP() string {
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Get("https://ifconfig.io/ip")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ip := strings.TrimSpace(string(body))
|
||||
|
||||
// Validate that it's a valid IP address
|
||||
if net.ParseIP(ip) != nil {
|
||||
return ip
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Run external commands with stdio/stderr attached.
|
||||
func run(name string, args ...string) error {
|
||||
cmd := exec.Command(name, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func checkPortsAvailable(port int) error {
|
||||
addr := fmt.Sprintf(":%d", port)
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"ERROR: port %d is occupied or cannot be bound: %w\n\n",
|
||||
port, err,
|
||||
)
|
||||
}
|
||||
if closeErr := ln.Close(); closeErr != nil {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"WARNING: failed to close test listener on port %d: %v\n",
|
||||
port, closeErr,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkIsPangolinInstalledWithHybrid() bool {
|
||||
// Check if config/config.yml exists and contains hybrid section
|
||||
if _, err := os.Stat("config/config.yml"); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Read config file to check for hybrid section
|
||||
content, err := os.ReadFile("config/config.yml")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for hybrid section
|
||||
return bytes.Contains(content, []byte("managed:"))
|
||||
}
|
||||
|
||||
110
install/quickStart.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
FRONTEND_SECRET_KEY = "af4e4785-7e09-11f0-b93a-74563c4e2a7e"
|
||||
// CLOUD_API_URL = "https://pangolin.fossorial.io/api/v1/remote-exit-node/quick-start"
|
||||
CLOUD_API_URL = "https://pangolin.fossorial.io/api/v1/remote-exit-node/quick-start"
|
||||
)
|
||||
|
||||
// HybridCredentials represents the response from the cloud API
|
||||
type HybridCredentials struct {
|
||||
RemoteExitNodeId string `json:"remoteExitNodeId"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
// APIResponse represents the full response structure from the cloud API
|
||||
type APIResponse struct {
|
||||
Data HybridCredentials `json:"data"`
|
||||
}
|
||||
|
||||
// RequestPayload represents the request body structure
|
||||
type RequestPayload struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func generateValidationToken() string {
|
||||
timestamp := time.Now().UnixMilli()
|
||||
data := fmt.Sprintf("%s|%d", FRONTEND_SECRET_KEY, timestamp)
|
||||
obfuscated := make([]byte, len(data))
|
||||
for i, char := range []byte(data) {
|
||||
obfuscated[i] = char + 5
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(obfuscated)
|
||||
}
|
||||
|
||||
// requestHybridCredentials makes an HTTP POST request to the cloud API
|
||||
// to get hybrid credentials (ID and secret)
|
||||
func requestHybridCredentials() (*HybridCredentials, error) {
|
||||
// Generate validation token
|
||||
token := generateValidationToken()
|
||||
|
||||
// Create request payload
|
||||
payload := RequestPayload{
|
||||
Token: token,
|
||||
}
|
||||
|
||||
// Marshal payload to JSON
|
||||
jsonData, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request payload: %v", err)
|
||||
}
|
||||
|
||||
// Create HTTP request
|
||||
req, err := http.NewRequest("POST", CLOUD_API_URL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HTTP request: %v", err)
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-CSRF-Token", "x-csrf-protection")
|
||||
|
||||
// Create HTTP client with timeout
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
// Make the request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make HTTP request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check response status
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Read response body for debugging
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body: %v", err)
|
||||
}
|
||||
|
||||
// Print the raw JSON response for debugging
|
||||
// fmt.Printf("Raw JSON response: %s\n", string(body))
|
||||
|
||||
// Parse response
|
||||
var apiResponse APIResponse
|
||||
if err := json.Unmarshal(body, &apiResponse); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode API response: %v", err)
|
||||
}
|
||||
|
||||
// Validate response data
|
||||
if apiResponse.Data.RemoteExitNodeId == "" || apiResponse.Data.Secret == "" {
|
||||
return nil, fmt.Errorf("invalid response: missing remoteExitNodeId or secret")
|
||||
}
|
||||
|
||||
return &apiResponse.Data, nil
|
||||
}
|
||||
1523
messages/bg-BG.json
Normal file
1523
messages/cs-CZ.json
Normal file
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"setupCreate": "Erstelle eine Organisation, Site und Ressourcen",
|
||||
"setupCreate": "Erstelle eine Organisation, einen Standort und Ressourcen",
|
||||
"setupNewOrg": "Neue Organisation",
|
||||
"setupCreateOrg": "Organisation erstellen",
|
||||
"setupCreateResources": "Ressource erstellen",
|
||||
@@ -11,11 +11,12 @@
|
||||
"componentsErrorNoMemberCreate": "Du bist derzeit kein Mitglied einer Organisation. Erstelle eine Organisation, um zu starten.",
|
||||
"componentsErrorNoMember": "Du bist aktuell kein Mitglied einer Organisation.",
|
||||
"welcome": "Willkommen zu Pangolin",
|
||||
"welcomeTo": "Willkommen bei",
|
||||
"componentsCreateOrg": "Erstelle eine Organisation",
|
||||
"componentsMember": "Du bist Mitglied von {count, plural, =0 {keiner Organisation} =1 {einer Organisation} other {# Organisationen}}.",
|
||||
"componentsMember": "Du bist Mitglied von {count, plural, =0 {keiner Organisation} one {einer Organisation} other {# Organisationen}}.",
|
||||
"componentsInvalidKey": "Ungültige oder abgelaufene Lizenzschlüssel erkannt. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"dismiss": "Verwerfen",
|
||||
"componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Sites, die das Lizenzlimit der {maxSites} Sites überschreiten. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Standorte, was das Lizenzlimit von {maxSites} Standorten überschreitet. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"componentsSupporterMessage": "Vielen Dank für die Unterstützung von Pangolin als {tier}!",
|
||||
"inviteErrorNotValid": "Es tut uns leid, aber es sieht so aus, als wäre die Einladung, auf die du zugreifen möchtest, entweder nicht angenommen worden oder nicht mehr gültig.",
|
||||
"inviteErrorUser": "Es tut uns leid, aber es scheint, als sei die Einladung, auf die du zugreifen möchtest, nicht für diesen Benutzer bestimmt.",
|
||||
@@ -37,28 +38,27 @@
|
||||
"name": "Name",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"site": "Seite",
|
||||
"site": "Standort",
|
||||
"dataIn": "Daten eingehend",
|
||||
"dataOut": "Daten ausgehend",
|
||||
"connectionType": "Verbindungstyp",
|
||||
"tunnelType": "Tunneltyp",
|
||||
"local": "Lokal",
|
||||
"edit": "Bearbeiten",
|
||||
"siteConfirmDelete": "Site löschen bestätigen",
|
||||
"siteDelete": "Site löschen",
|
||||
"siteMessageRemove": "Sobald diese Seite entfernt ist, wird sie nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit der Site verbunden sind, werden ebenfalls entfernt.",
|
||||
"siteMessageConfirm": "Um zu bestätigen, gib den Namen der Site ein.",
|
||||
"siteQuestionRemove": "Bist du sicher, dass Sie die Site {selectedSite} aus der Organisation entfernt werden soll?",
|
||||
"siteManageSites": "Sites verwalten",
|
||||
"siteConfirmDelete": "Standort löschen bestätigen",
|
||||
"siteDelete": "Standort löschen",
|
||||
"siteMessageRemove": "Sobald dieser Standort entfernt ist, wird er nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit diesem Standort verbunden sind, werden ebenfalls entfernt.",
|
||||
"siteMessageConfirm": "Um zu bestätigen, gib den Namen des Standortes unten ein.",
|
||||
"siteQuestionRemove": "Bist du sicher, dass der Standort {selectedSite} aus der Organisation entfernt werden soll?",
|
||||
"siteManageSites": "Standorte verwalten",
|
||||
"siteDescription": "Verbindung zum Netzwerk durch sichere Tunnel erlauben",
|
||||
"siteCreate": "Site erstellen",
|
||||
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um eine neue Site zu erstellen und zu verbinden",
|
||||
"siteCreateDescription": "Erstelle eine neue Site, um Ressourcen zu verbinden",
|
||||
"siteCreate": "Standort erstellen",
|
||||
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um einen neuen Standort zu erstellen und zu verbinden",
|
||||
"siteCreateDescription": "Erstelle einen neuen Standort, um Ressourcen zu verbinden",
|
||||
"close": "Schließen",
|
||||
"siteErrorCreate": "Fehler beim Erstellen der Site",
|
||||
"siteErrorCreate": "Fehler beim Erstellen des Standortes",
|
||||
"siteErrorCreateKeyPair": "Schlüsselpaar oder Standardwerte nicht gefunden",
|
||||
"siteErrorCreateDefaults": "Standardwerte der Site nicht gefunden",
|
||||
"siteNameDescription": "Dies ist der Anzeigename für die Site.",
|
||||
"method": "Methode",
|
||||
"siteMethodDescription": "So werden Verbindungen freigegeben.",
|
||||
"siteLearnNewt": "Wie du Newt auf deinem System installieren kannst",
|
||||
@@ -70,8 +70,8 @@
|
||||
"dockerRun": "Docker Run",
|
||||
"siteLearnLocal": "Mehr Infos zu lokalen Sites",
|
||||
"siteConfirmCopy": "Ich habe die Konfiguration kopiert",
|
||||
"searchSitesProgress": "Sites durchsuchen...",
|
||||
"siteAdd": "Site hinzufügen",
|
||||
"searchSitesProgress": "Standorte durchsuchen...",
|
||||
"siteAdd": "Standort hinzufügen",
|
||||
"siteInstallNewt": "Newt installieren",
|
||||
"siteInstallNewtDescription": "Installiere Newt auf deinem System.",
|
||||
"WgConfiguration": "WireGuard Konfiguration",
|
||||
@@ -82,26 +82,28 @@
|
||||
"siteNewtDescription": "Nutze Newt für die beste Benutzererfahrung. Newt verwendet WireGuard as Basis und erlaubt Ihnen, Ihre privaten Ressourcen über ihre LAN-Adresse in Ihrem privaten Netzwerk aus dem Pangolin-Dashboard heraus zu adressieren.",
|
||||
"siteRunsInDocker": "Läuft in Docker",
|
||||
"siteRunsInShell": "Läuft in der Konsole auf macOS, Linux und Windows",
|
||||
"siteErrorDelete": "Fehler beim Löschen der Site",
|
||||
"siteErrorUpdate": "Fehler beim Aktualisieren der Site",
|
||||
"siteErrorUpdateDescription": "Beim Aktualisieren der Site ist ein Fehler aufgetreten.",
|
||||
"siteUpdated": "Site aktualisiert",
|
||||
"siteUpdatedDescription": "Die Site wurde aktualisiert.",
|
||||
"siteGeneralDescription": "Allgemeine Einstellungen für diese Site konfigurieren",
|
||||
"siteSettingDescription": "Konfigurieren der Site Einstellungen",
|
||||
"siteErrorDelete": "Fehler beim Löschen des Standortes",
|
||||
"siteErrorUpdate": "Fehler beim Aktualisieren des Standortes",
|
||||
"siteErrorUpdateDescription": "Beim Aktualisieren des Standortes ist ein Fehler aufgetreten.",
|
||||
"siteUpdated": "Standort aktualisiert",
|
||||
"siteUpdatedDescription": "Der Standort wurde aktualisiert.",
|
||||
"siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren",
|
||||
"siteSettingDescription": "Konfigurieren der Standort Einstellungen",
|
||||
"siteSetting": "{siteName} Einstellungen",
|
||||
"siteNewtTunnel": "Newt-Tunnel (empfohlen)",
|
||||
"siteNewtTunnelDescription": "Einfachster Weg, einen Zugriffspunkt zu deinem Netzwerk zu erstellen. Keine zusätzliche Einrichtung erforderlich.",
|
||||
"siteWg": "Einfacher WireGuard Tunnel",
|
||||
"siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.",
|
||||
"siteWgDescriptionSaas": "Verwenden Sie jeden WireGuard-Client, um einen Tunnel zu erstellen. Manuelles NAT-Setup erforderlich. FUNKTIONIERT NUR BEI SELBSTGEHOSTETEN KNOTEN",
|
||||
"siteLocalDescription": "Nur lokale Ressourcen. Kein Tunneling.",
|
||||
"siteSeeAll": "Alle Sites anzeigen",
|
||||
"siteTunnelDescription": "Lege fest, wie du dich mit deiner Site verbinden möchtest",
|
||||
"siteLocalDescriptionSaas": "Nur lokale Ressourcen. Keine Tunneldurchführung. FUNKTIONIERT NUR BEI SELBSTGEHOSTETEN KNOTEN",
|
||||
"siteSeeAll": "Alle Standorte anzeigen",
|
||||
"siteTunnelDescription": "Lege fest, wie du dich mit deinem Standort verbinden möchtest",
|
||||
"siteNewtCredentials": "Neue Newt Zugangsdaten",
|
||||
"siteNewtCredentialsDescription": "So wird sich Newt mit dem Server authentifizieren",
|
||||
"siteCredentialsSave": "Ihre Zugangsdaten speichern",
|
||||
"siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.",
|
||||
"siteInfo": "Site-Informationen",
|
||||
"siteInfo": "Standort-Informationen",
|
||||
"status": "Status",
|
||||
"shareTitle": "Links zum Teilen verwalten",
|
||||
"shareDescription": "Erstellen Sie teilbare Links, um temporären oder permanenten Zugriff auf Ihre Ressourcen zu gewähren",
|
||||
@@ -163,10 +165,10 @@
|
||||
"resourceSeeAll": "Alle Ressourcen anzeigen",
|
||||
"resourceInfo": "Ressourcen-Informationen",
|
||||
"resourceNameDescription": "Dies ist der Anzeigename für die Ressource.",
|
||||
"siteSelect": "Site auswählen",
|
||||
"siteSearch": "Website durchsuchen",
|
||||
"siteNotFound": "Keine Site gefunden.",
|
||||
"siteSelectionDescription": "Diese Seite wird die Verbindung zu der Ressource herstellen.",
|
||||
"siteSelect": "Standort auswählen",
|
||||
"siteSearch": "Standorte durchsuchen",
|
||||
"siteNotFound": "Keinen Standort gefunden.",
|
||||
"siteSelectionDescription": "Dieser Standort wird die Verbindung zum Ziel herstellen.",
|
||||
"resourceType": "Ressourcentyp",
|
||||
"resourceTypeDescription": "Legen Sie fest, wie Sie auf Ihre Ressource zugreifen möchten",
|
||||
"resourceHTTPSSettings": "HTTPS-Einstellungen",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Allgemein",
|
||||
"generalSettings": "Allgemeine Einstellungen",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Intern",
|
||||
"rules": "Regeln",
|
||||
"resourceSettingDescription": "Konfigurieren Sie die Einstellungen Ihrer Ressource",
|
||||
"resourceSetting": "{resourceName} Einstellungen",
|
||||
"alwaysAllow": "Immer erlauben",
|
||||
"alwaysDeny": "Immer ablehnen",
|
||||
"passToAuth": "Weiterleiten zur Authentifizierung",
|
||||
"orgSettingsDescription": "Konfiguriere die allgemeinen Einstellungen deiner Organisation",
|
||||
"orgGeneralSettings": "Organisations-Einstellungen",
|
||||
"orgGeneralSettingsDescription": "Organisationsdetails und Konfiguration verwalten",
|
||||
"saveGeneralSettings": "Allgemeine Einstellungen speichern",
|
||||
"saveSettings": "Einstellungen speichern",
|
||||
"orgDangerZone": "Gefahrenzone",
|
||||
"orgDangerZoneDescription": "Sobald Sie diesen Org löschen, gibt es kein Zurück mehr. Bitte seien Sie vorsichtig.",
|
||||
"orgDelete": "Organisation löschen",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Wochen",
|
||||
"months": "Monate",
|
||||
"years": "Jahre",
|
||||
"day": "{count, plural, =1 {# Tag} other {# Tage}}",
|
||||
"day": "{count, plural, one {# Tag} other {# Tage}}",
|
||||
"apiKeysTitle": "API-Schlüssel Information",
|
||||
"apiKeysConfirmCopy2": "Sie müssen bestätigen, dass Sie den API-Schlüssel kopiert haben.",
|
||||
"apiKeysErrorCreate": "Fehler beim Erstellen des API-Schlüssels",
|
||||
@@ -301,7 +306,7 @@
|
||||
"userQuestionRemove": "Sind Sie sicher, dass Sie {selectedUser} dauerhaft vom Server löschen möchten?",
|
||||
"licenseKey": "Lizenzschlüssel",
|
||||
"valid": "Gültig",
|
||||
"numberOfSites": "Anzahl der Sites",
|
||||
"numberOfSites": "Anzahl der Standorte",
|
||||
"licenseKeySearch": "Lizenzschlüssel suchen...",
|
||||
"licenseKeyAdd": "Lizenzschlüssel hinzufügen",
|
||||
"type": "Typ",
|
||||
@@ -341,16 +346,16 @@
|
||||
"licensedNot": "Nicht lizenziert",
|
||||
"hostId": "Host-ID",
|
||||
"licenseReckeckAll": "Überprüfe alle Schlüssel",
|
||||
"licenseSiteUsage": "Website-Nutzung",
|
||||
"licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Sites an, die diese Lizenz verwenden.",
|
||||
"licenseNoSiteLimit": "Die Anzahl der Sites, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.",
|
||||
"licenseSiteUsage": "Standort-Nutzung",
|
||||
"licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Standorte an, die diese Lizenz verwenden.",
|
||||
"licenseNoSiteLimit": "Die Anzahl der Standorte, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.",
|
||||
"licensePurchase": "Lizenz kaufen",
|
||||
"licensePurchaseSites": "Zusätzliche Seiten kaufen",
|
||||
"licenseSitesUsedMax": "{usedSites} der {maxSites} Seiten verwendet",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# Seiten} =1 {# Seite} other {# Seiten}} im System.",
|
||||
"licensePurchaseSites": "Zusätzliche Standorte kaufen\n",
|
||||
"licenseSitesUsedMax": "{usedSites} von {maxSites} Standorten verwendet",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# Standorte} one {# Standort} other {# Standorte}} im System.",
|
||||
"licensePurchaseDescription": "Wähle aus, für wieviele Seiten du möchtest {selectedMode, select, license {kaufe eine Lizenz. Du kannst später immer weitere Seiten hinzufügen.} other {Füge zu deiner bestehenden Lizenz hinzu.}}",
|
||||
"licenseFee": "Lizenzgebühr",
|
||||
"licensePriceSite": "Preis pro Seite",
|
||||
"licensePriceSite": "Preis pro Standort",
|
||||
"total": "Gesamt",
|
||||
"licenseContinuePayment": "Weiter zur Zahlung",
|
||||
"pricingPage": "Preisseite",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Rolle auswählen",
|
||||
"inviteEmailSentDescription": "Eine E-Mail mit dem Zugangslink wurde an den Benutzer gesendet. Er muss den Link aufrufen, um die Einladung anzunehmen.",
|
||||
"inviteSentDescription": "Der Benutzer wurde eingeladen. Er muss den unten stehenden Link aufrufen, um die Einladung anzunehmen.",
|
||||
"inviteExpiresIn": "Die Einladung läuft in {days, plural, =1 {einem Tag} other {# Tagen}} ab.",
|
||||
"inviteExpiresIn": "Die Einladung läuft in {days, plural, one {einem Tag} other {# Tagen}} ab.",
|
||||
"idpTitle": "Allgemeine Informationen",
|
||||
"idpSelect": "Wählen Sie den Identitätsanbieter für den externen Benutzer",
|
||||
"idpNotConfigured": "Es sind keine Identitätsanbieter konfiguriert. Bitte konfigurieren Sie einen Identitätsanbieter, bevor Sie externe Benutzer erstellen.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Beim Hinzufügen des Benutzers zur Rolle ist ein Fehler aufgetreten.",
|
||||
"userSaved": "Benutzer gespeichert",
|
||||
"userSavedDescription": "Der Benutzer wurde aktualisiert.",
|
||||
"autoProvisioned": "Automatisch bereitgestellt",
|
||||
"autoProvisionedDescription": "Erlaube diesem Benutzer die automatische Verwaltung durch Identitätsanbieter",
|
||||
"accessControlsDescription": "Verwalten Sie, worauf dieser Benutzer in der Organisation zugreifen und was er tun kann",
|
||||
"accessControlsSubmit": "Zugriffskontrollen speichern",
|
||||
"roles": "Rollen",
|
||||
@@ -466,7 +473,7 @@
|
||||
"targetErrorDuplicate": "Doppeltes Ziel",
|
||||
"targetErrorDuplicateDescription": "Ein Ziel mit diesen Einstellungen existiert bereits",
|
||||
"targetWireGuardErrorInvalidIp": "Ungültige Ziel-IP",
|
||||
"targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Site-Subnets liegen",
|
||||
"targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Standort-Subnets liegen",
|
||||
"targetsUpdated": "Ziele aktualisiert",
|
||||
"targetsUpdatedDescription": "Ziele und Einstellungen erfolgreich aktualisiert",
|
||||
"targetsErrorUpdate": "Fehler beim Aktualisieren der Ziele",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "Der zu verwendende TLS-Servername für SNI. Leer lassen, um den Standard zu verwenden.",
|
||||
"targetTlsSubmit": "Einstellungen speichern",
|
||||
"targets": "Ziel-Konfiguration",
|
||||
"targetsDescription": "Richten Sie Ziele ein, um Datenverkehr zu Ihren Diensten zu leiten",
|
||||
"targetsDescription": "Richten Sie Ziele ein, um Datenverkehr zu Ihren Backend-Diensten zu leiten",
|
||||
"targetStickySessions": "Sticky Sessions aktivieren",
|
||||
"targetStickySessionsDescription": "Verbindungen für die gesamte Sitzung auf demselben Backend-Ziel halten.",
|
||||
"methodSelect": "Methode auswählen",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Ungültiges IP-Adressformat",
|
||||
"ipAddressErrorInvalidOctet": "Ungültiges IP-Adress-Oktett",
|
||||
"path": "Pfad",
|
||||
"matchPath": "Unterverzeichnis",
|
||||
"ipAddressRange": "IP-Bereich",
|
||||
"rulesErrorFetch": "Fehler beim Abrufen der Regeln",
|
||||
"rulesErrorFetchDescription": "Beim Abrufen der Regeln ist ein Fehler aufgetreten",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Aktionen",
|
||||
"rulesActionAlwaysAllow": "Immer erlauben: Alle Authentifizierungsmethoden umgehen",
|
||||
"rulesActionAlwaysDeny": "Immer verweigern: Alle Anfragen blockieren; keine Authentifizierung möglich",
|
||||
"rulesActionPassToAuth": "Weiterleiten zur Authentifizierung: Erlaubt das Versuchen von Authentifizierungsmethoden",
|
||||
"rulesMatchCriteria": "Übereinstimmungskriterien",
|
||||
"rulesMatchCriteriaIpAddress": "Mit einer bestimmten IP-Adresse übereinstimmen",
|
||||
"rulesMatchCriteriaIpAddressRange": "Mit einem IP-Adressbereich in CIDR-Notation übereinstimmen",
|
||||
@@ -557,8 +566,8 @@
|
||||
"resourceErrorCreateDescription": "Beim Erstellen der Ressource ist ein Fehler aufgetreten",
|
||||
"resourceErrorCreateMessage": "Fehler beim Erstellen der Ressource:",
|
||||
"resourceErrorCreateMessageDescription": "Ein unerwarteter Fehler ist aufgetreten",
|
||||
"sitesErrorFetch": "Fehler beim Abrufen der Sites",
|
||||
"sitesErrorFetchDescription": "Beim Abrufen der Sites ist ein Fehler aufgetreten",
|
||||
"sitesErrorFetch": "Fehler beim Abrufen der Standorte",
|
||||
"sitesErrorFetchDescription": "Beim Abrufen der Standorte ist ein Fehler aufgetreten",
|
||||
"domainsErrorFetch": "Fehler beim Abrufen der Domains",
|
||||
"domainsErrorFetchDescription": "Beim Abrufen der Domains ist ein Fehler aufgetreten",
|
||||
"none": "Keine",
|
||||
@@ -676,10 +685,10 @@
|
||||
"resourceGeneralDescription": "Konfigurieren Sie die allgemeinen Einstellungen für diese Ressource",
|
||||
"resourceEnable": "Ressource aktivieren",
|
||||
"resourceTransfer": "Ressource übertragen",
|
||||
"resourceTransferDescription": "Diese Ressource auf eine andere Site übertragen",
|
||||
"resourceTransferDescription": "Diese Ressource auf einen anderen Standort übertragen",
|
||||
"resourceTransferSubmit": "Ressource übertragen",
|
||||
"siteDestination": "Zielsite",
|
||||
"searchSites": "Sites durchsuchen",
|
||||
"siteDestination": "Zielort",
|
||||
"searchSites": "Standorte durchsuchen",
|
||||
"accessRoleCreate": "Rolle erstellen",
|
||||
"accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.",
|
||||
"accessRoleCreateSubmit": "Rolle erstellen",
|
||||
@@ -699,7 +708,7 @@
|
||||
"accessRoleRemovedDescription": "Die Rolle wurde erfolgreich entfernt.",
|
||||
"accessRoleRequiredRemove": "Bevor Sie diese Rolle löschen, wählen Sie bitte eine neue Rolle aus, zu der die bestehenden Mitglieder übertragen werden sollen.",
|
||||
"manage": "Verwalten",
|
||||
"sitesNotFound": "Keine Sites gefunden.",
|
||||
"sitesNotFound": "Keine Standorte gefunden.",
|
||||
"pangolinServerAdmin": "Server-Admin - Pangolin",
|
||||
"licenseTierProfessional": "Professional Lizenz",
|
||||
"licenseTierEnterprise": "Enterprise Lizenz",
|
||||
@@ -707,10 +716,10 @@
|
||||
"licensed": "Lizenziert",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"sitesAdditional": "Zusätzliche Sites",
|
||||
"sitesAdditional": "Zusätzliche Standorte",
|
||||
"licenseKeys": "Lizenzschlüssel",
|
||||
"sitestCountDecrease": "Anzahl der Sites verringern",
|
||||
"sitestCountIncrease": "Anzahl der Sites erhöhen",
|
||||
"sitestCountDecrease": "Anzahl der Standorte verringern",
|
||||
"sitestCountIncrease": "Anzahl der Standorte erhöhen",
|
||||
"idpManage": "Identitätsanbieter verwalten",
|
||||
"idpManageDescription": "Identitätsanbieter im System anzeigen und verwalten",
|
||||
"idpDeletedDescription": "Identitätsanbieter erfolgreich gelöscht",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "PIN muss genau 6 Ziffern lang sein",
|
||||
"pincodeRequirementsChars": "PIN darf nur Zahlen enthalten",
|
||||
"passwordRequirementsLength": "Passwort muss mindestens 1 Zeichen lang sein",
|
||||
"passwordRequirementsTitle": "Passwortanforderungen:",
|
||||
"passwordRequirementLength": "Mindestens 8 Zeichen lang",
|
||||
"passwordRequirementUppercase": "Mindestens ein Großbuchstabe",
|
||||
"passwordRequirementLowercase": "Mindestens ein Kleinbuchstabe",
|
||||
"passwordRequirementNumber": "Mindestens eine Zahl",
|
||||
"passwordRequirementSpecial": "Mindestens ein Sonderzeichen",
|
||||
"passwordRequirementsMet": "✓ Passwort erfüllt alle Anforderungen",
|
||||
"passwordStrength": "Passwortstärke",
|
||||
"passwordStrengthWeak": "Schwach",
|
||||
"passwordStrengthMedium": "Mittel",
|
||||
"passwordStrengthStrong": "Stark",
|
||||
"passwordRequirements": "Anforderungen:",
|
||||
"passwordRequirementLengthText": "8+ Zeichen",
|
||||
"passwordRequirementUppercaseText": "Großbuchstabe (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Kleinbuchstabe (a-z)",
|
||||
"passwordRequirementNumberText": "Zahl (0-9)",
|
||||
"passwordRequirementSpecialText": "Sonderzeichen (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
|
||||
"otpEmailRequirementsLength": "OTP muss mindestens 1 Zeichen lang sein",
|
||||
"otpEmailSent": "OTP gesendet",
|
||||
"otpEmailSentDescription": "Ein OTP wurde an Ihre E-Mail gesendet",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Verbunden",
|
||||
"idpErrorConnectingTo": "Es gab ein Problem bei der Verbindung zu {name}. Bitte kontaktieren Sie Ihren Administrator.",
|
||||
"idpErrorNotFound": "IdP nicht gefunden",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Ungültige Einladung",
|
||||
"inviteInvalidDescription": "Der Einladungslink ist ungültig.",
|
||||
"inviteErrorWrongUser": "Einladung ist nicht für diesen Benutzer",
|
||||
@@ -951,21 +980,30 @@
|
||||
"logoutError": "Fehler beim Abmelden",
|
||||
"signingAs": "Angemeldet als",
|
||||
"serverAdmin": "Server-Administrator",
|
||||
"managedSelfhosted": "Verwaltetes Selbsthosted",
|
||||
"otpEnable": "Zwei-Faktor aktivieren",
|
||||
"otpDisable": "Zwei-Faktor deaktivieren",
|
||||
"logout": "Abmelden",
|
||||
"licenseTierProfessionalRequired": "Professional Edition erforderlich",
|
||||
"licenseTierProfessionalRequiredDescription": "Diese Funktion ist nur in der Professional Edition verfügbar.",
|
||||
"actionGetOrg": "Organisation abrufen",
|
||||
"updateOrgUser": "Org Benutzer aktualisieren",
|
||||
"createOrgUser": "Org Benutzer erstellen",
|
||||
"actionUpdateOrg": "Organisation aktualisieren",
|
||||
"actionUpdateUser": "Benutzer aktualisieren",
|
||||
"actionGetUser": "Benutzer abrufen",
|
||||
"actionGetOrgUser": "Organisationsbenutzer abrufen",
|
||||
"actionListOrgDomains": "Organisationsdomänen auflisten",
|
||||
"actionCreateSite": "Site erstellen",
|
||||
"actionDeleteSite": "Site löschen",
|
||||
"actionGetSite": "Site abrufen",
|
||||
"actionListSites": "Sites auflisten",
|
||||
"actionUpdateSite": "Site aktualisieren",
|
||||
"actionListSiteRoles": "Erlaubte Site-Rollen auflisten",
|
||||
"actionCreateSite": "Standort erstellen",
|
||||
"actionDeleteSite": "Standort löschen",
|
||||
"actionGetSite": "Standort abrufen",
|
||||
"actionListSites": "Standorte auflisten",
|
||||
"actionApplyBlueprint": "Blaupause anwenden",
|
||||
"setupToken": "Setup-Token",
|
||||
"setupTokenDescription": "Geben Sie das Setup-Token von der Serverkonsole ein.",
|
||||
"setupTokenRequired": "Setup-Token ist erforderlich",
|
||||
"actionUpdateSite": "Standorte aktualisieren",
|
||||
"actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
|
||||
"actionCreateResource": "Ressource erstellen",
|
||||
"actionDeleteResource": "Ressource löschen",
|
||||
"actionGetResource": "Ressource abrufen",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "IDP-Organisationsrichtlinie löschen",
|
||||
"actionListIdpOrgs": "IDP-Organisationen auflisten",
|
||||
"actionUpdateIdpOrg": "IDP-Organisation aktualisieren",
|
||||
"actionCreateClient": "Kunde erstellen",
|
||||
"actionDeleteClient": "Kunde löschen",
|
||||
"actionUpdateClient": "Kunde aktualisieren",
|
||||
"actionListClients": "Kunden auflisten",
|
||||
"actionGetClient": "Kunde holen",
|
||||
"actionCreateSiteResource": "Site-Ressource erstellen",
|
||||
"actionDeleteSiteResource": "Site-Ressource löschen",
|
||||
"actionGetSiteResource": "Site-Ressource abrufen",
|
||||
"actionListSiteResources": "Site-Ressourcen auflisten",
|
||||
"actionUpdateSiteResource": "Site-Ressource aktualisieren",
|
||||
"actionListInvitations": "Einladungen auflisten",
|
||||
"noneSelected": "Keine ausgewählt",
|
||||
"orgNotFound2": "Keine Organisationen gefunden.",
|
||||
"searchProgress": "Suche...",
|
||||
@@ -1070,7 +1119,7 @@
|
||||
"language": "Sprache",
|
||||
"verificationCodeRequired": "Code ist erforderlich",
|
||||
"userErrorNoUpdate": "Kein Benutzer zum Aktualisieren",
|
||||
"siteErrorNoUpdate": "Keine Site zum Aktualisieren",
|
||||
"siteErrorNoUpdate": "Keine Standorte zum Aktualisieren",
|
||||
"resourceErrorNoUpdate": "Keine Ressource zum Aktualisieren",
|
||||
"authErrorNoUpdate": "Keine Auth-Informationen zum Aktualisieren",
|
||||
"orgErrorNoUpdate": "Keine Organisation zum Aktualisieren",
|
||||
@@ -1078,7 +1127,7 @@
|
||||
"apiKeysErrorNoUpdate": "Kein API-Schlüssel zum Aktualisieren",
|
||||
"sidebarOverview": "Übersicht",
|
||||
"sidebarHome": "Zuhause",
|
||||
"sidebarSites": "Seiten",
|
||||
"sidebarSites": "Standorte",
|
||||
"sidebarResources": "Ressourcen",
|
||||
"sidebarAccessControl": "Zugriffskontrolle",
|
||||
"sidebarUsers": "Benutzer",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Alle Benutzer",
|
||||
"sidebarIdentityProviders": "Identitätsanbieter",
|
||||
"sidebarLicense": "Lizenz",
|
||||
"enableDockerSocket": "Docker Socket aktivieren",
|
||||
"enableDockerSocketDescription": "Docker Socket-Erkennung aktivieren, um Container-Informationen zu befüllen. Socket-Pfad muss Newt bereitgestellt werden.",
|
||||
"sidebarClients": "Clients (Beta)",
|
||||
"sidebarDomains": "Domains",
|
||||
"enableDockerSocket": "Docker Blaupause aktivieren",
|
||||
"enableDockerSocketDescription": "Aktiviere Docker-Socket-Label-Scraping für Blaupausenbeschriftungen. Der Socket-Pfad muss neu angegeben werden.",
|
||||
"enableDockerSocketLink": "Mehr erfahren",
|
||||
"viewDockerContainers": "Docker Container anzeigen",
|
||||
"containersIn": "Container in {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Netzwerke",
|
||||
"containerHostnameIp": "Hostname/IP",
|
||||
"containerLabels": "Etiketten",
|
||||
"containerLabelsCount": "{count} Label{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# Etikett} other {# Etiketten}}",
|
||||
"containerLabelsTitle": "Container-Labels",
|
||||
"containerLabelEmpty": "<leer>",
|
||||
"containerPorts": "Häfen",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Stoppte Container anzeigen",
|
||||
"noContainersFound": "Keine Container gefunden. Stellen Sie sicher, dass Docker Container laufen.",
|
||||
"searchContainersPlaceholder": "Durchsuche {count} Container...",
|
||||
"searchResultsCount": "{count} Ergebnis{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# Ergebnis} other {# Ergebnisse}}",
|
||||
"filters": "Filter",
|
||||
"filterOptions": "Filteroptionen",
|
||||
"filterPorts": "Häfen",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "dunkel",
|
||||
"system": "System",
|
||||
"theme": "Design",
|
||||
"subnetRequired": "Subnetz ist erforderlich",
|
||||
"initialSetupTitle": "Initial Einrichtung des Servers",
|
||||
"initialSetupDescription": "Erstellen Sie das initiale Server-Admin-Konto. Es kann nur einen Server-Admin geben. Sie können diese Anmeldedaten später immer ändern.",
|
||||
"createAdminAccount": "Admin-Konto erstellen",
|
||||
"setupErrorCreateAdmin": "Beim Erstellen des Server-Admin-Kontos ist ein Fehler aufgetreten."
|
||||
"setupErrorCreateAdmin": "Beim Erstellen des Server-Admin-Kontos ist ein Fehler aufgetreten.",
|
||||
"certificateStatus": "Zertifikatsstatus",
|
||||
"loading": "Laden",
|
||||
"restart": "Neustart",
|
||||
"domains": "Domains",
|
||||
"domainsDescription": "Domains für Ihre Organisation verwalten",
|
||||
"domainsSearch": "Domains durchsuchen...",
|
||||
"domainAdd": "Domain hinzufügen",
|
||||
"domainAddDescription": "Eine neue Domain in Ihrer Organisation registrieren",
|
||||
"domainCreate": "Domain erstellen",
|
||||
"domainCreatedDescription": "Domain erfolgreich erstellt",
|
||||
"domainDeletedDescription": "Domain erfolgreich gelöscht",
|
||||
"domainQuestionRemove": "Möchten Sie die Domain {domain} wirklich aus Ihrem Konto entfernen?",
|
||||
"domainMessageRemove": "Nach dem Entfernen wird die Domain nicht mehr mit Ihrem Konto verknüpft.",
|
||||
"domainMessageConfirm": "Um zu bestätigen, geben Sie bitte den Domainnamen unten ein.",
|
||||
"domainConfirmDelete": "Domain-Löschung bestätigen",
|
||||
"domainDelete": "Domain löschen",
|
||||
"domain": "Domain",
|
||||
"selectDomainTypeNsName": "Domain-Delegation (NS)",
|
||||
"selectDomainTypeNsDescription": "Diese Domain und alle ihre Subdomains. Verwenden Sie dies, wenn Sie eine gesamte Domainzone kontrollieren möchten.",
|
||||
"selectDomainTypeCnameName": "Einzelne Domain (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Nur diese spezifische Domain. Verwenden Sie dies für einzelne Subdomains oder spezifische Domaineinträge.",
|
||||
"selectDomainTypeWildcardName": "Wildcard-Domain",
|
||||
"selectDomainTypeWildcardDescription": "Diese Domain und ihre Subdomains.",
|
||||
"domainDelegation": "Einzelne Domain",
|
||||
"selectType": "Typ auswählen",
|
||||
"actions": "Aktionen",
|
||||
"refresh": "Aktualisieren",
|
||||
"refreshError": "Datenaktualisierung fehlgeschlagen",
|
||||
"verified": "Verifiziert",
|
||||
"pending": "Ausstehend",
|
||||
"sidebarBilling": "Abrechnung",
|
||||
"billing": "Abrechnung",
|
||||
"orgBillingDescription": "Verwalten Sie Ihre Rechnungsinformationen und Abonnements",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hosted",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Kontoeinrichtung abschließen",
|
||||
"completeAccountSetupDescription": "Legen Sie Ihr Passwort fest, um zu beginnen",
|
||||
"accountSetupSent": "Wir senden einen Code für die Kontoeinrichtung an diese E-Mail-Adresse.",
|
||||
"accountSetupCode": "Einrichtungscode",
|
||||
"accountSetupCodeDescription": "Prüfen Sie Ihre E-Mail auf den Einrichtungscode.",
|
||||
"passwordCreate": "Passwort erstellen",
|
||||
"passwordCreateConfirm": "Passwort bestätigen",
|
||||
"accountSetupSubmit": "Einrichtungscode senden",
|
||||
"completeSetup": "Einrichtung abschließen",
|
||||
"accountSetupSuccess": "Kontoeinrichtung abgeschlossen! Willkommen bei Pangolin!",
|
||||
"documentation": "Dokumentation",
|
||||
"saveAllSettings": "Alle Einstellungen speichern",
|
||||
"settingsUpdated": "Einstellungen aktualisiert",
|
||||
"settingsUpdatedDescription": "Alle Einstellungen wurden erfolgreich aktualisiert",
|
||||
"settingsErrorUpdate": "Einstellungen konnten nicht aktualisiert werden",
|
||||
"settingsErrorUpdateDescription": "Beim Aktualisieren der Einstellungen ist ein Fehler aufgetreten",
|
||||
"sidebarCollapse": "Zusammenklappen",
|
||||
"sidebarExpand": "Erweitern",
|
||||
"newtUpdateAvailable": "Update verfügbar",
|
||||
"newtUpdateAvailableInfo": "Eine neue Version von Newt ist verfügbar. Bitte aktualisieren Sie auf die neueste Version für das beste Erlebnis.",
|
||||
"domainPickerEnterDomain": "Domain",
|
||||
"domainPickerPlaceholder": "myapp.example.com",
|
||||
"domainPickerDescription": "Geben Sie die vollständige Domäne der Ressource ein, um verfügbare Optionen zu sehen.",
|
||||
"domainPickerDescriptionSaas": "Geben Sie eine vollständige Domäne, Subdomäne oder einfach einen Namen ein, um verfügbare Optionen zu sehen",
|
||||
"domainPickerTabAll": "Alle",
|
||||
"domainPickerTabOrganization": "Organisation",
|
||||
"domainPickerTabProvided": "Bereitgestellt",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Verfügbarkeit prüfen...",
|
||||
"domainPickerNoMatchingDomains": "Keine passenden Domains gefunden. Versuchen Sie es mit einer anderen Domain oder überprüfen Sie die Domain-Einstellungen Ihrer Organisation.",
|
||||
"domainPickerOrganizationDomains": "Organisations-Domains",
|
||||
"domainPickerProvidedDomains": "Bereitgestellte Domains",
|
||||
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"domainPickerShowMore": "Mehr anzeigen",
|
||||
"domainNotFound": "Domain nicht gefunden",
|
||||
"domainNotFoundDescription": "Diese Ressource ist deaktiviert, weil die Domain nicht mehr in unserem System existiert. Bitte setzen Sie eine neue Domain für diese Ressource.",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"createNewOrgDescription": "Eine neue Organisation erstellen",
|
||||
"organization": "Organisation",
|
||||
"port": "Port",
|
||||
"securityKeyManage": "Sicherheitsschlüssel verwalten",
|
||||
"securityKeyDescription": "Sicherheitsschlüssel für passwortlose Authentifizierung hinzufügen oder entfernen",
|
||||
"securityKeyRegister": "Neuen Sicherheitsschlüssel registrieren",
|
||||
"securityKeyList": "Ihre Sicherheitsschlüssel",
|
||||
"securityKeyNone": "Noch keine Sicherheitsschlüssel registriert",
|
||||
"securityKeyNameRequired": "Name ist erforderlich",
|
||||
"securityKeyRemove": "Entfernen",
|
||||
"securityKeyLastUsed": "Zuletzt verwendet: {date}",
|
||||
"securityKeyNameLabel": "Name",
|
||||
"securityKeyRegisterSuccess": "Sicherheitsschlüssel erfolgreich registriert",
|
||||
"securityKeyRegisterError": "Fehler beim Registrieren des Sicherheitsschlüssels",
|
||||
"securityKeyRemoveSuccess": "Sicherheitsschlüssel erfolgreich entfernt",
|
||||
"securityKeyRemoveError": "Fehler beim Entfernen des Sicherheitsschlüssels",
|
||||
"securityKeyLoadError": "Fehler beim Laden der Sicherheitsschlüssel",
|
||||
"securityKeyLogin": "Mit dem Sicherheitsschlüssel fortfahren",
|
||||
"securityKeyAuthError": "Fehler bei der Authentifizierung mit Sicherheitsschlüssel",
|
||||
"securityKeyRecommendation": "Erwägen Sie die Registrierung eines weiteren Sicherheitsschlüssels auf einem anderen Gerät, um sicherzustellen, dass Sie sich nicht aus Ihrem Konto aussperren.",
|
||||
"registering": "Registrierung...",
|
||||
"securityKeyPrompt": "Bitte bestätigen Sie Ihre Identität mit Ihrem Sicherheitsschlüssel. Stellen Sie sicher, dass Ihr Sicherheitsschlüssel verbunden und einsatzbereit ist.",
|
||||
"securityKeyBrowserNotSupported": "Ihr Browser unterstützt Sicherheitsschlüssel nicht. Bitte verwenden Sie einen modernen Browser wie Chrome, Firefox oder Safari.",
|
||||
"securityKeyPermissionDenied": "Bitte erlauben Sie den Zugriff auf Ihren Sicherheitsschlüssel, um sich weiter anzumelden.",
|
||||
"securityKeyRemovedTooQuickly": "Lassen Sie Ihren Sicherheitsschlüssel verbunden, bis der Anmeldeprozess abgeschlossen ist.",
|
||||
"securityKeyNotSupported": "Ihr Sicherheitsschlüssel ist möglicherweise nicht kompatibel. Bitte versuchen Sie einen anderen Sicherheitsschlüssel.",
|
||||
"securityKeyUnknownError": "Es gab ein Problem mit Ihrem Sicherheitsschlüssel. Bitte versuchen Sie es erneut.",
|
||||
"twoFactorRequired": "Zur Registrierung eines Sicherheitsschlüssels ist eine Zwei-Faktor-Authentifizierung erforderlich.",
|
||||
"twoFactor": "Zwei-Faktor-Authentifizierung",
|
||||
"adminEnabled2FaOnYourAccount": "Ihr Administrator hat die Zwei-Faktor-Authentifizierung für {email} aktiviert. Bitte schließen Sie den Einrichtungsprozess ab, um fortzufahren.",
|
||||
"continueToApplication": "Weiter zur Anwendung",
|
||||
"securityKeyAdd": "Sicherheitsschlüssel hinzufügen",
|
||||
"securityKeyRegisterTitle": "Neuen Sicherheitsschlüssel registrieren",
|
||||
"securityKeyRegisterDescription": "Verbinden Sie Ihren Sicherheitsschlüssel und geben Sie einen Namen ein, um ihn zu identifizieren",
|
||||
"securityKeyTwoFactorRequired": "Zwei-Faktor-Authentifizierung erforderlich",
|
||||
"securityKeyTwoFactorDescription": "Bitte geben Sie Ihren Zwei-Faktor-Authentifizierungscode ein, um den Sicherheitsschlüssel zu registrieren",
|
||||
"securityKeyTwoFactorRemoveDescription": "Bitte geben Sie Ihren Zwei-Faktor-Authentifizierungscode ein, um den Sicherheitsschlüssel zu entfernen",
|
||||
"securityKeyTwoFactorCode": "Zwei-Faktor-Code",
|
||||
"securityKeyRemoveTitle": "Sicherheitsschlüssel entfernen",
|
||||
"securityKeyRemoveDescription": "Geben Sie Ihr Passwort ein, um den Sicherheitsschlüssel \"{name}\" zu entfernen",
|
||||
"securityKeyNoKeysRegistered": "Keine Sicherheitsschlüssel registriert",
|
||||
"securityKeyNoKeysDescription": "Fügen Sie einen Sicherheitsschlüssel hinzu, um die Sicherheit Ihres Kontos zu erhöhen",
|
||||
"createDomainRequired": "Domain ist erforderlich",
|
||||
"createDomainAddDnsRecords": "DNS-Einträge hinzufügen",
|
||||
"createDomainAddDnsRecordsDescription": "Fügen Sie die folgenden DNS-Einträge zu Ihrem Domain-Provider hinzu, um die Einrichtung abzuschließen.",
|
||||
"createDomainNsRecords": "NS-Einträge",
|
||||
"createDomainRecord": "Eintrag",
|
||||
"createDomainType": "Typ:",
|
||||
"createDomainName": "Name:",
|
||||
"createDomainValue": "Wert:",
|
||||
"createDomainCnameRecords": "CNAME-Einträge",
|
||||
"createDomainARecords": "A-Aufzeichnungen",
|
||||
"createDomainRecordNumber": "Eintrag {number}",
|
||||
"createDomainTxtRecords": "TXT-Einträge",
|
||||
"createDomainSaveTheseRecords": "Diese Einträge speichern",
|
||||
"createDomainSaveTheseRecordsDescription": "Achten Sie darauf, diese DNS-Einträge zu speichern, da Sie sie nicht erneut sehen werden.",
|
||||
"createDomainDnsPropagation": "DNS-Verbreitung",
|
||||
"createDomainDnsPropagationDescription": "Es kann einige Zeit dauern, bis DNS-Änderungen im Internet verbreitet werden. Dies kann je nach Ihrem DNS-Provider und den TTL-Einstellungen von einigen Minuten bis zu 48 Stunden dauern.",
|
||||
"resourcePortRequired": "Portnummer ist für nicht-HTTP-Ressourcen erforderlich",
|
||||
"resourcePortNotAllowed": "Portnummer sollte für HTTP-Ressourcen nicht gesetzt werden",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Ich stimme den",
|
||||
"termsOfService": "Nutzungsbedingungen zu",
|
||||
"and": "und",
|
||||
"privacyPolicy": "Datenschutzrichtlinie"
|
||||
},
|
||||
"siteRequired": "Standort ist erforderlich.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Nutzen Sie Olm für die Kundenverbindung",
|
||||
"errorCreatingClient": "Fehler beim Erstellen des Clients",
|
||||
"clientDefaultsNotFound": "Kundenvorgaben nicht gefunden",
|
||||
"createClient": "Client erstellen",
|
||||
"createClientDescription": "Erstellen Sie einen neuen Client für die Verbindung zu Ihren Standorten.",
|
||||
"seeAllClients": "Alle Clients anzeigen",
|
||||
"clientInformation": "Kundeninformationen",
|
||||
"clientNamePlaceholder": "Kundenname",
|
||||
"address": "Adresse",
|
||||
"subnetPlaceholder": "Subnetz",
|
||||
"addressDescription": "Die Adresse, die dieser Client für die Verbindung verwenden wird.",
|
||||
"selectSites": "Standorte auswählen",
|
||||
"sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
|
||||
"clientInstallOlm": "Olm installieren",
|
||||
"clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen",
|
||||
"clientOlmCredentials": "Olm-Zugangsdaten",
|
||||
"clientOlmCredentialsDescription": "So authentifiziert sich Olm beim Server",
|
||||
"olmEndpoint": "Olm-Endpunkt",
|
||||
"olmId": "Olm-ID",
|
||||
"olmSecretKey": "Olm-Geheimschlüssel",
|
||||
"clientCredentialsSave": "Speichern Sie Ihre Zugangsdaten",
|
||||
"clientCredentialsSaveDescription": "Sie können dies nur einmal sehen. Kopieren Sie es an einen sicheren Ort.",
|
||||
"generalSettingsDescription": "Konfigurieren Sie die allgemeinen Einstellungen für diesen Client",
|
||||
"clientUpdated": "Client aktualisiert",
|
||||
"clientUpdatedDescription": "Der Client wurde aktualisiert.",
|
||||
"clientUpdateFailed": "Fehler beim Aktualisieren des Clients",
|
||||
"clientUpdateError": "Beim Aktualisieren des Clients ist ein Fehler aufgetreten.",
|
||||
"sitesFetchFailed": "Fehler beim Abrufen von Standorten",
|
||||
"sitesFetchError": "Beim Abrufen von Standorten ist ein Fehler aufgetreten.",
|
||||
"olmErrorFetchReleases": "Beim Abrufen von Olm-Veröffentlichungen ist ein Fehler aufgetreten.",
|
||||
"olmErrorFetchLatest": "Beim Abrufen der neuesten Olm-Veröffentlichung ist ein Fehler aufgetreten.",
|
||||
"remoteSubnets": "Remote-Subnetze",
|
||||
"enterCidrRange": "Geben Sie den CIDR-Bereich ein",
|
||||
"remoteSubnetsDescription": "Fügen Sie CIDR-Bereiche hinzu, die über Clients von dieser Site aus remote zugänglich sind. Verwenden Sie ein Format wie 10.0.0.0/24. Dies gilt NUR für die VPN-Client-Konnektivität.",
|
||||
"resourceEnableProxy": "Öffentlichen Proxy aktivieren",
|
||||
"resourceEnableProxyDescription": "Ermöglichen Sie öffentliches Proxieren zu dieser Ressource. Dies ermöglicht den Zugriff auf die Ressource von außerhalb des Netzwerks durch die Cloud über einen offenen Port. Erfordert Traefik-Config.",
|
||||
"externalProxyEnabled": "Externer Proxy aktiviert",
|
||||
"addNewTarget": "Neues Ziel hinzufügen",
|
||||
"targetsList": "Ziel-Liste",
|
||||
"targetErrorDuplicateTargetFound": "Doppeltes Ziel gefunden",
|
||||
"httpMethod": "HTTP-Methode",
|
||||
"selectHttpMethod": "HTTP-Methode auswählen",
|
||||
"domainPickerSubdomainLabel": "Subdomain",
|
||||
"domainPickerBaseDomainLabel": "Basisdomäne",
|
||||
"domainPickerSearchDomains": "Domains suchen...",
|
||||
"domainPickerNoDomainsFound": "Keine Domains gefunden",
|
||||
"domainPickerLoadingDomains": "Domains werden geladen...",
|
||||
"domainPickerSelectBaseDomain": "Basisdomäne auswählen...",
|
||||
"domainPickerNotAvailableForCname": "Für CNAME-Domains nicht verfügbar",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Geben Sie eine Subdomain ein oder lassen Sie das Feld leer, um die Basisdomäne zu verwenden.",
|
||||
"domainPickerEnterSubdomainToSearch": "Geben Sie eine Subdomain ein, um verfügbare freie Domains zu suchen und auszuwählen.",
|
||||
"domainPickerFreeDomains": "Freie Domains",
|
||||
"domainPickerSearchForAvailableDomains": "Verfügbare Domains suchen",
|
||||
"resourceDomain": "Domain",
|
||||
"resourceEditDomain": "Domain bearbeiten",
|
||||
"siteName": "Site-Name",
|
||||
"proxyPort": "Port",
|
||||
"resourcesTableProxyResources": "Proxy-Ressourcen",
|
||||
"resourcesTableClientResources": "Client-Ressourcen",
|
||||
"resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.",
|
||||
"resourcesTableDestination": "Ziel",
|
||||
"resourcesTableTheseResourcesForUseWith": "Diese Ressourcen sind zur Verwendung mit",
|
||||
"resourcesTableClients": "Kunden",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "und sind nur intern zugänglich, wenn mit einem Client verbunden.",
|
||||
"editInternalResourceDialogEditClientResource": "Client-Ressource bearbeiten",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Aktualisieren Sie die Ressourceneigenschaften und die Zielkonfiguration für {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Ressourceneigenschaften",
|
||||
"editInternalResourceDialogName": "Name",
|
||||
"editInternalResourceDialogProtocol": "Protokoll",
|
||||
"editInternalResourceDialogSitePort": "Site-Port",
|
||||
"editInternalResourceDialogTargetConfiguration": "Zielkonfiguration",
|
||||
"editInternalResourceDialogCancel": "Abbrechen",
|
||||
"editInternalResourceDialogSaveResource": "Ressource speichern",
|
||||
"editInternalResourceDialogSuccess": "Erfolg",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne Ressource erfolgreich aktualisiert",
|
||||
"editInternalResourceDialogError": "Fehler",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Interne Ressource konnte nicht aktualisiert werden",
|
||||
"editInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||
"editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
|
||||
"editInternalResourceDialogProxyPortMax": "Proxy-Port muss kleiner als 65536 sein",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Ungültiges IP-Adressformat",
|
||||
"editInternalResourceDialogDestinationPortMin": "Ziel-Port muss mindestens 1 sein",
|
||||
"editInternalResourceDialogDestinationPortMax": "Ziel-Port muss kleiner als 65536 sein",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Keine Sites verfügbar",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Sie müssen mindestens eine Newt-Site mit einem konfigurierten Subnetz haben, um interne Ressourcen zu erstellen.",
|
||||
"createInternalResourceDialogClose": "Schließen",
|
||||
"createInternalResourceDialogCreateClientResource": "Ressource erstellen",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Erstellen Sie eine neue Ressource, die für Clients zugänglich ist, die mit der ausgewählten Site verbunden sind.",
|
||||
"createInternalResourceDialogResourceProperties": "Ressourceneigenschaften",
|
||||
"createInternalResourceDialogName": "Name",
|
||||
"createInternalResourceDialogSite": "Standort",
|
||||
"createInternalResourceDialogSelectSite": "Standort auswählen...",
|
||||
"createInternalResourceDialogSearchSites": "Sites durchsuchen...",
|
||||
"createInternalResourceDialogNoSitesFound": "Keine Standorte gefunden.",
|
||||
"createInternalResourceDialogProtocol": "Protokoll",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Site-Port",
|
||||
"createInternalResourceDialogSitePortDescription": "Verwenden Sie diesen Port, um bei Verbindung mit einem Client auf die Ressource an der Site zuzugreifen.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Zielkonfiguration",
|
||||
"createInternalResourceDialogDestinationIPDescription": "Die IP-Adresse oder Hostname Adresse der Ressource im Netzwerk der Website.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "Der Port auf der Ziel-IP, unter dem die Ressource zugänglich ist.",
|
||||
"createInternalResourceDialogCancel": "Abbrechen",
|
||||
"createInternalResourceDialogCreateResource": "Ressource erstellen",
|
||||
"createInternalResourceDialogSuccess": "Erfolg",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne Ressource erfolgreich erstellt",
|
||||
"createInternalResourceDialogError": "Fehler",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Interne Ressource konnte nicht erstellt werden",
|
||||
"createInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||
"createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie eine Site aus",
|
||||
"createInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
|
||||
"createInternalResourceDialogProxyPortMax": "Proxy-Port muss kleiner als 65536 sein",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Ungültiges IP-Adressformat",
|
||||
"createInternalResourceDialogDestinationPortMin": "Ziel-Port muss mindestens 1 sein",
|
||||
"createInternalResourceDialogDestinationPortMax": "Ziel-Port muss kleiner als 65536 sein",
|
||||
"siteConfiguration": "Konfiguration",
|
||||
"siteAcceptClientConnections": "Clientverbindungen akzeptieren",
|
||||
"siteAcceptClientConnectionsDescription": "Erlauben Sie anderen Geräten, über diese Newt-Instanz mit Clients als Gateway zu verbinden.",
|
||||
"siteAddress": "Site-Adresse",
|
||||
"siteAddressDescription": "Geben Sie die IP-Adresse des Hosts an, mit dem sich die Clients verbinden sollen. Dies ist die interne Adresse der Site im Pangolin-Netzwerk, die von Clients angesprochen werden muss. Muss innerhalb des Unternehmens-Subnetzes liegen.",
|
||||
"autoLoginExternalIdp": "Automatische Anmeldung mit externem IDP",
|
||||
"autoLoginExternalIdpDescription": "Leiten Sie den Benutzer sofort zur Authentifizierung an den externen IDP weiter.",
|
||||
"selectIdp": "IDP auswählen",
|
||||
"selectIdpPlaceholder": "Wählen Sie einen IDP...",
|
||||
"selectIdpRequired": "Bitte wählen Sie einen IDP aus, wenn automatische Anmeldung aktiviert ist.",
|
||||
"autoLoginTitle": "Weiterleitung",
|
||||
"autoLoginDescription": "Sie werden zum externen Identitätsanbieter zur Authentifizierung weitergeleitet.",
|
||||
"autoLoginProcessing": "Authentifizierung vorbereiten...",
|
||||
"autoLoginRedirecting": "Weiterleitung zur Anmeldung...",
|
||||
"autoLoginError": "Fehler bei der automatischen Anmeldung",
|
||||
"autoLoginErrorNoRedirectUrl": "Keine Weiterleitungs-URL vom Identitätsanbieter erhalten.",
|
||||
"autoLoginErrorGeneratingUrl": "Fehler beim Generieren der Authentifizierungs-URL.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Verwaltetes Selbsthosted",
|
||||
"description": "Zuverlässiger und wartungsarmer Pangolin Server mit zusätzlichen Glocken und Pfeifen",
|
||||
"introTitle": "Verwalteter selbstgehosteter Pangolin",
|
||||
"introDescription": "ist eine Deployment-Option, die für Personen konzipiert wurde, die Einfachheit und zusätzliche Zuverlässigkeit wünschen, während sie ihre Daten privat und selbstgehostet halten.",
|
||||
"introDetail": "Mit dieser Option haben Sie immer noch Ihren eigenen Pangolin-Knoten – Ihre Tunnel, SSL-Terminierung und Traffic bleiben auf Ihrem Server. Der Unterschied besteht darin, dass Verwaltung und Überwachung über unser Cloud-Dashboard abgewickelt werden, das eine Reihe von Vorteilen freischaltet:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Einfachere Operationen",
|
||||
"description": "Sie brauchen keinen eigenen Mail-Server auszuführen oder komplexe Warnungen einzurichten. Sie erhalten Gesundheitschecks und Ausfallwarnungen aus dem Box."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Automatische Updates",
|
||||
"description": "Das Cloud-Dashboard entwickelt sich schnell, so dass Sie neue Funktionen und Fehlerbehebungen erhalten, ohne jedes Mal neue Container manuell ziehen zu müssen."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Weniger Wartung",
|
||||
"description": "Keine Datenbankmigrationen, Sicherungen oder zusätzliche Infrastruktur zum Verwalten. Wir kümmern uns um das in der Cloud."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Cloud-Ausfall",
|
||||
"description": "Wenn Ihr Knoten runtergeht, können Ihre Tunnel vorübergehend an unsere Cloud-Punkte scheitern, bis Sie ihn wieder online bringen."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Hohe Verfügbarkeit (PoPs)",
|
||||
"description": "Sie können auch mehrere Knoten an Ihr Konto anhängen, um Redundanz und bessere Leistung zu erzielen."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Zukünftige Verbesserungen",
|
||||
"description": "Wir planen weitere Analyse-, Alarm- und Management-Tools hinzuzufügen, um Ihren Einsatz noch robuster zu machen."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Erfahren Sie mehr über die Managed Self-Hosted Option in unserer",
|
||||
"documentation": "dokumentation"
|
||||
},
|
||||
"convertButton": "Diesen Knoten in Managed Self-Hosted umwandeln"
|
||||
},
|
||||
"internationaldomaindetected": "Internationale Domain erkannt",
|
||||
"willbestoredas": "Wird gespeichert als:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC Provider",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Eigene Kopfzeilen",
|
||||
"headersValidationError": "Header müssen im Format Header-Name: Wert sein.",
|
||||
"domainPickerProvidedDomain": "Angegebene Domain",
|
||||
"domainPickerFreeProvidedDomain": "Kostenlose Domain",
|
||||
"domainPickerVerified": "Verifiziert",
|
||||
"domainPickerUnverified": "Nicht verifiziert",
|
||||
"domainPickerInvalidSubdomainStructure": "Diese Subdomain enthält ungültige Zeichen oder Struktur. Sie wird beim Speichern automatisch bereinigt.",
|
||||
"domainPickerError": "Fehler",
|
||||
"domainPickerErrorLoadDomains": "Fehler beim Laden der Organisations-Domänen",
|
||||
"domainPickerErrorCheckAvailability": "Fehler beim Prüfen der Domain-Verfügbarkeit",
|
||||
"domainPickerInvalidSubdomain": "Ungültige Subdomain",
|
||||
"domainPickerInvalidSubdomainRemoved": "Die Eingabe \"{sub}\" wurde entfernt, weil sie nicht gültig ist.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" konnte nicht für {domain} gültig gemacht werden.",
|
||||
"domainPickerSubdomainSanitized": "Subdomain bereinigt",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" wurde korrigiert zu \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Datei bearbeiten: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Datei bearbeiten: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
"setupErrorIdentifier": "Organization ID is already taken. Please choose a different one.",
|
||||
"componentsErrorNoMemberCreate": "You are not currently a member of any organizations. Create an organization to get started.",
|
||||
"componentsErrorNoMember": "You are not currently a member of any organizations.",
|
||||
"welcome": "Welcome to Pangolin",
|
||||
"welcome": "Welcome!",
|
||||
"welcomeTo": "Welcome to",
|
||||
"componentsCreateOrg": "Create an Organization",
|
||||
"componentsMember": "You're a member of {count, plural, =0 {no organization} =1 {one organization} other {# organizations}}.",
|
||||
"componentsMember": "You're a member of {count, plural, =0 {no organization} one {one organization} other {# organizations}}.",
|
||||
"componentsInvalidKey": "Invalid or expired license keys detected. Follow license terms to continue using all features.",
|
||||
"dismiss": "Dismiss",
|
||||
"componentsLicenseViolation": "License Violation: This server is using {usedSites} sites which exceeds its licensed limit of {maxSites} sites. Follow license terms to continue using all features.",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Error creating site",
|
||||
"siteErrorCreateKeyPair": "Key pair or site defaults not found",
|
||||
"siteErrorCreateDefaults": "Site defaults not found",
|
||||
"siteNameDescription": "This is the display name for the site.",
|
||||
"method": "Method",
|
||||
"siteMethodDescription": "This is how you will expose connections.",
|
||||
"siteLearnNewt": "Learn how to install Newt on your system",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "Easiest way to create an entrypoint into your network. No extra setup.",
|
||||
"siteWg": "Basic WireGuard",
|
||||
"siteWgDescription": "Use any WireGuard client to establish a tunnel. Manual NAT setup required.",
|
||||
"siteWgDescriptionSaas": "Use any WireGuard client to establish a tunnel. Manual NAT setup required. ONLY WORKS ON SELF HOSTED NODES",
|
||||
"siteLocalDescription": "Local resources only. No tunneling.",
|
||||
"siteLocalDescriptionSaas": "Local resources only. No tunneling. ONLY WORKS ON SELF HOSTED NODES",
|
||||
"siteSeeAll": "See All Sites",
|
||||
"siteTunnelDescription": "Determine how you want to connect to your site",
|
||||
"siteNewtCredentials": "Newt Credentials",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Select site",
|
||||
"siteSearch": "Search site",
|
||||
"siteNotFound": "No site found.",
|
||||
"siteSelectionDescription": "This site will provide connectivity to the resource.",
|
||||
"siteSelectionDescription": "This site will provide connectivity to the target.",
|
||||
"resourceType": "Resource Type",
|
||||
"resourceTypeDescription": "Determine how you want to access your resource",
|
||||
"resourceHTTPSSettings": "HTTPS Settings",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "General",
|
||||
"generalSettings": "General Settings",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Internal",
|
||||
"rules": "Rules",
|
||||
"resourceSettingDescription": "Configure the settings on your resource",
|
||||
"resourceSetting": "{resourceName} Settings",
|
||||
"alwaysAllow": "Always Allow",
|
||||
"alwaysDeny": "Always Deny",
|
||||
"passToAuth": "Pass to Auth",
|
||||
"orgSettingsDescription": "Configure your organization's general settings",
|
||||
"orgGeneralSettings": "Organization Settings",
|
||||
"orgGeneralSettingsDescription": "Manage your organization details and configuration",
|
||||
"saveGeneralSettings": "Save General Settings",
|
||||
"saveSettings": "Save Settings",
|
||||
"orgDangerZone": "Danger Zone",
|
||||
"orgDangerZoneDescription": "Once you delete this org, there is no going back. Please be certain.",
|
||||
"orgDelete": "Delete Organization",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Weeks",
|
||||
"months": "Months",
|
||||
"years": "Years",
|
||||
"day": "{count, plural, =1 {# day} other {# days}}",
|
||||
"day": "{count, plural, one {# day} other {# days}}",
|
||||
"apiKeysTitle": "API Key Information",
|
||||
"apiKeysConfirmCopy2": "You must confirm that you have copied the API key.",
|
||||
"apiKeysErrorCreate": "Error creating API key",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Purchase License",
|
||||
"licensePurchaseSites": "Purchase Additional Sites",
|
||||
"licenseSitesUsedMax": "{usedSites} of {maxSites} sites used",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} =1 {# site} other {# sites}} in system.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} one {# site} other {# sites}} in system.",
|
||||
"licensePurchaseDescription": "Choose how many sites you want to {selectedMode, select, license {purchase a license for. You can always add more sites later.} other {add to your existing license.}}",
|
||||
"licenseFee": "License fee",
|
||||
"licensePriceSite": "Price per site",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Select role",
|
||||
"inviteEmailSentDescription": "An email has been sent to the user with the access link below. They must access the link to accept the invitation.",
|
||||
"inviteSentDescription": "The user has been invited. They must access the link below to accept the invitation.",
|
||||
"inviteExpiresIn": "The invite will expire in {days, plural, =1 {# day} other {# days}}.",
|
||||
"inviteExpiresIn": "The invite will expire in {days, plural, one {# day} other {# days}}.",
|
||||
"idpTitle": "Identity Provider",
|
||||
"idpSelect": "Select the identity provider for the external user",
|
||||
"idpNotConfigured": "No identity providers are configured. Please configure an identity provider before creating external users.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "An error occurred while adding user to the role.",
|
||||
"userSaved": "User saved",
|
||||
"userSavedDescription": "The user has been updated.",
|
||||
"autoProvisioned": "Auto Provisioned",
|
||||
"autoProvisionedDescription": "Allow this user to be automatically managed by identity provider",
|
||||
"accessControlsDescription": "Manage what this user can access and do in the organization",
|
||||
"accessControlsSubmit": "Save Access Controls",
|
||||
"roles": "Roles",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "The TLS Server Name to use for SNI. Leave empty to use the default.",
|
||||
"targetTlsSubmit": "Save Settings",
|
||||
"targets": "Targets Configuration",
|
||||
"targetsDescription": "Set up targets to route traffic to your services",
|
||||
"targetsDescription": "Set up targets to route traffic to your backend services",
|
||||
"targetStickySessions": "Enable Sticky Sessions",
|
||||
"targetStickySessionsDescription": "Keep connections on the same backend target for their entire session.",
|
||||
"methodSelect": "Select method",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Invalid IP address format",
|
||||
"ipAddressErrorInvalidOctet": "Invalid IP address octet",
|
||||
"path": "Path",
|
||||
"matchPath": "Match Path",
|
||||
"ipAddressRange": "IP Range",
|
||||
"rulesErrorFetch": "Failed to fetch rules",
|
||||
"rulesErrorFetchDescription": "An error occurred while fetching rules",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Actions",
|
||||
"rulesActionAlwaysAllow": "Always Allow: Bypass all authentication methods",
|
||||
"rulesActionAlwaysDeny": "Always Deny: Block all requests; no authentication can be attempted",
|
||||
"rulesActionPassToAuth": "Pass to Auth: Allow authentication methods to be attempted",
|
||||
"rulesMatchCriteria": "Matching Criteria",
|
||||
"rulesMatchCriteriaIpAddress": "Match a specific IP address",
|
||||
"rulesMatchCriteriaIpAddressRange": "Match a range of IP addresses in CIDR notation",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "PIN must be exactly 6 digits",
|
||||
"pincodeRequirementsChars": "PIN must only contain numbers",
|
||||
"passwordRequirementsLength": "Password must be at least 1 character long",
|
||||
"passwordRequirementsTitle": "Password requirements:",
|
||||
"passwordRequirementLength": "At least 8 characters long",
|
||||
"passwordRequirementUppercase": "At least one uppercase letter",
|
||||
"passwordRequirementLowercase": "At least one lowercase letter",
|
||||
"passwordRequirementNumber": "At least one number",
|
||||
"passwordRequirementSpecial": "At least one special character",
|
||||
"passwordRequirementsMet": "✓ Password meets all requirements",
|
||||
"passwordStrength": "Password strength",
|
||||
"passwordStrengthWeak": "Weak",
|
||||
"passwordStrengthMedium": "Medium",
|
||||
"passwordStrengthStrong": "Strong",
|
||||
"passwordRequirements": "Requirements:",
|
||||
"passwordRequirementLengthText": "8+ characters",
|
||||
"passwordRequirementUppercaseText": "Uppercase letter (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Lowercase letter (a-z)",
|
||||
"passwordRequirementNumberText": "Number (0-9)",
|
||||
"passwordRequirementSpecialText": "Special character (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"otpEmailRequirementsLength": "OTP must be at least 1 character long",
|
||||
"otpEmailSent": "OTP Sent",
|
||||
"otpEmailSentDescription": "An OTP has been sent to your email",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Connected",
|
||||
"idpErrorConnectingTo": "There was a problem connecting to {name}. Please contact your administrator.",
|
||||
"idpErrorNotFound": "IdP not found",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Invalid Invite",
|
||||
"inviteInvalidDescription": "The invite link is invalid.",
|
||||
"inviteErrorWrongUser": "Invite is not for this user",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Error logging out",
|
||||
"signingAs": "Signed in as",
|
||||
"serverAdmin": "Server Admin",
|
||||
"managedSelfhosted": "Managed Self-Hosted",
|
||||
"otpEnable": "Enable Two-factor",
|
||||
"otpDisable": "Disable Two-factor",
|
||||
"logout": "Log Out",
|
||||
"licenseTierProfessionalRequired": "Professional Edition Required",
|
||||
"licenseTierProfessionalRequiredDescription": "This feature is only available in the Professional Edition.",
|
||||
"actionGetOrg": "Get Organization",
|
||||
"updateOrgUser": "Update Org User",
|
||||
"createOrgUser": "Create Org User",
|
||||
"actionUpdateOrg": "Update Organization",
|
||||
"actionUpdateUser": "Update User",
|
||||
"actionGetUser": "Get User",
|
||||
"actionGetOrgUser": "Get Organization User",
|
||||
"actionListOrgDomains": "List Organization Domains",
|
||||
"actionCreateSite": "Create Site",
|
||||
"actionDeleteSite": "Delete Site",
|
||||
"actionGetSite": "Get Site",
|
||||
"actionListSites": "List Sites",
|
||||
"actionApplyBlueprint": "Apply Blueprint",
|
||||
"setupToken": "Setup Token",
|
||||
"setupTokenDescription": "Enter the setup token from the server console.",
|
||||
"setupTokenRequired": "Setup token is required",
|
||||
"actionUpdateSite": "Update Site",
|
||||
"actionListSiteRoles": "List Allowed Site Roles",
|
||||
"actionCreateResource": "Create Resource",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Delete IDP Org Policy",
|
||||
"actionListIdpOrgs": "List IDP Orgs",
|
||||
"actionUpdateIdpOrg": "Update IDP Org",
|
||||
"actionCreateClient": "Create Client",
|
||||
"actionDeleteClient": "Delete Client",
|
||||
"actionUpdateClient": "Update Client",
|
||||
"actionListClients": "List Clients",
|
||||
"actionGetClient": "Get Client",
|
||||
"actionCreateSiteResource": "Create Site Resource",
|
||||
"actionDeleteSiteResource": "Delete Site Resource",
|
||||
"actionGetSiteResource": "Get Site Resource",
|
||||
"actionListSiteResources": "List Site Resources",
|
||||
"actionUpdateSiteResource": "Update Site Resource",
|
||||
"actionListInvitations": "List Invitations",
|
||||
"noneSelected": "None selected",
|
||||
"orgNotFound2": "No organizations found.",
|
||||
"searchProgress": "Search...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "All Users",
|
||||
"sidebarIdentityProviders": "Identity Providers",
|
||||
"sidebarLicense": "License",
|
||||
"enableDockerSocket": "Enable Docker Socket",
|
||||
"enableDockerSocketDescription": "Enable Docker Socket discovery for populating container information. Socket path must be provided to Newt.",
|
||||
"sidebarClients": "Clients (Beta)",
|
||||
"sidebarDomains": "Domains",
|
||||
"enableDockerSocket": "Enable Docker Blueprint",
|
||||
"enableDockerSocketDescription": "Enable Docker Socket label scraping for blueprint labels. Socket path must be provided to Newt.",
|
||||
"enableDockerSocketLink": "Learn More",
|
||||
"viewDockerContainers": "View Docker Containers",
|
||||
"containersIn": "Containers in {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Networks",
|
||||
"containerHostnameIp": "Hostname/IP",
|
||||
"containerLabels": "Labels",
|
||||
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# label} other {# labels}}",
|
||||
"containerLabelsTitle": "Container Labels",
|
||||
"containerLabelEmpty": "<empty>",
|
||||
"containerPorts": "Ports",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Show stopped containers",
|
||||
"noContainersFound": "No containers found. Make sure Docker containers are running.",
|
||||
"searchContainersPlaceholder": "Search across {count} containers...",
|
||||
"searchResultsCount": "{count} result{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# result} other {# results}}",
|
||||
"filters": "Filters",
|
||||
"filterOptions": "Filter Options",
|
||||
"filterPorts": "Ports",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "dark",
|
||||
"system": "system",
|
||||
"theme": "Theme",
|
||||
"subnetRequired": "Subnet is required",
|
||||
"initialSetupTitle": "Initial Server Setup",
|
||||
"initialSetupDescription": "Create the intial server admin account. Only one server admin can exist. You can always change these credentials later.",
|
||||
"createAdminAccount": "Create Admin Account",
|
||||
"setupErrorCreateAdmin": "An error occurred while creating the server admin account."
|
||||
"setupErrorCreateAdmin": "An error occurred while creating the server admin account.",
|
||||
"certificateStatus": "Certificate Status",
|
||||
"loading": "Loading",
|
||||
"restart": "Restart",
|
||||
"domains": "Domains",
|
||||
"domainsDescription": "Manage domains for your organization",
|
||||
"domainsSearch": "Search domains...",
|
||||
"domainAdd": "Add Domain",
|
||||
"domainAddDescription": "Register a new domain with your organization",
|
||||
"domainCreate": "Create Domain",
|
||||
"domainCreatedDescription": "Domain created successfully",
|
||||
"domainDeletedDescription": "Domain deleted successfully",
|
||||
"domainQuestionRemove": "Are you sure you want to remove the domain {domain} from your account?",
|
||||
"domainMessageRemove": "Once removed, the domain will no longer be associated with your account.",
|
||||
"domainMessageConfirm": "To confirm, please type the domain name below.",
|
||||
"domainConfirmDelete": "Confirm Delete Domain",
|
||||
"domainDelete": "Delete Domain",
|
||||
"domain": "Domain",
|
||||
"selectDomainTypeNsName": "Domain Delegation (NS)",
|
||||
"selectDomainTypeNsDescription": "This domain and all its subdomains. Use this when you want to control an entire domain zone.",
|
||||
"selectDomainTypeCnameName": "Single Domain (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Just this specific domain. Use this for individual subdomains or specific domain entries.",
|
||||
"selectDomainTypeWildcardName": "Wildcard Domain",
|
||||
"selectDomainTypeWildcardDescription": "This domain and its subdomains.",
|
||||
"domainDelegation": "Single Domain",
|
||||
"selectType": "Select a type",
|
||||
"actions": "Actions",
|
||||
"refresh": "Refresh",
|
||||
"refreshError": "Failed to refresh data",
|
||||
"verified": "Verified",
|
||||
"pending": "Pending",
|
||||
"sidebarBilling": "Billing",
|
||||
"billing": "Billing",
|
||||
"orgBillingDescription": "Manage your billing information and subscriptions",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hosted",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Complete Account Setup",
|
||||
"completeAccountSetupDescription": "Set your password to get started",
|
||||
"accountSetupSent": "We'll send an account setup code to this email address.",
|
||||
"accountSetupCode": "Setup Code",
|
||||
"accountSetupCodeDescription": "Check your email for the setup code.",
|
||||
"passwordCreate": "Create Password",
|
||||
"passwordCreateConfirm": "Confirm Password",
|
||||
"accountSetupSubmit": "Send Setup Code",
|
||||
"completeSetup": "Complete Setup",
|
||||
"accountSetupSuccess": "Account setup completed! Welcome to Pangolin!",
|
||||
"documentation": "Documentation",
|
||||
"saveAllSettings": "Save All Settings",
|
||||
"settingsUpdated": "Settings updated",
|
||||
"settingsUpdatedDescription": "All settings have been updated successfully",
|
||||
"settingsErrorUpdate": "Failed to update settings",
|
||||
"settingsErrorUpdateDescription": "An error occurred while updating settings",
|
||||
"sidebarCollapse": "Collapse",
|
||||
"sidebarExpand": "Expand",
|
||||
"newtUpdateAvailable": "Update Available",
|
||||
"newtUpdateAvailableInfo": "A new version of Newt is available. Please update to the latest version for the best experience.",
|
||||
"domainPickerEnterDomain": "Domain",
|
||||
"domainPickerPlaceholder": "myapp.example.com",
|
||||
"domainPickerDescription": "Enter the full domain of the resource to see available options.",
|
||||
"domainPickerDescriptionSaas": "Enter a full domain, subdomain, or just a name to see available options",
|
||||
"domainPickerTabAll": "All",
|
||||
"domainPickerTabOrganization": "Organization",
|
||||
"domainPickerTabProvided": "Provided",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Checking availability...",
|
||||
"domainPickerNoMatchingDomains": "No matching domains found. Try a different domain or check your organization's domain settings.",
|
||||
"domainPickerOrganizationDomains": "Organization Domains",
|
||||
"domainPickerProvidedDomains": "Provided Domains",
|
||||
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"domainPickerShowMore": "Show More",
|
||||
"domainNotFound": "Domain Not Found",
|
||||
"domainNotFoundDescription": "This resource is disabled because the domain no longer exists our system. Please set a new domain for this resource.",
|
||||
"failed": "Failed",
|
||||
"createNewOrgDescription": "Create a new organization",
|
||||
"organization": "Organization",
|
||||
"port": "Port",
|
||||
"securityKeyManage": "Manage Security Keys",
|
||||
"securityKeyDescription": "Add or remove security keys for passwordless authentication",
|
||||
"securityKeyRegister": "Register New Security Key",
|
||||
"securityKeyList": "Your Security Keys",
|
||||
"securityKeyNone": "No security keys registered yet",
|
||||
"securityKeyNameRequired": "Name is required",
|
||||
"securityKeyRemove": "Remove",
|
||||
"securityKeyLastUsed": "Last used: {date}",
|
||||
"securityKeyNameLabel": "Security Key Name",
|
||||
"securityKeyRegisterSuccess": "Security key registered successfully",
|
||||
"securityKeyRegisterError": "Failed to register security key",
|
||||
"securityKeyRemoveSuccess": "Security key removed successfully",
|
||||
"securityKeyRemoveError": "Failed to remove security key",
|
||||
"securityKeyLoadError": "Failed to load security keys",
|
||||
"securityKeyLogin": "Continue with security key",
|
||||
"securityKeyAuthError": "Failed to authenticate with security key",
|
||||
"securityKeyRecommendation": "Register a backup security key on another device to ensure you always have access to your account.",
|
||||
"registering": "Registering...",
|
||||
"securityKeyPrompt": "Please verify your identity using your security key. Make sure your security key is connected and ready.",
|
||||
"securityKeyBrowserNotSupported": "Your browser doesn't support security keys. Please use a modern browser like Chrome, Firefox, or Safari.",
|
||||
"securityKeyPermissionDenied": "Please allow access to your security key to continue signing in.",
|
||||
"securityKeyRemovedTooQuickly": "Please keep your security key connected until the sign-in process completes.",
|
||||
"securityKeyNotSupported": "Your security key may not be compatible. Please try a different security key.",
|
||||
"securityKeyUnknownError": "There was a problem using your security key. Please try again.",
|
||||
"twoFactorRequired": "Two-factor authentication is required to register a security key.",
|
||||
"twoFactor": "Two-Factor Authentication",
|
||||
"adminEnabled2FaOnYourAccount": "Your administrator has enabled two-factor authentication for {email}. Please complete the setup process to continue.",
|
||||
"continueToApplication": "Continue to Application",
|
||||
"securityKeyAdd": "Add Security Key",
|
||||
"securityKeyRegisterTitle": "Register New Security Key",
|
||||
"securityKeyRegisterDescription": "Connect your security key and enter a name to identify it",
|
||||
"securityKeyTwoFactorRequired": "Two-Factor Authentication Required",
|
||||
"securityKeyTwoFactorDescription": "Please enter your two-factor authentication code to register the security key",
|
||||
"securityKeyTwoFactorRemoveDescription": "Please enter your two-factor authentication code to remove the security key",
|
||||
"securityKeyTwoFactorCode": "Two-Factor Code",
|
||||
"securityKeyRemoveTitle": "Remove Security Key",
|
||||
"securityKeyRemoveDescription": "Enter your password to remove the security key \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "No security keys registered",
|
||||
"securityKeyNoKeysDescription": "Add a security key to enhance your account security",
|
||||
"createDomainRequired": "Domain is required",
|
||||
"createDomainAddDnsRecords": "Add DNS Records",
|
||||
"createDomainAddDnsRecordsDescription": "Add the following DNS records to your domain provider to complete the setup.",
|
||||
"createDomainNsRecords": "NS Records",
|
||||
"createDomainRecord": "Record",
|
||||
"createDomainType": "Type:",
|
||||
"createDomainName": "Name:",
|
||||
"createDomainValue": "Value:",
|
||||
"createDomainCnameRecords": "CNAME Records",
|
||||
"createDomainARecords": "A Records",
|
||||
"createDomainRecordNumber": "Record {number}",
|
||||
"createDomainTxtRecords": "TXT Records",
|
||||
"createDomainSaveTheseRecords": "Save These Records",
|
||||
"createDomainSaveTheseRecordsDescription": "Make sure to save these DNS records as you will not see them again.",
|
||||
"createDomainDnsPropagation": "DNS Propagation",
|
||||
"createDomainDnsPropagationDescription": "DNS changes may take some time to propagate across the internet. This can take anywhere from a few minutes to 48 hours, depending on your DNS provider and TTL settings.",
|
||||
"resourcePortRequired": "Port number is required for non-HTTP resources",
|
||||
"resourcePortNotAllowed": "Port number should not be set for HTTP resources",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "I agree to the",
|
||||
"termsOfService": "terms of service",
|
||||
"and": "and",
|
||||
"privacyPolicy": "privacy policy"
|
||||
},
|
||||
"siteRequired": "Site is required.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Use Olm for client connectivity",
|
||||
"errorCreatingClient": "Error creating client",
|
||||
"clientDefaultsNotFound": "Client defaults not found",
|
||||
"createClient": "Create Client",
|
||||
"createClientDescription": "Create a new client for connecting to your sites",
|
||||
"seeAllClients": "See All Clients",
|
||||
"clientInformation": "Client Information",
|
||||
"clientNamePlaceholder": "Client name",
|
||||
"address": "Address",
|
||||
"subnetPlaceholder": "Subnet",
|
||||
"addressDescription": "The address that this client will use for connectivity",
|
||||
"selectSites": "Select sites",
|
||||
"sitesDescription": "The client will have connectivity to the selected sites",
|
||||
"clientInstallOlm": "Install Olm",
|
||||
"clientInstallOlmDescription": "Get Olm running on your system",
|
||||
"clientOlmCredentials": "Olm Credentials",
|
||||
"clientOlmCredentialsDescription": "This is how Olm will authenticate with the server",
|
||||
"olmEndpoint": "Olm Endpoint",
|
||||
"olmId": "Olm ID",
|
||||
"olmSecretKey": "Olm Secret Key",
|
||||
"clientCredentialsSave": "Save Your Credentials",
|
||||
"clientCredentialsSaveDescription": "You will only be able to see this once. Make sure to copy it to a secure place.",
|
||||
"generalSettingsDescription": "Configure the general settings for this client",
|
||||
"clientUpdated": "Client updated",
|
||||
"clientUpdatedDescription": "The client has been updated.",
|
||||
"clientUpdateFailed": "Failed to update client",
|
||||
"clientUpdateError": "An error occurred while updating the client.",
|
||||
"sitesFetchFailed": "Failed to fetch sites",
|
||||
"sitesFetchError": "An error occurred while fetching sites.",
|
||||
"olmErrorFetchReleases": "An error occurred while fetching Olm releases.",
|
||||
"olmErrorFetchLatest": "An error occurred while fetching the latest Olm release.",
|
||||
"remoteSubnets": "Remote Subnets",
|
||||
"enterCidrRange": "Enter CIDR range",
|
||||
"remoteSubnetsDescription": "Add CIDR ranges that can be accessed from this site remotely using clients. Use format like 10.0.0.0/24. This ONLY applies to VPN client connectivity.",
|
||||
"resourceEnableProxy": "Enable Public Proxy",
|
||||
"resourceEnableProxyDescription": "Enable public proxying to this resource. This allows access to the resource from outside the network through the cloud on an open port. Requires Traefik config.",
|
||||
"externalProxyEnabled": "External Proxy Enabled",
|
||||
"addNewTarget": "Add New Target",
|
||||
"targetsList": "Targets List",
|
||||
"targetErrorDuplicateTargetFound": "Duplicate target found",
|
||||
"httpMethod": "HTTP Method",
|
||||
"selectHttpMethod": "Select HTTP method",
|
||||
"domainPickerSubdomainLabel": "Subdomain",
|
||||
"domainPickerBaseDomainLabel": "Base Domain",
|
||||
"domainPickerSearchDomains": "Search domains...",
|
||||
"domainPickerNoDomainsFound": "No domains found",
|
||||
"domainPickerLoadingDomains": "Loading domains...",
|
||||
"domainPickerSelectBaseDomain": "Select base domain...",
|
||||
"domainPickerNotAvailableForCname": "Not available for CNAME domains",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Enter subdomain or leave blank to use base domain.",
|
||||
"domainPickerEnterSubdomainToSearch": "Enter a subdomain to search and select from available free domains.",
|
||||
"domainPickerFreeDomains": "Free Domains",
|
||||
"domainPickerSearchForAvailableDomains": "Search for available domains",
|
||||
"resourceDomain": "Domain",
|
||||
"resourceEditDomain": "Edit Domain",
|
||||
"siteName": "Site Name",
|
||||
"proxyPort": "Port",
|
||||
"resourcesTableProxyResources": "Proxy Resources",
|
||||
"resourcesTableClientResources": "Client Resources",
|
||||
"resourcesTableNoProxyResourcesFound": "No proxy resources found.",
|
||||
"resourcesTableNoInternalResourcesFound": "No internal resources found.",
|
||||
"resourcesTableDestination": "Destination",
|
||||
"resourcesTableTheseResourcesForUseWith": "These resources are for use with",
|
||||
"resourcesTableClients": "Clients",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "and are only accessible internally when connected with a client.",
|
||||
"editInternalResourceDialogEditClientResource": "Edit Client Resource",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Update the resource properties and target configuration for {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Resource Properties",
|
||||
"editInternalResourceDialogName": "Name",
|
||||
"editInternalResourceDialogProtocol": "Protocol",
|
||||
"editInternalResourceDialogSitePort": "Site Port",
|
||||
"editInternalResourceDialogTargetConfiguration": "Target Configuration",
|
||||
"editInternalResourceDialogCancel": "Cancel",
|
||||
"editInternalResourceDialogSaveResource": "Save Resource",
|
||||
"editInternalResourceDialogSuccess": "Success",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Internal resource updated successfully",
|
||||
"editInternalResourceDialogError": "Error",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update internal resource",
|
||||
"editInternalResourceDialogNameRequired": "Name is required",
|
||||
"editInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy port must be at least 1",
|
||||
"editInternalResourceDialogProxyPortMax": "Proxy port must be less than 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Invalid IP address format",
|
||||
"editInternalResourceDialogDestinationPortMin": "Destination port must be at least 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "Destination port must be less than 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "No Sites Available",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create internal resources.",
|
||||
"createInternalResourceDialogClose": "Close",
|
||||
"createInternalResourceDialogCreateClientResource": "Create Client Resource",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will be accessible to clients connected to the selected site.",
|
||||
"createInternalResourceDialogResourceProperties": "Resource Properties",
|
||||
"createInternalResourceDialogName": "Name",
|
||||
"createInternalResourceDialogSite": "Site",
|
||||
"createInternalResourceDialogSelectSite": "Select site...",
|
||||
"createInternalResourceDialogSearchSites": "Search sites...",
|
||||
"createInternalResourceDialogNoSitesFound": "No sites found.",
|
||||
"createInternalResourceDialogProtocol": "Protocol",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Site Port",
|
||||
"createInternalResourceDialogSitePortDescription": "Use this port to access the resource on the site when connected with a client.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Target Configuration",
|
||||
"createInternalResourceDialogDestinationIPDescription": "The IP or hostname address of the resource on the site's network.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "The port on the destination IP where the resource is accessible.",
|
||||
"createInternalResourceDialogCancel": "Cancel",
|
||||
"createInternalResourceDialogCreateResource": "Create Resource",
|
||||
"createInternalResourceDialogSuccess": "Success",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Internal resource created successfully",
|
||||
"createInternalResourceDialogError": "Error",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Failed to create internal resource",
|
||||
"createInternalResourceDialogNameRequired": "Name is required",
|
||||
"createInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Please select a site",
|
||||
"createInternalResourceDialogProxyPortMin": "Proxy port must be at least 1",
|
||||
"createInternalResourceDialogProxyPortMax": "Proxy port must be less than 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Invalid IP address format",
|
||||
"createInternalResourceDialogDestinationPortMin": "Destination port must be at least 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "Destination port must be less than 65536",
|
||||
"siteConfiguration": "Configuration",
|
||||
"siteAcceptClientConnections": "Accept Client Connections",
|
||||
"siteAcceptClientConnectionsDescription": "Allow other devices to connect through this Newt instance as a gateway using clients.",
|
||||
"siteAddress": "Site Address",
|
||||
"siteAddressDescription": "Specify the IP address of the host for clients to connect to. This is the internal address of the site in the Pangolin network for clients to address. Must fall within the Org subnet.",
|
||||
"autoLoginExternalIdp": "Auto Login with External IDP",
|
||||
"autoLoginExternalIdpDescription": "Immediately redirect the user to the external IDP for authentication.",
|
||||
"selectIdp": "Select IDP",
|
||||
"selectIdpPlaceholder": "Choose an IDP...",
|
||||
"selectIdpRequired": "Please select an IDP when auto login is enabled.",
|
||||
"autoLoginTitle": "Redirecting",
|
||||
"autoLoginDescription": "Redirecting you to the external identity provider for authentication.",
|
||||
"autoLoginProcessing": "Preparing authentication...",
|
||||
"autoLoginRedirecting": "Redirecting to login...",
|
||||
"autoLoginError": "Auto Login Error",
|
||||
"autoLoginErrorNoRedirectUrl": "No redirect URL received from the identity provider.",
|
||||
"autoLoginErrorGeneratingUrl": "Failed to generate authentication URL.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Managed Self-Hosted",
|
||||
"description": "More reliable and low-maintenance self-hosted Pangolin server with extra bells and whistles",
|
||||
"introTitle": "Managed Self-Hosted Pangolin",
|
||||
"introDescription": "is a deployment option designed for people who want simplicity and extra reliability while still keeping their data private and self-hosted.",
|
||||
"introDetail": "With this option, you still run your own Pangolin node — your tunnels, SSL termination, and traffic all stay on your server. The difference is that management and monitoring are handled through our cloud dashboard, which unlocks a number of benefits:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Simpler operations",
|
||||
"description": "No need to run your own mail server or set up complex alerting. You'll get health checks and downtime alerts out of the box."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Automatic updates",
|
||||
"description": "The cloud dashboard evolves quickly, so you get new features and bug fixes without having to manually pull new containers every time."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Less maintenance",
|
||||
"description": "No database migrations, backups, or extra infrastructure to manage. We handle that in the cloud."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Cloud failover",
|
||||
"description": "If your node goes down, your tunnels can temporarily fail over to our cloud points of presence until you bring it back online."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "High availability (PoPs)",
|
||||
"description": "You can also attach multiple nodes to your account for redundancy and better performance."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Future enhancements",
|
||||
"description": "We're planning to add more analytics, alerting, and management tools to make your deployment even more robust."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Learn more about the Managed Self-Hosted option in our",
|
||||
"documentation": "documentation"
|
||||
},
|
||||
"convertButton": "Convert This Node to Managed Self-Hosted"
|
||||
},
|
||||
"internationaldomaindetected": "International Domain Detected",
|
||||
"willbestoredas": "Will be stored as:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC provider",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Custom Headers",
|
||||
"headersValidationError": "Headers must be in the format: Header-Name: value.",
|
||||
"domainPickerProvidedDomain": "Provided Domain",
|
||||
"domainPickerFreeProvidedDomain": "Free Provided Domain",
|
||||
"domainPickerVerified": "Verified",
|
||||
"domainPickerUnverified": "Unverified",
|
||||
"domainPickerInvalidSubdomainStructure": "This subdomain contains invalid characters or structure. It will be sanitized automatically when you save.",
|
||||
"domainPickerError": "Error",
|
||||
"domainPickerErrorLoadDomains": "Failed to load organization domains",
|
||||
"domainPickerErrorCheckAvailability": "Failed to check domain availability",
|
||||
"domainPickerInvalidSubdomain": "Invalid subdomain",
|
||||
"domainPickerInvalidSubdomainRemoved": "The input \"{sub}\" was removed because it's not valid.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" could not be made valid for {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Subdomain sanitized",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" was corrected to \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Edit file: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Edit file: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "Actualmente no eres miembro de ninguna organización. Crea una organización para empezar.",
|
||||
"componentsErrorNoMember": "Actualmente no eres miembro de ninguna organización.",
|
||||
"welcome": "Bienvenido a Pangolin",
|
||||
"welcomeTo": "Bienvenido a",
|
||||
"componentsCreateOrg": "Crear una organización",
|
||||
"componentsMember": "¡Eres un miembro de {count, plural, =0 {¡Ninguna organización} =1 {¡una organización} other {# organizaciones}}.",
|
||||
"componentsMember": "Eres un miembro de {count, plural, =0 {ninguna organización} one {una organización} other {# organizaciones}}.",
|
||||
"componentsInvalidKey": "Se han detectado claves de licencia inválidas o caducadas. Siga los términos de licencia para seguir usando todas las características.",
|
||||
"dismiss": "Descartar",
|
||||
"componentsLicenseViolation": "Violación de la Licencia: Este servidor está usando sitios {usedSites} que exceden su límite de licencias de sitios {maxSites} . Siga los términos de licencia para seguir usando todas las características.",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Error al crear el sitio",
|
||||
"siteErrorCreateKeyPair": "Por defecto no se encuentra el par de claves o el sitio",
|
||||
"siteErrorCreateDefaults": "Sitio por defecto no encontrado",
|
||||
"siteNameDescription": "Este es el nombre para mostrar el sitio.",
|
||||
"method": "Método",
|
||||
"siteMethodDescription": "Así es como se expondrán las conexiones.",
|
||||
"siteLearnNewt": "Aprende cómo instalar Newt en tu sistema",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "La forma más fácil de crear un punto de entrada en tu red. Sin configuración adicional.",
|
||||
"siteWg": "Wirex Guardia Básica",
|
||||
"siteWgDescription": "Utilice cualquier cliente Wirex Guard para establecer un túnel. Se requiere una configuración manual de NAT.",
|
||||
"siteWgDescriptionSaas": "Utilice cualquier cliente de WireGuard para establecer un túnel. Se requiere configuración manual de NAT. SOLO FUNCIONA EN NODOS AUTOGESTIONADOS",
|
||||
"siteLocalDescription": "Solo recursos locales. Sin túneles.",
|
||||
"siteLocalDescriptionSaas": "Solo recursos locales. Sin túneles. SOLO FUNCIONA EN NODOS AUTOGESTIONADOS",
|
||||
"siteSeeAll": "Ver todos los sitios",
|
||||
"siteTunnelDescription": "Determina cómo quieres conectarte a tu sitio",
|
||||
"siteNewtCredentials": "Credenciales nuevas",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Seleccionar sitio",
|
||||
"siteSearch": "Buscar sitio",
|
||||
"siteNotFound": "Sitio no encontrado.",
|
||||
"siteSelectionDescription": "Este sitio proporcionará conectividad al recurso.",
|
||||
"siteSelectionDescription": "Este sitio proporcionará conectividad al objetivo.",
|
||||
"resourceType": "Tipo de recurso",
|
||||
"resourceTypeDescription": "Determina cómo quieres acceder a tu recurso",
|
||||
"resourceHTTPSSettings": "Configuración HTTPS",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "General",
|
||||
"generalSettings": "Configuración General",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Interno",
|
||||
"rules": "Reglas",
|
||||
"resourceSettingDescription": "Configure la configuración de su recurso",
|
||||
"resourceSetting": "Ajustes {resourceName}",
|
||||
"alwaysAllow": "Permitir siempre",
|
||||
"alwaysDeny": "Denegar siempre",
|
||||
"passToAuth": "Pasar a Autenticación",
|
||||
"orgSettingsDescription": "Configurar la configuración general de su organización",
|
||||
"orgGeneralSettings": "Configuración de la organización",
|
||||
"orgGeneralSettingsDescription": "Administra los detalles y la configuración de tu organización",
|
||||
"saveGeneralSettings": "Guardar ajustes generales",
|
||||
"saveSettings": "Guardar ajustes",
|
||||
"orgDangerZone": "Zona de peligro",
|
||||
"orgDangerZoneDescription": "Una vez que elimines este órgano, no hay vuelta atrás. Por favor, asegúrate de ello.",
|
||||
"orgDelete": "Eliminar organización",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Semanas",
|
||||
"months": "Meses",
|
||||
"years": "Años",
|
||||
"day": "{count, plural, =1 {# día} other {# días}}",
|
||||
"day": "{count, plural, one {# día} other {# días}}",
|
||||
"apiKeysTitle": "Información de Clave API",
|
||||
"apiKeysConfirmCopy2": "Debes confirmar que has copiado la clave API.",
|
||||
"apiKeysErrorCreate": "Error al crear la clave API",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Comprar Licencia",
|
||||
"licensePurchaseSites": "Comprar sitios adicionales",
|
||||
"licenseSitesUsedMax": "{usedSites} de {maxSites} sitios usados",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sitios} =1 {# sitio} other {# sitios}} en el sistema.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sitios} one {# sitio} other {# sitios}} en el sistema.",
|
||||
"licensePurchaseDescription": "Elige cuántos sitios quieres {selectedMode, select, license {compra una licencia para. Siempre puedes añadir más sitios más tarde.} other {añadir a tu licencia existente.}}",
|
||||
"licenseFee": "Tarifa de licencia",
|
||||
"licensePriceSite": "Precio por sitio",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Seleccionar rol",
|
||||
"inviteEmailSentDescription": "Se ha enviado un correo electrónico al usuario con el siguiente enlace de acceso. Debe acceder al enlace para aceptar la invitación.",
|
||||
"inviteSentDescription": "El usuario ha sido invitado. Debe acceder al enlace de abajo para aceptar la invitación.",
|
||||
"inviteExpiresIn": "La invitación expirará en {days, plural, =1 {# día} other {# días}}.",
|
||||
"inviteExpiresIn": "La invitación expirará en {days, plural, one {# día} other {# días}}.",
|
||||
"idpTitle": "Proveedor de identidad",
|
||||
"idpSelect": "Seleccione el proveedor de identidad para el usuario externo",
|
||||
"idpNotConfigured": "No hay proveedores de identidad configurados. Por favor, configure un proveedor de identidad antes de crear usuarios externos.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Ocurrió un error mientras se añadía el usuario al rol.",
|
||||
"userSaved": "Usuario guardado",
|
||||
"userSavedDescription": "El usuario ha sido actualizado.",
|
||||
"autoProvisioned": "Auto asegurado",
|
||||
"autoProvisionedDescription": "Permitir a este usuario ser administrado automáticamente por el proveedor de identidad",
|
||||
"accessControlsDescription": "Administrar lo que este usuario puede acceder y hacer en la organización",
|
||||
"accessControlsSubmit": "Guardar controles de acceso",
|
||||
"roles": "Roles",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Formato de dirección IP inválido",
|
||||
"ipAddressErrorInvalidOctet": "Octet de dirección IP no válido",
|
||||
"path": "Ruta",
|
||||
"matchPath": "Coincidir ruta",
|
||||
"ipAddressRange": "Rango IP",
|
||||
"rulesErrorFetch": "Error al obtener las reglas",
|
||||
"rulesErrorFetchDescription": "Se ha producido un error al recuperar las reglas",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Acciones",
|
||||
"rulesActionAlwaysAllow": "Permitir siempre: pasar todos los métodos de autenticación",
|
||||
"rulesActionAlwaysDeny": "Denegar siempre: Bloquear todas las peticiones; no se puede intentar autenticación",
|
||||
"rulesActionPassToAuth": "Pasar a Autenticación: Permitir que se intenten los métodos de autenticación",
|
||||
"rulesMatchCriteria": "Criterios coincidentes",
|
||||
"rulesMatchCriteriaIpAddress": "Coincidir con una dirección IP específica",
|
||||
"rulesMatchCriteriaIpAddressRange": "Coincide con un rango de direcciones IP en notación CIDR",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "El PIN debe tener exactamente 6 dígitos",
|
||||
"pincodeRequirementsChars": "El PIN sólo debe contener números",
|
||||
"passwordRequirementsLength": "La contraseña debe tener al menos 1 carácter",
|
||||
"passwordRequirementsTitle": "Requisitos de la contraseña:",
|
||||
"passwordRequirementLength": "Al menos 8 caracteres de largo",
|
||||
"passwordRequirementUppercase": "Al menos una letra mayúscula",
|
||||
"passwordRequirementLowercase": "Al menos una letra minúscula",
|
||||
"passwordRequirementNumber": "Al menos un número",
|
||||
"passwordRequirementSpecial": "Al menos un carácter especial",
|
||||
"passwordRequirementsMet": "✓ La contraseña cumple con todos los requisitos",
|
||||
"passwordStrength": "Seguridad de la contraseña",
|
||||
"passwordStrengthWeak": "Débil",
|
||||
"passwordStrengthMedium": "Media",
|
||||
"passwordStrengthStrong": "Fuerte",
|
||||
"passwordRequirements": "Requisitos:",
|
||||
"passwordRequirementLengthText": "8+ caracteres",
|
||||
"passwordRequirementUppercaseText": "Letra mayúscula (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Letra minúscula (a-z)",
|
||||
"passwordRequirementNumberText": "Número (0-9)",
|
||||
"passwordRequirementSpecialText": "Caracter especial (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Las contraseñas no coinciden",
|
||||
"otpEmailRequirementsLength": "OTP debe tener al menos 1 carácter",
|
||||
"otpEmailSent": "OTP enviado",
|
||||
"otpEmailSentDescription": "Un OTP ha sido enviado a tu correo electrónico",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Conectado",
|
||||
"idpErrorConnectingTo": "Hubo un problema al conectar con {name}. Por favor, póngase en contacto con su administrador.",
|
||||
"idpErrorNotFound": "IdP no encontrado",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Invitación inválida",
|
||||
"inviteInvalidDescription": "El enlace de invitación no es válido.",
|
||||
"inviteErrorWrongUser": "La invitación no es para este usuario",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Error al cerrar sesión",
|
||||
"signingAs": "Conectado como",
|
||||
"serverAdmin": "Admin Servidor",
|
||||
"managedSelfhosted": "Autogestionado",
|
||||
"otpEnable": "Activar doble factor",
|
||||
"otpDisable": "Desactivar doble factor",
|
||||
"logout": "Cerrar sesión",
|
||||
"licenseTierProfessionalRequired": "Edición Profesional requerida",
|
||||
"licenseTierProfessionalRequiredDescription": "Esta característica sólo está disponible en la Edición Profesional.",
|
||||
"actionGetOrg": "Obtener organización",
|
||||
"updateOrgUser": "Actualizar usuario Org",
|
||||
"createOrgUser": "Crear usuario Org",
|
||||
"actionUpdateOrg": "Actualizar organización",
|
||||
"actionUpdateUser": "Actualizar usuario",
|
||||
"actionGetUser": "Obtener usuario",
|
||||
"actionGetOrgUser": "Obtener usuario de la organización",
|
||||
"actionListOrgDomains": "Listar dominios de la organización",
|
||||
"actionCreateSite": "Crear sitio",
|
||||
"actionDeleteSite": "Eliminar sitio",
|
||||
"actionGetSite": "Obtener sitio",
|
||||
"actionListSites": "Listar sitios",
|
||||
"actionApplyBlueprint": "Aplicar plano",
|
||||
"setupToken": "Configuración de token",
|
||||
"setupTokenDescription": "Ingrese el token de configuración desde la consola del servidor.",
|
||||
"setupTokenRequired": "Se requiere el token de configuración",
|
||||
"actionUpdateSite": "Actualizar sitio",
|
||||
"actionListSiteRoles": "Lista de roles permitidos del sitio",
|
||||
"actionCreateResource": "Crear Recurso",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Eliminar política de IDP Org",
|
||||
"actionListIdpOrgs": "Listar Orgs IDP",
|
||||
"actionUpdateIdpOrg": "Actualizar IDP Org",
|
||||
"actionCreateClient": "Crear cliente",
|
||||
"actionDeleteClient": "Eliminar cliente",
|
||||
"actionUpdateClient": "Actualizar cliente",
|
||||
"actionListClients": "Listar clientes",
|
||||
"actionGetClient": "Obtener cliente",
|
||||
"actionCreateSiteResource": "Crear Recurso del Sitio",
|
||||
"actionDeleteSiteResource": "Eliminar recurso del sitio",
|
||||
"actionGetSiteResource": "Obtener recurso del sitio",
|
||||
"actionListSiteResources": "Listar recursos del sitio",
|
||||
"actionUpdateSiteResource": "Actualizar recurso del sitio",
|
||||
"actionListInvitations": "Listar invitaciones",
|
||||
"noneSelected": "Ninguno seleccionado",
|
||||
"orgNotFound2": "No se encontraron organizaciones.",
|
||||
"searchProgress": "Buscar...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Todos los usuarios",
|
||||
"sidebarIdentityProviders": "Proveedores de identidad",
|
||||
"sidebarLicense": "Licencia",
|
||||
"enableDockerSocket": "Habilitar conector Docker",
|
||||
"enableDockerSocketDescription": "Habilitar el descubrimiento de Docker Socket para completar la información del contenedor. La ruta del socket debe proporcionarse a Newt.",
|
||||
"sidebarClients": "Clientes (Beta)",
|
||||
"sidebarDomains": "Dominios",
|
||||
"enableDockerSocket": "Habilitar Plano Docker",
|
||||
"enableDockerSocketDescription": "Activar el raspado de etiquetas de Socket Docker para etiquetas de planos. La ruta del Socket debe proporcionarse a Newt.",
|
||||
"enableDockerSocketLink": "Saber más",
|
||||
"viewDockerContainers": "Ver contenedores Docker",
|
||||
"containersIn": "Contenedores en {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Redes",
|
||||
"containerHostnameIp": "Nombre del host/IP",
|
||||
"containerLabels": "Etiquetas",
|
||||
"containerLabelsCount": "{count} etiqueta{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# etiqueta} other {# etiquetas}}",
|
||||
"containerLabelsTitle": "Etiquetas de contenedor",
|
||||
"containerLabelEmpty": "<vacío>",
|
||||
"containerPorts": "Puertos",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Mostrar contenedores parados",
|
||||
"noContainersFound": "No se han encontrado contenedores. Asegúrate de que los contenedores Docker se estén ejecutando.",
|
||||
"searchContainersPlaceholder": "Buscar a través de contenedores {count}...",
|
||||
"searchResultsCount": "{count} resultado{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# resultado} other {# resultados}}",
|
||||
"filters": "Filtros",
|
||||
"filterOptions": "Opciones de filtro",
|
||||
"filterPorts": "Puertos",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "oscuro",
|
||||
"system": "sistema",
|
||||
"theme": "Tema",
|
||||
"subnetRequired": "Se requiere subred",
|
||||
"initialSetupTitle": "Configuración inicial del servidor",
|
||||
"initialSetupDescription": "Cree la cuenta de administrador del servidor inicial. Solo puede existir un administrador del servidor. Siempre puede cambiar estas credenciales más tarde.",
|
||||
"createAdminAccount": "Crear cuenta de administrador",
|
||||
"setupErrorCreateAdmin": "Se produjo un error al crear la cuenta de administrador del servidor."
|
||||
"setupErrorCreateAdmin": "Se produjo un error al crear la cuenta de administrador del servidor.",
|
||||
"certificateStatus": "Estado del certificado",
|
||||
"loading": "Cargando",
|
||||
"restart": "Reiniciar",
|
||||
"domains": "Dominios",
|
||||
"domainsDescription": "Administrar dominios de tu organización",
|
||||
"domainsSearch": "Buscar dominios...",
|
||||
"domainAdd": "Agregar dominio",
|
||||
"domainAddDescription": "Registrar un nuevo dominio con tu organización",
|
||||
"domainCreate": "Crear dominio",
|
||||
"domainCreatedDescription": "Dominio creado con éxito",
|
||||
"domainDeletedDescription": "Dominio eliminado exitosamente",
|
||||
"domainQuestionRemove": "¿Está seguro de que desea eliminar el dominio {domain} de su cuenta?",
|
||||
"domainMessageRemove": "Una vez eliminado, el dominio ya no estará asociado con su cuenta.",
|
||||
"domainMessageConfirm": "Para confirmar, por favor escriba el nombre del dominio abajo.",
|
||||
"domainConfirmDelete": "Confirmar eliminación del dominio",
|
||||
"domainDelete": "Eliminar dominio",
|
||||
"domain": "Dominio",
|
||||
"selectDomainTypeNsName": "Delegación de dominio (NS)",
|
||||
"selectDomainTypeNsDescription": "Este dominio y todos sus subdominios. Usa esto cuando quieras controlar una zona de dominio completa.",
|
||||
"selectDomainTypeCnameName": "Dominio único (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Solo este dominio específico. Úsalo para subdominios individuales o entradas específicas de dominio.",
|
||||
"selectDomainTypeWildcardName": "Dominio comodín",
|
||||
"selectDomainTypeWildcardDescription": "Este dominio y sus subdominios.",
|
||||
"domainDelegation": "Dominio único",
|
||||
"selectType": "Selecciona un tipo",
|
||||
"actions": "Acciones",
|
||||
"refresh": "Actualizar",
|
||||
"refreshError": "Error al actualizar datos",
|
||||
"verified": "Verificado",
|
||||
"pending": "Pendiente",
|
||||
"sidebarBilling": "Facturación",
|
||||
"billing": "Facturación",
|
||||
"orgBillingDescription": "Gestiona tu información de facturación y suscripciones",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hosted",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Completar configuración de cuenta",
|
||||
"completeAccountSetupDescription": "Establece tu contraseña para comenzar",
|
||||
"accountSetupSent": "Enviaremos un código de configuración de cuenta a esta dirección de correo electrónico.",
|
||||
"accountSetupCode": "Código de configuración",
|
||||
"accountSetupCodeDescription": "Revisa tu correo para el código de configuración.",
|
||||
"passwordCreate": "Crear contraseña",
|
||||
"passwordCreateConfirm": "Confirmar contraseña",
|
||||
"accountSetupSubmit": "Enviar código de configuración",
|
||||
"completeSetup": "Completar configuración",
|
||||
"accountSetupSuccess": "¡Configuración de cuenta completada! ¡Bienvenido a Pangolin!",
|
||||
"documentation": "Documentación",
|
||||
"saveAllSettings": "Guardar todos los ajustes",
|
||||
"settingsUpdated": "Ajustes actualizados",
|
||||
"settingsUpdatedDescription": "Todos los ajustes han sido actualizados exitosamente",
|
||||
"settingsErrorUpdate": "Error al actualizar ajustes",
|
||||
"settingsErrorUpdateDescription": "Ocurrió un error al actualizar ajustes",
|
||||
"sidebarCollapse": "Colapsar",
|
||||
"sidebarExpand": "Expandir",
|
||||
"newtUpdateAvailable": "Nueva actualización disponible",
|
||||
"newtUpdateAvailableInfo": "Hay una nueva versión de Newt disponible. Actualice a la última versión para la mejor experiencia.",
|
||||
"domainPickerEnterDomain": "Dominio",
|
||||
"domainPickerPlaceholder": "miapp.ejemplo.com",
|
||||
"domainPickerDescription": "Ingresa el dominio completo del recurso para ver las opciones disponibles.",
|
||||
"domainPickerDescriptionSaas": "Ingresa un dominio completo, subdominio o simplemente un nombre para ver las opciones disponibles",
|
||||
"domainPickerTabAll": "Todo",
|
||||
"domainPickerTabOrganization": "Organización",
|
||||
"domainPickerTabProvided": "Proporcionado",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Comprobando disponibilidad...",
|
||||
"domainPickerNoMatchingDomains": "No se encontraron dominios que coincidan. Intente con un dominio diferente o verifique la configuración de dominios de su organización.",
|
||||
"domainPickerOrganizationDomains": "Dominios de la organización",
|
||||
"domainPickerProvidedDomains": "Dominios proporcionados",
|
||||
"domainPickerSubdomain": "Subdominio: {subdomain}",
|
||||
"domainPickerNamespace": "Espacio de nombres: {namespace}",
|
||||
"domainPickerShowMore": "Mostrar más",
|
||||
"domainNotFound": "Dominio no encontrado",
|
||||
"domainNotFoundDescription": "Este recurso está deshabilitado porque el dominio ya no existe en nuestro sistema. Por favor, establece un nuevo dominio para este recurso.",
|
||||
"failed": "Fallido",
|
||||
"createNewOrgDescription": "Crear una nueva organización",
|
||||
"organization": "Organización",
|
||||
"port": "Puerto",
|
||||
"securityKeyManage": "Gestionar llaves de seguridad",
|
||||
"securityKeyDescription": "Agregar o eliminar llaves de seguridad para autenticación sin contraseña",
|
||||
"securityKeyRegister": "Registrar nueva llave de seguridad",
|
||||
"securityKeyList": "Tus llaves de seguridad",
|
||||
"securityKeyNone": "No hay llaves de seguridad registradas",
|
||||
"securityKeyNameRequired": "El nombre es requerido",
|
||||
"securityKeyRemove": "Eliminar",
|
||||
"securityKeyLastUsed": "Último uso: {date}",
|
||||
"securityKeyNameLabel": "Nombre",
|
||||
"securityKeyRegisterSuccess": "Llave de seguridad registrada exitosamente",
|
||||
"securityKeyRegisterError": "Error al registrar la llave de seguridad",
|
||||
"securityKeyRemoveSuccess": "Llave de seguridad eliminada exitosamente",
|
||||
"securityKeyRemoveError": "Error al eliminar la llave de seguridad",
|
||||
"securityKeyLoadError": "Error al cargar las llaves de seguridad",
|
||||
"securityKeyLogin": "Continuar con clave de seguridad",
|
||||
"securityKeyAuthError": "Error al autenticar con llave de seguridad",
|
||||
"securityKeyRecommendation": "Considere registrar otra llave de seguridad en un dispositivo diferente para asegurarse de no quedar bloqueado de su cuenta.",
|
||||
"registering": "Registrando...",
|
||||
"securityKeyPrompt": "Por favor, verifica tu identidad usando tu llave de seguridad. Asegúrate de que tu llave de seguridad esté conectada y lista.",
|
||||
"securityKeyBrowserNotSupported": "Tu navegador no admite llaves de seguridad. Por favor, usa un navegador moderno como Chrome, Firefox o Safari.",
|
||||
"securityKeyPermissionDenied": "Por favor, permite el acceso a tu llave de seguridad para continuar iniciando sesión.",
|
||||
"securityKeyRemovedTooQuickly": "Por favor, mantén tu llave de seguridad conectada hasta que el proceso de inicio de sesión se complete.",
|
||||
"securityKeyNotSupported": "Tu llave de seguridad puede no ser compatible. Por favor, prueba con una llave de seguridad diferente.",
|
||||
"securityKeyUnknownError": "Hubo un problema al usar tu llave de seguridad. Por favor, inténtalo de nuevo.",
|
||||
"twoFactorRequired": "Se requiere autenticación de dos factores para registrar una llave de seguridad.",
|
||||
"twoFactor": "Autenticación de dos factores",
|
||||
"adminEnabled2FaOnYourAccount": "Su administrador ha habilitado la autenticación de dos factores para {email}. Por favor, complete el proceso de configuración para continuar.",
|
||||
"continueToApplication": "Continuar a la aplicación",
|
||||
"securityKeyAdd": "Agregar llave de seguridad",
|
||||
"securityKeyRegisterTitle": "Registrar nueva llave de seguridad",
|
||||
"securityKeyRegisterDescription": "Conecta tu llave de seguridad y escribe un nombre para identificarla",
|
||||
"securityKeyTwoFactorRequired": "Se requiere autenticación de dos factores",
|
||||
"securityKeyTwoFactorDescription": "Por favor, ingresa tu código de autenticación de dos factores para registrar la llave de seguridad",
|
||||
"securityKeyTwoFactorRemoveDescription": "Por favor, ingresa tu código de autenticación de dos factores para eliminar la llave de seguridad",
|
||||
"securityKeyTwoFactorCode": "Código de autenticación de dos factores",
|
||||
"securityKeyRemoveTitle": "Eliminar llave de seguridad",
|
||||
"securityKeyRemoveDescription": "Ingresa tu contraseña para eliminar la llave de seguridad \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "No hay llaves de seguridad registradas",
|
||||
"securityKeyNoKeysDescription": "Agrega una llave de seguridad para mejorar la seguridad de tu cuenta",
|
||||
"createDomainRequired": "Se requiere dominio",
|
||||
"createDomainAddDnsRecords": "Agregar registros DNS",
|
||||
"createDomainAddDnsRecordsDescription": "Agrega los siguientes registros DNS a tu proveedor de dominios para completar la configuración.",
|
||||
"createDomainNsRecords": "Registros NS",
|
||||
"createDomainRecord": "Registro",
|
||||
"createDomainType": "Tipo:",
|
||||
"createDomainName": "Nombre:",
|
||||
"createDomainValue": "Valor:",
|
||||
"createDomainCnameRecords": "Registros CNAME",
|
||||
"createDomainARecords": "Registros A",
|
||||
"createDomainRecordNumber": "Registro {number}",
|
||||
"createDomainTxtRecords": "Registros TXT",
|
||||
"createDomainSaveTheseRecords": "Guardar estos registros",
|
||||
"createDomainSaveTheseRecordsDescription": "Asegúrate de guardar estos registros DNS ya que no los verás de nuevo.",
|
||||
"createDomainDnsPropagation": "Propagación DNS",
|
||||
"createDomainDnsPropagationDescription": "Los cambios de DNS pueden tardar un tiempo en propagarse a través de internet. Esto puede tardar desde unos pocos minutos hasta 48 horas, dependiendo de tu proveedor de DNS y la configuración de TTL.",
|
||||
"resourcePortRequired": "Se requiere número de puerto para recursos no HTTP",
|
||||
"resourcePortNotAllowed": "El número de puerto no debe establecerse para recursos HTTP",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Estoy de acuerdo con los",
|
||||
"termsOfService": "términos del servicio",
|
||||
"and": "y",
|
||||
"privacyPolicy": "política de privacidad"
|
||||
},
|
||||
"siteRequired": "El sitio es requerido.",
|
||||
"olmTunnel": "Túnel Olm",
|
||||
"olmTunnelDescription": "Usar Olm para la conectividad del cliente",
|
||||
"errorCreatingClient": "Error al crear el cliente",
|
||||
"clientDefaultsNotFound": "Configuración predeterminada del cliente no encontrada",
|
||||
"createClient": "Crear cliente",
|
||||
"createClientDescription": "Crear un cliente nuevo para conectar a sus sitios",
|
||||
"seeAllClients": "Ver todos los clientes",
|
||||
"clientInformation": "Información del cliente",
|
||||
"clientNamePlaceholder": "Nombre del cliente",
|
||||
"address": "Dirección",
|
||||
"subnetPlaceholder": "Subred",
|
||||
"addressDescription": "La dirección que este cliente utilizará para la conectividad",
|
||||
"selectSites": "Seleccionar sitios",
|
||||
"sitesDescription": "El cliente tendrá conectividad con los sitios seleccionados",
|
||||
"clientInstallOlm": "Instalar Olm",
|
||||
"clientInstallOlmDescription": "Obtén Olm funcionando en tu sistema",
|
||||
"clientOlmCredentials": "Credenciales Olm",
|
||||
"clientOlmCredentialsDescription": "Así es como Olm se autentificará con el servidor",
|
||||
"olmEndpoint": "Punto final Olm",
|
||||
"olmId": "ID de Olm",
|
||||
"olmSecretKey": "Clave secreta de Olm",
|
||||
"clientCredentialsSave": "Guarda tus credenciales",
|
||||
"clientCredentialsSaveDescription": "Sólo podrás verlo una vez. Asegúrate de copiarlo a un lugar seguro.",
|
||||
"generalSettingsDescription": "Configura la configuración general para este cliente",
|
||||
"clientUpdated": "Cliente actualizado",
|
||||
"clientUpdatedDescription": "El cliente ha sido actualizado.",
|
||||
"clientUpdateFailed": "Error al actualizar el cliente",
|
||||
"clientUpdateError": "Se ha producido un error al actualizar el cliente.",
|
||||
"sitesFetchFailed": "Error al obtener los sitios",
|
||||
"sitesFetchError": "Se ha producido un error al recuperar los sitios.",
|
||||
"olmErrorFetchReleases": "Se ha producido un error al recuperar las versiones de Olm.",
|
||||
"olmErrorFetchLatest": "Se ha producido un error al recuperar la última versión de Olm.",
|
||||
"remoteSubnets": "Subredes remotas",
|
||||
"enterCidrRange": "Ingresa el rango CIDR",
|
||||
"remoteSubnetsDescription": "Agregue rangos CIDR que se puedan acceder desde este sitio de forma remota usando clientes. Utilice el formato como 10.0.0.0/24. Esto SOLO se aplica a la conectividad del cliente VPN.",
|
||||
"resourceEnableProxy": "Habilitar proxy público",
|
||||
"resourceEnableProxyDescription": "Habilite el proxy público para este recurso. Esto permite el acceso al recurso desde fuera de la red a través de la nube en un puerto abierto. Requiere configuración de Traefik.",
|
||||
"externalProxyEnabled": "Proxy externo habilitado",
|
||||
"addNewTarget": "Agregar nuevo destino",
|
||||
"targetsList": "Lista de destinos",
|
||||
"targetErrorDuplicateTargetFound": "Se encontró un destino duplicado",
|
||||
"httpMethod": "Método HTTP",
|
||||
"selectHttpMethod": "Seleccionar método HTTP",
|
||||
"domainPickerSubdomainLabel": "Subdominio",
|
||||
"domainPickerBaseDomainLabel": "Dominio base",
|
||||
"domainPickerSearchDomains": "Buscar dominios...",
|
||||
"domainPickerNoDomainsFound": "No se encontraron dominios",
|
||||
"domainPickerLoadingDomains": "Cargando dominios...",
|
||||
"domainPickerSelectBaseDomain": "Seleccionar dominio base...",
|
||||
"domainPickerNotAvailableForCname": "No disponible para dominios CNAME",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Ingrese subdominio o deje en blanco para usar dominio base.",
|
||||
"domainPickerEnterSubdomainToSearch": "Ingrese un subdominio para buscar y seleccionar entre dominios gratuitos disponibles.",
|
||||
"domainPickerFreeDomains": "Dominios gratuitos",
|
||||
"domainPickerSearchForAvailableDomains": "Buscar dominios disponibles",
|
||||
"resourceDomain": "Dominio",
|
||||
"resourceEditDomain": "Editar dominio",
|
||||
"siteName": "Nombre del sitio",
|
||||
"proxyPort": "Puerto",
|
||||
"resourcesTableProxyResources": "Recursos de proxy",
|
||||
"resourcesTableClientResources": "Recursos del cliente",
|
||||
"resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.",
|
||||
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.",
|
||||
"resourcesTableDestination": "Destino",
|
||||
"resourcesTableTheseResourcesForUseWith": "Estos recursos son para uso con",
|
||||
"resourcesTableClients": "Clientes",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "y solo son accesibles internamente cuando se conectan con un cliente.",
|
||||
"editInternalResourceDialogEditClientResource": "Editar recurso del cliente",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Actualizar las propiedades del recurso y la configuración del objetivo para {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Propiedades del recurso",
|
||||
"editInternalResourceDialogName": "Nombre",
|
||||
"editInternalResourceDialogProtocol": "Protocolo",
|
||||
"editInternalResourceDialogSitePort": "Puerto del sitio",
|
||||
"editInternalResourceDialogTargetConfiguration": "Configuración de objetivos",
|
||||
"editInternalResourceDialogCancel": "Cancelar",
|
||||
"editInternalResourceDialogSaveResource": "Guardar recurso",
|
||||
"editInternalResourceDialogSuccess": "Éxito",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno actualizado con éxito",
|
||||
"editInternalResourceDialogError": "Error",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso interno",
|
||||
"editInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||
"editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres",
|
||||
"editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
|
||||
"editInternalResourceDialogProxyPortMax": "El puerto del proxy debe ser menor de 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Formato de dirección IP inválido",
|
||||
"editInternalResourceDialogDestinationPortMin": "El puerto de destino debe ser al menos 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "El puerto de destino debe ser menor de 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "No hay sitios disponibles",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Necesita tener al menos un sitio de Newt con una subred configurada para crear recursos internos.",
|
||||
"createInternalResourceDialogClose": "Cerrar",
|
||||
"createInternalResourceDialogCreateClientResource": "Crear recurso del cliente",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que será accesible para los clientes conectados al sitio seleccionado.",
|
||||
"createInternalResourceDialogResourceProperties": "Propiedades del recurso",
|
||||
"createInternalResourceDialogName": "Nombre",
|
||||
"createInternalResourceDialogSite": "Sitio",
|
||||
"createInternalResourceDialogSelectSite": "Seleccionar sitio...",
|
||||
"createInternalResourceDialogSearchSites": "Buscar sitios...",
|
||||
"createInternalResourceDialogNoSitesFound": "Sitios no encontrados.",
|
||||
"createInternalResourceDialogProtocol": "Protocolo",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Puerto del sitio",
|
||||
"createInternalResourceDialogSitePortDescription": "Use este puerto para acceder al recurso en el sitio cuando se conecta con un cliente.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Configuración de objetivos",
|
||||
"createInternalResourceDialogDestinationIPDescription": "La dirección IP o nombre de host del recurso en la red del sitio.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "El puerto en la IP de destino donde el recurso es accesible.",
|
||||
"createInternalResourceDialogCancel": "Cancelar",
|
||||
"createInternalResourceDialogCreateResource": "Crear recurso",
|
||||
"createInternalResourceDialogSuccess": "Éxito",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno creado con éxito",
|
||||
"createInternalResourceDialogError": "Error",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso interno",
|
||||
"createInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||
"createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio",
|
||||
"createInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
|
||||
"createInternalResourceDialogProxyPortMax": "El puerto del proxy debe ser menor de 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Formato de dirección IP inválido",
|
||||
"createInternalResourceDialogDestinationPortMin": "El puerto de destino debe ser al menos 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "El puerto de destino debe ser menor de 65536",
|
||||
"siteConfiguration": "Configuración",
|
||||
"siteAcceptClientConnections": "Aceptar conexiones de clientes",
|
||||
"siteAcceptClientConnectionsDescription": "Permitir que otros dispositivos se conecten a través de esta instancia Newt como una puerta de enlace utilizando clientes.",
|
||||
"siteAddress": "Dirección del sitio",
|
||||
"siteAddressDescription": "Especifique la dirección IP del host que los clientes deben usar para conectarse. Esta es la dirección interna del sitio en la red de Pangolín para que los clientes dirijan. Debe estar dentro de la subred de la organización.",
|
||||
"autoLoginExternalIdp": "Inicio de sesión automático con IDP externo",
|
||||
"autoLoginExternalIdpDescription": "Redirigir inmediatamente al usuario al IDP externo para autenticación.",
|
||||
"selectIdp": "Seleccionar IDP",
|
||||
"selectIdpPlaceholder": "Elegir un IDP...",
|
||||
"selectIdpRequired": "Por favor seleccione un IDP cuando el inicio de sesión automático esté habilitado.",
|
||||
"autoLoginTitle": "Redirigiendo",
|
||||
"autoLoginDescription": "Te estamos redirigiendo al proveedor de identidad externo para autenticación.",
|
||||
"autoLoginProcessing": "Preparando autenticación...",
|
||||
"autoLoginRedirecting": "Redirigiendo al inicio de sesión...",
|
||||
"autoLoginError": "Error de inicio de sesión automático",
|
||||
"autoLoginErrorNoRedirectUrl": "No se recibió URL de redirección del proveedor de identidad.",
|
||||
"autoLoginErrorGeneratingUrl": "Error al generar URL de autenticación.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Autogestionado",
|
||||
"description": "Servidor Pangolin autoalojado más fiable y de bajo mantenimiento con campanas y silbidos extra",
|
||||
"introTitle": "Pangolin autogestionado",
|
||||
"introDescription": "es una opción de despliegue diseñada para personas que quieren simplicidad y fiabilidad extra mientras mantienen sus datos privados y autoalojados.",
|
||||
"introDetail": "Con esta opción, todavía ejecuta su propio nodo Pangolin, sus túneles, terminación SSL y tráfico permanecen en su servidor. La diferencia es que la gestión y el control se gestionan a través de nuestro panel de control en la nube, que desbloquea una serie de ventajas:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Operaciones simples",
|
||||
"description": "No necesitas ejecutar tu propio servidor de correo o configurar alertas complejas. Recibirás cheques de salud y alertas de tiempo de inactividad."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Actualizaciones automáticas",
|
||||
"description": "El tablero de la nube evolucionará rápidamente, por lo que obtendrá nuevas características y correcciones de errores sin tener que extraer manualmente nuevos contenedores cada vez."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Menos mantenimiento",
|
||||
"description": "No hay migraciones de base de datos, copias de seguridad o infraestructura extra para administrar. Lo manejamos en la nube."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Fallo en la nube",
|
||||
"description": "Si tu nodo cae, tus túneles pueden fallar temporalmente a nuestros puntos de presencia en la nube hasta que lo vuelvas a conectar."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Alta disponibilidad (PoPs)",
|
||||
"description": "También puede adjuntar múltiples nodos a su cuenta para redundancia y mejor rendimiento."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Mejoras futuras",
|
||||
"description": "Estamos planeando añadir más herramientas analíticas, alertas y de administración para hacer su despliegue aún más robusto."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Aprenda más acerca de la opción de autoalojamiento administrado en nuestra",
|
||||
"documentation": "documentación"
|
||||
},
|
||||
"convertButton": "Convierte este nodo a autoalojado administrado"
|
||||
},
|
||||
"internationaldomaindetected": "Dominio Internacional detectado",
|
||||
"willbestoredas": "Se almacenará como:",
|
||||
"idpGoogleDescription": "Proveedor OAuth2/OIDC de Google",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Cabeceras personalizadas",
|
||||
"headersValidationError": "Los encabezados deben estar en el formato: Nombre de cabecera: valor.",
|
||||
"domainPickerProvidedDomain": "Dominio proporcionado",
|
||||
"domainPickerFreeProvidedDomain": "Dominio proporcionado gratis",
|
||||
"domainPickerVerified": "Verificado",
|
||||
"domainPickerUnverified": "Sin verificar",
|
||||
"domainPickerInvalidSubdomainStructure": "Este subdominio contiene caracteres o estructura no válidos. Se limpiará automáticamente al guardar.",
|
||||
"domainPickerError": "Error",
|
||||
"domainPickerErrorLoadDomains": "Error al cargar los dominios de la organización",
|
||||
"domainPickerErrorCheckAvailability": "No se pudo comprobar la disponibilidad del dominio",
|
||||
"domainPickerInvalidSubdomain": "Subdominio inválido",
|
||||
"domainPickerInvalidSubdomainRemoved": "La entrada \"{sub}\" fue eliminada porque no es válida.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "No se ha podido hacer válido \"{sub}\" para {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Subdominio saneado",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" fue corregido a \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Editar archivo: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Editar archivo: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
"setupErrorIdentifier": "L'ID de l'organisation est déjà pris. Veuillez en choisir un autre.",
|
||||
"componentsErrorNoMemberCreate": "Vous n'êtes actuellement membre d'aucune organisation. Créez une organisation pour commencer.",
|
||||
"componentsErrorNoMember": "Vous n'êtes actuellement membre d'aucune organisation.",
|
||||
"welcome": "Bienvenue à Pangolin",
|
||||
"welcome": "Bienvenue sur Pangolin",
|
||||
"welcomeTo": "Bienvenue chez",
|
||||
"componentsCreateOrg": "Créer une organisation",
|
||||
"componentsMember": "Vous êtes membre de {count, plural, =0 {aucune organisation} =1 {Une organisation} other {# organisations}}.",
|
||||
"componentsMember": "Vous êtes membre de {count, plural, =0 {aucune organisation} one {une organisation} other {# organisations}}.",
|
||||
"componentsInvalidKey": "Clés de licence invalides ou expirées détectées. Suivez les conditions de licence pour continuer à utiliser toutes les fonctionnalités.",
|
||||
"dismiss": "Refuser",
|
||||
"componentsLicenseViolation": "Violation de licence : Ce serveur utilise des sites {usedSites} qui dépassent la limite autorisée des sites {maxSites} . Suivez les conditions de licence pour continuer à utiliser toutes les fonctionnalités.",
|
||||
@@ -33,13 +34,13 @@
|
||||
"confirmPassword": "Confirmer le mot de passe",
|
||||
"createAccount": "Créer un compte",
|
||||
"viewSettings": "Afficher les paramètres",
|
||||
"delete": "Supprimez",
|
||||
"delete": "Supprimer",
|
||||
"name": "Nom",
|
||||
"online": "En ligne",
|
||||
"offline": "Hors ligne",
|
||||
"site": "Site",
|
||||
"dataIn": "Données dans",
|
||||
"dataOut": "Données épuisées",
|
||||
"dataIn": "Données reçues",
|
||||
"dataOut": "Données envoyées",
|
||||
"connectionType": "Type de connexion",
|
||||
"tunnelType": "Type de tunnel",
|
||||
"local": "Locale",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Erreur lors de la création du site",
|
||||
"siteErrorCreateKeyPair": "Paire de clés ou site par défaut introuvable",
|
||||
"siteErrorCreateDefaults": "Les valeurs par défaut du site sont introuvables",
|
||||
"siteNameDescription": "Ceci est le nom d'affichage du site.",
|
||||
"method": "Méthode",
|
||||
"siteMethodDescription": "C'est ainsi que vous exposerez les connexions.",
|
||||
"siteLearnNewt": "Apprenez à installer Newt sur votre système",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "La façon la plus simple de créer un point d'entrée dans votre réseau. Pas de configuration supplémentaire.",
|
||||
"siteWg": "WireGuard basique",
|
||||
"siteWgDescription": "Utilisez n'importe quel client WireGuard pour établir un tunnel. Configuration NAT manuelle requise.",
|
||||
"siteWgDescriptionSaas": "Utilisez n'importe quel client WireGuard pour établir un tunnel. Configuration NAT manuelle requise. FONCTIONNE UNIQUEMENT SUR DES NŒUDS AUTONOMES",
|
||||
"siteLocalDescription": "Ressources locales seulement. Pas de tunneling.",
|
||||
"siteLocalDescriptionSaas": "Ressources locales uniquement. Pas de tunneling. FONCTIONNE UNIQUEMENT SUR DES NŒUDS AUTONOMES",
|
||||
"siteSeeAll": "Voir tous les sites",
|
||||
"siteTunnelDescription": "Déterminez comment vous voulez vous connecter à votre site",
|
||||
"siteNewtCredentials": "Identifiants Newt",
|
||||
@@ -166,14 +168,14 @@
|
||||
"siteSelect": "Sélectionner un site",
|
||||
"siteSearch": "Chercher un site",
|
||||
"siteNotFound": "Aucun site trouvé.",
|
||||
"siteSelectionDescription": "Ce site fournira la connectivité à la ressource.",
|
||||
"siteSelectionDescription": "Ce site fournira la connectivité à la cible.",
|
||||
"resourceType": "Type de ressource",
|
||||
"resourceTypeDescription": "Déterminer comment vous voulez accéder à votre ressource",
|
||||
"resourceHTTPSSettings": "Paramètres HTTPS",
|
||||
"resourceHTTPSSettingsDescription": "Configurer comment votre ressource sera accédée via HTTPS",
|
||||
"domainType": "Type de domaine",
|
||||
"subdomain": "Sous-domaine",
|
||||
"baseDomain": "Domaine de base",
|
||||
"baseDomain": "Domaine racine",
|
||||
"subdomnainDescription": "Le sous-domaine où votre ressource sera accessible.",
|
||||
"resourceRawSettings": "Paramètres TCP/UDP",
|
||||
"resourceRawSettingsDescription": "Configurer comment votre ressource sera accédée via TCP/UDP",
|
||||
@@ -184,7 +186,7 @@
|
||||
"cancel": "Abandonner",
|
||||
"resourceConfig": "Snippets de configuration",
|
||||
"resourceConfigDescription": "Copiez et collez ces modules de configuration pour configurer votre ressource TCP/UDP",
|
||||
"resourceAddEntrypoints": "Traefik: Ajouter des points d’entrée",
|
||||
"resourceAddEntrypoints": "Traefik: Ajouter des points d'entrée",
|
||||
"resourceExposePorts": "Gerbil: Exposer des ports dans Docker Compose",
|
||||
"resourceLearnRaw": "Apprenez à configurer les ressources TCP/UDP",
|
||||
"resourceBack": "Retour aux ressources",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Généraux",
|
||||
"generalSettings": "Paramètres généraux",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Interne",
|
||||
"rules": "Règles",
|
||||
"resourceSettingDescription": "Configurer les paramètres de votre ressource",
|
||||
"resourceSetting": "Réglages {resourceName}",
|
||||
"alwaysAllow": "Toujours autoriser",
|
||||
"alwaysDeny": "Toujours refuser",
|
||||
"passToAuth": "Paser à l'authentification",
|
||||
"orgSettingsDescription": "Configurer les paramètres généraux de votre organisation",
|
||||
"orgGeneralSettings": "Paramètres de l'organisation",
|
||||
"orgGeneralSettingsDescription": "Gérer les détails et la configuration de votre organisation",
|
||||
"saveGeneralSettings": "Enregistrer les paramètres généraux",
|
||||
"saveSettings": "Enregistrer les paramètres",
|
||||
"orgDangerZone": "Zone de danger",
|
||||
"orgDangerZoneDescription": "Une fois que vous supprimez cette organisation, il n'y a pas de retour en arrière. Soyez certain.",
|
||||
"orgDelete": "Supprimer l'organisation",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Semaines",
|
||||
"months": "Mois",
|
||||
"years": "Années",
|
||||
"day": "{count, plural, =1 {# jour} other {# jours}}",
|
||||
"day": "{count, plural, one {# jour} other {# jours}}",
|
||||
"apiKeysTitle": "Informations sur la clé API",
|
||||
"apiKeysConfirmCopy2": "Vous devez confirmer que vous avez copié la clé API.",
|
||||
"apiKeysErrorCreate": "Erreur lors de la création de la clé API",
|
||||
@@ -304,7 +309,7 @@
|
||||
"numberOfSites": "Nombre de sites",
|
||||
"licenseKeySearch": "Rechercher des clés de licence...",
|
||||
"licenseKeyAdd": "Ajouter une clé de licence",
|
||||
"type": "Type de texte",
|
||||
"type": "Type",
|
||||
"licenseKeyRequired": "La clé de licence est requise",
|
||||
"licenseTermsAgree": "Vous devez accepter les conditions de licence",
|
||||
"licenseErrorKeyLoad": "Impossible de charger les clés de licence",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Acheter une licence",
|
||||
"licensePurchaseSites": "Acheter des sites supplémentaires",
|
||||
"licenseSitesUsedMax": "{usedSites} des sites {maxSites} utilisés",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} =1 {# site} other {# sites}} dans le système.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} one {# site} other {# sites}} dans le système.",
|
||||
"licensePurchaseDescription": "Choisissez le nombre de sites que vous voulez {selectedMode, select, license {achetez une licence. Vous pouvez toujours ajouter plus de sites plus tard.} other {ajouter à votre licence existante.}}",
|
||||
"licenseFee": "Frais de licence",
|
||||
"licensePriceSite": "Prix par site",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Sélectionner un rôle",
|
||||
"inviteEmailSentDescription": "Un e-mail a été envoyé à l'utilisateur avec le lien d'accès ci-dessous. Ils doivent accéder au lien pour accepter l'invitation.",
|
||||
"inviteSentDescription": "L'utilisateur a été invité. Ils doivent accéder au lien ci-dessous pour accepter l'invitation.",
|
||||
"inviteExpiresIn": "L'invitation expirera dans {days, plural, =1 {# jour} other {# jours}}.",
|
||||
"inviteExpiresIn": "L'invitation expirera dans {days, plural, one {# jour} other {# jours}}.",
|
||||
"idpTitle": "Informations générales",
|
||||
"idpSelect": "Sélectionnez le fournisseur d'identité pour l'utilisateur externe",
|
||||
"idpNotConfigured": "Aucun fournisseur d'identité n'est configuré. Veuillez configurer un fournisseur d'identité avant de créer des utilisateurs externes.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Une erreur s'est produite lors de l'ajout de l'utilisateur au rôle.",
|
||||
"userSaved": "Utilisateur enregistré",
|
||||
"userSavedDescription": "L'utilisateur a été mis à jour.",
|
||||
"autoProvisioned": "Auto-provisionné",
|
||||
"autoProvisionedDescription": "Permettre à cet utilisateur d'être géré automatiquement par le fournisseur d'identité",
|
||||
"accessControlsDescription": "Gérer ce que cet utilisateur peut accéder et faire dans l'organisation",
|
||||
"accessControlsSubmit": "Enregistrer les contrôles d'accès",
|
||||
"roles": "Rôles",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "Le nom de serveur TLS à utiliser pour SNI. Laissez vide pour utiliser la valeur par défaut.",
|
||||
"targetTlsSubmit": "Enregistrer les paramètres",
|
||||
"targets": "Configuration des cibles",
|
||||
"targetsDescription": "Configurez les cibles pour router le trafic vers vos services",
|
||||
"targetsDescription": "Configurez les cibles pour router le trafic vers vos services.",
|
||||
"targetStickySessions": "Activer les sessions persistantes",
|
||||
"targetStickySessionsDescription": "Maintenir les connexions sur la même cible backend pendant toute leur session.",
|
||||
"methodSelect": "Sélectionner la méthode",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Format d'adresse IP invalide",
|
||||
"ipAddressErrorInvalidOctet": "Octet d'adresse IP invalide",
|
||||
"path": "Chemin",
|
||||
"matchPath": "Chemin de correspondance",
|
||||
"ipAddressRange": "Plage IP",
|
||||
"rulesErrorFetch": "Échec de la récupération des règles",
|
||||
"rulesErrorFetchDescription": "Une erreur s'est produite lors de la récupération des règles",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Actions",
|
||||
"rulesActionAlwaysAllow": "Toujours autoriser : Contourner toutes les méthodes d'authentification",
|
||||
"rulesActionAlwaysDeny": "Toujours refuser : Bloquer toutes les requêtes ; aucune authentification ne peut être tentée",
|
||||
"rulesActionPassToAuth": "Passer à l'authentification : Autoriser les méthodes d'authentification à être tentées",
|
||||
"rulesMatchCriteria": "Critères de correspondance",
|
||||
"rulesMatchCriteriaIpAddress": "Correspondre à une adresse IP spécifique",
|
||||
"rulesMatchCriteriaIpAddressRange": "Correspondre à une plage d'adresses IP en notation CIDR",
|
||||
@@ -589,7 +598,7 @@
|
||||
"newtId": "ID Newt",
|
||||
"newtSecretKey": "Clé secrète Newt",
|
||||
"architecture": "Architecture",
|
||||
"sites": "Espaces",
|
||||
"sites": "Sites",
|
||||
"siteWgAnyClients": "Utilisez n'importe quel client WireGuard pour vous connecter. Vous devrez adresser vos ressources internes en utilisant l'IP du pair.",
|
||||
"siteWgCompatibleAllClients": "Compatible avec tous les clients WireGuard",
|
||||
"siteWgManualConfigurationRequired": "Configuration manuelle requise",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "Le code PIN doit comporter exactement 6 chiffres",
|
||||
"pincodeRequirementsChars": "Le code PIN ne doit contenir que des chiffres",
|
||||
"passwordRequirementsLength": "Le mot de passe doit comporter au moins 1 caractère",
|
||||
"passwordRequirementsTitle": "Exigences relatives au mot de passe :",
|
||||
"passwordRequirementLength": "Au moins 8 caractères",
|
||||
"passwordRequirementUppercase": "Au moins une lettre majuscule",
|
||||
"passwordRequirementLowercase": "Au moins une lettre minuscule",
|
||||
"passwordRequirementNumber": "Au moins un chiffre",
|
||||
"passwordRequirementSpecial": "Au moins un caractère spécial",
|
||||
"passwordRequirementsMet": "✓ Le mot de passe répond à toutes les exigences",
|
||||
"passwordStrength": "Solidité du mot de passe",
|
||||
"passwordStrengthWeak": "Faible",
|
||||
"passwordStrengthMedium": "Moyen",
|
||||
"passwordStrengthStrong": "Fort",
|
||||
"passwordRequirements": "Exigences :",
|
||||
"passwordRequirementLengthText": "8+ caractères",
|
||||
"passwordRequirementUppercaseText": "Lettre majuscule (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Lettre minuscule (a-z)",
|
||||
"passwordRequirementNumberText": "Nombre (0-9)",
|
||||
"passwordRequirementSpecialText": "Caractère spécial (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
|
||||
"otpEmailRequirementsLength": "L'OTP doit comporter au moins 1 caractère",
|
||||
"otpEmailSent": "OTP envoyé",
|
||||
"otpEmailSentDescription": "Un OTP a été envoyé à votre e-mail",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Connecté",
|
||||
"idpErrorConnectingTo": "Un problème est survenu lors de la connexion à {name}. Veuillez contacter votre administrateur.",
|
||||
"idpErrorNotFound": "IdP introuvable",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Invitation invalide",
|
||||
"inviteInvalidDescription": "Le lien d'invitation n'est pas valide.",
|
||||
"inviteErrorWrongUser": "L'invitation n'est pas pour cet utilisateur",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Erreur lors de la déconnexion",
|
||||
"signingAs": "Connecté en tant que",
|
||||
"serverAdmin": "Admin Serveur",
|
||||
"managedSelfhosted": "Gestion autonome",
|
||||
"otpEnable": "Activer l'authentification à deux facteurs",
|
||||
"otpDisable": "Désactiver l'authentification à deux facteurs",
|
||||
"logout": "Déconnexion",
|
||||
"licenseTierProfessionalRequired": "Édition Professionnelle Requise",
|
||||
"licenseTierProfessionalRequiredDescription": "Cette fonctionnalité n'est disponible que dans l'Édition Professionnelle.",
|
||||
"actionGetOrg": "Obtenir l'organisation",
|
||||
"updateOrgUser": "Mise à jour de l'utilisateur Org",
|
||||
"createOrgUser": "Créer un utilisateur Org",
|
||||
"actionUpdateOrg": "Mettre à jour l'organisation",
|
||||
"actionUpdateUser": "Mettre à jour l'utilisateur",
|
||||
"actionGetUser": "Obtenir l'utilisateur",
|
||||
"actionGetOrgUser": "Obtenir l'utilisateur de l'organisation",
|
||||
"actionListOrgDomains": "Lister les domaines de l'organisation",
|
||||
"actionCreateSite": "Créer un site",
|
||||
"actionDeleteSite": "Supprimer un site",
|
||||
"actionGetSite": "Obtenir un site",
|
||||
"actionListSites": "Lister les sites",
|
||||
"actionApplyBlueprint": "Appliquer le Plan",
|
||||
"setupToken": "Jeton de configuration",
|
||||
"setupTokenDescription": "Entrez le jeton de configuration depuis la console du serveur.",
|
||||
"setupTokenRequired": "Le jeton de configuration est requis.",
|
||||
"actionUpdateSite": "Mettre à jour un site",
|
||||
"actionListSiteRoles": "Lister les rôles autorisés du site",
|
||||
"actionCreateResource": "Créer une ressource",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Supprimer une politique d'organisation IDP",
|
||||
"actionListIdpOrgs": "Lister les organisations IDP",
|
||||
"actionUpdateIdpOrg": "Mettre à jour une organisation IDP",
|
||||
"actionCreateClient": "Créer un client",
|
||||
"actionDeleteClient": "Supprimer le client",
|
||||
"actionUpdateClient": "Mettre à jour le client",
|
||||
"actionListClients": "Liste des clients",
|
||||
"actionGetClient": "Obtenir le client",
|
||||
"actionCreateSiteResource": "Créer une ressource de site",
|
||||
"actionDeleteSiteResource": "Supprimer une ressource de site",
|
||||
"actionGetSiteResource": "Obtenir une ressource de site",
|
||||
"actionListSiteResources": "Lister les ressources de site",
|
||||
"actionUpdateSiteResource": "Mettre à jour une ressource de site",
|
||||
"actionListInvitations": "Lister les invitations",
|
||||
"noneSelected": "Aucune sélection",
|
||||
"orgNotFound2": "Aucune organisation trouvée.",
|
||||
"searchProgress": "Rechercher...",
|
||||
@@ -1079,7 +1128,7 @@
|
||||
"sidebarOverview": "Aperçu",
|
||||
"sidebarHome": "Domicile",
|
||||
"sidebarSites": "Espaces",
|
||||
"sidebarResources": "Ressource",
|
||||
"sidebarResources": "Ressources",
|
||||
"sidebarAccessControl": "Contrôle d'accès",
|
||||
"sidebarUsers": "Utilisateurs",
|
||||
"sidebarInvitations": "Invitations",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Tous les utilisateurs",
|
||||
"sidebarIdentityProviders": "Fournisseurs d'identité",
|
||||
"sidebarLicense": "Licence",
|
||||
"enableDockerSocket": "Activer Docker Socket",
|
||||
"enableDockerSocketDescription": "Activer la découverte Docker Socket pour remplir les informations du conteneur. Le chemin du socket doit être fourni à Newt.",
|
||||
"sidebarClients": "Clients (Bêta)",
|
||||
"sidebarDomains": "Domaines",
|
||||
"enableDockerSocket": "Activer le Plan Docker",
|
||||
"enableDockerSocketDescription": "Activer le ramassage d'étiquettes de socket Docker pour les étiquettes de plan. Le chemin de socket doit être fourni à Newt.",
|
||||
"enableDockerSocketLink": "En savoir plus",
|
||||
"viewDockerContainers": "Voir les conteneurs Docker",
|
||||
"containersIn": "Conteneurs en {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Réseaux",
|
||||
"containerHostnameIp": "Nom d'hôte/IP",
|
||||
"containerLabels": "Étiquettes",
|
||||
"containerLabelsCount": "{count} étiquette{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# étiquette} other {# étiquettes}}",
|
||||
"containerLabelsTitle": "Étiquettes de conteneur",
|
||||
"containerLabelEmpty": "<vide>",
|
||||
"containerPorts": "Ports",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Afficher les conteneurs arrêtés",
|
||||
"noContainersFound": "Aucun conteneur trouvé. Assurez-vous que les conteneurs Docker sont en cours d'exécution.",
|
||||
"searchContainersPlaceholder": "Rechercher dans les conteneurs {count}...",
|
||||
"searchResultsCount": "{count} résultat{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# résultat} other {# résultats}}",
|
||||
"filters": "Filtres",
|
||||
"filterOptions": "Options de filtre",
|
||||
"filterPorts": "Ports",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "sombre",
|
||||
"system": "système",
|
||||
"theme": "Thème",
|
||||
"subnetRequired": "Le sous-réseau est requis",
|
||||
"initialSetupTitle": "Configuration initiale du serveur",
|
||||
"initialSetupDescription": "Créer le compte administrateur du serveur initial. Un seul administrateur serveur peut exister. Vous pouvez toujours changer ces informations d'identification plus tard.",
|
||||
"createAdminAccount": "Créer un compte administrateur",
|
||||
"setupErrorCreateAdmin": "Une erreur s'est produite lors de la création du compte administrateur du serveur."
|
||||
"setupErrorCreateAdmin": "Une erreur s'est produite lors de la création du compte administrateur du serveur.",
|
||||
"certificateStatus": "Statut du certificat",
|
||||
"loading": "Chargement",
|
||||
"restart": "Redémarrer",
|
||||
"domains": "Domaines",
|
||||
"domainsDescription": "Gérer les domaines de votre organisation",
|
||||
"domainsSearch": "Rechercher des domaines...",
|
||||
"domainAdd": "Ajouter un domaine",
|
||||
"domainAddDescription": "Enregistrez un nouveau domaine avec votre organisation",
|
||||
"domainCreate": "Créer un domaine",
|
||||
"domainCreatedDescription": "Domaine créé avec succès",
|
||||
"domainDeletedDescription": "Domaine supprimé avec succès",
|
||||
"domainQuestionRemove": "Êtes-vous sûr de vouloir supprimer le domaine {domain} de votre compte ?",
|
||||
"domainMessageRemove": "Une fois supprimé, le domaine ne sera plus associé à votre compte.",
|
||||
"domainMessageConfirm": "Pour confirmer, veuillez taper le nom du domaine ci-dessous.",
|
||||
"domainConfirmDelete": "Confirmer la suppression du domaine",
|
||||
"domainDelete": "Supprimer le domaine",
|
||||
"domain": "Domaine",
|
||||
"selectDomainTypeNsName": "Délégation de domaine (NS)",
|
||||
"selectDomainTypeNsDescription": "Ce domaine et tous ses sous-domaines. Utilisez cela lorsque vous souhaitez contrôler une zone de domaine entière.",
|
||||
"selectDomainTypeCnameName": "Domaine unique (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Juste ce domaine spécifique. Utilisez ce paramètre pour des sous-domaines individuels ou des entrées de domaine spécifiques.",
|
||||
"selectDomainTypeWildcardName": "Domaine Générique",
|
||||
"selectDomainTypeWildcardDescription": "Ce domaine et ses sous-domaines.",
|
||||
"domainDelegation": "Domaine Unique",
|
||||
"selectType": "Sélectionnez un type",
|
||||
"actions": "Actions",
|
||||
"refresh": "Actualiser",
|
||||
"refreshError": "Échec de l'actualisation des données",
|
||||
"verified": "Vérifié",
|
||||
"pending": "En attente",
|
||||
"sidebarBilling": "Facturation",
|
||||
"billing": "Facturation",
|
||||
"orgBillingDescription": "Gérez vos informations de facturation et vos abonnements",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hébergement",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Complétez la configuration du compte",
|
||||
"completeAccountSetupDescription": "Définissez votre mot de passe pour commencer",
|
||||
"accountSetupSent": "Nous enverrons un code de configuration de compte à cette adresse e-mail.",
|
||||
"accountSetupCode": "Code de configuration",
|
||||
"accountSetupCodeDescription": "Vérifiez votre e-mail pour le code de configuration.",
|
||||
"passwordCreate": "Créer un mot de passe",
|
||||
"passwordCreateConfirm": "Confirmer le mot de passe",
|
||||
"accountSetupSubmit": "Envoyer le code de configuration",
|
||||
"completeSetup": "Configuration complète",
|
||||
"accountSetupSuccess": "Configuration du compte terminée! Bienvenue chez Pangolin !",
|
||||
"documentation": "Documentation",
|
||||
"saveAllSettings": "Enregistrer tous les paramètres",
|
||||
"settingsUpdated": "Paramètres mis à jour",
|
||||
"settingsUpdatedDescription": "Tous les paramètres ont été mis à jour avec succès",
|
||||
"settingsErrorUpdate": "Échec de la mise à jour des paramètres",
|
||||
"settingsErrorUpdateDescription": "Une erreur s'est produite lors de la mise à jour des paramètres",
|
||||
"sidebarCollapse": "Réduire",
|
||||
"sidebarExpand": "Développer",
|
||||
"newtUpdateAvailable": "Mise à jour disponible",
|
||||
"newtUpdateAvailableInfo": "Une nouvelle version de Newt est disponible. Veuillez mettre à jour vers la dernière version pour une meilleure expérience.",
|
||||
"domainPickerEnterDomain": "Domaine",
|
||||
"domainPickerPlaceholder": "monapp.exemple.com",
|
||||
"domainPickerDescription": "Entrez le domaine complet de la ressource pour voir les options disponibles.",
|
||||
"domainPickerDescriptionSaas": "Entrez un domaine complet, un sous-domaine ou juste un nom pour voir les options disponibles",
|
||||
"domainPickerTabAll": "Tous",
|
||||
"domainPickerTabOrganization": "Organisation",
|
||||
"domainPickerTabProvided": "Fournis",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Vérification de la disponibilité...",
|
||||
"domainPickerNoMatchingDomains": "Aucun domaine correspondant trouvé. Essayez un autre domaine ou vérifiez les paramètres de domaine de votre organisation.",
|
||||
"domainPickerOrganizationDomains": "Domaines de l'organisation",
|
||||
"domainPickerProvidedDomains": "Domaines fournis",
|
||||
"domainPickerSubdomain": "Sous-domaine : {subdomain}",
|
||||
"domainPickerNamespace": "Espace de noms : {namespace}",
|
||||
"domainPickerShowMore": "Afficher plus",
|
||||
"domainNotFound": "Domaine introuvable",
|
||||
"domainNotFoundDescription": "Cette ressource est désactivée car le domaine n'existe plus dans notre système. Veuillez définir un nouveau domaine pour cette ressource.",
|
||||
"failed": "Échec",
|
||||
"createNewOrgDescription": "Créer une nouvelle organisation",
|
||||
"organization": "Organisation",
|
||||
"port": "Port",
|
||||
"securityKeyManage": "Gérer les clés de sécurité",
|
||||
"securityKeyDescription": "Ajouter ou supprimer des clés de sécurité pour l'authentification sans mot de passe",
|
||||
"securityKeyRegister": "Enregistrer une nouvelle clé de sécurité",
|
||||
"securityKeyList": "Vos clés de sécurité",
|
||||
"securityKeyNone": "Aucune clé de sécurité enregistrée",
|
||||
"securityKeyNameRequired": "Le nom est requis",
|
||||
"securityKeyRemove": "Supprimer",
|
||||
"securityKeyLastUsed": "Dernière utilisation : {date}",
|
||||
"securityKeyNameLabel": "Nom",
|
||||
"securityKeyRegisterSuccess": "Clé de sécurité enregistrée avec succès",
|
||||
"securityKeyRegisterError": "Échec de l'enregistrement de la clé de sécurité",
|
||||
"securityKeyRemoveSuccess": "Clé de sécurité supprimée avec succès",
|
||||
"securityKeyRemoveError": "Échec de la suppression de la clé de sécurité",
|
||||
"securityKeyLoadError": "Échec du chargement des clés de sécurité",
|
||||
"securityKeyLogin": "Continuer avec une clé de sécurité",
|
||||
"securityKeyAuthError": "Échec de l'authentification avec la clé de sécurité",
|
||||
"securityKeyRecommendation": "Envisagez d'enregistrer une autre clé de sécurité sur un appareil différent pour vous assurer de ne pas être bloqué de votre compte.",
|
||||
"registering": "Enregistrement...",
|
||||
"securityKeyPrompt": "Veuillez vérifier votre identité à l'aide de votre clé de sécurité. Assurez-vous que votre clé de sécurité est connectée et prête.",
|
||||
"securityKeyBrowserNotSupported": "Votre navigateur ne prend pas en charge les clés de sécurité. Veuillez utiliser un navigateur moderne comme Chrome, Firefox ou Safari.",
|
||||
"securityKeyPermissionDenied": "Veuillez autoriser l'accès à votre clé de sécurité pour continuer la connexion.",
|
||||
"securityKeyRemovedTooQuickly": "Veuillez garder votre clé de sécurité connectée jusqu'à ce que le processus de connexion soit terminé.",
|
||||
"securityKeyNotSupported": "Votre clé de sécurité peut ne pas être compatible. Veuillez essayer une clé de sécurité différente.",
|
||||
"securityKeyUnknownError": "Un problème est survenu avec votre clé de sécurité. Veuillez réessayer.",
|
||||
"twoFactorRequired": "L'authentification à deux facteurs est requise pour enregistrer une clé de sécurité.",
|
||||
"twoFactor": "Authentification à deux facteurs",
|
||||
"adminEnabled2FaOnYourAccount": "Votre administrateur a activé l'authentification à deux facteurs pour {email}. Veuillez terminer le processus d'installation pour continuer.",
|
||||
"continueToApplication": "Continuer vers l'application",
|
||||
"securityKeyAdd": "Ajouter une clé de sécurité",
|
||||
"securityKeyRegisterTitle": "Enregistrer une nouvelle clé de sécurité",
|
||||
"securityKeyRegisterDescription": "Connectez votre clé de sécurité et saisissez un nom pour l'identifier",
|
||||
"securityKeyTwoFactorRequired": "Authentification à deux facteurs requise",
|
||||
"securityKeyTwoFactorDescription": "Veuillez entrer votre code d'authentification à deux facteurs pour enregistrer la clé de sécurité",
|
||||
"securityKeyTwoFactorRemoveDescription": "Veuillez entrer votre code d'authentification à deux facteurs pour supprimer la clé de sécurité",
|
||||
"securityKeyTwoFactorCode": "Code à deux facteurs",
|
||||
"securityKeyRemoveTitle": "Supprimer la clé de sécurité",
|
||||
"securityKeyRemoveDescription": "Saisissez votre mot de passe pour supprimer la clé de sécurité \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "Aucune clé de sécurité enregistrée",
|
||||
"securityKeyNoKeysDescription": "Ajoutez une clé de sécurité pour améliorer la sécurité de votre compte",
|
||||
"createDomainRequired": "Le domaine est requis",
|
||||
"createDomainAddDnsRecords": "Ajouter des enregistrements DNS",
|
||||
"createDomainAddDnsRecordsDescription": "Ajouter les enregistrements DNS suivants à votre fournisseur de domaine pour compléter la configuration.",
|
||||
"createDomainNsRecords": "Enregistrements NS",
|
||||
"createDomainRecord": "Enregistrement",
|
||||
"createDomainType": "Type :",
|
||||
"createDomainName": "Nom :",
|
||||
"createDomainValue": "Valeur :",
|
||||
"createDomainCnameRecords": "Enregistrements CNAME",
|
||||
"createDomainARecords": "Enregistrements A",
|
||||
"createDomainRecordNumber": "Enregistrement {number}",
|
||||
"createDomainTxtRecords": "Enregistrements TXT",
|
||||
"createDomainSaveTheseRecords": "Enregistrez ces enregistrements",
|
||||
"createDomainSaveTheseRecordsDescription": "Assurez-vous de sauvegarder ces enregistrements DNS car vous ne les reverrez pas.",
|
||||
"createDomainDnsPropagation": "Propagation DNS",
|
||||
"createDomainDnsPropagationDescription": "Les modifications DNS peuvent mettre du temps à se propager sur internet. Cela peut prendre de quelques minutes à 48 heures selon votre fournisseur DNS et les réglages TTL.",
|
||||
"resourcePortRequired": "Le numéro de port est requis pour les ressources non-HTTP",
|
||||
"resourcePortNotAllowed": "Le numéro de port ne doit pas être défini pour les ressources HTTP",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Je suis d'accord avec",
|
||||
"termsOfService": "les conditions d'utilisation",
|
||||
"and": "et",
|
||||
"privacyPolicy": "la politique de confidentialité"
|
||||
},
|
||||
"siteRequired": "Le site est requis.",
|
||||
"olmTunnel": "Tunnel Olm",
|
||||
"olmTunnelDescription": "Utilisez Olm pour la connectivité client",
|
||||
"errorCreatingClient": "Erreur lors de la création du client",
|
||||
"clientDefaultsNotFound": "Les paramètres par défaut du client sont introuvables",
|
||||
"createClient": "Créer un client",
|
||||
"createClientDescription": "Créez un nouveau client pour vous connecter à vos sites",
|
||||
"seeAllClients": "Voir tous les clients",
|
||||
"clientInformation": "Informations client",
|
||||
"clientNamePlaceholder": "Nom du client",
|
||||
"address": "Adresse",
|
||||
"subnetPlaceholder": "Sous-réseau",
|
||||
"addressDescription": "L'adresse que ce client utilisera pour la connectivité",
|
||||
"selectSites": "Sélectionner des sites",
|
||||
"sitesDescription": "Le client aura une connectivité vers les sites sélectionnés",
|
||||
"clientInstallOlm": "Installer Olm",
|
||||
"clientInstallOlmDescription": "Faites fonctionner Olm sur votre système",
|
||||
"clientOlmCredentials": "Identifiants Olm",
|
||||
"clientOlmCredentialsDescription": "C'est ainsi qu'Olm s'authentifiera auprès du serveur",
|
||||
"olmEndpoint": "Point de terminaison Olm",
|
||||
"olmId": "ID Olm",
|
||||
"olmSecretKey": "Clé secrète Olm",
|
||||
"clientCredentialsSave": "Enregistrez vos identifiants",
|
||||
"clientCredentialsSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Assurez-vous de la copier dans un endroit sécurisé.",
|
||||
"generalSettingsDescription": "Configurez les paramètres généraux pour ce client",
|
||||
"clientUpdated": "Client mis à jour",
|
||||
"clientUpdatedDescription": "Le client a été mis à jour.",
|
||||
"clientUpdateFailed": "Échec de la mise à jour du client",
|
||||
"clientUpdateError": "Une erreur s'est produite lors de la mise à jour du client.",
|
||||
"sitesFetchFailed": "Échec de la récupération des sites",
|
||||
"sitesFetchError": "Une erreur s'est produite lors de la récupération des sites.",
|
||||
"olmErrorFetchReleases": "Une erreur s'est produite lors de la récupération des versions d'Olm.",
|
||||
"olmErrorFetchLatest": "Une erreur s'est produite lors de la récupération de la dernière version d'Olm.",
|
||||
"remoteSubnets": "Sous-réseaux distants",
|
||||
"enterCidrRange": "Entrez la plage CIDR",
|
||||
"remoteSubnetsDescription": "Ajoutez des plages CIDR accessibles à distance depuis ce site à l'aide de clients. Utilisez le format comme 10.0.0.0/24. Cela s'applique UNIQUEMENT à la connectivité des clients VPN.",
|
||||
"resourceEnableProxy": "Activer le proxy public",
|
||||
"resourceEnableProxyDescription": "Activez le proxy public vers cette ressource. Cela permet d'accéder à la ressource depuis l'extérieur du réseau via le cloud sur un port ouvert. Nécessite la configuration de Traefik.",
|
||||
"externalProxyEnabled": "Proxy externe activé",
|
||||
"addNewTarget": "Ajouter une nouvelle cible",
|
||||
"targetsList": "Liste des cibles",
|
||||
"targetErrorDuplicateTargetFound": "Cible en double trouvée",
|
||||
"httpMethod": "Méthode HTTP",
|
||||
"selectHttpMethod": "Sélectionnez la méthode HTTP",
|
||||
"domainPickerSubdomainLabel": "Sous-domaine",
|
||||
"domainPickerBaseDomainLabel": "Domaine de base",
|
||||
"domainPickerSearchDomains": "Rechercher des domaines...",
|
||||
"domainPickerNoDomainsFound": "Aucun domaine trouvé",
|
||||
"domainPickerLoadingDomains": "Chargement des domaines...",
|
||||
"domainPickerSelectBaseDomain": "Sélectionnez le domaine de base...",
|
||||
"domainPickerNotAvailableForCname": "Non disponible pour les domaines CNAME",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Entrez un sous-domaine ou laissez vide pour utiliser le domaine de base.",
|
||||
"domainPickerEnterSubdomainToSearch": "Entrez un sous-domaine pour rechercher et sélectionner parmi les domaines gratuits disponibles.",
|
||||
"domainPickerFreeDomains": "Domaines gratuits",
|
||||
"domainPickerSearchForAvailableDomains": "Rechercher des domaines disponibles",
|
||||
"resourceDomain": "Domaine",
|
||||
"resourceEditDomain": "Modifier le domaine",
|
||||
"siteName": "Nom du site",
|
||||
"proxyPort": "Port",
|
||||
"resourcesTableProxyResources": "Ressources proxy",
|
||||
"resourcesTableClientResources": "Ressources client",
|
||||
"resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.",
|
||||
"resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.",
|
||||
"resourcesTableDestination": "Destination",
|
||||
"resourcesTableTheseResourcesForUseWith": "Ces ressources sont à utiliser avec",
|
||||
"resourcesTableClients": "Clients",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "et sont uniquement accessibles en interne lorsqu'elles sont connectées avec un client.",
|
||||
"editInternalResourceDialogEditClientResource": "Modifier la ressource client",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Mettez à jour les propriétés de la ressource et la configuration de la cible pour {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Propriétés de la ressource",
|
||||
"editInternalResourceDialogName": "Nom",
|
||||
"editInternalResourceDialogProtocol": "Protocole",
|
||||
"editInternalResourceDialogSitePort": "Port du site",
|
||||
"editInternalResourceDialogTargetConfiguration": "Configuration de la cible",
|
||||
"editInternalResourceDialogCancel": "Abandonner",
|
||||
"editInternalResourceDialogSaveResource": "Enregistrer la ressource",
|
||||
"editInternalResourceDialogSuccess": "Succès",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource interne mise à jour avec succès",
|
||||
"editInternalResourceDialogError": "Erreur",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Échec de la mise à jour de la ressource interne",
|
||||
"editInternalResourceDialogNameRequired": "Le nom est requis",
|
||||
"editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||
"editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
|
||||
"editInternalResourceDialogProxyPortMax": "Le port proxy doit être inférieur à 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Format d'adresse IP invalide",
|
||||
"editInternalResourceDialogDestinationPortMin": "Le port de destination doit être d'au moins 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "Le port de destination doit être inférieur à 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Aucun site disponible",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Vous devez avoir au moins un site Newt avec un sous-réseau configuré pour créer des ressources internes.",
|
||||
"createInternalResourceDialogClose": "Fermer",
|
||||
"createInternalResourceDialogCreateClientResource": "Créer une ressource client",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Créez une ressource accessible aux clients connectés au site sélectionné.",
|
||||
"createInternalResourceDialogResourceProperties": "Propriétés de la ressource",
|
||||
"createInternalResourceDialogName": "Nom",
|
||||
"createInternalResourceDialogSite": "Site",
|
||||
"createInternalResourceDialogSelectSite": "Sélectionner un site...",
|
||||
"createInternalResourceDialogSearchSites": "Rechercher des sites...",
|
||||
"createInternalResourceDialogNoSitesFound": "Aucun site trouvé.",
|
||||
"createInternalResourceDialogProtocol": "Protocole",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Port du site",
|
||||
"createInternalResourceDialogSitePortDescription": "Utilisez ce port pour accéder à la ressource sur le site lors de la connexion avec un client.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Configuration de la cible",
|
||||
"createInternalResourceDialogDestinationIPDescription": "L'adresse IP ou le nom d'hôte de la ressource sur le réseau du site.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "Le port sur l'IP de destination où la ressource est accessible.",
|
||||
"createInternalResourceDialogCancel": "Abandonner",
|
||||
"createInternalResourceDialogCreateResource": "Créer une ressource",
|
||||
"createInternalResourceDialogSuccess": "Succès",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource interne créée avec succès",
|
||||
"createInternalResourceDialogError": "Erreur",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Échec de la création de la ressource interne",
|
||||
"createInternalResourceDialogNameRequired": "Le nom est requis",
|
||||
"createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site",
|
||||
"createInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
|
||||
"createInternalResourceDialogProxyPortMax": "Le port proxy doit être inférieur à 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Format d'adresse IP invalide",
|
||||
"createInternalResourceDialogDestinationPortMin": "Le port de destination doit être d'au moins 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "Le port de destination doit être inférieur à 65536",
|
||||
"siteConfiguration": "Configuration",
|
||||
"siteAcceptClientConnections": "Accepter les connexions client",
|
||||
"siteAcceptClientConnectionsDescription": "Permet à d'autres appareils de se connecter via cette instance de Newt en tant que passerelle utilisant des clients.",
|
||||
"siteAddress": "Adresse du site",
|
||||
"siteAddressDescription": "Spécifiez l'adresse IP de l'hôte pour que les clients puissent s'y connecter. C'est l'adresse interne du site dans le réseau Pangolin pour que les clients puissent s'adresser. Doit être dans le sous-réseau de l'organisation.",
|
||||
"autoLoginExternalIdp": "Connexion automatique avec IDP externe",
|
||||
"autoLoginExternalIdpDescription": "Rediriger immédiatement l'utilisateur vers l'IDP externe pour l'authentification.",
|
||||
"selectIdp": "Sélectionner l'IDP",
|
||||
"selectIdpPlaceholder": "Choisissez un IDP...",
|
||||
"selectIdpRequired": "Veuillez sélectionner un IDP lorsque la connexion automatique est activée.",
|
||||
"autoLoginTitle": "Redirection",
|
||||
"autoLoginDescription": "Redirection vers le fournisseur d'identité externe pour l'authentification.",
|
||||
"autoLoginProcessing": "Préparation de l'authentification...",
|
||||
"autoLoginRedirecting": "Redirection vers la connexion...",
|
||||
"autoLoginError": "Erreur de connexion automatique",
|
||||
"autoLoginErrorNoRedirectUrl": "Aucune URL de redirection reçue du fournisseur d'identité.",
|
||||
"autoLoginErrorGeneratingUrl": "Échec de la génération de l'URL d'authentification.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Gestion autonome",
|
||||
"description": "Serveur Pangolin auto-hébergé avec des cloches et des sifflets supplémentaires",
|
||||
"introTitle": "Pangolin auto-hébergé géré",
|
||||
"introDescription": "est une option de déploiement conçue pour les personnes qui veulent de la simplicité et de la fiabilité tout en gardant leurs données privées et auto-hébergées.",
|
||||
"introDetail": "Avec cette option, vous exécutez toujours votre propre nœud Pangolin — vos tunnels, la terminaison SSL et le trafic restent sur votre serveur. La différence est que la gestion et la surveillance sont gérées via notre tableau de bord du cloud, qui déverrouille un certain nombre d'avantages :",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Opérations plus simples",
|
||||
"description": "Pas besoin de faire tourner votre propre serveur de messagerie ou de configurer des alertes complexes. Vous obtiendrez des contrôles de santé et des alertes de temps d'arrêt par la suite."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Mises à jour automatiques",
|
||||
"description": "Le tableau de bord du cloud évolue rapidement, de sorte que vous obtenez de nouvelles fonctionnalités et des corrections de bugs sans avoir à extraire manuellement de nouveaux conteneurs à chaque fois."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Moins de maintenance",
|
||||
"description": "Aucune migration de base de données, sauvegarde ou infrastructure supplémentaire à gérer. Nous gérons cela dans le cloud."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Basculement du Cloud",
|
||||
"description": "Si votre nœud descend, vos tunnels peuvent temporairement échouer jusqu'à ce que vous le rapatriez en ligne."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Haute disponibilité (PoPs)",
|
||||
"description": "Vous pouvez également attacher plusieurs nœuds à votre compte pour une redondance et de meilleures performances."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Améliorations futures",
|
||||
"description": "Nous prévoyons d'ajouter plus d'outils d'analyse, d'alerte et de gestion pour rendre votre déploiement encore plus robuste."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "En savoir plus sur l'option Auto-Hébergement géré dans notre",
|
||||
"documentation": "documentation"
|
||||
},
|
||||
"convertButton": "Convertir ce noeud en auto-hébergé géré"
|
||||
},
|
||||
"internationaldomaindetected": "Domaine international détecté",
|
||||
"willbestoredas": "Sera stocké comme :",
|
||||
"idpGoogleDescription": "Fournisseur Google OAuth2/OIDC",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "En-têtes personnalisés",
|
||||
"headersValidationError": "Les entêtes doivent être au format : Header-Name: valeur.",
|
||||
"domainPickerProvidedDomain": "Domaine fourni",
|
||||
"domainPickerFreeProvidedDomain": "Domaine fourni gratuitement",
|
||||
"domainPickerVerified": "Vérifié",
|
||||
"domainPickerUnverified": "Non vérifié",
|
||||
"domainPickerInvalidSubdomainStructure": "Ce sous-domaine contient des caractères ou une structure non valide. Il sera automatiquement nettoyé lorsque vous enregistrez.",
|
||||
"domainPickerError": "Erreur",
|
||||
"domainPickerErrorLoadDomains": "Impossible de charger les domaines de l'organisation",
|
||||
"domainPickerErrorCheckAvailability": "Impossible de vérifier la disponibilité du domaine",
|
||||
"domainPickerInvalidSubdomain": "Sous-domaine invalide",
|
||||
"domainPickerInvalidSubdomainRemoved": "L'entrée \"{sub}\" a été supprimée car elle n'est pas valide.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "La «{sub}» n'a pas pu être validée pour {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Sous-domaine nettoyé",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" a été corrigé à \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Modifier le fichier : config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Modifier le fichier : docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "Al momento non sei un membro di nessuna organizzazione. Crea un'organizzazione per iniziare.",
|
||||
"componentsErrorNoMember": "Attualmente non sei membro di nessuna organizzazione.",
|
||||
"welcome": "Benvenuti a Pangolin",
|
||||
"welcomeTo": "Benvenuto a",
|
||||
"componentsCreateOrg": "Crea un'organizzazione",
|
||||
"componentsMember": "Sei un membro di {count, plural, =0 {nessuna organizzazione} =1 {una organizzazione} other {# organizzazioni}}.",
|
||||
"componentsMember": "Sei un membro di {count, plural, =0 {nessuna organizzazione} one {un'organizzazione} other {# organizzazioni}}.",
|
||||
"componentsInvalidKey": "Rilevata chiave di licenza non valida o scaduta. Segui i termini di licenza per continuare a utilizzare tutte le funzionalità.",
|
||||
"dismiss": "Ignora",
|
||||
"componentsLicenseViolation": "Violazione della licenza: Questo server sta usando i siti {usedSites} che superano il suo limite concesso in licenza per i siti {maxSites} . Segui i termini di licenza per continuare a usare tutte le funzionalità.",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Errore nella creazione del sito",
|
||||
"siteErrorCreateKeyPair": "Coppia di chiavi o valori predefiniti del sito non trovati",
|
||||
"siteErrorCreateDefaults": "Predefiniti del sito non trovati",
|
||||
"siteNameDescription": "Questo è il nome visualizzato per il sito.",
|
||||
"method": "Metodo",
|
||||
"siteMethodDescription": "Questo è il modo in cui esporrete le connessioni.",
|
||||
"siteLearnNewt": "Scopri come installare Newt sul tuo sistema",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "Modo più semplice per creare un entrypoint nella rete. Nessuna configurazione aggiuntiva.",
|
||||
"siteWg": "WireGuard Base",
|
||||
"siteWgDescription": "Usa qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta.",
|
||||
"siteWgDescriptionSaas": "Usa qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta. FUNZIONA SOLO SU NODI AUTO-OSPITATI",
|
||||
"siteLocalDescription": "Solo risorse locali. Nessun tunneling.",
|
||||
"siteLocalDescriptionSaas": "Solo risorse locali. Nessun tunneling. FUNZIONA SOLO SU NODI AUTO-OSPITATI",
|
||||
"siteSeeAll": "Vedi Tutti I Siti",
|
||||
"siteTunnelDescription": "Determina come vuoi connetterti al tuo sito",
|
||||
"siteNewtCredentials": "Credenziali Newt",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Seleziona sito",
|
||||
"siteSearch": "Cerca sito",
|
||||
"siteNotFound": "Nessun sito trovato.",
|
||||
"siteSelectionDescription": "Questo sito fornirà connettività alla risorsa.",
|
||||
"siteSelectionDescription": "Questo sito fornirà connettività all'obiettivo.",
|
||||
"resourceType": "Tipo Di Risorsa",
|
||||
"resourceTypeDescription": "Determina come vuoi accedere alla tua risorsa",
|
||||
"resourceHTTPSSettings": "Impostazioni HTTPS",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Generale",
|
||||
"generalSettings": "Impostazioni Generali",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Interno",
|
||||
"rules": "Regole",
|
||||
"resourceSettingDescription": "Configura le impostazioni sulla tua risorsa",
|
||||
"resourceSetting": "Impostazioni {resourceName}",
|
||||
"alwaysAllow": "Consenti Sempre",
|
||||
"alwaysDeny": "Nega Sempre",
|
||||
"passToAuth": "Passa all'autenticazione",
|
||||
"orgSettingsDescription": "Configura le impostazioni generali della tua organizzazione",
|
||||
"orgGeneralSettings": "Impostazioni Organizzazione",
|
||||
"orgGeneralSettingsDescription": "Gestisci i dettagli dell'organizzazione e la configurazione",
|
||||
"saveGeneralSettings": "Salva Impostazioni Generali",
|
||||
"saveSettings": "Salva Impostazioni",
|
||||
"orgDangerZone": "Zona Pericolosa",
|
||||
"orgDangerZoneDescription": "Una volta che si elimina questo org, non c'è ritorno. Si prega di essere certi.",
|
||||
"orgDelete": "Elimina Organizzazione",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Settimane",
|
||||
"months": "Mesi",
|
||||
"years": "Anni",
|
||||
"day": "{count, plural, =1 {# giorno} other {# giorni}}",
|
||||
"day": "{count, plural, one {# giorno} other {# giorni}}",
|
||||
"apiKeysTitle": "Informazioni Chiave API",
|
||||
"apiKeysConfirmCopy2": "Devi confermare di aver copiato la chiave API.",
|
||||
"apiKeysErrorCreate": "Errore nella creazione della chiave API",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Acquista Licenza",
|
||||
"licensePurchaseSites": "Acquista Siti Aggiuntivi",
|
||||
"licenseSitesUsedMax": "{usedSites} di {maxSites} siti utilizzati",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# siti} =1 {# sito} other {# siti}} nel sistema.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# siti} one {# sito} other {# siti}} nel sistema.",
|
||||
"licensePurchaseDescription": "Scegli quanti siti vuoi {selectedMode, select, license {acquista una licenza. Puoi sempre aggiungere altri siti più tardi.} other {aggiungi alla tua licenza esistente.}}",
|
||||
"licenseFee": "Costo della licenza",
|
||||
"licensePriceSite": "Prezzo per sito",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Seleziona ruolo",
|
||||
"inviteEmailSentDescription": "È stata inviata un'email all'utente con il link di accesso qui sotto. Devono accedere al link per accettare l'invito.",
|
||||
"inviteSentDescription": "L'utente è stato invitato. Deve accedere al link qui sotto per accettare l'invito.",
|
||||
"inviteExpiresIn": "L'invito scadrà tra {days, plural, =1 {# giorno} other {# giorni}}.",
|
||||
"inviteExpiresIn": "L'invito scadrà tra {days, plural, one {# giorno} other {# giorni}}.",
|
||||
"idpTitle": "Informazioni Generali",
|
||||
"idpSelect": "Seleziona il provider di identità per l'utente esterno",
|
||||
"idpNotConfigured": "Nessun provider di identità configurato. Configura un provider di identità prima di creare utenti esterni.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Si è verificato un errore durante l'aggiunta dell'utente al ruolo.",
|
||||
"userSaved": "Utente salvato",
|
||||
"userSavedDescription": "L'utente è stato aggiornato.",
|
||||
"autoProvisioned": "Auto Provisioned",
|
||||
"autoProvisionedDescription": "Permetti a questo utente di essere gestito automaticamente dal provider di identità",
|
||||
"accessControlsDescription": "Gestisci cosa questo utente può accedere e fare nell'organizzazione",
|
||||
"accessControlsSubmit": "Salva Controlli di Accesso",
|
||||
"roles": "Ruoli",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "Il Nome Server TLS da usare per SNI. Lascia vuoto per usare quello predefinito.",
|
||||
"targetTlsSubmit": "Salva Impostazioni",
|
||||
"targets": "Configurazione Target",
|
||||
"targetsDescription": "Configura i target per instradare il traffico ai tuoi servizi",
|
||||
"targetsDescription": "Configura i target per instradare il traffico ai tuoi servizi backend",
|
||||
"targetStickySessions": "Abilita Sessioni Persistenti",
|
||||
"targetStickySessionsDescription": "Mantieni le connessioni sullo stesso target backend per l'intera sessione.",
|
||||
"methodSelect": "Seleziona metodo",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Formato indirizzo IP non valido",
|
||||
"ipAddressErrorInvalidOctet": "Ottetto indirizzo IP non valido",
|
||||
"path": "Percorso",
|
||||
"matchPath": "Corrispondenza Tracciato",
|
||||
"ipAddressRange": "Intervallo IP",
|
||||
"rulesErrorFetch": "Impossibile recuperare le regole",
|
||||
"rulesErrorFetchDescription": "Si è verificato un errore durante il recupero delle regole",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Azioni",
|
||||
"rulesActionAlwaysAllow": "Consenti Sempre: Ignora tutti i metodi di autenticazione",
|
||||
"rulesActionAlwaysDeny": "Nega Sempre: Blocca tutte le richieste; nessuna autenticazione può essere tentata",
|
||||
"rulesActionPassToAuth": "Passa all'autenticazione: Consenti di tentare i metodi di autenticazione",
|
||||
"rulesMatchCriteria": "Criteri di Corrispondenza",
|
||||
"rulesMatchCriteriaIpAddress": "Corrisponde a un indirizzo IP specifico",
|
||||
"rulesMatchCriteriaIpAddressRange": "Corrisponde a un intervallo di indirizzi IP in notazione CIDR",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "Il PIN deve essere esattamente di 6 cifre",
|
||||
"pincodeRequirementsChars": "Il PIN deve contenere solo numeri",
|
||||
"passwordRequirementsLength": "La password deve essere lunga almeno 1 carattere",
|
||||
"passwordRequirementsTitle": "Requisiti della password:",
|
||||
"passwordRequirementLength": "Almeno 8 caratteri",
|
||||
"passwordRequirementUppercase": "Almeno una lettera maiuscola",
|
||||
"passwordRequirementLowercase": "Almeno una lettera minuscola",
|
||||
"passwordRequirementNumber": "Almeno un numero",
|
||||
"passwordRequirementSpecial": "Almeno un carattere speciale",
|
||||
"passwordRequirementsMet": "✓ La password soddisfa tutti i requisiti",
|
||||
"passwordStrength": "Forza della password",
|
||||
"passwordStrengthWeak": "Debole",
|
||||
"passwordStrengthMedium": "Media",
|
||||
"passwordStrengthStrong": "Forte",
|
||||
"passwordRequirements": "Requisiti:",
|
||||
"passwordRequirementLengthText": "8+ caratteri",
|
||||
"passwordRequirementUppercaseText": "Lettera maiuscola (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Lettera minuscola (a-z)",
|
||||
"passwordRequirementNumberText": "Numero (0-9)",
|
||||
"passwordRequirementSpecialText": "Carattere speciale (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Le password non coincidono",
|
||||
"otpEmailRequirementsLength": "L'OTP deve essere lungo almeno 1 carattere",
|
||||
"otpEmailSent": "OTP Inviato",
|
||||
"otpEmailSentDescription": "Un OTP è stato inviato alla tua email",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Connesso",
|
||||
"idpErrorConnectingTo": "Si è verificato un problema durante la connessione a {name}. Contatta il tuo amministratore.",
|
||||
"idpErrorNotFound": "IdP non trovato",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Invito Non Valido",
|
||||
"inviteInvalidDescription": "Il link di invito non è valido.",
|
||||
"inviteErrorWrongUser": "L'invito non è per questo utente",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Errore durante il logout",
|
||||
"signingAs": "Accesso come",
|
||||
"serverAdmin": "Amministratore Server",
|
||||
"managedSelfhosted": "Gestito Auto-Ospitato",
|
||||
"otpEnable": "Abilita Autenticazione a Due Fattori",
|
||||
"otpDisable": "Disabilita Autenticazione a Due Fattori",
|
||||
"logout": "Disconnetti",
|
||||
"licenseTierProfessionalRequired": "Edizione Professional Richiesta",
|
||||
"licenseTierProfessionalRequiredDescription": "Questa funzionalità è disponibile solo nell'Edizione Professional.",
|
||||
"actionGetOrg": "Ottieni Organizzazione",
|
||||
"updateOrgUser": "Aggiorna Utente Org",
|
||||
"createOrgUser": "Crea Utente Org",
|
||||
"actionUpdateOrg": "Aggiorna Organizzazione",
|
||||
"actionUpdateUser": "Aggiorna Utente",
|
||||
"actionGetUser": "Ottieni Utente",
|
||||
"actionGetOrgUser": "Ottieni Utente Organizzazione",
|
||||
"actionListOrgDomains": "Elenca Domini Organizzazione",
|
||||
"actionCreateSite": "Crea Sito",
|
||||
"actionDeleteSite": "Elimina Sito",
|
||||
"actionGetSite": "Ottieni Sito",
|
||||
"actionListSites": "Elenca Siti",
|
||||
"actionApplyBlueprint": "Applica Progetto",
|
||||
"setupToken": "Configura Token",
|
||||
"setupTokenDescription": "Inserisci il token di configurazione dalla console del server.",
|
||||
"setupTokenRequired": "Il token di configurazione è richiesto",
|
||||
"actionUpdateSite": "Aggiorna Sito",
|
||||
"actionListSiteRoles": "Elenca Ruoli Sito Consentiti",
|
||||
"actionCreateResource": "Crea Risorsa",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Elimina Politica Org IDP",
|
||||
"actionListIdpOrgs": "Elenca Org IDP",
|
||||
"actionUpdateIdpOrg": "Aggiorna Org IDP",
|
||||
"actionCreateClient": "Crea Client",
|
||||
"actionDeleteClient": "Elimina Client",
|
||||
"actionUpdateClient": "Aggiorna Client",
|
||||
"actionListClients": "Elenco Clienti",
|
||||
"actionGetClient": "Ottieni Client",
|
||||
"actionCreateSiteResource": "Crea Risorsa del Sito",
|
||||
"actionDeleteSiteResource": "Elimina Risorsa del Sito",
|
||||
"actionGetSiteResource": "Ottieni Risorsa del Sito",
|
||||
"actionListSiteResources": "Elenca Risorse del Sito",
|
||||
"actionUpdateSiteResource": "Aggiorna Risorsa del Sito",
|
||||
"actionListInvitations": "Elenco Inviti",
|
||||
"noneSelected": "Nessuna selezione",
|
||||
"orgNotFound2": "Nessuna organizzazione trovata.",
|
||||
"searchProgress": "Ricerca...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Tutti Gli Utenti",
|
||||
"sidebarIdentityProviders": "Fornitori Di Identità",
|
||||
"sidebarLicense": "Licenza",
|
||||
"enableDockerSocket": "Abilita Docker Socket",
|
||||
"enableDockerSocketDescription": "Abilita il rilevamento Docker Socket per popolare le informazioni del contenitore. Il percorso del socket deve essere fornito a Newt.",
|
||||
"sidebarClients": "Clienti (Beta)",
|
||||
"sidebarDomains": "Domini",
|
||||
"enableDockerSocket": "Abilita Progetto Docker",
|
||||
"enableDockerSocketDescription": "Abilita la raschiatura dell'etichetta Docker Socket per le etichette dei progetti. Il percorso del socket deve essere fornito a Newt.",
|
||||
"enableDockerSocketLink": "Scopri di più",
|
||||
"viewDockerContainers": "Visualizza Contenitori Docker",
|
||||
"containersIn": "Contenitori in {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Reti",
|
||||
"containerHostnameIp": "Hostname/IP",
|
||||
"containerLabels": "Etichette",
|
||||
"containerLabelsCount": "{count} etichetta{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# etichetta} other {# etichette}}",
|
||||
"containerLabelsTitle": "Etichette Del Contenitore",
|
||||
"containerLabelEmpty": "<vuoto>",
|
||||
"containerPorts": "Porte",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Mostra contenitori fermati",
|
||||
"noContainersFound": "Nessun contenitore trovato. Assicurarsi che i contenitori Docker siano in esecuzione.",
|
||||
"searchContainersPlaceholder": "Cerca tra i contenitori {count}...",
|
||||
"searchResultsCount": "{count} risultato{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# risultato} other {# risultati}}",
|
||||
"filters": "Filtri",
|
||||
"filterOptions": "Opzioni Filtro",
|
||||
"filterPorts": "Porte",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "scuro",
|
||||
"system": "sistema",
|
||||
"theme": "Tema",
|
||||
"subnetRequired": "Sottorete richiesta",
|
||||
"initialSetupTitle": "Impostazione Iniziale del Server",
|
||||
"initialSetupDescription": "Crea l'account amministratore del server iniziale. Può esistere solo un amministratore del server. È sempre possibile modificare queste credenziali in seguito.",
|
||||
"createAdminAccount": "Crea Account Admin",
|
||||
"setupErrorCreateAdmin": "Si è verificato un errore durante la creazione dell'account amministratore del server."
|
||||
"setupErrorCreateAdmin": "Si è verificato un errore durante la creazione dell'account amministratore del server.",
|
||||
"certificateStatus": "Stato del Certificato",
|
||||
"loading": "Caricamento",
|
||||
"restart": "Riavvia",
|
||||
"domains": "Domini",
|
||||
"domainsDescription": "Gestisci domini per la tua organizzazione",
|
||||
"domainsSearch": "Cerca domini...",
|
||||
"domainAdd": "Aggiungi Dominio",
|
||||
"domainAddDescription": "Registra un nuovo dominio con la tua organizzazione",
|
||||
"domainCreate": "Crea Dominio",
|
||||
"domainCreatedDescription": "Dominio creato con successo",
|
||||
"domainDeletedDescription": "Dominio eliminato con successo",
|
||||
"domainQuestionRemove": "Sei sicuro di voler rimuovere il dominio {domain} dal tuo account?",
|
||||
"domainMessageRemove": "Una volta rimosso, il dominio non sarà più associato al tuo account.",
|
||||
"domainMessageConfirm": "Per confermare, digita il nome del dominio qui sotto.",
|
||||
"domainConfirmDelete": "Conferma Eliminazione Dominio",
|
||||
"domainDelete": "Elimina Dominio",
|
||||
"domain": "Dominio",
|
||||
"selectDomainTypeNsName": "Delega Dominio (NS)",
|
||||
"selectDomainTypeNsDescription": "Questo dominio e tutti i suoi sottodomini. Usa questo quando desideri controllare un'intera zona di dominio.",
|
||||
"selectDomainTypeCnameName": "Dominio Singolo (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Solo questo dominio specifico. Usa questo per sottodomini individuali o specifiche voci di dominio.",
|
||||
"selectDomainTypeWildcardName": "Dominio Jolly",
|
||||
"selectDomainTypeWildcardDescription": "Questo dominio e i suoi sottodomini.",
|
||||
"domainDelegation": "Dominio Singolo",
|
||||
"selectType": "Seleziona un tipo",
|
||||
"actions": "Azioni",
|
||||
"refresh": "Aggiorna",
|
||||
"refreshError": "Impossibile aggiornare i dati",
|
||||
"verified": "Verificato",
|
||||
"pending": "In attesa",
|
||||
"sidebarBilling": "Fatturazione",
|
||||
"billing": "Fatturazione",
|
||||
"orgBillingDescription": "Gestisci le tue informazioni di fatturazione e abbonamenti",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hosted",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Completa la Configurazione dell'Account",
|
||||
"completeAccountSetupDescription": "Imposta la tua password per iniziare",
|
||||
"accountSetupSent": "Invieremo un codice di configurazione dell'account a questo indirizzo email.",
|
||||
"accountSetupCode": "Codice di Configurazione",
|
||||
"accountSetupCodeDescription": "Controlla la tua email per il codice di configurazione.",
|
||||
"passwordCreate": "Crea Password",
|
||||
"passwordCreateConfirm": "Conferma Password",
|
||||
"accountSetupSubmit": "Invia Codice di Configurazione",
|
||||
"completeSetup": "Completa la Configurazione",
|
||||
"accountSetupSuccess": "Configurazione dell'account completata! Benvenuto su Pangolin!",
|
||||
"documentation": "Documentazione",
|
||||
"saveAllSettings": "Salva Tutte le Impostazioni",
|
||||
"settingsUpdated": "Impostazioni aggiornate",
|
||||
"settingsUpdatedDescription": "Tutte le impostazioni sono state aggiornate con successo",
|
||||
"settingsErrorUpdate": "Impossibile aggiornare le impostazioni",
|
||||
"settingsErrorUpdateDescription": "Si è verificato un errore durante l'aggiornamento delle impostazioni",
|
||||
"sidebarCollapse": "Comprimi",
|
||||
"sidebarExpand": "Espandi",
|
||||
"newtUpdateAvailable": "Aggiornamento Disponibile",
|
||||
"newtUpdateAvailableInfo": "È disponibile una nuova versione di Newt. Si prega di aggiornare all'ultima versione per la migliore esperienza.",
|
||||
"domainPickerEnterDomain": "Dominio",
|
||||
"domainPickerPlaceholder": "myapp.example.com",
|
||||
"domainPickerDescription": "Inserisci il dominio completo della risorsa per vedere le opzioni disponibili.",
|
||||
"domainPickerDescriptionSaas": "Inserisci un dominio completo, un sottodominio o semplicemente un nome per vedere le opzioni disponibili",
|
||||
"domainPickerTabAll": "Tutti",
|
||||
"domainPickerTabOrganization": "Organizzazione",
|
||||
"domainPickerTabProvided": "Fornito",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Controllando la disponibilità...",
|
||||
"domainPickerNoMatchingDomains": "Nessun dominio corrispondente trovato. Prova un dominio diverso o verifica le impostazioni del dominio della tua organizzazione.",
|
||||
"domainPickerOrganizationDomains": "Domini dell'Organizzazione",
|
||||
"domainPickerProvidedDomains": "Domini Forniti",
|
||||
"domainPickerSubdomain": "Sottodominio: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"domainPickerShowMore": "Mostra Altro",
|
||||
"domainNotFound": "Domini Non Trovati",
|
||||
"domainNotFoundDescription": "Questa risorsa è disabilitata perché il dominio non esiste più nel nostro sistema. Si prega di impostare un nuovo dominio per questa risorsa.",
|
||||
"failed": "Fallito",
|
||||
"createNewOrgDescription": "Crea una nuova organizzazione",
|
||||
"organization": "Organizzazione",
|
||||
"port": "Porta",
|
||||
"securityKeyManage": "Gestisci chiavi di sicurezza",
|
||||
"securityKeyDescription": "Aggiungi o rimuovi chiavi di sicurezza per l'autenticazione senza password",
|
||||
"securityKeyRegister": "Registra nuova chiave di sicurezza",
|
||||
"securityKeyList": "Le tue chiavi di sicurezza",
|
||||
"securityKeyNone": "Nessuna chiave di sicurezza registrata",
|
||||
"securityKeyNameRequired": "Il nome è obbligatorio",
|
||||
"securityKeyRemove": "Rimuovi",
|
||||
"securityKeyLastUsed": "Ultimo utilizzo: {date}",
|
||||
"securityKeyNameLabel": "Nome",
|
||||
"securityKeyRegisterSuccess": "Chiave di sicurezza registrata con successo",
|
||||
"securityKeyRegisterError": "Errore durante la registrazione della chiave di sicurezza",
|
||||
"securityKeyRemoveSuccess": "Chiave di sicurezza rimossa con successo",
|
||||
"securityKeyRemoveError": "Errore durante la rimozione della chiave di sicurezza",
|
||||
"securityKeyLoadError": "Errore durante il caricamento delle chiavi di sicurezza",
|
||||
"securityKeyLogin": "Continua con la chiave di sicurezza",
|
||||
"securityKeyAuthError": "Errore durante l'autenticazione con chiave di sicurezza",
|
||||
"securityKeyRecommendation": "Considera di registrare un'altra chiave di sicurezza su un dispositivo diverso per assicurarti di non rimanere bloccato fuori dal tuo account.",
|
||||
"registering": "Registrazione in corso...",
|
||||
"securityKeyPrompt": "Verifica la tua identità usando la chiave di sicurezza. Assicurati che sia connessa e pronta.",
|
||||
"securityKeyBrowserNotSupported": "Il tuo browser non supporta le chiavi di sicurezza. Per favore, usa un browser moderno come Chrome, Firefox o Safari.",
|
||||
"securityKeyPermissionDenied": "Consenti accesso alla tua chiave di sicurezza per continuare ad accedere.",
|
||||
"securityKeyRemovedTooQuickly": "Mantieni la chiave di sicurezza connessa fino a quando il processo di accesso non è completato.",
|
||||
"securityKeyNotSupported": "La tua chiave di sicurezza potrebbe non essere compatibile. Prova un'altra chiave di sicurezza.",
|
||||
"securityKeyUnknownError": "Si è verificato un problema con la tua chiave di sicurezza. Riprova.",
|
||||
"twoFactorRequired": "È richiesta l'autenticazione a due fattori per registrare una chiave di sicurezza.",
|
||||
"twoFactor": "Autenticazione a Due Fattori",
|
||||
"adminEnabled2FaOnYourAccount": "Il tuo amministratore ha abilitato l'autenticazione a due fattori per {email}. Completa il processo di configurazione per continuare.",
|
||||
"continueToApplication": "Continua all'Applicazione",
|
||||
"securityKeyAdd": "Aggiungi Chiave di Sicurezza",
|
||||
"securityKeyRegisterTitle": "Registra Nuova Chiave di Sicurezza",
|
||||
"securityKeyRegisterDescription": "Collega la tua chiave di sicurezza e inserisci un nome per identificarla",
|
||||
"securityKeyTwoFactorRequired": "Autenticazione a Due Fattori Richiesta",
|
||||
"securityKeyTwoFactorDescription": "Inserisci il codice di autenticazione a due fattori per registrare la chiave di sicurezza",
|
||||
"securityKeyTwoFactorRemoveDescription": "Inserisci il codice di autenticazione a due fattori per rimuovere la chiave di sicurezza",
|
||||
"securityKeyTwoFactorCode": "Codice a Due Fattori",
|
||||
"securityKeyRemoveTitle": "Rimuovi Chiave di Sicurezza",
|
||||
"securityKeyRemoveDescription": "Inserisci la tua password per rimuovere la chiave di sicurezza \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "Nessuna chiave di sicurezza registrata",
|
||||
"securityKeyNoKeysDescription": "Aggiungi una chiave di sicurezza per migliorare la sicurezza del tuo account",
|
||||
"createDomainRequired": "Dominio richiesto",
|
||||
"createDomainAddDnsRecords": "Aggiungi Record DNS",
|
||||
"createDomainAddDnsRecordsDescription": "Aggiungi i seguenti record DNS al tuo provider di domini per completare la configurazione.",
|
||||
"createDomainNsRecords": "Record NS",
|
||||
"createDomainRecord": "Record",
|
||||
"createDomainType": "Tipo:",
|
||||
"createDomainName": "Nome:",
|
||||
"createDomainValue": "Valore:",
|
||||
"createDomainCnameRecords": "Record CNAME",
|
||||
"createDomainARecords": "Record A",
|
||||
"createDomainRecordNumber": "Record {number}",
|
||||
"createDomainTxtRecords": "Record TXT",
|
||||
"createDomainSaveTheseRecords": "Salva Questi Record",
|
||||
"createDomainSaveTheseRecordsDescription": "Assicurati di salvare questi record DNS poiché non li vedrai più.",
|
||||
"createDomainDnsPropagation": "Propagazione DNS",
|
||||
"createDomainDnsPropagationDescription": "Le modifiche DNS possono richiedere del tempo per propagarsi in Internet. Questo può richiedere da pochi minuti a 48 ore, a seconda del tuo provider DNS e delle impostazioni TTL.",
|
||||
"resourcePortRequired": "Numero di porta richiesto per risorse non-HTTP",
|
||||
"resourcePortNotAllowed": "Il numero di porta non deve essere impostato per risorse HTTP",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Accetto i",
|
||||
"termsOfService": "termini di servizio",
|
||||
"and": "e",
|
||||
"privacyPolicy": "informativa sulla privacy"
|
||||
},
|
||||
"siteRequired": "Il sito è richiesto.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Usa Olm per la connettività client",
|
||||
"errorCreatingClient": "Errore nella creazione del client",
|
||||
"clientDefaultsNotFound": "Impostazioni predefinite del client non trovate",
|
||||
"createClient": "Crea Cliente",
|
||||
"createClientDescription": "Crea un nuovo cliente per connettersi ai tuoi siti",
|
||||
"seeAllClients": "Vedi Tutti i Clienti",
|
||||
"clientInformation": "Informazioni sul Cliente",
|
||||
"clientNamePlaceholder": "Nome Cliente",
|
||||
"address": "Indirizzo",
|
||||
"subnetPlaceholder": "Sottorete",
|
||||
"addressDescription": "L'indirizzo che questo cliente utilizzerà per la connettività",
|
||||
"selectSites": "Seleziona siti",
|
||||
"sitesDescription": "Il cliente avrà connettività ai siti selezionati",
|
||||
"clientInstallOlm": "Installa Olm",
|
||||
"clientInstallOlmDescription": "Avvia Olm sul tuo sistema",
|
||||
"clientOlmCredentials": "Credenziali Olm",
|
||||
"clientOlmCredentialsDescription": "Ecco come Olm si autenticherà con il server",
|
||||
"olmEndpoint": "Endpoint Olm",
|
||||
"olmId": "ID Olm",
|
||||
"olmSecretKey": "Chiave Segreta Olm",
|
||||
"clientCredentialsSave": "Salva le Tue Credenziali",
|
||||
"clientCredentialsSaveDescription": "Potrai vederlo solo una volta. Assicurati di copiarlo in un luogo sicuro.",
|
||||
"generalSettingsDescription": "Configura le impostazioni generali per questo cliente",
|
||||
"clientUpdated": "Cliente aggiornato",
|
||||
"clientUpdatedDescription": "Il cliente è stato aggiornato.",
|
||||
"clientUpdateFailed": "Impossibile aggiornare il cliente",
|
||||
"clientUpdateError": "Si è verificato un errore durante l'aggiornamento del cliente.",
|
||||
"sitesFetchFailed": "Impossibile recuperare i siti",
|
||||
"sitesFetchError": "Si è verificato un errore durante il recupero dei siti.",
|
||||
"olmErrorFetchReleases": "Si è verificato un errore durante il recupero delle versioni di Olm.",
|
||||
"olmErrorFetchLatest": "Si è verificato un errore durante il recupero dell'ultima versione di Olm.",
|
||||
"remoteSubnets": "Sottoreti Remote",
|
||||
"enterCidrRange": "Inserisci l'intervallo CIDR",
|
||||
"remoteSubnetsDescription": "Aggiungi intervalli CIDR che possono essere accessibili da questo sito in remoto utilizzando i client. Usa il formato come 10.0.0.0/24. Questo si applica SOLO alla connettività del client VPN.",
|
||||
"resourceEnableProxy": "Abilita Proxy Pubblico",
|
||||
"resourceEnableProxyDescription": "Abilita il proxy pubblico a questa risorsa. Consente l'accesso alla risorsa dall'esterno della rete tramite il cloud su una porta aperta. Richiede la configurazione di Traefik.",
|
||||
"externalProxyEnabled": "Proxy Esterno Abilitato",
|
||||
"addNewTarget": "Aggiungi Nuovo Target",
|
||||
"targetsList": "Elenco dei Target",
|
||||
"targetErrorDuplicateTargetFound": "Target duplicato trovato",
|
||||
"httpMethod": "Metodo HTTP",
|
||||
"selectHttpMethod": "Seleziona metodo HTTP",
|
||||
"domainPickerSubdomainLabel": "Sottodominio",
|
||||
"domainPickerBaseDomainLabel": "Dominio Base",
|
||||
"domainPickerSearchDomains": "Cerca domini...",
|
||||
"domainPickerNoDomainsFound": "Nessun dominio trovato",
|
||||
"domainPickerLoadingDomains": "Caricamento domini...",
|
||||
"domainPickerSelectBaseDomain": "Seleziona dominio base...",
|
||||
"domainPickerNotAvailableForCname": "Non disponibile per i domini CNAME",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Inserisci un sottodominio o lascia vuoto per utilizzare il dominio base.",
|
||||
"domainPickerEnterSubdomainToSearch": "Inserisci un sottodominio per cercare e selezionare dai domini gratuiti disponibili.",
|
||||
"domainPickerFreeDomains": "Domini Gratuiti",
|
||||
"domainPickerSearchForAvailableDomains": "Cerca domini disponibili",
|
||||
"resourceDomain": "Dominio",
|
||||
"resourceEditDomain": "Modifica Dominio",
|
||||
"siteName": "Nome del Sito",
|
||||
"proxyPort": "Porta",
|
||||
"resourcesTableProxyResources": "Risorse Proxy",
|
||||
"resourcesTableClientResources": "Risorse Client",
|
||||
"resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.",
|
||||
"resourcesTableDestination": "Destinazione",
|
||||
"resourcesTableTheseResourcesForUseWith": "Queste risorse sono per uso con",
|
||||
"resourcesTableClients": "Client",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "e sono accessibili solo internamente quando connessi con un client.",
|
||||
"editInternalResourceDialogEditClientResource": "Modifica Risorsa Client",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Aggiorna le proprietà della risorsa e la configurazione del target per {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Proprietà della Risorsa",
|
||||
"editInternalResourceDialogName": "Nome",
|
||||
"editInternalResourceDialogProtocol": "Protocollo",
|
||||
"editInternalResourceDialogSitePort": "Porta del Sito",
|
||||
"editInternalResourceDialogTargetConfiguration": "Configurazione Target",
|
||||
"editInternalResourceDialogCancel": "Annulla",
|
||||
"editInternalResourceDialogSaveResource": "Salva Risorsa",
|
||||
"editInternalResourceDialogSuccess": "Successo",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa interna aggiornata con successo",
|
||||
"editInternalResourceDialogError": "Errore",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa interna",
|
||||
"editInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||
"editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri",
|
||||
"editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
|
||||
"editInternalResourceDialogProxyPortMax": "La porta proxy deve essere inferiore a 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Formato dell'indirizzo IP non valido",
|
||||
"editInternalResourceDialogDestinationPortMin": "La porta di destinazione deve essere almeno 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "La porta di destinazione deve essere inferiore a 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Nessun Sito Disponibile",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Devi avere almeno un sito Newt con una subnet configurata per creare risorse interne.",
|
||||
"createInternalResourceDialogClose": "Chiudi",
|
||||
"createInternalResourceDialogCreateClientResource": "Crea Risorsa Client",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile ai client connessi al sito selezionato.",
|
||||
"createInternalResourceDialogResourceProperties": "Proprietà della Risorsa",
|
||||
"createInternalResourceDialogName": "Nome",
|
||||
"createInternalResourceDialogSite": "Sito",
|
||||
"createInternalResourceDialogSelectSite": "Seleziona sito...",
|
||||
"createInternalResourceDialogSearchSites": "Cerca siti...",
|
||||
"createInternalResourceDialogNoSitesFound": "Nessun sito trovato.",
|
||||
"createInternalResourceDialogProtocol": "Protocollo",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Porta del Sito",
|
||||
"createInternalResourceDialogSitePortDescription": "Usa questa porta per accedere alla risorsa nel sito quando sei connesso con un client.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Configurazione Target",
|
||||
"createInternalResourceDialogDestinationIPDescription": "L'indirizzo IP o hostname della risorsa nella rete del sito.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "La porta sull'IP di destinazione dove la risorsa è accessibile.",
|
||||
"createInternalResourceDialogCancel": "Annulla",
|
||||
"createInternalResourceDialogCreateResource": "Crea Risorsa",
|
||||
"createInternalResourceDialogSuccess": "Successo",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa interna creata con successo",
|
||||
"createInternalResourceDialogError": "Errore",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa interna",
|
||||
"createInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||
"createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito",
|
||||
"createInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
|
||||
"createInternalResourceDialogProxyPortMax": "La porta proxy deve essere inferiore a 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Formato dell'indirizzo IP non valido",
|
||||
"createInternalResourceDialogDestinationPortMin": "La porta di destinazione deve essere almeno 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "La porta di destinazione deve essere inferiore a 65536",
|
||||
"siteConfiguration": "Configurazione",
|
||||
"siteAcceptClientConnections": "Accetta Connessioni Client",
|
||||
"siteAcceptClientConnectionsDescription": "Permetti ad altri dispositivi di connettersi attraverso questa istanza Newt come gateway utilizzando i client.",
|
||||
"siteAddress": "Indirizzo del Sito",
|
||||
"siteAddressDescription": "Specifica l'indirizzo IP dell'host a cui i client si collegano. Questo è l'indirizzo interno del sito nella rete Pangolin per indirizzare i client. Deve rientrare nella subnet dell'Organizzazione.",
|
||||
"autoLoginExternalIdp": "Accesso Automatico con IDP Esterno",
|
||||
"autoLoginExternalIdpDescription": "Reindirizzare immediatamente l'utente all'IDP esterno per l'autenticazione.",
|
||||
"selectIdp": "Seleziona IDP",
|
||||
"selectIdpPlaceholder": "Scegli un IDP...",
|
||||
"selectIdpRequired": "Si prega di selezionare un IDP quando l'accesso automatico è abilitato.",
|
||||
"autoLoginTitle": "Reindirizzamento",
|
||||
"autoLoginDescription": "Reindirizzandoti al provider di identità esterno per l'autenticazione.",
|
||||
"autoLoginProcessing": "Preparazione dell'autenticazione...",
|
||||
"autoLoginRedirecting": "Reindirizzamento al login...",
|
||||
"autoLoginError": "Errore di Accesso Automatico",
|
||||
"autoLoginErrorNoRedirectUrl": "Nessun URL di reindirizzamento ricevuto dal provider di identità.",
|
||||
"autoLoginErrorGeneratingUrl": "Impossibile generare l'URL di autenticazione.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Gestito Auto-Ospitato",
|
||||
"description": "Server Pangolin self-hosted più affidabile e a bassa manutenzione con campanelli e fischietti extra",
|
||||
"introTitle": "Managed Self-Hosted Pangolin",
|
||||
"introDescription": "è un'opzione di distribuzione progettata per le persone che vogliono la semplicità e l'affidabilità extra mantenendo i loro dati privati e self-hosted.",
|
||||
"introDetail": "Con questa opzione, esegui ancora il tuo nodo Pangolin — i tunnel, la terminazione SSL e il traffico rimangono tutti sul tuo server. La differenza è che la gestione e il monitoraggio sono gestiti attraverso il nostro cruscotto cloud, che sblocca una serie di vantaggi:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Operazioni più semplici",
|
||||
"description": "Non è necessario eseguire il proprio server di posta o impostare un avviso complesso. Otterrai controlli di salute e avvisi di inattività fuori dalla casella."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Aggiornamenti automatici",
|
||||
"description": "Il cruscotto cloud si evolve rapidamente, in modo da ottenere nuove funzionalità e correzioni di bug senza dover tirare manualmente nuovi contenitori ogni volta."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Meno manutenzione",
|
||||
"description": "Nessuna migrazione di database, backup o infrastruttura extra da gestire. Gestiamo questo problema nel cloud."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "failover del cloud",
|
||||
"description": "Se il tuo nodo scende, i tuoi tunnel possono temporaneamente fallire nei nostri punti di presenza cloud fino a quando non lo riporti online."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Alta disponibilità (PoPs)",
|
||||
"description": "Puoi anche allegare più nodi al tuo account per ridondanza e prestazioni migliori."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Miglioramenti futuri",
|
||||
"description": "Stiamo pianificando di aggiungere più strumenti di analisi, allerta e gestione per rendere la tua distribuzione ancora più robusta."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Scopri di più sull'opzione Managed Self-Hosted nella nostra",
|
||||
"documentation": "documentazione"
|
||||
},
|
||||
"convertButton": "Converti questo nodo in auto-ospitato gestito"
|
||||
},
|
||||
"internationaldomaindetected": "Dominio Internazionale Rilevato",
|
||||
"willbestoredas": "Verrà conservato come:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC provider",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Intestazioni Personalizzate",
|
||||
"headersValidationError": "Le intestazioni devono essere nel formato: Intestazione-Nome: valore.",
|
||||
"domainPickerProvidedDomain": "Dominio Fornito",
|
||||
"domainPickerFreeProvidedDomain": "Dominio Fornito Gratuito",
|
||||
"domainPickerVerified": "Verificato",
|
||||
"domainPickerUnverified": "Non Verificato",
|
||||
"domainPickerInvalidSubdomainStructure": "Questo sottodominio contiene caratteri o struttura non validi. Sarà sanificato automaticamente quando si salva.",
|
||||
"domainPickerError": "Errore",
|
||||
"domainPickerErrorLoadDomains": "Impossibile caricare i domini dell'organizzazione",
|
||||
"domainPickerErrorCheckAvailability": "Impossibile verificare la disponibilità del dominio",
|
||||
"domainPickerInvalidSubdomain": "Sottodominio non valido",
|
||||
"domainPickerInvalidSubdomainRemoved": "L'input \"{sub}\" è stato rimosso perché non è valido.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" non può essere reso valido per {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Sottodominio igienizzato",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" è stato corretto in \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Modifica file: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Modifica file: docker-compose.yml"
|
||||
}
|
||||
|
||||
1523
messages/ko-KR.json
Normal file
1523
messages/nb-NO.json
Normal file
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "U bent momenteel geen lid van een organisatie. Maak een organisatie aan om aan de slag te gaan.",
|
||||
"componentsErrorNoMember": "U bent momenteel geen lid van een organisatie.",
|
||||
"welcome": "Welkom bij Pangolin",
|
||||
"welcomeTo": "Welkom bij",
|
||||
"componentsCreateOrg": "Maak een Organisatie",
|
||||
"componentsMember": "Je bent lid van {count, plural, =0 {geen organisatie} =1 {één organisatie} other {# organisaties}}.",
|
||||
"componentsMember": "Je bent lid van {count, plural, =0 {geen organisatie} one {één organisatie} other {# organisaties}}.",
|
||||
"componentsInvalidKey": "Ongeldige of verlopen licentiesleutels gedetecteerd. Volg de licentievoorwaarden om alle functies te blijven gebruiken.",
|
||||
"dismiss": "Uitschakelen",
|
||||
"componentsLicenseViolation": "Licentie overtreding: Deze server gebruikt {usedSites} sites die de gelicentieerde limiet van {maxSites} sites overschrijden. Volg de licentievoorwaarden om door te gaan met het gebruik van alle functies.",
|
||||
@@ -37,12 +38,12 @@
|
||||
"name": "naam",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"site": "Website",
|
||||
"dataIn": "Gegevens in",
|
||||
"dataOut": "Data Uit",
|
||||
"site": "Referentie",
|
||||
"dataIn": "Dataverbruik inkomend",
|
||||
"dataOut": "Dataverbruik uitgaand",
|
||||
"connectionType": "Type verbinding",
|
||||
"tunnelType": "Tunnel type",
|
||||
"local": "lokaal",
|
||||
"local": "Lokaal",
|
||||
"edit": "Bewerken",
|
||||
"siteConfirmDelete": "Verwijderen van site bevestigen",
|
||||
"siteDelete": "Site verwijderen",
|
||||
@@ -54,11 +55,10 @@
|
||||
"siteCreate": "Site maken",
|
||||
"siteCreateDescription2": "Volg de onderstaande stappen om een nieuwe site aan te maken en te verbinden",
|
||||
"siteCreateDescription": "Maak een nieuwe site aan om verbinding te maken met uw bronnen",
|
||||
"close": "Afsluiten",
|
||||
"close": "Sluiten",
|
||||
"siteErrorCreate": "Fout bij maken site",
|
||||
"siteErrorCreateKeyPair": "Key pair of site standaard niet gevonden",
|
||||
"siteErrorCreateDefaults": "Standaardinstellingen niet gevonden",
|
||||
"siteNameDescription": "Dit is de weergavenaam van de site.",
|
||||
"method": "Methode",
|
||||
"siteMethodDescription": "Op deze manier legt u verbindingen bloot.",
|
||||
"siteLearnNewt": "Leer hoe u Newt kunt installeren op uw systeem",
|
||||
@@ -90,11 +90,13 @@
|
||||
"siteGeneralDescription": "Algemene instellingen voor deze site configureren",
|
||||
"siteSettingDescription": "Configureer de instellingen op uw site",
|
||||
"siteSetting": "{siteName} instellingen",
|
||||
"siteNewtTunnel": "Nieuwstunnel (Aanbevolen)",
|
||||
"siteNewtTunnel": "Newttunnel (Aanbevolen)",
|
||||
"siteNewtTunnelDescription": "Gemakkelijkste manier om een ingangspunt in uw netwerk te maken. Geen extra opzet.",
|
||||
"siteWg": "Basis WireGuard",
|
||||
"siteWgDescription": "Gebruik een WireGuard client om een tunnel te bouwen. Handmatige NAT installatie vereist.",
|
||||
"siteWgDescriptionSaas": "Gebruik elke WireGuard-client om een tunnel op te zetten. Handmatige NAT-instelling vereist. WERKT ALLEEN OP SELF HOSTED NODES",
|
||||
"siteLocalDescription": "Alleen lokale bronnen. Geen tunneling.",
|
||||
"siteLocalDescriptionSaas": "Alleen lokale bronnen. Geen tunneling. WERKT ALLEEN OP SELF HOSTED NODES",
|
||||
"siteSeeAll": "Alle werkruimtes bekijken",
|
||||
"siteTunnelDescription": "Bepaal hoe u verbinding wilt maken met uw site",
|
||||
"siteNewtCredentials": "Nieuwste aanmeldgegevens",
|
||||
@@ -102,7 +104,7 @@
|
||||
"siteCredentialsSave": "Uw referenties opslaan",
|
||||
"siteCredentialsSaveDescription": "Je kunt dit slechts één keer zien. Kopieer het naar een beveiligde plek.",
|
||||
"siteInfo": "Site informatie",
|
||||
"status": "status",
|
||||
"status": "Status",
|
||||
"shareTitle": "Beheer deellinks",
|
||||
"shareDescription": "Maak deelbare links aan om tijdelijke of permanente toegang tot uw bronnen te verlenen",
|
||||
"shareSearch": "Zoek share links...",
|
||||
@@ -144,19 +146,19 @@
|
||||
"never": "Nooit",
|
||||
"shareErrorSelectResource": "Selecteer een bron",
|
||||
"resourceTitle": "Bronnen beheren",
|
||||
"resourceDescription": "Veilige proxy's voor uw privé applicaties maken",
|
||||
"resourceDescription": "Veilige proxy's voor uw privé applicaties aanmaken",
|
||||
"resourcesSearch": "Zoek bronnen...",
|
||||
"resourceAdd": "Bron toevoegen",
|
||||
"resourceErrorDelte": "Fout bij verwijderen document",
|
||||
"authentication": "Authenticatie",
|
||||
"protected": "Beschermd",
|
||||
"notProtected": "Niet beschermd",
|
||||
"protected": "Beveiligd",
|
||||
"notProtected": "Niet beveiligd",
|
||||
"resourceMessageRemove": "Eenmaal verwijderd, zal het bestand niet langer toegankelijk zijn. Alle doelen die gekoppeld zijn aan het hulpbron, zullen ook verwijderd worden.",
|
||||
"resourceMessageConfirm": "Om te bevestigen, typ de naam van de bron hieronder.",
|
||||
"resourceQuestionRemove": "Weet u zeker dat u de resource {selectedResource} uit de organisatie wilt verwijderen?",
|
||||
"resourceHTTP": "HTTPS bron",
|
||||
"resourceHTTPDescription": "Proxy verzoeken aan uw app via HTTPS via een subdomein of basisdomein.",
|
||||
"resourceRaw": "Ruwe TCP/UDP bron",
|
||||
"resourceRaw": "TCP/UDP bron",
|
||||
"resourceRawDescription": "Proxy verzoeken naar je app via TCP/UDP met behulp van een poortnummer.",
|
||||
"resourceCreate": "Bron maken",
|
||||
"resourceCreateDescription": "Volg de onderstaande stappen om een nieuwe bron te maken",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Selecteer site",
|
||||
"siteSearch": "Zoek site",
|
||||
"siteNotFound": "Geen site gevonden.",
|
||||
"siteSelectionDescription": "Deze site zal connectiviteit met de bron geven.",
|
||||
"siteSelectionDescription": "Deze site zal connectiviteit met het doelwit bieden.",
|
||||
"resourceType": "Type bron",
|
||||
"resourceTypeDescription": "Bepaal hoe u toegang wilt krijgen tot uw bron",
|
||||
"resourceHTTPSSettings": "HTTPS instellingen",
|
||||
@@ -181,7 +183,7 @@
|
||||
"protocolSelect": "Selecteer een protocol",
|
||||
"resourcePortNumber": "Nummer van poort",
|
||||
"resourcePortNumberDescription": "Het externe poortnummer naar proxyverzoeken.",
|
||||
"cancel": "annuleren",
|
||||
"cancel": "Annuleren",
|
||||
"resourceConfig": "Configuratie tekstbouwstenen",
|
||||
"resourceConfigDescription": "Kopieer en plak deze configuratie-snippets om je TCP/UDP-bron in te stellen",
|
||||
"resourceAddEntrypoints": "Traefik: Entrypoints toevoegen",
|
||||
@@ -197,17 +199,20 @@
|
||||
"general": "Algemeen",
|
||||
"generalSettings": "Algemene instellingen",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Intern",
|
||||
"rules": "Regels",
|
||||
"resourceSettingDescription": "Configureer de instellingen op uw bron",
|
||||
"resourceSetting": "{resourceName} instellingen",
|
||||
"alwaysAllow": "Altijd toestaan",
|
||||
"alwaysDeny": "Altijd weigeren",
|
||||
"passToAuth": "Passeren naar Auth",
|
||||
"orgSettingsDescription": "Configureer de algemene instellingen van je organisatie",
|
||||
"orgGeneralSettings": "Organisatie Instellingen",
|
||||
"orgGeneralSettingsDescription": "Beheer de details en configuratie van uw organisatie",
|
||||
"saveGeneralSettings": "Algemene instellingen opslaan",
|
||||
"saveSettings": "Instellingen opslaan",
|
||||
"orgDangerZone": "Gevaarlijke zone",
|
||||
"orgDangerZoneDescription": "Als u deze instantie verwijdert, is er geen weg terug. Wees het alstublieft zeker.",
|
||||
"orgDangerZoneDescription": "Deze instantie verwijderen is onomkeerbaar. Bevestig alstublieft dat u wilt doorgaan.",
|
||||
"orgDelete": "Verwijder organisatie",
|
||||
"orgDeleteConfirm": "Bevestig Verwijderen Organisatie",
|
||||
"orgMessageRemove": "Deze actie is onomkeerbaar en zal alle bijbehorende gegevens verwijderen.",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Weken",
|
||||
"months": "maanden",
|
||||
"years": "Jaar",
|
||||
"day": "{count, plural, =1 {# dag} other {# dagen}}",
|
||||
"day": "{count, plural, one {# dag} other {# dagen}}",
|
||||
"apiKeysTitle": "API Key Informatie",
|
||||
"apiKeysConfirmCopy2": "Bevestig dat u de API-sleutel hebt gekopieerd.",
|
||||
"apiKeysErrorCreate": "Fout bij maken API-sleutel",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Licentie kopen",
|
||||
"licensePurchaseSites": "Extra sites kopen",
|
||||
"licenseSitesUsedMax": "{usedSites} van {maxSites} sites gebruikt",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} =1 {# site} other {# sites}} in het systeem.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# locaties} one {# locatie} other {# locaties}} in het systeem.",
|
||||
"licensePurchaseDescription": "Kies hoeveel sites je wilt {selectedMode, select, license {Koop een licentie. Je kunt later altijd meer sites toevoegen.} other {Voeg je bestaande licentie toe}}",
|
||||
"licenseFee": "Licentie vergoeding",
|
||||
"licensePriceSite": "Prijs per site",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Selecteer rol",
|
||||
"inviteEmailSentDescription": "Een e-mail is verstuurd naar de gebruiker met de link hieronder. Ze moeten toegang krijgen tot de link om de uitnodiging te accepteren.",
|
||||
"inviteSentDescription": "De gebruiker is uitgenodigd. Ze moeten toegang krijgen tot de link hieronder om de uitnodiging te accepteren.",
|
||||
"inviteExpiresIn": "De uitnodiging vervalt in {days, plural, =1 {# dag} other {# dagen}}.",
|
||||
"inviteExpiresIn": "De uitnodiging vervalt over {days, plural, one {# dag} other {# dagen}}.",
|
||||
"idpTitle": "Identiteit Provider",
|
||||
"idpSelect": "Identiteitsprovider voor de externe gebruiker selecteren",
|
||||
"idpNotConfigured": "Er zijn geen identiteitsproviders geconfigureerd. Configureer een identiteitsprovider voordat u externe gebruikers aanmaakt.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Er is een fout opgetreden tijdens het toevoegen van de rol.",
|
||||
"userSaved": "Gebruiker opgeslagen",
|
||||
"userSavedDescription": "De gebruiker is bijgewerkt.",
|
||||
"autoProvisioned": "Automatisch bevestigen",
|
||||
"autoProvisionedDescription": "Toestaan dat deze gebruiker automatisch wordt beheerd door een identiteitsprovider",
|
||||
"accessControlsDescription": "Beheer wat deze gebruiker toegang heeft tot en doet in de organisatie",
|
||||
"accessControlsSubmit": "Bewaar Toegangsbesturing",
|
||||
"roles": "Rollen",
|
||||
@@ -489,13 +496,13 @@
|
||||
"targetTlsSniDescription": "De TLS servernaam om te gebruiken voor SNI. Laat leeg om de standaard te gebruiken.",
|
||||
"targetTlsSubmit": "Instellingen opslaan",
|
||||
"targets": "Doelstellingen configuratie",
|
||||
"targetsDescription": "Stel doelen in om verkeer naar uw diensten te leiden",
|
||||
"targetsDescription": "Stel doelen in om verkeer naar uw backend-services te leiden",
|
||||
"targetStickySessions": "Sticky sessies inschakelen",
|
||||
"targetStickySessionsDescription": "Behoud verbindingen op hetzelfde backend doel voor hun hele sessie.",
|
||||
"methodSelect": "Selecteer methode",
|
||||
"targetSubmit": "Doelwit toevoegen",
|
||||
"targetNoOne": "Geen doelwitten. Voeg een doel toe via het formulier.",
|
||||
"targetNoOneDescription": "Het toevoegen van meer dan één doel hierboven zal de load balancering mogelijk maken.",
|
||||
"targetNoOne": "Geen doel toegevoegd. Voeg deze toe via dit formulier.",
|
||||
"targetNoOneDescription": "Het toevoegen van meer dan één doel hierboven zal load balancering mogelijk maken.",
|
||||
"targetsSubmit": "Doelstellingen opslaan",
|
||||
"proxyAdditional": "Extra Proxy-instellingen",
|
||||
"proxyAdditionalDescription": "Configureer hoe de proxy-instellingen van uw bron worden afgehandeld",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Ongeldig IP-adresformaat",
|
||||
"ipAddressErrorInvalidOctet": "Ongeldige IP adres octet",
|
||||
"path": "Pad",
|
||||
"matchPath": "Overeenkomend pad",
|
||||
"ipAddressRange": "IP Bereik",
|
||||
"rulesErrorFetch": "Regels ophalen mislukt",
|
||||
"rulesErrorFetchDescription": "Er is een fout opgetreden bij het ophalen van de regels",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "acties",
|
||||
"rulesActionAlwaysAllow": "Altijd toegestaan: Omzeil alle authenticatiemethoden",
|
||||
"rulesActionAlwaysDeny": "Altijd weigeren: Blokkeer alle aanvragen, er kan geen verificatie worden geprobeerd",
|
||||
"rulesActionPassToAuth": "Doorgeven aan Auth: Toestaan dat authenticatiemethoden worden geprobeerd",
|
||||
"rulesMatchCriteria": "Overeenkomende criteria",
|
||||
"rulesMatchCriteriaIpAddress": "Overeenkomen met een specifiek IP-adres",
|
||||
"rulesMatchCriteriaIpAddressRange": "Overeenkomen met een bereik van IP-adressen in de CIDR-notatie",
|
||||
@@ -589,7 +598,7 @@
|
||||
"newtId": "Newt-ID",
|
||||
"newtSecretKey": "Nieuwe geheime sleutel",
|
||||
"architecture": "Architectuur",
|
||||
"sites": "Werkruimtes",
|
||||
"sites": "Verbindingen",
|
||||
"siteWgAnyClients": "Gebruik een willekeurige WireGuard client om verbinding te maken. Je moet je interne bronnen aanspreken met behulp van de peer IP.",
|
||||
"siteWgCompatibleAllClients": "Compatibel met alle WireGuard clients",
|
||||
"siteWgManualConfigurationRequired": "Handmatige configuratie vereist",
|
||||
@@ -720,7 +729,7 @@
|
||||
"idpMessageConfirm": "Om dit te bevestigen, typt u de naam van onderstaande identiteitsprovider.",
|
||||
"idpConfirmDelete": "Bevestig verwijderen Identity Provider",
|
||||
"idpDelete": "Identity Provider verwijderen",
|
||||
"idp": "Identiteit aanbieders",
|
||||
"idp": "Identiteitsaanbieders",
|
||||
"idpSearch": "Identiteitsaanbieders zoeken...",
|
||||
"idpAdd": "Identity Provider toevoegen",
|
||||
"idpClientIdRequired": "Client-ID is vereist.",
|
||||
@@ -792,7 +801,7 @@
|
||||
"defaultMappingsOrgDescription": "Deze expressie moet de org-ID teruggeven of waar om de gebruiker toegang te geven tot de organisatie.",
|
||||
"defaultMappingsSubmit": "Standaard toewijzingen opslaan",
|
||||
"orgPoliciesEdit": "Organisatie beleid bewerken",
|
||||
"org": "Rekening",
|
||||
"org": "Organisatie",
|
||||
"orgSelect": "Selecteer organisatie",
|
||||
"orgSearch": "Zoek in org",
|
||||
"orgNotFound": "Geen org gevonden.",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "Pincode moet precies 6 cijfers zijn",
|
||||
"pincodeRequirementsChars": "Pincode mag alleen cijfers bevatten",
|
||||
"passwordRequirementsLength": "Wachtwoord moet ten minste 1 teken lang zijn",
|
||||
"passwordRequirementsTitle": "Wachtwoordvereisten:",
|
||||
"passwordRequirementLength": "Minstens 8 tekens lang",
|
||||
"passwordRequirementUppercase": "Minstens één hoofdletter",
|
||||
"passwordRequirementLowercase": "Minstens één kleine letter",
|
||||
"passwordRequirementNumber": "Minstens één cijfer",
|
||||
"passwordRequirementSpecial": "Minstens één speciaal teken",
|
||||
"passwordRequirementsMet": "✓ Wachtwoord voldoet aan alle vereisten",
|
||||
"passwordStrength": "Wachtwoord sterkte",
|
||||
"passwordStrengthWeak": "Zwak",
|
||||
"passwordStrengthMedium": "Gemiddeld",
|
||||
"passwordStrengthStrong": "Sterk",
|
||||
"passwordRequirements": "Vereisten:",
|
||||
"passwordRequirementLengthText": "8+ tekens",
|
||||
"passwordRequirementUppercaseText": "Hoofdletter (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Kleine letter (a-z)",
|
||||
"passwordRequirementNumberText": "Cijfer (0-9)",
|
||||
"passwordRequirementSpecialText": "Speciaal teken (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Wachtwoorden komen niet overeen",
|
||||
"otpEmailRequirementsLength": "OTP moet minstens 1 teken lang zijn",
|
||||
"otpEmailSent": "OTP verzonden",
|
||||
"otpEmailSentDescription": "Een OTP is naar uw e-mail verzonden",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Verbonden",
|
||||
"idpErrorConnectingTo": "Er was een probleem bij het verbinden met {name}. Neem contact op met uw beheerder.",
|
||||
"idpErrorNotFound": "IdP niet gevonden",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Ongeldige uitnodiging",
|
||||
"inviteInvalidDescription": "Uitnodigingslink is ongeldig.",
|
||||
"inviteErrorWrongUser": "Uitnodiging is niet voor deze gebruiker",
|
||||
@@ -947,23 +976,32 @@
|
||||
"supportKeyEnterDescription": "Ontmoet je eigen huisdier Pangolin!",
|
||||
"githubUsername": "GitHub-gebruikersnaam",
|
||||
"supportKeyInput": "Supporter Sleutel",
|
||||
"supportKeyBuy": "Koop Supportersleutel",
|
||||
"supportKeyBuy": "Koop supportersleutel",
|
||||
"logoutError": "Fout bij uitloggen",
|
||||
"signingAs": "Ingelogd als",
|
||||
"serverAdmin": "Server Beheerder",
|
||||
"serverAdmin": "Server beheer",
|
||||
"managedSelfhosted": "Beheerde Self-Hosted",
|
||||
"otpEnable": "Twee-factor inschakelen",
|
||||
"otpDisable": "Tweestapsverificatie uitschakelen",
|
||||
"logout": "Log uit",
|
||||
"licenseTierProfessionalRequired": "Professionele editie vereist",
|
||||
"licenseTierProfessionalRequiredDescription": "Deze functie is alleen beschikbaar in de Professional Edition.",
|
||||
"actionGetOrg": "Krijg Organisatie",
|
||||
"updateOrgUser": "Org gebruiker bijwerken",
|
||||
"createOrgUser": "Org gebruiker aanmaken",
|
||||
"actionUpdateOrg": "Organisatie bijwerken",
|
||||
"actionUpdateUser": "Gebruiker bijwerken",
|
||||
"actionGetUser": "Gebruiker ophalen",
|
||||
"actionGetOrgUser": "Krijg organisatie-gebruiker",
|
||||
"actionListOrgDomains": "Lijst organisatie domeinen",
|
||||
"actionCreateSite": "Site maken",
|
||||
"actionDeleteSite": "Site verwijderen",
|
||||
"actionGetSite": "Site ophalen",
|
||||
"actionListSites": "Sites weergeven",
|
||||
"actionApplyBlueprint": "Blauwdruk toepassen",
|
||||
"setupToken": "Setup Token",
|
||||
"setupTokenDescription": "Voer het setup-token in vanaf de serverconsole.",
|
||||
"setupTokenRequired": "Setup-token is vereist",
|
||||
"actionUpdateSite": "Site bijwerken",
|
||||
"actionListSiteRoles": "Toon toegestane sitenollen",
|
||||
"actionCreateResource": "Bron maken",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Verwijder IDP Org Beleid",
|
||||
"actionListIdpOrgs": "Toon IDP Orgs",
|
||||
"actionUpdateIdpOrg": "IDP-org bijwerken",
|
||||
"actionCreateClient": "Client aanmaken",
|
||||
"actionDeleteClient": "Verwijder klant",
|
||||
"actionUpdateClient": "Klant bijwerken",
|
||||
"actionListClients": "Lijst klanten",
|
||||
"actionGetClient": "Client ophalen",
|
||||
"actionCreateSiteResource": "Sitebron maken",
|
||||
"actionDeleteSiteResource": "Document verwijderen van site",
|
||||
"actionGetSiteResource": "Bron van site ophalen",
|
||||
"actionListSiteResources": "Bronnen van site weergeven",
|
||||
"actionUpdateSiteResource": "Document bijwerken van site",
|
||||
"actionListInvitations": "Toon uitnodigingen",
|
||||
"noneSelected": "Niet geselecteerd",
|
||||
"orgNotFound2": "Geen organisaties gevonden.",
|
||||
"searchProgress": "Zoeken...",
|
||||
@@ -1079,7 +1128,7 @@
|
||||
"sidebarOverview": "Overzicht.",
|
||||
"sidebarHome": "Startpagina",
|
||||
"sidebarSites": "Werkruimtes",
|
||||
"sidebarResources": "Hulpmiddelen",
|
||||
"sidebarResources": "Bronnen",
|
||||
"sidebarAccessControl": "Toegangs controle",
|
||||
"sidebarUsers": "Gebruikers",
|
||||
"sidebarInvitations": "Uitnodigingen",
|
||||
@@ -1090,19 +1139,21 @@
|
||||
"sidebarAllUsers": "Alle gebruikers",
|
||||
"sidebarIdentityProviders": "Identiteit aanbieders",
|
||||
"sidebarLicense": "Licentie",
|
||||
"enableDockerSocket": "Docker Socket inschakelen",
|
||||
"enableDockerSocketDescription": "Docker Socket-ontdekking inschakelen voor het invullen van containerinformatie. Socket-pad moet aan Newt worden verstrekt.",
|
||||
"sidebarClients": "Clients (Bèta)",
|
||||
"sidebarDomains": "Domeinen",
|
||||
"enableDockerSocket": "Schakel Docker Blauwdruk in",
|
||||
"enableDockerSocketDescription": "Schakel Docker Socket label in voor blauwdruk labels. Pad naar Nieuw.",
|
||||
"enableDockerSocketLink": "Meer informatie",
|
||||
"viewDockerContainers": "Bekijk Docker containers",
|
||||
"containersIn": "Containers in {siteName}",
|
||||
"selectContainerDescription": "Selecteer een container om als hostnaam voor dit doel te gebruiken. Klik op een poort om een poort te gebruiken.",
|
||||
"containerName": "naam",
|
||||
"containerName": "Naam",
|
||||
"containerImage": "Afbeelding",
|
||||
"containerState": "Provincie",
|
||||
"containerNetworks": "Netwerken",
|
||||
"containerHostnameIp": "Hostnaam/IP",
|
||||
"containerLabels": "Labels",
|
||||
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# label} other {# labels}}",
|
||||
"containerLabelsTitle": "Container labels",
|
||||
"containerLabelEmpty": "<leeg>",
|
||||
"containerPorts": "Poorten",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Toon gestopte containers",
|
||||
"noContainersFound": "Geen containers gevonden. Zorg ervoor dat Docker containers draaien.",
|
||||
"searchContainersPlaceholder": "Zoek tussen {count} containers...",
|
||||
"searchResultsCount": "{count} resultaat{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# resultaat} other {# resultaten}}",
|
||||
"filters": "Filters",
|
||||
"filterOptions": "Filter opties",
|
||||
"filterPorts": "Poorten",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "donker",
|
||||
"system": "systeem",
|
||||
"theme": "Thema",
|
||||
"subnetRequired": "Subnet is vereist",
|
||||
"initialSetupTitle": "Initiële serverconfiguratie",
|
||||
"initialSetupDescription": "Maak het eerste serverbeheeraccount aan. Er kan slechts één serverbeheerder bestaan. U kunt deze inloggegevens later altijd wijzigen.",
|
||||
"createAdminAccount": "Maak een beheeraccount aan",
|
||||
"setupErrorCreateAdmin": "Er is een fout opgetreden bij het maken van het serverbeheerdersaccount."
|
||||
"setupErrorCreateAdmin": "Er is een fout opgetreden bij het maken van het serverbeheerdersaccount.",
|
||||
"certificateStatus": "Certificaatstatus",
|
||||
"loading": "Bezig met laden",
|
||||
"restart": "Herstarten",
|
||||
"domains": "Domeinen",
|
||||
"domainsDescription": "Beheer domeinen voor je organisatie",
|
||||
"domainsSearch": "Zoek domeinen...",
|
||||
"domainAdd": "Domein toevoegen",
|
||||
"domainAddDescription": "Registreer een nieuw domein bij je organisatie",
|
||||
"domainCreate": "Domein aanmaken",
|
||||
"domainCreatedDescription": "Domein succesvol aangemaakt",
|
||||
"domainDeletedDescription": "Domein succesvol verwijderd",
|
||||
"domainQuestionRemove": "Weet je zeker dat je het domein {domain} uit je account wilt verwijderen?",
|
||||
"domainMessageRemove": "Na verwijdering zal het domein niet langer aan je account gekoppeld zijn.",
|
||||
"domainMessageConfirm": "Om te bevestigen, typ hieronder de domeinnaam.",
|
||||
"domainConfirmDelete": "Bevestig verwijdering van domein",
|
||||
"domainDelete": "Domein verwijderen",
|
||||
"domain": "Domein",
|
||||
"selectDomainTypeNsName": "Domeindelegatie (NS)",
|
||||
"selectDomainTypeNsDescription": "Dit domein en al zijn subdomeinen. Gebruik dit wanneer je een volledige domeinzone wilt beheersen.",
|
||||
"selectDomainTypeCnameName": "Enkel domein (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Alleen dit specifieke domein. Gebruik dit voor individuele subdomeinen of specifieke domeinvermeldingen.",
|
||||
"selectDomainTypeWildcardName": "Wildcard Domein",
|
||||
"selectDomainTypeWildcardDescription": "Dit domein en zijn subdomeinen.",
|
||||
"domainDelegation": "Enkel domein",
|
||||
"selectType": "Selecteer een type",
|
||||
"actions": "acties",
|
||||
"refresh": "Vernieuwen",
|
||||
"refreshError": "Het vernieuwen van gegevens is mislukt",
|
||||
"verified": "Gecontroleerd",
|
||||
"pending": "In afwachting",
|
||||
"sidebarBilling": "Facturering",
|
||||
"billing": "Facturering",
|
||||
"orgBillingDescription": "Beheer je factureringsgegevens en abonnementen",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin gehost",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Voltooi accountinstelling",
|
||||
"completeAccountSetupDescription": "Stel je wachtwoord in om te beginnen",
|
||||
"accountSetupSent": "We sturen een accountinstellingscode naar dit e-mailadres.",
|
||||
"accountSetupCode": "Instellingscode",
|
||||
"accountSetupCodeDescription": "Controleer je e-mail voor de instellingscode.",
|
||||
"passwordCreate": "Wachtwoord aanmaken",
|
||||
"passwordCreateConfirm": "Bevestig wachtwoord",
|
||||
"accountSetupSubmit": "Instellingscode verzenden",
|
||||
"completeSetup": "Voltooi instellen",
|
||||
"accountSetupSuccess": "Accountinstelling voltooid! Welkom bij Pangolin!",
|
||||
"documentation": "Documentatie",
|
||||
"saveAllSettings": "Alle instellingen opslaan",
|
||||
"settingsUpdated": "Instellingen bijgewerkt",
|
||||
"settingsUpdatedDescription": "Alle instellingen zijn succesvol bijgewerkt",
|
||||
"settingsErrorUpdate": "Bijwerken van instellingen mislukt",
|
||||
"settingsErrorUpdateDescription": "Er is een fout opgetreden bij het bijwerken van instellingen",
|
||||
"sidebarCollapse": "Inklappen",
|
||||
"sidebarExpand": "Uitklappen",
|
||||
"newtUpdateAvailable": "Update beschikbaar",
|
||||
"newtUpdateAvailableInfo": "Er is een nieuwe versie van Newt beschikbaar. Update naar de nieuwste versie voor de beste ervaring.",
|
||||
"domainPickerEnterDomain": "Domein",
|
||||
"domainPickerPlaceholder": "mijnapp.voorbeeld.nl",
|
||||
"domainPickerDescription": "Voer de volledige domein van de bron in om beschikbare opties te zien.",
|
||||
"domainPickerDescriptionSaas": "Voer een volledig domein, subdomein of gewoon een naam in om beschikbare opties te zien",
|
||||
"domainPickerTabAll": "Alles",
|
||||
"domainPickerTabOrganization": "Organisatie",
|
||||
"domainPickerTabProvided": "Aangeboden",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Beschikbaarheid controleren...",
|
||||
"domainPickerNoMatchingDomains": "Geen overeenkomende domeinen gevonden. Probeer een ander domein of controleer de domeininstellingen van uw organisatie.",
|
||||
"domainPickerOrganizationDomains": "Organisatiedomeinen",
|
||||
"domainPickerProvidedDomains": "Aangeboden domeinen",
|
||||
"domainPickerSubdomain": "Subdomein: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"domainPickerShowMore": "Meer weergeven",
|
||||
"domainNotFound": "Domein niet gevonden",
|
||||
"domainNotFoundDescription": "Deze bron is uitgeschakeld omdat het domein niet langer in ons systeem bestaat. Stel een nieuw domein in voor deze bron.",
|
||||
"failed": "Mislukt",
|
||||
"createNewOrgDescription": "Maak een nieuwe organisatie",
|
||||
"organization": "Organisatie",
|
||||
"port": "Poort",
|
||||
"securityKeyManage": "Beveiligingssleutels beheren",
|
||||
"securityKeyDescription": "Voeg beveiligingssleutels toe of verwijder ze voor wachtwoordloze authenticatie",
|
||||
"securityKeyRegister": "Nieuwe beveiligingssleutel registreren",
|
||||
"securityKeyList": "Uw beveiligingssleutels",
|
||||
"securityKeyNone": "Nog geen beveiligingssleutels geregistreerd",
|
||||
"securityKeyNameRequired": "Naam is verplicht",
|
||||
"securityKeyRemove": "Verwijderen",
|
||||
"securityKeyLastUsed": "Laatst gebruikt: {date}",
|
||||
"securityKeyNameLabel": "Naam",
|
||||
"securityKeyRegisterSuccess": "Beveiligingssleutel succesvol geregistreerd",
|
||||
"securityKeyRegisterError": "Fout bij registreren van beveiligingssleutel",
|
||||
"securityKeyRemoveSuccess": "Beveiligingssleutel succesvol verwijderd",
|
||||
"securityKeyRemoveError": "Fout bij verwijderen van beveiligingssleutel",
|
||||
"securityKeyLoadError": "Fout bij laden van beveiligingssleutels",
|
||||
"securityKeyLogin": "Doorgaan met beveiligingssleutel",
|
||||
"securityKeyAuthError": "Fout bij authenticatie met beveiligingssleutel",
|
||||
"securityKeyRecommendation": "Overweeg om een andere beveiligingssleutel te registreren op een ander apparaat om ervoor te zorgen dat u niet buitengesloten raakt van uw account.",
|
||||
"registering": "Registreren...",
|
||||
"securityKeyPrompt": "Verifieer je identiteit met je beveiligingssleutel. Zorg ervoor dat je beveiligingssleutel verbonden en klaar is.",
|
||||
"securityKeyBrowserNotSupported": "Je browser ondersteunt geen beveiligingssleutels. Gebruik een moderne browser zoals Chrome, Firefox of Safari.",
|
||||
"securityKeyPermissionDenied": "Verleen toegang tot je beveiligingssleutel om door te gaan met inloggen.",
|
||||
"securityKeyRemovedTooQuickly": "Houd je beveiligingssleutel verbonden totdat het inlogproces is voltooid.",
|
||||
"securityKeyNotSupported": "Je beveiligingssleutel is mogelijk niet compatibel. Probeer een andere beveiligingssleutel.",
|
||||
"securityKeyUnknownError": "Er was een probleem met het gebruik van je beveiligingssleutel. Probeer het opnieuw.",
|
||||
"twoFactorRequired": "Tweestapsverificatie is vereist om een beveiligingssleutel te registreren.",
|
||||
"twoFactor": "Tweestapsverificatie",
|
||||
"adminEnabled2FaOnYourAccount": "Je beheerder heeft tweestapsverificatie voor {email} ingeschakeld. Voltooi het instellingsproces om verder te gaan.",
|
||||
"continueToApplication": "Doorgaan naar de applicatie",
|
||||
"securityKeyAdd": "Beveiligingssleutel toevoegen",
|
||||
"securityKeyRegisterTitle": "Nieuwe beveiligingssleutel registreren",
|
||||
"securityKeyRegisterDescription": "Verbind je beveiligingssleutel en voer een naam in om deze te identificeren",
|
||||
"securityKeyTwoFactorRequired": "Tweestapsverificatie vereist",
|
||||
"securityKeyTwoFactorDescription": "Voer je tweestapsverificatiecode in om de beveiligingssleutel te registreren",
|
||||
"securityKeyTwoFactorRemoveDescription": "Voer je tweestapsverificatiecode in om de beveiligingssleutel te verwijderen",
|
||||
"securityKeyTwoFactorCode": "Tweestapsverificatiecode",
|
||||
"securityKeyRemoveTitle": "Beveiligingssleutel verwijderen",
|
||||
"securityKeyRemoveDescription": "Voer je wachtwoord in om de beveiligingssleutel \"{name}\" te verwijderen",
|
||||
"securityKeyNoKeysRegistered": "Geen beveiligingssleutels geregistreerd",
|
||||
"securityKeyNoKeysDescription": "Voeg een beveiligingssleutel toe om je accountbeveiliging te verbeteren",
|
||||
"createDomainRequired": "Domein is vereist",
|
||||
"createDomainAddDnsRecords": "DNS-records toevoegen",
|
||||
"createDomainAddDnsRecordsDescription": "Voeg de volgende DNS-records toe aan je domeinprovider om het instellen te voltooien.",
|
||||
"createDomainNsRecords": "NS-records",
|
||||
"createDomainRecord": "Record",
|
||||
"createDomainType": "Type:",
|
||||
"createDomainName": "Naam:",
|
||||
"createDomainValue": "Waarde:",
|
||||
"createDomainCnameRecords": "CNAME-records",
|
||||
"createDomainARecords": "A Records",
|
||||
"createDomainRecordNumber": "Record {number}",
|
||||
"createDomainTxtRecords": "TXT-records",
|
||||
"createDomainSaveTheseRecords": "Deze records opslaan",
|
||||
"createDomainSaveTheseRecordsDescription": "Zorg ervoor dat je deze DNS-records opslaat, want je zult ze niet opnieuw zien.",
|
||||
"createDomainDnsPropagation": "DNS-propagatie",
|
||||
"createDomainDnsPropagationDescription": "DNS-wijzigingen kunnen enige tijd duren om over het internet te worden verspreid. Dit kan enkele minuten tot 48 uur duren, afhankelijk van je DNS-provider en TTL-instellingen.",
|
||||
"resourcePortRequired": "Poortnummer is vereist voor niet-HTTP-bronnen",
|
||||
"resourcePortNotAllowed": "Poortnummer mag niet worden ingesteld voor HTTP-bronnen",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Ik ga akkoord met de",
|
||||
"termsOfService": "servicevoorwaarden",
|
||||
"and": "en",
|
||||
"privacyPolicy": "privacybeleid"
|
||||
},
|
||||
"siteRequired": "Site is vereist.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Gebruik Olm voor clientconnectiviteit",
|
||||
"errorCreatingClient": "Fout bij het aanmaken van de client",
|
||||
"clientDefaultsNotFound": "Standaardinstellingen van klant niet gevonden",
|
||||
"createClient": "Client aanmaken",
|
||||
"createClientDescription": "Maak een nieuwe client aan om verbinding te maken met uw sites",
|
||||
"seeAllClients": "Alle clients bekijken",
|
||||
"clientInformation": "Klantinformatie",
|
||||
"clientNamePlaceholder": "Clientnaam",
|
||||
"address": "Adres",
|
||||
"subnetPlaceholder": "Subnet",
|
||||
"addressDescription": "Het adres dat deze client zal gebruiken voor connectiviteit",
|
||||
"selectSites": "Selecteer sites",
|
||||
"sitesDescription": "De client heeft connectiviteit met de geselecteerde sites",
|
||||
"clientInstallOlm": "Installeer Olm",
|
||||
"clientInstallOlmDescription": "Laat Olm draaien op uw systeem",
|
||||
"clientOlmCredentials": "Olm inloggegevens",
|
||||
"clientOlmCredentialsDescription": "Dit is hoe Olm zich bij de server zal verifiëren",
|
||||
"olmEndpoint": "Olm Eindpunt",
|
||||
"olmId": "Olm ID",
|
||||
"olmSecretKey": "Olm Geheime Sleutel",
|
||||
"clientCredentialsSave": "Uw referenties opslaan",
|
||||
"clientCredentialsSaveDescription": "Je kunt dit slechts één keer zien. Kopieer deze naar een veilige plek.",
|
||||
"generalSettingsDescription": "Configureer de algemene instellingen voor deze client",
|
||||
"clientUpdated": "Klant bijgewerkt ",
|
||||
"clientUpdatedDescription": "De client is bijgewerkt.",
|
||||
"clientUpdateFailed": "Het bijwerken van de client is mislukt",
|
||||
"clientUpdateError": "Er is een fout opgetreden tijdens het bijwerken van de client.",
|
||||
"sitesFetchFailed": "Het ophalen van sites is mislukt",
|
||||
"sitesFetchError": "Er is een fout opgetreden bij het ophalen van sites.",
|
||||
"olmErrorFetchReleases": "Er is een fout opgetreden bij het ophalen van Olm releases.",
|
||||
"olmErrorFetchLatest": "Er is een fout opgetreden bij het ophalen van de nieuwste Olm release.",
|
||||
"remoteSubnets": "Externe Subnets",
|
||||
"enterCidrRange": "Voer CIDR-bereik in",
|
||||
"remoteSubnetsDescription": "Voeg CIDR-bereiken toe die vanaf deze site op afstand toegankelijk zijn met behulp van clients. Gebruik een formaat zoals 10.0.0.0/24. Dit geldt ALLEEN voor VPN-clientconnectiviteit.",
|
||||
"resourceEnableProxy": "Openbare proxy inschakelen",
|
||||
"resourceEnableProxyDescription": "Schakel publieke proxy in voor deze resource. Dit maakt toegang tot de resource mogelijk vanuit het netwerk via de cloud met een open poort. Vereist Traefik-configuratie.",
|
||||
"externalProxyEnabled": "Externe Proxy Ingeschakeld",
|
||||
"addNewTarget": "Voeg nieuw doelwit toe",
|
||||
"targetsList": "Lijst met doelen",
|
||||
"targetErrorDuplicateTargetFound": "Dubbel doelwit gevonden",
|
||||
"httpMethod": "HTTP-methode",
|
||||
"selectHttpMethod": "Selecteer HTTP-methode",
|
||||
"domainPickerSubdomainLabel": "Subdomein",
|
||||
"domainPickerBaseDomainLabel": "Basisdomein",
|
||||
"domainPickerSearchDomains": "Zoek domeinen...",
|
||||
"domainPickerNoDomainsFound": "Geen domeinen gevonden",
|
||||
"domainPickerLoadingDomains": "Domeinen laden...",
|
||||
"domainPickerSelectBaseDomain": "Selecteer basisdomein...",
|
||||
"domainPickerNotAvailableForCname": "Niet beschikbaar voor CNAME-domeinen",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Voer een subdomein in of laat leeg om basisdomein te gebruiken.",
|
||||
"domainPickerEnterSubdomainToSearch": "Voer een subdomein in om te zoeken en te selecteren uit beschikbare gratis domeinen.",
|
||||
"domainPickerFreeDomains": "Gratis Domeinen",
|
||||
"domainPickerSearchForAvailableDomains": "Zoek naar beschikbare domeinen",
|
||||
"resourceDomain": "Domein",
|
||||
"resourceEditDomain": "Domein bewerken",
|
||||
"siteName": "Site Naam",
|
||||
"proxyPort": "Poort",
|
||||
"resourcesTableProxyResources": "Proxybronnen",
|
||||
"resourcesTableClientResources": "Clientbronnen",
|
||||
"resourcesTableNoProxyResourcesFound": "Geen proxybronnen gevonden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Geen interne bronnen gevonden.",
|
||||
"resourcesTableDestination": "Bestemming",
|
||||
"resourcesTableTheseResourcesForUseWith": "Deze bronnen zijn bedoeld voor gebruik met",
|
||||
"resourcesTableClients": "Clienten",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "en zijn alleen intern toegankelijk wanneer verbonden met een client.",
|
||||
"editInternalResourceDialogEditClientResource": "Bewerk clientbron",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Werk de eigenschapen van de bron en doelconfiguratie bij voor {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Bron eigenschappen",
|
||||
"editInternalResourceDialogName": "Naam",
|
||||
"editInternalResourceDialogProtocol": "Protocol",
|
||||
"editInternalResourceDialogSitePort": "Site Poort",
|
||||
"editInternalResourceDialogTargetConfiguration": "Doelconfiguratie",
|
||||
"editInternalResourceDialogCancel": "Annuleren",
|
||||
"editInternalResourceDialogSaveResource": "Sla bron op",
|
||||
"editInternalResourceDialogSuccess": "Succes",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne bron succesvol bijgewerkt",
|
||||
"editInternalResourceDialogError": "Fout",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Het bijwerken van de interne bron is mislukt",
|
||||
"editInternalResourceDialogNameRequired": "Naam is verplicht",
|
||||
"editInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy poort moet minstens 1 zijn",
|
||||
"editInternalResourceDialogProxyPortMax": "Proxy poort moet minder dan 65536 zijn",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Ongeldig IP-adresformaat",
|
||||
"editInternalResourceDialogDestinationPortMin": "Bestemmingspoort moet minstens 1 zijn",
|
||||
"editInternalResourceDialogDestinationPortMax": "Bestemmingspoort moet minder dan 65536 zijn",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Geen sites beschikbaar",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "U moet ten minste één Newt-site hebben met een geconfigureerd subnet om interne bronnen aan te maken.",
|
||||
"createInternalResourceDialogClose": "Sluiten",
|
||||
"createInternalResourceDialogCreateClientResource": "Maak clientbron",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Maak een nieuwe bron die toegankelijk zal zijn voor clients die verbonden zijn met de geselecteerde site.",
|
||||
"createInternalResourceDialogResourceProperties": "Bron-eigenschappen",
|
||||
"createInternalResourceDialogName": "Naam",
|
||||
"createInternalResourceDialogSite": "Site",
|
||||
"createInternalResourceDialogSelectSite": "Selecteer site...",
|
||||
"createInternalResourceDialogSearchSites": "Zoek sites...",
|
||||
"createInternalResourceDialogNoSitesFound": "Geen sites gevonden.",
|
||||
"createInternalResourceDialogProtocol": "Protocol",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Site Poort",
|
||||
"createInternalResourceDialogSitePortDescription": "Gebruik deze poort om toegang te krijgen tot de bron op de site wanneer verbonden met een client.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Doelconfiguratie",
|
||||
"createInternalResourceDialogDestinationIPDescription": "Het IP of hostnaam adres van de bron op het netwerk van de site.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "De poort op het bestemmings-IP waar de bron toegankelijk is.",
|
||||
"createInternalResourceDialogCancel": "Annuleren",
|
||||
"createInternalResourceDialogCreateResource": "Bron aanmaken",
|
||||
"createInternalResourceDialogSuccess": "Succes",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne bron succesvol aangemaakt",
|
||||
"createInternalResourceDialogError": "Fout",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Het aanmaken van de interne bron is mislukt",
|
||||
"createInternalResourceDialogNameRequired": "Naam is verplicht",
|
||||
"createInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Selecteer alstublieft een site",
|
||||
"createInternalResourceDialogProxyPortMin": "Proxy poort moet minstens 1 zijn",
|
||||
"createInternalResourceDialogProxyPortMax": "Proxy poort moet minder dan 65536 zijn",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Ongeldig IP-adresformaat",
|
||||
"createInternalResourceDialogDestinationPortMin": "Bestemmingspoort moet minstens 1 zijn",
|
||||
"createInternalResourceDialogDestinationPortMax": "Bestemmingspoort moet minder dan 65536 zijn",
|
||||
"siteConfiguration": "Configuratie",
|
||||
"siteAcceptClientConnections": "Accepteer clientverbindingen",
|
||||
"siteAcceptClientConnectionsDescription": "Sta toe dat andere apparaten verbinding maken via deze Newt-instantie als een gateway met behulp van clients.",
|
||||
"siteAddress": "Siteadres",
|
||||
"siteAddressDescription": "Specificeren het IP-adres van de host voor clients om verbinding mee te maken. Dit is het interne adres van de site in het Pangolin netwerk voor clients om te adresseren. Moet binnen het Organisatienetwerk vallen.",
|
||||
"autoLoginExternalIdp": "Auto Login met Externe IDP",
|
||||
"autoLoginExternalIdpDescription": "De gebruiker onmiddellijk doorsturen naar de externe IDP voor authenticatie.",
|
||||
"selectIdp": "Selecteer IDP",
|
||||
"selectIdpPlaceholder": "Kies een IDP...",
|
||||
"selectIdpRequired": "Selecteer alstublieft een IDP wanneer automatisch inloggen is ingeschakeld.",
|
||||
"autoLoginTitle": "Omleiden",
|
||||
"autoLoginDescription": "Je wordt doorverwezen naar de externe identity provider voor authenticatie.",
|
||||
"autoLoginProcessing": "Authenticatie voorbereiden...",
|
||||
"autoLoginRedirecting": "Redirecting naar inloggen...",
|
||||
"autoLoginError": "Auto Login Fout",
|
||||
"autoLoginErrorNoRedirectUrl": "Geen redirect URL ontvangen van de identity provider.",
|
||||
"autoLoginErrorGeneratingUrl": "Genereren van authenticatie-URL mislukt.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Beheerde Self-Hosted",
|
||||
"description": "betrouwbaardere en slecht onderhouden Pangolin server met extra klokken en klokkenluiders",
|
||||
"introTitle": "Beheerde zelfgehoste pangolin",
|
||||
"introDescription": "is een implementatieoptie ontworpen voor mensen die eenvoud en extra betrouwbaarheid willen, terwijl hun gegevens privé en zelf georganiseerd blijven.",
|
||||
"introDetail": "Met deze optie beheert u nog steeds uw eigen Pangolin node - uw tunnels, SSL-verbinding en verkeer alles op uw server. Het verschil is dat beheer en monitoring worden behandeld via onze cloud dashboard, wat een aantal voordelen oplevert:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Simpler operaties",
|
||||
"description": "Je hoeft geen eigen mailserver te draaien of complexe waarschuwingen in te stellen. Je krijgt gezondheidscontroles en downtime meldingen uit de box."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Automatische updates",
|
||||
"description": "Het cloud dashboard evolueert snel, zodat u nieuwe functies en bug fixes krijgt zonder elke keer handmatig nieuwe containers te moeten trekken."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Minder onderhoud",
|
||||
"description": "Geen database migratie, back-ups of extra infrastructuur om te beheren. Dat behandelen we in de cloud."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Cloud fout",
|
||||
"description": "Als uw node omlaag gaat, kunnen uw tunnels tijdelijk niet meer naar onze aanwezigheidspunten gaan totdat u hem weer online brengt."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Hoge beschikbaarheid (PoPs)",
|
||||
"description": "U kunt ook meerdere nodes koppelen aan uw account voor ontslag en betere prestaties."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Toekomstige verbeteringen",
|
||||
"description": "We zijn van plan om meer analytica, waarschuwing en beheerhulpmiddelen toe te voegen om uw implementatie nog steviger te maken."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Meer informatie over de optie voor zelf-verzorging in onze",
|
||||
"documentation": "documentatie"
|
||||
},
|
||||
"convertButton": "Converteer deze node naar Beheerde Zelf-Hosted"
|
||||
},
|
||||
"internationaldomaindetected": "Internationaal Domein Gedetecteerd",
|
||||
"willbestoredas": "Zal worden opgeslagen als:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC provider",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Aangepaste headers",
|
||||
"headersValidationError": "Headers moeten in het formaat zijn: Header-Naam: waarde.",
|
||||
"domainPickerProvidedDomain": "Opgegeven domein",
|
||||
"domainPickerFreeProvidedDomain": "Gratis verstrekt domein",
|
||||
"domainPickerVerified": "Geverifieerd",
|
||||
"domainPickerUnverified": "Ongeverifieerd",
|
||||
"domainPickerInvalidSubdomainStructure": "Dit subdomein bevat ongeldige tekens of structuur. Het zal automatisch worden gesaneerd wanneer u opslaat.",
|
||||
"domainPickerError": "Foutmelding",
|
||||
"domainPickerErrorLoadDomains": "Fout bij het laden van organisatiedomeinen",
|
||||
"domainPickerErrorCheckAvailability": "Kan domein beschikbaarheid niet controleren",
|
||||
"domainPickerInvalidSubdomain": "Ongeldig subdomein",
|
||||
"domainPickerInvalidSubdomainRemoved": "De invoer \"{sub}\" is verwijderd omdat het niet geldig is.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" kon niet geldig worden gemaakt voor {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Subdomein gesaniseerd",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" was gecorrigeerd op \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Bestand bewerken: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Bestand bewerken: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "Nie jesteś obecnie członkiem żadnej organizacji. Aby rozpocząć, utwórz organizację.",
|
||||
"componentsErrorNoMember": "Nie jesteś obecnie członkiem żadnej organizacji.",
|
||||
"welcome": "Witaj w Pangolinie",
|
||||
"welcomeTo": "Witaj w",
|
||||
"componentsCreateOrg": "Utwórz organizację",
|
||||
"componentsMember": "Jesteś członkiem {count, plural, =0 {Żadna organizacja} =1 {Jedna organizacja} other {# organizacji}}.",
|
||||
"componentsMember": "Jesteś członkiem {count, plural, =0 {żadna organizacja} one {jedna organizacja} few {# organizacje} many {# organizacji} other {# organizacji}}.",
|
||||
"componentsInvalidKey": "Wykryto nieprawidłowe lub wygasłe klucze licencyjne. Postępuj zgodnie z warunkami licencji, aby kontynuować korzystanie ze wszystkich funkcji.",
|
||||
"dismiss": "Odrzuć",
|
||||
"componentsLicenseViolation": "Naruszenie licencji: Ten serwer używa stron {usedSites} , które przekraczają limit licencyjny stron {maxSites} . Postępuj zgodnie z warunkami licencji, aby kontynuować korzystanie ze wszystkich funkcji.",
|
||||
@@ -34,7 +35,7 @@
|
||||
"createAccount": "Utwórz konto",
|
||||
"viewSettings": "Pokaż ustawienia",
|
||||
"delete": "Usuń",
|
||||
"name": "Nazwisko",
|
||||
"name": "Nazwa",
|
||||
"online": "Dostępny",
|
||||
"offline": "Offline",
|
||||
"site": "Witryna",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Błąd podczas tworzenia witryny",
|
||||
"siteErrorCreateKeyPair": "Nie znaleziono pary kluczy lub domyślnych ustawień witryny",
|
||||
"siteErrorCreateDefaults": "Nie znaleziono domyślnych ustawień witryny",
|
||||
"siteNameDescription": "To jest wyświetlana nazwa witryny.",
|
||||
"method": "Metoda",
|
||||
"siteMethodDescription": "W ten sposób ujawnisz połączenia.",
|
||||
"siteLearnNewt": "Dowiedz się, jak zainstalować Newt w systemie",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "Łatwiejszy sposób na stworzenie punktu wejścia w sieci. Nie ma dodatkowej konfiguracji.",
|
||||
"siteWg": "Podstawowy WireGuard",
|
||||
"siteWgDescription": "Użyj dowolnego klienta WireGuard do utworzenia tunelu. Wymagana jest ręczna konfiguracja NAT.",
|
||||
"siteWgDescriptionSaas": "Użyj dowolnego klienta WireGuard do utworzenia tunelu. Wymagana ręczna konfiguracja NAT. DZIAŁA TYLKO NA SAMODZIELNIE HOSTOWANYCH WĘZŁACH",
|
||||
"siteLocalDescription": "Tylko lokalne zasoby. Brak tunelu.",
|
||||
"siteLocalDescriptionSaas": "Tylko zasoby lokalne. Brak tunelowania. DZIAŁA TYLKO NA SAMODZIELNIE HOSTOWANYCH WĘZŁACH",
|
||||
"siteSeeAll": "Zobacz wszystkie witryny",
|
||||
"siteTunnelDescription": "Określ jak chcesz połączyć się ze swoją stroną",
|
||||
"siteNewtCredentials": "Aktualne dane logowania",
|
||||
@@ -138,7 +140,7 @@
|
||||
"resourceSearch": "Szukaj zasobów",
|
||||
"openMenu": "Otwórz menu",
|
||||
"resource": "Zasoby",
|
||||
"title": "Rozporządzenie Rady (EWG) nr 2658/87 z dnia 23 lipca 1987 r. w sprawie nomenklatury taryfowej i statystycznej oraz w sprawie Wspólnej Taryfy Celnej (Dz.U. L 256 z 7.9.1987, s. 1).",
|
||||
"title": "Tytuł",
|
||||
"created": "Utworzono",
|
||||
"expires": "Wygasa",
|
||||
"never": "Nigdy",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Wybierz witrynę",
|
||||
"siteSearch": "Szukaj witryny",
|
||||
"siteNotFound": "Nie znaleziono witryny.",
|
||||
"siteSelectionDescription": "Ta strona zapewni połączenie z zasobem.",
|
||||
"siteSelectionDescription": "Ta strona zapewni połączenie z celem.",
|
||||
"resourceType": "Typ zasobu",
|
||||
"resourceTypeDescription": "Określ jak chcesz uzyskać dostęp do swojego zasobu",
|
||||
"resourceHTTPSSettings": "Ustawienia HTTPS",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Ogólny",
|
||||
"generalSettings": "Ustawienia ogólne",
|
||||
"proxy": "Serwer pośredniczący",
|
||||
"internal": "Wewętrzny",
|
||||
"rules": "Regulamin",
|
||||
"resourceSettingDescription": "Skonfiguruj ustawienia zasobu",
|
||||
"resourceSetting": "Ustawienia {resourceName}",
|
||||
"alwaysAllow": "Zawsze zezwalaj",
|
||||
"alwaysDeny": "Zawsze odmawiaj",
|
||||
"passToAuth": "Przekaż do Autoryzacji",
|
||||
"orgSettingsDescription": "Skonfiguruj ustawienia ogólne swojej organizacji",
|
||||
"orgGeneralSettings": "Ustawienia organizacji",
|
||||
"orgGeneralSettingsDescription": "Zarządzaj szczegółami swojej organizacji i konfiguracją",
|
||||
"saveGeneralSettings": "Zapisz ustawienia ogólne",
|
||||
"saveSettings": "Zapisz ustawienia",
|
||||
"orgDangerZone": "Strefa zagrożenia",
|
||||
"orgDangerZoneDescription": "Po usunięciu tego organa nie ma odwrotu. Upewnij się.",
|
||||
"orgDelete": "Usuń organizację",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Tygodnie",
|
||||
"months": "Miesiące",
|
||||
"years": "Lata",
|
||||
"day": "{count, plural, =1 {# dzień} other {# dni}}",
|
||||
"day": "{count, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}",
|
||||
"apiKeysTitle": "Informacje o kluczu API",
|
||||
"apiKeysConfirmCopy2": "Musisz potwierdzić, że skopiowałeś klucz API.",
|
||||
"apiKeysErrorCreate": "Błąd podczas tworzenia klucza API",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Kup licencję",
|
||||
"licensePurchaseSites": "Kup dodatkowe witryny",
|
||||
"licenseSitesUsedMax": "Użyte strony {usedSites} z {maxSites}",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# witryn} =1 {# witryn} other {# witryn}} w systemie.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# witryn} one {# witryna} few {# witryny} many {# witryn} other {# witryn}} w systemie.",
|
||||
"licensePurchaseDescription": "Wybierz ile witryn chcesz {selectedMode, select, license {kupić licencję. Zawsze możesz dodać więcej witryn później.} other {dodaj do swojej istniejącej licencji.}}",
|
||||
"licenseFee": "Opłata licencyjna",
|
||||
"licensePriceSite": "Cena za witrynę",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Wybierz rolę",
|
||||
"inviteEmailSentDescription": "Email został wysłany do użytkownika z linkiem dostępu poniżej. Musi on uzyskać dostęp do linku, aby zaakceptować zaproszenie.",
|
||||
"inviteSentDescription": "Użytkownik został zaproszony. Musi uzyskać dostęp do poniższego linku, aby zaakceptować zaproszenie.",
|
||||
"inviteExpiresIn": "Zaproszenie wygaśnie za {days, plural, =1 {# dzień} other {# dni}}.",
|
||||
"inviteExpiresIn": "Zaproszenie wygaśnie za {days, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}.",
|
||||
"idpTitle": "Informacje ogólne",
|
||||
"idpSelect": "Wybierz dostawcę tożsamości dla użytkownika zewnętrznego",
|
||||
"idpNotConfigured": "Nie skonfigurowano żadnych dostawców tożsamości. Skonfiguruj dostawcę tożsamości przed utworzeniem użytkowników zewnętrznych.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Wystąpił błąd podczas dodawania użytkownika do roli.",
|
||||
"userSaved": "Użytkownik zapisany",
|
||||
"userSavedDescription": "Użytkownik został zaktualizowany.",
|
||||
"autoProvisioned": "Przesłane automatycznie",
|
||||
"autoProvisionedDescription": "Pozwól temu użytkownikowi na automatyczne zarządzanie przez dostawcę tożsamości",
|
||||
"accessControlsDescription": "Zarządzaj tym, do czego użytkownik ma dostęp i co może robić w organizacji",
|
||||
"accessControlsSubmit": "Zapisz kontrole dostępu",
|
||||
"roles": "Role",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "Nazwa serwera TLS do użycia dla SNI. Pozostaw puste, aby użyć domyślnej.",
|
||||
"targetTlsSubmit": "Zapisz ustawienia",
|
||||
"targets": "Konfiguracja celów",
|
||||
"targetsDescription": "Skonfiguruj cele do kierowania ruchu do swoich usług",
|
||||
"targetsDescription": "Skonfiguruj cele do kierowania ruchu do usług zaplecza",
|
||||
"targetStickySessions": "Włącz sesje trwałe",
|
||||
"targetStickySessionsDescription": "Utrzymuj połączenia na tym samym celu backendowym przez całą sesję.",
|
||||
"methodSelect": "Wybierz metodę",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Nieprawidłowy format adresu IP",
|
||||
"ipAddressErrorInvalidOctet": "Nieprawidłowy oktet adresu IP",
|
||||
"path": "Ścieżka",
|
||||
"matchPath": "Ścieżka dopasowania",
|
||||
"ipAddressRange": "Zakres IP",
|
||||
"rulesErrorFetch": "Nie udało się pobrać reguł",
|
||||
"rulesErrorFetchDescription": "Wystąpił błąd podczas pobierania reguł",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Akcje",
|
||||
"rulesActionAlwaysAllow": "Zawsze zezwalaj: Pomiń wszystkie metody uwierzytelniania",
|
||||
"rulesActionAlwaysDeny": "Zawsze odmawiaj: Blokuj wszystkie żądania; nie można próbować uwierzytelniania",
|
||||
"rulesActionPassToAuth": "Przekaż do Autoryzacji: Zezwól na próby metod uwierzytelniania",
|
||||
"rulesMatchCriteria": "Kryteria dopasowania",
|
||||
"rulesMatchCriteriaIpAddress": "Dopasuj konkretny adres IP",
|
||||
"rulesMatchCriteriaIpAddressRange": "Dopasuj zakres adresów IP w notacji CIDR",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "PIN musi składać się dokładnie z 6 cyfr",
|
||||
"pincodeRequirementsChars": "PIN może zawierać tylko cyfry",
|
||||
"passwordRequirementsLength": "Hasło musi mieć co najmniej 1 znak",
|
||||
"passwordRequirementsTitle": "Wymagania dotyczące hasła:",
|
||||
"passwordRequirementLength": "Przynajmniej 8 znaków długości",
|
||||
"passwordRequirementUppercase": "Przynajmniej jedna wielka litera",
|
||||
"passwordRequirementLowercase": "Przynajmniej jedna mała litera",
|
||||
"passwordRequirementNumber": "Przynajmniej jedna cyfra",
|
||||
"passwordRequirementSpecial": "Przynajmniej jeden znak specjalny",
|
||||
"passwordRequirementsMet": "✓ Hasło spełnia wszystkie wymagania",
|
||||
"passwordStrength": "Siła hasła",
|
||||
"passwordStrengthWeak": "Słabe",
|
||||
"passwordStrengthMedium": "Średnie",
|
||||
"passwordStrengthStrong": "Silne",
|
||||
"passwordRequirements": "Wymagania:",
|
||||
"passwordRequirementLengthText": "8+ znaków",
|
||||
"passwordRequirementUppercaseText": "Wielka litera (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Mała litera (a-z)",
|
||||
"passwordRequirementNumberText": "Cyfra (0-9)",
|
||||
"passwordRequirementSpecialText": "Znak specjalny (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Hasła nie są zgodne",
|
||||
"otpEmailRequirementsLength": "Kod jednorazowy musi mieć co najmniej 1 znak",
|
||||
"otpEmailSent": "Kod jednorazowy wysłany",
|
||||
"otpEmailSentDescription": "Kod jednorazowy został wysłany na Twój e-mail",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Połączono",
|
||||
"idpErrorConnectingTo": "Wystąpił problem z połączeniem z {name}. Skontaktuj się z administratorem.",
|
||||
"idpErrorNotFound": "Nie znaleziono IdP",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Nieprawidłowe zaproszenie",
|
||||
"inviteInvalidDescription": "Link zapraszający jest nieprawidłowy.",
|
||||
"inviteErrorWrongUser": "Zaproszenie nie jest dla tego użytkownika",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Błąd podczas wylogowywania",
|
||||
"signingAs": "Zalogowany jako",
|
||||
"serverAdmin": "Administrator serwera",
|
||||
"managedSelfhosted": "Zarządzane Samodzielnie-Hostingowane",
|
||||
"otpEnable": "Włącz uwierzytelnianie dwuskładnikowe",
|
||||
"otpDisable": "Wyłącz uwierzytelnianie dwuskładnikowe",
|
||||
"logout": "Wyloguj się",
|
||||
"licenseTierProfessionalRequired": "Wymagana edycja Professional",
|
||||
"licenseTierProfessionalRequiredDescription": "Ta funkcja jest dostępna tylko w edycji Professional.",
|
||||
"actionGetOrg": "Pobierz organizację",
|
||||
"updateOrgUser": "Aktualizuj użytkownika Org",
|
||||
"createOrgUser": "Utwórz użytkownika Org",
|
||||
"actionUpdateOrg": "Aktualizuj organizację",
|
||||
"actionUpdateUser": "Zaktualizuj użytkownika",
|
||||
"actionGetUser": "Pobierz użytkownika",
|
||||
"actionGetOrgUser": "Pobierz użytkownika organizacji",
|
||||
"actionListOrgDomains": "Lista domen organizacji",
|
||||
"actionCreateSite": "Utwórz witrynę",
|
||||
"actionDeleteSite": "Usuń witrynę",
|
||||
"actionGetSite": "Pobierz witrynę",
|
||||
"actionListSites": "Lista witryn",
|
||||
"actionApplyBlueprint": "Zastosuj schemat",
|
||||
"setupToken": "Skonfiguruj token",
|
||||
"setupTokenDescription": "Wprowadź token konfiguracji z konsoli serwera.",
|
||||
"setupTokenRequired": "Wymagany jest token konfiguracji",
|
||||
"actionUpdateSite": "Aktualizuj witrynę",
|
||||
"actionListSiteRoles": "Lista dozwolonych ról witryny",
|
||||
"actionCreateResource": "Utwórz zasób",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Usuń politykę organizacji IDP",
|
||||
"actionListIdpOrgs": "Lista organizacji IDP",
|
||||
"actionUpdateIdpOrg": "Aktualizuj organizację IDP",
|
||||
"actionCreateClient": "Utwórz klienta",
|
||||
"actionDeleteClient": "Usuń klienta",
|
||||
"actionUpdateClient": "Aktualizuj klienta",
|
||||
"actionListClients": "Lista klientów",
|
||||
"actionGetClient": "Pobierz klienta",
|
||||
"actionCreateSiteResource": "Utwórz zasób witryny",
|
||||
"actionDeleteSiteResource": "Usuń zasób strony",
|
||||
"actionGetSiteResource": "Pobierz zasób strony",
|
||||
"actionListSiteResources": "Lista zasobów strony",
|
||||
"actionUpdateSiteResource": "Aktualizuj zasób strony",
|
||||
"actionListInvitations": "Lista zaproszeń",
|
||||
"noneSelected": "Nie wybrano",
|
||||
"orgNotFound2": "Nie znaleziono organizacji.",
|
||||
"searchProgress": "Szukaj...",
|
||||
@@ -1090,19 +1139,21 @@
|
||||
"sidebarAllUsers": "Wszyscy użytkownicy",
|
||||
"sidebarIdentityProviders": "Dostawcy tożsamości",
|
||||
"sidebarLicense": "Licencja",
|
||||
"enableDockerSocket": "Włącz gniazdo dokera",
|
||||
"enableDockerSocketDescription": "Włącz wykrywanie Docker Socket w celu wypełnienia informacji o kontenerach. Ścieżka gniazda musi być dostarczona do Newt.",
|
||||
"sidebarClients": "Klienci (Beta)",
|
||||
"sidebarDomains": "Domeny",
|
||||
"enableDockerSocket": "Włącz schemat dokera",
|
||||
"enableDockerSocketDescription": "Włącz etykietowanie kieszeni dokującej dla etykiet schematów. Ścieżka do gniazda musi być dostarczona do Newt.",
|
||||
"enableDockerSocketLink": "Dowiedz się więcej",
|
||||
"viewDockerContainers": "Zobacz kontenery dokujące",
|
||||
"containersIn": "Pojemniki w {siteName}",
|
||||
"selectContainerDescription": "Wybierz dowolny kontener do użycia jako nazwa hosta dla tego celu. Kliknij port, aby użyć portu.",
|
||||
"containerName": "Nazwisko",
|
||||
"containerName": "Nazwa",
|
||||
"containerImage": "Obraz",
|
||||
"containerState": "Stan",
|
||||
"containerNetworks": "Sieci",
|
||||
"containerHostnameIp": "Nazwa hosta/IP",
|
||||
"containerLabels": "Etykiety",
|
||||
"containerLabelsCount": "{count} etykieta{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# etykieta} few {# etykiety} many {# etykiet} other {# etykiet}}",
|
||||
"containerLabelsTitle": "Etykiety kontenera",
|
||||
"containerLabelEmpty": "<empty>",
|
||||
"containerPorts": "Porty",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Pokaż zatrzymane kontenery",
|
||||
"noContainersFound": "Nie znaleziono kontenerów. Upewnij się, że kontenery dokujące są uruchomione.",
|
||||
"searchContainersPlaceholder": "Szukaj w {count} kontenerach...",
|
||||
"searchResultsCount": "{count} wynik{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# wynik} few {# wyniki} many {# wyników} other {# wyników}}",
|
||||
"filters": "Filtry",
|
||||
"filterOptions": "Opcje filtru",
|
||||
"filterPorts": "Porty",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "ciemny",
|
||||
"system": "System",
|
||||
"theme": "Motyw",
|
||||
"subnetRequired": "Podsieć jest wymagana",
|
||||
"initialSetupTitle": "Wstępna konfiguracja serwera",
|
||||
"initialSetupDescription": "Utwórz początkowe konto administratora serwera. Może istnieć tylko jeden administrator serwera. Zawsze można zmienić te dane uwierzytelniające.",
|
||||
"createAdminAccount": "Utwórz konto administratora",
|
||||
"setupErrorCreateAdmin": "Wystąpił błąd podczas tworzenia konta administratora serwera."
|
||||
"setupErrorCreateAdmin": "Wystąpił błąd podczas tworzenia konta administratora serwera.",
|
||||
"certificateStatus": "Status certyfikatu",
|
||||
"loading": "Ładowanie",
|
||||
"restart": "Uruchom ponownie",
|
||||
"domains": "Domeny",
|
||||
"domainsDescription": "Zarządzaj domenami swojej organizacji",
|
||||
"domainsSearch": "Szukaj domen...",
|
||||
"domainAdd": "Dodaj domenę",
|
||||
"domainAddDescription": "Zarejestruj nową domenę w swojej organizacji",
|
||||
"domainCreate": "Utwórz domenę",
|
||||
"domainCreatedDescription": "Domena utworzona pomyślnie",
|
||||
"domainDeletedDescription": "Domena usunięta pomyślnie",
|
||||
"domainQuestionRemove": "Czy na pewno chcesz usunąć domenę {domain} ze swojego konta?",
|
||||
"domainMessageRemove": "Po usunięciu domena nie będzie już powiązana z twoim kontem.",
|
||||
"domainMessageConfirm": "Aby potwierdzić, wpisz nazwę domeny poniżej.",
|
||||
"domainConfirmDelete": "Potwierdź usunięcie domeny",
|
||||
"domainDelete": "Usuń domenę",
|
||||
"domain": "Domena",
|
||||
"selectDomainTypeNsName": "Delegacja domeny (NS)",
|
||||
"selectDomainTypeNsDescription": "Ta domena i wszystkie jej subdomeny. Użyj tego, gdy chcesz kontrolować całą strefę domeny.",
|
||||
"selectDomainTypeCnameName": "Pojedyncza domena (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Tylko ta pojedyncza domena. Użyj tego dla poszczególnych subdomen lub wpisów specyficznych dla domeny.",
|
||||
"selectDomainTypeWildcardName": "Domena wieloznaczna",
|
||||
"selectDomainTypeWildcardDescription": "Ta domena i jej subdomeny.",
|
||||
"domainDelegation": "Pojedyncza domena",
|
||||
"selectType": "Wybierz typ",
|
||||
"actions": "Akcje",
|
||||
"refresh": "Odśwież",
|
||||
"refreshError": "Nie udało się odświeżyć danych",
|
||||
"verified": "Zatwierdzony",
|
||||
"pending": "Oczekuje",
|
||||
"sidebarBilling": "Fakturowanie",
|
||||
"billing": "Fakturowanie",
|
||||
"orgBillingDescription": "Zarządzaj swoimi informacjami rozliczeniowymi i subskrypcjami",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Logo Pangolin",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Zakończ konfigurację konta",
|
||||
"completeAccountSetupDescription": "Ustaw swoje hasło, aby rozpocząć",
|
||||
"accountSetupSent": "Wyślemy kod konfiguracji konta na ten adres e-mail.",
|
||||
"accountSetupCode": "Kod konfiguracji",
|
||||
"accountSetupCodeDescription": "Sprawdź swój e-mail, aby znaleźć kod konfiguracji.",
|
||||
"passwordCreate": "Utwórz hasło",
|
||||
"passwordCreateConfirm": "Potwierdź hasło",
|
||||
"accountSetupSubmit": "Wyślij kod konfiguracji",
|
||||
"completeSetup": "Zakończ konfigurację",
|
||||
"accountSetupSuccess": "Konfiguracja konta zakończona! Witaj w Pangolin!",
|
||||
"documentation": "Dokumentacja",
|
||||
"saveAllSettings": "Zapisz wszystkie ustawienia",
|
||||
"settingsUpdated": "Ustawienia zaktualizowane",
|
||||
"settingsUpdatedDescription": "Wszystkie ustawienia zostały pomyślnie zaktualizowane",
|
||||
"settingsErrorUpdate": "Nie udało się zaktualizować ustawień",
|
||||
"settingsErrorUpdateDescription": "Wystąpił błąd podczas aktualizacji ustawień",
|
||||
"sidebarCollapse": "Zwiń",
|
||||
"sidebarExpand": "Rozwiń",
|
||||
"newtUpdateAvailable": "Dostępna aktualizacja",
|
||||
"newtUpdateAvailableInfo": "Nowa wersja Newt jest dostępna. Prosimy o aktualizację do najnowszej wersji dla najlepszej pracy.",
|
||||
"domainPickerEnterDomain": "Domena",
|
||||
"domainPickerPlaceholder": "mojapp.example.com",
|
||||
"domainPickerDescription": "Wpisz pełną domenę zasobu, aby zobaczyć dostępne opcje.",
|
||||
"domainPickerDescriptionSaas": "Wprowadź pełną domenę, subdomenę lub po prostu nazwę, aby zobaczyć dostępne opcje",
|
||||
"domainPickerTabAll": "Wszystko",
|
||||
"domainPickerTabOrganization": "Organizacja",
|
||||
"domainPickerTabProvided": "Dostarczona",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Sprawdzanie dostępności...",
|
||||
"domainPickerNoMatchingDomains": "Nie znaleziono pasujących domen. Spróbuj innej domeny lub sprawdź ustawienia domeny swojej organizacji.",
|
||||
"domainPickerOrganizationDomains": "Domeny organizacji",
|
||||
"domainPickerProvidedDomains": "Dostarczone domeny",
|
||||
"domainPickerSubdomain": "Subdomena: {subdomain}",
|
||||
"domainPickerNamespace": "Przestrzeń nazw: {namespace}",
|
||||
"domainPickerShowMore": "Pokaż więcej",
|
||||
"domainNotFound": "Nie znaleziono domeny",
|
||||
"domainNotFoundDescription": "Zasób jest wyłączony, ponieważ domena nie istnieje już w naszym systemie. Proszę ustawić nową domenę dla tego zasobu.",
|
||||
"failed": "Niepowodzenie",
|
||||
"createNewOrgDescription": "Utwórz nową organizację",
|
||||
"organization": "Organizacja",
|
||||
"port": "Port",
|
||||
"securityKeyManage": "Zarządzaj kluczami bezpieczeństwa",
|
||||
"securityKeyDescription": "Dodaj lub usuń klucze bezpieczeństwa do uwierzytelniania bez hasła",
|
||||
"securityKeyRegister": "Zarejestruj nowy klucz bezpieczeństwa",
|
||||
"securityKeyList": "Twoje klucze bezpieczeństwa",
|
||||
"securityKeyNone": "Brak zarejestrowanych kluczy bezpieczeństwa",
|
||||
"securityKeyNameRequired": "Nazwa jest wymagana",
|
||||
"securityKeyRemove": "Usuń",
|
||||
"securityKeyLastUsed": "Ostatnio używany: {date}",
|
||||
"securityKeyNameLabel": "Nazwa",
|
||||
"securityKeyRegisterSuccess": "Klucz bezpieczeństwa został pomyślnie zarejestrowany",
|
||||
"securityKeyRegisterError": "Błąd podczas rejestracji klucza bezpieczeństwa",
|
||||
"securityKeyRemoveSuccess": "Klucz bezpieczeństwa został pomyślnie usunięty",
|
||||
"securityKeyRemoveError": "Błąd podczas usuwania klucza bezpieczeństwa",
|
||||
"securityKeyLoadError": "Błąd podczas ładowania kluczy bezpieczeństwa",
|
||||
"securityKeyLogin": "Zaloguj się kluczem bezpieczeństwa",
|
||||
"securityKeyAuthError": "Błąd podczas uwierzytelniania kluczem bezpieczeństwa",
|
||||
"securityKeyRecommendation": "Rozważ zarejestrowanie innego klucza bezpieczeństwa na innym urządzeniu, aby upewnić się, że nie zostaniesz zablokowany z dostępu do swojego konta.",
|
||||
"registering": "Rejestracja...",
|
||||
"securityKeyPrompt": "Proszę zweryfikować swoją tożsamość, używając klucza bezpieczeństwa. Upewnij się, że twój klucz bezpieczeństwa jest podłączony i gotowy.",
|
||||
"securityKeyBrowserNotSupported": "Twoja przeglądarka nie obsługuje kluczy bezpieczeństwa. Proszę użyć nowoczesnej przeglądarki, takiej jak Chrome, Firefox lub Safari.",
|
||||
"securityKeyPermissionDenied": "Proszę umożliwić dostęp do klucza bezpieczeństwa, aby kontynuować logowanie.",
|
||||
"securityKeyRemovedTooQuickly": "Proszę utrzymać klucz bezpieczeństwa podłączony, dopóki proces logowania się nie zakończy.",
|
||||
"securityKeyNotSupported": "Twój klucz bezpieczeństwa może być niekompatybilny. Proszę spróbować innego klucza bezpieczeństwa.",
|
||||
"securityKeyUnknownError": "Wystąpił problem z używaniem klucza bezpieczeństwa. Proszę spróbować ponownie.",
|
||||
"twoFactorRequired": "Uwierzytelnianie dwuskładnikowe jest wymagane do zarejestrowania klucza bezpieczeństwa.",
|
||||
"twoFactor": "Uwierzytelnianie dwuskładnikowe",
|
||||
"adminEnabled2FaOnYourAccount": "Twój administrator włączył uwierzytelnianie dwuskładnikowe dla {email}. Proszę ukończyć proces konfiguracji, aby kontynuować.",
|
||||
"continueToApplication": "Kontynuuj do aplikacji",
|
||||
"securityKeyAdd": "Dodaj klucz bezpieczeństwa",
|
||||
"securityKeyRegisterTitle": "Zarejestruj nowy klucz bezpieczeństwa",
|
||||
"securityKeyRegisterDescription": "Podłącz swój klucz bezpieczeństwa i wprowadź nazwę, aby go zidentyfikować",
|
||||
"securityKeyTwoFactorRequired": "Wymagane uwierzytelnianie dwuskładnikowe",
|
||||
"securityKeyTwoFactorDescription": "Proszę wprowadzić kod uwierzytelnienia dwuskładnikowego, aby zarejestrować klucz bezpieczeństwa",
|
||||
"securityKeyTwoFactorRemoveDescription": "Proszę wprowadzić kod uwierzytelnienia dwuskładnikowego, aby usunąć klucz bezpieczeństwa",
|
||||
"securityKeyTwoFactorCode": "Kod dwuskładnikowy",
|
||||
"securityKeyRemoveTitle": "Usuń klucz bezpieczeństwa",
|
||||
"securityKeyRemoveDescription": "Wprowadź hasło, aby usunąć klucz bezpieczeństwa \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "Nie zarejestrowano kluczy bezpieczeństwa",
|
||||
"securityKeyNoKeysDescription": "Dodaj klucz bezpieczeństwa, aby zwiększyć swoje zabezpieczenia konta",
|
||||
"createDomainRequired": "Domena jest wymagana",
|
||||
"createDomainAddDnsRecords": "Dodaj rekordy DNS",
|
||||
"createDomainAddDnsRecordsDescription": "Dodaj poniższe rekordy DNS do swojego dostawcy domeny, aby zakończyć konfigurację.",
|
||||
"createDomainNsRecords": "Rekordy NS",
|
||||
"createDomainRecord": "Rekord",
|
||||
"createDomainType": "Typ:",
|
||||
"createDomainName": "Nazwa:",
|
||||
"createDomainValue": "Wartość:",
|
||||
"createDomainCnameRecords": "Rekordy CNAME",
|
||||
"createDomainARecords": "Rekordy A",
|
||||
"createDomainRecordNumber": "Rekord {number}",
|
||||
"createDomainTxtRecords": "Rekordy TXT",
|
||||
"createDomainSaveTheseRecords": "Zapisz te rekordy",
|
||||
"createDomainSaveTheseRecordsDescription": "Upewnij się, że zapiszesz te rekordy DNS, ponieważ nie będziesz mieć ich ponownie na ekranie.",
|
||||
"createDomainDnsPropagation": "Propagacja DNS",
|
||||
"createDomainDnsPropagationDescription": "Zmiany DNS mogą zająć trochę czasu na rozpropagowanie się w Internecie. Może to potrwać od kilku minut do 48 godzin, w zależności od dostawcy DNS i ustawień TTL.",
|
||||
"resourcePortRequired": "Numer portu jest wymagany dla zasobów non-HTTP",
|
||||
"resourcePortNotAllowed": "Numer portu nie powinien być ustawiony dla zasobów HTTP",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Zgadzam się z",
|
||||
"termsOfService": "warunkami usługi",
|
||||
"and": "oraz",
|
||||
"privacyPolicy": "polityką prywatności"
|
||||
},
|
||||
"siteRequired": "Strona jest wymagana.",
|
||||
"olmTunnel": "Tunel Olm",
|
||||
"olmTunnelDescription": "Użyj Olm do łączności klienta",
|
||||
"errorCreatingClient": "Błąd podczas tworzenia klienta",
|
||||
"clientDefaultsNotFound": "Nie znaleziono domyślnych ustawień klienta",
|
||||
"createClient": "Utwórz Klienta",
|
||||
"createClientDescription": "Utwórz nowego klienta do łączenia się z Twoimi witrynami",
|
||||
"seeAllClients": "Zobacz Wszystkich Klientów",
|
||||
"clientInformation": "Informacje o Kliencie",
|
||||
"clientNamePlaceholder": "Nazwa klienta",
|
||||
"address": "Adres",
|
||||
"subnetPlaceholder": "Podsieć",
|
||||
"addressDescription": "Adres, którego ten klient będzie używać do łączności",
|
||||
"selectSites": "Wybierz witryny",
|
||||
"sitesDescription": "Klient będzie miał łączność z wybranymi witrynami",
|
||||
"clientInstallOlm": "Zainstaluj Olm",
|
||||
"clientInstallOlmDescription": "Uruchom Olm na swoim systemie",
|
||||
"clientOlmCredentials": "Poświadczenia Olm",
|
||||
"clientOlmCredentialsDescription": "To jest sposób, w jaki Olm będzie się uwierzytelniać z serwerem",
|
||||
"olmEndpoint": "Punkt Końcowy Olm",
|
||||
"olmId": "Identyfikator Olm",
|
||||
"olmSecretKey": "Tajny Klucz Olm",
|
||||
"clientCredentialsSave": "Zapisz swoje poświadczenia",
|
||||
"clientCredentialsSaveDescription": "Będziesz mógł zobaczyć to tylko raz. Upewnij się, że skopiujesz go w bezpieczne miejsce.",
|
||||
"generalSettingsDescription": "Skonfiguruj ogólne ustawienia dla tego klienta",
|
||||
"clientUpdated": "Klient zaktualizowany",
|
||||
"clientUpdatedDescription": "Klient został zaktualizowany.",
|
||||
"clientUpdateFailed": "Nie udało się zaktualizować klienta",
|
||||
"clientUpdateError": "Wystąpił błąd podczas aktualizacji klienta.",
|
||||
"sitesFetchFailed": "Nie udało się pobrać witryn",
|
||||
"sitesFetchError": "Wystąpił błąd podczas pobierania witryn.",
|
||||
"olmErrorFetchReleases": "Wystąpił błąd podczas pobierania wydań Olm.",
|
||||
"olmErrorFetchLatest": "Wystąpił błąd podczas pobierania najnowszego wydania Olm.",
|
||||
"remoteSubnets": "Zdalne Podsieci",
|
||||
"enterCidrRange": "Wprowadź zakres CIDR",
|
||||
"remoteSubnetsDescription": "Dodaj zakresy CIDR, które można uzyskać zdalnie z tej strony za pomocą klientów. Użyj formatu jak 10.0.0.0/24. Dotyczy to WYŁĄCZNIE łączności klienta VPN.",
|
||||
"resourceEnableProxy": "Włącz publiczny proxy",
|
||||
"resourceEnableProxyDescription": "Włącz publiczne proxy dla tego zasobu. To umożliwia dostęp do zasobu spoza sieci przez chmurę na otwartym porcie. Wymaga konfiguracji Traefik.",
|
||||
"externalProxyEnabled": "Zewnętrzny Proxy Włączony",
|
||||
"addNewTarget": "Dodaj nowy cel",
|
||||
"targetsList": "Lista celów",
|
||||
"targetErrorDuplicateTargetFound": "Znaleziono duplikat celu",
|
||||
"httpMethod": "Metoda HTTP",
|
||||
"selectHttpMethod": "Wybierz metodę HTTP",
|
||||
"domainPickerSubdomainLabel": "Poddomena",
|
||||
"domainPickerBaseDomainLabel": "Domen bazowa",
|
||||
"domainPickerSearchDomains": "Szukaj domen...",
|
||||
"domainPickerNoDomainsFound": "Nie znaleziono domen",
|
||||
"domainPickerLoadingDomains": "Ładowanie domen...",
|
||||
"domainPickerSelectBaseDomain": "Wybierz domenę bazową...",
|
||||
"domainPickerNotAvailableForCname": "Niedostępne dla domen CNAME",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Wprowadź poddomenę lub pozostaw puste, aby użyć domeny bazowej.",
|
||||
"domainPickerEnterSubdomainToSearch": "Wprowadź poddomenę, aby wyszukać i wybrać z dostępnych darmowych domen.",
|
||||
"domainPickerFreeDomains": "Darmowe domeny",
|
||||
"domainPickerSearchForAvailableDomains": "Szukaj dostępnych domen",
|
||||
"resourceDomain": "Domena",
|
||||
"resourceEditDomain": "Edytuj domenę",
|
||||
"siteName": "Nazwa strony",
|
||||
"proxyPort": "Port",
|
||||
"resourcesTableProxyResources": "Zasoby proxy",
|
||||
"resourcesTableClientResources": "Zasoby klienta",
|
||||
"resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.",
|
||||
"resourcesTableDestination": "Miejsce docelowe",
|
||||
"resourcesTableTheseResourcesForUseWith": "Te zasoby są do użytku z",
|
||||
"resourcesTableClients": "Klientami",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "i są dostępne tylko wewnętrznie po połączeniu z klientem.",
|
||||
"editInternalResourceDialogEditClientResource": "Edytuj zasób klienta",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Zaktualizuj właściwości zasobu i konfigurację celu dla {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Właściwości zasobów",
|
||||
"editInternalResourceDialogName": "Nazwa",
|
||||
"editInternalResourceDialogProtocol": "Protokół",
|
||||
"editInternalResourceDialogSitePort": "Port witryny",
|
||||
"editInternalResourceDialogTargetConfiguration": "Konfiguracja celu",
|
||||
"editInternalResourceDialogCancel": "Anuluj",
|
||||
"editInternalResourceDialogSaveResource": "Zapisz zasób",
|
||||
"editInternalResourceDialogSuccess": "Sukces",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Wewnętrzny zasób zaktualizowany pomyślnie",
|
||||
"editInternalResourceDialogError": "Błąd",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować wewnętrznego zasobu",
|
||||
"editInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||
"editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||
"editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
|
||||
"editInternalResourceDialogProxyPortMax": "Port proxy nie może być większy niż 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Nieprawidłowy format adresu IP",
|
||||
"editInternalResourceDialogDestinationPortMin": "Port docelowy musi wynosić przynajmniej 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "Port docelowy nie może być większy niż 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Brak dostępnych stron",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Musisz mieć co najmniej jedną stronę Newt z skonfigurowanym podsiecią, aby tworzyć wewnętrzne zasoby.",
|
||||
"createInternalResourceDialogClose": "Zamknij",
|
||||
"createInternalResourceDialogCreateClientResource": "Utwórz zasób klienta",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Utwórz nowy zasób, który będzie dostępny dla klientów połączonych z wybraną stroną.",
|
||||
"createInternalResourceDialogResourceProperties": "Właściwości zasobów",
|
||||
"createInternalResourceDialogName": "Nazwa",
|
||||
"createInternalResourceDialogSite": "Witryna",
|
||||
"createInternalResourceDialogSelectSite": "Wybierz stronę...",
|
||||
"createInternalResourceDialogSearchSites": "Szukaj stron...",
|
||||
"createInternalResourceDialogNoSitesFound": "Nie znaleziono stron.",
|
||||
"createInternalResourceDialogProtocol": "Protokół",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Port witryny",
|
||||
"createInternalResourceDialogSitePortDescription": "Użyj tego portu, aby uzyskać dostęp do zasobu na stronie, gdy połączony z klientem.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Konfiguracja celu",
|
||||
"createInternalResourceDialogDestinationIPDescription": "Adres IP lub nazwa hosta zasobu w sieci witryny.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "Port na docelowym IP, gdzie zasób jest dostępny.",
|
||||
"createInternalResourceDialogCancel": "Anuluj",
|
||||
"createInternalResourceDialogCreateResource": "Utwórz zasób",
|
||||
"createInternalResourceDialogSuccess": "Sukces",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Wewnętrzny zasób utworzony pomyślnie",
|
||||
"createInternalResourceDialogError": "Błąd",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć wewnętrznego zasobu",
|
||||
"createInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||
"createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę",
|
||||
"createInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
|
||||
"createInternalResourceDialogProxyPortMax": "Port proxy nie może być większy niż 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Nieprawidłowy format adresu IP",
|
||||
"createInternalResourceDialogDestinationPortMin": "Port docelowy musi wynosić przynajmniej 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "Port docelowy nie może być większy niż 65536",
|
||||
"siteConfiguration": "Konfiguracja",
|
||||
"siteAcceptClientConnections": "Akceptuj połączenia klienta",
|
||||
"siteAcceptClientConnectionsDescription": "Pozwól innym urządzeniom połączyć się przez tę instancję Newt jako bramę za pomocą klientów.",
|
||||
"siteAddress": "Adres strony",
|
||||
"siteAddressDescription": "Podaj adres IP hosta, do którego klienci będą się łączyć. Jest to wewnętrzny adres strony w sieci Pangolin dla klientów do adresowania. Musi zawierać się w podsieci organizacji.",
|
||||
"autoLoginExternalIdp": "Automatyczny login z zewnętrznym IDP",
|
||||
"autoLoginExternalIdpDescription": "Natychmiastowe przekierowanie użytkownika do zewnętrznego IDP w celu uwierzytelnienia.",
|
||||
"selectIdp": "Wybierz IDP",
|
||||
"selectIdpPlaceholder": "Wybierz IDP...",
|
||||
"selectIdpRequired": "Proszę wybrać IDP, gdy aktywne jest automatyczne logowanie.",
|
||||
"autoLoginTitle": "Przekierowywanie",
|
||||
"autoLoginDescription": "Przekierowanie do zewnętrznego dostawcy tożsamości w celu uwierzytelnienia.",
|
||||
"autoLoginProcessing": "Przygotowywanie uwierzytelniania...",
|
||||
"autoLoginRedirecting": "Przekierowanie do logowania...",
|
||||
"autoLoginError": "Błąd automatycznego logowania",
|
||||
"autoLoginErrorNoRedirectUrl": "Nie otrzymano URL przekierowania od dostawcy tożsamości.",
|
||||
"autoLoginErrorGeneratingUrl": "Nie udało się wygenerować URL uwierzytelniania.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Zarządzane Samodzielnie-Hostingowane",
|
||||
"description": "Większa niezawodność i niska konserwacja serwera Pangolin z dodatkowymi dzwonkami i sygnałami",
|
||||
"introTitle": "Zarządzany samowystarczalny Pangolin",
|
||||
"introDescription": "jest opcją wdrażania zaprojektowaną dla osób, które chcą prostoty i dodatkowej niezawodności, przy jednoczesnym utrzymaniu swoich danych prywatnych i samodzielnych.",
|
||||
"introDetail": "Z tą opcją nadal obsługujesz swój własny węzeł Pangolin — tunele, zakończenie SSL i ruch na Twoim serwerze. Różnica polega na tym, że zarządzanie i monitorowanie odbywa się za pomocą naszej tablicy rozdzielczej, która odblokowuje szereg korzyści:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Uproszczone operacje",
|
||||
"description": "Nie ma potrzeby uruchamiania własnego serwera pocztowego lub ustawiania skomplikowanych powiadomień. Będziesz mieć kontrolę zdrowia i powiadomienia o przestoju."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Automatyczne aktualizacje",
|
||||
"description": "Panel chmury rozwija się szybko, więc otrzymujesz nowe funkcje i poprawki błędów bez konieczności ręcznego ciągnięcia nowych kontenerów za każdym razem."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Mniej konserwacji",
|
||||
"description": "Brak migracji bazy danych, kopii zapasowych lub dodatkowej infrastruktury do zarządzania. Obsługujemy to w chmurze."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Przegrywanie w chmurze",
|
||||
"description": "Jeśli Twój węzeł zostanie wyłączony, tunele mogą tymczasowo zawieść do naszych punktów w chmurze, dopóki nie przyniesiesz go z powrotem do trybu online."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Wysoka dostępność (PoPs)",
|
||||
"description": "Możesz również dołączyć wiele węzłów do swojego konta w celu nadmiarowości i lepszej wydajności."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Przyszłe ulepszenia",
|
||||
"description": "Planujemy dodać więcej narzędzi analitycznych, ostrzegawczych i zarządzania, aby zwiększyć odporność wdrożenia."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Dowiedz się więcej o opcji zarządzania samodzielnym hostingiem w naszym",
|
||||
"documentation": "dokumentacja"
|
||||
},
|
||||
"convertButton": "Konwertuj ten węzeł do zarządzanego samodzielnie"
|
||||
},
|
||||
"internationaldomaindetected": "Wykryto międzynarodową domenę",
|
||||
"willbestoredas": "Będą przechowywane jako:",
|
||||
"idpGoogleDescription": "Dostawca Google OAuth2/OIDC",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Niestandardowe nagłówki",
|
||||
"headersValidationError": "Nagłówki muszą być w formacie: Nazwa nagłówka: wartość.",
|
||||
"domainPickerProvidedDomain": "Dostarczona domena",
|
||||
"domainPickerFreeProvidedDomain": "Darmowa oferowana domena",
|
||||
"domainPickerVerified": "Zweryfikowano",
|
||||
"domainPickerUnverified": "Niezweryfikowane",
|
||||
"domainPickerInvalidSubdomainStructure": "Ta subdomena zawiera nieprawidłowe znaki lub strukturę. Zostanie ona automatycznie oczyszczona po zapisaniu.",
|
||||
"domainPickerError": "Błąd",
|
||||
"domainPickerErrorLoadDomains": "Nie udało się załadować domen organizacji",
|
||||
"domainPickerErrorCheckAvailability": "Nie udało się sprawdzić dostępności domeny",
|
||||
"domainPickerInvalidSubdomain": "Nieprawidłowa subdomena",
|
||||
"domainPickerInvalidSubdomainRemoved": "Wejście \"{sub}\" zostało usunięte, ponieważ jest nieprawidłowe.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" nie może być poprawne dla {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Poddomena oczyszczona",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" został skorygowany do \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Edytuj plik: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Edytuj plik: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "Você não é atualmente um membro de nenhuma organização. Crie uma organização para começar.",
|
||||
"componentsErrorNoMember": "Você não é atualmente um membro de nenhuma organização.",
|
||||
"welcome": "Bem-vindo ao Pangolin",
|
||||
"welcomeTo": "Bem-vindo ao",
|
||||
"componentsCreateOrg": "Criar uma organização",
|
||||
"componentsMember": "Você é membro de {count, plural, =0 {Nenhuma organização} =1 {Uma organização} other {# organizações}}",
|
||||
"componentsMember": "Você é membro de {count, plural, =0 {nenhuma organização} one {uma organização} other {# organizações}}.",
|
||||
"componentsInvalidKey": "Chaves de licença inválidas ou expiradas detectadas. Siga os termos da licença para continuar usando todos os recursos.",
|
||||
"dismiss": "Descartar",
|
||||
"componentsLicenseViolation": "Violação de Licença: Este servidor está usando sites {usedSites} que excedem o limite licenciado de sites {maxSites} . Siga os termos da licença para continuar usando todos os recursos.",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Erro ao criar site",
|
||||
"siteErrorCreateKeyPair": "Par de chaves ou padrões do site não encontrados",
|
||||
"siteErrorCreateDefaults": "Padrão do site não encontrado",
|
||||
"siteNameDescription": "Este é o nome de exibição do site.",
|
||||
"method": "Método",
|
||||
"siteMethodDescription": "É assim que você irá expor as conexões.",
|
||||
"siteLearnNewt": "Saiba como instalar o Newt no seu sistema",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "A maneira mais fácil de criar um ponto de entrada na sua rede. Nenhuma configuração extra.",
|
||||
"siteWg": "WireGuard Básico",
|
||||
"siteWgDescription": "Use qualquer cliente do WireGuard para estabelecer um túnel. Configuração manual NAT é necessária.",
|
||||
"siteWgDescriptionSaas": "Use qualquer cliente WireGuard para estabelecer um túnel. Configuração manual NAT necessária. SOMENTE FUNCIONA EM NODES AUTO-HOSPEDADOS",
|
||||
"siteLocalDescription": "Recursos locais apenas. Sem túneis.",
|
||||
"siteLocalDescriptionSaas": "Apenas recursos locais. Sem tunelamento. SOMENTE FUNCIONA EM NODES AUTO-HOSPEDADOS",
|
||||
"siteSeeAll": "Ver todos os sites",
|
||||
"siteTunnelDescription": "Determine como você deseja se conectar ao seu site",
|
||||
"siteNewtCredentials": "Credenciais Novas",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Selecionar site",
|
||||
"siteSearch": "Procurar no site",
|
||||
"siteNotFound": "Nenhum site encontrado.",
|
||||
"siteSelectionDescription": "Este site fornecerá conectividade ao recurso.",
|
||||
"siteSelectionDescription": "Este site fornecerá conectividade ao destino.",
|
||||
"resourceType": "Tipo de Recurso",
|
||||
"resourceTypeDescription": "Determine como você deseja acessar seu recurso",
|
||||
"resourceHTTPSSettings": "Configurações de HTTPS",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Gerais",
|
||||
"generalSettings": "Configurações Gerais",
|
||||
"proxy": "Proxy",
|
||||
"internal": "Interno",
|
||||
"rules": "Regras",
|
||||
"resourceSettingDescription": "Configure as configurações do seu recurso",
|
||||
"resourceSetting": "Configurações do {resourceName}",
|
||||
"alwaysAllow": "Sempre permitir",
|
||||
"alwaysDeny": "Sempre negar",
|
||||
"passToAuth": "Passar para Autenticação",
|
||||
"orgSettingsDescription": "Configurar as configurações gerais da sua organização",
|
||||
"orgGeneralSettings": "Configurações da organização",
|
||||
"orgGeneralSettingsDescription": "Gerencie os detalhes e a configuração da sua organização",
|
||||
"saveGeneralSettings": "Salvar configurações gerais",
|
||||
"saveSettings": "Salvar Configurações",
|
||||
"orgDangerZone": "Zona de Perigo",
|
||||
"orgDangerZoneDescription": "Uma vez que você exclui esta organização, não há volta. Por favor, tenha certeza.",
|
||||
"orgDelete": "Excluir Organização",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "semanas",
|
||||
"months": "Meses",
|
||||
"years": "anos",
|
||||
"day": "{count, plural, =1 {# dia} other {# dias}}",
|
||||
"day": "{count, plural, one {# dia} other {# dias}}",
|
||||
"apiKeysTitle": "Informações da Chave API",
|
||||
"apiKeysConfirmCopy2": "Você deve confirmar que copiou a chave API.",
|
||||
"apiKeysErrorCreate": "Erro ao criar chave API",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Comprar Licença",
|
||||
"licensePurchaseSites": "Comprar Sites Adicionais",
|
||||
"licenseSitesUsedMax": "{usedSites} de {maxSites} utilizados",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} =1 {# site} other {# sites}} no sistema.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# sites} one {# site} other {# sites}} no sistema.",
|
||||
"licensePurchaseDescription": "Escolha quantos sites você quer {selectedMode, select, license {Compre uma licença. Você sempre pode adicionar mais sites depois.} other {adicione à sua licença existente.}}",
|
||||
"licenseFee": "Taxa de licença",
|
||||
"licensePriceSite": "Preço por site",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Selecionar função",
|
||||
"inviteEmailSentDescription": "Um e-mail foi enviado ao usuário com o link de acesso abaixo. Eles devem acessar o link para aceitar o convite.",
|
||||
"inviteSentDescription": "O usuário foi convidado. Eles devem acessar o link abaixo para aceitar o convite.",
|
||||
"inviteExpiresIn": "O convite expirará em {days, plural, =1 {# dia} other {# dias}}.",
|
||||
"inviteExpiresIn": "O convite expirará em {days, plural, one {# dia} other {# dias}}.",
|
||||
"idpTitle": "Informações Gerais",
|
||||
"idpSelect": "Selecione o provedor de identidade para o usuário externo",
|
||||
"idpNotConfigured": "Nenhum provedor de identidade está configurado. Configure um provedor de identidade antes de criar usuários externos.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Ocorreu um erro ao adicionar usuário à função.",
|
||||
"userSaved": "Usuário salvo",
|
||||
"userSavedDescription": "O usuário foi atualizado.",
|
||||
"autoProvisioned": "Auto provisionado",
|
||||
"autoProvisionedDescription": "Permitir que este usuário seja gerenciado automaticamente pelo provedor de identidade",
|
||||
"accessControlsDescription": "Gerencie o que este usuário pode acessar e fazer na organização",
|
||||
"accessControlsSubmit": "Salvar Controles de Acesso",
|
||||
"roles": "Funções",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "O Nome do Servidor TLS para usar para SNI. Deixe vazio para usar o padrão.",
|
||||
"targetTlsSubmit": "Salvar Configurações",
|
||||
"targets": "Configuração de Alvos",
|
||||
"targetsDescription": "Configure alvos para rotear tráfego para seus serviços",
|
||||
"targetsDescription": "Configure alvos para rotear tráfego para seus serviços de backend",
|
||||
"targetStickySessions": "Ativar Sessões Persistentes",
|
||||
"targetStickySessionsDescription": "Manter conexões no mesmo alvo backend durante toda a sessão.",
|
||||
"methodSelect": "Selecionar método",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Formato de endereço IP inválido",
|
||||
"ipAddressErrorInvalidOctet": "Octeto de endereço IP inválido",
|
||||
"path": "Caminho",
|
||||
"matchPath": "Correspondência de caminho",
|
||||
"ipAddressRange": "Faixa de IP",
|
||||
"rulesErrorFetch": "Falha ao buscar regras",
|
||||
"rulesErrorFetchDescription": "Ocorreu um erro ao buscar regras",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Ações",
|
||||
"rulesActionAlwaysAllow": "Sempre Permitir: Ignorar todos os métodos de autenticação",
|
||||
"rulesActionAlwaysDeny": "Sempre Negar: Bloquear todas as requisições; nenhuma autenticação pode ser tentada",
|
||||
"rulesActionPassToAuth": "Passar para Autenticação: Permitir que métodos de autenticação sejam tentados",
|
||||
"rulesMatchCriteria": "Critérios de Correspondência",
|
||||
"rulesMatchCriteriaIpAddress": "Corresponder a um endereço IP específico",
|
||||
"rulesMatchCriteriaIpAddressRange": "Corresponder a uma faixa de endereços IP em notação CIDR",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "O PIN deve ter exatamente 6 dígitos",
|
||||
"pincodeRequirementsChars": "O PIN deve conter apenas números",
|
||||
"passwordRequirementsLength": "A palavra-passe deve ter pelo menos 1 caractere",
|
||||
"passwordRequirementsTitle": "Requisitos de senha:",
|
||||
"passwordRequirementLength": "Pelo menos 8 caracteres de comprimento",
|
||||
"passwordRequirementUppercase": "Pelo menos uma letra maiúscula",
|
||||
"passwordRequirementLowercase": "Pelo menos uma letra minúscula",
|
||||
"passwordRequirementNumber": "Pelo menos um número",
|
||||
"passwordRequirementSpecial": "Pelo menos um caractere especial",
|
||||
"passwordRequirementsMet": "✓ Senha atende a todos os requisitos",
|
||||
"passwordStrength": "Força da senha",
|
||||
"passwordStrengthWeak": "Fraca",
|
||||
"passwordStrengthMedium": "Média",
|
||||
"passwordStrengthStrong": "Forte",
|
||||
"passwordRequirements": "Requisitos:",
|
||||
"passwordRequirementLengthText": "8+ caracteres",
|
||||
"passwordRequirementUppercaseText": "Letra maiúscula (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Letra minúscula (a-z)",
|
||||
"passwordRequirementNumberText": "Número (0-9)",
|
||||
"passwordRequirementSpecialText": "Caractere especial (!@#$%...)",
|
||||
"passwordsDoNotMatch": "As palavras-passe não correspondem",
|
||||
"otpEmailRequirementsLength": "O OTP deve ter pelo menos 1 caractere",
|
||||
"otpEmailSent": "OTP Enviado",
|
||||
"otpEmailSentDescription": "Um OTP foi enviado para o seu email",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Conectado",
|
||||
"idpErrorConnectingTo": "Ocorreu um problema ao ligar a {name}. Por favor, contacte o seu administrador.",
|
||||
"idpErrorNotFound": "IdP não encontrado",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Convite Inválido",
|
||||
"inviteInvalidDescription": "O link do convite é inválido.",
|
||||
"inviteErrorWrongUser": "O convite não é para este usuário",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Erro ao terminar sessão",
|
||||
"signingAs": "Sessão iniciada como",
|
||||
"serverAdmin": "Administrador do Servidor",
|
||||
"managedSelfhosted": "Gerenciado Auto-Hospedado",
|
||||
"otpEnable": "Ativar Autenticação de Dois Fatores",
|
||||
"otpDisable": "Desativar Autenticação de Dois Fatores",
|
||||
"logout": "Terminar Sessão",
|
||||
"licenseTierProfessionalRequired": "Edição Profissional Necessária",
|
||||
"licenseTierProfessionalRequiredDescription": "Esta funcionalidade só está disponível na Edição Profissional.",
|
||||
"actionGetOrg": "Obter Organização",
|
||||
"updateOrgUser": "Atualizar usuário Org",
|
||||
"createOrgUser": "Criar usuário Org",
|
||||
"actionUpdateOrg": "Atualizar Organização",
|
||||
"actionUpdateUser": "Atualizar Usuário",
|
||||
"actionGetUser": "Obter Usuário",
|
||||
"actionGetOrgUser": "Obter Utilizador da Organização",
|
||||
"actionListOrgDomains": "Listar Domínios da Organização",
|
||||
"actionCreateSite": "Criar Site",
|
||||
"actionDeleteSite": "Eliminar Site",
|
||||
"actionGetSite": "Obter Site",
|
||||
"actionListSites": "Listar Sites",
|
||||
"actionApplyBlueprint": "Aplicar Diagrama",
|
||||
"setupToken": "Configuração do Token",
|
||||
"setupTokenDescription": "Digite o token de configuração do console do servidor.",
|
||||
"setupTokenRequired": "Token de configuração é necessário",
|
||||
"actionUpdateSite": "Atualizar Site",
|
||||
"actionListSiteRoles": "Listar Funções Permitidas do Site",
|
||||
"actionCreateResource": "Criar Recurso",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Eliminar Política de Organização IDP",
|
||||
"actionListIdpOrgs": "Listar Organizações IDP",
|
||||
"actionUpdateIdpOrg": "Atualizar Organização IDP",
|
||||
"actionCreateClient": "Criar Cliente",
|
||||
"actionDeleteClient": "Excluir Cliente",
|
||||
"actionUpdateClient": "Atualizar Cliente",
|
||||
"actionListClients": "Listar Clientes",
|
||||
"actionGetClient": "Obter Cliente",
|
||||
"actionCreateSiteResource": "Criar Recurso do Site",
|
||||
"actionDeleteSiteResource": "Eliminar Recurso do Site",
|
||||
"actionGetSiteResource": "Obter Recurso do Site",
|
||||
"actionListSiteResources": "Listar Recursos do Site",
|
||||
"actionUpdateSiteResource": "Atualizar Recurso do Site",
|
||||
"actionListInvitations": "Listar Convites",
|
||||
"noneSelected": "Nenhum selecionado",
|
||||
"orgNotFound2": "Nenhuma organização encontrada.",
|
||||
"searchProgress": "Pesquisar...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Todos os usuários",
|
||||
"sidebarIdentityProviders": "Provedores de identidade",
|
||||
"sidebarLicense": "Tipo:",
|
||||
"enableDockerSocket": "Habilitar Docker Socket",
|
||||
"enableDockerSocketDescription": "Ativar a descoberta do Docker Socket para preencher informações do contêiner. O caminho do socket deve ser fornecido ao Newt.",
|
||||
"sidebarClients": "Clientes (Beta)",
|
||||
"sidebarDomains": "Domínios",
|
||||
"enableDockerSocket": "Habilitar o Diagrama Docker",
|
||||
"enableDockerSocketDescription": "Ativar a scraping de rótulo Docker para rótulos de diagramas. Caminho de Socket deve ser fornecido para Newt.",
|
||||
"enableDockerSocketLink": "Saiba mais",
|
||||
"viewDockerContainers": "Ver contêineres Docker",
|
||||
"containersIn": "Contêineres em {siteName}",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Redes",
|
||||
"containerHostnameIp": "Hostname/IP",
|
||||
"containerLabels": "Marcadores",
|
||||
"containerLabelsCount": "{count} rótulo{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, one {# rótulo} other {# rótulos}}",
|
||||
"containerLabelsTitle": "Etiquetas do Contêiner",
|
||||
"containerLabelEmpty": "<vazio>",
|
||||
"containerPorts": "Portas",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Mostrar contêineres parados",
|
||||
"noContainersFound": "Nenhum contêiner encontrado. Certifique-se de que os contêineres Docker estão em execução.",
|
||||
"searchContainersPlaceholder": "Pesquisar entre os contêineres {count}...",
|
||||
"searchResultsCount": "{count} resultado{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, one {# resultado} other {# resultados}}",
|
||||
"filters": "Filtros",
|
||||
"filterOptions": "Opções de Filtro",
|
||||
"filterPorts": "Portas",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "escuro",
|
||||
"system": "sistema",
|
||||
"theme": "Tema",
|
||||
"subnetRequired": "Sub-rede é obrigatória",
|
||||
"initialSetupTitle": "Configuração Inicial do Servidor",
|
||||
"initialSetupDescription": "Crie a conta de administrador inicial do servidor. Apenas um administrador do servidor pode existir. Você sempre pode alterar essas credenciais posteriormente.",
|
||||
"createAdminAccount": "Criar Conta de Administrador",
|
||||
"setupErrorCreateAdmin": "Ocorreu um erro ao criar a conta de administrador do servidor."
|
||||
"setupErrorCreateAdmin": "Ocorreu um erro ao criar a conta de administrador do servidor.",
|
||||
"certificateStatus": "Status do Certificado",
|
||||
"loading": "Carregando",
|
||||
"restart": "Reiniciar",
|
||||
"domains": "Domínios",
|
||||
"domainsDescription": "Gerencie domínios para sua organização",
|
||||
"domainsSearch": "Pesquisar domínios...",
|
||||
"domainAdd": "Adicionar Domínio",
|
||||
"domainAddDescription": "Registre um novo domínio com sua organização",
|
||||
"domainCreate": "Criar Domínio",
|
||||
"domainCreatedDescription": "Domínio criado com sucesso",
|
||||
"domainDeletedDescription": "Domínio deletado com sucesso",
|
||||
"domainQuestionRemove": "Tem certeza de que deseja remover o domínio {domain} da sua conta?",
|
||||
"domainMessageRemove": "Uma vez removido, o domínio não estará mais associado à sua conta.",
|
||||
"domainMessageConfirm": "Para confirmar, digite o nome do domínio abaixo.",
|
||||
"domainConfirmDelete": "Confirmar Exclusão de Domínio",
|
||||
"domainDelete": "Excluir Domínio",
|
||||
"domain": "Domínio",
|
||||
"selectDomainTypeNsName": "Delegação de Domínio (NS)",
|
||||
"selectDomainTypeNsDescription": "Este domínio e todos os seus subdomínios. Use isso quando quiser controlar uma zona de domínio inteira.",
|
||||
"selectDomainTypeCnameName": "Domínio Único (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Apenas este domínio específico. Use isso para subdomínios individuais ou entradas de domínio específicas.",
|
||||
"selectDomainTypeWildcardName": "Domínio Coringa",
|
||||
"selectDomainTypeWildcardDescription": "Este domínio e seus subdomínios.",
|
||||
"domainDelegation": "Domínio Único",
|
||||
"selectType": "Selecione um tipo",
|
||||
"actions": "Ações",
|
||||
"refresh": "Atualizar",
|
||||
"refreshError": "Falha ao atualizar dados",
|
||||
"verified": "Verificado",
|
||||
"pending": "Pendente",
|
||||
"sidebarBilling": "Faturamento",
|
||||
"billing": "Faturamento",
|
||||
"orgBillingDescription": "Gerencie suas informações de faturamento e assinaturas",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Hospedagem Pangolin",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Completar Configuração da Conta",
|
||||
"completeAccountSetupDescription": "Defina sua senha para começar",
|
||||
"accountSetupSent": "Enviaremos um código de ativação da conta para este endereço de e-mail.",
|
||||
"accountSetupCode": "Código de Ativação",
|
||||
"accountSetupCodeDescription": "Verifique seu e-mail para obter o código de ativação.",
|
||||
"passwordCreate": "Criar Senha",
|
||||
"passwordCreateConfirm": "Confirmar Senha",
|
||||
"accountSetupSubmit": "Enviar Código de Ativação",
|
||||
"completeSetup": "Configuração Completa",
|
||||
"accountSetupSuccess": "Configuração da conta concluída! Bem-vindo ao Pangolin!",
|
||||
"documentation": "Documentação",
|
||||
"saveAllSettings": "Salvar Todas as Configurações",
|
||||
"settingsUpdated": "Configurações atualizadas",
|
||||
"settingsUpdatedDescription": "Todas as configurações foram atualizadas com sucesso",
|
||||
"settingsErrorUpdate": "Falha ao atualizar configurações",
|
||||
"settingsErrorUpdateDescription": "Ocorreu um erro ao atualizar configurações",
|
||||
"sidebarCollapse": "Recolher",
|
||||
"sidebarExpand": "Expandir",
|
||||
"newtUpdateAvailable": "Nova Atualização Disponível",
|
||||
"newtUpdateAvailableInfo": "Uma nova versão do Newt está disponível. Atualize para a versão mais recente para uma melhor experiência.",
|
||||
"domainPickerEnterDomain": "Domínio",
|
||||
"domainPickerPlaceholder": "myapp.exemplo.com",
|
||||
"domainPickerDescription": "Insira o domínio completo do recurso para ver as opções disponíveis.",
|
||||
"domainPickerDescriptionSaas": "Insira um domínio completo, subdomínio ou apenas um nome para ver as opções disponíveis",
|
||||
"domainPickerTabAll": "Todos",
|
||||
"domainPickerTabOrganization": "Organização",
|
||||
"domainPickerTabProvided": "Fornecido",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Verificando disponibilidade...",
|
||||
"domainPickerNoMatchingDomains": "Nenhum domínio correspondente encontrado. Tente um domínio diferente ou verifique as configurações do domínio da sua organização.",
|
||||
"domainPickerOrganizationDomains": "Domínios da Organização",
|
||||
"domainPickerProvidedDomains": "Domínios Fornecidos",
|
||||
"domainPickerSubdomain": "Subdomínio: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"domainPickerShowMore": "Mostrar Mais",
|
||||
"domainNotFound": "Domínio Não Encontrado",
|
||||
"domainNotFoundDescription": "Este recurso está desativado porque o domínio não existe mais em nosso sistema. Defina um novo domínio para este recurso.",
|
||||
"failed": "Falhou",
|
||||
"createNewOrgDescription": "Crie uma nova organização",
|
||||
"organization": "Organização",
|
||||
"port": "Porta",
|
||||
"securityKeyManage": "Gerenciar chaves de segurança",
|
||||
"securityKeyDescription": "Adicionar ou remover chaves de segurança para autenticação sem senha",
|
||||
"securityKeyRegister": "Registrar nova chave de segurança",
|
||||
"securityKeyList": "Suas chaves de segurança",
|
||||
"securityKeyNone": "Nenhuma chave de segurança registrada",
|
||||
"securityKeyNameRequired": "Nome é obrigatório",
|
||||
"securityKeyRemove": "Remover",
|
||||
"securityKeyLastUsed": "Último uso: {date}",
|
||||
"securityKeyNameLabel": "Nome",
|
||||
"securityKeyRegisterSuccess": "Chave de segurança registrada com sucesso",
|
||||
"securityKeyRegisterError": "Erro ao registrar chave de segurança",
|
||||
"securityKeyRemoveSuccess": "Chave de segurança removida com sucesso",
|
||||
"securityKeyRemoveError": "Erro ao remover chave de segurança",
|
||||
"securityKeyLoadError": "Erro ao carregar chaves de segurança",
|
||||
"securityKeyLogin": "Continuar com a chave de segurança",
|
||||
"securityKeyAuthError": "Erro ao autenticar com chave de segurança",
|
||||
"securityKeyRecommendation": "Considere registrar outra chave de segurança em um dispositivo diferente para garantir que você não fique bloqueado da sua conta.",
|
||||
"registering": "Registrando...",
|
||||
"securityKeyPrompt": "Verifique sua identidade usando sua chave de segurança. Certifique-se de que sua chave de segurança está conectada e pronta.",
|
||||
"securityKeyBrowserNotSupported": "Seu navegador não suporta chaves de segurança. Use um navegador moderno como Chrome, Firefox ou Safari.",
|
||||
"securityKeyPermissionDenied": "Permita o acesso à sua chave de segurança para continuar o login.",
|
||||
"securityKeyRemovedTooQuickly": "Mantenha sua chave de segurança conectada até que o processo de login seja concluído.",
|
||||
"securityKeyNotSupported": "Sua chave de segurança pode não ser compatível. Tente uma chave de segurança diferente.",
|
||||
"securityKeyUnknownError": "Houve um problema ao usar sua chave de segurança. Tente novamente.",
|
||||
"twoFactorRequired": "A autenticação de dois fatores é necessária para registrar uma chave de segurança.",
|
||||
"twoFactor": "Autenticação de Dois Fatores",
|
||||
"adminEnabled2FaOnYourAccount": "Seu administrador ativou a autenticação de dois fatores para {email}. Complete o processo de configuração para continuar.",
|
||||
"continueToApplication": "Continuar para Aplicativo",
|
||||
"securityKeyAdd": "Adicionar Chave de Segurança",
|
||||
"securityKeyRegisterTitle": "Registrar Nova Chave de Segurança",
|
||||
"securityKeyRegisterDescription": "Conecte sua chave de segurança e insira um nome para identificá-la",
|
||||
"securityKeyTwoFactorRequired": "Autenticação de Dois Fatores Obrigatória",
|
||||
"securityKeyTwoFactorDescription": "Insira seu código de autenticação de dois fatores para registrar a chave de segurança",
|
||||
"securityKeyTwoFactorRemoveDescription": "Insira seu código de autenticação de dois fatores para remover a chave de segurança",
|
||||
"securityKeyTwoFactorCode": "Código de Dois Fatores",
|
||||
"securityKeyRemoveTitle": "Remover Chave de Segurança",
|
||||
"securityKeyRemoveDescription": "Insira sua senha para remover a chave de segurança \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "Nenhuma chave de segurança registrada",
|
||||
"securityKeyNoKeysDescription": "Adicione uma chave de segurança para melhorar a segurança da sua conta",
|
||||
"createDomainRequired": "Domínio é obrigatório",
|
||||
"createDomainAddDnsRecords": "Adicionar Registros DNS",
|
||||
"createDomainAddDnsRecordsDescription": "Adicione os seguintes registros DNS ao seu provedor de domínio para completar a configuração.",
|
||||
"createDomainNsRecords": "Registros NS",
|
||||
"createDomainRecord": "Registrar",
|
||||
"createDomainType": "Tipo:",
|
||||
"createDomainName": "Nome:",
|
||||
"createDomainValue": "Valor:",
|
||||
"createDomainCnameRecords": "Registros CNAME",
|
||||
"createDomainARecords": "Registros A",
|
||||
"createDomainRecordNumber": "Registrar {number}",
|
||||
"createDomainTxtRecords": "Registros TXT",
|
||||
"createDomainSaveTheseRecords": "Salvar Esses Registros",
|
||||
"createDomainSaveTheseRecordsDescription": "Certifique-se de salvar esses registros DNS, pois você não os verá novamente.",
|
||||
"createDomainDnsPropagation": "Propagação DNS",
|
||||
"createDomainDnsPropagationDescription": "Alterações no DNS podem levar algum tempo para se propagar pela internet. Pode levar de alguns minutos a 48 horas, dependendo do seu provedor de DNS e das configurações de TTL.",
|
||||
"resourcePortRequired": "Número da porta é obrigatório para recursos não-HTTP",
|
||||
"resourcePortNotAllowed": "Número da porta não deve ser definido para recursos HTTP",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Concordo com",
|
||||
"termsOfService": "os termos de serviço",
|
||||
"and": "e",
|
||||
"privacyPolicy": "política de privacidade"
|
||||
},
|
||||
"siteRequired": "Site é obrigatório.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Use Olm para conectividade do cliente",
|
||||
"errorCreatingClient": "Erro ao criar cliente",
|
||||
"clientDefaultsNotFound": "Padrões do cliente não encontrados",
|
||||
"createClient": "Criar Cliente",
|
||||
"createClientDescription": "Crie um novo cliente para conectar aos seus sites",
|
||||
"seeAllClients": "Ver Todos os Clientes",
|
||||
"clientInformation": "Informações do Cliente",
|
||||
"clientNamePlaceholder": "Nome do cliente",
|
||||
"address": "Endereço",
|
||||
"subnetPlaceholder": "Sub-rede",
|
||||
"addressDescription": "O endereço que este cliente usará para conectividade",
|
||||
"selectSites": "Selecionar sites",
|
||||
"sitesDescription": "O cliente terá conectividade com os sites selecionados",
|
||||
"clientInstallOlm": "Instalar Olm",
|
||||
"clientInstallOlmDescription": "Execute o Olm em seu sistema",
|
||||
"clientOlmCredentials": "Credenciais Olm",
|
||||
"clientOlmCredentialsDescription": "É assim que Olm se autenticará com o servidor",
|
||||
"olmEndpoint": "Endpoint Olm",
|
||||
"olmId": "ID Olm",
|
||||
"olmSecretKey": "Chave Secreta Olm",
|
||||
"clientCredentialsSave": "Salve suas Credenciais",
|
||||
"clientCredentialsSaveDescription": "Você só poderá ver isto uma vez. Certifique-se de copiá-las para um local seguro.",
|
||||
"generalSettingsDescription": "Configure as configurações gerais para este cliente",
|
||||
"clientUpdated": "Cliente atualizado",
|
||||
"clientUpdatedDescription": "O cliente foi atualizado.",
|
||||
"clientUpdateFailed": "Falha ao atualizar cliente",
|
||||
"clientUpdateError": "Ocorreu um erro ao atualizar o cliente.",
|
||||
"sitesFetchFailed": "Falha ao buscar sites",
|
||||
"sitesFetchError": "Ocorreu um erro ao buscar sites.",
|
||||
"olmErrorFetchReleases": "Ocorreu um erro ao buscar lançamentos do Olm.",
|
||||
"olmErrorFetchLatest": "Ocorreu um erro ao buscar o lançamento mais recente do Olm.",
|
||||
"remoteSubnets": "Sub-redes Remotas",
|
||||
"enterCidrRange": "Insira o intervalo CIDR",
|
||||
"remoteSubnetsDescription": "Adicionar intervalos CIDR que podem ser acessados deste site remotamente usando clientes. Use um formato como 10.0.0.0/24. Isso SOMENTE se aplica à conectividade do cliente VPN.",
|
||||
"resourceEnableProxy": "Ativar Proxy Público",
|
||||
"resourceEnableProxyDescription": "Permite proxy público para este recurso. Isso permite o acesso ao recurso de fora da rede através da nuvem em uma porta aberta. Requer configuração do Traefik.",
|
||||
"externalProxyEnabled": "Proxy Externo Habilitado",
|
||||
"addNewTarget": "Adicionar Novo Alvo",
|
||||
"targetsList": "Lista de Alvos",
|
||||
"targetErrorDuplicateTargetFound": "Alvo duplicado encontrado",
|
||||
"httpMethod": "Método HTTP",
|
||||
"selectHttpMethod": "Selecionar método HTTP",
|
||||
"domainPickerSubdomainLabel": "Subdomínio",
|
||||
"domainPickerBaseDomainLabel": "Domínio Base",
|
||||
"domainPickerSearchDomains": "Buscar domínios...",
|
||||
"domainPickerNoDomainsFound": "Nenhum domínio encontrado",
|
||||
"domainPickerLoadingDomains": "Carregando domínios...",
|
||||
"domainPickerSelectBaseDomain": "Selecione o domínio base...",
|
||||
"domainPickerNotAvailableForCname": "Não disponível para domínios CNAME",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Digite um subdomínio ou deixe em branco para usar o domínio base.",
|
||||
"domainPickerEnterSubdomainToSearch": "Digite um subdomínio para buscar e selecionar entre os domínios gratuitos disponíveis.",
|
||||
"domainPickerFreeDomains": "Domínios Gratuitos",
|
||||
"domainPickerSearchForAvailableDomains": "Pesquise por domínios disponíveis",
|
||||
"resourceDomain": "Domínio",
|
||||
"resourceEditDomain": "Editar Domínio",
|
||||
"siteName": "Nome do Site",
|
||||
"proxyPort": "Porta",
|
||||
"resourcesTableProxyResources": "Recursos de Proxy",
|
||||
"resourcesTableClientResources": "Recursos do Cliente",
|
||||
"resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.",
|
||||
"resourcesTableDestination": "Destino",
|
||||
"resourcesTableTheseResourcesForUseWith": "Esses recursos são para uso com",
|
||||
"resourcesTableClients": "Clientes",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "e são acessíveis apenas internamente quando conectados com um cliente.",
|
||||
"editInternalResourceDialogEditClientResource": "Editar Recurso do Cliente",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "Atualize as propriedades do recurso e a configuração do alvo para {resourceName}.",
|
||||
"editInternalResourceDialogResourceProperties": "Propriedades do Recurso",
|
||||
"editInternalResourceDialogName": "Nome",
|
||||
"editInternalResourceDialogProtocol": "Protocolo",
|
||||
"editInternalResourceDialogSitePort": "Porta do Site",
|
||||
"editInternalResourceDialogTargetConfiguration": "Configuração do Alvo",
|
||||
"editInternalResourceDialogCancel": "Cancelar",
|
||||
"editInternalResourceDialogSaveResource": "Salvar Recurso",
|
||||
"editInternalResourceDialogSuccess": "Sucesso",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno atualizado com sucesso",
|
||||
"editInternalResourceDialogError": "Erro",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso interno",
|
||||
"editInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||
"editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||
"editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
|
||||
"editInternalResourceDialogProxyPortMax": "Porta de proxy deve ser inferior a 65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Formato de endereço IP inválido",
|
||||
"editInternalResourceDialogDestinationPortMin": "Porta de destino deve ser pelo menos 1",
|
||||
"editInternalResourceDialogDestinationPortMax": "Porta de destino deve ser inferior a 65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Nenhum Site Disponível",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Você precisa ter pelo menos um site Newt com uma sub-rede configurada para criar recursos internos.",
|
||||
"createInternalResourceDialogClose": "Fechar",
|
||||
"createInternalResourceDialogCreateClientResource": "Criar Recurso do Cliente",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Crie um novo recurso que estará acessível aos clientes conectados ao site selecionado.",
|
||||
"createInternalResourceDialogResourceProperties": "Propriedades do Recurso",
|
||||
"createInternalResourceDialogName": "Nome",
|
||||
"createInternalResourceDialogSite": "Site",
|
||||
"createInternalResourceDialogSelectSite": "Selecionar site...",
|
||||
"createInternalResourceDialogSearchSites": "Procurar sites...",
|
||||
"createInternalResourceDialogNoSitesFound": "Nenhum site encontrado.",
|
||||
"createInternalResourceDialogProtocol": "Protocolo",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Porta do Site",
|
||||
"createInternalResourceDialogSitePortDescription": "Use esta porta para acessar o recurso no site quando conectado com um cliente.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Configuração do Alvo",
|
||||
"createInternalResourceDialogDestinationIPDescription": "O IP ou endereço do hostname do recurso na rede do site.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "A porta no IP de destino onde o recurso está acessível.",
|
||||
"createInternalResourceDialogCancel": "Cancelar",
|
||||
"createInternalResourceDialogCreateResource": "Criar Recurso",
|
||||
"createInternalResourceDialogSuccess": "Sucesso",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno criado com sucesso",
|
||||
"createInternalResourceDialogError": "Erro",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso interno",
|
||||
"createInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||
"createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site",
|
||||
"createInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
|
||||
"createInternalResourceDialogProxyPortMax": "Porta de proxy deve ser inferior a 65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Formato de endereço IP inválido",
|
||||
"createInternalResourceDialogDestinationPortMin": "Porta de destino deve ser pelo menos 1",
|
||||
"createInternalResourceDialogDestinationPortMax": "Porta de destino deve ser inferior a 65536",
|
||||
"siteConfiguration": "Configuração",
|
||||
"siteAcceptClientConnections": "Aceitar Conexões de Clientes",
|
||||
"siteAcceptClientConnectionsDescription": "Permitir que outros dispositivos se conectem através desta instância Newt como um gateway usando clientes.",
|
||||
"siteAddress": "Endereço do Site",
|
||||
"siteAddressDescription": "Especificar o endereço IP do host para que os clientes se conectem. Este é o endereço interno do site na rede Pangolin para os clientes endereçarem. Deve estar dentro da sub-rede da Organização.",
|
||||
"autoLoginExternalIdp": "Login Automático com IDP Externo",
|
||||
"autoLoginExternalIdpDescription": "Redirecionar imediatamente o usuário para o IDP externo para autenticação.",
|
||||
"selectIdp": "Selecionar IDP",
|
||||
"selectIdpPlaceholder": "Escolher um IDP...",
|
||||
"selectIdpRequired": "Por favor, selecione um IDP quando o login automático estiver ativado.",
|
||||
"autoLoginTitle": "Redirecionando",
|
||||
"autoLoginDescription": "Redirecionando você para o provedor de identidade externo para autenticação.",
|
||||
"autoLoginProcessing": "Preparando autenticação...",
|
||||
"autoLoginRedirecting": "Redirecionando para login...",
|
||||
"autoLoginError": "Erro de Login Automático",
|
||||
"autoLoginErrorNoRedirectUrl": "Nenhum URL de redirecionamento recebido do provedor de identidade.",
|
||||
"autoLoginErrorGeneratingUrl": "Falha ao gerar URL de autenticação.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Gerenciado Auto-Hospedado",
|
||||
"description": "Servidor Pangolin auto-hospedado mais confiável e com baixa manutenção com sinos extras e assobiamentos",
|
||||
"introTitle": "Pangolin Auto-Hospedado Gerenciado",
|
||||
"introDescription": "é uma opção de implantação projetada para pessoas que querem simplicidade e confiança adicional, mantendo os seus dados privados e auto-hospedados.",
|
||||
"introDetail": "Com esta opção, você ainda roda seu próprio nó Pangolin — seus túneis, terminação SSL e tráfego todos permanecem no seu servidor. A diferença é que a gestão e a monitorização são geridos através do nosso painel de nuvem, que desbloqueia vários benefícios:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Operações simples",
|
||||
"description": "Não é necessário executar o seu próprio servidor de e-mail ou configurar um alerta complexo. Você receberá fora de caixa verificações de saúde e alertas de tempo de inatividade."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Atualizações automáticas",
|
||||
"description": "O painel em nuvem evolui rapidamente, para que você obtenha novos recursos e correções de bugs sem ter de puxar manualmente novos contêineres toda vez."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Menos manutenção",
|
||||
"description": "Sem migrações, backups ou infraestrutura extra para gerenciar. Lidamos com isso na nuvem."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Falha na nuvem",
|
||||
"description": "Se o seu nó descer, seus túneis podem falhar temporariamente nos nossos pontos de presença na nuvem até que você o traga online."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Alta disponibilidade (Ppos)",
|
||||
"description": "Você também pode anexar vários nós à sua conta para um melhor desempenho."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Aprimoramentos futuros",
|
||||
"description": "Estamos planejando adicionar mais análises, alertas e ferramentas de gerenciamento para tornar sua implantação ainda mais robusta."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Saiba mais sobre a opção Hospedagem Auto-Gerenciada no nosso",
|
||||
"documentation": "documentação"
|
||||
},
|
||||
"convertButton": "Converter este nó para Auto-Hospedado Gerenciado"
|
||||
},
|
||||
"internationaldomaindetected": "Domínio Internacional Detectado",
|
||||
"willbestoredas": "Será armazenado como:",
|
||||
"idpGoogleDescription": "Provedor Google OAuth2/OIDC",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "Cabeçalhos Personalizados",
|
||||
"headersValidationError": "Cabeçalhos devem estar no formato: Nome do Cabeçalho: valor.",
|
||||
"domainPickerProvidedDomain": "Domínio fornecido",
|
||||
"domainPickerFreeProvidedDomain": "Domínio fornecido grátis",
|
||||
"domainPickerVerified": "Verificada",
|
||||
"domainPickerUnverified": "Não verificado",
|
||||
"domainPickerInvalidSubdomainStructure": "Este subdomínio contém caracteres ou estrutura inválidos. Ele será eliminado automaticamente quando você salvar.",
|
||||
"domainPickerError": "ERRO",
|
||||
"domainPickerErrorLoadDomains": "Falha ao carregar domínios da organização",
|
||||
"domainPickerErrorCheckAvailability": "Não foi possível verificar a disponibilidade do domínio",
|
||||
"domainPickerInvalidSubdomain": "Subdomínio inválido",
|
||||
"domainPickerInvalidSubdomainRemoved": "A entrada \"{sub}\" foi removida porque ela não é válida.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" não pôde ser válido para {domain}.",
|
||||
"domainPickerSubdomainSanitized": "Subdomínio banalizado",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" foi corrigido para \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "Editar arquivo: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Editar arquivo: docker-compose.yml"
|
||||
}
|
||||
|
||||
1523
messages/ru-RU.json
Normal file
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "Şu anda herhangi bir organizasyona üye değilsiniz. Başlamak için bir organizasyon oluşturun.",
|
||||
"componentsErrorNoMember": "Şu anda herhangi bir organizasyona üye değilsiniz.",
|
||||
"welcome": "Pangolin'e hoş geldiniz",
|
||||
"welcomeTo": "Hoş geldiniz",
|
||||
"componentsCreateOrg": "Bir Organizasyon Oluşturun",
|
||||
"componentsMember": "You're a member of {count, plural, =0 {no organization} =1 {one organization} other {# organizations}}.",
|
||||
"componentsMember": "{count, plural, =0 {hiçbir organizasyon} one {bir organizasyon} other {# organizasyon}} üyesisiniz.",
|
||||
"componentsInvalidKey": "Geçersiz veya süresi dolmuş lisans anahtarları tespit edildi. Tüm özellikleri kullanmaya devam etmek için lisans koşullarına uyun.",
|
||||
"dismiss": "Kapat",
|
||||
"componentsLicenseViolation": "Lisans İhlali: Bu sunucu, lisanslı sınırı olan {maxSites} sitesini aşarak {usedSites} site kullanmaktadır. Tüm özellikleri kullanmaya devam etmek için lisans koşullarına uyun.",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "Site oluşturulurken hata",
|
||||
"siteErrorCreateKeyPair": "Anahtar çifti veya site varsayılanları bulunamadı",
|
||||
"siteErrorCreateDefaults": "Site varsayılanları bulunamadı",
|
||||
"siteNameDescription": "Bu, site için görünen addır.",
|
||||
"method": "Yöntem",
|
||||
"siteMethodDescription": "Bağlantıları nasıl açığa çıkaracağınız budur.",
|
||||
"siteLearnNewt": "Newt'i sisteminize nasıl kuracağınızı öğrenin",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "Ağınıza giriş noktası oluşturmanın en kolay yolu. Ekstra kurulum gerekmez.",
|
||||
"siteWg": "Temel WireGuard",
|
||||
"siteWgDescription": "Bir tünel oluşturmak için herhangi bir WireGuard istemcisi kullanın. Manuel NAT kurulumu gereklidir.",
|
||||
"siteWgDescriptionSaas": "Bir tünel oluşturmak için herhangi bir WireGuard istemcisi kullanın. Manuel NAT kurulumu gereklidir. YALNIZCA SELF HOSTED DÜĞÜMLERDE ÇALIŞIR",
|
||||
"siteLocalDescription": "Yalnızca yerel kaynaklar. Tünelleme yok.",
|
||||
"siteLocalDescriptionSaas": "Yalnızca yerel kaynaklar. Tünel yok. YALNIZCA SELF HOSTED DÜĞÜMLERDE ÇALIŞIR",
|
||||
"siteSeeAll": "Tüm Siteleri Gör",
|
||||
"siteTunnelDescription": "Sitenize nasıl bağlanmak istediğinizi belirleyin",
|
||||
"siteNewtCredentials": "Newt Kimlik Bilgileri",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "Site seç",
|
||||
"siteSearch": "Site ara",
|
||||
"siteNotFound": "Herhangi bir site bulunamadı.",
|
||||
"siteSelectionDescription": "Bu site, kaynağa bağlanabilirliği sağlayacaktır.",
|
||||
"siteSelectionDescription": "Bu site hedefe bağlantı sağlayacaktır.",
|
||||
"resourceType": "Kaynak Türü",
|
||||
"resourceTypeDescription": "Kaynağınıza nasıl erişmek istediğinizi belirleyin",
|
||||
"resourceHTTPSSettings": "HTTPS Ayarları",
|
||||
@@ -197,15 +199,18 @@
|
||||
"general": "Genel",
|
||||
"generalSettings": "Genel Ayarlar",
|
||||
"proxy": "Vekil Sunucu",
|
||||
"internal": "Dahili",
|
||||
"rules": "Kurallar",
|
||||
"resourceSettingDescription": "Kaynağınızdaki ayarları yapılandırın",
|
||||
"resourceSetting": "{resourceName} Ayarları",
|
||||
"alwaysAllow": "Her Zaman İzin Ver",
|
||||
"alwaysDeny": "Her Zaman Reddet",
|
||||
"passToAuth": "Kimlik Doğrulamasına Geç",
|
||||
"orgSettingsDescription": "Organizasyonunuzun genel ayarlarını yapılandırın",
|
||||
"orgGeneralSettings": "Organizasyon Ayarları",
|
||||
"orgGeneralSettingsDescription": "Organizasyon detaylarınızı ve yapılandırmanızı yönetin",
|
||||
"saveGeneralSettings": "Genel Ayarları Kaydet",
|
||||
"saveSettings": "Ayarları Kaydet",
|
||||
"orgDangerZone": "Tehlike Alanı",
|
||||
"orgDangerZoneDescription": "Bu organizasyonu sildikten sonra geri dönüş yoktur. Emin olun.",
|
||||
"orgDelete": "Organizasyonu Sil",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "Hafta",
|
||||
"months": "Ay",
|
||||
"years": "Yıl",
|
||||
"day": "{count, plural, =1 {# day} other {# days}}",
|
||||
"day": "{count, plural, one {# gün} other {# gün}}",
|
||||
"apiKeysTitle": "API Anahtar Bilgilendirmesi",
|
||||
"apiKeysConfirmCopy2": "API anahtarını kopyaladığınızı onaylamanız gerekmektedir.",
|
||||
"apiKeysErrorCreate": "API anahtarı oluşturulurken hata",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "Lisans Satın Al",
|
||||
"licensePurchaseSites": "Ek Siteler Satın Al",
|
||||
"licenseSitesUsedMax": "{usedSites} / {maxSites} siteleri kullanıldı",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# site} =1 {# site} other {# site}} sistemde bulunmaktadır.",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# site} one {# site} other {# site}} sistemde bulunmaktadır.",
|
||||
"licensePurchaseDescription": "{selectedMode, select, license {Lisans satın almak için kaç site istediğinizi seçin. Daha sonra daha fazla site ekleyebilirsiniz.} other {mevcut lisansınıza kaç site ekleneceğini seçin.}}",
|
||||
"licenseFee": "Lisans ücreti",
|
||||
"licensePriceSite": "Site başına fiyat",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "Rol seçin",
|
||||
"inviteEmailSentDescription": "Kullanıcıya erişim bağlantısı ile bir e-posta gönderildi. Daveti kabul etmek için bağlantıya erişmelidirler.",
|
||||
"inviteSentDescription": "Kullanıcı davet edilmiştir. Daveti kabul etmek için aşağıdaki bağlantıya erişmelidirler.",
|
||||
"inviteExpiresIn": "The invite will expire in {days, plural, =1 {# day} other {# days}}.",
|
||||
"inviteExpiresIn": "Davetiye {days, plural, one {# gün} other {# gün}} içinde sona erecektir.",
|
||||
"idpTitle": "General Information",
|
||||
"idpSelect": "Dış kullanıcı için kimlik sağlayıcıyı seçin",
|
||||
"idpNotConfigured": "Herhangi bir kimlik sağlayıcı yapılandırılmamış. Harici kullanıcılar oluşturulmadan önce lütfen bir kimlik sağlayıcı yapılandırın.",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "Kullanıcı role eklenirken bir hata oluştu.",
|
||||
"userSaved": "Kullanıcı kaydedildi",
|
||||
"userSavedDescription": "Kullanıcı güncellenmiştir.",
|
||||
"autoProvisioned": "Otomatik Sağlandı",
|
||||
"autoProvisionedDescription": "Bu kullanıcının kimlik sağlayıcısı tarafından otomatik olarak yönetilmesine izin ver",
|
||||
"accessControlsDescription": "Bu kullanıcının organizasyonda neleri erişebileceğini ve yapabileceğini yönetin",
|
||||
"accessControlsSubmit": "Erişim Kontrollerini Kaydet",
|
||||
"roles": "Roller",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "SNI için kullanılacak TLS Sunucu Adı'",
|
||||
"targetTlsSubmit": "Ayarları Kaydet",
|
||||
"targets": "Hedefler Konfigürasyonu",
|
||||
"targetsDescription": "Trafiği hizmetlerinize yönlendirmek için hedefleri ayarlayın",
|
||||
"targetsDescription": "Trafiği arka uç hizmetlerinize yönlendirmek için hedefleri ayarlayın",
|
||||
"targetStickySessions": "Yapışkan Oturumları Etkinleştir",
|
||||
"targetStickySessionsDescription": "Bağlantıları oturum süresince aynı arka uç hedef üzerinde tutun.",
|
||||
"methodSelect": "Yöntemi Seç",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "Geçersiz IP adresi formatı",
|
||||
"ipAddressErrorInvalidOctet": "Geçersiz IP adresi okteti",
|
||||
"path": "Yol",
|
||||
"matchPath": "Yol Eşleştir",
|
||||
"ipAddressRange": "IP Aralığı",
|
||||
"rulesErrorFetch": "Kurallar alınamadı",
|
||||
"rulesErrorFetchDescription": "Kurallar alınırken bir hata oluştu",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "Aksiyonlar",
|
||||
"rulesActionAlwaysAllow": "Her Zaman İzin Ver: Tüm kimlik doğrulama yöntemlerini atlayın",
|
||||
"rulesActionAlwaysDeny": "Her Zaman Reddedin: Tüm istekleri engelleyin; kimlik doğrulaması yapılamaz",
|
||||
"rulesActionPassToAuth": "Kimlik Doğrulamasına Geç: Kimlik doğrulama yöntemlerinin denenmesine izin ver",
|
||||
"rulesMatchCriteria": "Eşleşme Kriterleri",
|
||||
"rulesMatchCriteriaIpAddress": "Belirli bir IP adresi ile eşleşme",
|
||||
"rulesMatchCriteriaIpAddressRange": "CIDR gösteriminde bir IP adresi aralığı ile eşleşme",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "PIN kesinlikle 6 haneli olmalıdır",
|
||||
"pincodeRequirementsChars": "PIN sadece numaralardan oluşmalıdır",
|
||||
"passwordRequirementsLength": "Şifre en az 1 karakter uzunluğunda olmalıdır",
|
||||
"passwordRequirementsTitle": "Şifre gereksinimleri:",
|
||||
"passwordRequirementLength": "En az 8 karakter uzunluğunda",
|
||||
"passwordRequirementUppercase": "En az bir büyük harf",
|
||||
"passwordRequirementLowercase": "En az bir küçük harf",
|
||||
"passwordRequirementNumber": "En az bir sayı",
|
||||
"passwordRequirementSpecial": "En az bir özel karakter",
|
||||
"passwordRequirementsMet": "✓ Şifre tüm gereksinimleri karşılıyor",
|
||||
"passwordStrength": "Şifre gücü",
|
||||
"passwordStrengthWeak": "Zayıf",
|
||||
"passwordStrengthMedium": "Orta",
|
||||
"passwordStrengthStrong": "Güçlü",
|
||||
"passwordRequirements": "Gereksinimler:",
|
||||
"passwordRequirementLengthText": "8+ karakter",
|
||||
"passwordRequirementUppercaseText": "Büyük harf (A-Z)",
|
||||
"passwordRequirementLowercaseText": "Küçük harf (a-z)",
|
||||
"passwordRequirementNumberText": "Sayı (0-9)",
|
||||
"passwordRequirementSpecialText": "Özel karakter (!@#$%...)",
|
||||
"passwordsDoNotMatch": "Parolalar eşleşmiyor",
|
||||
"otpEmailRequirementsLength": "OTP en az 1 karakter uzunluğunda olmalıdır",
|
||||
"otpEmailSent": "OTP Gönderildi",
|
||||
"otpEmailSentDescription": "E-posta adresinize bir OTP gönderildi",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "Bağlandı",
|
||||
"idpErrorConnectingTo": "{name} ile bağlantı kurarken bir sorun meydana geldi. Lütfen yöneticiye danışın.",
|
||||
"idpErrorNotFound": "IdP bulunamadı",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "Geçersiz Davet",
|
||||
"inviteInvalidDescription": "Davet bağlantısı geçersiz.",
|
||||
"inviteErrorWrongUser": "Davet bu kullanıcı için değil",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "Çıkış yaparken hata",
|
||||
"signingAs": "Olarak giriş yapıldı",
|
||||
"serverAdmin": "Sunucu Yöneticisi",
|
||||
"managedSelfhosted": "Yönetilen Self-Hosted",
|
||||
"otpEnable": "İki faktörlü özelliğini etkinleştir",
|
||||
"otpDisable": "İki faktörlü özelliğini devre dışı bırak",
|
||||
"logout": "Çıkış Yap",
|
||||
"licenseTierProfessionalRequired": "Profesyonel Sürüme Gereklidir",
|
||||
"licenseTierProfessionalRequiredDescription": "Bu özellik yalnızca Professional Edition'da kullanılabilir.",
|
||||
"actionGetOrg": "Kuruluşu Al",
|
||||
"updateOrgUser": "Organizasyon Kullanıcısını Güncelle",
|
||||
"createOrgUser": "Organizasyon Kullanıcısı Oluştur",
|
||||
"actionUpdateOrg": "Kuruluşu Güncelle",
|
||||
"actionUpdateUser": "Kullanıcıyı Güncelle",
|
||||
"actionGetUser": "Kullanıcıyı Getir",
|
||||
"actionGetOrgUser": "Kuruluş Kullanıcısını Al",
|
||||
"actionListOrgDomains": "Kuruluş Alan Adlarını Listele",
|
||||
"actionCreateSite": "Site Oluştur",
|
||||
"actionDeleteSite": "Siteyi Sil",
|
||||
"actionGetSite": "Siteyi Al",
|
||||
"actionListSites": "Siteleri Listele",
|
||||
"actionApplyBlueprint": "Planı Uygula",
|
||||
"setupToken": "Kurulum Simgesi",
|
||||
"setupTokenDescription": "Sunucu konsolundan kurulum simgesini girin.",
|
||||
"setupTokenRequired": "Kurulum simgesi gerekli",
|
||||
"actionUpdateSite": "Siteyi Güncelle",
|
||||
"actionListSiteRoles": "İzin Verilen Site Rolleri Listele",
|
||||
"actionCreateResource": "Kaynak Oluştur",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "Kimlik Sağlayıcı Organizasyon Politikasını Sil",
|
||||
"actionListIdpOrgs": "Kimlik Sağlayıcı Organizasyonları Listele",
|
||||
"actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle",
|
||||
"actionCreateClient": "Müşteri Oluştur",
|
||||
"actionDeleteClient": "Müşteri Sil",
|
||||
"actionUpdateClient": "Müşteri Güncelle",
|
||||
"actionListClients": "Müşterileri Listele",
|
||||
"actionGetClient": "Müşteriyi Al",
|
||||
"actionCreateSiteResource": "Site Kaynağı Oluştur",
|
||||
"actionDeleteSiteResource": "Site Kaynağını Sil",
|
||||
"actionGetSiteResource": "Site Kaynağını Al",
|
||||
"actionListSiteResources": "Site Kaynaklarını Listele",
|
||||
"actionUpdateSiteResource": "Site Kaynağını Güncelle",
|
||||
"actionListInvitations": "Davetiyeleri Listele",
|
||||
"noneSelected": "Hiçbiri seçili değil",
|
||||
"orgNotFound2": "Hiçbir organizasyon bulunamadı.",
|
||||
"searchProgress": "Ara...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "Tüm Kullanıcılar",
|
||||
"sidebarIdentityProviders": "Kimlik Sağlayıcılar",
|
||||
"sidebarLicense": "Lisans",
|
||||
"enableDockerSocket": "Docker Soketi Etkinleştir",
|
||||
"enableDockerSocketDescription": "Konteyner bilgilerini doldurmak için Docker Socket keşfini etkinleştirin. Socket yolu Newt'e sağlanmalıdır.",
|
||||
"sidebarClients": "Müşteriler (Beta)",
|
||||
"sidebarDomains": "Alan Adları",
|
||||
"enableDockerSocket": "Docker Soketini Etkinleştir",
|
||||
"enableDockerSocketDescription": "Plan etiketleri için Docker Socket etiket toplamasını etkinleştirin. Newt'e soket yolu sağlanmalıdır.",
|
||||
"enableDockerSocketLink": "Daha fazla bilgi",
|
||||
"viewDockerContainers": "Docker Konteynerlerini Görüntüle",
|
||||
"containersIn": "{siteName} içindeki konteynerler",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "Ağlar",
|
||||
"containerHostnameIp": "Ana Makine/IP",
|
||||
"containerLabels": "Etiketler",
|
||||
"containerLabelsCount": "{count} etiket{s,plural,one{} other{ler}}",
|
||||
"containerLabelsCount": "{count, plural, one {# etiket} other {# etiketler}}",
|
||||
"containerLabelsTitle": "Konteyner Etiketleri",
|
||||
"containerLabelEmpty": "<boş>",
|
||||
"containerPorts": "Bağlantı Noktaları",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "Durdurulmuş konteynerleri göster",
|
||||
"noContainersFound": "Konteyner bulunamadı. Docker konteynerlerinin çalıştığından emin olun.",
|
||||
"searchContainersPlaceholder": "{count} konteyner arasında arama yapın...",
|
||||
"searchResultsCount": "{count} sonuç{s,plural,one{} other{lar}}",
|
||||
"searchResultsCount": "{count, plural, one {# sonuç} other {# sonuçlar}}",
|
||||
"filters": "Filtreler",
|
||||
"filterOptions": "Filtre Seçenekleri",
|
||||
"filterPorts": "Bağlantı Noktaları",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "koyu",
|
||||
"system": "sistem",
|
||||
"theme": "Tema",
|
||||
"subnetRequired": "Alt ağ gereklidir",
|
||||
"initialSetupTitle": "İlk Sunucu Kurulumu",
|
||||
"initialSetupDescription": "İlk sunucu yönetici hesabını oluşturun. Yalnızca bir sunucu yöneticisi olabilir. Bu kimlik bilgilerini daha sonra her zaman değiştirebilirsiniz.",
|
||||
"createAdminAccount": "Yönetici Hesabı Oluştur",
|
||||
"setupErrorCreateAdmin": "Sunucu yönetici hesabı oluşturulurken bir hata oluştu."
|
||||
"setupErrorCreateAdmin": "Sunucu yönetici hesabı oluşturulurken bir hata oluştu.",
|
||||
"certificateStatus": "Sertifika Durumu",
|
||||
"loading": "Yükleniyor",
|
||||
"restart": "Yeniden Başlat",
|
||||
"domains": "Alan Adları",
|
||||
"domainsDescription": "Organizasyonunuz için alan adlarını yönetin",
|
||||
"domainsSearch": "Alan adlarını ara...",
|
||||
"domainAdd": "Alan Adı Ekle",
|
||||
"domainAddDescription": "Organizasyonunuz için yeni bir alan adı kaydedin",
|
||||
"domainCreate": "Alan Adı Oluştur",
|
||||
"domainCreatedDescription": "Alan adı başarıyla oluşturuldu",
|
||||
"domainDeletedDescription": "Alan adı başarıyla silindi",
|
||||
"domainQuestionRemove": "{domain} alan adını hesabınızdan kaldırmak istediğinizden emin misiniz?",
|
||||
"domainMessageRemove": "Kaldırıldığında, alan adı hesabınızla ilişkilendirilmeyecek.",
|
||||
"domainMessageConfirm": "Onaylamak için lütfen aşağıya alan adını yazın.",
|
||||
"domainConfirmDelete": "Alan Adı Silinmesini Onayla",
|
||||
"domainDelete": "Alan Adını Sil",
|
||||
"domain": "Alan Adı",
|
||||
"selectDomainTypeNsName": "Alan Adı Delege Etme (NS)",
|
||||
"selectDomainTypeNsDescription": "Bu alan adı ve tüm alt alan adları. Tüm bir alan adı bölgesini kontrol etmek istediğinizde bunu kullanın.",
|
||||
"selectDomainTypeCnameName": "Tekil Alan Adı (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Sadece bu belirli alan adı. Bireysel alt alan adları veya belirli alan adı girişleri için bunu kullanın.",
|
||||
"selectDomainTypeWildcardName": "Wildcard Alan Adı",
|
||||
"selectDomainTypeWildcardDescription": "Bu domain ve alt alan adları.",
|
||||
"domainDelegation": "Tekil Alan Adı",
|
||||
"selectType": "Bir tür seçin",
|
||||
"actions": "İşlemler",
|
||||
"refresh": "Yenile",
|
||||
"refreshError": "Veriler yenilenemedi",
|
||||
"verified": "Doğrulandı",
|
||||
"pending": "Beklemede",
|
||||
"sidebarBilling": "Faturalama",
|
||||
"billing": "Faturalama",
|
||||
"orgBillingDescription": "Fatura bilgilerinizi ve aboneliklerinizi yönetin",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Barındırılan",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Hesap Kurulumunu Tamamla",
|
||||
"completeAccountSetupDescription": "Başlamak için şifrenizi ayarlayın",
|
||||
"accountSetupSent": "Bu e-posta adresine bir hesap kurulum kodu göndereceğiz.",
|
||||
"accountSetupCode": "Kurulum Kodu",
|
||||
"accountSetupCodeDescription": "Kurulum kodu için e-posta gelen kutunuzu kontrol edin.",
|
||||
"passwordCreate": "Parola Oluştur",
|
||||
"passwordCreateConfirm": "Şifreyi Onayla",
|
||||
"accountSetupSubmit": "Kurulum Kodunu Gönder",
|
||||
"completeSetup": "Kurulumu Tamamla",
|
||||
"accountSetupSuccess": "Hesap kurulumu tamamlandı! Pangolin'e hoş geldiniz!",
|
||||
"documentation": "Dokümantasyon",
|
||||
"saveAllSettings": "Tüm Ayarları Kaydet",
|
||||
"settingsUpdated": "Ayarlar güncellendi",
|
||||
"settingsUpdatedDescription": "Tüm ayarlar başarıyla güncellendi",
|
||||
"settingsErrorUpdate": "Ayarlar güncellenemedi",
|
||||
"settingsErrorUpdateDescription": "Ayarları güncellerken bir hata oluştu",
|
||||
"sidebarCollapse": "Daralt",
|
||||
"sidebarExpand": "Genişlet",
|
||||
"newtUpdateAvailable": "Güncelleme Mevcut",
|
||||
"newtUpdateAvailableInfo": "Newt'in yeni bir versiyonu mevcut. En iyi deneyim için lütfen en son sürüme güncelleyin.",
|
||||
"domainPickerEnterDomain": "Domain",
|
||||
"domainPickerPlaceholder": "myapp.example.com",
|
||||
"domainPickerDescription": "Mevcut seçenekleri görmek için kaynağın tam etki alanını girin.",
|
||||
"domainPickerDescriptionSaas": "Mevcut seçenekleri görmek için tam etki alanı, alt etki alanı veya sadece bir isim girin",
|
||||
"domainPickerTabAll": "Tümü",
|
||||
"domainPickerTabOrganization": "Organizasyon",
|
||||
"domainPickerTabProvided": "Sağlanan",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "Kullanılabilirlik kontrol ediliyor...",
|
||||
"domainPickerNoMatchingDomains": "Eşleşen domain bulunamadı. Farklı bir domain deneyin veya organizasyonunuzun domain ayarlarını kontrol edin.",
|
||||
"domainPickerOrganizationDomains": "Organizasyon Alan Adları",
|
||||
"domainPickerProvidedDomains": "Sağlanan Alan Adları",
|
||||
"domainPickerSubdomain": "Alt Alan: {subdomain}",
|
||||
"domainPickerNamespace": "Ad Alanı: {namespace}",
|
||||
"domainPickerShowMore": "Daha Fazla Göster",
|
||||
"domainNotFound": "Alan Adı Bulunamadı",
|
||||
"domainNotFoundDescription": "Bu kaynak devre dışıdır çünkü alan adı sistemimizde artık mevcut değil. Bu kaynak için yeni bir alan adı belirleyin.",
|
||||
"failed": "Başarısız",
|
||||
"createNewOrgDescription": "Yeni bir organizasyon oluşturun",
|
||||
"organization": "Kuruluş",
|
||||
"port": "Bağlantı Noktası",
|
||||
"securityKeyManage": "Güvenlik Anahtarlarını Yönet",
|
||||
"securityKeyDescription": "Şifresiz kimlik doğrulama için güvenlik anahtarları ekleyin veya kaldırın",
|
||||
"securityKeyRegister": "Yeni Güvenlik Anahtarı Kaydet",
|
||||
"securityKeyList": "Güvenlik Anahtarlarınız",
|
||||
"securityKeyNone": "Henüz kayıtlı güvenlik anahtarı yok",
|
||||
"securityKeyNameRequired": "İsim gerekli",
|
||||
"securityKeyRemove": "Kaldır",
|
||||
"securityKeyLastUsed": "Son kullanım: {date}",
|
||||
"securityKeyNameLabel": "İsim",
|
||||
"securityKeyRegisterSuccess": "Güvenlik anahtarı başarıyla kaydedildi",
|
||||
"securityKeyRegisterError": "Güvenlik anahtarı kaydedilirken hata oluştu",
|
||||
"securityKeyRemoveSuccess": "Güvenlik anahtarı başarıyla kaldırıldı",
|
||||
"securityKeyRemoveError": "Güvenlik anahtarı kaldırılırken hata oluştu",
|
||||
"securityKeyLoadError": "Güvenlik anahtarları yüklenirken hata oluştu",
|
||||
"securityKeyLogin": "Güvenlik anahtarı ile devam edin",
|
||||
"securityKeyAuthError": "Güvenlik anahtarı ile kimlik doğrulama başarısız oldu",
|
||||
"securityKeyRecommendation": "Hesabınızdan kilitlenmediğinizden emin olmak için farklı bir cihazda başka bir güvenlik anahtarı kaydetmeyi düşünün.",
|
||||
"registering": "Kaydediliyor...",
|
||||
"securityKeyPrompt": "Lütfen güvenlik anahtarınızı kullanarak kimliğinizi doğrulayın. Güvenlik anahtarınızın bağlı ve hazır olduğundan emin olun.",
|
||||
"securityKeyBrowserNotSupported": "Tarayıcınız güvenlik anahtarlarını desteklemiyor. Lütfen Chrome, Firefox veya Safari gibi modern bir tarayıcı kullanın.",
|
||||
"securityKeyPermissionDenied": "Giriş yapmaya devam etmek için lütfen güvenlik anahtarınıza erişime izin verin.",
|
||||
"securityKeyRemovedTooQuickly": "Güvenlik anahtarınızın bağlantısını kesmeden önce oturum açma işlemi tamamlanana kadar bağlı kalmasını sağlayın.",
|
||||
"securityKeyNotSupported": "Güvenlik anahtarınız uyumlu olmayabilir. Lütfen farklı bir güvenlik anahtarı deneyin.",
|
||||
"securityKeyUnknownError": "Güvenlik anahtarınızı kullanırken bir sorun oluştu. Lütfen tekrar deneyin.",
|
||||
"twoFactorRequired": "Güvenlik anahtarını kaydetmek için iki faktörlü kimlik doğrulama gereklidir.",
|
||||
"twoFactor": "İki Faktörlü Kimlik Doğrulama",
|
||||
"adminEnabled2FaOnYourAccount": "Yöneticiniz {email} için iki faktörlü kimlik doğrulamayı etkinleştirdi. Devam etmek için kurulum işlemini tamamlayın.",
|
||||
"continueToApplication": "Uygulamaya Devam Et",
|
||||
"securityKeyAdd": "Güvenlik Anahtarı Ekle",
|
||||
"securityKeyRegisterTitle": "Yeni Güvenlik Anahtarı Kaydet",
|
||||
"securityKeyRegisterDescription": "Güvenlik anahtarınızı bağlayın ve tanımlamak için bir ad girin",
|
||||
"securityKeyTwoFactorRequired": "İki Faktörlü Kimlik Doğrulama Gereklidir",
|
||||
"securityKeyTwoFactorDescription": "Güvenlik anahtarını kaydetmek için lütfen iki faktörlü kimlik doğrulama kodunuzu girin",
|
||||
"securityKeyTwoFactorRemoveDescription": "Güvenlik anahtarını kaldırmak için lütfen iki faktörlü kimlik doğrulama kodunuzu girin",
|
||||
"securityKeyTwoFactorCode": "İki Faktörlü Kod",
|
||||
"securityKeyRemoveTitle": "Güvenlik Anahtarını Kaldır",
|
||||
"securityKeyRemoveDescription": "Güvenlik anahtarını \"{name}\" kaldırmak için şifrenizi girin",
|
||||
"securityKeyNoKeysRegistered": "Kayıtlı güvenlik anahtarı yok",
|
||||
"securityKeyNoKeysDescription": "Hesabınızın güvenliğini artırmak için bir güvenlik anahtarı ekleyin",
|
||||
"createDomainRequired": "Alan adı gereklidir",
|
||||
"createDomainAddDnsRecords": "DNS Kayıtlarını Ekle",
|
||||
"createDomainAddDnsRecordsDescription": "Kurulumu tamamlamak için alan sağlayıcınıza şu DNS kayıtlarını ekleyin.",
|
||||
"createDomainNsRecords": "NS Kayıtları",
|
||||
"createDomainRecord": "Kayıt",
|
||||
"createDomainType": "Tür:",
|
||||
"createDomainName": "Ad:",
|
||||
"createDomainValue": "Değer:",
|
||||
"createDomainCnameRecords": "CNAME Kayıtları",
|
||||
"createDomainARecords": "A Kayıtları",
|
||||
"createDomainRecordNumber": "Kayıt {number}",
|
||||
"createDomainTxtRecords": "TXT Kayıtları",
|
||||
"createDomainSaveTheseRecords": "Bu Kayıtları Kaydet",
|
||||
"createDomainSaveTheseRecordsDescription": "Bu DNS kayıtlarını kaydettiğinizden emin olun çünkü tekrar görmeyeceksiniz.",
|
||||
"createDomainDnsPropagation": "DNS Yayılması",
|
||||
"createDomainDnsPropagationDescription": "DNS değişikliklerinin internet genelinde yayılması zaman alabilir. DNS sağlayıcınız ve TTL ayarlarına bağlı olarak bu birkaç dakika ile 48 saat arasında değişebilir.",
|
||||
"resourcePortRequired": "HTTP dışı kaynaklar için bağlantı noktası numarası gereklidir",
|
||||
"resourcePortNotAllowed": "HTTP kaynakları için bağlantı noktası numarası ayarlanmamalı",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "Kabul ediyorum",
|
||||
"termsOfService": "hizmet şartları",
|
||||
"and": "ve",
|
||||
"privacyPolicy": "gizlilik politikası"
|
||||
},
|
||||
"siteRequired": "Site gerekli.",
|
||||
"olmTunnel": "Olm Tüneli",
|
||||
"olmTunnelDescription": "Müşteri bağlantıları için Olm kullanın",
|
||||
"errorCreatingClient": "Müşteri oluşturulurken hata oluştu",
|
||||
"clientDefaultsNotFound": "Müşteri varsayılanları bulunamadı",
|
||||
"createClient": "Müşteri Oluştur",
|
||||
"createClientDescription": "Sitelerinize bağlanmak için yeni bir müşteri oluşturun",
|
||||
"seeAllClients": "Tüm Müşterileri Gör",
|
||||
"clientInformation": "Müşteri Bilgileri",
|
||||
"clientNamePlaceholder": "Müşteri adı",
|
||||
"address": "Adres",
|
||||
"subnetPlaceholder": "Alt ağ",
|
||||
"addressDescription": "Bu müşteri için bağlantıda kullanılacak adres",
|
||||
"selectSites": "Siteleri seçin",
|
||||
"sitesDescription": "Müşteri seçilen sitelere bağlantı kuracaktır",
|
||||
"clientInstallOlm": "Olm Yükle",
|
||||
"clientInstallOlmDescription": "Sisteminizde Olm çalıştırın",
|
||||
"clientOlmCredentials": "Olm Kimlik Bilgileri",
|
||||
"clientOlmCredentialsDescription": "Bu, Olm'in sunucu ile kimlik doğrulaması yapacağı yöntemdir",
|
||||
"olmEndpoint": "Olm Uç Noktası",
|
||||
"olmId": "Olm Kimliği",
|
||||
"olmSecretKey": "Olm Gizli Anahtarı",
|
||||
"clientCredentialsSave": "Kimlik Bilgilerinizi Kaydedin",
|
||||
"clientCredentialsSaveDescription": "Bunu yalnızca bir kez görebileceksiniz. Güvenli bir yere kopyaladığınızdan emin olun.",
|
||||
"generalSettingsDescription": "Bu müşteri için genel ayarları yapılandırın",
|
||||
"clientUpdated": "Müşteri güncellendi",
|
||||
"clientUpdatedDescription": "Müşteri güncellenmiştir.",
|
||||
"clientUpdateFailed": "Müşteri güncellenemedi",
|
||||
"clientUpdateError": "Müşteri güncellenirken bir hata oluştu.",
|
||||
"sitesFetchFailed": "Siteler alınamadı",
|
||||
"sitesFetchError": "Siteler alınırken bir hata oluştu.",
|
||||
"olmErrorFetchReleases": "Olm yayınları alınırken bir hata oluştu.",
|
||||
"olmErrorFetchLatest": "En son Olm yayını alınırken bir hata oluştu.",
|
||||
"remoteSubnets": "Uzak Alt Ağlar",
|
||||
"enterCidrRange": "CIDR aralığını girin",
|
||||
"remoteSubnetsDescription": "Bu siteye uzaktan erişilebilen CIDR aralıklarını ekleyin. 10.0.0.0/24 formatını kullanın. Bu YALNIZCA VPN istemci bağlantıları için geçerlidir.",
|
||||
"resourceEnableProxy": "Genel Proxy'i Etkinleştir",
|
||||
"resourceEnableProxyDescription": "Bu kaynağa genel proxy erişimini etkinleştirin. Bu sayede ağ dışından açık bir port üzerinden kaynağa bulut aracılığıyla erişim sağlanır. Traefik yapılandırması gereklidir.",
|
||||
"externalProxyEnabled": "Dış Proxy Etkinleştirildi",
|
||||
"addNewTarget": "Yeni Hedef Ekle",
|
||||
"targetsList": "Hedefler Listesi",
|
||||
"targetErrorDuplicateTargetFound": "Yinelenen hedef bulundu",
|
||||
"httpMethod": "HTTP Yöntemi",
|
||||
"selectHttpMethod": "HTTP yöntemini seçin",
|
||||
"domainPickerSubdomainLabel": "Alt Alan Adı",
|
||||
"domainPickerBaseDomainLabel": "Temel Alan Adı",
|
||||
"domainPickerSearchDomains": "Alan adlarını ara...",
|
||||
"domainPickerNoDomainsFound": "Hiçbir alan adı bulunamadı",
|
||||
"domainPickerLoadingDomains": "Alan adları yükleniyor...",
|
||||
"domainPickerSelectBaseDomain": "Temel alan adını seçin...",
|
||||
"domainPickerNotAvailableForCname": "CNAME alan adları için kullanılabilir değil",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "Alt alan adını girin veya temel alan adını kullanmak için boş bırakın.",
|
||||
"domainPickerEnterSubdomainToSearch": "Mevcut ücretsiz alan adları arasından aramak ve seçmek için bir alt alan adı girin.",
|
||||
"domainPickerFreeDomains": "Ücretsiz Alan Adları",
|
||||
"domainPickerSearchForAvailableDomains": "Mevcut alan adlarını ara",
|
||||
"resourceDomain": "Alan Adı",
|
||||
"resourceEditDomain": "Alan Adını Düzenle",
|
||||
"siteName": "Site Adı",
|
||||
"proxyPort": "Bağlantı Noktası",
|
||||
"resourcesTableProxyResources": "Proxy Kaynaklar",
|
||||
"resourcesTableClientResources": "İstemci Kaynaklar",
|
||||
"resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.",
|
||||
"resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.",
|
||||
"resourcesTableDestination": "Hedef",
|
||||
"resourcesTableTheseResourcesForUseWith": "Bu kaynaklar ile kullanılmak için",
|
||||
"resourcesTableClients": "İstemciler",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "veyalnızca bir istemci ile bağlandığında dahili olarak erişilebilir.",
|
||||
"editInternalResourceDialogEditClientResource": "İstemci Kaynağı Düzenleyin",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "{resourceName} için kaynak özelliklerini ve hedef yapılandırmasını güncelleyin.",
|
||||
"editInternalResourceDialogResourceProperties": "Kaynak Özellikleri",
|
||||
"editInternalResourceDialogName": "Ad",
|
||||
"editInternalResourceDialogProtocol": "Protokol",
|
||||
"editInternalResourceDialogSitePort": "Site Bağlantı Noktası",
|
||||
"editInternalResourceDialogTargetConfiguration": "Hedef Yapılandırma",
|
||||
"editInternalResourceDialogCancel": "İptal",
|
||||
"editInternalResourceDialogSaveResource": "Kaynağı Kaydet",
|
||||
"editInternalResourceDialogSuccess": "Başarı",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Dahili kaynak başarıyla güncellendi",
|
||||
"editInternalResourceDialogError": "Hata",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Dahili kaynak güncellenemedi",
|
||||
"editInternalResourceDialogNameRequired": "Ad gerekli",
|
||||
"editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
|
||||
"editInternalResourceDialogProxyPortMax": "Proxy bağlantı noktası 65536'dan küçük olmalıdır",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "Geçersiz IP adresi formatı",
|
||||
"editInternalResourceDialogDestinationPortMin": "Hedef bağlantı noktası en az 1 olmalıdır",
|
||||
"editInternalResourceDialogDestinationPortMax": "Hedef bağlantı noktası 65536'dan küçük olmalıdır",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Site Bulunamadı",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Dahili kaynak oluşturmak için en az bir Newt sitesine ve alt ağa sahip olmalısınız.",
|
||||
"createInternalResourceDialogClose": "Kapat",
|
||||
"createInternalResourceDialogCreateClientResource": "İstemci Kaynağı Oluştur",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemciler için erişilebilir olacak yeni bir kaynak oluşturun.",
|
||||
"createInternalResourceDialogResourceProperties": "Kaynak Özellikleri",
|
||||
"createInternalResourceDialogName": "Ad",
|
||||
"createInternalResourceDialogSite": "Site",
|
||||
"createInternalResourceDialogSelectSite": "Site seç...",
|
||||
"createInternalResourceDialogSearchSites": "Siteleri ara...",
|
||||
"createInternalResourceDialogNoSitesFound": "Site bulunamadı.",
|
||||
"createInternalResourceDialogProtocol": "Protokol",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "Site Bağlantı Noktası",
|
||||
"createInternalResourceDialogSitePortDescription": "İstemci ile bağlanıldığında site üzerindeki kaynağa erişmek için bu bağlantı noktasını kullanın.",
|
||||
"createInternalResourceDialogTargetConfiguration": "Hedef Yapılandırma",
|
||||
"createInternalResourceDialogDestinationIPDescription": "Kaynağın site ağındaki IP veya ana bilgisayar adresi.",
|
||||
"createInternalResourceDialogDestinationPortDescription": "Kaynağa erişilebilecek hedef IP üzerindeki bağlantı noktası.",
|
||||
"createInternalResourceDialogCancel": "İptal",
|
||||
"createInternalResourceDialogCreateResource": "Kaynak Oluştur",
|
||||
"createInternalResourceDialogSuccess": "Başarı",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Dahili kaynak başarıyla oluşturuldu",
|
||||
"createInternalResourceDialogError": "Hata",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Dahili kaynak oluşturulamadı",
|
||||
"createInternalResourceDialogNameRequired": "Ad gerekli",
|
||||
"createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin",
|
||||
"createInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
|
||||
"createInternalResourceDialogProxyPortMax": "Proxy bağlantı noktası 65536'dan küçük olmalıdır",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "Geçersiz IP adresi formatı",
|
||||
"createInternalResourceDialogDestinationPortMin": "Hedef bağlantı noktası en az 1 olmalıdır",
|
||||
"createInternalResourceDialogDestinationPortMax": "Hedef bağlantı noktası 65536'dan küçük olmalıdır",
|
||||
"siteConfiguration": "Yapılandırma",
|
||||
"siteAcceptClientConnections": "İstemci Bağlantılarını Kabul Et",
|
||||
"siteAcceptClientConnectionsDescription": "Bu Newt örneğini bir geçit olarak kullanarak diğer cihazların bağlanmasına izin verin.",
|
||||
"siteAddress": "Site Adresi",
|
||||
"siteAddressDescription": "İstemcilerin bağlanması için hostun IP adresini belirtin. Bu, Pangolin ağındaki sitenin iç adresidir ve istemciler için atlas olmalıdır. Org alt ağına düşmelidir.",
|
||||
"autoLoginExternalIdp": "Harici IDP ile Otomatik Giriş",
|
||||
"autoLoginExternalIdpDescription": "Kullanıcıyı kimlik doğrulama için otomatik olarak harici IDP'ye yönlendirin.",
|
||||
"selectIdp": "IDP Seç",
|
||||
"selectIdpPlaceholder": "IDP seçin...",
|
||||
"selectIdpRequired": "Otomatik giriş etkinleştirildiğinde lütfen bir IDP seçin.",
|
||||
"autoLoginTitle": "Yönlendiriliyor",
|
||||
"autoLoginDescription": "Kimlik doğrulama için harici kimlik sağlayıcıya yönlendiriliyorsunuz.",
|
||||
"autoLoginProcessing": "Kimlik doğrulama hazırlanıyor...",
|
||||
"autoLoginRedirecting": "Girişe yönlendiriliyorsunuz...",
|
||||
"autoLoginError": "Otomatik Giriş Hatası",
|
||||
"autoLoginErrorNoRedirectUrl": "Kimlik sağlayıcıdan yönlendirme URL'si alınamadı.",
|
||||
"autoLoginErrorGeneratingUrl": "Kimlik doğrulama URL'si oluşturulamadı.",
|
||||
"managedSelfHosted": {
|
||||
"title": "Yönetilen Self-Hosted",
|
||||
"description": "Daha güvenilir ve düşük bakım gerektiren, ekstra özelliklere sahip kendi kendine barındırabileceğiniz Pangolin sunucusu",
|
||||
"introTitle": "Yönetilen Kendi Kendine Barındırılan Pangolin",
|
||||
"introDescription": "Bu, basitlik ve ekstra güvenilirlik arayan, ancak verilerini gizli tutmak ve kendi sunucularında barındırmak isteyen kişiler için tasarlanmış bir dağıtım seçeneğidir.",
|
||||
"introDetail": "Bu seçenekle, kendi Pangolin düğümünüzü çalıştırmaya devam edersiniz — tünelleriniz, SSL bitişiniz ve trafiğiniz tamamen sunucunuzda kalır. Fark, yönetim ve izlemeyi bulut panomuz üzerinden gerçekleştiririz, bu da bir dizi avantaj sağlar:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "Daha basit işlemler",
|
||||
"description": "Kendi e-posta sunucunuzu çalıştırmanıza veya karmaşık uyarılar kurmanıza gerek yok. Sağlık kontrolleri ve kesinti uyarılarını kutudan çıktığı gibi alırsınız."
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "Otomatik güncellemeler",
|
||||
"description": "Bulut panosu hızla gelişir, böylece her seferinde yeni konteynerler manuel olarak çekmeden yeni özellikler ve hata düzeltmeleri alırsınız."
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "Daha az bakım",
|
||||
"description": "Veritabanı geçişleri, yedeklemeler veya ekstra altyapı yönetimi yok. Biz bunu bulutta hallederiz."
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "Bulut yedekleme",
|
||||
"description": "Düğümünüz kapandığında, tünelleriniz geçici olarak bulut bağlantı noktalarımıza geçebilir, böylece tekrar çevrimiçi hale getirene kadar tünelleriniz kesintiye uğramaz."
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "Yüksek kullanılabilirlik (Bağlantı Noktaları)",
|
||||
"description": "Yedeklilik ve daha iyi performans için hesabınıza birden fazla düğüm bağlayabilirsiniz."
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "Gelecek iyileştirmeler",
|
||||
"description": "Dağıtımınızı daha sağlam hale getirmek amacıyla daha fazla analiz, uyarı ve yönetim aracı eklemeyi planlıyoruz."
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "Yönetilen Kendi Kendine Barındırılan seçeneği hakkında daha fazla bilgi edinin",
|
||||
"documentation": "dokümantasyon"
|
||||
},
|
||||
"convertButton": "Bu Düğümü Yönetilen Kendi Kendine Barındırma Dönüştürün"
|
||||
},
|
||||
"internationaldomaindetected": "Uluslararası Alan Adı Tespit Edildi",
|
||||
"willbestoredas": "Şu şekilde depolanacak:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC sağlayıcısı",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC sağlayıcısı",
|
||||
"customHeaders": "Özel Başlıklar",
|
||||
"headersValidationError": "Başlıklar şu formatta olmalıdır: Başlık-Adı: değer.",
|
||||
"domainPickerProvidedDomain": "Sağlanan Alan Adı",
|
||||
"domainPickerFreeProvidedDomain": "Ücretsiz Sağlanan Alan Adı",
|
||||
"domainPickerVerified": "Doğrulandı",
|
||||
"domainPickerUnverified": "Doğrulanmadı",
|
||||
"domainPickerInvalidSubdomainStructure": "Bu alt alan adı geçersiz karakterler veya yapı içeriyor. Kaydettiğinizde otomatik olarak temizlenecektir.",
|
||||
"domainPickerError": "Hata",
|
||||
"domainPickerErrorLoadDomains": "Organizasyon alan adları yüklenemedi",
|
||||
"domainPickerErrorCheckAvailability": "Alan adı kullanılabilirliği kontrol edilemedi",
|
||||
"domainPickerInvalidSubdomain": "Geçersiz alt alan adı",
|
||||
"domainPickerInvalidSubdomainRemoved": "Girdi \"{sub}\" geçersiz olduğu için kaldırıldı.",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" {domain} için geçerli yapılamadı.",
|
||||
"domainPickerSubdomainSanitized": "Alt alan adı temizlendi",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" \"{sanitized}\" olarak düzeltildi",
|
||||
"resourceAddEntrypointsEditFile": "Dosyayı düzenle: config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "Dosyayı düzenle: docker-compose.yml"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"componentsErrorNoMemberCreate": "您目前不是任何组织的成员。创建组织以开始操作。",
|
||||
"componentsErrorNoMember": "您目前不是任何组织的成员。",
|
||||
"welcome": "欢迎使用 Pangolin",
|
||||
"welcomeTo": "欢迎来到",
|
||||
"componentsCreateOrg": "创建组织",
|
||||
"componentsMember": "您属于 {count, plural, =0 {无组织} =1 {一个组织} other {# 个组织}}。",
|
||||
"componentsMember": "您属于{count, plural, =0 {没有组织} one {一个组织} other {# 个组织}}。",
|
||||
"componentsInvalidKey": "检测到无效或过期的许可证密钥。按照许可证条款操作以继续使用所有功能。",
|
||||
"dismiss": "忽略",
|
||||
"componentsLicenseViolation": "许可证超限:该服务器使用了 {usedSites} 个站点,已超过授权的 {maxSites} 个。请遵守许可证条款以继续使用全部功能。",
|
||||
@@ -58,7 +59,6 @@
|
||||
"siteErrorCreate": "创建站点出错",
|
||||
"siteErrorCreateKeyPair": "找不到密钥对或站点默认值",
|
||||
"siteErrorCreateDefaults": "未找到站点默认值",
|
||||
"siteNameDescription": "这是站点的显示名称。",
|
||||
"method": "方法",
|
||||
"siteMethodDescription": "这是您将如何显示连接。",
|
||||
"siteLearnNewt": "学习如何在您的系统上安装 Newt",
|
||||
@@ -94,7 +94,9 @@
|
||||
"siteNewtTunnelDescription": "最简单的方式来连接到您的网络。不需要任何额外设置。",
|
||||
"siteWg": "基本 WireGuard",
|
||||
"siteWgDescription": "使用任何 WireGuard 客户端来建立隧道。需要手动配置 NAT。",
|
||||
"siteWgDescriptionSaas": "使用任何WireGuard客户端建立隧道。需要手动配置NAT。仅适用于自托管节点。",
|
||||
"siteLocalDescription": "仅限本地资源。不需要隧道。",
|
||||
"siteLocalDescriptionSaas": "仅本地资源。无需隧道。仅适用于自托管节点。",
|
||||
"siteSeeAll": "查看所有站点",
|
||||
"siteTunnelDescription": "确定如何连接到您的网站",
|
||||
"siteNewtCredentials": "Newt 凭据",
|
||||
@@ -166,7 +168,7 @@
|
||||
"siteSelect": "选择站点",
|
||||
"siteSearch": "搜索站点",
|
||||
"siteNotFound": "未找到站点。",
|
||||
"siteSelectionDescription": "此站点将为资源提供连接。",
|
||||
"siteSelectionDescription": "此站点将为目标提供连接。",
|
||||
"resourceType": "资源类型",
|
||||
"resourceTypeDescription": "确定如何访问您的资源",
|
||||
"resourceHTTPSSettings": "HTTPS 设置",
|
||||
@@ -197,22 +199,25 @@
|
||||
"general": "概览",
|
||||
"generalSettings": "常规设置",
|
||||
"proxy": "代理服务器",
|
||||
"internal": "内部设置",
|
||||
"rules": "规则",
|
||||
"resourceSettingDescription": "配置您资源上的设置",
|
||||
"resourceSetting": "{resourceName} 设置",
|
||||
"alwaysAllow": "一律允许",
|
||||
"alwaysDeny": "一律拒绝",
|
||||
"passToAuth": "传递至认证",
|
||||
"orgSettingsDescription": "配置您组织的一般设置",
|
||||
"orgGeneralSettings": "组织设置",
|
||||
"orgGeneralSettingsDescription": "管理您的机构详细信息和配置",
|
||||
"saveGeneralSettings": "保存常规设置",
|
||||
"saveSettings": "保存设置",
|
||||
"orgDangerZone": "危险区域",
|
||||
"orgDangerZoneDescription": "一旦删除该组织,将无法恢复,请务必确认。",
|
||||
"orgDelete": "删除组织",
|
||||
"orgDeleteConfirm": "确认删除组织",
|
||||
"orgMessageRemove": "此操作不可逆,这将删除所有相关数据。",
|
||||
"orgMessageConfirm": "要确认,请在下面输入组织名称。",
|
||||
"orgQuestionRemove": "你确定要删除 “{selectedOrg}” 组织吗?",
|
||||
"orgQuestionRemove": "你确定要删除 \"{selectedOrg}\" 组织吗?",
|
||||
"orgUpdated": "组织已更新",
|
||||
"orgUpdatedDescription": "组织已更新。",
|
||||
"orgErrorUpdate": "更新组织失败",
|
||||
@@ -249,7 +254,7 @@
|
||||
"weeks": "周",
|
||||
"months": "月",
|
||||
"years": "年",
|
||||
"day": "{count, plural, =1 {# 天} other {# 天}}",
|
||||
"day": "{count, plural, other {# 天}}",
|
||||
"apiKeysTitle": "API 密钥",
|
||||
"apiKeysConfirmCopy2": "您必须确认您已复制 API 密钥。",
|
||||
"apiKeysErrorCreate": "创建 API 密钥出错",
|
||||
@@ -279,7 +284,7 @@
|
||||
"apiKeysAdd": "生成 API 密钥",
|
||||
"apiKeysErrorDelete": "删除 API 密钥出错",
|
||||
"apiKeysErrorDeleteMessage": "删除 API 密钥出错",
|
||||
"apiKeysQuestionRemove": "您确定要从组织中删除 “{selectedApiKey}” API密钥吗?",
|
||||
"apiKeysQuestionRemove": "您确定要从组织中删除 \"{selectedApiKey}\" API密钥吗?",
|
||||
"apiKeysMessageRemove": "一旦删除,此API密钥将无法被使用。",
|
||||
"apiKeysMessageConfirm": "要确认,请在下方输入API密钥名称。",
|
||||
"apiKeysDeleteConfirm": "确认删除 API 密钥",
|
||||
@@ -347,7 +352,7 @@
|
||||
"licensePurchase": "购买许可证",
|
||||
"licensePurchaseSites": "购买更多站点",
|
||||
"licenseSitesUsedMax": "使用了 {usedSites}/{maxSites} 个站点",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# 站点} =1 {# 站点} other {# 站点}}",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# 站点} one {# 站点} other {# 站点}}",
|
||||
"licensePurchaseDescription": "请选择您希望 {selectedMode, select, license {直接购买许可证,您可以随时增加更多站点。} other {为现有许可证购买更多站点}}",
|
||||
"licenseFee": "许可证费用",
|
||||
"licensePriceSite": "每个站点的价格",
|
||||
@@ -436,7 +441,7 @@
|
||||
"accessRoleSelect": "选择角色",
|
||||
"inviteEmailSentDescription": "一封电子邮件已经发送给用户,带有下面的访问链接。他们必须访问该链接才能接受邀请。",
|
||||
"inviteSentDescription": "用户已被邀请。他们必须访问下面的链接才能接受邀请。",
|
||||
"inviteExpiresIn": "邀请将于 {days, plural, =1 {# 天} other {# 天}}",
|
||||
"inviteExpiresIn": "邀请将在{days, plural, other {# 天}}后过期。",
|
||||
"idpTitle": "身份提供商",
|
||||
"idpSelect": "为外部用户选择身份提供商",
|
||||
"idpNotConfigured": "没有配置身份提供者。请在创建外部用户之前配置身份提供者。",
|
||||
@@ -449,6 +454,8 @@
|
||||
"accessRoleErrorAddDescription": "添加用户到角色时出错。",
|
||||
"userSaved": "用户已保存",
|
||||
"userSavedDescription": "用户已更新。",
|
||||
"autoProvisioned": "自动设置",
|
||||
"autoProvisionedDescription": "允许此用户由身份提供商自动管理",
|
||||
"accessControlsDescription": "管理此用户在组织中可以访问和做什么",
|
||||
"accessControlsSubmit": "保存访问控制",
|
||||
"roles": "角色",
|
||||
@@ -489,7 +496,7 @@
|
||||
"targetTlsSniDescription": "SNI使用的 TLS 服务器名称。留空使用默认值。",
|
||||
"targetTlsSubmit": "保存设置",
|
||||
"targets": "目标配置",
|
||||
"targetsDescription": "设置目标来路由流量到您的服务",
|
||||
"targetsDescription": "设置目标来路由流量到您的后端服务",
|
||||
"targetStickySessions": "启用置顶会话",
|
||||
"targetStickySessionsDescription": "将连接保持在同一个后端目标的整个会话中。",
|
||||
"methodSelect": "选择方法",
|
||||
@@ -506,6 +513,7 @@
|
||||
"ipAddressErrorInvalidFormat": "无效的 IP 地址格式",
|
||||
"ipAddressErrorInvalidOctet": "无效的 IP 地址",
|
||||
"path": "路径",
|
||||
"matchPath": "匹配路径",
|
||||
"ipAddressRange": "IP 范围",
|
||||
"rulesErrorFetch": "获取规则失败",
|
||||
"rulesErrorFetchDescription": "获取规则时出错",
|
||||
@@ -541,6 +549,7 @@
|
||||
"rulesActions": "行动",
|
||||
"rulesActionAlwaysAllow": "总是允许:绕过所有身份验证方法",
|
||||
"rulesActionAlwaysDeny": "总是拒绝:阻止所有请求;无法尝试验证",
|
||||
"rulesActionPassToAuth": "传递至认证:允许尝试身份验证方法",
|
||||
"rulesMatchCriteria": "匹配条件",
|
||||
"rulesMatchCriteriaIpAddress": "匹配一个指定的 IP 地址",
|
||||
"rulesMatchCriteriaIpAddressRange": "在 CIDR 符号中匹配一系列IP地址",
|
||||
@@ -715,7 +724,7 @@
|
||||
"idpManageDescription": "查看和管理系统中的身份提供商",
|
||||
"idpDeletedDescription": "身份提供商删除成功",
|
||||
"idpOidc": "OAuth2/OIDC",
|
||||
"idpQuestionRemove": "你确定要永久删除 “{name}” 这个身份提供商吗?",
|
||||
"idpQuestionRemove": "你确定要永久删除 \"{name}\" 这个身份提供商吗?",
|
||||
"idpMessageRemove": "这将删除身份提供者和所有相关的配置。通过此提供者进行身份验证的用户将无法登录。",
|
||||
"idpMessageConfirm": "要确认,请在下面输入身份提供者的名称。",
|
||||
"idpConfirmDelete": "确认删除身份提供商",
|
||||
@@ -832,6 +841,24 @@
|
||||
"pincodeRequirementsLength": "PIN码必须是6位数字",
|
||||
"pincodeRequirementsChars": "PIN 必须只包含数字",
|
||||
"passwordRequirementsLength": "密码必须至少 1 个字符长",
|
||||
"passwordRequirementsTitle": "密码要求:",
|
||||
"passwordRequirementLength": "至少8个字符长",
|
||||
"passwordRequirementUppercase": "至少一个大写字母",
|
||||
"passwordRequirementLowercase": "至少一个小写字母",
|
||||
"passwordRequirementNumber": "至少一个数字",
|
||||
"passwordRequirementSpecial": "至少一个特殊字符",
|
||||
"passwordRequirementsMet": "✓ 密码满足所有要求",
|
||||
"passwordStrength": "密码强度",
|
||||
"passwordStrengthWeak": "弱",
|
||||
"passwordStrengthMedium": "中",
|
||||
"passwordStrengthStrong": "强",
|
||||
"passwordRequirements": "要求:",
|
||||
"passwordRequirementLengthText": "8+ 个字符",
|
||||
"passwordRequirementUppercaseText": "大写字母 (A-Z)",
|
||||
"passwordRequirementLowercaseText": "小写字母 (a-z)",
|
||||
"passwordRequirementNumberText": "数字 (0-9)",
|
||||
"passwordRequirementSpecialText": "特殊字符 (!@#$%...)",
|
||||
"passwordsDoNotMatch": "密码不匹配",
|
||||
"otpEmailRequirementsLength": "OTP 必须至少 1 个字符长",
|
||||
"otpEmailSent": "OTP 已发送",
|
||||
"otpEmailSentDescription": "OTP 已经发送到您的电子邮件",
|
||||
@@ -887,6 +914,8 @@
|
||||
"idpConnectingToFinished": "已连接",
|
||||
"idpErrorConnectingTo": "无法连接到 {name},请联系管理员协助处理。",
|
||||
"idpErrorNotFound": "找不到 IdP",
|
||||
"idpGoogleAlt": "Google",
|
||||
"idpAzureAlt": "Azure",
|
||||
"inviteInvalid": "无效邀请",
|
||||
"inviteInvalidDescription": "邀请链接无效。",
|
||||
"inviteErrorWrongUser": "邀请不是该用户的",
|
||||
@@ -951,19 +980,28 @@
|
||||
"logoutError": "注销错误",
|
||||
"signingAs": "登录为",
|
||||
"serverAdmin": "服务器管理员",
|
||||
"managedSelfhosted": "托管自托管",
|
||||
"otpEnable": "启用双因子认证",
|
||||
"otpDisable": "禁用双因子认证",
|
||||
"logout": "登出",
|
||||
"licenseTierProfessionalRequired": "需要专业版",
|
||||
"licenseTierProfessionalRequiredDescription": "此功能仅在专业版可用。",
|
||||
"actionGetOrg": "获取组织",
|
||||
"updateOrgUser": "更新组织用户",
|
||||
"createOrgUser": "创建组织用户",
|
||||
"actionUpdateOrg": "更新组织",
|
||||
"actionUpdateUser": "更新用户",
|
||||
"actionGetUser": "获取用户",
|
||||
"actionGetOrgUser": "获取组织用户",
|
||||
"actionListOrgDomains": "列出组织域",
|
||||
"actionCreateSite": "创建站点",
|
||||
"actionDeleteSite": "删除站点",
|
||||
"actionGetSite": "获取站点",
|
||||
"actionListSites": "站点列表",
|
||||
"actionApplyBlueprint": "应用蓝图",
|
||||
"setupToken": "设置令牌",
|
||||
"setupTokenDescription": "从服务器控制台输入设置令牌。",
|
||||
"setupTokenRequired": "需要设置令牌",
|
||||
"actionUpdateSite": "更新站点",
|
||||
"actionListSiteRoles": "允许站点角色列表",
|
||||
"actionCreateResource": "创建资源",
|
||||
@@ -1019,6 +1057,17 @@
|
||||
"actionDeleteIdpOrg": "删除 IDP组织策略",
|
||||
"actionListIdpOrgs": "列出 IDP组织",
|
||||
"actionUpdateIdpOrg": "更新 IDP组织",
|
||||
"actionCreateClient": "创建客户端",
|
||||
"actionDeleteClient": "删除客户端",
|
||||
"actionUpdateClient": "更新客户端",
|
||||
"actionListClients": "列出客户端",
|
||||
"actionGetClient": "获取客户端",
|
||||
"actionCreateSiteResource": "创建站点资源",
|
||||
"actionDeleteSiteResource": "删除站点资源",
|
||||
"actionGetSiteResource": "获取站点资源",
|
||||
"actionListSiteResources": "列出站点资源",
|
||||
"actionUpdateSiteResource": "更新站点资源",
|
||||
"actionListInvitations": "邀请列表",
|
||||
"noneSelected": "未选择",
|
||||
"orgNotFound2": "未找到组织。",
|
||||
"searchProgress": "搜索中...",
|
||||
@@ -1090,8 +1139,10 @@
|
||||
"sidebarAllUsers": "所有用户",
|
||||
"sidebarIdentityProviders": "身份提供商",
|
||||
"sidebarLicense": "证书",
|
||||
"enableDockerSocket": "启用停靠套接字",
|
||||
"enableDockerSocketDescription": "启用 Docker Socket 发现以填充容器信息。必须向 Newt 提供 Socket 路径。",
|
||||
"sidebarClients": "客户端(测试版)",
|
||||
"sidebarDomains": "域",
|
||||
"enableDockerSocket": "启用 Docker 蓝图",
|
||||
"enableDockerSocketDescription": "启用 Docker Socket 标签擦除蓝图标签。套接字路径必须提供给新的。",
|
||||
"enableDockerSocketLink": "了解更多",
|
||||
"viewDockerContainers": "查看停靠容器",
|
||||
"containersIn": "{siteName} 中的容器",
|
||||
@@ -1102,7 +1153,7 @@
|
||||
"containerNetworks": "网络",
|
||||
"containerHostnameIp": "主机名/IP",
|
||||
"containerLabels": "标签",
|
||||
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
|
||||
"containerLabelsCount": "{count, plural, other {# 标签}}",
|
||||
"containerLabelsTitle": "容器标签",
|
||||
"containerLabelEmpty": "<empty>",
|
||||
"containerPorts": "端口",
|
||||
@@ -1114,7 +1165,7 @@
|
||||
"showStoppedContainers": "显示已停止的容器",
|
||||
"noContainersFound": "未找到容器。请确保Docker容器正在运行。",
|
||||
"searchContainersPlaceholder": "在 {count} 个容器中搜索...",
|
||||
"searchResultsCount": "{count} result{s,plural,one{} other{s}}",
|
||||
"searchResultsCount": "{count, plural, other {# 个结果}}",
|
||||
"filters": "筛选器",
|
||||
"filterOptions": "过滤器选项",
|
||||
"filterPorts": "端口",
|
||||
@@ -1129,8 +1180,344 @@
|
||||
"dark": "深色",
|
||||
"system": "系统",
|
||||
"theme": "主题",
|
||||
"subnetRequired": "子网是必填项",
|
||||
"initialSetupTitle": "初始服务器设置",
|
||||
"initialSetupDescription": "创建初始服务器管理员帐户。 只能存在一个服务器管理员。 您可以随时更改这些凭据。",
|
||||
"createAdminAccount": "创建管理员帐户",
|
||||
"setupErrorCreateAdmin": "创建服务器管理员帐户时出错。"
|
||||
"setupErrorCreateAdmin": "创建服务器管理员账户时发生错误。",
|
||||
"certificateStatus": "证书状态",
|
||||
"loading": "加载中",
|
||||
"restart": "重启",
|
||||
"domains": "域",
|
||||
"domainsDescription": "管理您的组织域",
|
||||
"domainsSearch": "搜索域...",
|
||||
"domainAdd": "添加域",
|
||||
"domainAddDescription": "在您的组织中注册新域",
|
||||
"domainCreate": "创建域",
|
||||
"domainCreatedDescription": "域创建成功",
|
||||
"domainDeletedDescription": "成功删除域",
|
||||
"domainQuestionRemove": "您确定要从您的账户中移除域{domain}吗?",
|
||||
"domainMessageRemove": "移除后,该域将不再与您的账户关联。",
|
||||
"domainMessageConfirm": "要确认,请在下方输入域名。",
|
||||
"domainConfirmDelete": "确认删除域",
|
||||
"domainDelete": "删除域",
|
||||
"domain": "域",
|
||||
"selectDomainTypeNsName": "域委派(NS)",
|
||||
"selectDomainTypeNsDescription": "此域及其所有子域。当您希望控制整个域区域时使用此选项。",
|
||||
"selectDomainTypeCnameName": "单个域(CNAME)",
|
||||
"selectDomainTypeCnameDescription": "仅此特定域。用于单个子域或特定域条目。",
|
||||
"selectDomainTypeWildcardName": "通配符域",
|
||||
"selectDomainTypeWildcardDescription": "此域名及其子域名。",
|
||||
"domainDelegation": "单个域",
|
||||
"selectType": "选择一个类型",
|
||||
"actions": "操作",
|
||||
"refresh": "刷新",
|
||||
"refreshError": "刷新数据失败",
|
||||
"verified": "已验证",
|
||||
"pending": "待定",
|
||||
"sidebarBilling": "计费",
|
||||
"billing": "计费",
|
||||
"orgBillingDescription": "管理您的账单信息和订阅",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin 托管",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "完成账户设置",
|
||||
"completeAccountSetupDescription": "设置您的密码以开始",
|
||||
"accountSetupSent": "我们将发送账号设置代码到该电子邮件地址。",
|
||||
"accountSetupCode": "设置代码",
|
||||
"accountSetupCodeDescription": "请检查您的邮箱以获取设置代码。",
|
||||
"passwordCreate": "创建密码",
|
||||
"passwordCreateConfirm": "确认密码",
|
||||
"accountSetupSubmit": "发送设置代码",
|
||||
"completeSetup": "完成设置",
|
||||
"accountSetupSuccess": "账号设置完成!欢迎来到 Pangolin!",
|
||||
"documentation": "文档",
|
||||
"saveAllSettings": "保存所有设置",
|
||||
"settingsUpdated": "设置已更新",
|
||||
"settingsUpdatedDescription": "所有设置已成功更新",
|
||||
"settingsErrorUpdate": "设置更新失败",
|
||||
"settingsErrorUpdateDescription": "更新设置时发生错误",
|
||||
"sidebarCollapse": "折叠",
|
||||
"sidebarExpand": "展开",
|
||||
"newtUpdateAvailable": "更新可用",
|
||||
"newtUpdateAvailableInfo": "新版本的 Newt 已可用。请更新到最新版本以获得最佳体验。",
|
||||
"domainPickerEnterDomain": "域名",
|
||||
"domainPickerPlaceholder": "example.com",
|
||||
"domainPickerDescription": "输入资源的完整域名以查看可用选项。",
|
||||
"domainPickerDescriptionSaas": "输入完整域名、子域或名称以查看可用选项。",
|
||||
"domainPickerTabAll": "所有",
|
||||
"domainPickerTabOrganization": "组织",
|
||||
"domainPickerTabProvided": "提供的",
|
||||
"domainPickerSortAsc": "A-Z",
|
||||
"domainPickerSortDesc": "Z-A",
|
||||
"domainPickerCheckingAvailability": "检查可用性...",
|
||||
"domainPickerNoMatchingDomains": "未找到匹配的域名。尝试不同的域名或检查您组织的域名设置。",
|
||||
"domainPickerOrganizationDomains": "组织域",
|
||||
"domainPickerProvidedDomains": "提供的域",
|
||||
"domainPickerSubdomain": "子域:{subdomain}",
|
||||
"domainPickerNamespace": "命名空间:{namespace}",
|
||||
"domainPickerShowMore": "显示更多",
|
||||
"domainNotFound": "域未找到",
|
||||
"domainNotFoundDescription": "此资源已禁用,因为该域不再在我们的系统中存在。请为此资源设置一个新域。",
|
||||
"failed": "失败",
|
||||
"createNewOrgDescription": "创建一个新组织",
|
||||
"organization": "组织",
|
||||
"port": "端口",
|
||||
"securityKeyManage": "管理安全密钥",
|
||||
"securityKeyDescription": "添加或删除用于无密码认证的安全密钥",
|
||||
"securityKeyRegister": "注册新的安全密钥",
|
||||
"securityKeyList": "您的安全密钥",
|
||||
"securityKeyNone": "尚未注册安全密钥",
|
||||
"securityKeyNameRequired": "名称为必填项",
|
||||
"securityKeyRemove": "删除",
|
||||
"securityKeyLastUsed": "上次使用:{date}",
|
||||
"securityKeyNameLabel": "名称",
|
||||
"securityKeyRegisterSuccess": "安全密钥注册成功",
|
||||
"securityKeyRegisterError": "注册安全密钥失败",
|
||||
"securityKeyRemoveSuccess": "安全密钥删除成功",
|
||||
"securityKeyRemoveError": "删除安全密钥失败",
|
||||
"securityKeyLoadError": "加载安全密钥失败",
|
||||
"securityKeyLogin": "使用安全密钥继续",
|
||||
"securityKeyAuthError": "使用安全密钥认证失败",
|
||||
"securityKeyRecommendation": "考虑在其他设备上注册另一个安全密钥,以确保不会被锁定在您的账户之外。",
|
||||
"registering": "注册中...",
|
||||
"securityKeyPrompt": "请使用您的安全密钥验证身份。确保您的安全密钥已连接并准备好。",
|
||||
"securityKeyBrowserNotSupported": "您的浏览器不支持安全密钥。请使用像 Chrome、Firefox 或 Safari 这样的现代浏览器。",
|
||||
"securityKeyPermissionDenied": "请允许访问您的安全密钥以继续登录。",
|
||||
"securityKeyRemovedTooQuickly": "请保持您的安全密钥连接,直到登录过程完成。",
|
||||
"securityKeyNotSupported": "您的安全密钥可能不兼容。请尝试不同的安全密钥。",
|
||||
"securityKeyUnknownError": "使用安全密钥时出现问题。请再试一次。",
|
||||
"twoFactorRequired": "注册安全密钥需要两步验证。",
|
||||
"twoFactor": "两步验证",
|
||||
"adminEnabled2FaOnYourAccount": "管理员已为{email}启用两步验证。请完成设置以继续。",
|
||||
"continueToApplication": "继续到应用程序",
|
||||
"securityKeyAdd": "添加安全密钥",
|
||||
"securityKeyRegisterTitle": "注册新安全密钥",
|
||||
"securityKeyRegisterDescription": "连接您的安全密钥并输入名称以便识别",
|
||||
"securityKeyTwoFactorRequired": "要求两步验证",
|
||||
"securityKeyTwoFactorDescription": "请输入你的两步验证代码以注册安全密钥",
|
||||
"securityKeyTwoFactorRemoveDescription": "请输入你的两步验证代码以移除安全密钥",
|
||||
"securityKeyTwoFactorCode": "双因素代码",
|
||||
"securityKeyRemoveTitle": "移除安全密钥",
|
||||
"securityKeyRemoveDescription": "输入您的密码以移除安全密钥 \"{name}\"",
|
||||
"securityKeyNoKeysRegistered": "没有注册安全密钥",
|
||||
"securityKeyNoKeysDescription": "添加安全密钥以加强您的账户安全",
|
||||
"createDomainRequired": "必须输入域",
|
||||
"createDomainAddDnsRecords": "添加 DNS 记录",
|
||||
"createDomainAddDnsRecordsDescription": "将以下 DNS 记录添加到您的域名提供商以完成设置。",
|
||||
"createDomainNsRecords": "NS 记录",
|
||||
"createDomainRecord": "记录",
|
||||
"createDomainType": "类型:",
|
||||
"createDomainName": "名称:",
|
||||
"createDomainValue": "值:",
|
||||
"createDomainCnameRecords": "CNAME 记录",
|
||||
"createDomainARecords": "A记录",
|
||||
"createDomainRecordNumber": "记录 {number}",
|
||||
"createDomainTxtRecords": "TXT 记录",
|
||||
"createDomainSaveTheseRecords": "保存这些记录",
|
||||
"createDomainSaveTheseRecordsDescription": "务必保存这些 DNS 记录,因为您将无法再次查看它们。",
|
||||
"createDomainDnsPropagation": "DNS 传播",
|
||||
"createDomainDnsPropagationDescription": "DNS 更改可能需要一些时间才能在互联网上传播。这可能需要从几分钟到 48 小时,具体取决于您的 DNS 提供商和 TTL 设置。",
|
||||
"resourcePortRequired": "非 HTTP 资源必须输入端口号",
|
||||
"resourcePortNotAllowed": "HTTP 资源不应设置端口号",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "我同意",
|
||||
"termsOfService": "服务条款",
|
||||
"and": "和",
|
||||
"privacyPolicy": "隐私政策"
|
||||
},
|
||||
"siteRequired": "需要站点。",
|
||||
"olmTunnel": "Olm 隧道",
|
||||
"olmTunnelDescription": "使用 Olm 进行客户端连接",
|
||||
"errorCreatingClient": "创建客户端出错",
|
||||
"clientDefaultsNotFound": "未找到客户端默认值",
|
||||
"createClient": "创建客户端",
|
||||
"createClientDescription": "创建一个新客户端来连接您的站点",
|
||||
"seeAllClients": "查看所有客户端",
|
||||
"clientInformation": "客户端信息",
|
||||
"clientNamePlaceholder": "客户端名称",
|
||||
"address": "地址",
|
||||
"subnetPlaceholder": "子网",
|
||||
"addressDescription": "此客户端将用于连接的地址",
|
||||
"selectSites": "选择站点",
|
||||
"sitesDescription": "客户端将与所选站点进行连接",
|
||||
"clientInstallOlm": "安装 Olm",
|
||||
"clientInstallOlmDescription": "在您的系统上运行 Olm",
|
||||
"clientOlmCredentials": "Olm 凭据",
|
||||
"clientOlmCredentialsDescription": "这是 Olm 服务器的身份验证方式",
|
||||
"olmEndpoint": "Olm 端点",
|
||||
"olmId": "Olm ID",
|
||||
"olmSecretKey": "Olm 私钥",
|
||||
"clientCredentialsSave": "保存您的凭据",
|
||||
"clientCredentialsSaveDescription": "该信息仅会显示一次,请确保将其复制到安全位置。",
|
||||
"generalSettingsDescription": "配置此客户端的常规设置",
|
||||
"clientUpdated": "客户端已更新",
|
||||
"clientUpdatedDescription": "客户端已更新。",
|
||||
"clientUpdateFailed": "更新客户端失败",
|
||||
"clientUpdateError": "更新客户端时出错。",
|
||||
"sitesFetchFailed": "获取站点失败",
|
||||
"sitesFetchError": "获取站点时出错。",
|
||||
"olmErrorFetchReleases": "获取 Olm 发布版本时出错。",
|
||||
"olmErrorFetchLatest": "获取最新 Olm 发布版本时出错。",
|
||||
"remoteSubnets": "远程子网",
|
||||
"enterCidrRange": "输入 CIDR 范围",
|
||||
"remoteSubnetsDescription": "添加可以通过客户端远程访问该站点的CIDR范围。使用类似10.0.0.0/24的格式。这仅适用于VPN客户端连接。",
|
||||
"resourceEnableProxy": "启用公共代理",
|
||||
"resourceEnableProxyDescription": "启用到此资源的公共代理。这允许外部网络通过开放端口访问资源。需要 Traefik 配置。",
|
||||
"externalProxyEnabled": "外部代理已启用",
|
||||
"addNewTarget": "添加新目标",
|
||||
"targetsList": "目标列表",
|
||||
"targetErrorDuplicateTargetFound": "找到重复的目标",
|
||||
"httpMethod": "HTTP 方法",
|
||||
"selectHttpMethod": "选择 HTTP 方法",
|
||||
"domainPickerSubdomainLabel": "子域名",
|
||||
"domainPickerBaseDomainLabel": "根域名",
|
||||
"domainPickerSearchDomains": "搜索域名...",
|
||||
"domainPickerNoDomainsFound": "未找到域名",
|
||||
"domainPickerLoadingDomains": "加载域名...",
|
||||
"domainPickerSelectBaseDomain": "选择根域名...",
|
||||
"domainPickerNotAvailableForCname": "不适用于CNAME域",
|
||||
"domainPickerEnterSubdomainOrLeaveBlank": "输入子域名或留空以使用根域名。",
|
||||
"domainPickerEnterSubdomainToSearch": "输入一个子域名以搜索并从可用免费域名中选择。",
|
||||
"domainPickerFreeDomains": "免费域名",
|
||||
"domainPickerSearchForAvailableDomains": "搜索可用域名",
|
||||
"resourceDomain": "域名",
|
||||
"resourceEditDomain": "编辑域名",
|
||||
"siteName": "站点名称",
|
||||
"proxyPort": "端口",
|
||||
"resourcesTableProxyResources": "代理资源",
|
||||
"resourcesTableClientResources": "客户端资源",
|
||||
"resourcesTableNoProxyResourcesFound": "未找到代理资源。",
|
||||
"resourcesTableNoInternalResourcesFound": "未找到内部资源。",
|
||||
"resourcesTableDestination": "目标",
|
||||
"resourcesTableTheseResourcesForUseWith": "这些资源供...使用",
|
||||
"resourcesTableClients": "客户端",
|
||||
"resourcesTableAndOnlyAccessibleInternally": "且仅在与客户端连接时可内部访问。",
|
||||
"editInternalResourceDialogEditClientResource": "编辑客户端资源",
|
||||
"editInternalResourceDialogUpdateResourceProperties": "更新{resourceName}的资源属性和目标配置。",
|
||||
"editInternalResourceDialogResourceProperties": "资源属性",
|
||||
"editInternalResourceDialogName": "名称",
|
||||
"editInternalResourceDialogProtocol": "协议",
|
||||
"editInternalResourceDialogSitePort": "站点端口",
|
||||
"editInternalResourceDialogTargetConfiguration": "目标配置",
|
||||
"editInternalResourceDialogCancel": "取消",
|
||||
"editInternalResourceDialogSaveResource": "保存资源",
|
||||
"editInternalResourceDialogSuccess": "成功",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "内部资源更新成功",
|
||||
"editInternalResourceDialogError": "错误",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "更新内部资源失败",
|
||||
"editInternalResourceDialogNameRequired": "名称为必填项",
|
||||
"editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||
"editInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
|
||||
"editInternalResourceDialogProxyPortMax": "代理端口必须小于65536",
|
||||
"editInternalResourceDialogInvalidIPAddressFormat": "无效的IP地址格式",
|
||||
"editInternalResourceDialogDestinationPortMin": "目标端口必须至少为1",
|
||||
"editInternalResourceDialogDestinationPortMax": "目标端口必须小于65536",
|
||||
"createInternalResourceDialogNoSitesAvailable": "暂无可用站点",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建内部资源。",
|
||||
"createInternalResourceDialogClose": "关闭",
|
||||
"createInternalResourceDialogCreateClientResource": "创建客户端资源",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源,该资源将可供连接到所选站点的客户端访问。",
|
||||
"createInternalResourceDialogResourceProperties": "资源属性",
|
||||
"createInternalResourceDialogName": "名称",
|
||||
"createInternalResourceDialogSite": "站点",
|
||||
"createInternalResourceDialogSelectSite": "选择站点...",
|
||||
"createInternalResourceDialogSearchSites": "搜索站点...",
|
||||
"createInternalResourceDialogNoSitesFound": "未找到站点。",
|
||||
"createInternalResourceDialogProtocol": "协议",
|
||||
"createInternalResourceDialogTcp": "TCP",
|
||||
"createInternalResourceDialogUdp": "UDP",
|
||||
"createInternalResourceDialogSitePort": "站点端口",
|
||||
"createInternalResourceDialogSitePortDescription": "使用此端口在连接到客户端时访问站点上的资源。",
|
||||
"createInternalResourceDialogTargetConfiguration": "目标配置",
|
||||
"createInternalResourceDialogDestinationIPDescription": "站点网络上资源的IP或主机名地址。",
|
||||
"createInternalResourceDialogDestinationPortDescription": "资源在目标IP上可访问的端口。",
|
||||
"createInternalResourceDialogCancel": "取消",
|
||||
"createInternalResourceDialogCreateResource": "创建资源",
|
||||
"createInternalResourceDialogSuccess": "成功",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "内部资源创建成功",
|
||||
"createInternalResourceDialogError": "错误",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "创建内部资源失败",
|
||||
"createInternalResourceDialogNameRequired": "名称为必填项",
|
||||
"createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||
"createInternalResourceDialogPleaseSelectSite": "请选择一个站点",
|
||||
"createInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
|
||||
"createInternalResourceDialogProxyPortMax": "代理端口必须小于65536",
|
||||
"createInternalResourceDialogInvalidIPAddressFormat": "无效的IP地址格式",
|
||||
"createInternalResourceDialogDestinationPortMin": "目标端口必须至少为1",
|
||||
"createInternalResourceDialogDestinationPortMax": "目标端口必须小于65536",
|
||||
"siteConfiguration": "配置",
|
||||
"siteAcceptClientConnections": "接受客户端连接",
|
||||
"siteAcceptClientConnectionsDescription": "允许其他设备通过此Newt实例使用客户端作为网关连接。",
|
||||
"siteAddress": "站点地址",
|
||||
"siteAddressDescription": "指定主机的IP地址以供客户端连接。这是Pangolin网络中站点的内部地址,供客户端访问。必须在Org子网内。",
|
||||
"autoLoginExternalIdp": "自动使用外部IDP登录",
|
||||
"autoLoginExternalIdpDescription": "立即将用户重定向到外部IDP进行身份验证。",
|
||||
"selectIdp": "选择IDP",
|
||||
"selectIdpPlaceholder": "选择一个IDP...",
|
||||
"selectIdpRequired": "在启用自动登录时,请选择一个IDP。",
|
||||
"autoLoginTitle": "重定向中",
|
||||
"autoLoginDescription": "正在将您重定向到外部身份提供商进行身份验证。",
|
||||
"autoLoginProcessing": "准备身份验证...",
|
||||
"autoLoginRedirecting": "重定向到登录...",
|
||||
"autoLoginError": "自动登录错误",
|
||||
"autoLoginErrorNoRedirectUrl": "未从身份提供商收到重定向URL。",
|
||||
"autoLoginErrorGeneratingUrl": "生成身份验证URL失败。",
|
||||
"managedSelfHosted": {
|
||||
"title": "托管自托管",
|
||||
"description": "更可靠和低维护自我托管的 Pangolin 服务器,带有额外的铃声和告密器",
|
||||
"introTitle": "托管自托管的潘戈林公司",
|
||||
"introDescription": "这是一种部署选择,为那些希望简洁和额外可靠的人设计,同时仍然保持他们的数据的私密性和自我托管性。",
|
||||
"introDetail": "通过此选项,您仍然运行您自己的 Pangolin 节点 — — 您的隧道、SSL 终止,并且流量在您的服务器上保持所有状态。 不同之处在于,管理和监测是通过我们的云层仪表板进行的,该仪表板开启了一些好处:",
|
||||
"benefitSimplerOperations": {
|
||||
"title": "简单的操作",
|
||||
"description": "无需运行您自己的邮件服务器或设置复杂的警报。您将从方框中获得健康检查和下限提醒。"
|
||||
},
|
||||
"benefitAutomaticUpdates": {
|
||||
"title": "自动更新",
|
||||
"description": "云仪表盘快速演化,所以您可以获得新的功能和错误修复,而不必每次手动拉取新的容器。"
|
||||
},
|
||||
"benefitLessMaintenance": {
|
||||
"title": "减少维护时间",
|
||||
"description": "没有要管理的数据库迁移、备份或额外的基础设施。我们在云端处理这个问题。"
|
||||
},
|
||||
"benefitCloudFailover": {
|
||||
"title": "云失败",
|
||||
"description": "如果您的节点被关闭,您的隧道可能暂时无法连接到我们的云端,直到您将其重新连接上线。"
|
||||
},
|
||||
"benefitHighAvailability": {
|
||||
"title": "高可用率(PoPs)",
|
||||
"description": "您还可以将多个节点添加到您的帐户中以获取冗余和更好的性能。"
|
||||
},
|
||||
"benefitFutureEnhancements": {
|
||||
"title": "将来的改进",
|
||||
"description": "我们正在计划添加更多的分析、警报和管理工具,使你的部署更加有力。"
|
||||
},
|
||||
"docsAlert": {
|
||||
"text": "在我们中更多地了解管理下的自托管选项",
|
||||
"documentation": "文档"
|
||||
},
|
||||
"convertButton": "将此节点转换为管理自托管的"
|
||||
},
|
||||
"internationaldomaindetected": "检测到国际域",
|
||||
"willbestoredas": "储存为:",
|
||||
"idpGoogleDescription": "Google OAuth2/OIDC 提供商",
|
||||
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
|
||||
"customHeaders": "自定义标题",
|
||||
"headersValidationError": "头部必须是格式:头部名称:值。",
|
||||
"domainPickerProvidedDomain": "提供的域",
|
||||
"domainPickerFreeProvidedDomain": "免费提供的域",
|
||||
"domainPickerVerified": "已验证",
|
||||
"domainPickerUnverified": "未验证",
|
||||
"domainPickerInvalidSubdomainStructure": "此子域包含无效的字符或结构。当您保存时,它将被自动清除。",
|
||||
"domainPickerError": "错误",
|
||||
"domainPickerErrorLoadDomains": "加载组织域名失败",
|
||||
"domainPickerErrorCheckAvailability": "检查域可用性失败",
|
||||
"domainPickerInvalidSubdomain": "无效的子域",
|
||||
"domainPickerInvalidSubdomainRemoved": "输入 \"{sub}\" 已被移除,因为其无效。",
|
||||
"domainPickerInvalidSubdomainCannotMakeValid": "\"{sub}\" 无法为 {domain} 变为有效。",
|
||||
"domainPickerSubdomainSanitized": "子域已净化",
|
||||
"domainPickerSubdomainCorrected": "\"{sub}\" 已被更正为 \"{sanitized}\"",
|
||||
"resourceAddEntrypointsEditFile": "编辑文件:config/traefik/traefik_config.yml",
|
||||
"resourceExposePortsEditFile": "编辑文件:docker-compose.yml"
|
||||
}
|
||||
|
||||
4440
package-lock.json
generated
112
package.json
@@ -21,44 +21,46 @@
|
||||
"db:clear-migrations": "rm -rf server/migrations",
|
||||
"build:sqlite": "mkdir -p dist && next build && node esbuild.mjs -e server/index.ts -o dist/server.mjs && node esbuild.mjs -e server/setup/migrationsSqlite.ts -o dist/migrations.mjs",
|
||||
"build:pg": "mkdir -p dist && next build && node esbuild.mjs -e server/index.ts -o dist/server.mjs && node esbuild.mjs -e server/setup/migrationsPg.ts -o dist/migrations.mjs",
|
||||
"start:sqlite": "DB_TYPE=sqlite NODE_OPTIONS=--enable-source-maps NODE_ENV=development ENVIRONMENT=prod sh -c 'node dist/migrations.mjs && node dist/server.mjs'",
|
||||
"start:pg": "DB_TYPE=pg NODE_OPTIONS=--enable-source-maps NODE_ENV=development ENVIRONMENT=prod sh -c 'node dist/migrations.mjs && node dist/server.mjs'",
|
||||
"start": "ENVIRONMENT=prod node dist/migrations.mjs && ENVIRONMENT=prod NODE_ENV=development node --enable-source-maps dist/server.mjs",
|
||||
"email": "email dev --dir server/emails/templates --port 3005",
|
||||
"build:cli": "node esbuild.mjs -e cli/index.ts -o dist/cli.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@asteasolutions/zod-to-openapi": "^7.3.4",
|
||||
"@hookform/resolvers": "3.9.1",
|
||||
"@hookform/resolvers": "4.1.3",
|
||||
"@node-rs/argon2": "^2.0.2",
|
||||
"@oslojs/crypto": "1.0.1",
|
||||
"@oslojs/encoding": "1.1.0",
|
||||
"@radix-ui/react-avatar": "1.1.10",
|
||||
"@radix-ui/react-checkbox": "1.3.2",
|
||||
"@radix-ui/react-collapsible": "1.1.11",
|
||||
"@radix-ui/react-dialog": "1.1.14",
|
||||
"@radix-ui/react-dropdown-menu": "2.1.15",
|
||||
"@radix-ui/react-checkbox": "1.3.3",
|
||||
"@radix-ui/react-collapsible": "1.1.12",
|
||||
"@radix-ui/react-dialog": "1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "2.1.16",
|
||||
"@radix-ui/react-icons": "1.3.2",
|
||||
"@radix-ui/react-label": "2.1.7",
|
||||
"@radix-ui/react-popover": "1.1.14",
|
||||
"@radix-ui/react-popover": "1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-radio-group": "1.3.7",
|
||||
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||
"@radix-ui/react-select": "2.2.5",
|
||||
"@radix-ui/react-radio-group": "1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "2.2.6",
|
||||
"@radix-ui/react-separator": "1.1.7",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-switch": "1.2.5",
|
||||
"@radix-ui/react-tabs": "1.1.12",
|
||||
"@radix-ui/react-toast": "1.2.14",
|
||||
"@react-email/components": "0.1.0",
|
||||
"@react-email/render": "^1.1.2",
|
||||
"@react-email/tailwind": "1.0.5",
|
||||
"@radix-ui/react-switch": "1.2.6",
|
||||
"@radix-ui/react-tabs": "1.1.13",
|
||||
"@radix-ui/react-toast": "1.2.15",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@react-email/components": "0.5.3",
|
||||
"@react-email/render": "^1.2.0",
|
||||
"@react-email/tailwind": "1.2.2",
|
||||
"@simplewebauthn/browser": "^13.1.2",
|
||||
"@simplewebauthn/server": "^9.0.3",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tanstack/react-table": "8.21.3",
|
||||
"arctic": "^3.7.0",
|
||||
"axios": "1.10.0",
|
||||
"axios": "^1.12.2",
|
||||
"better-sqlite3": "11.7.0",
|
||||
"canvas-confetti": "1.9.3",
|
||||
"class-variance-authority": "0.7.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"cookie": "^1.0.2",
|
||||
@@ -66,11 +68,11 @@
|
||||
"cookies": "^0.9.1",
|
||||
"cors": "2.8.5",
|
||||
"crypto-js": "^4.2.0",
|
||||
"drizzle-orm": "0.44.2",
|
||||
"eslint": "9.29.0",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"express": "4.21.2",
|
||||
"express-rate-limit": "7.5.1",
|
||||
"drizzle-orm": "0.44.5",
|
||||
"eslint": "9.35.0",
|
||||
"eslint-config-next": "15.5.3",
|
||||
"express": "5.1.0",
|
||||
"express-rate-limit": "8.1.0",
|
||||
"glob": "11.0.3",
|
||||
"helmet": "8.1.0",
|
||||
"http-errors": "2.0.0",
|
||||
@@ -79,68 +81,70 @@
|
||||
"jmespath": "^0.16.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "0.522.0",
|
||||
"lucide-react": "^0.544.0",
|
||||
"moment": "2.30.1",
|
||||
"next": "15.3.4",
|
||||
"next-intl": "^4.1.0",
|
||||
"next": "15.5.3",
|
||||
"next-intl": "^4.3.9",
|
||||
"next-themes": "0.4.6",
|
||||
"node-cache": "5.1.2",
|
||||
"node-fetch": "3.3.2",
|
||||
"nodemailer": "7.0.3",
|
||||
"npm": "^11.4.2",
|
||||
"nodemailer": "7.0.6",
|
||||
"npm": "^11.6.0",
|
||||
"oslo": "1.2.1",
|
||||
"pg": "^8.16.2",
|
||||
"posthog-node": "^5.8.4",
|
||||
"qrcode.react": "4.2.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-easy-sort": "^1.6.0",
|
||||
"react-hook-form": "7.58.1",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"react-easy-sort": "^1.7.0",
|
||||
"react-hook-form": "7.62.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"rebuild": "0.1.2",
|
||||
"semver": "7.7.2",
|
||||
"semver": "^7.7.2",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"tailwind-merge": "3.3.1",
|
||||
"tw-animate-css": "^1.3.3",
|
||||
"uuid": "^11.1.0",
|
||||
"tw-animate-css": "^1.3.8",
|
||||
"uuid": "^13.0.0",
|
||||
"vaul": "1.1.2",
|
||||
"winston": "3.17.0",
|
||||
"winston-daily-rotate-file": "5.0.0",
|
||||
"ws": "8.18.2",
|
||||
"zod": "3.25.67",
|
||||
"zod-validation-error": "3.5.2",
|
||||
"yargs": "18.0.0"
|
||||
"ws": "8.18.3",
|
||||
"yargs": "18.0.0",
|
||||
"zod": "3.25.76",
|
||||
"zod-validation-error": "3.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dotenvx/dotenvx": "1.45.1",
|
||||
"@dotenvx/dotenvx": "1.49.1",
|
||||
"@esbuild-plugins/tsconfig-paths": "0.1.2",
|
||||
"@tailwindcss/postcss": "^4.1.10",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@types/better-sqlite3": "7.6.12",
|
||||
"@types/cookie-parser": "1.4.9",
|
||||
"@types/cors": "2.8.19",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/express": "5.0.3",
|
||||
"@types/express-session": "^1.18.2",
|
||||
"@types/jmespath": "^0.15.2",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^24",
|
||||
"@types/nodemailer": "6.4.17",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"@types/semver": "7.7.0",
|
||||
"@types/node": "24.5.2",
|
||||
"@types/nodemailer": "7.0.1",
|
||||
"@types/pg": "8.15.5",
|
||||
"@types/react": "19.1.13",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/swagger-ui-express": "^4.1.8",
|
||||
"@types/ws": "8.18.1",
|
||||
"@types/yargs": "17.0.33",
|
||||
"drizzle-kit": "0.31.2",
|
||||
"esbuild": "0.25.5",
|
||||
"drizzle-kit": "0.31.4",
|
||||
"esbuild": "0.25.10",
|
||||
"esbuild-node-externals": "1.18.0",
|
||||
"postcss": "^8",
|
||||
"react-email": "4.0.16",
|
||||
"react-email": "4.2.11",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsx": "4.20.3",
|
||||
"tsx": "4.20.5",
|
||||
"typescript": "^5",
|
||||
"typescript-eslint": "^8.35.0",
|
||||
"yargs": "18.0.0"
|
||||
"typescript-eslint": "^8.44.0"
|
||||
},
|
||||
"overrides": {
|
||||
"emblor": {
|
||||
|
||||
BIN
public/auth-diagram1.png
Normal file
|
After Width: | Height: | Size: 647 KiB |
BIN
public/clip.gif
Normal file
|
After Width: | Height: | Size: 500 KiB |
132
public/diagram-dark.svg
Normal file
|
After Width: | Height: | Size: 52 KiB |
132
public/diagram.svg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
public/idp/azure.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
public/idp/google.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 574 KiB |
BIN
public/screenshots/create-api-key.png
Normal file
|
After Width: | Height: | Size: 748 KiB |
BIN
public/screenshots/create-idp.png
Normal file
|
After Width: | Height: | Size: 688 KiB |
BIN
public/screenshots/create-resource.png
Normal file
|
After Width: | Height: | Size: 687 KiB |
BIN
public/screenshots/create-share-link.png
Normal file
|
After Width: | Height: | Size: 669 KiB |
BIN
public/screenshots/create-site.png
Normal file
|
After Width: | Height: | Size: 713 KiB |
BIN
public/screenshots/edit-resource.png
Normal file
|
After Width: | Height: | Size: 636 KiB |
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 713 KiB |
BIN
public/screenshots/resource-auth.png
Normal file
|
After Width: | Height: | Size: 356 KiB |
BIN
public/screenshots/resource-authentication.png
Normal file
|
After Width: | Height: | Size: 707 KiB |
BIN
public/screenshots/resources.png
Normal file
|
After Width: | Height: | Size: 713 KiB |
BIN
public/screenshots/roles.png
Normal file
|
After Width: | Height: | Size: 556 KiB |
BIN
public/screenshots/site-online.png
Normal file
|
After Width: | Height: | Size: 585 KiB |
BIN
public/screenshots/sites-fade.png
Normal file
|
After Width: | Height: | Size: 456 KiB |
BIN
public/screenshots/sites.png
Normal file
|
After Width: | Height: | Size: 674 KiB |
BIN
public/screenshots/users.png
Normal file
|
After Width: | Height: | Size: 597 KiB |
@@ -5,20 +5,25 @@ import config from "@server/lib/config";
|
||||
import logger from "@server/logger";
|
||||
import {
|
||||
errorHandlerMiddleware,
|
||||
notFoundMiddleware,
|
||||
rateLimitMiddleware
|
||||
notFoundMiddleware
|
||||
} from "@server/middlewares";
|
||||
import { authenticated, unauthenticated } from "@server/routers/external";
|
||||
import { router as wsRouter, handleWSUpgrade } from "@server/routers/ws";
|
||||
import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
||||
import { csrfProtectionMiddleware } from "./middlewares/csrfProtection";
|
||||
import helmet from "helmet";
|
||||
import rateLimit, { ipKeyGenerator } from "express-rate-limit";
|
||||
import createHttpError from "http-errors";
|
||||
import HttpCode from "./types/HttpCode";
|
||||
import requestTimeoutMiddleware from "./middlewares/requestTimeout";
|
||||
import { createStore } from "./lib/rateLimitStore";
|
||||
|
||||
const dev = config.isDev;
|
||||
const externalPort = config.getRawConfig().server.external_port;
|
||||
|
||||
export function createApiServer() {
|
||||
const apiServer = express();
|
||||
const prefix = `/api/v1`;
|
||||
|
||||
const trustProxy = config.getRawConfig().server.trust_proxy;
|
||||
if (trustProxy) {
|
||||
@@ -54,19 +59,30 @@ export function createApiServer() {
|
||||
apiServer.use(cookieParser());
|
||||
apiServer.use(express.json());
|
||||
|
||||
// Add request timeout middleware
|
||||
apiServer.use(requestTimeoutMiddleware(60000)); // 60 second timeout
|
||||
|
||||
if (!dev) {
|
||||
apiServer.use(
|
||||
rateLimitMiddleware({
|
||||
windowMin:
|
||||
config.getRawConfig().rate_limits.global.window_minutes,
|
||||
rateLimit({
|
||||
windowMs:
|
||||
config.getRawConfig().rate_limits.global.window_minutes *
|
||||
60 *
|
||||
1000,
|
||||
max: config.getRawConfig().rate_limits.global.max_requests,
|
||||
type: "IP_AND_PATH"
|
||||
keyGenerator: (req) => `apiServerGlobal:${ipKeyGenerator(req.ip || "")}:${req.path}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `Rate limit exceeded. You can make ${config.getRawConfig().rate_limits.global.max_requests} requests every ${config.getRawConfig().rate_limits.global.window_minutes} minute(s).`;
|
||||
return next(
|
||||
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
|
||||
);
|
||||
},
|
||||
store: createStore()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// API routes
|
||||
const prefix = `/api/v1`;
|
||||
apiServer.use(logIncomingMiddleware);
|
||||
apiServer.use(prefix, unauthenticated);
|
||||
apiServer.use(prefix, authenticated);
|
||||
|
||||
@@ -56,6 +56,8 @@ export enum ActionsEnum {
|
||||
// removeUserAction = "removeUserAction",
|
||||
// removeUserSite = "removeUserSite",
|
||||
getOrgUser = "getOrgUser",
|
||||
updateUser = "updateUser",
|
||||
getUser = "getUser",
|
||||
setResourcePassword = "setResourcePassword",
|
||||
setResourcePincode = "setResourcePincode",
|
||||
setResourceWhitelist = "setResourceWhitelist",
|
||||
@@ -67,6 +69,16 @@ export enum ActionsEnum {
|
||||
deleteResourceRule = "deleteResourceRule",
|
||||
listResourceRules = "listResourceRules",
|
||||
updateResourceRule = "updateResourceRule",
|
||||
createSiteResource = "createSiteResource",
|
||||
deleteSiteResource = "deleteSiteResource",
|
||||
getSiteResource = "getSiteResource",
|
||||
listSiteResources = "listSiteResources",
|
||||
updateSiteResource = "updateSiteResource",
|
||||
createClient = "createClient",
|
||||
deleteClient = "deleteClient",
|
||||
updateClient = "updateClient",
|
||||
listClients = "listClients",
|
||||
getClient = "getClient",
|
||||
listOrgDomains = "listOrgDomains",
|
||||
createNewt = "createNewt",
|
||||
createIdp = "createIdp",
|
||||
@@ -85,7 +97,12 @@ export enum ActionsEnum {
|
||||
setApiKeyOrgs = "setApiKeyOrgs",
|
||||
listApiKeyActions = "listApiKeyActions",
|
||||
listApiKeys = "listApiKeys",
|
||||
getApiKey = "getApiKey"
|
||||
getApiKey = "getApiKey",
|
||||
createOrgDomain = "createOrgDomain",
|
||||
deleteOrgDomain = "deleteOrgDomain",
|
||||
restartOrgDomain = "restartOrgDomain",
|
||||
updateOrgUser = "updateOrgUser",
|
||||
applyBlueprint = "applyBlueprint"
|
||||
}
|
||||
|
||||
export async function checkUserActionPermission(
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { db } from '@server/db';
|
||||
import { limitsTable } from '@server/db';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import createHttpError from 'http-errors';
|
||||
import HttpCode from '@server/types/HttpCode';
|
||||
|
||||
interface CheckLimitOptions {
|
||||
orgId: string;
|
||||
limitName: string;
|
||||
currentValue: number;
|
||||
increment?: number;
|
||||
}
|
||||
|
||||
export async function checkOrgLimit({ orgId, limitName, currentValue, increment = 0 }: CheckLimitOptions): Promise<boolean> {
|
||||
try {
|
||||
const limit = await db.select()
|
||||
.from(limitsTable)
|
||||
.where(
|
||||
and(
|
||||
eq(limitsTable.orgId, orgId),
|
||||
eq(limitsTable.name, limitName)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (limit.length === 0) {
|
||||
throw createHttpError(HttpCode.NOT_FOUND, `Limit "${limitName}" not found for organization`);
|
||||
}
|
||||
|
||||
const limitValue = limit[0].value;
|
||||
|
||||
// Check if the current value plus the increment is within the limit
|
||||
return (currentValue + increment) <= limitValue;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw createHttpError(HttpCode.INTERNAL_SERVER_ERROR, `Error checking limit: ${error.message}`);
|
||||
}
|
||||
throw createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Unknown error occurred while checking limit');
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@ export const SESSION_COOKIE_EXPIRES =
|
||||
60 *
|
||||
60 *
|
||||
config.getRawConfig().server.dashboard_session_length_hours;
|
||||
export const COOKIE_DOMAIN =
|
||||
"." + new URL(config.getRawConfig().app.dashboard_url).hostname;
|
||||
export const COOKIE_DOMAIN = config.getRawConfig().app.dashboard_url ?
|
||||
"." + new URL(config.getRawConfig().app.dashboard_url!).hostname : undefined;
|
||||
|
||||
export function generateSessionToken(): string {
|
||||
const bytes = new Uint8Array(20);
|
||||
|
||||
72
server/auth/sessions/olm.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
encodeHexLowerCase,
|
||||
} from "@oslojs/encoding";
|
||||
import { sha256 } from "@oslojs/crypto/sha2";
|
||||
import { Olm, olms, olmSessions, OlmSession } from "@server/db";
|
||||
import { db } from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export const EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
|
||||
export async function createOlmSession(
|
||||
token: string,
|
||||
olmId: string,
|
||||
): Promise<OlmSession> {
|
||||
const sessionId = encodeHexLowerCase(
|
||||
sha256(new TextEncoder().encode(token)),
|
||||
);
|
||||
const session: OlmSession = {
|
||||
sessionId: sessionId,
|
||||
olmId,
|
||||
expiresAt: new Date(Date.now() + EXPIRES).getTime(),
|
||||
};
|
||||
await db.insert(olmSessions).values(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
export async function validateOlmSessionToken(
|
||||
token: string,
|
||||
): Promise<SessionValidationResult> {
|
||||
const sessionId = encodeHexLowerCase(
|
||||
sha256(new TextEncoder().encode(token)),
|
||||
);
|
||||
const result = await db
|
||||
.select({ olm: olms, session: olmSessions })
|
||||
.from(olmSessions)
|
||||
.innerJoin(olms, eq(olmSessions.olmId, olms.olmId))
|
||||
.where(eq(olmSessions.sessionId, sessionId));
|
||||
if (result.length < 1) {
|
||||
return { session: null, olm: null };
|
||||
}
|
||||
const { olm, session } = result[0];
|
||||
if (Date.now() >= session.expiresAt) {
|
||||
await db
|
||||
.delete(olmSessions)
|
||||
.where(eq(olmSessions.sessionId, session.sessionId));
|
||||
return { session: null, olm: null };
|
||||
}
|
||||
if (Date.now() >= session.expiresAt - (EXPIRES / 2)) {
|
||||
session.expiresAt = new Date(
|
||||
Date.now() + EXPIRES,
|
||||
).getTime();
|
||||
await db
|
||||
.update(olmSessions)
|
||||
.set({
|
||||
expiresAt: session.expiresAt,
|
||||
})
|
||||
.where(eq(olmSessions.sessionId, session.sessionId));
|
||||
}
|
||||
return { session, olm };
|
||||
}
|
||||
|
||||
export async function invalidateOlmSession(sessionId: string): Promise<void> {
|
||||
await db.delete(olmSessions).where(eq(olmSessions.sessionId, sessionId));
|
||||
}
|
||||
|
||||
export async function invalidateAllOlmSessions(olmId: string): Promise<void> {
|
||||
await db.delete(olmSessions).where(eq(olmSessions.olmId, olmId));
|
||||
}
|
||||
|
||||
export type SessionValidationResult =
|
||||
| { session: OlmSession; olm: Olm }
|
||||
| { session: null; olm: null };
|
||||
@@ -4,6 +4,9 @@ import { resourceSessions, ResourceSession } from "@server/db";
|
||||
import { db } from "@server/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import config from "@server/lib/config";
|
||||
import axios from "axios";
|
||||
import logger from "@server/logger";
|
||||
import { tokenManager } from "@server/lib/tokenManager";
|
||||
|
||||
export const SESSION_COOKIE_NAME =
|
||||
config.getRawConfig().server.session_cookie_name;
|
||||
@@ -62,6 +65,29 @@ export async function validateResourceSessionToken(
|
||||
token: string,
|
||||
resourceId: number
|
||||
): Promise<ResourceSessionValidationResult> {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.post(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/resource/${resourceId}/session/validate`, {
|
||||
token: token
|
||||
}, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error validating resource session token in hybrid mode:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error validating resource session token in hybrid mode:", error);
|
||||
}
|
||||
return { resourceSession: null };
|
||||
}
|
||||
}
|
||||
|
||||
const sessionId = encodeHexLowerCase(
|
||||
sha256(new TextEncoder().encode(token))
|
||||
);
|
||||
|
||||
1
server/build.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const build = "oss" as any;
|
||||
@@ -1,6 +1,6 @@
|
||||
import { join } from "path";
|
||||
import { readFileSync } from "fs";
|
||||
import { db } from "@server/db";
|
||||
import { db, resources, siteResources } from "@server/db";
|
||||
import { exitNodes, sites } from "@server/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { __DIRNAME } from "@server/lib/consts";
|
||||
@@ -34,6 +34,44 @@ export async function getUniqueSiteName(orgId: string): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUniqueResourceName(orgId: string): Promise<string> {
|
||||
let loops = 0;
|
||||
while (true) {
|
||||
if (loops > 100) {
|
||||
throw new Error("Could not generate a unique name");
|
||||
}
|
||||
|
||||
const name = generateName();
|
||||
const count = await db
|
||||
.select({ niceId: resources.niceId, orgId: resources.orgId })
|
||||
.from(resources)
|
||||
.where(and(eq(resources.niceId, name), eq(resources.orgId, orgId)));
|
||||
if (count.length === 0) {
|
||||
return name;
|
||||
}
|
||||
loops++;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUniqueSiteResourceName(orgId: string): Promise<string> {
|
||||
let loops = 0;
|
||||
while (true) {
|
||||
if (loops > 100) {
|
||||
throw new Error("Could not generate a unique name");
|
||||
}
|
||||
|
||||
const name = generateName();
|
||||
const count = await db
|
||||
.select({ niceId: siteResources.niceId, orgId: siteResources.orgId })
|
||||
.from(siteResources)
|
||||
.where(and(eq(siteResources.niceId, name), eq(siteResources.orgId, orgId)));
|
||||
if (count.length === 0) {
|
||||
return name;
|
||||
}
|
||||
loops++;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUniqueExitNodeEndpointName(): Promise<string> {
|
||||
let loops = 0;
|
||||
const count = await db
|
||||
@@ -59,7 +97,7 @@ export async function getUniqueExitNodeEndpointName(): Promise<string> {
|
||||
|
||||
|
||||
export function generateName(): string {
|
||||
return (
|
||||
const name = (
|
||||
names.descriptors[
|
||||
Math.floor(Math.random() * names.descriptors.length)
|
||||
] +
|
||||
@@ -68,4 +106,7 @@ export function generateName(): string {
|
||||
)
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, "-");
|
||||
|
||||
// clean out any non-alphanumeric characters except for dashes
|
||||
return name.replace(/[^a-z0-9-]/g, "");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { drizzle as DrizzlePostgres } from "drizzle-orm/node-postgres";
|
||||
import { Pool } from "pg";
|
||||
import { readConfigFile } from "@server/lib/readConfigFile";
|
||||
import { withReplicas } from "drizzle-orm/pg-core";
|
||||
|
||||
@@ -20,20 +21,33 @@ function createDb() {
|
||||
);
|
||||
}
|
||||
|
||||
const primary = DrizzlePostgres(connectionString);
|
||||
// Create connection pools instead of individual connections
|
||||
const primaryPool = new Pool({
|
||||
connectionString,
|
||||
max: 20,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 2000,
|
||||
});
|
||||
|
||||
const replicas = [];
|
||||
|
||||
if (!replicaConnections.length) {
|
||||
replicas.push(primary);
|
||||
replicas.push(DrizzlePostgres(primaryPool));
|
||||
} else {
|
||||
for (const conn of replicaConnections) {
|
||||
const replica = DrizzlePostgres(conn.connection_string);
|
||||
replicas.push(replica);
|
||||
const replicaPool = new Pool({
|
||||
connectionString: conn.connection_string,
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 2000,
|
||||
});
|
||||
replicas.push(DrizzlePostgres(replicaPool));
|
||||
}
|
||||
}
|
||||
|
||||
return withReplicas(primary, replicas as any);
|
||||
return withReplicas(DrizzlePostgres(primaryPool), replicas as any);
|
||||
}
|
||||
|
||||
export const db = createDb();
|
||||
export default db;
|
||||
export type Transaction = Parameters<Parameters<typeof db["transaction"]>[0]>[0];
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./driver";
|
||||
export * from "./schema";
|
||||
export * from "./schema";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||
import db from "./driver";
|
||||
import { db } from "./driver";
|
||||
import path from "path";
|
||||
|
||||
const migrationsFolder = path.join("server/migrations");
|
||||
|
||||
@@ -5,19 +5,26 @@ import {
|
||||
boolean,
|
||||
integer,
|
||||
bigint,
|
||||
real
|
||||
real,
|
||||
text
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { InferSelectModel } from "drizzle-orm";
|
||||
|
||||
export const domains = pgTable("domains", {
|
||||
domainId: varchar("domainId").primaryKey(),
|
||||
baseDomain: varchar("baseDomain").notNull(),
|
||||
configManaged: boolean("configManaged").notNull().default(false)
|
||||
configManaged: boolean("configManaged").notNull().default(false),
|
||||
type: varchar("type"), // "ns", "cname", "wildcard"
|
||||
verified: boolean("verified").notNull().default(false),
|
||||
failed: boolean("failed").notNull().default(false),
|
||||
tries: integer("tries").notNull().default(0)
|
||||
});
|
||||
|
||||
export const orgs = pgTable("orgs", {
|
||||
orgId: varchar("orgId").primaryKey(),
|
||||
name: varchar("name").notNull()
|
||||
name: varchar("name").notNull(),
|
||||
subnet: varchar("subnet"),
|
||||
createdAt: text("createdAt")
|
||||
});
|
||||
|
||||
export const orgDomains = pgTable("orgDomains", {
|
||||
@@ -42,27 +49,29 @@ export const sites = pgTable("sites", {
|
||||
}),
|
||||
name: varchar("name").notNull(),
|
||||
pubKey: varchar("pubKey"),
|
||||
subnet: varchar("subnet").notNull(),
|
||||
megabytesIn: real("bytesIn"),
|
||||
megabytesOut: real("bytesOut"),
|
||||
subnet: varchar("subnet"),
|
||||
megabytesIn: real("bytesIn").default(0),
|
||||
megabytesOut: real("bytesOut").default(0),
|
||||
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
||||
type: varchar("type").notNull(), // "newt" or "wireguard"
|
||||
online: boolean("online").notNull().default(false),
|
||||
dockerSocketEnabled: boolean("dockerSocketEnabled").notNull().default(true)
|
||||
address: varchar("address"),
|
||||
endpoint: varchar("endpoint"),
|
||||
publicKey: varchar("publicKey"),
|
||||
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
|
||||
listenPort: integer("listenPort"),
|
||||
dockerSocketEnabled: boolean("dockerSocketEnabled").notNull().default(true),
|
||||
remoteSubnets: text("remoteSubnets") // comma-separated list of subnets that this site can access
|
||||
});
|
||||
|
||||
export const resources = pgTable("resources", {
|
||||
resourceId: serial("resourceId").primaryKey(),
|
||||
siteId: integer("siteId")
|
||||
.references(() => sites.siteId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
orgId: varchar("orgId")
|
||||
.references(() => orgs.orgId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
niceId: text("niceId").notNull(),
|
||||
name: varchar("name").notNull(),
|
||||
subdomain: varchar("subdomain"),
|
||||
fullDomain: varchar("fullDomain"),
|
||||
@@ -78,12 +87,16 @@ export const resources = pgTable("resources", {
|
||||
emailWhitelistEnabled: boolean("emailWhitelistEnabled")
|
||||
.notNull()
|
||||
.default(false),
|
||||
isBaseDomain: boolean("isBaseDomain"),
|
||||
applyRules: boolean("applyRules").notNull().default(false),
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
stickySession: boolean("stickySession").notNull().default(false),
|
||||
tlsServerName: varchar("tlsServerName"),
|
||||
setHostHeader: varchar("setHostHeader")
|
||||
setHostHeader: varchar("setHostHeader"),
|
||||
enableProxy: boolean("enableProxy").default(true),
|
||||
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
|
||||
onDelete: "cascade"
|
||||
}),
|
||||
headers: text("headers"), // comma-separated list of headers to add to the request
|
||||
});
|
||||
|
||||
export const targets = pgTable("targets", {
|
||||
@@ -93,11 +106,18 @@ export const targets = pgTable("targets", {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
siteId: integer("siteId")
|
||||
.references(() => sites.siteId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
ip: varchar("ip").notNull(),
|
||||
method: varchar("method"),
|
||||
port: integer("port").notNull(),
|
||||
internalPort: integer("internalPort"),
|
||||
enabled: boolean("enabled").notNull().default(true)
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
path: text("path"),
|
||||
pathMatchType: text("pathMatchType"), // exact, prefix, regex
|
||||
});
|
||||
|
||||
export const exitNodes = pgTable("exitNodes", {
|
||||
@@ -107,7 +127,29 @@ export const exitNodes = pgTable("exitNodes", {
|
||||
endpoint: varchar("endpoint").notNull(),
|
||||
publicKey: varchar("publicKey").notNull(),
|
||||
listenPort: integer("listenPort").notNull(),
|
||||
reachableAt: varchar("reachableAt")
|
||||
reachableAt: varchar("reachableAt"),
|
||||
maxConnections: integer("maxConnections"),
|
||||
online: boolean("online").notNull().default(false),
|
||||
lastPing: integer("lastPing"),
|
||||
type: text("type").default("gerbil"), // gerbil, remoteExitNode
|
||||
region: varchar("region")
|
||||
});
|
||||
|
||||
export const siteResources = pgTable("siteResources", { // this is for the clients
|
||||
siteResourceId: serial("siteResourceId").primaryKey(),
|
||||
siteId: integer("siteId")
|
||||
.notNull()
|
||||
.references(() => sites.siteId, { onDelete: "cascade" }),
|
||||
orgId: varchar("orgId")
|
||||
.notNull()
|
||||
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||
niceId: varchar("niceId").notNull(),
|
||||
name: varchar("name").notNull(),
|
||||
protocol: varchar("protocol").notNull(),
|
||||
proxyPort: integer("proxyPort").notNull(),
|
||||
destinationPort: integer("destinationPort").notNull(),
|
||||
destinationIp: varchar("destinationIp").notNull(),
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
});
|
||||
|
||||
export const users = pgTable("user", {
|
||||
@@ -121,9 +163,12 @@ export const users = pgTable("user", {
|
||||
}),
|
||||
passwordHash: varchar("passwordHash"),
|
||||
twoFactorEnabled: boolean("twoFactorEnabled").notNull().default(false),
|
||||
twoFactorSetupRequested: boolean("twoFactorSetupRequested").default(false),
|
||||
twoFactorSecret: varchar("twoFactorSecret"),
|
||||
emailVerified: boolean("emailVerified").notNull().default(false),
|
||||
dateCreated: varchar("dateCreated").notNull(),
|
||||
termsAcceptedTimestamp: varchar("termsAcceptedTimestamp"),
|
||||
termsVersion: varchar("termsVersion"),
|
||||
serverAdmin: boolean("serverAdmin").notNull().default(false)
|
||||
});
|
||||
|
||||
@@ -131,6 +176,7 @@ export const newts = pgTable("newt", {
|
||||
newtId: varchar("id").primaryKey(),
|
||||
secretHash: varchar("secretHash").notNull(),
|
||||
dateCreated: varchar("dateCreated").notNull(),
|
||||
version: varchar("version"),
|
||||
siteId: integer("siteId").references(() => sites.siteId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
@@ -172,7 +218,8 @@ export const userOrgs = pgTable("userOrgs", {
|
||||
roleId: integer("roleId")
|
||||
.notNull()
|
||||
.references(() => roles.roleId),
|
||||
isOwner: boolean("isOwner").notNull().default(false)
|
||||
isOwner: boolean("isOwner").notNull().default(false),
|
||||
autoProvisioned: boolean("autoProvisioned").default(false)
|
||||
});
|
||||
|
||||
export const emailVerificationCodes = pgTable("emailVerificationCodes", {
|
||||
@@ -273,18 +320,6 @@ export const userResources = pgTable("userResources", {
|
||||
.references(() => resources.resourceId, { onDelete: "cascade" })
|
||||
});
|
||||
|
||||
export const limitsTable = pgTable("limits", {
|
||||
limitId: serial("limitId").primaryKey(),
|
||||
orgId: varchar("orgId")
|
||||
.references(() => orgs.orgId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
name: varchar("name").notNull(),
|
||||
value: bigint("value", { mode: "number" }).notNull(),
|
||||
description: varchar("description")
|
||||
});
|
||||
|
||||
export const userInvites = pgTable("userInvites", {
|
||||
inviteId: varchar("inviteId").primaryKey(),
|
||||
orgId: varchar("orgId")
|
||||
@@ -402,7 +437,7 @@ export const resourceRules = pgTable("resourceRules", {
|
||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
priority: integer("priority").notNull(),
|
||||
action: varchar("action").notNull(), // ACCEPT, DROP
|
||||
action: varchar("action").notNull(), // ACCEPT, DROP, PASS
|
||||
match: varchar("match").notNull(), // CIDR, PATH, IP
|
||||
value: varchar("value").notNull()
|
||||
});
|
||||
@@ -430,6 +465,7 @@ export const idpOidcConfig = pgTable("idpOidcConfig", {
|
||||
idpId: integer("idpId")
|
||||
.notNull()
|
||||
.references(() => idp.idpId, { onDelete: "cascade" }),
|
||||
variant: varchar("variant").notNull().default("oidc"),
|
||||
clientId: varchar("clientId").notNull(),
|
||||
clientSecret: varchar("clientSecret").notNull(),
|
||||
authUrl: varchar("authUrl").notNull(),
|
||||
@@ -491,6 +527,111 @@ export const idpOrg = pgTable("idpOrg", {
|
||||
orgMapping: varchar("orgMapping")
|
||||
});
|
||||
|
||||
export const clients = pgTable("clients", {
|
||||
clientId: serial("id").primaryKey(),
|
||||
orgId: varchar("orgId")
|
||||
.references(() => orgs.orgId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
.notNull(),
|
||||
exitNodeId: integer("exitNode").references(() => exitNodes.exitNodeId, {
|
||||
onDelete: "set null"
|
||||
}),
|
||||
name: varchar("name").notNull(),
|
||||
pubKey: varchar("pubKey"),
|
||||
subnet: varchar("subnet").notNull(),
|
||||
megabytesIn: real("bytesIn"),
|
||||
megabytesOut: real("bytesOut"),
|
||||
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
||||
lastPing: integer("lastPing"),
|
||||
type: varchar("type").notNull(), // "olm"
|
||||
online: boolean("online").notNull().default(false),
|
||||
// endpoint: varchar("endpoint"),
|
||||
lastHolePunch: integer("lastHolePunch"),
|
||||
maxConnections: integer("maxConnections")
|
||||
});
|
||||
|
||||
export const clientSites = pgTable("clientSites", {
|
||||
clientId: integer("clientId")
|
||||
.notNull()
|
||||
.references(() => clients.clientId, { onDelete: "cascade" }),
|
||||
siteId: integer("siteId")
|
||||
.notNull()
|
||||
.references(() => sites.siteId, { onDelete: "cascade" }),
|
||||
isRelayed: boolean("isRelayed").notNull().default(false),
|
||||
endpoint: varchar("endpoint")
|
||||
});
|
||||
|
||||
export const olms = pgTable("olms", {
|
||||
olmId: varchar("id").primaryKey(),
|
||||
secretHash: varchar("secretHash").notNull(),
|
||||
dateCreated: varchar("dateCreated").notNull(),
|
||||
version: text("version"),
|
||||
clientId: integer("clientId").references(() => clients.clientId, {
|
||||
onDelete: "cascade"
|
||||
})
|
||||
});
|
||||
|
||||
export const olmSessions = pgTable("clientSession", {
|
||||
sessionId: varchar("id").primaryKey(),
|
||||
olmId: varchar("olmId")
|
||||
.notNull()
|
||||
.references(() => olms.olmId, { onDelete: "cascade" }),
|
||||
expiresAt: bigint("expiresAt", { mode: "number" }).notNull()
|
||||
});
|
||||
|
||||
export const userClients = pgTable("userClients", {
|
||||
userId: varchar("userId")
|
||||
.notNull()
|
||||
.references(() => users.userId, { onDelete: "cascade" }),
|
||||
clientId: integer("clientId")
|
||||
.notNull()
|
||||
.references(() => clients.clientId, { onDelete: "cascade" })
|
||||
});
|
||||
|
||||
export const roleClients = pgTable("roleClients", {
|
||||
roleId: integer("roleId")
|
||||
.notNull()
|
||||
.references(() => roles.roleId, { onDelete: "cascade" }),
|
||||
clientId: integer("clientId")
|
||||
.notNull()
|
||||
.references(() => clients.clientId, { onDelete: "cascade" })
|
||||
});
|
||||
|
||||
export const securityKeys = pgTable("webauthnCredentials", {
|
||||
credentialId: varchar("credentialId").primaryKey(),
|
||||
userId: varchar("userId")
|
||||
.notNull()
|
||||
.references(() => users.userId, {
|
||||
onDelete: "cascade"
|
||||
}),
|
||||
publicKey: varchar("publicKey").notNull(),
|
||||
signCount: integer("signCount").notNull(),
|
||||
transports: varchar("transports"),
|
||||
name: varchar("name"),
|
||||
lastUsed: varchar("lastUsed").notNull(),
|
||||
dateCreated: varchar("dateCreated").notNull(),
|
||||
securityKeyName: varchar("securityKeyName")
|
||||
});
|
||||
|
||||
export const webauthnChallenge = pgTable("webauthnChallenge", {
|
||||
sessionId: varchar("sessionId").primaryKey(),
|
||||
challenge: varchar("challenge").notNull(),
|
||||
securityKeyName: varchar("securityKeyName"),
|
||||
userId: varchar("userId").references(() => users.userId, {
|
||||
onDelete: "cascade"
|
||||
}),
|
||||
expiresAt: bigint("expiresAt", { mode: "number" }).notNull() // Unix timestamp
|
||||
});
|
||||
|
||||
export const setupTokens = pgTable("setupTokens", {
|
||||
tokenId: varchar("tokenId").primaryKey(),
|
||||
token: varchar("token").notNull(),
|
||||
used: boolean("used").notNull().default(false),
|
||||
dateCreated: varchar("dateCreated").notNull(),
|
||||
dateUsed: varchar("dateUsed")
|
||||
});
|
||||
|
||||
export type Org = InferSelectModel<typeof orgs>;
|
||||
export type User = InferSelectModel<typeof users>;
|
||||
export type Site = InferSelectModel<typeof sites>;
|
||||
@@ -513,7 +654,6 @@ export type RoleSite = InferSelectModel<typeof roleSites>;
|
||||
export type UserSite = InferSelectModel<typeof userSites>;
|
||||
export type RoleResource = InferSelectModel<typeof roleResources>;
|
||||
export type UserResource = InferSelectModel<typeof userResources>;
|
||||
export type Limit = InferSelectModel<typeof limitsTable>;
|
||||
export type UserInvite = InferSelectModel<typeof userInvites>;
|
||||
export type UserOrg = InferSelectModel<typeof userOrgs>;
|
||||
export type ResourceSession = InferSelectModel<typeof resourceSessions>;
|
||||
@@ -530,3 +670,13 @@ export type Idp = InferSelectModel<typeof idp>;
|
||||
export type ApiKey = InferSelectModel<typeof apiKeys>;
|
||||
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
|
||||
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
|
||||
export type Client = InferSelectModel<typeof clients>;
|
||||
export type ClientSite = InferSelectModel<typeof clientSites>;
|
||||
export type Olm = InferSelectModel<typeof olms>;
|
||||
export type OlmSession = InferSelectModel<typeof olmSessions>;
|
||||
export type UserClient = InferSelectModel<typeof userClients>;
|
||||
export type RoleClient = InferSelectModel<typeof roleClients>;
|
||||
export type OrgDomains = InferSelectModel<typeof orgDomains>;
|
||||
export type SiteResource = InferSelectModel<typeof siteResources>;
|
||||
export type SetupToken = InferSelectModel<typeof setupTokens>;
|
||||
export type HostMeta = InferSelectModel<typeof hostMeta>;
|
||||
|
||||
277
server/db/queries/verifySessionQueries.ts
Normal file
@@ -0,0 +1,277 @@
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
Resource,
|
||||
ResourcePassword,
|
||||
ResourcePincode,
|
||||
ResourceRule,
|
||||
resourcePassword,
|
||||
resourcePincode,
|
||||
resourceRules,
|
||||
resources,
|
||||
roleResources,
|
||||
sessions,
|
||||
userOrgs,
|
||||
userResources,
|
||||
users
|
||||
} from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import axios from "axios";
|
||||
import config from "@server/lib/config";
|
||||
import logger from "@server/logger";
|
||||
import { tokenManager } from "@server/lib/tokenManager";
|
||||
|
||||
export type ResourceWithAuth = {
|
||||
resource: Resource | null;
|
||||
pincode: ResourcePincode | null;
|
||||
password: ResourcePassword | null;
|
||||
};
|
||||
|
||||
export type UserSessionWithUser = {
|
||||
session: any;
|
||||
user: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get resource by domain with pincode and password information
|
||||
*/
|
||||
export async function getResourceByDomain(
|
||||
domain: string
|
||||
): Promise<ResourceWithAuth | null> {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/resource/domain/${domain}`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const [result] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.leftJoin(
|
||||
resourcePincode,
|
||||
eq(resourcePincode.resourceId, resources.resourceId)
|
||||
)
|
||||
.leftJoin(
|
||||
resourcePassword,
|
||||
eq(resourcePassword.resourceId, resources.resourceId)
|
||||
)
|
||||
.where(eq(resources.fullDomain, domain))
|
||||
.limit(1);
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
resource: result.resources,
|
||||
pincode: result.resourcePincode,
|
||||
password: result.resourcePassword
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user session with user information
|
||||
*/
|
||||
export async function getUserSessionWithUser(
|
||||
userSessionId: string
|
||||
): Promise<UserSessionWithUser | null> {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/session/${userSessionId}`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const [res] = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.leftJoin(users, eq(users.userId, sessions.userId))
|
||||
.where(eq(sessions.sessionId, userSessionId));
|
||||
|
||||
if (!res) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
session: res.session,
|
||||
user: res.user
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user organization role
|
||||
*/
|
||||
export async function getUserOrgRole(userId: string, orgId: string) {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/user/${userId}/org/${orgId}/role`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, userId),
|
||||
eq(userOrgs.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return userOrgRole.length > 0 ? userOrgRole[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if role has access to resource
|
||||
*/
|
||||
export async function getRoleResourceAccess(resourceId: number, roleId: number) {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/role/${roleId}/resource/${resourceId}/access`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const roleResourceAccess = await db
|
||||
.select()
|
||||
.from(roleResources)
|
||||
.where(
|
||||
and(
|
||||
eq(roleResources.resourceId, resourceId),
|
||||
eq(roleResources.roleId, roleId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return roleResourceAccess.length > 0 ? roleResourceAccess[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has direct access to resource
|
||||
*/
|
||||
export async function getUserResourceAccess(userId: string, resourceId: number) {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/user/${userId}/resource/${resourceId}/access`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const userResourceAccess = await db
|
||||
.select()
|
||||
.from(userResources)
|
||||
.where(
|
||||
and(
|
||||
eq(userResources.userId, userId),
|
||||
eq(userResources.resourceId, resourceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return userResourceAccess.length > 0 ? userResourceAccess[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource rules for a given resource
|
||||
*/
|
||||
export async function getResourceRules(resourceId: number): Promise<ResourceRule[]> {
|
||||
if (config.isManagedMode()) {
|
||||
try {
|
||||
const response = await axios.get(`${config.getRawConfig().managed?.endpoint}/api/v1/hybrid/resource/${resourceId}/rules`, await tokenManager.getAuthHeader());
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error("Error fetching config in verify session:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method
|
||||
});
|
||||
} else {
|
||||
logger.error("Error fetching config in verify session:", error);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const rules = await db
|
||||
.select()
|
||||
.from(resourceRules)
|
||||
.where(eq(resourceRules.resourceId, resourceId));
|
||||
|
||||
return rules;
|
||||
}
|
||||
@@ -2,12 +2,12 @@ import { drizzle as DrizzleSqlite } from "drizzle-orm/better-sqlite3";
|
||||
import Database from "better-sqlite3";
|
||||
import * as schema from "./schema";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import fs from "fs";
|
||||
import { APP_PATH } from "@server/lib/consts";
|
||||
import { existsSync, mkdirSync } from "fs";
|
||||
|
||||
export const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||
export const exists = await checkFileExists(location);
|
||||
export const exists = checkFileExists(location);
|
||||
|
||||
bootstrapVolume();
|
||||
|
||||
@@ -18,10 +18,11 @@ function createDb() {
|
||||
|
||||
export const db = createDb();
|
||||
export default db;
|
||||
export type Transaction = Parameters<Parameters<typeof db["transaction"]>[0]>[0];
|
||||
|
||||
async function checkFileExists(filePath: string): Promise<boolean> {
|
||||
function checkFileExists(filePath: string): boolean {
|
||||
try {
|
||||
await fs.access(filePath);
|
||||
fs.accessSync(filePath);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import db from "./driver";
|
||||
import { db } from "./driver";
|
||||
import path from "path";
|
||||
|
||||
const migrationsFolder = path.join("server/migrations");
|
||||
|
||||