Compare commits
61 Commits
release-1.
...
dev-1.10.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7872770a1 | ||
|
|
004ddcb2bb | ||
|
|
8eeef84b8a | ||
|
|
dc88ae5e8b | ||
|
|
cb478477e9 | ||
|
|
b7bd1e50b3 | ||
|
|
230ab2f737 | ||
|
|
042bf255ef | ||
|
|
f7e99b5af5 | ||
|
|
8fa093ae60 | ||
|
|
dd62b77c79 | ||
|
|
264682c5ad | ||
|
|
7210381f17 | ||
|
|
c0f4f1d74b | ||
|
|
f957959a86 | ||
|
|
a54dbe5b46 | ||
|
|
ac1cf82bba | ||
|
|
de556e3911 | ||
|
|
9be6b945c8 | ||
|
|
1aebbee21e | ||
|
|
80c09aef7d | ||
|
|
115a1fd7f0 | ||
|
|
a1c260ad22 | ||
|
|
18aa4f4877 | ||
|
|
8fc038e59b | ||
|
|
aea87be4d3 | ||
|
|
7caa32b364 | ||
|
|
868ac39b71 | ||
|
|
8ae8520c44 | ||
|
|
8ce4c6f364 | ||
|
|
a9a1a4b3d5 | ||
|
|
2e3f7e10c7 | ||
|
|
d821373b15 | ||
|
|
816172d67b | ||
|
|
ceff07c685 | ||
|
|
1eb28dec8b | ||
|
|
2b6361cbb6 | ||
|
|
e6870f962a | ||
|
|
99b0181c45 | ||
|
|
58945288e0 | ||
|
|
afb66a1098 | ||
|
|
5f080be4ee | ||
|
|
4648549e74 | ||
|
|
f5d948aa45 | ||
|
|
81d506afba | ||
|
|
4150faa558 | ||
|
|
7ecfb4d685 | ||
|
|
614f2f84ec | ||
|
|
af63fe1b7b | ||
|
|
4896b71b01 | ||
|
|
69f3f88ae5 | ||
|
|
d632f2b91f | ||
|
|
5366cb24ef | ||
|
|
177e783f92 | ||
|
|
1a2179c345 | ||
|
|
bdf9ea282e | ||
|
|
6feb8405ce | ||
|
|
2ee1318ded | ||
|
|
51e6826c95 | ||
|
|
0216a2d2fe | ||
|
|
8106999d1e |
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -17,7 +17,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
27
.github/workflows/electron.yml
vendored
27
.github/workflows/electron.yml
vendored
@@ -356,7 +356,7 @@ jobs:
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
if: github.event.inputs.build_type == 'macos' || github.event.inputs.build_type == 'all'
|
||||
if: (github.event.inputs.build_type == 'macos' || github.event.inputs.build_type == 'all') && github.event.inputs.artifact_destination != 'submit'
|
||||
needs: []
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -584,7 +584,7 @@ jobs:
|
||||
|
||||
submit-to-chocolatey:
|
||||
runs-on: windows-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit'
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'windows' || github.event.inputs.build_type == '')
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -689,7 +689,7 @@ jobs:
|
||||
|
||||
submit-to-flatpak:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit'
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'linux' || github.event.inputs.build_type == '')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -776,7 +776,7 @@ jobs:
|
||||
|
||||
submit-to-homebrew:
|
||||
runs-on: macos-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit'
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'macos')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -801,11 +801,20 @@ jobs:
|
||||
URL="https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$DMG_NAME"
|
||||
|
||||
mkdir -p release_asset
|
||||
PATH="release_asset/$DMG_NAME"
|
||||
DOWNLOAD_PATH="release_asset/$DMG_NAME"
|
||||
echo "Downloading DMG from $URL"
|
||||
curl -L -o "$PATH" "$URL"
|
||||
|
||||
CHECKSUM=$(shasum -a 256 "$PATH" | awk '{print $1}')
|
||||
if command -v curl &> /dev/null; then
|
||||
curl -L -o "$DOWNLOAD_PATH" "$URL"
|
||||
elif command -v wget &> /dev/null; then
|
||||
wget -O "$DOWNLOAD_PATH" "$URL"
|
||||
else
|
||||
echo "Neither curl nor wget is available, installing curl"
|
||||
brew install curl
|
||||
curl -L -o "$DOWNLOAD_PATH" "$URL"
|
||||
fi
|
||||
|
||||
CHECKSUM=$(shasum -a 256 "$DOWNLOAD_PATH" | awk '{print $1}')
|
||||
|
||||
echo "dmg_name=$DMG_NAME" >> $GITHUB_OUTPUT
|
||||
echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT
|
||||
@@ -872,7 +881,7 @@ jobs:
|
||||
|
||||
submit-to-testflight:
|
||||
runs-on: macos-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit'
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'macos')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -977,7 +986,7 @@ jobs:
|
||||
- name: Deploy to App Store Connect (TestFlight)
|
||||
if: steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: |
|
||||
PKG_FILE=$(find artifact-mas -name "*.pkg" -type f | head -n 1)
|
||||
PKG_FILE=$(find release -name "termix_macos_universal_mas.pkg" -type f | head -n 1)
|
||||
if [ -z "$PKG_FILE" ]; then
|
||||
echo "PKG file not found, exiting."
|
||||
exit 1
|
||||
|
||||
32
.github/workflows/openapi.yml
vendored
Normal file
32
.github/workflows/openapi.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Generate OpenAPI Specification
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
generate-openapi:
|
||||
name: Generate OpenAPI JSON
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Generate OpenAPI specification
|
||||
run: npm run generate:openapi
|
||||
|
||||
- name: Upload OpenAPI artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: openapi-spec
|
||||
path: openapi.json
|
||||
retention-days: 90
|
||||
437
.github/workflows/translate.yml
vendored
437
.github/workflows/translate.yml
vendored
@@ -1,437 +0,0 @@
|
||||
name: Auto Translate
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
translate-zh:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t zh --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-zh
|
||||
path: src/locales/zh.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-ru:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ru --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-ru
|
||||
path: src/locales/ru.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-pt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t pt --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-pt
|
||||
path: src/locales/pt.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-fr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t fr --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-fr
|
||||
path: src/locales/fr.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-es:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t es --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-es
|
||||
path: src/locales/es.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-de:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t de --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-de
|
||||
path: src/locales/de.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-hi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t hi --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-hi
|
||||
path: src/locales/hi.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-bn:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t bn --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-bn
|
||||
path: src/locales/bn.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-ja:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ja --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-ja
|
||||
path: src/locales/ja.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-vi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t vi --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-vi
|
||||
path: src/locales/vi.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-tr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t tr --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-tr
|
||||
path: src/locales/tr.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-ko:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ko --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-ko
|
||||
path: src/locales/ko.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-it:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t it --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-it
|
||||
path: src/locales/it.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-he:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t he --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-he
|
||||
path: src/locales/he.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-ar:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ar --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-ar
|
||||
path: src/locales/ar.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-pl:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t pl --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-pl
|
||||
path: src/locales/pl.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-nl:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t nl --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-nl
|
||||
path: src/locales/nl.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-sv:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t sv --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-sv
|
||||
path: src/locales/sv.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-id:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t id --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-id
|
||||
path: src/locales/id.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-th:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t th --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-th
|
||||
path: src/locales/th.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-uk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t uk --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-uk
|
||||
path: src/locales/uk.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-cs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t cs --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-cs
|
||||
path: src/locales/cs.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-ro:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ro --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-ro
|
||||
path: src/locales/ro.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-el:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t el --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-el
|
||||
path: src/locales/el.json
|
||||
continue-on-error: true
|
||||
|
||||
translate-nb:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t nb --maxLinesPerRequest 1
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: translations-nb
|
||||
path: src/locales/nb.json
|
||||
continue-on-error: true
|
||||
|
||||
create-pr:
|
||||
needs:
|
||||
[
|
||||
translate-zh,
|
||||
translate-ru,
|
||||
translate-pt,
|
||||
translate-fr,
|
||||
translate-es,
|
||||
translate-de,
|
||||
translate-hi,
|
||||
translate-bn,
|
||||
translate-ja,
|
||||
translate-vi,
|
||||
translate-tr,
|
||||
translate-ko,
|
||||
translate-it,
|
||||
translate-he,
|
||||
translate-ar,
|
||||
translate-pl,
|
||||
translate-nl,
|
||||
translate-sv,
|
||||
translate-id,
|
||||
translate-th,
|
||||
translate-uk,
|
||||
translate-cs,
|
||||
translate-ro,
|
||||
translate-el,
|
||||
translate-nb,
|
||||
]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: translations-temp
|
||||
|
||||
- name: Move translations to src/locales
|
||||
run: |
|
||||
cp translations-temp/translations-zh/zh.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-ru/ru.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-pt/pt.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-fr/fr.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-es/es.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-de/de.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-hi/hi.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-bn/bn.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-ja/ja.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-vi/vi.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-tr/tr.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-ko/ko.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-it/it.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-he/he.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-ar/ar.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-pl/pl.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-nl/nl.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-sv/sv.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-id/id.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-th/th.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-uk/uk.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-cs/cs.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-ro/ro.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-el/el.json src/locales/ 2>/dev/null || true
|
||||
cp translations-temp/translations-nb/nb.json src/locales/ 2>/dev/null || true
|
||||
rm -rf translations-temp
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
commit-message: "chore: auto-translate to multiple languages"
|
||||
branch: translations-update
|
||||
delete-branch: true
|
||||
title: "chore: Update translations for all languages"
|
||||
@@ -1,6 +1,6 @@
|
||||
cask "termix" do
|
||||
version "1.9.0"
|
||||
sha256 "8fedd242b3cae1ebfd0c391a36f1c246a26ecac258b02478ee8dea2f33cd6d96"
|
||||
version "1.10.0"
|
||||
sha256 "327c5026006c949f992447835aa6754113f731065b410bedbfa5da5af7cb2386"
|
||||
|
||||
url "https://github.com/Termix-SSH/Termix/releases/download/release-#{version}-tag/termix_macos_universal_dmg.dmg"
|
||||
name "Termix"
|
||||
|
||||
24
README.md
24
README.md
@@ -16,17 +16,6 @@
|
||||
<small style="color: #666;">Achieved on September 1st, 2025</small>
|
||||
</p>
|
||||
|
||||
#### Top Technologies
|
||||
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/Termix-SSH/Termix">
|
||||
@@ -85,6 +74,7 @@ Supported Devices:
|
||||
- Chocolatey Package Manager
|
||||
- Linux (x64/ia32)
|
||||
- Portable
|
||||
- AUR
|
||||
- AppImage
|
||||
- Deb
|
||||
- Flatpak
|
||||
@@ -120,6 +110,18 @@ volumes:
|
||||
driver: local
|
||||
```
|
||||
|
||||
# Sponsors
|
||||
|
||||
<p align="left">
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="50" alt="DigitalOcean">
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="50" alt="Crowdin">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# Support
|
||||
|
||||
If you need help or want to request a feature with Termix, visit the [Issues](https://github.com/Termix-SSH/Support/issues) page, log in, and press `New Issue`.
|
||||
|
||||
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: /src/locales/en.json
|
||||
translation: /src/locales/translated/%two_letters_code%.json
|
||||
@@ -19,7 +19,7 @@ COPY . .
|
||||
RUN find public/fonts -name "*.ttf" ! -name "*Regular.ttf" ! -name "*Bold.ttf" ! -name "*Italic.ttf" -delete
|
||||
|
||||
RUN npm cache clean --force && \
|
||||
npm run build
|
||||
NODE_OPTIONS="--max-old-space-size=2048" npm run build
|
||||
|
||||
# Stage 3: Build backend
|
||||
FROM deps AS backend-builder
|
||||
@@ -74,6 +74,9 @@ VOLUME ["/app/data"]
|
||||
|
||||
EXPOSE ${PORT} 30001 30002 30003 30004 30005 30006
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD node -e "require('http').get('http://localhost:30001/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"
|
||||
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /app/nginx/nginx.pid;
|
||||
error_log /app/nginx/logs/error.log warn;
|
||||
|
||||
@@ -199,6 +201,18 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /ssh/quick-connect {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /ssh/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -286,6 +300,15 @@ http {
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ ^/network-topology(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -335,6 +358,15 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/dashboard/preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30006;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ^~ /docker/console/ {
|
||||
proxy_pass http://127.0.0.1:30008/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /app/nginx/nginx.pid;
|
||||
error_log /app/nginx/logs/error.log warn;
|
||||
|
||||
@@ -188,6 +190,18 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /ssh/quick-connect {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /ssh/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -275,6 +289,15 @@ http {
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ ^/network-topology(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -324,6 +347,15 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/dashboard/preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30006;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ^~ /docker/console/ {
|
||||
proxy_pass http://127.0.0.1:30008/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta name="theme-color" content="#09090b" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Termix" />
|
||||
<link rel="apple-touch-icon" href="/icons/512x512.png" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title>Termix</title>
|
||||
<style>
|
||||
.hide-scrollbar {
|
||||
|
||||
2305
openapi.json
2305
openapi.json
File diff suppressed because it is too large
Load Diff
262
package-lock.json
generated
262
package-lock.json
generated
@@ -34,6 +34,7 @@
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/cookie-parser": "^1.4.9",
|
||||
"@types/cytoscape": "^3.21.9",
|
||||
"@types/jszip": "^3.4.0",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
@@ -56,6 +57,7 @@
|
||||
"cmdk": "^1.1.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"cytoscape": "^3.33.1",
|
||||
"dotenv": "^17.2.0",
|
||||
"drizzle-orm": "^0.44.3",
|
||||
"express": "^5.1.0",
|
||||
@@ -72,6 +74,7 @@
|
||||
"node-fetch": "^3.3.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.1.0",
|
||||
"react-cytoscapejs": "^2.0.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-h5-audio-player": "^3.10.1",
|
||||
"react-hook-form": "^7.60.0",
|
||||
@@ -122,11 +125,60 @@
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.3",
|
||||
"prettier": "3.6.2",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript-eslint": "^8.40.0",
|
||||
"vite": "^7.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
|
||||
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/openapi-schemas": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
||||
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-methods": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
||||
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-parser": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
||||
"@apidevtools/openapi-schemas": "^2.0.4",
|
||||
"@apidevtools/swagger-methods": "^3.0.2",
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"z-schema": "^5.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"openapi-types": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
||||
@@ -2619,6 +2671,13 @@
|
||||
"url": "https://opencollective.com/js-sdsl"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lezer/common": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz",
|
||||
@@ -5228,6 +5287,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cytoscape": {
|
||||
"version": "3.21.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.9.tgz",
|
||||
"integrity": "sha512-JyrG4tllI6jvuISPjHK9j2Xv/LTbnLekLke5otGStjFluIyA9JjgnvgZrSBsp8cEDpiTjwgZUZwpPv8TSBcoLw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/d3-array": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
|
||||
@@ -6958,6 +7023,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/call-me-maybe": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -7776,6 +7848,15 @@
|
||||
"integrity": "sha512-cjrsQufETwxjvwZbYbKBCJNvmQ2++G9AvT45zDi7NXL9k2PdVcs2h0jQz96J6G4TMKRCcEsoJ+QTgQD00Igtjw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cytoscape": {
|
||||
"version": "3.33.1",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
|
||||
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-array": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
||||
@@ -8304,6 +8385,19 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz",
|
||||
@@ -12195,6 +12289,14 @@
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
||||
"deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
@@ -12207,6 +12309,14 @@
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
@@ -14068,6 +14178,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi-types": {
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
@@ -15109,6 +15227,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-cytoscapejs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-cytoscapejs/-/react-cytoscapejs-2.0.0.tgz",
|
||||
"integrity": "sha512-t3SSl1DQy7+JQjN+8QHi1anEJlM3i3aAeydHTsJwmjo/isyKK7Rs7oCvU6kZsB9NwZidzZQR21Vm2PcBLG/Tjg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cytoscape": "^3.2.19",
|
||||
"react": ">=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
@@ -16717,6 +16848,95 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc": {
|
||||
"version": "6.2.8",
|
||||
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
|
||||
"integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "6.2.0",
|
||||
"doctrine": "3.0.0",
|
||||
"glob": "7.1.6",
|
||||
"lodash.mergewith": "^4.6.2",
|
||||
"swagger-parser": "^10.0.3",
|
||||
"yaml": "2.0.0-1"
|
||||
},
|
||||
"bin": {
|
||||
"swagger-jsdoc": "bin/swagger-jsdoc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/commander": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
|
||||
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/yaml": {
|
||||
"version": "2.0.0-1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
||||
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-parser": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
|
||||
@@ -17566,6 +17786,16 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.15.26",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz",
|
||||
"integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@@ -18120,6 +18350,38 @@
|
||||
"integrity": "sha512-YHDIOAqgRpfl1Ois9HcB8UFtWOxK8KJrV5TXpImj4BKYP1rWT04f/fMM9tQ9SYZlBKukT7NR+9wcI3UpB5BMDQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/z-schema": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
|
||||
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.7.0"
|
||||
},
|
||||
"bin": {
|
||||
"z-schema": "bin/z-schema"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"commander": "^9.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/z-schema/node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "termix",
|
||||
"private": true,
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"description": "A web-based server management platform with SSH terminal, tunneling, and file editing capabilities",
|
||||
"author": "Karmaa",
|
||||
"main": "electron/main.cjs",
|
||||
@@ -17,6 +17,7 @@
|
||||
"build": "vite build && tsc -p tsconfig.node.json",
|
||||
"build:backend": "tsc -p tsconfig.node.json",
|
||||
"dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/backend/starter.js",
|
||||
"generate:openapi": "tsc -p tsconfig.node.json && node ./dist/backend/backend/swagger.js",
|
||||
"preview": "vite preview",
|
||||
"electron:dev": "concurrently \"npm run dev\" \"powershell -c \\\"Start-Sleep -Seconds 5\\\" && electron .\"",
|
||||
"build:win-portable": "npm run build && electron-builder --win --dir",
|
||||
@@ -53,6 +54,7 @@
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/cookie-parser": "^1.4.9",
|
||||
"@types/cytoscape": "^3.21.9",
|
||||
"@types/jszip": "^3.4.0",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
@@ -75,6 +77,7 @@
|
||||
"cmdk": "^1.1.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"cytoscape": "^3.33.1",
|
||||
"dotenv": "^17.2.0",
|
||||
"drizzle-orm": "^0.44.3",
|
||||
"express": "^5.1.0",
|
||||
@@ -91,6 +94,7 @@
|
||||
"node-fetch": "^3.3.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.1.0",
|
||||
"react-cytoscapejs": "^2.0.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-h5-audio-player": "^3.10.1",
|
||||
"react-hook-form": "^7.60.0",
|
||||
@@ -141,6 +145,7 @@
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.3",
|
||||
"prettier": "3.6.2",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript-eslint": "^8.40.0",
|
||||
"vite": "^7.1.5"
|
||||
|
||||
40
public/manifest.json
Normal file
40
public/manifest.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "Termix",
|
||||
"short_name": "Termix",
|
||||
"description": "A web-based server management platform with SSH terminal, tunneling, and file editing capabilities",
|
||||
"theme_color": "#09090b",
|
||||
"background_color": "#09090b",
|
||||
"display": "standalone",
|
||||
"orientation": "any",
|
||||
"scope": "/",
|
||||
"start_url": "/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icons/64x64.png",
|
||||
"sizes": "64x64",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icons/128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icons/256x256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icons/512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
],
|
||||
"categories": ["utilities", "developer", "productivity"]
|
||||
}
|
||||
120
public/sw.js
Normal file
120
public/sw.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Termix Service Worker
|
||||
* Handles caching for offline PWA support
|
||||
*/
|
||||
|
||||
const CACHE_NAME = "termix-v1";
|
||||
const STATIC_ASSETS = [
|
||||
"/",
|
||||
"/index.html",
|
||||
"/manifest.json",
|
||||
"/favicon.ico",
|
||||
"/icons/48x48.png",
|
||||
"/icons/128x128.png",
|
||||
"/icons/256x256.png",
|
||||
"/icons/512x512.png",
|
||||
];
|
||||
|
||||
// Install event - cache static assets
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
console.log("[SW] Caching static assets");
|
||||
return cache.addAll(STATIC_ASSETS);
|
||||
})
|
||||
.then(() => {
|
||||
// Activate immediately without waiting
|
||||
return self.skipWaiting();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// Activate event - clean up old caches
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((cacheNames) => {
|
||||
return Promise.all(
|
||||
cacheNames
|
||||
.filter((name) => name !== CACHE_NAME)
|
||||
.map((name) => {
|
||||
console.log("[SW] Deleting old cache:", name);
|
||||
return caches.delete(name);
|
||||
}),
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
// Take control of all pages immediately
|
||||
return self.clients.claim();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch event - serve from cache, fall back to network
|
||||
self.addEventListener("fetch", (event) => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
// Skip non-GET requests
|
||||
if (request.method !== "GET") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip API requests - these must be online
|
||||
if (url.pathname.startsWith("/api/") || url.pathname.startsWith("/ws")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip cross-origin requests
|
||||
if (url.origin !== self.location.origin) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For navigation requests (HTML), use network-first
|
||||
if (request.mode === "navigate") {
|
||||
event.respondWith(
|
||||
fetch(request)
|
||||
.then((response) => {
|
||||
// Clone and cache the response
|
||||
const responseClone = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
cache.put(request, responseClone);
|
||||
});
|
||||
return response;
|
||||
})
|
||||
.catch(() => {
|
||||
// Offline: return cached index.html
|
||||
return caches.match("/index.html");
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// For all other assets, use cache-first
|
||||
event.respondWith(
|
||||
caches.match(request).then((cachedResponse) => {
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
// Not in cache, fetch from network
|
||||
return fetch(request).then((response) => {
|
||||
// Don't cache non-successful responses
|
||||
if (!response || response.status !== 200 || response.type !== "basic") {
|
||||
return response;
|
||||
}
|
||||
|
||||
// Clone and cache the response
|
||||
const responseClone = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
cache.put(request, responseClone);
|
||||
});
|
||||
|
||||
return response;
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -1,9 +1,14 @@
|
||||
import express from "express";
|
||||
import cors from "cors";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { getDb } from "./database/db/index.js";
|
||||
import { recentActivity, sshData, hostAccess } from "./database/db/schema.js";
|
||||
import { eq, and, desc, or } from "drizzle-orm";
|
||||
import { getDb, DatabaseSaveTrigger } from "./database/db/index.js";
|
||||
import {
|
||||
recentActivity,
|
||||
sshData,
|
||||
hostAccess,
|
||||
dashboardPreferences,
|
||||
} from "./database/db/schema.js";
|
||||
import { eq, and, desc, or, sql } from "drizzle-orm";
|
||||
import { dashboardLogger } from "./utils/logger.js";
|
||||
import { SimpleDBOps } from "./utils/simple-db-ops.js";
|
||||
import { AuthManager } from "./utils/auth-manager.js";
|
||||
@@ -58,6 +63,31 @@ app.use(express.json({ limit: "1mb" }));
|
||||
|
||||
app.use(authManager.createAuthMiddleware());
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /uptime:
|
||||
* get:
|
||||
* summary: Get server uptime
|
||||
* description: Returns the uptime of the server in various formats.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Server uptime information.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* uptimeMs:
|
||||
* type: number
|
||||
* uptimeSeconds:
|
||||
* type: number
|
||||
* formatted:
|
||||
* type: string
|
||||
* 500:
|
||||
* description: Failed to get uptime.
|
||||
*/
|
||||
app.get("/uptime", async (req, res) => {
|
||||
try {
|
||||
const uptimeMs = Date.now() - serverStartTime;
|
||||
@@ -77,6 +107,28 @@ app.get("/uptime", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /activity/recent:
|
||||
* get:
|
||||
* summary: Get recent activity
|
||||
* description: Fetches the most recent activities for the authenticated user.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: limit
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: The maximum number of activities to return.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of recent activities.
|
||||
* 401:
|
||||
* description: Session expired.
|
||||
* 500:
|
||||
* description: Failed to get recent activity.
|
||||
*/
|
||||
app.get("/activity/recent", async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -108,6 +160,40 @@ app.get("/activity/recent", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /activity/log:
|
||||
* post:
|
||||
* summary: Log a new activity
|
||||
* description: Logs a new user activity, such as accessing a terminal or file manager. This endpoint is rate-limited.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* enum: [terminal, file_manager, server_stats, tunnel, docker]
|
||||
* hostId:
|
||||
* type: integer
|
||||
* hostName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Activity logged successfully or rate-limited.
|
||||
* 400:
|
||||
* description: Invalid request body.
|
||||
* 401:
|
||||
* description: Session expired.
|
||||
* 404:
|
||||
* description: Host not found or access denied.
|
||||
* 500:
|
||||
* description: Failed to log activity.
|
||||
*/
|
||||
app.post("/activity/log", async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -224,6 +310,22 @@ app.post("/activity/log", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /activity/reset:
|
||||
* delete:
|
||||
* summary: Reset recent activity
|
||||
* description: Clears all recent activity for the authenticated user.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Recent activity cleared.
|
||||
* 401:
|
||||
* description: Session expired.
|
||||
* 500:
|
||||
* description: Failed to reset activity.
|
||||
*/
|
||||
app.delete("/activity/reset", async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -253,6 +355,166 @@ app.delete("/activity/reset", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /dashboard/preferences:
|
||||
* get:
|
||||
* summary: Get dashboard layout preferences
|
||||
* description: Returns the user's customized dashboard layout settings. If no preferences exist, returns default layout.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Dashboard preferences retrieved
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* cards:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* enabled:
|
||||
* type: boolean
|
||||
* order:
|
||||
* type: integer
|
||||
* gridColumns:
|
||||
* type: integer
|
||||
* 401:
|
||||
* description: Session expired
|
||||
* 500:
|
||||
* description: Failed to get preferences
|
||||
*/
|
||||
app.get("/dashboard/preferences", async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
if (!SimpleDBOps.isUserDataUnlocked(userId)) {
|
||||
return res.status(401).json({
|
||||
error: "Session expired - please log in again",
|
||||
code: "SESSION_EXPIRED",
|
||||
});
|
||||
}
|
||||
|
||||
const preferences = await getDb()
|
||||
.select()
|
||||
.from(dashboardPreferences)
|
||||
.where(eq(dashboardPreferences.userId, userId));
|
||||
|
||||
if (preferences.length === 0) {
|
||||
const defaultLayout = {
|
||||
cards: [
|
||||
{ id: "server_overview", enabled: true, order: 1 },
|
||||
{ id: "recent_activity", enabled: true, order: 2 },
|
||||
{ id: "network_graph", enabled: false, order: 3 },
|
||||
{ id: "quick_actions", enabled: true, order: 4 },
|
||||
{ id: "server_stats", enabled: true, order: 5 },
|
||||
],
|
||||
gridColumns: 2,
|
||||
};
|
||||
return res.json(defaultLayout);
|
||||
}
|
||||
|
||||
const layout = JSON.parse(preferences[0].layout as string);
|
||||
res.json(layout);
|
||||
} catch (err) {
|
||||
dashboardLogger.error("Failed to get dashboard preferences", err);
|
||||
res.status(500).json({ error: "Failed to get dashboard preferences" });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /dashboard/preferences:
|
||||
* post:
|
||||
* summary: Save dashboard layout preferences
|
||||
* description: Saves or updates the user's customized dashboard layout settings.
|
||||
* tags:
|
||||
* - Dashboard
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* cards:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* enabled:
|
||||
* type: boolean
|
||||
* order:
|
||||
* type: integer
|
||||
* gridColumns:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Preferences saved successfully
|
||||
* 400:
|
||||
* description: Invalid request body
|
||||
* 401:
|
||||
* description: Session expired
|
||||
* 500:
|
||||
* description: Failed to save preferences
|
||||
*/
|
||||
app.post("/dashboard/preferences", async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
if (!SimpleDBOps.isUserDataUnlocked(userId)) {
|
||||
return res.status(401).json({
|
||||
error: "Session expired - please log in again",
|
||||
code: "SESSION_EXPIRED",
|
||||
});
|
||||
}
|
||||
|
||||
const { cards, gridColumns } = req.body;
|
||||
|
||||
if (!cards || !Array.isArray(cards) || typeof gridColumns !== "number") {
|
||||
return res.status(400).json({
|
||||
error:
|
||||
"Invalid request body. Expected { cards: Array, gridColumns: number }",
|
||||
});
|
||||
}
|
||||
|
||||
const layout = JSON.stringify({ cards, gridColumns });
|
||||
|
||||
const existing = await getDb()
|
||||
.select()
|
||||
.from(dashboardPreferences)
|
||||
.where(eq(dashboardPreferences.userId, userId));
|
||||
|
||||
if (existing.length > 0) {
|
||||
await getDb()
|
||||
.update(dashboardPreferences)
|
||||
.set({ layout, updatedAt: sql`CURRENT_TIMESTAMP` })
|
||||
.where(eq(dashboardPreferences.userId, userId));
|
||||
} else {
|
||||
await getDb().insert(dashboardPreferences).values({ userId, layout });
|
||||
}
|
||||
|
||||
await DatabaseSaveTrigger.triggerSave("dashboard_preferences_updated");
|
||||
|
||||
dashboardLogger.success("Dashboard preferences saved", {
|
||||
operation: "save_dashboard_preferences",
|
||||
userId,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: "Dashboard preferences saved" });
|
||||
} catch (err) {
|
||||
dashboardLogger.error("Failed to save dashboard preferences", err);
|
||||
res.status(500).json({ error: "Failed to save dashboard preferences" });
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = 30006;
|
||||
app.listen(PORT, async () => {
|
||||
try {
|
||||
|
||||
@@ -8,6 +8,7 @@ import alertRoutes from "./routes/alerts.js";
|
||||
import credentialsRoutes from "./routes/credentials.js";
|
||||
import snippetsRoutes from "./routes/snippets.js";
|
||||
import terminalRoutes from "./routes/terminal.js";
|
||||
import networkTopologyRoutes from "./routes/network-topology.js";
|
||||
import rbacRoutes from "./routes/rbac.js";
|
||||
import cors from "cors";
|
||||
import fetch from "node-fetch";
|
||||
@@ -205,10 +206,46 @@ app.use(bodyParser.urlencoded({ limit: "1gb", extended: true }));
|
||||
app.use(bodyParser.raw({ limit: "5gb", type: "application/octet-stream" }));
|
||||
app.use(cookieParser());
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /health:
|
||||
* get:
|
||||
* summary: Health check
|
||||
* description: Returns the health status of the server.
|
||||
* tags:
|
||||
* - General
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Server is healthy.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: ok
|
||||
*/
|
||||
app.get("/health", (req, res) => {
|
||||
res.json({ status: "ok" });
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /version:
|
||||
* get:
|
||||
* summary: Get version information
|
||||
* description: Returns the local and remote version of the application.
|
||||
* tags:
|
||||
* - General
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Version information.
|
||||
* 404:
|
||||
* description: Local version not set.
|
||||
* 500:
|
||||
* description: Fetch error.
|
||||
*/
|
||||
app.get("/version", authenticateJWT, async (req, res) => {
|
||||
let localVersion = process.env.VERSION;
|
||||
|
||||
@@ -307,6 +344,31 @@ app.get("/version", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /releases/rss:
|
||||
* get:
|
||||
* summary: Get releases in RSS format
|
||||
* description: Returns the latest releases from the GitHub repository in an RSS-like JSON format.
|
||||
* tags:
|
||||
* - General
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: page
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: The page number of the releases to fetch.
|
||||
* - in: query
|
||||
* name: per_page
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: The number of releases to fetch per page.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Releases in RSS format.
|
||||
* 500:
|
||||
* description: Failed to generate RSS format.
|
||||
*/
|
||||
app.get("/releases/rss", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const page = parseInt(req.query.page as string) || 1;
|
||||
@@ -363,6 +425,20 @@ app.get("/releases/rss", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /encryption/status:
|
||||
* get:
|
||||
* summary: Get encryption status
|
||||
* description: Returns the security status of the application.
|
||||
* tags:
|
||||
* - Encryption
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Security status.
|
||||
* 500:
|
||||
* description: Failed to get security status.
|
||||
*/
|
||||
app.get("/encryption/status", requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const securityStatus = {
|
||||
@@ -384,6 +460,20 @@ app.get("/encryption/status", requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /encryption/initialize:
|
||||
* post:
|
||||
* summary: Initialize security system
|
||||
* description: Initializes the security system for the application.
|
||||
* tags:
|
||||
* - Encryption
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Security system initialized successfully.
|
||||
* 500:
|
||||
* description: Failed to initialize security system.
|
||||
*/
|
||||
app.post("/encryption/initialize", requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const authManager = AuthManager.getInstance();
|
||||
@@ -407,6 +497,20 @@ app.post("/encryption/initialize", requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /encryption/regenerate:
|
||||
* post:
|
||||
* summary: Regenerate JWT secret
|
||||
* description: Regenerates the system JWT secret. This will invalidate all existing JWT tokens.
|
||||
* tags:
|
||||
* - Encryption
|
||||
* responses:
|
||||
* 200:
|
||||
* description: System JWT secret regenerated.
|
||||
* 500:
|
||||
* description: Failed to regenerate JWT secret.
|
||||
*/
|
||||
app.post("/encryption/regenerate", requireAdmin, async (req, res) => {
|
||||
try {
|
||||
apiLogger.warn("System JWT secret regenerated via API", {
|
||||
@@ -428,6 +532,20 @@ app.post("/encryption/regenerate", requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /encryption/regenerate-jwt:
|
||||
* post:
|
||||
* summary: Regenerate JWT secret
|
||||
* description: Regenerates the JWT secret. This will invalidate all existing JWT tokens.
|
||||
* tags:
|
||||
* - Encryption
|
||||
* responses:
|
||||
* 200:
|
||||
* description: New JWT secret generated.
|
||||
* 500:
|
||||
* description: Failed to regenerate JWT secret.
|
||||
*/
|
||||
app.post("/encryption/regenerate-jwt", requireAdmin, async (req, res) => {
|
||||
try {
|
||||
apiLogger.warn("JWT secret regenerated via API", {
|
||||
@@ -448,6 +566,33 @@ app.post("/encryption/regenerate-jwt", requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/export:
|
||||
* post:
|
||||
* summary: Export user data
|
||||
* description: Exports the user's data as a SQLite database file.
|
||||
* tags:
|
||||
* - Database
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* password:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User data exported successfully.
|
||||
* 400:
|
||||
* description: Password required for export.
|
||||
* 401:
|
||||
* description: Invalid password.
|
||||
* 500:
|
||||
* description: Failed to export user data.
|
||||
*/
|
||||
app.post("/database/export", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -898,6 +1043,36 @@ app.post("/database/export", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/import:
|
||||
* post:
|
||||
* summary: Import user data
|
||||
* description: Imports user data from a SQLite database file.
|
||||
* tags:
|
||||
* - Database
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* multipart/form-data:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* file:
|
||||
* type: string
|
||||
* format: binary
|
||||
* password:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Incremental import completed successfully.
|
||||
* 400:
|
||||
* description: No file uploaded or password required for import.
|
||||
* 401:
|
||||
* description: Invalid password.
|
||||
* 500:
|
||||
* description: Failed to import SQLite data.
|
||||
*/
|
||||
app.post(
|
||||
"/database/import",
|
||||
authenticateJWT,
|
||||
@@ -1362,6 +1537,31 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/export/preview:
|
||||
* post:
|
||||
* summary: Preview user data export
|
||||
* description: Generates a preview of the user data export, including statistics about the data.
|
||||
* tags:
|
||||
* - Database
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* scope:
|
||||
* type: string
|
||||
* includeCredentials:
|
||||
* type: boolean
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Export preview generated successfully.
|
||||
* 500:
|
||||
* description: Failed to generate export preview.
|
||||
*/
|
||||
app.post("/database/export/preview", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -1397,6 +1597,33 @@ app.post("/database/export/preview", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/restore:
|
||||
* post:
|
||||
* summary: Restore database from backup
|
||||
* description: Restores the database from an encrypted backup file.
|
||||
* tags:
|
||||
* - Database
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* backupPath:
|
||||
* type: string
|
||||
* targetPath:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Database restored successfully.
|
||||
* 400:
|
||||
* description: Backup path is required or invalid encrypted backup file.
|
||||
* 500:
|
||||
* description: Database restore failed.
|
||||
*/
|
||||
app.post("/database/restore", requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const { backupPath, targetPath } = req.body;
|
||||
@@ -1437,6 +1664,7 @@ app.use("/alerts", alertRoutes);
|
||||
app.use("/credentials", credentialsRoutes);
|
||||
app.use("/snippets", snippetsRoutes);
|
||||
app.use("/terminal", terminalRoutes);
|
||||
app.use("/network-topology", networkTopologyRoutes);
|
||||
app.use("/rbac", rbacRoutes);
|
||||
|
||||
app.use(
|
||||
@@ -1477,6 +1705,20 @@ async function initializeSecurity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/migration/status:
|
||||
* get:
|
||||
* summary: Get database migration status
|
||||
* description: Returns the status of the database migration.
|
||||
* tags:
|
||||
* - Database
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Migration status.
|
||||
* 500:
|
||||
* description: Failed to get migration status.
|
||||
*/
|
||||
app.get(
|
||||
"/database/migration/status",
|
||||
authenticateJWT,
|
||||
@@ -1530,6 +1772,20 @@ app.get(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /database/migration/history:
|
||||
* get:
|
||||
* summary: Get database migration history
|
||||
* description: Returns the history of database migrations.
|
||||
* tags:
|
||||
* - Database
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Migration history.
|
||||
* 500:
|
||||
* description: Failed to get migration history.
|
||||
*/
|
||||
app.get(
|
||||
"/database/migration/history",
|
||||
authenticateJWT,
|
||||
|
||||
@@ -585,6 +585,32 @@ const migrateSchema = () => {
|
||||
addColumnIfNotExists("ssh_data", "socks5_password", "TEXT");
|
||||
addColumnIfNotExists("ssh_data", "socks5_proxy_chain", "TEXT");
|
||||
|
||||
addColumnIfNotExists(
|
||||
"ssh_data",
|
||||
"show_terminal_in_sidebar",
|
||||
"INTEGER NOT NULL DEFAULT 1",
|
||||
);
|
||||
addColumnIfNotExists(
|
||||
"ssh_data",
|
||||
"show_file_manager_in_sidebar",
|
||||
"INTEGER NOT NULL DEFAULT 0",
|
||||
);
|
||||
addColumnIfNotExists(
|
||||
"ssh_data",
|
||||
"show_tunnel_in_sidebar",
|
||||
"INTEGER NOT NULL DEFAULT 0",
|
||||
);
|
||||
addColumnIfNotExists(
|
||||
"ssh_data",
|
||||
"show_docker_in_sidebar",
|
||||
"INTEGER NOT NULL DEFAULT 0",
|
||||
);
|
||||
addColumnIfNotExists(
|
||||
"ssh_data",
|
||||
"show_server_stats_in_sidebar",
|
||||
"INTEGER NOT NULL DEFAULT 0",
|
||||
);
|
||||
|
||||
addColumnIfNotExists("ssh_credentials", "private_key", "TEXT");
|
||||
addColumnIfNotExists("ssh_credentials", "public_key", "TEXT");
|
||||
addColumnIfNotExists("ssh_credentials", "detected_key_type", "TEXT");
|
||||
@@ -653,6 +679,54 @@ const migrateSchema = () => {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sqlite
|
||||
.prepare("SELECT id FROM network_topology LIMIT 1")
|
||||
.get();
|
||||
} catch {
|
||||
try {
|
||||
sqlite.exec(`
|
||||
CREATE TABLE IF NOT EXISTS network_topology (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT NOT NULL,
|
||||
topology TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
} catch (createError) {
|
||||
databaseLogger.warn("Failed to create network_topology table", {
|
||||
operation: "schema_migration",
|
||||
error: createError,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sqlite
|
||||
.prepare("SELECT id FROM dashboard_preferences LIMIT 1")
|
||||
.get();
|
||||
} catch {
|
||||
try {
|
||||
sqlite.exec(`
|
||||
CREATE TABLE IF NOT EXISTS dashboard_preferences (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT NOT NULL UNIQUE,
|
||||
layout TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
} catch (createError) {
|
||||
databaseLogger.warn("Failed to create dashboard_preferences table", {
|
||||
operation: "schema_migration",
|
||||
error: createError,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sqlite.prepare("SELECT id FROM host_access LIMIT 1").get();
|
||||
} catch {
|
||||
|
||||
@@ -90,6 +90,21 @@ export const sshData = sqliteTable("ssh_data", {
|
||||
enableDocker: integer("enable_docker", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
showTerminalInSidebar: integer("show_terminal_in_sidebar", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(true),
|
||||
showFileManagerInSidebar: integer("show_file_manager_in_sidebar", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
showTunnelInSidebar: integer("show_tunnel_in_sidebar", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
showDockerInSidebar: integer("show_docker_in_sidebar", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
showServerStatsInSidebar: integer("show_server_stats_in_sidebar", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
defaultPath: text("default_path"),
|
||||
statsConfig: text("stats_config"),
|
||||
terminalConfig: text("terminal_config"),
|
||||
@@ -295,6 +310,35 @@ export const commandHistory = sqliteTable("command_history", {
|
||||
.default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
export const networkTopology = sqliteTable("network_topology", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
topology: text("topology"),
|
||||
createdAt: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`CURRENT_TIMESTAMP`),
|
||||
updatedAt: text("updated_at")
|
||||
.notNull()
|
||||
.default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
export const dashboardPreferences = sqliteTable("dashboard_preferences", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.unique()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
layout: text("layout").notNull(),
|
||||
createdAt: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`CURRENT_TIMESTAMP`),
|
||||
updatedAt: text("updated_at")
|
||||
.notNull()
|
||||
.default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
export const hostAccess = sqliteTable("host_access", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
hostId: integer("host_id")
|
||||
|
||||
@@ -99,8 +99,20 @@ const router = express.Router();
|
||||
const authManager = AuthManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
|
||||
// Route: Get alerts for the authenticated user (excluding dismissed ones)
|
||||
// GET /alerts
|
||||
/**
|
||||
* @openapi
|
||||
* /alerts:
|
||||
* get:
|
||||
* summary: Get active alerts
|
||||
* description: Fetches active alerts for the authenticated user, excluding those that have been dismissed.
|
||||
* tags:
|
||||
* - Alerts
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of active alerts.
|
||||
* 500:
|
||||
* description: Failed to fetch alerts.
|
||||
*/
|
||||
router.get("/", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -131,8 +143,33 @@ router.get("/", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Route: Dismiss an alert for the authenticated user
|
||||
// POST /alerts/dismiss
|
||||
/**
|
||||
* @openapi
|
||||
* /alerts/dismiss:
|
||||
* post:
|
||||
* summary: Dismiss an alert
|
||||
* description: Marks an alert as dismissed for the authenticated user.
|
||||
* tags:
|
||||
* - Alerts
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* alertId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Alert dismissed successfully.
|
||||
* 400:
|
||||
* description: Alert ID is required.
|
||||
* 409:
|
||||
* description: Alert already dismissed.
|
||||
* 500:
|
||||
* description: Failed to dismiss alert.
|
||||
*/
|
||||
router.post("/dismiss", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const { alertId } = req.body;
|
||||
@@ -170,8 +207,20 @@ router.post("/dismiss", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Route: Get dismissed alerts for a user
|
||||
// GET /alerts/dismissed/:userId
|
||||
/**
|
||||
* @openapi
|
||||
* /alerts/dismissed:
|
||||
* get:
|
||||
* summary: Get dismissed alerts
|
||||
* description: Fetches a list of alerts that have been dismissed by the authenticated user.
|
||||
* tags:
|
||||
* - Alerts
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of dismissed alerts.
|
||||
* 500:
|
||||
* description: Failed to fetch dismissed alerts.
|
||||
*/
|
||||
router.get("/dismissed", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -194,8 +243,33 @@ router.get("/dismissed", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Route: Undismiss an alert for the authenticated user (remove from dismissed list)
|
||||
// DELETE /alerts/dismiss
|
||||
/**
|
||||
* @openapi
|
||||
* /alerts/dismiss:
|
||||
* delete:
|
||||
* summary: Undismiss an alert
|
||||
* description: Removes an alert from the dismissed list for the authenticated user.
|
||||
* tags:
|
||||
* - Alerts
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* alertId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Alert undismissed successfully.
|
||||
* 400:
|
||||
* description: Alert ID is required.
|
||||
* 404:
|
||||
* description: Dismissed alert not found.
|
||||
* 500:
|
||||
* description: Failed to undismiss alert.
|
||||
*/
|
||||
router.delete("/dismiss", authenticateJWT, async (req, res) => {
|
||||
try {
|
||||
const { alertId } = req.body;
|
||||
|
||||
@@ -84,8 +84,52 @@ const authManager = AuthManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
const requireDataAccess = authManager.createDataAccessMiddleware();
|
||||
|
||||
// Create a new credential
|
||||
// POST /credentials
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials:
|
||||
* post:
|
||||
* summary: Create a new credential
|
||||
* description: Creates a new SSH credential for the authenticated user.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* folder:
|
||||
* type: string
|
||||
* tags:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* authType:
|
||||
* type: string
|
||||
* enum: [password, key]
|
||||
* username:
|
||||
* type: string
|
||||
* password:
|
||||
* type: string
|
||||
* key:
|
||||
* type: string
|
||||
* keyPassword:
|
||||
* type: string
|
||||
* keyType:
|
||||
* type: string
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Credential created successfully.
|
||||
* 400:
|
||||
* description: Invalid request body.
|
||||
* 500:
|
||||
* description: Failed to create credential.
|
||||
*/
|
||||
router.post(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
@@ -231,8 +275,22 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Get all credentials for the authenticated user
|
||||
// GET /credentials
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials:
|
||||
* get:
|
||||
* summary: Get all credentials
|
||||
* description: Retrieves all SSH credentials for the authenticated user.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of credentials.
|
||||
* 400:
|
||||
* description: Invalid userId.
|
||||
* 500:
|
||||
* description: Failed to fetch credentials.
|
||||
*/
|
||||
router.get(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
@@ -264,8 +322,22 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get all unique credential folders for the authenticated user
|
||||
// GET /credentials/folders
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/folders:
|
||||
* get:
|
||||
* summary: Get credential folders
|
||||
* description: Retrieves all unique credential folders for the authenticated user.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of folder names.
|
||||
* 400:
|
||||
* description: Invalid userId.
|
||||
* 500:
|
||||
* description: Failed to fetch credential folders.
|
||||
*/
|
||||
router.get(
|
||||
"/folders",
|
||||
authenticateJWT,
|
||||
@@ -302,8 +374,30 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get a specific credential by ID (with plain text secrets)
|
||||
// GET /credentials/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}:
|
||||
* get:
|
||||
* summary: Get a specific credential
|
||||
* description: Retrieves a specific credential by its ID, including secrets.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The requested credential.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Credential not found.
|
||||
* 500:
|
||||
* description: Failed to fetch credential.
|
||||
*/
|
||||
router.get(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
@@ -366,8 +460,41 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Update a credential
|
||||
// PUT /credentials/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}:
|
||||
* put:
|
||||
* summary: Update a credential
|
||||
* description: Updates a specific credential by its ID.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated credential.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Credential not found.
|
||||
* 500:
|
||||
* description: Failed to update credential.
|
||||
*/
|
||||
router.put(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
@@ -510,8 +637,30 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Delete a credential
|
||||
// DELETE /credentials/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}:
|
||||
* delete:
|
||||
* summary: Delete a credential
|
||||
* description: Deletes a specific credential by its ID.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Credential deleted successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Credential not found.
|
||||
* 500:
|
||||
* description: Failed to delete credential.
|
||||
*/
|
||||
router.delete(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
@@ -626,8 +775,35 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Apply a credential to an SSH host (for quick application)
|
||||
// POST /credentials/:id/apply-to-host/:hostId
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}/apply-to-host/{hostId}:
|
||||
* post:
|
||||
* summary: Apply a credential to a host
|
||||
* description: Applies a credential to an SSH host for quick application.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - in: path
|
||||
* name: hostId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Credential applied to host successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Credential not found.
|
||||
* 500:
|
||||
* description: Failed to apply credential to host.
|
||||
*/
|
||||
router.post(
|
||||
"/:id/apply-to-host/:hostId",
|
||||
authenticateJWT,
|
||||
@@ -705,8 +881,28 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Get hosts using a specific credential
|
||||
// GET /credentials/:id/hosts
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}/hosts:
|
||||
* get:
|
||||
* summary: Get hosts using a credential
|
||||
* description: Retrieves a list of hosts that are using a specific credential.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of hosts.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 500:
|
||||
* description: Failed to fetch hosts using credential.
|
||||
*/
|
||||
router.get(
|
||||
"/:id/hosts",
|
||||
authenticateJWT,
|
||||
@@ -800,8 +996,33 @@ function formatSSHHostOutput(
|
||||
};
|
||||
}
|
||||
|
||||
// Rename a credential folder
|
||||
// PUT /credentials/folders/rename
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/folders/rename:
|
||||
* put:
|
||||
* summary: Rename a credential folder
|
||||
* description: Renames a credential folder for the authenticated user.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* oldName:
|
||||
* type: string
|
||||
* newName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Folder renamed successfully.
|
||||
* 400:
|
||||
* description: Both oldName and newName are required.
|
||||
* 500:
|
||||
* description: Failed to rename folder.
|
||||
*/
|
||||
router.put(
|
||||
"/folders/rename",
|
||||
authenticateJWT,
|
||||
@@ -840,8 +1061,33 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Detect SSH key type endpoint
|
||||
// POST /credentials/detect-key-type
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/detect-key-type:
|
||||
* post:
|
||||
* summary: Detect SSH key type
|
||||
* description: Detects the type of an SSH private key.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* privateKey:
|
||||
* type: string
|
||||
* keyPassword:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Key type detection result.
|
||||
* 400:
|
||||
* description: Private key is required.
|
||||
* 500:
|
||||
* description: Failed to detect key type.
|
||||
*/
|
||||
router.post(
|
||||
"/detect-key-type",
|
||||
authenticateJWT,
|
||||
@@ -874,8 +1120,31 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Detect SSH public key type endpoint
|
||||
// POST /credentials/detect-public-key-type
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/detect-public-key-type:
|
||||
* post:
|
||||
* summary: Detect SSH public key type
|
||||
* description: Detects the type of an SSH public key.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* publicKey:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Key type detection result.
|
||||
* 400:
|
||||
* description: Public key is required.
|
||||
* 500:
|
||||
* description: Failed to detect public key type.
|
||||
*/
|
||||
router.post(
|
||||
"/detect-public-key-type",
|
||||
authenticateJWT,
|
||||
@@ -909,8 +1178,35 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Validate SSH key pair endpoint
|
||||
// POST /credentials/validate-key-pair
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/validate-key-pair:
|
||||
* post:
|
||||
* summary: Validate SSH key pair
|
||||
* description: Validates if a given SSH private key and public key match.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* privateKey:
|
||||
* type: string
|
||||
* publicKey:
|
||||
* type: string
|
||||
* keyPassword:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Key pair validation result.
|
||||
* 400:
|
||||
* description: Private key and public key are required.
|
||||
* 500:
|
||||
* description: Failed to validate key pair.
|
||||
*/
|
||||
router.post(
|
||||
"/validate-key-pair",
|
||||
authenticateJWT,
|
||||
@@ -953,8 +1249,32 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Generate new SSH key pair endpoint
|
||||
// POST /credentials/generate-key-pair
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/generate-key-pair:
|
||||
* post:
|
||||
* summary: Generate new SSH key pair
|
||||
* description: Generates a new SSH key pair.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* keyType:
|
||||
* type: string
|
||||
* keySize:
|
||||
* type: integer
|
||||
* passphrase:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The new key pair.
|
||||
* 500:
|
||||
* description: Failed to generate SSH key pair.
|
||||
*/
|
||||
router.post(
|
||||
"/generate-key-pair",
|
||||
authenticateJWT,
|
||||
@@ -996,8 +1316,33 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Generate public key from private key endpoint
|
||||
// POST /credentials/generate-public-key
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/generate-public-key:
|
||||
* post:
|
||||
* summary: Generate public key from private key
|
||||
* description: Generates a public key from a given private key.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* privateKey:
|
||||
* type: string
|
||||
* keyPassword:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The generated public key.
|
||||
* 400:
|
||||
* description: Private key is required.
|
||||
* 500:
|
||||
* description: Failed to generate public key.
|
||||
*/
|
||||
router.post(
|
||||
"/generate-public-key",
|
||||
authenticateJWT,
|
||||
@@ -1283,7 +1628,7 @@ async function deploySSHKeyToHost(
|
||||
.replace(/'/g, "'\\''");
|
||||
|
||||
conn.exec(
|
||||
`printf '%s\\n' '${escapedKey} ${credData.name}@Termix' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys`,
|
||||
`printf '%s\n' '${escapedKey} ${credData.name}@Termix' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys`,
|
||||
(err, stream) => {
|
||||
if (err) {
|
||||
clearTimeout(addTimeout);
|
||||
@@ -1502,8 +1847,41 @@ async function deploySSHKeyToHost(
|
||||
});
|
||||
}
|
||||
|
||||
// Deploy SSH Key to Host endpoint
|
||||
// POST /credentials/:id/deploy-to-host
|
||||
/**
|
||||
* @openapi
|
||||
* /credentials/{id}/deploy-to-host:
|
||||
* post:
|
||||
* summary: Deploy SSH key to a host
|
||||
* description: Deploys an SSH public key to a target host's authorized_keys file.
|
||||
* tags:
|
||||
* - Credentials
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* targetHostId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: SSH key deployed successfully.
|
||||
* 400:
|
||||
* description: Credential ID and target host ID are required.
|
||||
* 401:
|
||||
* description: Authentication required.
|
||||
* 404:
|
||||
* description: Credential or target host not found.
|
||||
* 500:
|
||||
* description: Failed to deploy SSH key.
|
||||
*/
|
||||
router.post(
|
||||
"/:id/deploy-to-host",
|
||||
authenticateJWT,
|
||||
|
||||
142
src/backend/database/routes/network-topology.ts
Normal file
142
src/backend/database/routes/network-topology.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import express from "express";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { getDb } from "../db/index.js";
|
||||
import { networkTopology } from "../db/schema.js";
|
||||
import { AuthManager } from "../../utils/auth-manager.js";
|
||||
import type { AuthenticatedRequest } from "../../../types/index.js";
|
||||
|
||||
const router = express.Router();
|
||||
const authManager = AuthManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /network-topology:
|
||||
* get:
|
||||
* summary: Get network topology
|
||||
* description: Retrieves the network topology for the authenticated user.
|
||||
* tags:
|
||||
* - Network Topology
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The network topology.
|
||||
* 401:
|
||||
* description: User not authenticated.
|
||||
* 500:
|
||||
* description: Failed to fetch network topology.
|
||||
*/
|
||||
router.get(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: "User not authenticated" });
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
const result = await db
|
||||
.select()
|
||||
.from(networkTopology)
|
||||
.where(eq(networkTopology.userId, userId));
|
||||
|
||||
if (result.length > 0) {
|
||||
const topologyStr = result[0].topology;
|
||||
const topology = topologyStr ? JSON.parse(topologyStr) : null;
|
||||
return res.json(topology);
|
||||
} else {
|
||||
return res.json(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching network topology:", error);
|
||||
return res
|
||||
.status(500)
|
||||
.json({
|
||||
error: "Failed to fetch network topology",
|
||||
details: (error as Error).message,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /network-topology:
|
||||
* post:
|
||||
* summary: Save network topology
|
||||
* description: Saves the network topology for the authenticated user.
|
||||
* tags:
|
||||
* - Network Topology
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* topology:
|
||||
* type: object
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Network topology saved successfully.
|
||||
* 400:
|
||||
* description: Topology data is required.
|
||||
* 401:
|
||||
* description: User not authenticated.
|
||||
* 500:
|
||||
* description: Failed to save network topology.
|
||||
*/
|
||||
router.post(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: "User not authenticated" });
|
||||
}
|
||||
|
||||
const { topology } = req.body;
|
||||
if (!topology) {
|
||||
return res.status(400).json({ error: "Topology data is required" });
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
|
||||
// Ensure topology is a string
|
||||
const topologyStr =
|
||||
typeof topology === "string" ? topology : JSON.stringify(topology);
|
||||
|
||||
const existing = await db
|
||||
.select()
|
||||
.from(networkTopology)
|
||||
.where(eq(networkTopology.userId, userId));
|
||||
|
||||
if (existing.length > 0) {
|
||||
// Update existing record
|
||||
await db
|
||||
.update(networkTopology)
|
||||
.set({ topology: topologyStr })
|
||||
.where(eq(networkTopology.userId, userId));
|
||||
} else {
|
||||
// Insert new record
|
||||
await db
|
||||
.insert(networkTopology)
|
||||
.values({ userId, topology: topologyStr });
|
||||
}
|
||||
|
||||
return res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error("Error saving network topology:", error);
|
||||
return res
|
||||
.status(500)
|
||||
.json({
|
||||
error: "Failed to save network topology",
|
||||
details: (error as Error).message,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export default router;
|
||||
@@ -27,8 +27,51 @@ function isNonEmptyString(value: unknown): value is string {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
}
|
||||
|
||||
//Share a host with a user or role
|
||||
//POST /rbac/host/:id/share
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/host/{id}/share:
|
||||
* post:
|
||||
* summary: Share a host
|
||||
* description: Shares a host with a user or a role.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* targetType:
|
||||
* type: string
|
||||
* enum: [user, role]
|
||||
* targetUserId:
|
||||
* type: string
|
||||
* targetRoleId:
|
||||
* type: integer
|
||||
* durationHours:
|
||||
* type: number
|
||||
* permissionLevel:
|
||||
* type: string
|
||||
* enum: [view]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Host shared successfully.
|
||||
* 400:
|
||||
* description: Invalid request body.
|
||||
* 403:
|
||||
* description: Not host owner.
|
||||
* 404:
|
||||
* description: Target user or role not found.
|
||||
* 500:
|
||||
* description: Failed to share host.
|
||||
*/
|
||||
router.post(
|
||||
"/host/:id/share",
|
||||
authenticateJWT,
|
||||
@@ -227,8 +270,35 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Revoke host access
|
||||
// DELETE /rbac/host/:id/access/:accessId
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/host/{id}/access/{accessId}:
|
||||
* delete:
|
||||
* summary: Revoke host access
|
||||
* description: Revokes a user's or role's access to a host.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - in: path
|
||||
* name: accessId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Access revoked successfully.
|
||||
* 400:
|
||||
* description: Invalid ID.
|
||||
* 403:
|
||||
* description: Not host owner.
|
||||
* 500:
|
||||
* description: Failed to revoke access.
|
||||
*/
|
||||
router.delete(
|
||||
"/host/:id/access/:accessId",
|
||||
authenticateJWT,
|
||||
@@ -267,8 +337,30 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Get host access list
|
||||
// GET /rbac/host/:id/access
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/host/{id}/access:
|
||||
* get:
|
||||
* summary: Get host access list
|
||||
* description: Retrieves the list of users and roles that have access to a host.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The access list for the host.
|
||||
* 400:
|
||||
* description: Invalid host ID.
|
||||
* 403:
|
||||
* description: Not host owner.
|
||||
* 500:
|
||||
* description: Failed to get access list.
|
||||
*/
|
||||
router.get(
|
||||
"/host/:id/access",
|
||||
authenticateJWT,
|
||||
@@ -338,8 +430,20 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get user's shared hosts (hosts shared WITH this user)
|
||||
// GET /rbac/shared-hosts
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/shared-hosts:
|
||||
* get:
|
||||
* summary: Get shared hosts
|
||||
* description: Retrieves the list of hosts that have been shared with the authenticated user.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of shared hosts.
|
||||
* 500:
|
||||
* description: Failed to get shared hosts.
|
||||
*/
|
||||
router.get(
|
||||
"/shared-hosts",
|
||||
authenticateJWT,
|
||||
@@ -385,8 +489,20 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get all roles
|
||||
// GET /rbac/roles
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/roles:
|
||||
* get:
|
||||
* summary: Get all roles
|
||||
* description: Retrieves a list of all roles.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of roles.
|
||||
* 500:
|
||||
* description: Failed to get roles.
|
||||
*/
|
||||
router.get(
|
||||
"/roles",
|
||||
authenticateJWT,
|
||||
@@ -413,8 +529,20 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get all roles
|
||||
// GET /rbac/roles
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/roles:
|
||||
* get:
|
||||
* summary: Get all roles
|
||||
* description: Retrieves a list of all roles.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of roles.
|
||||
* 500:
|
||||
* description: Failed to get roles.
|
||||
*/
|
||||
router.get(
|
||||
"/roles",
|
||||
authenticateJWT,
|
||||
@@ -443,8 +571,37 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Create new role
|
||||
// POST /rbac/roles
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/roles:
|
||||
* post:
|
||||
* summary: Create a new role
|
||||
* description: Creates a new role.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* displayName:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Role created successfully.
|
||||
* 400:
|
||||
* description: Invalid request body.
|
||||
* 409:
|
||||
* description: A role with this name already exists.
|
||||
* 500:
|
||||
* description: Failed to create role.
|
||||
*/
|
||||
router.post(
|
||||
"/roles",
|
||||
authenticateJWT,
|
||||
@@ -503,8 +660,41 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Update role
|
||||
// PUT /rbac/roles/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/roles/{id}:
|
||||
* put:
|
||||
* summary: Update a role
|
||||
* description: Updates a role by its ID.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* displayName:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role updated successfully.
|
||||
* 400:
|
||||
* description: Invalid request body or role ID.
|
||||
* 404:
|
||||
* description: Role not found.
|
||||
* 500:
|
||||
* description: Failed to update role.
|
||||
*/
|
||||
router.put(
|
||||
"/roles/:id",
|
||||
authenticateJWT,
|
||||
@@ -570,8 +760,32 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Delete role
|
||||
// DELETE /rbac/roles/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/roles/{id}:
|
||||
* delete:
|
||||
* summary: Delete a role
|
||||
* description: Deletes a role by its ID.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role deleted successfully.
|
||||
* 400:
|
||||
* description: Invalid role ID.
|
||||
* 403:
|
||||
* description: Cannot delete system roles.
|
||||
* 404:
|
||||
* description: Role not found.
|
||||
* 500:
|
||||
* description: Failed to delete role.
|
||||
*/
|
||||
router.delete(
|
||||
"/roles/:id",
|
||||
authenticateJWT,
|
||||
@@ -634,8 +848,43 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Assign role to user
|
||||
// POST /rbac/users/:userId/roles
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/users/{userId}/roles:
|
||||
* post:
|
||||
* summary: Assign a role to a user
|
||||
* description: Assigns a role to a user.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: userId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* roleId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role assigned successfully.
|
||||
* 400:
|
||||
* description: Role ID is required.
|
||||
* 403:
|
||||
* description: System roles cannot be manually assigned.
|
||||
* 404:
|
||||
* description: User or role not found.
|
||||
* 409:
|
||||
* description: Role already assigned.
|
||||
* 500:
|
||||
* description: Failed to assign role.
|
||||
*/
|
||||
router.post(
|
||||
"/users/:userId/roles",
|
||||
authenticateJWT,
|
||||
@@ -746,8 +995,37 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Remove role from user
|
||||
// DELETE /rbac/users/:userId/roles/:roleId
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/users/{userId}/roles/{roleId}:
|
||||
* delete:
|
||||
* summary: Remove a role from a user
|
||||
* description: Removes a role from a user.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: userId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: roleId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role removed successfully.
|
||||
* 400:
|
||||
* description: Invalid role ID.
|
||||
* 403:
|
||||
* description: System roles cannot be removed.
|
||||
* 404:
|
||||
* description: Role not found.
|
||||
* 500:
|
||||
* description: Failed to remove role.
|
||||
*/
|
||||
router.delete(
|
||||
"/users/:userId/roles/:roleId",
|
||||
authenticateJWT,
|
||||
@@ -805,8 +1083,28 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Get user's roles
|
||||
// GET /rbac/users/:userId/roles
|
||||
/**
|
||||
* @openapi
|
||||
* /rbac/users/{userId}/roles:
|
||||
* get:
|
||||
* summary: Get user's roles
|
||||
* description: Retrieves a list of roles for a specific user.
|
||||
* tags:
|
||||
* - RBAC
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: userId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of roles.
|
||||
* 403:
|
||||
* description: Access denied.
|
||||
* 500:
|
||||
* description: Failed to get user roles.
|
||||
*/
|
||||
router.get(
|
||||
"/users/:userId/roles",
|
||||
authenticateJWT,
|
||||
|
||||
@@ -17,8 +17,22 @@ const authManager = AuthManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
const requireDataAccess = authManager.createDataAccessMiddleware();
|
||||
|
||||
// Get all snippet folders
|
||||
// GET /snippets/folders
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/folders:
|
||||
* get:
|
||||
* summary: Get all snippet folders
|
||||
* description: Retrieves all snippet folders for the authenticated user.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of snippet folders.
|
||||
* 400:
|
||||
* description: Invalid userId.
|
||||
* 500:
|
||||
* description: Failed to fetch snippet folders.
|
||||
*/
|
||||
router.get(
|
||||
"/folders",
|
||||
authenticateJWT,
|
||||
@@ -46,8 +60,37 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Create a new snippet folder
|
||||
// POST /snippets/folders
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/folders:
|
||||
* post:
|
||||
* summary: Create a new snippet folder
|
||||
* description: Creates a new snippet folder for the authenticated user.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* color:
|
||||
* type: string
|
||||
* icon:
|
||||
* type: string
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Snippet folder created successfully.
|
||||
* 400:
|
||||
* description: Folder name is required.
|
||||
* 409:
|
||||
* description: Folder with this name already exists.
|
||||
* 500:
|
||||
* description: Failed to create snippet folder.
|
||||
*/
|
||||
router.post(
|
||||
"/folders",
|
||||
authenticateJWT,
|
||||
@@ -110,8 +153,41 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Update snippet folder metadata (color, icon)
|
||||
// PUT /snippets/folders/:name/metadata
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/folders/{name}/metadata:
|
||||
* put:
|
||||
* summary: Update snippet folder metadata
|
||||
* description: Updates the metadata (color, icon) of a snippet folder.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: name
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* color:
|
||||
* type: string
|
||||
* icon:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Snippet folder metadata updated successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Folder not found.
|
||||
* 500:
|
||||
* description: Failed to update snippet folder metadata.
|
||||
*/
|
||||
router.put(
|
||||
"/folders/:name/metadata",
|
||||
authenticateJWT,
|
||||
@@ -194,8 +270,37 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Rename snippet folder
|
||||
// PUT /snippets/folders/rename
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/folders/rename:
|
||||
* put:
|
||||
* summary: Rename a snippet folder
|
||||
* description: Renames a snippet folder for the authenticated user.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* oldName:
|
||||
* type: string
|
||||
* newName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Folder renamed successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Folder not found.
|
||||
* 409:
|
||||
* description: Folder with new name already exists.
|
||||
* 500:
|
||||
* description: Failed to rename snippet folder.
|
||||
*/
|
||||
router.put(
|
||||
"/folders/rename",
|
||||
authenticateJWT,
|
||||
@@ -282,8 +387,28 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Delete snippet folder
|
||||
// DELETE /snippets/folders/:name
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/folders/{name}:
|
||||
* delete:
|
||||
* summary: Delete a snippet folder
|
||||
* description: Deletes a snippet folder and moves its snippets to the root.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: name
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Snippet folder deleted successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 500:
|
||||
* description: Failed to delete snippet folder.
|
||||
*/
|
||||
router.delete(
|
||||
"/folders/:name",
|
||||
authenticateJWT,
|
||||
@@ -338,8 +463,40 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Reorder snippets (bulk update)
|
||||
// PUT /snippets/reorder
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/reorder:
|
||||
* put:
|
||||
* summary: Reorder snippets
|
||||
* description: Bulk updates the order and folder of snippets.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* snippets:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* order:
|
||||
* type: integer
|
||||
* folder:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Snippets reordered successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 500:
|
||||
* description: Failed to reorder snippets.
|
||||
*/
|
||||
router.put(
|
||||
"/reorder",
|
||||
authenticateJWT,
|
||||
@@ -405,8 +562,35 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Execute a snippet on a host
|
||||
// POST /snippets/execute
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/execute:
|
||||
* post:
|
||||
* summary: Execute a snippet on a host
|
||||
* description: Executes a snippet on a specified host.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* snippetId:
|
||||
* type: integer
|
||||
* hostId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Snippet executed successfully.
|
||||
* 400:
|
||||
* description: Snippet ID and Host ID are required.
|
||||
* 404:
|
||||
* description: Snippet or host not found.
|
||||
* 500:
|
||||
* description: Failed to execute snippet.
|
||||
*/
|
||||
router.post(
|
||||
"/execute",
|
||||
authenticateJWT,
|
||||
@@ -662,8 +846,22 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Get all snippets for the authenticated user
|
||||
// GET /snippets
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets:
|
||||
* get:
|
||||
* summary: Get all snippets
|
||||
* description: Retrieves all snippets for the authenticated user.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of snippets.
|
||||
* 400:
|
||||
* description: Invalid userId.
|
||||
* 500:
|
||||
* description: Failed to fetch snippets.
|
||||
*/
|
||||
router.get(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
@@ -696,8 +894,30 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get a specific snippet by ID
|
||||
// GET /snippets/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/{id}:
|
||||
* get:
|
||||
* summary: Get a specific snippet
|
||||
* description: Retrieves a specific snippet by its ID.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The requested snippet.
|
||||
* 400:
|
||||
* description: Invalid request parameters.
|
||||
* 404:
|
||||
* description: Snippet not found.
|
||||
* 500:
|
||||
* description: Failed to fetch snippet.
|
||||
*/
|
||||
router.get(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
@@ -735,8 +955,39 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Create a new snippet
|
||||
// POST /snippets
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets:
|
||||
* post:
|
||||
* summary: Create a new snippet
|
||||
* description: Creates a new snippet for the authenticated user.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* content:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* folder:
|
||||
* type: string
|
||||
* order:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Snippet created successfully.
|
||||
* 400:
|
||||
* description: Name and content are required.
|
||||
* 500:
|
||||
* description: Failed to create snippet.
|
||||
*/
|
||||
router.post(
|
||||
"/",
|
||||
authenticateJWT,
|
||||
@@ -806,8 +1057,47 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Update a snippet
|
||||
// PUT /snippets/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/{id}:
|
||||
* put:
|
||||
* summary: Update a snippet
|
||||
* description: Updates a specific snippet by its ID.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* content:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* folder:
|
||||
* type: string
|
||||
* order:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated snippet.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Snippet not found.
|
||||
* 500:
|
||||
* description: Failed to update snippet.
|
||||
*/
|
||||
router.put(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
@@ -883,8 +1173,30 @@ router.put(
|
||||
},
|
||||
);
|
||||
|
||||
// Delete a snippet
|
||||
// DELETE /snippets/:id
|
||||
/**
|
||||
* @openapi
|
||||
* /snippets/{id}:
|
||||
* delete:
|
||||
* summary: Delete a snippet
|
||||
* description: Deletes a specific snippet by its ID.
|
||||
* tags:
|
||||
* - Snippets
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Snippet deleted successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 404:
|
||||
* description: Snippet not found.
|
||||
* 500:
|
||||
* description: Failed to delete snippet.
|
||||
*/
|
||||
router.delete(
|
||||
"/:id",
|
||||
authenticateJWT,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,33 @@ const authManager = AuthManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
const requireDataAccess = authManager.createDataAccessMiddleware();
|
||||
|
||||
// Save command to history
|
||||
// POST /terminal/command_history
|
||||
/**
|
||||
* @openapi
|
||||
* /terminal/command_history:
|
||||
* post:
|
||||
* summary: Save command to history
|
||||
* description: Saves a command to the command history for a specific host.
|
||||
* tags:
|
||||
* - Terminal
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* command:
|
||||
* type: string
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Command saved successfully.
|
||||
* 400:
|
||||
* description: Missing required parameters.
|
||||
* 500:
|
||||
* description: Failed to save command.
|
||||
*/
|
||||
router.post(
|
||||
"/command_history",
|
||||
authenticateJWT,
|
||||
@@ -59,8 +84,28 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Get command history for a specific host
|
||||
// GET /terminal/command_history/:hostId
|
||||
/**
|
||||
* @openapi
|
||||
* /terminal/command_history/{hostId}:
|
||||
* get:
|
||||
* summary: Get command history
|
||||
* description: Retrieves the command history for a specific host.
|
||||
* tags:
|
||||
* - Terminal
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: hostId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of commands.
|
||||
* 400:
|
||||
* description: Invalid request parameters.
|
||||
* 500:
|
||||
* description: Failed to fetch history.
|
||||
*/
|
||||
router.get(
|
||||
"/command_history/:hostId",
|
||||
authenticateJWT,
|
||||
@@ -107,8 +152,33 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Delete a specific command from history
|
||||
// POST /terminal/command_history/delete
|
||||
/**
|
||||
* @openapi
|
||||
* /terminal/command_history/delete:
|
||||
* post:
|
||||
* summary: Delete a specific command from history
|
||||
* description: Deletes a specific command from the history of a host.
|
||||
* tags:
|
||||
* - Terminal
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* command:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Command deleted successfully.
|
||||
* 400:
|
||||
* description: Missing required parameters.
|
||||
* 500:
|
||||
* description: Failed to delete command.
|
||||
*/
|
||||
router.post(
|
||||
"/command_history/delete",
|
||||
authenticateJWT,
|
||||
@@ -150,8 +220,28 @@ router.post(
|
||||
},
|
||||
);
|
||||
|
||||
// Clear command history for a specific host (optional feature)
|
||||
// DELETE /terminal/command_history/:hostId
|
||||
/**
|
||||
* @openapi
|
||||
* /terminal/command_history/{hostId}:
|
||||
* delete:
|
||||
* summary: Clear command history
|
||||
* description: Clears the entire command history for a specific host.
|
||||
* tags:
|
||||
* - Terminal
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: hostId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Command history cleared successfully.
|
||||
* 400:
|
||||
* description: Invalid request.
|
||||
* 500:
|
||||
* description: Failed to clear history.
|
||||
*/
|
||||
router.delete(
|
||||
"/command_history/:hostId",
|
||||
authenticateJWT,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -365,7 +365,34 @@ app.use(express.urlencoded({ limit: "100mb", extended: true }));
|
||||
const authManager = AuthManager.getInstance();
|
||||
app.use(authManager.createAuthMiddleware());
|
||||
|
||||
// POST /docker/ssh/connect - Establish SSH session
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/ssh/connect:
|
||||
* post:
|
||||
* summary: Establish SSH session for Docker
|
||||
* description: Establishes an SSH session to a host for Docker operations.
|
||||
* tags:
|
||||
* - Docker
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* responses:
|
||||
* 200:
|
||||
* description: SSH connection established.
|
||||
* 400:
|
||||
* description: Missing sessionId or hostId.
|
||||
* 401:
|
||||
* description: Authentication required.
|
||||
* 403:
|
||||
* description: Docker is not enabled for this host.
|
||||
* 404:
|
||||
* description: Host not found.
|
||||
* 500:
|
||||
* description: SSH connection failed.
|
||||
*/
|
||||
app.post("/docker/ssh/connect", async (req, res) => {
|
||||
const {
|
||||
sessionId,
|
||||
@@ -929,7 +956,29 @@ app.post("/docker/ssh/connect", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /docker/ssh/disconnect - Close SSH session
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/ssh/disconnect:
|
||||
* post:
|
||||
* summary: Disconnect SSH session
|
||||
* description: Closes an active SSH session for Docker operations.
|
||||
* tags:
|
||||
* - Docker
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sessionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: SSH session disconnected.
|
||||
* 400:
|
||||
* description: Session ID is required.
|
||||
*/
|
||||
app.post("/docker/ssh/disconnect", async (req, res) => {
|
||||
const { sessionId } = req.body;
|
||||
|
||||
@@ -942,7 +991,35 @@ app.post("/docker/ssh/disconnect", async (req, res) => {
|
||||
res.json({ success: true, message: "SSH session disconnected" });
|
||||
});
|
||||
|
||||
// POST /docker/ssh/connect-totp - Verify TOTP and complete connection
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/ssh/connect-totp:
|
||||
* post:
|
||||
* summary: Verify TOTP and complete connection
|
||||
* description: Verifies the TOTP code and completes the SSH connection.
|
||||
* tags:
|
||||
* - Docker
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sessionId:
|
||||
* type: string
|
||||
* totpCode:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: TOTP verified, SSH connection established.
|
||||
* 400:
|
||||
* description: Session ID and TOTP code required.
|
||||
* 401:
|
||||
* description: Invalid TOTP code.
|
||||
* 404:
|
||||
* description: TOTP session expired.
|
||||
*/
|
||||
app.post("/docker/ssh/connect-totp", async (req, res) => {
|
||||
const { sessionId, totpCode } = req.body;
|
||||
const userId = (req as any).userId;
|
||||
@@ -1105,7 +1182,29 @@ app.post("/docker/ssh/connect-totp", async (req, res) => {
|
||||
session.finish(responses);
|
||||
});
|
||||
|
||||
// POST /docker/ssh/keepalive - Keep session alive
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/ssh/keepalive:
|
||||
* post:
|
||||
* summary: Keep SSH session alive
|
||||
* description: Keeps an active SSH session alive.
|
||||
* tags:
|
||||
* - Docker
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sessionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Session keepalive successful.
|
||||
* 400:
|
||||
* description: Session ID is required or session not found.
|
||||
*/
|
||||
app.post("/docker/ssh/keepalive", async (req, res) => {
|
||||
const { sessionId } = req.body;
|
||||
|
||||
@@ -1133,7 +1232,26 @@ app.post("/docker/ssh/keepalive", async (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// GET /docker/ssh/status - Check session status
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/ssh/status:
|
||||
* get:
|
||||
* summary: Check SSH session status
|
||||
* description: Checks the status of an active SSH session.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Session status.
|
||||
* 400:
|
||||
* description: Session ID is required.
|
||||
*/
|
||||
app.get("/docker/ssh/status", async (req, res) => {
|
||||
const sessionId = req.query.sessionId as string;
|
||||
|
||||
@@ -1146,7 +1264,28 @@ app.get("/docker/ssh/status", async (req, res) => {
|
||||
res.json({ success: true, connected: isConnected });
|
||||
});
|
||||
|
||||
// GET /docker/validate/:sessionId - Validate Docker availability
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/validate/{sessionId}:
|
||||
* get:
|
||||
* summary: Validate Docker availability
|
||||
* description: Validates if Docker is available on the host.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Docker availability status.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 500:
|
||||
* description: Validation failed.
|
||||
*/
|
||||
app.get("/docker/validate/:sessionId", async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
const userId = (req as any).userId;
|
||||
@@ -1236,7 +1375,32 @@ app.get("/docker/validate/:sessionId", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /docker/containers/:sessionId - List all containers
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}:
|
||||
* get:
|
||||
* summary: List all containers
|
||||
* description: Lists all Docker containers on the host.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: all
|
||||
* schema:
|
||||
* type: boolean
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of containers.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 500:
|
||||
* description: Failed to list containers.
|
||||
*/
|
||||
app.get("/docker/containers/:sessionId", async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
const all = req.query.all !== "false";
|
||||
@@ -1297,7 +1461,35 @@ app.get("/docker/containers/:sessionId", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /docker/containers/:sessionId/:containerId - Get container details
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}:
|
||||
* get:
|
||||
* summary: Get container details
|
||||
* description: Retrieves detailed information about a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container details.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to get container details.
|
||||
*/
|
||||
app.get("/docker/containers/:sessionId/:containerId", async (req, res) => {
|
||||
const { sessionId, containerId } = req.params;
|
||||
const userId = (req as any).userId;
|
||||
@@ -1356,7 +1548,35 @@ app.get("/docker/containers/:sessionId/:containerId", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /docker/containers/:sessionId/:containerId/start - Start container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/start:
|
||||
* post:
|
||||
* summary: Start container
|
||||
* description: Starts a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container started successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to start container.
|
||||
*/
|
||||
app.post(
|
||||
"/docker/containers/:sessionId/:containerId/start",
|
||||
async (req, res) => {
|
||||
@@ -1414,7 +1634,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// POST /docker/containers/:sessionId/:containerId/stop - Stop container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/stop:
|
||||
* post:
|
||||
* summary: Stop container
|
||||
* description: Stops a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container stopped successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to stop container.
|
||||
*/
|
||||
app.post(
|
||||
"/docker/containers/:sessionId/:containerId/stop",
|
||||
async (req, res) => {
|
||||
@@ -1472,7 +1720,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// POST /docker/containers/:sessionId/:containerId/restart - Restart container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/restart:
|
||||
* post:
|
||||
* summary: Restart container
|
||||
* description: Restarts a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container restarted successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to restart container.
|
||||
*/
|
||||
app.post(
|
||||
"/docker/containers/:sessionId/:containerId/restart",
|
||||
async (req, res) => {
|
||||
@@ -1530,7 +1806,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// POST /docker/containers/:sessionId/:containerId/pause - Pause container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/pause:
|
||||
* post:
|
||||
* summary: Pause container
|
||||
* description: Pauses a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container paused successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to pause container.
|
||||
*/
|
||||
app.post(
|
||||
"/docker/containers/:sessionId/:containerId/pause",
|
||||
async (req, res) => {
|
||||
@@ -1588,7 +1892,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// POST /docker/containers/:sessionId/:containerId/unpause - Unpause container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/unpause:
|
||||
* post:
|
||||
* summary: Unpause container
|
||||
* description: Unpauses a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container unpaused successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to unpause container.
|
||||
*/
|
||||
app.post(
|
||||
"/docker/containers/:sessionId/:containerId/unpause",
|
||||
async (req, res) => {
|
||||
@@ -1646,7 +1978,39 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// DELETE /docker/containers/:sessionId/:containerId/remove - Remove container
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/remove:
|
||||
* delete:
|
||||
* summary: Remove container
|
||||
* description: Removes a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: force
|
||||
* schema:
|
||||
* type: boolean
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container removed successfully.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected, or cannot remove a running container.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to remove container.
|
||||
*/
|
||||
app.delete(
|
||||
"/docker/containers/:sessionId/:containerId/remove",
|
||||
async (req, res) => {
|
||||
@@ -1718,7 +2082,51 @@ app.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// GET /docker/containers/:sessionId/:containerId/logs - Get container logs
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/logs:
|
||||
* get:
|
||||
* summary: Get container logs
|
||||
* description: Retrieves logs for a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: tail
|
||||
* schema:
|
||||
* type: integer
|
||||
* - in: query
|
||||
* name: timestamps
|
||||
* schema:
|
||||
* type: boolean
|
||||
* - in: query
|
||||
* name: since
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: until
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container logs.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to get container logs.
|
||||
*/
|
||||
app.get("/docker/containers/:sessionId/:containerId/logs", async (req, res) => {
|
||||
const { sessionId, containerId } = req.params;
|
||||
const tail = req.query.tail ? parseInt(req.query.tail as string) : 100;
|
||||
@@ -1795,7 +2203,35 @@ app.get("/docker/containers/:sessionId/:containerId/logs", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /docker/containers/:sessionId/:containerId/stats - Get container stats
|
||||
/**
|
||||
* @openapi
|
||||
* /docker/containers/{sessionId}/{containerId}/stats:
|
||||
* get:
|
||||
* summary: Get container stats
|
||||
* description: Retrieves stats for a specific container.
|
||||
* tags:
|
||||
* - Docker
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: path
|
||||
* name: containerId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Container stats.
|
||||
* 400:
|
||||
* description: SSH session not found or not connected.
|
||||
* 404:
|
||||
* description: Container not found.
|
||||
* 500:
|
||||
* description: Failed to get container stats.
|
||||
*/
|
||||
app.get(
|
||||
"/docker/containers/:sessionId/:containerId/stats",
|
||||
async (req, res) => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,8 @@ import { collectUptimeMetrics } from "./widgets/uptime-collector.js";
|
||||
import { collectProcessesMetrics } from "./widgets/processes-collector.js";
|
||||
import { collectSystemMetrics } from "./widgets/system-collector.js";
|
||||
import { collectLoginStats } from "./widgets/login-stats-collector.js";
|
||||
import { collectPortsMetrics } from "./widgets/ports-collector.js";
|
||||
import { collectFirewallMetrics } from "./widgets/firewall-collector.js";
|
||||
import { createSocks5Connection } from "../utils/socks5-helper.js";
|
||||
|
||||
async function resolveJumpHost(
|
||||
@@ -1782,6 +1784,62 @@ async function collectMetrics(host: SSHHostWithCredentials): Promise<{
|
||||
login_stats = await collectLoginStats(client);
|
||||
} catch (e) {}
|
||||
|
||||
let ports: {
|
||||
source: "ss" | "netstat" | "none";
|
||||
ports: Array<{
|
||||
protocol: "tcp" | "udp";
|
||||
localAddress: string;
|
||||
localPort: number;
|
||||
state?: string;
|
||||
pid?: number;
|
||||
process?: string;
|
||||
}>;
|
||||
} = {
|
||||
source: "none",
|
||||
ports: [],
|
||||
};
|
||||
try {
|
||||
ports = await collectPortsMetrics(client);
|
||||
} catch (e) {
|
||||
statsLogger.debug("Failed to collect ports metrics", {
|
||||
operation: "ports_metrics_failed",
|
||||
error: e instanceof Error ? e.message : String(e),
|
||||
});
|
||||
}
|
||||
|
||||
let firewall: {
|
||||
type: "iptables" | "nftables" | "none";
|
||||
status: "active" | "inactive" | "unknown";
|
||||
chains: Array<{
|
||||
name: string;
|
||||
policy: string;
|
||||
rules: Array<{
|
||||
chain: string;
|
||||
target: string;
|
||||
protocol: string;
|
||||
source: string;
|
||||
destination: string;
|
||||
dport?: string;
|
||||
sport?: string;
|
||||
state?: string;
|
||||
interface?: string;
|
||||
extra?: string;
|
||||
}>;
|
||||
}>;
|
||||
} = {
|
||||
type: "none",
|
||||
status: "unknown",
|
||||
chains: [],
|
||||
};
|
||||
try {
|
||||
firewall = await collectFirewallMetrics(client);
|
||||
} catch (e) {
|
||||
statsLogger.debug("Failed to collect firewall metrics", {
|
||||
operation: "firewall_metrics_failed",
|
||||
error: e instanceof Error ? e.message : String(e),
|
||||
});
|
||||
}
|
||||
|
||||
const result = {
|
||||
cpu,
|
||||
memory,
|
||||
@@ -1791,6 +1849,8 @@ async function collectMetrics(host: SSHHostWithCredentials): Promise<{
|
||||
processes,
|
||||
system,
|
||||
login_stats,
|
||||
ports,
|
||||
firewall,
|
||||
};
|
||||
|
||||
metricsCache.set(host.id, result);
|
||||
@@ -1864,6 +1924,20 @@ function tcpPing(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /status:
|
||||
* get:
|
||||
* summary: Get all host statuses
|
||||
* description: Retrieves the status of all hosts for the authenticated user.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A map of host IDs to their status entries.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
*/
|
||||
app.get("/status", async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
@@ -1886,6 +1960,28 @@ app.get("/status", async (req, res) => {
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /status/{id}:
|
||||
* get:
|
||||
* summary: Get host status by ID
|
||||
* description: Retrieves the status of a specific host by its ID.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Host status entry.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 404:
|
||||
* description: Status not available.
|
||||
*/
|
||||
app.get("/status/:id", validateHostId, async (req, res) => {
|
||||
const id = Number(req.params.id);
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -1910,6 +2006,20 @@ app.get("/status/:id", validateHostId, async (req, res) => {
|
||||
res.json(statusEntry);
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /clear-connections:
|
||||
* post:
|
||||
* summary: Clear all SSH connections
|
||||
* description: Clears all SSH connections from the connection pool.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* responses:
|
||||
* 200:
|
||||
* description: All SSH connections cleared.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
*/
|
||||
app.post("/clear-connections", async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
@@ -1924,6 +2034,20 @@ app.post("/clear-connections", async (req, res) => {
|
||||
res.json({ message: "All SSH connections cleared" });
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /refresh:
|
||||
* post:
|
||||
* summary: Refresh polling
|
||||
* description: Clears all SSH connections and refreshes host polling.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Polling refreshed.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
*/
|
||||
app.post("/refresh", async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
@@ -1940,6 +2064,35 @@ app.post("/refresh", async (req, res) => {
|
||||
res.json({ message: "Polling refreshed" });
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /host-updated:
|
||||
* post:
|
||||
* summary: Start polling for updated host
|
||||
* description: Starts polling for a specific host after it has been updated.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Host polling started.
|
||||
* 400:
|
||||
* description: Invalid hostId.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 404:
|
||||
* description: Host not found.
|
||||
* 500:
|
||||
* description: Failed to start polling.
|
||||
*/
|
||||
app.post("/host-updated", async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
const { hostId } = req.body;
|
||||
@@ -1975,6 +2128,33 @@ app.post("/host-updated", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /host-deleted:
|
||||
* post:
|
||||
* summary: Stop polling for deleted host
|
||||
* description: Stops polling for a specific host after it has been deleted.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Host polling stopped.
|
||||
* 400:
|
||||
* description: Invalid hostId.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 500:
|
||||
* description: Failed to stop polling.
|
||||
*/
|
||||
app.post("/host-deleted", async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
const { hostId } = req.body;
|
||||
@@ -2003,6 +2183,28 @@ app.post("/host-deleted", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/{id}:
|
||||
* get:
|
||||
* summary: Get host metrics
|
||||
* description: Retrieves current metrics for a specific host including CPU, memory, disk, network, processes, and system information.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Host metrics data.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 404:
|
||||
* description: Metrics not available.
|
||||
*/
|
||||
app.get("/metrics/:id", validateHostId, async (req, res) => {
|
||||
const id = Number(req.params.id);
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2040,6 +2242,30 @@ app.get("/metrics/:id", validateHostId, async (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/start/{id}:
|
||||
* post:
|
||||
* summary: Start metrics collection
|
||||
* description: Establishes an SSH connection and starts collecting metrics for a specific host.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Metrics collection started successfully, or TOTP required.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 404:
|
||||
* description: Host not found.
|
||||
* 500:
|
||||
* description: Failed to start metrics collection.
|
||||
*/
|
||||
app.post("/metrics/start/:id", validateHostId, async (req, res) => {
|
||||
const id = Number(req.params.id);
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2219,6 +2445,37 @@ app.post("/metrics/start/:id", validateHostId, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/stop/{id}:
|
||||
* post:
|
||||
* summary: Stop metrics collection
|
||||
* description: Stops metrics collection for a specific host and cleans up the SSH session.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: false
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* viewerSessionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Metrics collection stopped successfully.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 500:
|
||||
* description: Failed to stop metrics collection.
|
||||
*/
|
||||
app.post("/metrics/stop/:id", validateHostId, async (req, res) => {
|
||||
const id = Number(req.params.id);
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2261,6 +2518,37 @@ app.post("/metrics/stop/:id", validateHostId, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/connect-totp:
|
||||
* post:
|
||||
* summary: Complete TOTP verification for metrics
|
||||
* description: Verifies the TOTP code and completes the metrics SSH connection.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sessionId:
|
||||
* type: string
|
||||
* totpCode:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: TOTP verified, metrics connection established.
|
||||
* 400:
|
||||
* description: Missing sessionId or totpCode.
|
||||
* 401:
|
||||
* description: Session expired or invalid TOTP code.
|
||||
* 404:
|
||||
* description: TOTP session not found or expired.
|
||||
* 500:
|
||||
* description: Failed to verify TOTP.
|
||||
*/
|
||||
app.post("/metrics/connect-totp", async (req, res) => {
|
||||
const { sessionId, totpCode } = req.body;
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2396,6 +2684,35 @@ app.post("/metrics/connect-totp", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/heartbeat:
|
||||
* post:
|
||||
* summary: Update viewer heartbeat
|
||||
* description: Updates the heartbeat timestamp for a metrics viewer session to keep it alive.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* viewerSessionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Heartbeat updated successfully.
|
||||
* 400:
|
||||
* description: Invalid viewerSessionId.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 404:
|
||||
* description: Viewer session not found.
|
||||
* 500:
|
||||
* description: Failed to update heartbeat.
|
||||
*/
|
||||
app.post("/metrics/heartbeat", async (req, res) => {
|
||||
const { viewerSessionId } = req.body;
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2428,6 +2745,33 @@ app.post("/metrics/heartbeat", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/register-viewer:
|
||||
* post:
|
||||
* summary: Register metrics viewer
|
||||
* description: Registers a new viewer session for a host to track who is viewing metrics.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Viewer registered successfully.
|
||||
* 400:
|
||||
* description: Invalid hostId.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 500:
|
||||
* description: Failed to register viewer.
|
||||
*/
|
||||
app.post("/metrics/register-viewer", async (req, res) => {
|
||||
const { hostId } = req.body;
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -2458,6 +2802,35 @@ app.post("/metrics/register-viewer", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /metrics/unregister-viewer:
|
||||
* post:
|
||||
* summary: Unregister metrics viewer
|
||||
* description: Unregisters a viewer session when they stop viewing metrics for a host.
|
||||
* tags:
|
||||
* - Server Stats
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* hostId:
|
||||
* type: integer
|
||||
* viewerSessionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Viewer unregistered successfully.
|
||||
* 400:
|
||||
* description: Invalid hostId or viewerSessionId.
|
||||
* 401:
|
||||
* description: Session expired - please log in again.
|
||||
* 500:
|
||||
* description: Failed to unregister viewer.
|
||||
*/
|
||||
app.post("/metrics/unregister-viewer", async (req, res) => {
|
||||
const { hostId, viewerSessionId } = req.body;
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
|
||||
@@ -648,7 +648,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
);
|
||||
cleanupSSH(connectionTimeout);
|
||||
}
|
||||
}, 30000);
|
||||
}, 120000);
|
||||
|
||||
let resolvedCredentials = { password, key, keyPassword, keyType, authType };
|
||||
let authMethodNotAvailable = false;
|
||||
@@ -761,6 +761,36 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
return;
|
||||
}
|
||||
|
||||
sshLogger.info("Creating shell", {
|
||||
operation: "ssh_shell_start",
|
||||
hostId: id,
|
||||
ip,
|
||||
port,
|
||||
username,
|
||||
});
|
||||
|
||||
let shellCallbackReceived = false;
|
||||
const shellTimeout = setTimeout(() => {
|
||||
if (!shellCallbackReceived && isShellInitializing) {
|
||||
sshLogger.error("Shell creation timeout - no response from server", {
|
||||
operation: "ssh_shell_timeout",
|
||||
hostId: id,
|
||||
ip,
|
||||
port,
|
||||
username,
|
||||
});
|
||||
isShellInitializing = false;
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
message:
|
||||
"Shell creation timeout. The server may not support interactive shells or the connection was interrupted.",
|
||||
}),
|
||||
);
|
||||
cleanupSSH(connectionTimeout);
|
||||
}
|
||||
}, 15000);
|
||||
|
||||
conn.shell(
|
||||
{
|
||||
rows: data.rows,
|
||||
@@ -768,6 +798,8 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
term: "xterm-256color",
|
||||
} as PseudoTtyOptions,
|
||||
(err, stream) => {
|
||||
shellCallbackReceived = true;
|
||||
clearTimeout(shellTimeout);
|
||||
isShellInitializing = false;
|
||||
|
||||
if (err) {
|
||||
@@ -784,6 +816,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
message: "Shell error: " + err.message,
|
||||
}),
|
||||
);
|
||||
cleanupSSH(connectionTimeout);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -969,6 +1002,31 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
|
||||
sshConn.on("close", () => {
|
||||
clearTimeout(connectionTimeout);
|
||||
if (isShellInitializing || (isConnected && !sshStream)) {
|
||||
sshLogger.warn("SSH connection closed during shell initialization", {
|
||||
operation: "ssh_close_during_init",
|
||||
hostId: id,
|
||||
ip,
|
||||
port,
|
||||
username,
|
||||
isShellInitializing,
|
||||
hasStream: !!sshStream,
|
||||
});
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
message:
|
||||
"Connection closed during shell initialization. The server may have rejected the shell request.",
|
||||
}),
|
||||
);
|
||||
} else if (!sshStream) {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "disconnected",
|
||||
message: "Connection closed",
|
||||
}),
|
||||
);
|
||||
}
|
||||
cleanupSSH(connectionTimeout);
|
||||
});
|
||||
|
||||
@@ -1115,10 +1173,10 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
tryKeyboard: true,
|
||||
keepaliveInterval: 30000,
|
||||
keepaliveCountMax: 3,
|
||||
readyTimeout: 30000,
|
||||
readyTimeout: 120000,
|
||||
tcpKeepAlive: true,
|
||||
tcpKeepAliveInitialDelay: 30000,
|
||||
timeout: 30000,
|
||||
timeout: 120000,
|
||||
env: {
|
||||
TERM: "xterm-256color",
|
||||
LANG: "en_US.UTF-8",
|
||||
|
||||
@@ -828,15 +828,22 @@ async function connectSSHTunnel(
|
||||
return;
|
||||
}
|
||||
|
||||
const tunnelType = tunnelConfig.tunnelType || "remote";
|
||||
const tunnelFlag = tunnelType === "local" ? "-L" : "-R";
|
||||
const portMapping =
|
||||
tunnelType === "local"
|
||||
? `${tunnelConfig.sourcePort}:${tunnelConfig.endpointIP}:${tunnelConfig.endpointPort}`
|
||||
: `${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort}`;
|
||||
|
||||
let tunnelCmd: string;
|
||||
if (
|
||||
resolvedEndpointCredentials.authMethod === "key" &&
|
||||
resolvedEndpointCredentials.sshKey
|
||||
) {
|
||||
const keyFilePath = `/tmp/tunnel_key_${tunnelName.replace(/[^a-zA-Z0-9]/g, "_")}`;
|
||||
tunnelCmd = `echo '${resolvedEndpointCredentials.sshKey}' > ${keyFilePath} && chmod 600 ${keyFilePath} && exec -a "${tunnelMarker}" ssh -i ${keyFilePath} -N -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o GatewayPorts=yes -R ${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort} ${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP} && rm -f ${keyFilePath}`;
|
||||
tunnelCmd = `echo '${resolvedEndpointCredentials.sshKey}' > ${keyFilePath} && chmod 600 ${keyFilePath} && exec -a "${tunnelMarker}" ssh -i ${keyFilePath} -N -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o GatewayPorts=yes ${tunnelFlag} ${portMapping} ${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP} && rm -f ${keyFilePath}`;
|
||||
} else {
|
||||
tunnelCmd = `exec -a "${tunnelMarker}" sshpass -p '${resolvedEndpointCredentials.password || ""}' ssh -N -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o GatewayPorts=yes -R ${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort} ${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}`;
|
||||
tunnelCmd = `exec -a "${tunnelMarker}" sshpass -p '${resolvedEndpointCredentials.password || ""}' ssh -N -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o GatewayPorts=yes ${tunnelFlag} ${portMapping} ${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}`;
|
||||
}
|
||||
|
||||
conn.exec(tunnelCmd, (err, stream) => {
|
||||
@@ -1302,7 +1309,9 @@ async function killRemoteTunnelByMarker(
|
||||
}
|
||||
|
||||
conn.on("ready", () => {
|
||||
const checkCmd = `ps aux | grep -E '(${tunnelMarker}|ssh.*-R.*${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort}.*${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}|sshpass.*ssh.*-R.*${tunnelConfig.endpointPort})' | grep -v grep`;
|
||||
const tunnelType = tunnelConfig.tunnelType || "remote";
|
||||
const tunnelFlag = tunnelType === "local" ? "-L" : "-R";
|
||||
const checkCmd = `ps aux | grep -E '(${tunnelMarker}|ssh.*${tunnelFlag}.*${tunnelConfig.endpointPort}:.*:${tunnelConfig.sourcePort}.*${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}|sshpass.*ssh.*${tunnelFlag})' | grep -v grep`;
|
||||
|
||||
conn.exec(checkCmd, (_err, stream) => {
|
||||
let foundProcesses = false;
|
||||
@@ -1323,8 +1332,8 @@ async function killRemoteTunnelByMarker(
|
||||
|
||||
const killCmds = [
|
||||
`pkill -TERM -f '${tunnelMarker}'`,
|
||||
`sleep 1 && pkill -f 'ssh.*-R.*${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort}.*${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}'`,
|
||||
`sleep 1 && pkill -f 'sshpass.*ssh.*-R.*${tunnelConfig.endpointPort}'`,
|
||||
`sleep 1 && pkill -f 'ssh.*${tunnelFlag}.*${tunnelConfig.endpointPort}:.*:${tunnelConfig.sourcePort}.*${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}'`,
|
||||
`sleep 1 && pkill -f 'sshpass.*ssh.*${tunnelFlag}.*${tunnelConfig.endpointPort}'`,
|
||||
`sleep 2 && pkill -9 -f '${tunnelMarker}'`,
|
||||
];
|
||||
|
||||
@@ -1450,10 +1459,42 @@ async function killRemoteTunnelByMarker(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /ssh/tunnel/status:
|
||||
* get:
|
||||
* summary: Get all tunnel statuses
|
||||
* description: Retrieves the status of all SSH tunnels.
|
||||
* tags:
|
||||
* - SSH Tunnels
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of all tunnel statuses.
|
||||
*/
|
||||
app.get("/ssh/tunnel/status", (req, res) => {
|
||||
res.json(getAllTunnelStatus());
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /ssh/tunnel/status/{tunnelName}:
|
||||
* get:
|
||||
* summary: Get tunnel status by name
|
||||
* description: Retrieves the status of a specific SSH tunnel by its name.
|
||||
* tags:
|
||||
* - SSH Tunnels
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: tunnelName
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Tunnel status.
|
||||
* 404:
|
||||
* description: Tunnel not found.
|
||||
*/
|
||||
app.get("/ssh/tunnel/status/:tunnelName", (req, res) => {
|
||||
const { tunnelName } = req.params;
|
||||
const status = connectionStatus.get(tunnelName);
|
||||
@@ -1465,6 +1506,39 @@ app.get("/ssh/tunnel/status/:tunnelName", (req, res) => {
|
||||
res.json({ name: tunnelName, status });
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /ssh/tunnel/connect:
|
||||
* post:
|
||||
* summary: Connect SSH tunnel
|
||||
* description: Establishes an SSH tunnel connection with the specified configuration.
|
||||
* tags:
|
||||
* - SSH Tunnels
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* sourceHostId:
|
||||
* type: integer
|
||||
* tunnelIndex:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Connection request received.
|
||||
* 400:
|
||||
* description: Invalid tunnel configuration.
|
||||
* 401:
|
||||
* description: Authentication required.
|
||||
* 403:
|
||||
* description: Access denied to this host.
|
||||
* 500:
|
||||
* description: Failed to connect tunnel.
|
||||
*/
|
||||
app.post(
|
||||
"/ssh/tunnel/connect",
|
||||
authenticateJWT,
|
||||
@@ -1619,6 +1693,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /ssh/tunnel/disconnect:
|
||||
* post:
|
||||
* summary: Disconnect SSH tunnel
|
||||
* description: Disconnects an active SSH tunnel.
|
||||
* tags:
|
||||
* - SSH Tunnels
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* tunnelName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Disconnect request received.
|
||||
* 400:
|
||||
* description: Tunnel name required.
|
||||
* 401:
|
||||
* description: Authentication required.
|
||||
* 403:
|
||||
* description: Access denied.
|
||||
* 500:
|
||||
* description: Failed to disconnect tunnel.
|
||||
*/
|
||||
app.post(
|
||||
"/ssh/tunnel/disconnect",
|
||||
authenticateJWT,
|
||||
@@ -1683,6 +1786,35 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /ssh/tunnel/cancel:
|
||||
* post:
|
||||
* summary: Cancel tunnel retry
|
||||
* description: Cancels the retry mechanism for a failed SSH tunnel connection.
|
||||
* tags:
|
||||
* - SSH Tunnels
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* tunnelName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Cancel request received.
|
||||
* 400:
|
||||
* description: Tunnel name required.
|
||||
* 401:
|
||||
* description: Authentication required.
|
||||
* 403:
|
||||
* description: Access denied.
|
||||
* 500:
|
||||
* description: Failed to cancel tunnel retry.
|
||||
*/
|
||||
app.post(
|
||||
"/ssh/tunnel/cancel",
|
||||
authenticateJWT,
|
||||
@@ -1806,6 +1938,7 @@ async function initializeAutoStartTunnels(): Promise<void> {
|
||||
tunnelConnection.endpointHost,
|
||||
tunnelConnection.endpointPort,
|
||||
),
|
||||
tunnelType: tunnelConnection.tunnelType || "remote",
|
||||
sourceHostId: host.id,
|
||||
tunnelIndex: tunnelIndex,
|
||||
hostName: host.name || `${host.username}@${host.ip}`,
|
||||
|
||||
254
src/backend/ssh/widgets/firewall-collector.ts
Normal file
254
src/backend/ssh/widgets/firewall-collector.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import type { Client } from "ssh2";
|
||||
import { execCommand } from "./common-utils.js";
|
||||
import type {
|
||||
FirewallMetrics,
|
||||
FirewallChain,
|
||||
FirewallRule,
|
||||
} from "../../../types/stats-widgets.js";
|
||||
|
||||
function parseIptablesRule(line: string): FirewallRule | null {
|
||||
if (!line.startsWith("-A ")) return null;
|
||||
|
||||
const rule: FirewallRule = {
|
||||
chain: "",
|
||||
target: "",
|
||||
protocol: "all",
|
||||
source: "0.0.0.0/0",
|
||||
destination: "0.0.0.0/0",
|
||||
};
|
||||
|
||||
const chainMatch = line.match(/^-A\s+(\S+)/);
|
||||
if (chainMatch) {
|
||||
rule.chain = chainMatch[1];
|
||||
}
|
||||
|
||||
const targetMatch = line.match(/-j\s+(\S+)/);
|
||||
if (targetMatch) {
|
||||
rule.target = targetMatch[1];
|
||||
}
|
||||
|
||||
const protocolMatch = line.match(/-p\s+(\S+)/);
|
||||
if (protocolMatch) {
|
||||
rule.protocol = protocolMatch[1];
|
||||
}
|
||||
|
||||
const sourceMatch = line.match(/-s\s+(\S+)/);
|
||||
if (sourceMatch) {
|
||||
rule.source = sourceMatch[1];
|
||||
}
|
||||
|
||||
const destMatch = line.match(/-d\s+(\S+)/);
|
||||
if (destMatch) {
|
||||
rule.destination = destMatch[1];
|
||||
}
|
||||
|
||||
const dportMatch = line.match(/--dport\s+(\S+)/);
|
||||
if (dportMatch) {
|
||||
rule.dport = dportMatch[1];
|
||||
}
|
||||
|
||||
const sportMatch = line.match(/--sport\s+(\S+)/);
|
||||
if (sportMatch) {
|
||||
rule.sport = sportMatch[1];
|
||||
}
|
||||
|
||||
const stateMatch = line.match(/--state\s+(\S+)/);
|
||||
if (stateMatch) {
|
||||
rule.state = stateMatch[1];
|
||||
}
|
||||
|
||||
const interfaceMatch = line.match(/-i\s+(\S+)/);
|
||||
if (interfaceMatch) {
|
||||
rule.interface = interfaceMatch[1];
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
function parseIptablesOutput(output: string): FirewallChain[] {
|
||||
const chains: Map<string, FirewallChain> = new Map();
|
||||
const lines = output.split("\n");
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
const policyMatch = trimmed.match(/^:(\S+)\s+(\S+)/);
|
||||
if (policyMatch) {
|
||||
const [, chainName, policy] = policyMatch;
|
||||
chains.set(chainName, {
|
||||
name: chainName,
|
||||
policy: policy,
|
||||
rules: [],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const rule = parseIptablesRule(trimmed);
|
||||
if (rule) {
|
||||
let chain = chains.get(rule.chain);
|
||||
if (!chain) {
|
||||
chain = {
|
||||
name: rule.chain,
|
||||
policy: "ACCEPT",
|
||||
rules: [],
|
||||
};
|
||||
chains.set(rule.chain, chain);
|
||||
}
|
||||
chain.rules.push(rule);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(chains.values());
|
||||
}
|
||||
|
||||
function parseNftablesOutput(output: string): FirewallChain[] {
|
||||
const chains: FirewallChain[] = [];
|
||||
let currentChain: FirewallChain | null = null;
|
||||
|
||||
const lines = output.split("\n");
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
const chainMatch = trimmed.match(
|
||||
/chain\s+(\S+)\s*\{?\s*(?:type\s+\S+\s+hook\s+(\S+))?/,
|
||||
);
|
||||
if (chainMatch) {
|
||||
if (currentChain) {
|
||||
chains.push(currentChain);
|
||||
}
|
||||
currentChain = {
|
||||
name: chainMatch[1].toUpperCase(),
|
||||
policy: "ACCEPT",
|
||||
rules: [],
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentChain && trimmed.startsWith("policy ")) {
|
||||
const policyMatch = trimmed.match(/policy\s+(\S+)/);
|
||||
if (policyMatch) {
|
||||
currentChain.policy = policyMatch[1].toUpperCase();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentChain && trimmed && !trimmed.startsWith("}")) {
|
||||
const rule: FirewallRule = {
|
||||
chain: currentChain.name,
|
||||
target: "",
|
||||
protocol: "all",
|
||||
source: "0.0.0.0/0",
|
||||
destination: "0.0.0.0/0",
|
||||
};
|
||||
|
||||
if (trimmed.includes("accept")) rule.target = "ACCEPT";
|
||||
else if (trimmed.includes("drop")) rule.target = "DROP";
|
||||
else if (trimmed.includes("reject")) rule.target = "REJECT";
|
||||
|
||||
const tcpMatch = trimmed.match(/tcp\s+dport\s+(\S+)/);
|
||||
if (tcpMatch) {
|
||||
rule.protocol = "tcp";
|
||||
rule.dport = tcpMatch[1];
|
||||
}
|
||||
|
||||
const udpMatch = trimmed.match(/udp\s+dport\s+(\S+)/);
|
||||
if (udpMatch) {
|
||||
rule.protocol = "udp";
|
||||
rule.dport = udpMatch[1];
|
||||
}
|
||||
|
||||
const saddrMatch = trimmed.match(/saddr\s+(\S+)/);
|
||||
if (saddrMatch) {
|
||||
rule.source = saddrMatch[1];
|
||||
}
|
||||
|
||||
const daddrMatch = trimmed.match(/daddr\s+(\S+)/);
|
||||
if (daddrMatch) {
|
||||
rule.destination = daddrMatch[1];
|
||||
}
|
||||
|
||||
const iifMatch = trimmed.match(/iif\s+"?(\S+)"?/);
|
||||
if (iifMatch) {
|
||||
rule.interface = iifMatch[1].replace(/"/g, "");
|
||||
}
|
||||
|
||||
const ctStateMatch = trimmed.match(/ct\s+state\s+(\S+)/);
|
||||
if (ctStateMatch) {
|
||||
rule.state = ctStateMatch[1].toUpperCase();
|
||||
}
|
||||
|
||||
if (rule.target) {
|
||||
currentChain.rules.push(rule);
|
||||
}
|
||||
}
|
||||
|
||||
if (trimmed === "}") {
|
||||
if (currentChain) {
|
||||
chains.push(currentChain);
|
||||
currentChain = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentChain) {
|
||||
chains.push(currentChain);
|
||||
}
|
||||
|
||||
return chains;
|
||||
}
|
||||
|
||||
export async function collectFirewallMetrics(
|
||||
client: Client,
|
||||
): Promise<FirewallMetrics> {
|
||||
try {
|
||||
const iptablesResult = await execCommand(
|
||||
client,
|
||||
"iptables-save 2>/dev/null",
|
||||
15000,
|
||||
);
|
||||
|
||||
if (iptablesResult.stdout && iptablesResult.stdout.includes("*filter")) {
|
||||
const chains = parseIptablesOutput(iptablesResult.stdout);
|
||||
const hasRules = chains.some((c) => c.rules.length > 0);
|
||||
|
||||
return {
|
||||
type: "iptables",
|
||||
status: hasRules ? "active" : "inactive",
|
||||
chains: chains.filter(
|
||||
(c) =>
|
||||
c.name === "INPUT" || c.name === "OUTPUT" || c.name === "FORWARD",
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const nftResult = await execCommand(
|
||||
client,
|
||||
"nft list ruleset 2>/dev/null",
|
||||
15000,
|
||||
);
|
||||
|
||||
if (nftResult.stdout && nftResult.stdout.trim()) {
|
||||
const chains = parseNftablesOutput(nftResult.stdout);
|
||||
const hasRules = chains.some((c) => c.rules.length > 0);
|
||||
|
||||
return {
|
||||
type: "nftables",
|
||||
status: hasRules ? "active" : "inactive",
|
||||
chains,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: "none",
|
||||
status: "unknown",
|
||||
chains: [],
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
type: "none",
|
||||
status: "unknown",
|
||||
chains: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
155
src/backend/ssh/widgets/ports-collector.ts
Normal file
155
src/backend/ssh/widgets/ports-collector.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import type { Client } from "ssh2";
|
||||
import { execCommand } from "./common-utils.js";
|
||||
import type { PortsMetrics, ListeningPort } from "../../../types/stats-widgets.js";
|
||||
|
||||
function parseSsOutput(output: string): ListeningPort[] {
|
||||
const ports: ListeningPort[] = [];
|
||||
const lines = output.split("\n").slice(1);
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
|
||||
const parts = trimmed.split(/\s+/);
|
||||
if (parts.length < 5) continue;
|
||||
|
||||
const protocol = parts[0]?.toLowerCase();
|
||||
if (protocol !== "tcp" && protocol !== "udp") continue;
|
||||
|
||||
const state = parts[1];
|
||||
const localAddr = parts[4];
|
||||
|
||||
if (!localAddr) continue;
|
||||
|
||||
const lastColon = localAddr.lastIndexOf(":");
|
||||
if (lastColon === -1) continue;
|
||||
|
||||
const address = localAddr.substring(0, lastColon);
|
||||
const portStr = localAddr.substring(lastColon + 1);
|
||||
const port = parseInt(portStr, 10);
|
||||
|
||||
if (isNaN(port)) continue;
|
||||
|
||||
const portEntry: ListeningPort = {
|
||||
protocol: protocol as "tcp" | "udp",
|
||||
localAddress: address.replace(/^\[|\]$/g, ""),
|
||||
localPort: port,
|
||||
state: protocol === "tcp" ? state : undefined,
|
||||
};
|
||||
|
||||
const processInfo = parts[6];
|
||||
if (processInfo && processInfo.startsWith("users:")) {
|
||||
const pidMatch = processInfo.match(/pid=(\d+)/);
|
||||
const nameMatch = processInfo.match(/\("([^"]+)"/);
|
||||
if (pidMatch) portEntry.pid = parseInt(pidMatch[1], 10);
|
||||
if (nameMatch) portEntry.process = nameMatch[1];
|
||||
}
|
||||
|
||||
ports.push(portEntry);
|
||||
}
|
||||
|
||||
return ports;
|
||||
}
|
||||
|
||||
function parseNetstatOutput(output: string): ListeningPort[] {
|
||||
const ports: ListeningPort[] = [];
|
||||
const lines = output.split("\n");
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
|
||||
const parts = trimmed.split(/\s+/);
|
||||
if (parts.length < 4) continue;
|
||||
|
||||
const proto = parts[0]?.toLowerCase();
|
||||
if (!proto) continue;
|
||||
|
||||
let protocol: "tcp" | "udp";
|
||||
if (proto.startsWith("tcp")) {
|
||||
protocol = "tcp";
|
||||
} else if (proto.startsWith("udp")) {
|
||||
protocol = "udp";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const localAddr = parts[3];
|
||||
if (!localAddr) continue;
|
||||
|
||||
const lastColon = localAddr.lastIndexOf(":");
|
||||
if (lastColon === -1) continue;
|
||||
|
||||
const address = localAddr.substring(0, lastColon);
|
||||
const portStr = localAddr.substring(lastColon + 1);
|
||||
const port = parseInt(portStr, 10);
|
||||
|
||||
if (isNaN(port)) continue;
|
||||
|
||||
const portEntry: ListeningPort = {
|
||||
protocol,
|
||||
localAddress: address,
|
||||
localPort: port,
|
||||
};
|
||||
|
||||
if (protocol === "tcp" && parts.length >= 6) {
|
||||
portEntry.state = parts[5];
|
||||
}
|
||||
|
||||
const pidProgram = parts[parts.length - 1];
|
||||
if (pidProgram && pidProgram.includes("/")) {
|
||||
const [pidStr, process] = pidProgram.split("/");
|
||||
const pid = parseInt(pidStr, 10);
|
||||
if (!isNaN(pid)) portEntry.pid = pid;
|
||||
if (process) portEntry.process = process;
|
||||
}
|
||||
|
||||
ports.push(portEntry);
|
||||
}
|
||||
|
||||
return ports;
|
||||
}
|
||||
|
||||
export async function collectPortsMetrics(
|
||||
client: Client,
|
||||
): Promise<PortsMetrics> {
|
||||
try {
|
||||
const ssResult = await execCommand(
|
||||
client,
|
||||
"ss -tulnp 2>/dev/null",
|
||||
15000,
|
||||
);
|
||||
|
||||
if (ssResult.stdout && ssResult.stdout.includes("Local")) {
|
||||
const ports = parseSsOutput(ssResult.stdout);
|
||||
return {
|
||||
source: "ss",
|
||||
ports: ports.sort((a, b) => a.localPort - b.localPort),
|
||||
};
|
||||
}
|
||||
|
||||
const netstatResult = await execCommand(
|
||||
client,
|
||||
"netstat -tulnp 2>/dev/null",
|
||||
15000,
|
||||
);
|
||||
|
||||
if (netstatResult.stdout && netstatResult.stdout.includes("Local")) {
|
||||
const ports = parseNetstatOutput(netstatResult.stdout);
|
||||
return {
|
||||
source: "netstat",
|
||||
ports: ports.sort((a, b) => a.localPort - b.localPort),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
source: "none",
|
||||
ports: [],
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
source: "none",
|
||||
ports: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
145
src/backend/swagger.ts
Normal file
145
src/backend/swagger.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import swaggerJSDoc from "swagger-jsdoc";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { promises as fs } from "fs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const projectRoot = path.join(__dirname, "..", "..", "..");
|
||||
|
||||
const swaggerOptions: swaggerJSDoc.Options = {
|
||||
definition: {
|
||||
openapi: "3.0.3",
|
||||
info: {
|
||||
title: "Termix API",
|
||||
version: "0.0.0",
|
||||
description: "Termix Backend API Reference",
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: "http://localhost:30001",
|
||||
description: "Main database and authentication server",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:30003",
|
||||
description: "SSH tunnel management server",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:30004",
|
||||
description: "SSH file manager server",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:30005",
|
||||
description: "Server statistics and monitoring server",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:30006",
|
||||
description: "Dashboard server",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:30007",
|
||||
description: "Docker management server",
|
||||
},
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
},
|
||||
},
|
||||
schemas: {
|
||||
Error: {
|
||||
type: "object",
|
||||
properties: {
|
||||
error: { type: "string" },
|
||||
details: { type: "string" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
{
|
||||
name: "Alerts",
|
||||
description: "System alerts and notifications management",
|
||||
},
|
||||
{
|
||||
name: "Credentials",
|
||||
description: "SSH credential management",
|
||||
},
|
||||
{
|
||||
name: "Network Topology",
|
||||
description: "Network topology visualization and management",
|
||||
},
|
||||
{
|
||||
name: "RBAC",
|
||||
description: "Role-based access control for host sharing",
|
||||
},
|
||||
{
|
||||
name: "Snippets",
|
||||
description: "Command snippet management",
|
||||
},
|
||||
{
|
||||
name: "Terminal",
|
||||
description: "Terminal command history",
|
||||
},
|
||||
{
|
||||
name: "Users",
|
||||
description: "User management and authentication",
|
||||
},
|
||||
{
|
||||
name: "Dashboard",
|
||||
description: "Dashboard statistics and activity",
|
||||
},
|
||||
{
|
||||
name: "Docker",
|
||||
description: "Docker container management",
|
||||
},
|
||||
{
|
||||
name: "SSH Tunnels",
|
||||
description: "SSH tunnel connection management",
|
||||
},
|
||||
{
|
||||
name: "Server Stats",
|
||||
description: "Server status monitoring and metrics collection",
|
||||
},
|
||||
{
|
||||
name: "File Manager",
|
||||
description: "SSH file management operations",
|
||||
},
|
||||
],
|
||||
},
|
||||
apis: [
|
||||
path.join(projectRoot, "src", "backend", "database", "routes", "*.ts"),
|
||||
path.join(projectRoot, "src", "backend", "dashboard.ts"),
|
||||
path.join(projectRoot, "src", "backend", "ssh", "*.ts"),
|
||||
],
|
||||
};
|
||||
|
||||
async function generateOpenAPISpec() {
|
||||
try {
|
||||
const swaggerSpec = swaggerJSDoc(swaggerOptions);
|
||||
|
||||
const outputPath = path.join(projectRoot, "openapi.json");
|
||||
|
||||
await fs.writeFile(
|
||||
outputPath,
|
||||
JSON.stringify(swaggerSpec, null, 2),
|
||||
"utf-8",
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to generate OpenAPI specification:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
generateOpenAPISpec();
|
||||
|
||||
export { swaggerOptions, generateOpenAPISpec };
|
||||
@@ -32,7 +32,6 @@ class FieldCrypto {
|
||||
"key",
|
||||
"key_password",
|
||||
"keyPassword",
|
||||
"keyType",
|
||||
"autostartPassword",
|
||||
"autostartKey",
|
||||
"autostartKeyPassword",
|
||||
@@ -46,7 +45,6 @@ class FieldCrypto {
|
||||
"key",
|
||||
"public_key",
|
||||
"publicKey",
|
||||
"keyType",
|
||||
]),
|
||||
};
|
||||
|
||||
|
||||
@@ -7,11 +7,21 @@ interface LoginAttempt {
|
||||
class LoginRateLimiter {
|
||||
private ipAttempts = new Map<string, LoginAttempt>();
|
||||
private usernameAttempts = new Map<string, LoginAttempt>();
|
||||
private totpAttempts = new Map<string, LoginAttempt>();
|
||||
private resetCodeAttempts = new Map<string, LoginAttempt>();
|
||||
|
||||
private readonly MAX_ATTEMPTS = 5;
|
||||
private readonly WINDOW_MS = 10 * 60 * 1000;
|
||||
private readonly LOCKOUT_MS = 10 * 60 * 1000;
|
||||
|
||||
private readonly TOTP_MAX_ATTEMPTS = 5;
|
||||
private readonly TOTP_WINDOW_MS = 1 * 60 * 1000;
|
||||
private readonly TOTP_LOCKOUT_MS = 5 * 60 * 1000;
|
||||
|
||||
private readonly RESET_CODE_MAX_ATTEMPTS = 5;
|
||||
private readonly RESET_CODE_WINDOW_MS = 1 * 60 * 1000;
|
||||
private readonly RESET_CODE_LOCKOUT_MS = 5 * 60 * 1000;
|
||||
|
||||
constructor() {
|
||||
setInterval(() => this.cleanup(), 5 * 60 * 1000);
|
||||
}
|
||||
@@ -40,6 +50,28 @@ class LoginRateLimiter {
|
||||
this.usernameAttempts.delete(username);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [userId, attempt] of this.totpAttempts.entries()) {
|
||||
if (attempt.lockedUntil && attempt.lockedUntil < now) {
|
||||
this.totpAttempts.delete(userId);
|
||||
} else if (
|
||||
!attempt.lockedUntil &&
|
||||
now - attempt.firstAttempt > this.TOTP_WINDOW_MS
|
||||
) {
|
||||
this.totpAttempts.delete(userId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [username, attempt] of this.resetCodeAttempts.entries()) {
|
||||
if (attempt.lockedUntil && attempt.lockedUntil < now) {
|
||||
this.resetCodeAttempts.delete(username);
|
||||
} else if (
|
||||
!attempt.lockedUntil &&
|
||||
now - attempt.firstAttempt > this.RESET_CODE_WINDOW_MS
|
||||
) {
|
||||
this.resetCodeAttempts.delete(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recordFailedAttempt(ip: string, username?: string): void {
|
||||
@@ -141,6 +173,114 @@ class LoginRateLimiter {
|
||||
|
||||
return minRemaining;
|
||||
}
|
||||
|
||||
recordFailedTOTPAttempt(userId: string): void {
|
||||
const now = Date.now();
|
||||
|
||||
const totpAttempt = this.totpAttempts.get(userId);
|
||||
if (!totpAttempt) {
|
||||
this.totpAttempts.set(userId, {
|
||||
count: 1,
|
||||
firstAttempt: now,
|
||||
});
|
||||
} else if (now - totpAttempt.firstAttempt > this.TOTP_WINDOW_MS) {
|
||||
this.totpAttempts.set(userId, {
|
||||
count: 1,
|
||||
firstAttempt: now,
|
||||
});
|
||||
} else {
|
||||
totpAttempt.count++;
|
||||
if (totpAttempt.count >= this.TOTP_MAX_ATTEMPTS) {
|
||||
totpAttempt.lockedUntil = now + this.TOTP_LOCKOUT_MS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetTOTPAttempts(userId: string): void {
|
||||
this.totpAttempts.delete(userId);
|
||||
}
|
||||
|
||||
isTOTPLocked(userId: string): { locked: boolean; remainingTime?: number } {
|
||||
const now = Date.now();
|
||||
|
||||
const totpAttempt = this.totpAttempts.get(userId);
|
||||
if (totpAttempt?.lockedUntil && totpAttempt.lockedUntil > now) {
|
||||
return {
|
||||
locked: true,
|
||||
remainingTime: Math.ceil((totpAttempt.lockedUntil - now) / 1000),
|
||||
};
|
||||
}
|
||||
|
||||
return { locked: false };
|
||||
}
|
||||
|
||||
getRemainingTOTPAttempts(userId: string): number {
|
||||
const now = Date.now();
|
||||
|
||||
const totpAttempt = this.totpAttempts.get(userId);
|
||||
if (totpAttempt && now - totpAttempt.firstAttempt <= this.TOTP_WINDOW_MS) {
|
||||
return Math.max(0, this.TOTP_MAX_ATTEMPTS - totpAttempt.count);
|
||||
}
|
||||
|
||||
return this.TOTP_MAX_ATTEMPTS;
|
||||
}
|
||||
|
||||
recordResetCodeAttempt(username: string): void {
|
||||
const now = Date.now();
|
||||
|
||||
const resetAttempt = this.resetCodeAttempts.get(username);
|
||||
if (!resetAttempt) {
|
||||
this.resetCodeAttempts.set(username, {
|
||||
count: 1,
|
||||
firstAttempt: now,
|
||||
});
|
||||
} else if (now - resetAttempt.firstAttempt > this.RESET_CODE_WINDOW_MS) {
|
||||
this.resetCodeAttempts.set(username, {
|
||||
count: 1,
|
||||
firstAttempt: now,
|
||||
});
|
||||
} else {
|
||||
resetAttempt.count++;
|
||||
if (resetAttempt.count >= this.RESET_CODE_MAX_ATTEMPTS) {
|
||||
resetAttempt.lockedUntil = now + this.RESET_CODE_LOCKOUT_MS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetResetCodeAttempts(username: string): void {
|
||||
this.resetCodeAttempts.delete(username);
|
||||
}
|
||||
|
||||
isResetCodeLocked(username: string): {
|
||||
locked: boolean;
|
||||
remainingTime?: number;
|
||||
} {
|
||||
const now = Date.now();
|
||||
|
||||
const resetAttempt = this.resetCodeAttempts.get(username);
|
||||
if (resetAttempt?.lockedUntil && resetAttempt.lockedUntil > now) {
|
||||
return {
|
||||
locked: true,
|
||||
remainingTime: Math.ceil((resetAttempt.lockedUntil - now) / 1000),
|
||||
};
|
||||
}
|
||||
|
||||
return { locked: false };
|
||||
}
|
||||
|
||||
getRemainingResetCodeAttempts(username: string): number {
|
||||
const now = Date.now();
|
||||
|
||||
const resetAttempt = this.resetCodeAttempts.get(username);
|
||||
if (
|
||||
resetAttempt &&
|
||||
now - resetAttempt.firstAttempt <= this.RESET_CODE_WINDOW_MS
|
||||
) {
|
||||
return Math.max(0, this.RESET_CODE_MAX_ATTEMPTS - resetAttempt.count);
|
||||
}
|
||||
|
||||
return this.RESET_CODE_MAX_ATTEMPTS;
|
||||
}
|
||||
}
|
||||
|
||||
export const loginRateLimiter = new LoginRateLimiter();
|
||||
|
||||
@@ -177,30 +177,57 @@ class UserDataImport {
|
||||
continue;
|
||||
}
|
||||
|
||||
const tempId = `import-ssh-${targetUserId}-${Date.now()}-${imported}`;
|
||||
const newHostData = {
|
||||
const existing = await getDb()
|
||||
.select()
|
||||
.from(sshData)
|
||||
.where(
|
||||
and(
|
||||
eq(sshData.userId, targetUserId),
|
||||
eq(sshData.ip, host.ip as string),
|
||||
eq(sshData.port, host.port as number),
|
||||
eq(sshData.username, host.username as string),
|
||||
),
|
||||
);
|
||||
|
||||
if (existing.length > 0 && !options.replaceExisting) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const newHostData: any = {
|
||||
...host,
|
||||
id: tempId,
|
||||
userId: targetUserId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
let processedHostData = newHostData;
|
||||
if (existing.length === 0) {
|
||||
newHostData.createdAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
let processedHostData: any = newHostData;
|
||||
if (options.userDataKey) {
|
||||
processedHostData = DataCrypto.encryptRecord(
|
||||
"ssh_data",
|
||||
newHostData,
|
||||
targetUserId,
|
||||
options.userDataKey,
|
||||
);
|
||||
) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
delete processedHostData.id;
|
||||
|
||||
await getDb()
|
||||
.insert(sshData)
|
||||
.values(processedHostData as unknown as typeof sshData.$inferInsert);
|
||||
if (existing.length > 0 && options.replaceExisting) {
|
||||
await getDb()
|
||||
.update(sshData)
|
||||
.set(processedHostData as unknown as typeof sshData.$inferInsert)
|
||||
.where(eq(sshData.id, existing[0].id));
|
||||
} else {
|
||||
await getDb()
|
||||
.insert(sshData)
|
||||
.values(
|
||||
processedHostData as unknown as typeof sshData.$inferInsert,
|
||||
);
|
||||
}
|
||||
imported++;
|
||||
} catch (error) {
|
||||
errors.push(
|
||||
@@ -233,34 +260,59 @@ class UserDataImport {
|
||||
continue;
|
||||
}
|
||||
|
||||
const tempCredId = `import-cred-${targetUserId}-${Date.now()}-${imported}`;
|
||||
const newCredentialData = {
|
||||
const existing = await getDb()
|
||||
.select()
|
||||
.from(sshCredentials)
|
||||
.where(
|
||||
and(
|
||||
eq(sshCredentials.userId, targetUserId),
|
||||
eq(sshCredentials.name, credential.name as string),
|
||||
),
|
||||
);
|
||||
|
||||
if (existing.length > 0 && !options.replaceExisting) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const newCredentialData: any = {
|
||||
...credential,
|
||||
id: tempCredId,
|
||||
userId: targetUserId,
|
||||
usageCount: 0,
|
||||
lastUsed: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
let processedCredentialData = newCredentialData;
|
||||
if (existing.length === 0) {
|
||||
newCredentialData.usageCount = 0;
|
||||
newCredentialData.lastUsed = null;
|
||||
newCredentialData.createdAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
let processedCredentialData: any = newCredentialData;
|
||||
if (options.userDataKey) {
|
||||
processedCredentialData = DataCrypto.encryptRecord(
|
||||
"ssh_credentials",
|
||||
newCredentialData,
|
||||
targetUserId,
|
||||
options.userDataKey,
|
||||
);
|
||||
) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
delete processedCredentialData.id;
|
||||
|
||||
await getDb()
|
||||
.insert(sshCredentials)
|
||||
.values(
|
||||
processedCredentialData as unknown as typeof sshCredentials.$inferInsert,
|
||||
);
|
||||
if (existing.length > 0 && options.replaceExisting) {
|
||||
await getDb()
|
||||
.update(sshCredentials)
|
||||
.set(
|
||||
processedCredentialData as unknown as typeof sshCredentials.$inferInsert,
|
||||
)
|
||||
.where(eq(sshCredentials.id, existing[0].id));
|
||||
} else {
|
||||
await getDb()
|
||||
.insert(sshCredentials)
|
||||
.values(
|
||||
processedCredentialData as unknown as typeof sshCredentials.$inferInsert,
|
||||
);
|
||||
}
|
||||
imported++;
|
||||
} catch (error) {
|
||||
errors.push(
|
||||
|
||||
@@ -36,7 +36,7 @@ function TooltipTrigger({
|
||||
|
||||
function TooltipContent({
|
||||
className,
|
||||
sideOffset = 0,
|
||||
sideOffset = 4,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||||
@@ -46,7 +46,7 @@ function TooltipContent({
|
||||
data-slot="tooltip-content"
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||
"bg-elevated text-foreground border border-edge-medium shadow-lg animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -745,7 +745,7 @@ export const DEFAULT_TERMINAL_CONFIG = {
|
||||
fontSize: 14,
|
||||
fontFamily: "Caskaydia Cove Nerd Font Mono",
|
||||
letterSpacing: 0,
|
||||
lineHeight: 1.2,
|
||||
lineHeight: 1.0,
|
||||
theme: "termix",
|
||||
|
||||
scrollback: 10000,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
interface ConfirmationOptions {
|
||||
@@ -9,10 +9,47 @@ interface ConfirmationOptions {
|
||||
variant?: "default" | "destructive";
|
||||
}
|
||||
|
||||
interface ToastConfirmOptions {
|
||||
confirmOnEnter?: boolean;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
export function useConfirmation() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [options, setOptions] = useState<ConfirmationOptions | null>(null);
|
||||
const [onConfirm, setOnConfirm] = useState<(() => void) | null>(null);
|
||||
const [activeToastId, setActiveToastId] = useState<string | number | null>(null);
|
||||
const [pendingConfirmCallback, setPendingConfirmCallback] = useState<(() => void) | null>(null);
|
||||
const [pendingResolve, setPendingResolve] = useState<((value: boolean) => void) | null>(null);
|
||||
|
||||
const handleEnterKey = useCallback((event: KeyboardEvent) => {
|
||||
if (event.key === "Enter" && activeToastId !== null) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (pendingConfirmCallback) {
|
||||
pendingConfirmCallback();
|
||||
}
|
||||
if (pendingResolve) {
|
||||
pendingResolve(true);
|
||||
}
|
||||
|
||||
toast.dismiss(activeToastId);
|
||||
setActiveToastId(null);
|
||||
setPendingConfirmCallback(null);
|
||||
setPendingResolve(null);
|
||||
}
|
||||
}, [activeToastId, pendingConfirmCallback, pendingResolve]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeToastId !== null) {
|
||||
// Use capture phase to intercept Enter before terminal receives it
|
||||
window.addEventListener("keydown", handleEnterKey, true);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleEnterKey, true);
|
||||
};
|
||||
}
|
||||
}, [activeToastId, handleEnterKey]);
|
||||
|
||||
const confirm = (opts: ConfirmationOptions, callback: () => void) => {
|
||||
setOptions(opts);
|
||||
@@ -40,6 +77,7 @@ export function useConfirmation() {
|
||||
callback?: () => void,
|
||||
variantOrConfirmLabel: "default" | "destructive" | string = "Confirm",
|
||||
cancelLabel: string = "Cancel",
|
||||
toastOptions: ToastConfirmOptions = { confirmOnEnter: false },
|
||||
): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
const isVariant =
|
||||
@@ -47,43 +85,56 @@ export function useConfirmation() {
|
||||
variantOrConfirmLabel === "destructive";
|
||||
const confirmLabel = isVariant ? "Confirm" : variantOrConfirmLabel;
|
||||
|
||||
if (typeof opts === "string") {
|
||||
toast(opts, {
|
||||
action: {
|
||||
label: confirmLabel,
|
||||
onClick: () => {
|
||||
if (callback) callback();
|
||||
resolve(true);
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
label: cancelLabel,
|
||||
onClick: () => {
|
||||
resolve(false);
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
} else if (typeof opts === "object") {
|
||||
const actualConfirmLabel = opts.confirmText || confirmLabel;
|
||||
const actualCancelLabel = opts.cancelText || cancelLabel;
|
||||
const { confirmOnEnter = false, duration = 8000 } = toastOptions;
|
||||
|
||||
toast(opts.description, {
|
||||
action: {
|
||||
label: actualConfirmLabel,
|
||||
onClick: () => {
|
||||
if (callback) callback();
|
||||
resolve(true);
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
label: actualCancelLabel,
|
||||
onClick: () => {
|
||||
resolve(false);
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
} else {
|
||||
const handleToastConfirm = () => {
|
||||
if (callback) callback();
|
||||
resolve(true);
|
||||
setActiveToastId(null);
|
||||
setPendingConfirmCallback(null);
|
||||
setPendingResolve(null);
|
||||
};
|
||||
|
||||
const handleToastCancel = () => {
|
||||
resolve(false);
|
||||
setActiveToastId(null);
|
||||
setPendingConfirmCallback(null);
|
||||
setPendingResolve(null);
|
||||
};
|
||||
|
||||
const message = typeof opts === "string" ? opts : opts.description;
|
||||
const actualConfirmLabel = typeof opts === "object" && opts.confirmText ? opts.confirmText : confirmLabel;
|
||||
const actualCancelLabel = typeof opts === "object" && opts.cancelText ? opts.cancelText : cancelLabel;
|
||||
|
||||
const toastId = toast(message, {
|
||||
duration,
|
||||
action: {
|
||||
label: confirmOnEnter ? `${actualConfirmLabel} ↵` : actualConfirmLabel,
|
||||
onClick: handleToastConfirm,
|
||||
},
|
||||
cancel: {
|
||||
label: actualCancelLabel,
|
||||
onClick: handleToastCancel,
|
||||
},
|
||||
onDismiss: () => {
|
||||
setActiveToastId(null);
|
||||
setPendingConfirmCallback(null);
|
||||
setPendingResolve(null);
|
||||
},
|
||||
onAutoClose: () => {
|
||||
resolve(false);
|
||||
setActiveToastId(null);
|
||||
setPendingConfirmCallback(null);
|
||||
setPendingResolve(null);
|
||||
},
|
||||
} as any);
|
||||
|
||||
if (confirmOnEnter) {
|
||||
setActiveToastId(toastId);
|
||||
setPendingConfirmCallback(() => () => {
|
||||
if (callback) callback();
|
||||
});
|
||||
setPendingResolve(() => resolve);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
71
src/hooks/use-service-worker.ts
Normal file
71
src/hooks/use-service-worker.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { isElectron } from "@/ui/main-axios";
|
||||
|
||||
interface ServiceWorkerState {
|
||||
isSupported: boolean;
|
||||
isRegistered: boolean;
|
||||
updateAvailable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to manage PWA Service Worker registration.
|
||||
* Only registers in production web environment (not in Electron).
|
||||
*/
|
||||
export function useServiceWorker(): ServiceWorkerState {
|
||||
const [state, setState] = useState<ServiceWorkerState>({
|
||||
isSupported: false,
|
||||
isRegistered: false,
|
||||
updateAvailable: false,
|
||||
});
|
||||
|
||||
const handleUpdateFound = useCallback(
|
||||
(registration: ServiceWorkerRegistration) => {
|
||||
const newWorker = registration.installing;
|
||||
if (!newWorker) return;
|
||||
|
||||
newWorker.addEventListener("statechange", () => {
|
||||
if (
|
||||
newWorker.state === "installed" &&
|
||||
navigator.serviceWorker.controller
|
||||
) {
|
||||
setState((prev) => ({ ...prev, updateAvailable: true }));
|
||||
console.log("[SW] Update available");
|
||||
}
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const isSupported =
|
||||
"serviceWorker" in navigator && !isElectron() && import.meta.env.PROD;
|
||||
|
||||
setState((prev) => ({ ...prev, isSupported }));
|
||||
|
||||
if (!isSupported) return;
|
||||
|
||||
const registerSW = async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register("/sw.js");
|
||||
console.log("[SW] Registered:", registration.scope);
|
||||
|
||||
setState((prev) => ({ ...prev, isRegistered: true }));
|
||||
|
||||
registration.addEventListener("updatefound", () =>
|
||||
handleUpdateFound(registration),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("[SW] Registration failed:", error);
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === "complete") {
|
||||
registerSW();
|
||||
} else {
|
||||
window.addEventListener("load", registerSW);
|
||||
return () => window.removeEventListener("load", registerSW);
|
||||
}
|
||||
}, [handleUpdateFound]);
|
||||
|
||||
return state;
|
||||
}
|
||||
249
src/i18n/i18n.ts
249
src/i18n/i18n.ts
@@ -3,31 +3,38 @@ import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
|
||||
import enTranslation from "../locales/en.json";
|
||||
import zhTranslation from "../locales/zh.json";
|
||||
import deTranslation from "../locales/de.json";
|
||||
import ptTranslation from "../locales/pt.json";
|
||||
import ruTranslation from "../locales/ru.json";
|
||||
import frTranslation from "../locales/fr.json";
|
||||
import koTranslation from "../locales/ko.json";
|
||||
import itTranslation from "../locales/it.json";
|
||||
import esTranslation from "../locales/es.json";
|
||||
import hiTranslation from "../locales/hi.json";
|
||||
import bnTranslation from "../locales/bn.json";
|
||||
import jaTranslation from "../locales/ja.json";
|
||||
import viTranslation from "../locales/vi.json";
|
||||
import trTranslation from "../locales/tr.json";
|
||||
import heTranslation from "../locales/he.json";
|
||||
import arTranslation from "../locales/ar.json";
|
||||
import plTranslation from "../locales/pl.json";
|
||||
import nlTranslation from "../locales/nl.json";
|
||||
import svTranslation from "../locales/sv.json";
|
||||
import idTranslation from "../locales/id.json";
|
||||
import thTranslation from "../locales/th.json";
|
||||
import ukTranslation from "../locales/uk.json";
|
||||
import csTranslation from "../locales/cs.json";
|
||||
import roTranslation from "../locales/ro.json";
|
||||
import elTranslation from "../locales/el.json";
|
||||
import nbTranslation from "../locales/nb.json";
|
||||
import afTranslation from "../locales/translated/af.json";
|
||||
import arTranslation from "../locales/translated/ar.json";
|
||||
import bnTranslation from "../locales/translated/bn.json";
|
||||
import bgTranslation from "../locales/translated/bg.json";
|
||||
import caTranslation from "../locales/translated/ca.json";
|
||||
import csTranslation from "../locales/translated/cs.json";
|
||||
import daTranslation from "../locales/translated/da.json";
|
||||
import deTranslation from "../locales/translated/de.json";
|
||||
import elTranslation from "../locales/translated/el.json";
|
||||
import esTranslation from "../locales/translated/es.json";
|
||||
import fiTranslation from "../locales/translated/fi.json";
|
||||
import frTranslation from "../locales/translated/fr.json";
|
||||
import heTranslation from "../locales/translated/he.json";
|
||||
import hiTranslation from "../locales/translated/hi.json";
|
||||
import huTranslation from "../locales/translated/hu.json";
|
||||
import idTranslation from "../locales/translated/id.json";
|
||||
import itTranslation from "../locales/translated/it.json";
|
||||
import jaTranslation from "../locales/translated/ja.json";
|
||||
import koTranslation from "../locales/translated/ko.json";
|
||||
import nlTranslation from "../locales/translated/nl.json";
|
||||
import noTranslation from "../locales/translated/no.json";
|
||||
import plTranslation from "../locales/translated/pl.json";
|
||||
import ptTranslation from "../locales/translated/pt.json";
|
||||
import roTranslation from "../locales/translated/ro.json";
|
||||
import ruTranslation from "../locales/translated/ru.json";
|
||||
import srTranslation from "../locales/translated/sr.json";
|
||||
import svTranslation from "../locales/translated/sv.json";
|
||||
import thTranslation from "../locales/translated/th.json";
|
||||
import trTranslation from "../locales/translated/tr.json";
|
||||
import ukTranslation from "../locales/translated/uk.json";
|
||||
import viTranslation from "../locales/translated/vi.json";
|
||||
import zhTranslation from "../locales/translated/zh.json";
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
@@ -35,31 +42,38 @@ i18n
|
||||
.init({
|
||||
supportedLngs: [
|
||||
"en",
|
||||
"zh",
|
||||
"de",
|
||||
"pt",
|
||||
"ru",
|
||||
"fr",
|
||||
"ko",
|
||||
"it",
|
||||
"es",
|
||||
"hi",
|
||||
"bn",
|
||||
"ja",
|
||||
"vi",
|
||||
"tr",
|
||||
"he",
|
||||
"af",
|
||||
"ar",
|
||||
"pl",
|
||||
"nl",
|
||||
"sv",
|
||||
"id",
|
||||
"th",
|
||||
"uk",
|
||||
"bn",
|
||||
"bg",
|
||||
"ca",
|
||||
"cs",
|
||||
"ro",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"nb",
|
||||
"es",
|
||||
"fi",
|
||||
"fr",
|
||||
"he",
|
||||
"hi",
|
||||
"hu",
|
||||
"id",
|
||||
"it",
|
||||
"ja",
|
||||
"ko",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt",
|
||||
"ro",
|
||||
"ru",
|
||||
"sr",
|
||||
"sv",
|
||||
"th",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
"zh",
|
||||
],
|
||||
fallbackLng: "en",
|
||||
debug: false,
|
||||
@@ -76,80 +90,101 @@ i18n
|
||||
en: {
|
||||
translation: enTranslation,
|
||||
},
|
||||
zh: {
|
||||
translation: zhTranslation,
|
||||
},
|
||||
de: {
|
||||
translation: deTranslation,
|
||||
},
|
||||
pt: {
|
||||
translation: ptTranslation,
|
||||
},
|
||||
ru: {
|
||||
translation: ruTranslation,
|
||||
},
|
||||
fr: {
|
||||
translation: frTranslation,
|
||||
},
|
||||
ko: {
|
||||
translation: koTranslation,
|
||||
},
|
||||
it: {
|
||||
translation: itTranslation,
|
||||
},
|
||||
es: {
|
||||
translation: esTranslation,
|
||||
},
|
||||
hi: {
|
||||
translation: hiTranslation,
|
||||
},
|
||||
bn: {
|
||||
translation: bnTranslation,
|
||||
},
|
||||
ja: {
|
||||
translation: jaTranslation,
|
||||
},
|
||||
vi: {
|
||||
translation: viTranslation,
|
||||
},
|
||||
tr: {
|
||||
translation: trTranslation,
|
||||
},
|
||||
he: {
|
||||
translation: heTranslation,
|
||||
af: {
|
||||
translation: afTranslation,
|
||||
},
|
||||
ar: {
|
||||
translation: arTranslation,
|
||||
},
|
||||
pl: {
|
||||
translation: plTranslation,
|
||||
bn: {
|
||||
translation: bnTranslation,
|
||||
},
|
||||
nl: {
|
||||
translation: nlTranslation,
|
||||
bg: {
|
||||
translation: bgTranslation,
|
||||
},
|
||||
sv: {
|
||||
translation: svTranslation,
|
||||
},
|
||||
id: {
|
||||
translation: idTranslation,
|
||||
},
|
||||
th: {
|
||||
translation: thTranslation,
|
||||
},
|
||||
uk: {
|
||||
translation: ukTranslation,
|
||||
ca: {
|
||||
translation: caTranslation,
|
||||
},
|
||||
cs: {
|
||||
translation: csTranslation,
|
||||
},
|
||||
ro: {
|
||||
translation: roTranslation,
|
||||
da: {
|
||||
translation: daTranslation,
|
||||
},
|
||||
de: {
|
||||
translation: deTranslation,
|
||||
},
|
||||
el: {
|
||||
translation: elTranslation,
|
||||
},
|
||||
nb: {
|
||||
translation: nbTranslation,
|
||||
es: {
|
||||
translation: esTranslation,
|
||||
},
|
||||
fi: {
|
||||
translation: fiTranslation,
|
||||
},
|
||||
fr: {
|
||||
translation: frTranslation,
|
||||
},
|
||||
he: {
|
||||
translation: heTranslation,
|
||||
},
|
||||
hi: {
|
||||
translation: hiTranslation,
|
||||
},
|
||||
hu: {
|
||||
translation: huTranslation,
|
||||
},
|
||||
id: {
|
||||
translation: idTranslation,
|
||||
},
|
||||
it: {
|
||||
translation: itTranslation,
|
||||
},
|
||||
ja: {
|
||||
translation: jaTranslation,
|
||||
},
|
||||
ko: {
|
||||
translation: koTranslation,
|
||||
},
|
||||
nl: {
|
||||
translation: nlTranslation,
|
||||
},
|
||||
no: {
|
||||
translation: noTranslation,
|
||||
},
|
||||
pl: {
|
||||
translation: plTranslation,
|
||||
},
|
||||
pt: {
|
||||
translation: ptTranslation,
|
||||
},
|
||||
ro: {
|
||||
translation: roTranslation,
|
||||
},
|
||||
ru: {
|
||||
translation: ruTranslation,
|
||||
},
|
||||
sr: {
|
||||
translation: srTranslation,
|
||||
},
|
||||
sv: {
|
||||
translation: svTranslation,
|
||||
},
|
||||
th: {
|
||||
translation: thTranslation,
|
||||
},
|
||||
tr: {
|
||||
translation: trTranslation,
|
||||
},
|
||||
uk: {
|
||||
translation: ukTranslation,
|
||||
},
|
||||
vi: {
|
||||
translation: viTranslation,
|
||||
},
|
||||
zh: {
|
||||
translation: zhTranslation,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
104
src/lib/db-health-monitor.ts
Normal file
104
src/lib/db-health-monitor.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
type EventListener = (...args: any[]) => void;
|
||||
|
||||
class DatabaseHealthMonitor {
|
||||
private static instance: DatabaseHealthMonitor;
|
||||
private dbHealthy: boolean = true;
|
||||
private lastCheckTime: number = 0;
|
||||
private checkInProgress: boolean = false;
|
||||
private listeners: Map<string, EventListener[]> = new Map();
|
||||
|
||||
private constructor() {}
|
||||
|
||||
static getInstance(): DatabaseHealthMonitor {
|
||||
if (!DatabaseHealthMonitor.instance) {
|
||||
DatabaseHealthMonitor.instance = new DatabaseHealthMonitor();
|
||||
}
|
||||
return DatabaseHealthMonitor.instance;
|
||||
}
|
||||
|
||||
on(event: string, listener: EventListener): void {
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
this.listeners.get(event)!.push(listener);
|
||||
}
|
||||
|
||||
off(event: string, listener: EventListener): void {
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
const index = eventListeners.indexOf(listener);
|
||||
if (index !== -1) {
|
||||
eventListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private emit(event: string, ...args: any[]): void {
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
eventListeners.forEach((listener) => listener(...args));
|
||||
}
|
||||
}
|
||||
|
||||
reportDatabaseError(error: any, wasAuthenticated: boolean = false) {
|
||||
const errorMessage = error?.response?.data?.error || error?.message || "";
|
||||
const errorCode = error?.response?.data?.code || error?.code;
|
||||
const httpStatus = error?.response?.status;
|
||||
|
||||
const isDatabaseError =
|
||||
errorMessage.toLowerCase().includes("database") ||
|
||||
errorMessage.toLowerCase().includes("sqlite") ||
|
||||
errorMessage.toLowerCase().includes("drizzle") ||
|
||||
errorCode === "DATABASE_ERROR" ||
|
||||
errorCode === "DB_CONNECTION_FAILED";
|
||||
|
||||
const isBackendUnreachable =
|
||||
errorCode === "ERR_NETWORK" ||
|
||||
errorCode === "ECONNREFUSED" ||
|
||||
(errorMessage.toLowerCase().includes("network error") &&
|
||||
error?.response === undefined);
|
||||
|
||||
const isAuthenticationLost =
|
||||
wasAuthenticated &&
|
||||
httpStatus === 401 &&
|
||||
(errorCode === "AUTH_REQUIRED" ||
|
||||
errorCode === "SESSION_EXPIRED" ||
|
||||
errorCode === "SESSION_NOT_FOUND" ||
|
||||
errorMessage === "Missing authentication token" ||
|
||||
errorMessage === "Invalid token" ||
|
||||
errorMessage === "Authentication required");
|
||||
|
||||
if (
|
||||
(isDatabaseError || isBackendUnreachable || isAuthenticationLost) &&
|
||||
this.dbHealthy
|
||||
) {
|
||||
this.dbHealthy = false;
|
||||
this.emit("database-connection-lost", {
|
||||
error: errorMessage || "Backend server unreachable",
|
||||
code: errorCode,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reportDatabaseSuccess() {
|
||||
if (!this.dbHealthy) {
|
||||
this.dbHealthy = true;
|
||||
this.emit("database-connection-restored", {
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isDatabaseHealthy(): boolean {
|
||||
return this.dbHealthy;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.dbHealthy = true;
|
||||
this.lastCheckTime = 0;
|
||||
this.checkInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
export const dbHealthMonitor = DatabaseHealthMonitor.getInstance();
|
||||
2402
src/locales/ar.json
2402
src/locales/ar.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/cs.json
2402
src/locales/cs.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/de.json
2402
src/locales/de.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/el.json
2402
src/locales/el.json
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,8 @@
|
||||
"passwordRequired": "Password is required",
|
||||
"sshKeyRequired": "SSH key is required",
|
||||
"credentialAddedSuccessfully": "Credential \"{{name}}\" added successfully",
|
||||
"savingCredential": "Saving credential...",
|
||||
"updatingCredential": "Updating credential...",
|
||||
"general": "General",
|
||||
"description": "Description",
|
||||
"folder": "Folder",
|
||||
@@ -184,6 +186,32 @@
|
||||
"renameFolder": "Rename folder",
|
||||
"idLabel": "ID:"
|
||||
},
|
||||
"quickConnect": {
|
||||
"title": "Quick Connect",
|
||||
"description": "Connect directly to a terminal or file manager session without saving a host configuration",
|
||||
"ipAddress": "IP Address or Hostname",
|
||||
"port": "Port",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"key": "SSH Private Key",
|
||||
"keyPassword": "Key Password (Optional)",
|
||||
"keyType": "Key Type",
|
||||
"uploadFile": "Upload File",
|
||||
"pasteKey": "Paste Key",
|
||||
"credential": "Credential",
|
||||
"overrideUsername": "Override Credential Username",
|
||||
"overrideUsernameDesc": "Use a different username than the one stored in the credential",
|
||||
"connectTerminal": "Connect to Terminal",
|
||||
"connectFileManager": "Connect to File Manager",
|
||||
"cancel": "Cancel",
|
||||
"passwordRequired": "Password is required",
|
||||
"keyRequired": "SSH key is required",
|
||||
"credentialRequired": "Credential selection is required",
|
||||
"connectionEstablished": "Connection established successfully",
|
||||
"connectionFailed": "Failed to establish connection",
|
||||
"autoDetect": "Auto Detect",
|
||||
"authentication": "Authentication"
|
||||
},
|
||||
"dragIndicator": {
|
||||
"error": "Error: {{error}}",
|
||||
"dragging": "Dragging {{fileName}}",
|
||||
@@ -464,6 +492,7 @@
|
||||
"retry": "Retry",
|
||||
"checking": "Checking...",
|
||||
"checkingDatabase": "Checking database connection...",
|
||||
"checkingAuthentication": "Checking authentication...",
|
||||
"actions": "Actions",
|
||||
"remove": "Remove",
|
||||
"revoke": "Revoke",
|
||||
@@ -489,7 +518,12 @@
|
||||
"hostManager": "Host Manager",
|
||||
"cannotSplitTab": "Cannot split this tab",
|
||||
"tabNavigation": "Tab Navigation",
|
||||
"hostTabTitle": "{{username}}@{{ip}}:{{port}}"
|
||||
"hostTabTitle": "{{username}}@{{ip}}:{{port}}",
|
||||
"copyPassword": "Copy Password",
|
||||
"copySudoPassword": "Copy Sudo Password",
|
||||
"passwordCopied": "Password copied to clipboard",
|
||||
"sudoPasswordCopied": "Sudo password copied to clipboard",
|
||||
"noPasswordAvailable": "No password available"
|
||||
},
|
||||
"admin": {
|
||||
"title": "Admin Settings",
|
||||
@@ -537,6 +571,7 @@
|
||||
"userRegistration": "User Registration",
|
||||
"allowNewAccountRegistration": "Allow new account registration",
|
||||
"allowPasswordLogin": "Allow username/password login",
|
||||
"allowPasswordReset": "Allow password reset via reset code",
|
||||
"missingRequiredFields": "Missing required fields: {{fields}}",
|
||||
"oidcConfigurationUpdated": "OIDC configuration updated successfully!",
|
||||
"failedToFetchOidcConfig": "Failed to fetch OIDC configuration",
|
||||
@@ -856,6 +891,13 @@
|
||||
"autoStartContainer": "Auto Start on Container Launch",
|
||||
"autoStartDesc": "Automatically start this tunnel when the container launches",
|
||||
"addConnection": "Add Tunnel Connection",
|
||||
"tunnelType": "Tunnel Type",
|
||||
"tunnelTypeLocal": "Local (-L)",
|
||||
"tunnelTypeRemote": "Remote (-R)",
|
||||
"tunnelTypeLocalDesc": "Forward local port to remote endpoint",
|
||||
"tunnelTypeRemoteDesc": "Forward remote port to local machine",
|
||||
"tunnelForwardDescriptionLocal": "This tunnel will forward traffic from local port {{sourcePort}} to port {{endpointPort}} on the endpoint machine.",
|
||||
"tunnelForwardDescriptionRemote": "This tunnel will forward traffic from port {{sourcePort}} on the source machine (current connection details in general tab) to port {{endpointPort}} on the endpoint machine.",
|
||||
"sshpassRequired": "Sshpass Required For Password Authentication",
|
||||
"sshpassRequiredDesc": "For password authentication in tunnels, sshpass must be installed on the system.",
|
||||
"otherInstallMethods": "Other installation methods:",
|
||||
@@ -1106,6 +1148,19 @@
|
||||
"quickActionName": "Action name",
|
||||
"noSnippetFound": "No snippet found",
|
||||
"quickActionsOrder": "Quick action buttons will appear in the order listed above on the Server Stats page",
|
||||
"sidebarCustomization": "Sidebar Button Customization",
|
||||
"sidebarCustomizationDesc": "Choose which actions appear as quick buttons in the sidebar. Actions not shown as buttons will appear in the dropdown menu.",
|
||||
"showTerminalInSidebar": "Show Terminal Button",
|
||||
"showTerminalInSidebarDesc": "Display terminal as a quick button in the sidebar",
|
||||
"showFileManagerInSidebar": "Show File Manager Button",
|
||||
"showFileManagerInSidebarDesc": "Display file manager as a quick button in the sidebar",
|
||||
"showTunnelInSidebar": "Show Tunnel Button",
|
||||
"showTunnelInSidebarDesc": "Display tunnel management as a quick button in the sidebar",
|
||||
"showDockerInSidebar": "Show Docker Button",
|
||||
"showDockerInSidebarDesc": "Display docker management as a quick button in the sidebar",
|
||||
"showServerStatsInSidebar": "Show Server Stats Button",
|
||||
"showServerStatsInSidebarDesc": "Display server statistics as a quick button in the sidebar",
|
||||
"atLeastOneActionRequired": "At least one enabled action must be shown in the sidebar",
|
||||
"advancedAuthSettings": "Advanced Authentication Settings",
|
||||
"sudoPasswordAutoFill": "Sudo Password Auto-Fill",
|
||||
"sudoPasswordAutoFillDesc": "Automatically offer to insert SSH password when sudo prompts for password",
|
||||
@@ -1360,6 +1415,12 @@
|
||||
"itemDeletedSuccessfully": "{{type}} deleted successfully",
|
||||
"itemsDeletedSuccessfully": "{{count}} items deleted successfully",
|
||||
"failedToDeleteItems": "Failed to delete items",
|
||||
"sudoPasswordRequired": "Administrator Password Required",
|
||||
"enterSudoPassword": "Enter sudo password to continue this operation",
|
||||
"sudoPassword": "Sudo password",
|
||||
"sudoOperationFailed": "Sudo operation failed",
|
||||
"sudoAuthFailed": "Sudo authentication failed",
|
||||
"deleteOperation": "Delete files/folders",
|
||||
"dragFilesToUpload": "Drop files here to upload",
|
||||
"emptyFolder": "This folder is empty",
|
||||
"itemCount": "{{count}} items",
|
||||
@@ -1731,7 +1792,34 @@
|
||||
"executingQuickAction": "Executing {{name}}...",
|
||||
"quickActionSuccess": "{{name}} completed successfully",
|
||||
"quickActionFailed": "{{name}} failed",
|
||||
"quickActionError": "Failed to execute {{name}}"
|
||||
"quickActionError": "Failed to execute {{name}}",
|
||||
"ports": {
|
||||
"title": "Listening Ports",
|
||||
"protocol": "Protocol",
|
||||
"port": "Port",
|
||||
"address": "Address",
|
||||
"state": "State",
|
||||
"process": "Process",
|
||||
"noData": "No listening ports data"
|
||||
},
|
||||
"firewall": {
|
||||
"title": "Firewall",
|
||||
"active": "Active",
|
||||
"inactive": "Inactive",
|
||||
"notDetected": "Not Detected",
|
||||
"policy": "Policy",
|
||||
"rules": "rules",
|
||||
"noRules": "No rules",
|
||||
"noData": "No firewall data available",
|
||||
"action": "Action",
|
||||
"protocol": "Proto",
|
||||
"port": "Port",
|
||||
"source": "Source",
|
||||
"accept": "ACCEPT",
|
||||
"drop": "DROP",
|
||||
"reject": "REJECT",
|
||||
"anywhere": "Anywhere"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "SSH SERVER MANAGER",
|
||||
@@ -1841,7 +1929,8 @@
|
||||
"authenticationDisabled": "Authentication Disabled",
|
||||
"authenticationDisabledDesc": "All authentication methods are currently disabled. Please contact your administrator.",
|
||||
"passwordResetSuccess": "Password Reset Successful",
|
||||
"passwordResetSuccessDesc": "Your password has been reset successfully. You can now log in with your new password."
|
||||
"passwordResetSuccessDesc": "Your password has been reset successfully. You can now log in with your new password.",
|
||||
"attemptsRemaining": "attempts remaining"
|
||||
},
|
||||
"errors": {
|
||||
"notFound": "Page not found",
|
||||
@@ -1873,7 +1962,11 @@
|
||||
"emailExists": "Email already exists",
|
||||
"loadFailed": "Failed to load data",
|
||||
"saveError": "Failed to save",
|
||||
"sessionExpired": "Session expired - please log in again"
|
||||
"sessionExpired": "Session expired - please log in again",
|
||||
"totpRateLimited": "Rate limited: Too many TOTP verification attempts. Please try again later.",
|
||||
"totpRateLimitedWithTime": "Rate limited: Too many TOTP verification attempts. Please wait {{time}} seconds before trying again.",
|
||||
"resetCodeRateLimited": "Rate limited: Too many verification attempts. Please try again later.",
|
||||
"resetCodeRateLimitedWithTime": "Rate limited: Too many verification attempts. Please wait {{time}} seconds before trying again."
|
||||
},
|
||||
"messages": {
|
||||
"saveSuccess": "Saved successfully",
|
||||
@@ -1931,6 +2024,9 @@
|
||||
"terminalSettings": "Terminal",
|
||||
"hostSidebarSettings": "Host & Sidebar",
|
||||
"snippetsSettings": "Snippets",
|
||||
"updateSettings": "Updates",
|
||||
"disableUpdateCheck": "Disable Update Check",
|
||||
"disableUpdateCheckDesc": "Stop checking for new versions on startup and dashboard. Reduces network requests.",
|
||||
"currentPassword": "Current Password",
|
||||
"passwordChangedSuccess": "Password changed successfully! Please log in again.",
|
||||
"failedToChangePassword": "Failed to change password. Please check your current password and try again.",
|
||||
@@ -1939,7 +2035,9 @@
|
||||
"themeDark": "Dark",
|
||||
"themeSystem": "System",
|
||||
"appearanceDesc": "Select the color theme for the application",
|
||||
"terminalSyntaxHighlightingDesc": "Automatically highlight commands, paths, IPs, and log levels in terminal output"
|
||||
"terminalSyntaxHighlightingDesc": "Automatically highlight commands, paths, IPs, and log levels in terminal output",
|
||||
"enableCommandPaletteShortcut": "Enable Command Palette Shortcut",
|
||||
"enableCommandPaletteShortcutDesc": "Double-tap left Shift to open the Command Palette for quick access to hosts"
|
||||
},
|
||||
"user": {
|
||||
"failedToLoadVersionInfo": "Failed to load version information"
|
||||
@@ -2163,7 +2261,20 @@
|
||||
"noServerData": "No server data available",
|
||||
"cpu": "CPU",
|
||||
"ram": "RAM",
|
||||
"notAvailable": "N/A"
|
||||
"notAvailable": "N/A",
|
||||
"customizeLayout": "Customize Dashboard",
|
||||
"dashboardSettings": "Dashboard Settings",
|
||||
"enableDisableCards": "Enable/Disable Cards",
|
||||
"gridColumns": "Grid Columns",
|
||||
"column": "Column",
|
||||
"columns": "Columns",
|
||||
"resetLayout": "Reset to Default",
|
||||
"serverOverviewCard": "Server Overview",
|
||||
"recentActivityCard": "Recent Activity",
|
||||
"networkGraphCard": "Network Graph",
|
||||
"quickActionsCard": "Quick Actions",
|
||||
"serverStatsCard": "Server Stats",
|
||||
"networkGraph": "Network Graph"
|
||||
},
|
||||
"rbac": {
|
||||
"shareHost": "Share Host",
|
||||
|
||||
2402
src/locales/es.json
2402
src/locales/es.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/fr.json
2402
src/locales/fr.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/it.json
2402
src/locales/it.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/ja.json
2402
src/locales/ja.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/nb.json
2402
src/locales/nb.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/nl.json
2402
src/locales/nl.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/pl.json
2402
src/locales/pl.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/pt.json
2402
src/locales/pt.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/ro.json
2402
src/locales/ro.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/ru.json
2402
src/locales/ru.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/sv.json
2402
src/locales/sv.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/af.json
Normal file
2402
src/locales/translated/af.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/ar.json
Normal file
2402
src/locales/translated/ar.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/bg.json
Normal file
2402
src/locales/translated/bg.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@
|
||||
"failedToFetchCredentials": "শংসাপত্রগুলি আনতে ব্যর্থ হয়েছে",
|
||||
"credentialDeletedSuccessfully": "শংসাপত্র সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"failedToDeleteCredential": "শংসাপত্র মুছে ফেলা যায়নি",
|
||||
"confirmDeleteCredential": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" শংসাপত্র মুছে ফেলতে চান?",
|
||||
"confirmDeleteCredential": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" শংসাপত্রটি মুছে ফেলতে চান?",
|
||||
"credentialCreatedSuccessfully": "শংসাপত্র সফলভাবে তৈরি করা হয়েছে",
|
||||
"credentialUpdatedSuccessfully": "শংসাপত্র সফলভাবে আপডেট করা হয়েছে",
|
||||
"failedToSaveCredential": "শংসাপত্র সংরক্ষণ করা যায়নি",
|
||||
@@ -43,7 +43,7 @@
|
||||
"refresh": "রিফ্রেশ করুন",
|
||||
"passwordRequired": "পাসওয়ার্ড প্রয়োজন।",
|
||||
"sshKeyRequired": "SSH কী প্রয়োজন",
|
||||
"credentialAddedSuccessfully": "\"{{name}}\" প্রমাণপত্র সফলভাবে যোগ করা হয়েছে",
|
||||
"credentialAddedSuccessfully": "\"{{name}}\" শংসাপত্র সফলভাবে যোগ করা হয়েছে",
|
||||
"general": "সাধারণ",
|
||||
"description": "বিবরণ",
|
||||
"folder": "ফোল্ডার",
|
||||
@@ -96,7 +96,7 @@
|
||||
"deploymentProcess": "স্থাপনার প্রক্রিয়া",
|
||||
"deploymentProcessDescription": "এটি বিদ্যমান কীগুলিকে ওভাররাইট না করেই টার্গেট হোস্টের ~/.ssh/authorized_keys ফাইলে নিরাপদে পাবলিক কী যুক্ত করবে। এই অপারেশনটি বিপরীতমুখী।",
|
||||
"chooseHostToDeploy": "স্থাপনের জন্য একটি হোস্ট বেছে নিন...",
|
||||
"deploying": "মোতায়েন করা হচ্ছে...",
|
||||
"deploying": "স্থাপন করা হচ্ছে...",
|
||||
"name": "নাম",
|
||||
"noHostsAvailable": "কোনও হোস্ট উপলব্ধ নেই",
|
||||
"noHostsMatchSearch": "আপনার অনুসন্ধানের সাথে কোনও হোস্ট মেলেনি।",
|
||||
@@ -119,7 +119,7 @@
|
||||
"passwordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
||||
"keyAuthentication": "কী প্রমাণীকরণ",
|
||||
"securityReminder": "নিরাপত্তা অনুস্মারক",
|
||||
"securityReminderText": "আপনার শংসাপত্রগুলি কখনও শেয়ার করবেন না। সমস্ত ডেটা বিশ্রামে এনক্রিপ্ট করা থাকে।",
|
||||
"securityReminderText": "আপনার পরিচয়পত্র কখনও শেয়ার করবেন না। সমস্ত ডেটা স্থিরভাবে এনক্রিপ্ট করা থাকে।",
|
||||
"hostsUsingCredential": "এই শংসাপত্র ব্যবহার করে হোস্টরা",
|
||||
"noHostsUsingCredential": "বর্তমানে কোনও হোস্ট এই শংসাপত্র ব্যবহার করছে না।",
|
||||
"timesUsed": "ব্যবহৃত সময়",
|
||||
@@ -136,12 +136,12 @@
|
||||
"listView": "তালিকা",
|
||||
"folderView": "ফোল্ডার",
|
||||
"unknownCredential": "অজানা",
|
||||
"confirmRemoveFromFolder": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" ফোল্ডার থেকে \"{{folder}}\" মুছে ফেলতে চান? শংসাপত্রটি \"অশ্রেণীবদ্ধ\" এ সরানো হবে।",
|
||||
"removedFromFolder": "ফোল্ডার থেকে \"{{name}}\" শংসাপত্র সফলভাবে সরানো হয়েছে",
|
||||
"confirmRemoveFromFolder": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" ফোল্ডার থেকে \"{{folder}}\" সরাতে চান? শংসাপত্রটি \"অশ্রেণীবদ্ধ\" এ সরানো হবে।",
|
||||
"removedFromFolder": "\"{{name}}\" শংসাপত্রটি ফোল্ডার থেকে সফলভাবে সরানো হয়েছে",
|
||||
"failedToRemoveFromFolder": "ফোল্ডার থেকে শংসাপত্র সরানো যায়নি",
|
||||
"folderRenamed": "\"{{oldName}}\" ফোল্ডারটির নাম পরিবর্তন করে \"{{newName}}\" করা হয়েছে।",
|
||||
"folderRenamed": "\"{{oldName}}\" ফোল্ডারের নাম পরিবর্তন করে \"{{newName}}\" করা হয়েছে",
|
||||
"failedToRenameFolder": "ফোল্ডারের নাম পরিবর্তন করা যায়নি",
|
||||
"movedToFolder": "\"{{name}}\" প্রমাণপত্র সফলভাবে \"{{folder}}}\" এ সরানো হয়েছে",
|
||||
"movedToFolder": "\"{{name}}\" শংসাপত্র সফলভাবে \"{{folder}}\" এ সরানো হয়েছে",
|
||||
"failedToMoveToFolder": "শংসাপত্র ফোল্ডারে সরানো যায়নি",
|
||||
"sshPublicKey": "SSH পাবলিক কী",
|
||||
"publicKeyNote": "পাবলিক কী ঐচ্ছিক কিন্তু কী যাচাইকরণের জন্য সুপারিশ করা হয়",
|
||||
@@ -166,7 +166,7 @@
|
||||
"keyTypeDsa": "ডিএসএ (এসএসএইচ)",
|
||||
"keyTypeRsaSha256": "আরএসএ-এসএইচএ২-২৫৬",
|
||||
"keyTypeRsaSha512": "আরএসএ-এসএইচএ২-৫১২",
|
||||
"keyPairGeneratedSuccessfully": "{{keyType}} কী জোড়া সফলভাবে তৈরি হয়েছে",
|
||||
"keyPairGeneratedSuccessfully": "{{keyType}} কী জোড়া সফলভাবে তৈরি করা হয়েছে",
|
||||
"failedToGenerateKeyPair": "কী জোড়া তৈরি করতে ব্যর্থ হয়েছে",
|
||||
"generateKeyPairNote": "সরাসরি একটি নতুন SSH কী জোড়া তৈরি করুন। এটি ফর্মে বিদ্যমান যেকোনো কী প্রতিস্থাপন করবে।",
|
||||
"invalidKey": "অবৈধ কী",
|
||||
@@ -187,10 +187,10 @@
|
||||
"dragIndicator": {
|
||||
"error": "ত্রুটি: {{error}}",
|
||||
"dragging": "টেনে আনা হচ্ছে {{fileName}}",
|
||||
"preparing": "প্রস্তুতি নিচ্ছে {{fileName}}",
|
||||
"preparing": "প্রস্তুতি {{fileName}}",
|
||||
"readySingle": "ডাউনলোড করার জন্য প্রস্তুত {{fileName}}",
|
||||
"readyMultiple": "{{count}} ফাইল ডাউনলোড করার জন্য প্রস্তুত",
|
||||
"batchDrag": "{{count}} ফাইলগুলি ডেস্কটপে টেনে আনুন",
|
||||
"batchDrag": "{{count}} ফাইলগুলিকে ডেস্কটপে টেনে আনুন",
|
||||
"dragToDesktop": "ডেস্কটপে টেনে আনুন",
|
||||
"canDragAnywhere": "আপনি আপনার ডেস্কটপের যেকোনো জায়গায় ফাইল টেনে আনতে পারেন"
|
||||
},
|
||||
@@ -202,7 +202,7 @@
|
||||
"stopKeyRecording": "কী রেকর্ডিং বন্ধ করুন",
|
||||
"selectTerminals": "টার্মিনাল নির্বাচন করুন:",
|
||||
"typeCommands": "কমান্ড টাইপ করুন (সকল কী সমর্থিত):",
|
||||
"commandsWillBeSent": "কমান্ডগুলি {{count}} নির্বাচিত টার্মিনালে পাঠানো হবে।",
|
||||
"commandsWillBeSent": "কমান্ডগুলি নির্বাচিত টার্মিনালে {{count}} পাঠানো হবে।",
|
||||
"settings": "সেটিংস",
|
||||
"enableRightClickCopyPaste": "রাইট-ক্লিক কপি/পেস্ট সক্ষম করুন",
|
||||
"shareIdeas": "ssh টুলের জন্য পরবর্তীতে কী করা উচিত সে সম্পর্কে আপনার কি কোন ধারণা আছে? সেগুলি শেয়ার করুন",
|
||||
@@ -230,7 +230,7 @@
|
||||
"createDescription": "দ্রুত কার্যকর করার জন্য একটি নতুন কমান্ড স্নিপেট তৈরি করুন",
|
||||
"editDescription": "এই কমান্ড স্নিপেটটি সম্পাদনা করুন",
|
||||
"deleteConfirmTitle": "স্নিপেট মুছুন",
|
||||
"deleteConfirmDescription": "তুমি কি নিশ্চিত যে তুমি \"{{name}}\" মুছে ফেলতে চাও?",
|
||||
"deleteConfirmDescription": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" মুছে ফেলতে চান?",
|
||||
"createSuccess": "স্নিপেট সফলভাবে তৈরি করা হয়েছে",
|
||||
"updateSuccess": "স্নিপেট সফলভাবে আপডেট করা হয়েছে",
|
||||
"deleteSuccess": "স্নিপেট সফলভাবে মুছে ফেলা হয়েছে",
|
||||
@@ -239,7 +239,7 @@
|
||||
"deleteFailed": "স্নিপেট মুছে ফেলা যায়নি",
|
||||
"failedToFetch": "স্নিপেটগুলি আনা যায়নি",
|
||||
"executeSuccess": "কার্যকর করা হচ্ছে: {{name}}",
|
||||
"copySuccess": "ক্লিপবোর্ডে \"{{name}}\" কপি করা হয়েছে",
|
||||
"copySuccess": "\"{{name}}\" ক্লিপবোর্ডে কপি করা হয়েছে",
|
||||
"runTooltip": "টার্মিনালে এই স্নিপেটটি কার্যকর করুন।",
|
||||
"copyTooltip": "ক্লিপবোর্ডে স্নিপেট কপি করুন",
|
||||
"editTooltip": "এই স্নিপেটটি সম্পাদনা করুন",
|
||||
@@ -248,7 +248,7 @@
|
||||
"reorderSameFolder": "শুধুমাত্র একই ফোল্ডারের মধ্যে স্নিপেটগুলি পুনরায় সাজাতে পারে",
|
||||
"reorderSuccess": "স্নিপেটগুলি সফলভাবে পুনঃক্রম করা হয়েছে",
|
||||
"reorderFailed": "স্নিপেটগুলি পুনঃক্রম করতে ব্যর্থ হয়েছে",
|
||||
"deleteFolderConfirm": "\"{{name}}\" ফোল্ডারটি মুছে ফেলবেন? সমস্ত স্নিপেট অশ্রেণীবদ্ধে সরানো হবে।",
|
||||
"deleteFolderConfirm": "\"{{name}}\" ফোল্ডারটি মুছবেন? সমস্ত স্নিপেট অশ্রেণীবদ্ধে সরানো হবে।",
|
||||
"deleteFolderSuccess": "ফোল্ডারটি সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"deleteFolderFailed": "ফোল্ডারটি মুছে ফেলা যায়নি",
|
||||
"updateFolderSuccess": "ফোল্ডারটি সফলভাবে আপডেট করা হয়েছে",
|
||||
@@ -256,7 +256,7 @@
|
||||
"updateFolderFailed": "ফোল্ডার আপডেট করতে ব্যর্থ হয়েছে",
|
||||
"createFolderFailed": "ফোল্ডার তৈরি করতে ব্যর্থ হয়েছে",
|
||||
"selectTerminals": "টার্মিনাল নির্বাচন করুন (ঐচ্ছিক)",
|
||||
"executeOnSelected": "নির্বাচিত {{count}} টার্মিনালে কার্যকর করুন",
|
||||
"executeOnSelected": "নির্বাচিত টার্মিনাল(গুলি) তে {{count}} কার্যকর করুন",
|
||||
"executeOnCurrent": "বর্তমান টার্মিনালে এক্সিকিউট করুন (একাধিক নির্বাচন করতে ক্লিক করুন)",
|
||||
"folder": "ফোল্ডার",
|
||||
"selectFolder": "একটি ফোল্ডার নির্বাচন করুন অথবা খালি রাখুন",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "স্প্লিট স্ক্রিন সাফ করা হয়েছে",
|
||||
"error": {
|
||||
"noAssignments": "লেআউটে কমপক্ষে একটি ট্যাব বরাদ্দ করুন।",
|
||||
"fillAllSlots": "আবেদন করার আগে অনুগ্রহ করে সমস্ত {{count}} স্থান পূরণ করুন।"
|
||||
"fillAllSlots": "আবেদন করার আগে দয়া করে সমস্ত {{count}} স্লট পূরণ করুন।"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -343,10 +343,10 @@
|
||||
"error": "সংস্করণ পরীক্ষা ত্রুটি",
|
||||
"checkFailed": "আপডেটগুলি পরীক্ষা করা যায়নি",
|
||||
"upToDate": "অ্যাপটি আপ টু ডেট আছে",
|
||||
"currentVersion": "আপনি {{version}} সংস্করণটি চালাচ্ছেন",
|
||||
"currentVersion": "তুমি {{version}}সংস্করণটি চালাচ্ছো",
|
||||
"updateAvailable": "আপডেট উপলব্ধ",
|
||||
"newVersionAvailable": "একটি নতুন সংস্করণ উপলব্ধ! আপনি {{current}} ব্যবহার করছেন, কিন্তু {{latest}} উপলব্ধ।",
|
||||
"releasedOn": "{{date}} তারিখে মুক্তি পেয়েছে",
|
||||
"newVersionAvailable": "একটি নতুন সংস্করণ উপলব্ধ! আপনি {{current}}ব্যবহার করছেন, কিন্তু {{latest}} উপলব্ধ।",
|
||||
"releasedOn": "মুক্তিপ্রাপ্ত {{date}}",
|
||||
"downloadUpdate": "আপডেট ডাউনলোড করুন",
|
||||
"dismiss": "খারিজ করুন",
|
||||
"checking": "আপডেটের জন্য চেক করা হচ্ছে...",
|
||||
@@ -382,7 +382,7 @@
|
||||
"home": "হোম",
|
||||
"expired": "মেয়াদোত্তীর্ণ",
|
||||
"expiresToday": "আজ মেয়াদ শেষ হবে",
|
||||
"expiresTomorrow": "{{days}} দিনের মধ্যে মেয়াদ শেষ হবে",
|
||||
"expiresTomorrow": "{{days}} দিনে মেয়াদ শেষ হবে",
|
||||
"updateAvailable": "আপডেট উপলব্ধ",
|
||||
"sshPath": "SSH পাথ",
|
||||
"localPath": "স্থানীয় পথ",
|
||||
@@ -498,7 +498,7 @@
|
||||
"userManagement": "ব্যবহারকারী ব্যবস্থাপনা",
|
||||
"makeAdmin": "অ্যাডমিন করুন",
|
||||
"removeAdmin": "অ্যাডমিন সরান",
|
||||
"deleteUser": "ব্যবহারকারী {{username}} মুছে ফেলবেন? এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"deleteUser": "ব্যবহারকারী {{username}}মুছে ফেলবেন? এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"allowRegistration": "নিবন্ধনের অনুমতি দিন",
|
||||
"oidcSettings": "OIDC সেটিংস",
|
||||
"clientId": "ক্লায়েন্ট আইডি",
|
||||
@@ -509,7 +509,7 @@
|
||||
"updateSettings": "সেটিংস আপডেট করুন",
|
||||
"confirmDelete": "আপনি কি নিশ্চিত যে আপনি এই ব্যবহারকারীকে মুছে ফেলতে চান?",
|
||||
"confirmMakeAdmin": "তুমি কি নিশ্চিত যে তুমি {{username}} কে একজন অ্যাডমিন বানাতে চাও?",
|
||||
"confirmRemoveAdmin": "আপনি কি নিশ্চিত যে আপনি {{username}} থেকে অ্যাডমিন স্ট্যাটাসটি সরাতে চান?",
|
||||
"confirmRemoveAdmin": "আপনি কি নিশ্চিত যে আপনি {{username}}থেকে অ্যাডমিন স্ট্যাটাসটি সরাতে চান?",
|
||||
"externalAuthentication": "বাহ্যিক প্রমাণীকরণ (OIDC)",
|
||||
"configureExternalProvider": "OIDC/OAuth2 প্রমাণীকরণের জন্য বহিরাগত পরিচয় প্রদানকারী কনফিগার করুন।",
|
||||
"userIdentifierPath": "ব্যবহারকারী শনাক্তকারী পথ",
|
||||
@@ -547,10 +547,10 @@
|
||||
"failedToUpdateOidcConfig": "OIDC কনফিগারেশন আপডেট করতে ব্যর্থ হয়েছে",
|
||||
"failedToDisableOidcConfig": "OIDC কনফিগারেশন নিষ্ক্রিয় করতে ব্যর্থ হয়েছে",
|
||||
"enterUsernameToMakeAdmin": "অ্যাডমিন করতে ব্যবহারকারীর নাম লিখুন",
|
||||
"userIsNowAdmin": "ব্যবহারকারী {{username}} এখন একজন প্রশাসক",
|
||||
"userIsNowAdmin": "ব্যবহারকারী {{username}} এখন একজন অ্যাডমিন",
|
||||
"failedToMakeUserAdmin": "ব্যবহারকারীকে প্রশাসক করা যায়নি",
|
||||
"removeAdminStatus": "{{username}} থেকে অ্যাডমিন স্ট্যাটাস সরাবেন?",
|
||||
"adminStatusRemoved": "{{username}} থেকে অ্যাডমিন স্ট্যাটাস সরানো হয়েছে",
|
||||
"removeAdminStatus": "{{username}}থেকে অ্যাডমিন স্ট্যাটাস সরাবেন?",
|
||||
"adminStatusRemoved": "{{username}}থেকে অ্যাডমিন স্ট্যাটাস সরানো হয়েছে",
|
||||
"failedToRemoveAdminStatus": "অ্যাডমিন স্ট্যাটাস সরাতে ব্যর্থ হয়েছে",
|
||||
"userDeletedSuccessfully": "ব্যবহারকারী {{username}} সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"failedToDeleteUser": "ব্যবহারকারী মুছে ফেলা যায়নি",
|
||||
@@ -581,21 +581,21 @@
|
||||
"administratorRole": "প্রশাসকের ভূমিকা",
|
||||
"administratorRoleDescription": "সম্পূর্ণ সিস্টেম অ্যাক্সেস এবং পরিচালনার সুবিধা প্রদান করুন",
|
||||
"passwordManagement": "পাসওয়ার্ড ব্যবস্থাপনা",
|
||||
"passwordResetWarning": "ব্যবহারকারীর পাসওয়ার্ড রিসেট করলে তাদের সমস্ত ডেটা (SSH হোস্ট, শংসাপত্র, সেটিংস) মুছে যাবে। এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"passwordResetWarning": "ব্যবহারকারীর পাসওয়ার্ড রিসেট করলে তার সমস্ত ডেটা (SSH হোস্ট, শংসাপত্র, সেটিংস) মুছে যাবে। এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"resetUserPassword": "ব্যবহারকারীর পাসওয়ার্ড রিসেট করুন",
|
||||
"resettingPassword": "রিসেট করা হচ্ছে...",
|
||||
"passwordResetInitiated": "{{username}} এর জন্য পাসওয়ার্ড রিসেট শুরু হয়েছে। রিসেট কোড পাঠানো হয়েছে।",
|
||||
"passwordResetInitiated": "{{username}}এর জন্য পাসওয়ার্ড রিসেট শুরু হয়েছে। রিসেট কোড পাঠানো হয়েছে।",
|
||||
"failedToResetPassword": "পাসওয়ার্ড রিসেট শুরু করা যায়নি",
|
||||
"sessionManagement": "সেশন ম্যানেজমেন্ট",
|
||||
"revokeAllSessions": "সকল সেশন প্রত্যাহার করুন",
|
||||
"revokeAllSessionsDescription": "সমস্ত ডিভাইস এবং সেশন থেকে জোর করে লগআউট করুন",
|
||||
"revokeAllSessionsDescription": "সকল ডিভাইস এবং সেশন থেকে জোর করে লগআউট করুন",
|
||||
"revoking": "প্রত্যাহার করা হচ্ছে...",
|
||||
"revoke": "সব প্রত্যাহার করুন",
|
||||
"dangerZone": "বিপদ অঞ্চল",
|
||||
"deleteUserTitle": "ব্যবহারকারীর অ্যাকাউন্ট মুছুন",
|
||||
"deleteUserWarning": "এই ব্যবহারকারীর অ্যাকাউন্ট এবং এর সাথে সম্পর্কিত সমস্ত ডেটা স্থায়ীভাবে মুছে ফেলুন। এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"deleting": "মুছে ফেলা হচ্ছে...",
|
||||
"cannotDeleteSelf": "আপনি নিজের অ্যাকাউন্ট মুছে ফেলতে পারবেন না।",
|
||||
"cannotDeleteSelf": "আপনি নিজের অ্যাকাউন্ট মুছে ফেলতে পারবেন না",
|
||||
"cannotRemoveLastAdmin": "শেষ প্রশাসককে সরানো যাচ্ছে না",
|
||||
"cannotRemoveOwnAdmin": "আপনি আপনার নিজস্ব প্রশাসকের অধিকারগুলি সরাতে পারবেন না।",
|
||||
"cannotModifyOwnAdminStatus": "আপনি আপনার নিজের অ্যাডমিন স্ট্যাটাস পরিবর্তন করতে পারবেন না।",
|
||||
@@ -611,12 +611,12 @@
|
||||
"linkTargetUsernamePlaceholder": "পাসওয়ার্ড অ্যাকাউন্টের ব্যবহারকারীর নাম লিখুন",
|
||||
"linkAccountsButton": "অ্যাকাউন্ট লিঙ্ক করুন",
|
||||
"linkingAccounts": "লিঙ্ক করা হচ্ছে...",
|
||||
"accountsLinkedSuccessfully": "OIDC ব্যবহারকারী {{oidcUsername}} কে {{targetUsername}} এর সাথে লিঙ্ক করা হয়েছে",
|
||||
"accountsLinkedSuccessfully": "OIDC ব্যবহারকারী {{oidcUsername}} কে {{targetUsername}}এর সাথে লিঙ্ক করা হয়েছে",
|
||||
"failedToLinkAccounts": "অ্যাকাউন্ট লিঙ্ক করা যায়নি",
|
||||
"linkTargetUsernameRequired": "লক্ষ্য ব্যবহারকারীর নাম প্রয়োজন",
|
||||
"unlinkOIDCTitle": "OIDC প্রমাণীকরণ আনলিঙ্ক করুন",
|
||||
"unlinkOIDCDescription": "{{username}} থেকে OIDC প্রমাণীকরণ সরাবেন? এর পরে ব্যবহারকারী কেবল ব্যবহারকারীর নাম/পাসওয়ার্ড দিয়ে লগইন করতে পারবেন।",
|
||||
"unlinkOIDCSuccess": "{{username}} থেকে OIDC আনলিঙ্ক করা হয়েছে",
|
||||
"unlinkOIDCDescription": "{{username}}থেকে OIDC প্রমাণীকরণ সরান? এর পরে ব্যবহারকারী কেবল ব্যবহারকারীর নাম/পাসওয়ার্ড দিয়ে লগইন করতে পারবেন।",
|
||||
"unlinkOIDCSuccess": "OIDC {{username}}থেকে আনলিঙ্ক করা হয়েছে",
|
||||
"failedToUnlinkOIDC": "OIDC লিঙ্কমুক্ত করতে ব্যর্থ হয়েছে",
|
||||
"databaseSecurity": "ডাটাবেস নিরাপত্তা",
|
||||
"encryptionStatus": "এনক্রিপশন স্ট্যাটাস",
|
||||
@@ -631,7 +631,7 @@
|
||||
"deviceProtectedMasterKey": "পরিবেশ-সুরক্ষিত মাস্টার কী",
|
||||
"legacyKeyStorage": "লিগ্যাসি কী স্টোরেজ",
|
||||
"masterKeyEncryptedWithDeviceFingerprint": "পরিবেশগত ফিঙ্গারপ্রিন্ট সহ এনক্রিপ্ট করা মাস্টার কী (KEK সুরক্ষা সক্রিয়)",
|
||||
"keyNotProtectedByDeviceBinding": "কী পরিবেশগত বাঁধাই দ্বারা সুরক্ষিত নয় (আপগ্রেড করার প্রস্তাব দেওয়া হয়েছে)",
|
||||
"keyNotProtectedByDeviceBinding": "কী পরিবেশগত বাঁধাই দ্বারা সুরক্ষিত নয় (আপগ্রেড করার পরামর্শ দেওয়া হচ্ছে)",
|
||||
"valid": "বৈধ",
|
||||
"initializeDatabaseEncryption": "ডাটাবেস এনক্রিপশন শুরু করুন",
|
||||
"enableAes256EncryptionWithDeviceBinding": "পরিবেশ-ভিত্তিক মাস্টার কী সুরক্ষা সহ AES-256 এনক্রিপশন সক্ষম করুন। এটি SSH কী, পাসওয়ার্ড এবং প্রমাণীকরণ টোকেনের জন্য এন্টারপ্রাইজ-গ্রেড সুরক্ষা তৈরি করে।",
|
||||
@@ -713,7 +713,7 @@
|
||||
"activeSecurityFeatures": "বর্তমানে সক্রিয় নিরাপত্তা ব্যবস্থা এবং সুরক্ষা",
|
||||
"deviceBindingTechnology": "উন্নত হার্ডওয়্যার-ভিত্তিক কী সুরক্ষা প্রযুক্তি",
|
||||
"backupAndRecovery": "নিরাপদ ব্যাকআপ তৈরি এবং ডাটাবেস পুনরুদ্ধারের বিকল্পগুলি",
|
||||
"crossSystemDataTransfer": "বিভিন্ন সিস্টেমে ডাটাবেস রপ্তানি এবং আমদানি করুন",
|
||||
"crossSystemDataTransfer": "বিভিন্ন সিস্টেম জুড়ে ডাটাবেস রপ্তানি এবং আমদানি করুন",
|
||||
"noMigrationNeeded": "কোনও স্থানান্তরের প্রয়োজন নেই",
|
||||
"encryptionKey": "এনক্রিপশন কী",
|
||||
"keyProtection": "চাবি সুরক্ষা",
|
||||
@@ -785,15 +785,15 @@
|
||||
"downloadSample": "নমুনা ডাউনলোড করুন",
|
||||
"formatGuide": "ফর্ম্যাট গাইড",
|
||||
"exportCredentialWarning": "সতর্কতা: হোস্ট \"{{name}}\" শংসাপত্র প্রমাণীকরণ ব্যবহার করে। রপ্তানি করা ফাইলটিতে শংসাপত্রের ডেটা অন্তর্ভুক্ত থাকবে না এবং আমদানির পরে ম্যানুয়ালি পুনরায় কনফিগার করতে হবে। আপনি কি চালিয়ে যেতে চান?",
|
||||
"exportSensitiveDataWarning": "সতর্কতা: হোস্ট \"{{name}}\"-এ সংবেদনশীল প্রমাণীকরণ ডেটা (পাসওয়ার্ড/SSH কী) রয়েছে। এক্সপোর্ট করা ফাইলটিতে এই ডেটা প্লেইন টেক্সটে অন্তর্ভুক্ত থাকবে। দয়া করে ফাইলটি সুরক্ষিত রাখুন এবং ব্যবহারের পরে এটি মুছে ফেলুন। আপনি কি চালিয়ে যেতে চান?",
|
||||
"exportSensitiveDataWarning": "সতর্কতা: \"{{name}}\" হোস্টে সংবেদনশীল প্রমাণীকরণ ডেটা (পাসওয়ার্ড/SSH কী) রয়েছে। এক্সপোর্ট করা ফাইলটিতে এই ডেটা প্লেইন টেক্সটে অন্তর্ভুক্ত থাকবে। দয়া করে ফাইলটি সুরক্ষিত রাখুন এবং ব্যবহারের পরে এটি মুছে ফেলুন। আপনি কি চালিয়ে যেতে চান?",
|
||||
"uncategorized": "শ্রেণীবদ্ধ নয়",
|
||||
"confirmDelete": "তুমি কি নিশ্চিত যে তুমি \"{{name}}\" মুছে ফেলতে চাও?",
|
||||
"confirmDelete": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" মুছে ফেলতে চান?",
|
||||
"failedToDeleteHost": "হোস্ট মুছে ফেলা যায়নি",
|
||||
"failedToExportHost": "হোস্ট এক্সপোর্ট করতে ব্যর্থ হয়েছে। অনুগ্রহ করে নিশ্চিত করুন যে আপনি লগ ইন করেছেন এবং হোস্ট ডেটাতে অ্যাক্সেস আছে।",
|
||||
"jsonMustContainHosts": "JSON-এ অবশ্যই একটি \"হোস্ট\" অ্যারে থাকতে হবে অথবা হোস্টের একটি অ্যারে হতে হবে",
|
||||
"failedToExportHost": "হোস্ট এক্সপোর্ট করা যায়নি। অনুগ্রহ করে নিশ্চিত করুন যে আপনি লগ ইন করেছেন এবং হোস্ট ডেটাতে অ্যাক্সেস আছে।",
|
||||
"jsonMustContainHosts": "JSON-এ অবশ্যই একটি \"হোস্ট\" অ্যারে থাকতে হবে অথবা হোস্টের একটি অ্যারে হতে হবে।",
|
||||
"noHostsInJson": "JSON ফাইলে কোনও হোস্ট পাওয়া যায়নি",
|
||||
"maxHostsAllowed": "প্রতি আমদানিতে সর্বোচ্চ ১০০টি হোস্ট অনুমোদিত",
|
||||
"importCompleted": "আমদানি সম্পন্ন হয়েছে: {{success}} সফল, {{failed}} ব্যর্থ হয়েছে",
|
||||
"importCompleted": "আমদানি সম্পন্ন হয়েছে: {{success}} সফল, {{failed}} ব্যর্থ",
|
||||
"importFailed": "আমদানি ব্যর্থ হয়েছে",
|
||||
"importError": "আমদানি ত্রুটি",
|
||||
"failedToImportJson": "JSON ফাইল আমদানি করা যায়নি",
|
||||
@@ -816,9 +816,9 @@
|
||||
"editHost": "হোস্ট সম্পাদনা করুন",
|
||||
"cloneHost": "ক্লোন হোস্ট",
|
||||
"updateHost": "হোস্ট আপডেট করুন",
|
||||
"hostUpdatedSuccessfully": "হোস্ট \"{{name}}\" সফলভাবে আপডেট হয়েছে!",
|
||||
"hostAddedSuccessfully": "হোস্ট \"{{name}}\" সফলভাবে যোগ করা হয়েছে!",
|
||||
"hostDeletedSuccessfully": "হোস্ট \"{{name}}\" সফলভাবে মুছে ফেলা হয়েছে!",
|
||||
"hostUpdatedSuccessfully": "\"{{name}}\" হোস্ট সফলভাবে আপডেট হয়েছে!",
|
||||
"hostAddedSuccessfully": "\"{{name}}\" হোস্ট সফলভাবে যোগ করা হয়েছে!",
|
||||
"hostDeletedSuccessfully": "\"{{name}}\" হোস্টটি সফলভাবে মুছে ফেলা হয়েছে!",
|
||||
"failedToSaveHost": "হোস্ট সংরক্ষণ করতে ব্যর্থ হয়েছে। দয়া করে আবার চেষ্টা করুন।",
|
||||
"savingHost": "হোস্ট সংরক্ষণ করা হচ্ছে...",
|
||||
"updatingHost": "হোস্ট আপডেট করা হচ্ছে...",
|
||||
@@ -837,10 +837,10 @@
|
||||
"connection": "সংযোগ",
|
||||
"remove": "অপসারণ",
|
||||
"sourcePort": "সোর্স পোর্ট",
|
||||
"sourcePortDesc": "(উৎসটি সাধারণ ট্যাবে বর্তমান সংযোগের বিবরণ উল্লেখ করে)",
|
||||
"sourcePortDesc": " (উৎসটি সাধারণ ট্যাবে বর্তমান সংযোগের বিবরণ উল্লেখ করে)",
|
||||
"endpointPort": "এন্ডপয়েন্ট পোর্ট",
|
||||
"endpointSshConfig": "এন্ডপয়েন্ট SSH কনফিগারেশন",
|
||||
"tunnelForwardDescription": "এই টানেলটি সোর্স মেশিনের {{sourcePort}} পোর্ট (সাধারণ ট্যাবে বর্তমান সংযোগের বিবরণ) থেকে ট্র্যাফিককে এন্ডপয়েন্ট মেশিনের {{endpointPort}} পোর্টে ফরোয়ার্ড করবে।",
|
||||
"tunnelForwardDescription": "এই টানেলটি সোর্স মেশিনের {{sourcePort}} পোর্ট থেকে ট্র্যাফিককে এন্ডপয়েন্ট মেশিনের {{endpointPort}} পোর্টে ফরোয়ার্ড করবে।",
|
||||
"maxRetries": "সর্বোচ্চ পুনঃপ্রচেষ্টা",
|
||||
"maxRetriesDescription": "টানেল সংযোগের জন্য সর্বোচ্চ সংখ্যক পুনঃপ্রচেষ্টা।",
|
||||
"retryInterval": "পুনরায় চেষ্টা করার ব্যবধান (সেকেন্ড)",
|
||||
@@ -916,10 +916,10 @@
|
||||
"customCommandsDesc": "এই সার্ভারের জন্য কাস্টম শাটডাউন এবং রিবুট কমান্ড নির্ধারণ করুন",
|
||||
"shutdownCommand": "শাটডাউন কমান্ড",
|
||||
"rebootCommand": "কমান্ড রিবুট করুন",
|
||||
"confirmRemoveFromFolder": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" ফোল্ডার থেকে \"{{folder}}\" মুছে ফেলতে চান? হোস্টটি \"কোন ফোল্ডার নেই\" তে সরানো হবে।",
|
||||
"removedFromFolder": "ফোল্ডার থেকে হোস্ট \"{{name}}\" সফলভাবে সরানো হয়েছে",
|
||||
"confirmRemoveFromFolder": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" ফোল্ডার থেকে \"{{folder}}\" সরাতে চান? হোস্টটি \"কোনও ফোল্ডার নেই\" তে সরানো হবে?",
|
||||
"removedFromFolder": "\"{{name}}\" হোস্টটি ফোল্ডার থেকে সফলভাবে সরানো হয়েছে",
|
||||
"failedToRemoveFromFolder": "ফোল্ডার থেকে হোস্ট সরানো যায়নি",
|
||||
"folderRenamed": "\"{{oldName}}\" ফোল্ডারটির নাম পরিবর্তন করে \"{{newName}}\" করা হয়েছে।",
|
||||
"folderRenamed": "\"{{oldName}}\" ফোল্ডারের নাম পরিবর্তন করে \"{{newName}}\" করা হয়েছে",
|
||||
"failedToRenameFolder": "ফোল্ডারের নাম পরিবর্তন করা যায়নি",
|
||||
"editFolderAppearance": "ফোল্ডারের উপস্থিতি সম্পাদনা করুন",
|
||||
"editFolderAppearanceDesc": "ফোল্ডারের রঙ এবং আইকন কাস্টমাইজ করুন",
|
||||
@@ -929,21 +929,21 @@
|
||||
"folderAppearanceUpdated": "ফোল্ডারের উপস্থিতি সফলভাবে আপডেট করা হয়েছে",
|
||||
"failedToUpdateFolderAppearance": "ফোল্ডারের উপস্থিতি আপডেট করা যায়নি",
|
||||
"deleteAllHostsInFolder": "ফোল্ডারে থাকা সকল হোস্ট মুছে ফেলুন",
|
||||
"confirmDeleteAllHostsInFolder": "আপনি কি নিশ্চিত যে আপনি \"{{count}}\" ফোল্ডারের সমস্ত {{folder}} হোস্ট মুছে ফেলতে চান? এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"allHostsInFolderDeleted": "\"{{count}}\" ফোল্ডার থেকে {{folder}} হোস্ট সফলভাবে মুছে ফেলা হয়েছে।",
|
||||
"confirmDeleteAllHostsInFolder": "\"{{folder}}\" ফোল্ডারে থাকা সমস্ত {{count}} হোস্ট মুছে ফেলার বিষয়ে আপনি কি নিশ্চিত? এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"allHostsInFolderDeleted": "\"{{folder}}\" ফোল্ডার থেকে {{count}} হোস্টগুলি সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"failedToDeleteHostsInFolder": "ফোল্ডারে হোস্ট মুছে ফেলা যায়নি",
|
||||
"movedToFolder": "হোস্ট \"{{name}}\" সফলভাবে \"{{folder}}\" এ সরানো হয়েছে",
|
||||
"movedToFolder": "\"{{name}}\" হোস্টটি সফলভাবে \"{{folder}}\" তে সরানো হয়েছে",
|
||||
"failedToMoveToFolder": "হোস্টকে ফোল্ডারে সরানো যায়নি",
|
||||
"clickToRenameFolder": "ফোল্ডারের নাম পরিবর্তন করতে ক্লিক করুন",
|
||||
"renameFolder": "ফোল্ডারটির নাম পরিবর্তন করুন",
|
||||
"removeFromFolder": "\"{{folder}}\" ফোল্ডার থেকে সরান।",
|
||||
"removeFromFolder": "\"{{folder}}\" ফোল্ডার থেকে সরান",
|
||||
"editHostTooltip": "হোস্ট সম্পাদনা করুন",
|
||||
"deleteHostTooltip": "হোস্ট মুছুন",
|
||||
"exportHostTooltip": "হোস্ট রপ্তানি করুন",
|
||||
"cloneHostTooltip": "ক্লোন হোস্ট",
|
||||
"clickToEditHost": "হোস্ট সম্পাদনা করতে ক্লিক করুন",
|
||||
"dragToMoveBetweenFolders": "ফোল্ডার থেকে অন্য ফোল্ডারে যেতে টেনে আনুন",
|
||||
"exportedHostConfig": "{{name}} এর জন্য হোস্ট কনফিগারেশন রপ্তানি করা হয়েছে",
|
||||
"exportedHostConfig": "{{name}}এর জন্য হোস্ট কনফিগারেশন রপ্তানি করা হয়েছে",
|
||||
"openTerminal": "টার্মিনাল খুলুন",
|
||||
"openFileManager": "ফাইল ম্যানেজার খুলুন",
|
||||
"openTunnels": "খোলা টানেল",
|
||||
@@ -982,7 +982,7 @@
|
||||
"selectFont": "ফন্ট নির্বাচন করুন",
|
||||
"selectFontDesc": "টার্মিনালে ব্যবহার করার জন্য ফন্ট নির্বাচন করুন",
|
||||
"fontSize": "ফন্ট সাইজ",
|
||||
"fontSizeValue": "ফন্ট সাইজ: {{value}}px",
|
||||
"fontSizeValue": "ফন্ট সাইজ: {{value}}পিক্সেল",
|
||||
"adjustFontSize": "টার্মিনাল ফন্টের আকার সামঞ্জস্য করুন",
|
||||
"letterSpacing": "অক্ষরের ব্যবধান",
|
||||
"letterSpacingValue": "অক্ষরের ব্যবধান: {{value}}px",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "শব্দ",
|
||||
"bellStyleVisual": "ভিজ্যুয়াল",
|
||||
"bellStyleBoth": "উভয়ই",
|
||||
"bellStyleDesc": "টার্মিনাল বেল (BEL অক্ষর, \\x07) কীভাবে পরিচালনা করবেন। প্রোগ্রামগুলি কাজ সম্পন্ন করার সময়, ত্রুটির সম্মুখীন হওয়ার সময় বা বিজ্ঞপ্তির জন্য এটি ট্রিগার করে। \"সাউন্ড\" একটি অডিও বিপ বাজায়, \"ভিজ্যুয়াল\" স্ক্রিনটি সংক্ষিপ্তভাবে ফ্ল্যাশ করে, \"উভয়\" উভয়ই করে, \"কোনটিই নয়\" বেল সতর্কতা অক্ষম করে।",
|
||||
"bellStyleDesc": "টার্মিনাল বেল (BEL অক্ষর, \\x07) কীভাবে পরিচালনা করবেন। প্রোগ্রামগুলি কাজ সম্পন্ন করার সময়, ত্রুটির সম্মুখীন হওয়ার সময় বা বিজ্ঞপ্তির জন্য এটি ট্রিগার করে। \"সাউন্ড\" একটি অডিও বিপ বাজায়, \"ভিজ্যুয়াল\" স্ক্রিনটি সংক্ষিপ্তভাবে ফ্ল্যাশ করে, \"উভয়\" উভয়ই করে, \"কিছুই নয়\" বেল সতর্কতা অক্ষম করে।",
|
||||
"rightClickSelectsWord": "রাইট ক্লিক করলে শব্দ নির্বাচন করা হয়",
|
||||
"rightClickSelectsWordDesc": "ডান-ক্লিক করলে কার্সারের নীচের শব্দটি নির্বাচন করা হয়",
|
||||
"fastScrollModifier": "দ্রুত স্ক্রোল সংশোধক",
|
||||
@@ -1049,15 +1049,15 @@
|
||||
"noServerFound": "কোন সার্ভার পাওয়া যায়নি।",
|
||||
"jumpHostsOrder": "সংযোগগুলি ক্রমানুসারে তৈরি করা হবে: জাম্প হোস্ট ১ → জাম্প হোস্ট ২ → ... → টার্গেট সার্ভার",
|
||||
"socks5Proxy": "SOCKS5 প্রক্সি",
|
||||
"socks5Description": "SSH সংযোগের জন্য SOCKS5 প্রক্সি কনফিগার করুন। সমস্ত ট্র্যাফিক নির্দিষ্ট প্রক্সি সার্ভারের মাধ্যমে রাউটেড হবে।",
|
||||
"socks5Description": "SSH সংযোগের জন্য SOCKS5 প্রক্সি কনফিগার করুন। সমস্ত ট্র্যাফিক নির্দিষ্ট প্রক্সি সার্ভারের মাধ্যমে রাউট করা হবে।",
|
||||
"enableSocks5": "SOCKS5 প্রক্সি সক্ষম করুন",
|
||||
"enableSocks5Description": "এই SSH সংযোগের জন্য SOCKS5 প্রক্সি ব্যবহার করুন",
|
||||
"socks5Host": "প্রক্সি হোস্ট",
|
||||
"socks5Port": "প্রক্সি পোর্ট",
|
||||
"socks5Username": "প্রক্সি ব্যবহারকারীর নাম",
|
||||
"socks5Password": "প্রক্সি পাসওয়ার্ড",
|
||||
"socks5UsernameOptional": "ঐচ্ছিক: যদি প্রক্সির প্রমাণীকরণের প্রয়োজন না হয় তবে খালি রাখুন",
|
||||
"socks5PasswordOptional": "ঐচ্ছিক: যদি প্রক্সির প্রমাণীকরণের প্রয়োজন না হয় তবে খালি রাখুন",
|
||||
"socks5UsernameOptional": "ঐচ্ছিক: প্রক্সির প্রমাণীকরণের প্রয়োজন না হলে খালি রাখুন",
|
||||
"socks5PasswordOptional": "ঐচ্ছিক: প্রক্সির প্রমাণীকরণের প্রয়োজন না হলে খালি রাখুন",
|
||||
"socks5ProxyChain": "প্রক্সি চেইন",
|
||||
"socks5ProxyChainDescription": "SOCKS প্রক্সির একটি চেইন কনফিগার করুন। চেইনের প্রতিটি প্রক্সি পূর্ববর্তীটির মাধ্যমে সংযুক্ত হবে।",
|
||||
"socks5ProxyMode": "প্রক্সি মোড",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "প্রক্সি চেইন প্রিসেট তৈরি করা হয়েছে",
|
||||
"socks5PresetUpdated": "প্রক্সি চেইন প্রিসেট আপডেট করা হয়েছে",
|
||||
"socks5PresetDeleted": "প্রক্সি চেইন প্রিসেট মুছে ফেলা হয়েছে",
|
||||
"socks5PresetSaved": "প্রিসেট \"{{name}}\" সফলভাবে সংরক্ষিত হয়েছে",
|
||||
"socks5PresetSaved": "\"{{name}}\" প্রিসেট সফলভাবে সংরক্ষণ করা হয়েছে",
|
||||
"socks5PresetSaveError": "প্রিসেট সংরক্ষণ করা যায়নি",
|
||||
"socks5PresetNameRequired": "প্রিসেট নাম প্রয়োজন",
|
||||
"socks5EmptyChainError": "একটি খালি প্রক্সি চেইন সংরক্ষণ করা যাচ্ছে না",
|
||||
@@ -1095,7 +1095,7 @@
|
||||
"addQuickAction": "দ্রুত পদক্ষেপ যোগ করুন",
|
||||
"quickActionName": "অ্যাকশনের নাম",
|
||||
"noSnippetFound": "কোনও স্নিপেট পাওয়া যায়নি",
|
||||
"quickActionsOrder": "সার্ভার স্ট্যাটাস পৃষ্ঠায় উপরে তালিকাভুক্ত ক্রমে দ্রুত পদক্ষেপের বোতামগুলি প্রদর্শিত হবে।",
|
||||
"quickActionsOrder": "সার্ভার পরিসংখ্যান পৃষ্ঠায় উপরে তালিকাভুক্ত ক্রমে দ্রুত পদক্ষেপের বোতামগুলি প্রদর্শিত হবে।",
|
||||
"advancedAuthSettings": "উন্নত প্রমাণীকরণ সেটিংস",
|
||||
"sudoPasswordAutoFill": "সুডো পাসওয়ার্ড অটো-ফিল",
|
||||
"sudoPasswordAutoFillDesc": "sudo পাসওয়ার্ডের জন্য অনুরোধ করলে স্বয়ংক্রিয়ভাবে SSH পাসওয়ার্ড সন্নিবেশ করার প্রস্তাব দেয়",
|
||||
@@ -1119,7 +1119,7 @@
|
||||
"validating": "ডকার যাচাই করা হচ্ছে...",
|
||||
"error": "ত্রুটি",
|
||||
"errorCode": "ত্রুটি কোড: {{code}}",
|
||||
"version": "ডকার v{{version}}",
|
||||
"version": "ডকার বনাম{{version}}",
|
||||
"current": "বর্তমান",
|
||||
"used_limit": "ব্যবহৃত / সীমা",
|
||||
"percentage": "শতাংশ",
|
||||
@@ -1133,7 +1133,7 @@
|
||||
"console": "কনসোল",
|
||||
"containerMustBeRunning": "কনসোলের সাথে সংযোগ স্থাপনের জন্য কন্টেইনারটি অবশ্যই চলমান থাকতে হবে",
|
||||
"authenticationRequired": "প্রমাণীকরণ প্রয়োজন",
|
||||
"connectedTo": "{{containerName}} এর সাথে সংযুক্ত",
|
||||
"connectedTo": "{{containerName}}এর সাথে সংযুক্ত",
|
||||
"disconnected": "সংযোগ বিচ্ছিন্ন",
|
||||
"consoleError": "কনসোল ত্রুটি",
|
||||
"errorMessage": "ত্রুটি: {{message}}",
|
||||
@@ -1150,7 +1150,7 @@
|
||||
"disconnect": "সংযোগ বিচ্ছিন্ন করুন",
|
||||
"notConnected": "সংযুক্ত নেই",
|
||||
"clickToConnect": "একটি ইন্টারেক্টিভ শেল শুরু করতে Connect এ ক্লিক করুন।",
|
||||
"connectingTo": "{{containerName}} এর সাথে সংযোগ স্থাপন করা হচ্ছে...",
|
||||
"connectingTo": "{{containerName}}এর সাথে সংযুক্ত হচ্ছে ...",
|
||||
"containerMustBeRunningToViewStats": "পরিসংখ্যান দেখার জন্য কন্টেইনারটি অবশ্যই চলমান থাকতে হবে",
|
||||
"failedToFetchStats": "পরিসংখ্যান আনতে ব্যর্থ হয়েছে",
|
||||
"noContainersFound": "কোনও কন্টেইনার পাওয়া যায়নি",
|
||||
@@ -1162,15 +1162,15 @@
|
||||
"noContainersMatchFilters": "আপনার ফিল্টারের সাথে কোনও কন্টেইনার মেলে না",
|
||||
"noContainersMatchFiltersHint": "আপনার অনুসন্ধান বা ফিল্টার সামঞ্জস্য করার চেষ্টা করুন",
|
||||
"containerStarted": "কন্টেইনার {{name}} শুরু হয়েছে",
|
||||
"failedToStartContainer": "কন্টেইনার চালু করতে ব্যর্থ: {{error}}",
|
||||
"containerStopped": "{{name}} কন্টেইনার থামানো হয়েছে",
|
||||
"failedToStopContainer": "কন্টেইনার থামাতে ব্যর্থ: {{error}}",
|
||||
"failedToStartContainer": "কন্টেইনার শুরু করতে ব্যর্থ: {{error}}",
|
||||
"containerStopped": "কন্টেইনার {{name}} বন্ধ করা হয়েছে",
|
||||
"failedToStopContainer": "কন্টেইনার থামাতে ব্যর্থ হয়েছে: {{error}}",
|
||||
"containerRestarted": "কন্টেইনার {{name}} পুনরায় চালু হয়েছে",
|
||||
"failedToRestartContainer": "কন্টেইনারটি পুনরায় চালু করতে ব্যর্থ হয়েছে: {{error}}",
|
||||
"containerUnpaused": "{{name}} কন্টেইনারটি আনপজ করা হয়েছে",
|
||||
"containerPaused": "{{name}} কন্টেইনার থামানো হয়েছে",
|
||||
"failedToTogglePauseContainer": "{{action}} কন্টেইনারে ব্যর্থ হয়েছে: {{error}}",
|
||||
"containerRemoved": "{{name}} কন্টেইনার সরানো হয়েছে",
|
||||
"containerUnpaused": "কন্টেইনার {{name}} অব্যবহৃত",
|
||||
"containerPaused": "কন্টেইনার {{name}} থামানো হয়েছে",
|
||||
"failedToTogglePauseContainer": "{{action}} কন্টেইনারে ব্যর্থ: {{error}}",
|
||||
"containerRemoved": "কন্টেইনার {{name}} সরানো হয়েছে",
|
||||
"failedToRemoveContainer": "কন্টেইনার সরানো যায়নি: {{error}}",
|
||||
"image": "ছবি:",
|
||||
"idLabel": "আইডি:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "বিরতি",
|
||||
"restart": "পুনরারম্ভ করুন",
|
||||
"removeContainer": "কন্টেইনার সরান",
|
||||
"confirmRemoveContainer": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" কন্টেইনারটি সরাতে চান?",
|
||||
"confirmRemoveContainer": "Are you sure you want to remove container \"{{name}}\"?",
|
||||
"runningContainerWarning": "সতর্কতা: এই কন্টেইনারটি বর্তমানে চলছে এবং জোর করে সরিয়ে ফেলা হবে।",
|
||||
"removing": "অপসারণ:",
|
||||
"containerNotFound": "কন্টেইনারটি পাওয়া যায়নি",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"logs": "লগ",
|
||||
"stats": "পরিসংখ্যান",
|
||||
"consoleTab": "কনসোল",
|
||||
"failedToFetchLogs": "লগগুলি আনা যায়নি: {{error}}",
|
||||
"failedToFetchLogs": "লগগুলি আনতে ব্যর্থ হয়েছে: {{error}}",
|
||||
"failedToDownloadLogs": "লগ ডাউনলোড করতে ব্যর্থ: {{error}}",
|
||||
"linesToShow": "দেখানোর জন্য লাইনগুলি",
|
||||
"last50Lines": "শেষ ৫০টি লাইন",
|
||||
@@ -1254,26 +1254,26 @@
|
||||
"uploadFile": "ফাইল আপলোড করুন",
|
||||
"downloadFile": "ডাউনলোড করুন",
|
||||
"extractArchive": "আর্কাইভ এক্সট্র্যাক্ট করুন",
|
||||
"extractingArchive": "{{name}} বের করা হচ্ছে...",
|
||||
"extractingArchive": "এক্সট্রাক্ট করা হচ্ছে {{name}}...",
|
||||
"archiveExtractedSuccessfully": "{{name}} সফলভাবে বের করা হয়েছে",
|
||||
"extractFailed": "এক্সট্র্যাক্ট করা যায়নি",
|
||||
"compressFile": "ফাইল কম্প্রেস করুন",
|
||||
"compressFiles": "ফাইল কম্প্রেস করুন",
|
||||
"compressFilesDesc": "{{count}} টি আইটেম একটি আর্কাইভে সঙ্কুচিত করুন",
|
||||
"compressFilesDesc": "{{count}} আইটেমগুলিকে একটি আর্কাইভে সঙ্কুচিত করুন",
|
||||
"archiveName": "আর্কাইভের নাম",
|
||||
"enterArchiveName": "সংরক্ষণাগারের নাম লিখুন...",
|
||||
"compressionFormat": "কম্প্রেশন ফর্ম্যাট",
|
||||
"selectedFiles": "নির্বাচিত ফাইলগুলি",
|
||||
"andMoreFiles": "এবং {{count}} আরও...",
|
||||
"compress": "সংকুচিত করুন",
|
||||
"compressingFiles": "{{count}}টি আইটেমকে {{name}}... এ সংকুচিত করা হচ্ছে",
|
||||
"compressingFiles": "{{count}} আইটেমগুলিকে {{name}}এ সংকুচিত করা হচ্ছে ...",
|
||||
"filesCompressedSuccessfully": "{{name}} সফলভাবে তৈরি করা হয়েছে",
|
||||
"compressFailed": "কম্প্রেশন ব্যর্থ হয়েছে",
|
||||
"edit": "সম্পাদনা",
|
||||
"preview": "প্রিভিউ",
|
||||
"previous": "পূর্ববর্তী",
|
||||
"next": "পরবর্তী",
|
||||
"pageXOfY": "{{current}} পৃষ্ঠা {{total}}",
|
||||
"pageXOfY": "{{current}} এর {{total}}পৃষ্ঠা",
|
||||
"zoomOut": "জুম কমান",
|
||||
"zoomIn": "জুম ইন",
|
||||
"newFile": "নতুন ফাইল",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "ফাইল নির্বাচন করুন",
|
||||
"uploading": "আপলোড হচ্ছে...",
|
||||
"downloading": "ডাউনলোড হচ্ছে...",
|
||||
"uploadingFile": "{{name}} আপলোড করা হচ্ছে...",
|
||||
"uploadingFile": "আপলোড করা হচ্ছে {{name}}...",
|
||||
"uploadingLargeFile": "বড় ফাইল আপলোড করা হচ্ছে {{name}} ({{size}})...",
|
||||
"downloadingFile": "{{name}} ডাউনলোড হচ্ছে...",
|
||||
"creatingFile": "{{name}} তৈরি করা হচ্ছে...",
|
||||
"creatingFolder": "{{name}} তৈরি করা হচ্ছে...",
|
||||
"deletingItem": "{{type}} {{name}} মুছে ফেলা হচ্ছে...",
|
||||
"renamingItem": "{{type}} {{oldName}} এর নাম পরিবর্তন করে {{newName}} করা হচ্ছে...",
|
||||
"downloadingFile": "ডাউনলোড করা হচ্ছে {{name}}...",
|
||||
"creatingFile": "{{name}}তৈরি করা হচ্ছে ...",
|
||||
"creatingFolder": "{{name}}তৈরি করা হচ্ছে ...",
|
||||
"deletingItem": "মুছে ফেলা হচ্ছে {{type}} {{name}}...",
|
||||
"renamingItem": "{{type}} {{oldName}} নাম পরিবর্তন করে {{newName}}করা হচ্ছে ...",
|
||||
"createNewFile": "নতুন ফাইল তৈরি করুন",
|
||||
"fileName": "ফাইলের নাম",
|
||||
"creating": "তৈরি করা হচ্ছে...",
|
||||
@@ -1311,25 +1311,25 @@
|
||||
"newName": "নতুন নাম",
|
||||
"thisIsDirectoryRename": "এটি একটি ডিরেক্টরি।",
|
||||
"renaming": "নাম পরিবর্তন করা হচ্ছে...",
|
||||
"fileUploadedSuccessfully": "\"{{name}}}\" ফাইলটি সফলভাবে আপলোড করা হয়েছে।",
|
||||
"fileUploadedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে আপলোড করা হয়েছে",
|
||||
"failedToUploadFile": "ফাইল আপলোড করা যায়নি",
|
||||
"fileDownloadedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে ডাউনলোড করা হয়েছে।",
|
||||
"fileDownloadedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে ডাউনলোড করা হয়েছে",
|
||||
"failedToDownloadFile": "ফাইল ডাউনলোড করতে ব্যর্থ হয়েছে",
|
||||
"noFileContent": "কোনও ফাইলের বিষয়বস্তু পাওয়া যায়নি",
|
||||
"filePath": "ফাইল পাথ",
|
||||
"fileCreatedSuccessfully": "\"{{name}}}\" ফাইলটি সফলভাবে তৈরি করা হয়েছে।",
|
||||
"fileCreatedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে তৈরি করা হয়েছে",
|
||||
"failedToCreateFile": "ফাইল তৈরি করা যায়নি",
|
||||
"folderCreatedSuccessfully": "\"{{name}}\" ফোল্ডারটি সফলভাবে তৈরি করা হয়েছে",
|
||||
"failedToCreateFolder": "ফোল্ডার তৈরি করতে ব্যর্থ হয়েছে",
|
||||
"failedToCreateItem": "আইটেম তৈরি করা যায়নি",
|
||||
"operationFailed": "{{operation}} {{name}}: {{error}} এর জন্য অপারেশন ব্যর্থ হয়েছে",
|
||||
"operationFailed": "{{operation}} {{name}}এর জন্য অপারেশন ব্যর্থ হয়েছে : {{error}}",
|
||||
"failedToResolveSymlink": "সিমলিঙ্ক সমাধান করা যায়নি",
|
||||
"itemDeletedSuccessfully": "{{type}} সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"itemsDeletedSuccessfully": "{{count}}টি আইটেম সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"itemsDeletedSuccessfully": "{{count}} আইটেমগুলি সফলভাবে মুছে ফেলা হয়েছে",
|
||||
"failedToDeleteItems": "আইটেমগুলি মোছা যায়নি",
|
||||
"dragFilesToUpload": "আপলোড করার জন্য ফাইলগুলি এখানে ফেলে দিন",
|
||||
"emptyFolder": "এই ফোল্ডারটি খালি।",
|
||||
"itemCount": "{{count}}টি আইটেম",
|
||||
"itemCount": "{{count}} আইটেম",
|
||||
"selectedCount": "{{count}} নির্বাচিত",
|
||||
"searchFiles": "ফাইলগুলি অনুসন্ধান করুন...",
|
||||
"upload": "আপলোড করুন",
|
||||
@@ -1347,25 +1347,25 @@
|
||||
"delete": "মুছে ফেলুন",
|
||||
"properties": "বৈশিষ্ট্য",
|
||||
"refresh": "রিফ্রেশ করুন",
|
||||
"downloadFiles": "ব্রাউজারে {{count}} ফাইল ডাউনলোড করুন",
|
||||
"copyFiles": "{{count}} টি আইটেম কপি করুন",
|
||||
"cutFiles": "{{count}}টি আইটেম কাটুন",
|
||||
"deleteFiles": "{{count}}টি আইটেম মুছুন",
|
||||
"filesCopiedToClipboard": "{{count}}টি আইটেম ক্লিপবোর্ডে কপি করা হয়েছে",
|
||||
"filesCutToClipboard": "{{count}}টি আইটেম ক্লিপবোর্ডে কাটা হয়েছে",
|
||||
"downloadFiles": "{{count}} ফাইলগুলি ব্রাউজারে ডাউনলোড করুন",
|
||||
"copyFiles": "{{count}} আইটেমগুলি কপি করুন",
|
||||
"cutFiles": "{{count}} আইটেম কাটুন",
|
||||
"deleteFiles": "{{count}} আইটেম মুছুন",
|
||||
"filesCopiedToClipboard": "{{count}} আইটেমগুলি ক্লিপবোর্ডে কপি করা হয়েছে",
|
||||
"filesCutToClipboard": "{{count}} ক্লিপবোর্ডে কাটা আইটেম",
|
||||
"pathCopiedToClipboard": "ক্লিপবোর্ডে পাথ কপি করা হয়েছে",
|
||||
"pathsCopiedToClipboard": "{{count}} পাথ ক্লিপবোর্ডে কপি করা হয়েছে",
|
||||
"pathsCopiedToClipboard": "{{count}} ক্লিপবোর্ডে পাথ কপি করা হয়েছে",
|
||||
"failedToCopyPath": "ক্লিপবোর্ডে পাথ কপি করতে ব্যর্থ হয়েছে",
|
||||
"movedItems": "{{count}}টি আইটেম সরানো হয়েছে",
|
||||
"movedItems": "{{count}} আইটেমগুলি সরানো হয়েছে",
|
||||
"failedToDeleteItem": "আইটেমটি মোছা যায়নি",
|
||||
"itemRenamedSuccessfully": "{{type}} সফলভাবে পুনঃনামকরণ করা হয়েছে",
|
||||
"itemRenamedSuccessfully": "{{type}} নাম পরিবর্তন করা হয়েছে",
|
||||
"failedToRenameItem": "আইটেমটির নাম পরিবর্তন করা যায়নি",
|
||||
"download": "ডাউনলোড করুন",
|
||||
"permissions": "অনুমতিসমূহ",
|
||||
"size": "আকার",
|
||||
"modified": "পরিবর্তিত",
|
||||
"path": "পথ",
|
||||
"confirmDelete": "আপনি কি নিশ্চিত যে আপনি {{name}} মুছে ফেলতে চান?",
|
||||
"confirmDelete": "আপনি কি নিশ্চিত যে আপনি {{name}}মুছে ফেলতে চান?",
|
||||
"uploadSuccess": "ফাইলটি সফলভাবে আপলোড করা হয়েছে",
|
||||
"uploadFailed": "ফাইল আপলোড ব্যর্থ হয়েছে",
|
||||
"downloadSuccess": "ফাইলটি সফলভাবে ডাউনলোড হয়েছে",
|
||||
@@ -1388,9 +1388,9 @@
|
||||
"connectToServer": "একটি সার্ভারের সাথে সংযোগ করুন",
|
||||
"selectServerToEdit": "ফাইল সম্পাদনা শুরু করতে সাইডবার থেকে একটি সার্ভার নির্বাচন করুন।",
|
||||
"fileOperations": "ফাইল অপারেশন",
|
||||
"confirmDeleteMessage": "আপনি কি নিশ্চিত যে আপনি {{name}} মুছে ফেলতে চান?",
|
||||
"confirmDeleteMessage": "আপনি কি নিশ্চিত যে আপনি {{name}}মুছে ফেলতে চান?",
|
||||
"confirmDeleteSingleItem": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" স্থায়ীভাবে মুছে ফেলতে চান?",
|
||||
"confirmDeleteMultipleItems": "আপনি কি নিশ্চিত যে আপনি {{count}} টি আইটেম স্থায়ীভাবে মুছে ফেলতে চান?",
|
||||
"confirmDeleteMultipleItems": "আপনি কি নিশ্চিত যে আপনি {{count}} আইটেমগুলি স্থায়ীভাবে মুছে ফেলতে চান?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "আপনি কি নিশ্চিত যে আপনি {{count}} আইটেমগুলি স্থায়ীভাবে মুছে ফেলতে চান? এর মধ্যে ফোল্ডার এবং তাদের সামগ্রী অন্তর্ভুক্ত।",
|
||||
"confirmDeleteFolder": "আপনি কি নিশ্চিত যে আপনি \"{{name}}\" ফোল্ডারটি এবং এর সমস্ত বিষয়বস্তু স্থায়ীভাবে মুছে ফেলতে চান?",
|
||||
"deleteDirectoryWarning": "এটি ফোল্ডার এবং এর সমস্ত বিষয়বস্তু মুছে ফেলবে।",
|
||||
@@ -1422,7 +1422,7 @@
|
||||
"openTerminalInFolder": "এই ফোল্ডারে টার্মিনাল খুলুন",
|
||||
"openTerminalInFileLocation": "ফাইলের অবস্থানে টার্মিনাল খুলুন",
|
||||
"terminalWithPath": "টার্মিনাল - {{host}}:{{path}}",
|
||||
"runningFile": "চলমান - {{file}}",
|
||||
"runningFile": "দৌড়ানো - {{file}}",
|
||||
"onlyRunExecutableFiles": "শুধুমাত্র এক্সিকিউটেবল ফাইল চালানো যাবে",
|
||||
"noHostSelected": "কোনও হোস্ট নির্বাচিত হয়নি",
|
||||
"starred": "তারকাচিহ্নিত",
|
||||
@@ -1432,7 +1432,7 @@
|
||||
"removeFailed": "সরানো ব্যর্থ হয়েছে",
|
||||
"unpinnedSuccessfully": "\"{{name}}\" সফলভাবে আনপিন করা হয়েছে",
|
||||
"unpinFailed": "আনপিন করা যায়নি",
|
||||
"removedShortcut": "\"{{name}}\" শর্টকাটটি সরানো হয়েছে।",
|
||||
"removedShortcut": "\"{{name}}\" শর্টকাটটি সরানো হয়েছে",
|
||||
"removeShortcutFailed": "শর্টকাট সরানো যায়নি",
|
||||
"clearedAllRecentFiles": "সাম্প্রতিক সব ফাইল সাফ করা হয়েছে",
|
||||
"clearFailed": "সাফ করা যায়নি",
|
||||
@@ -1445,11 +1445,11 @@
|
||||
"addToShortcuts": "শর্টকাটে যোগ করুন",
|
||||
"downloadToDefaultLocation": "ডিফল্ট অবস্থানে ডাউনলোড করুন",
|
||||
"pasteFailed": "আটকানো ব্যর্থ হয়েছে",
|
||||
"noUndoableActions": "কোনও পূর্বাবস্থায় ফেরানো যাবে না",
|
||||
"noUndoableActions": "কোনও পূর্বাবস্থায়ী পদক্ষেপ নেই",
|
||||
"undoCopySuccess": "কপি করার কাজ বাতিল করা হয়েছে: {{count}} কপি করা ফাইল মুছে ফেলা হয়েছে",
|
||||
"undoCopyFailedDelete": "পূর্বাবস্থায় ফেরানো যায়নি: কোনও কপি করা ফাইল মোছা যায়নি",
|
||||
"undoCopyFailedNoInfo": "পূর্বাবস্থায় ফেরানো যায়নি: কপি করা ফাইলের তথ্য খুঁজে পাওয়া যায়নি",
|
||||
"undoMoveSuccess": "সরানোর কাজটি বাতিল করা হয়েছে: {{count}} ফাইলগুলিকে মূল স্থানে ফিরিয়ে আনা হয়েছে",
|
||||
"undoMoveSuccess": "সরানোর কাজটি পূর্বাবস্থায় ফেরানো হয়েছে: {{count}} ফাইলগুলিকে মূল স্থানে ফিরিয়ে আনা হয়েছে",
|
||||
"undoMoveFailedMove": "পূর্বাবস্থায় ফেরানো যায়নি: কোনও ফাইল পিছনে সরানো যায়নি",
|
||||
"undoMoveFailedNoInfo": "পূর্বাবস্থায় ফেরানো যায়নি: সরানো ফাইলের তথ্য খুঁজে পাওয়া যায়নি",
|
||||
"undoDeleteNotSupported": "মুছে ফেলার কাজটি পূর্বাবস্থায় ফেরানো যাবে না: সার্ভার থেকে ফাইলগুলি স্থায়ীভাবে মুছে ফেলা হয়েছে",
|
||||
@@ -1491,36 +1491,36 @@
|
||||
"unknownSize": "অজানা আকার",
|
||||
"fileIsEmpty": "ফাইল খালি।",
|
||||
"largeFileWarning": "বড় ফাইলের সতর্কতা",
|
||||
"largeFileWarningDesc": "এই ফাইলটির আকার {{size}}, যা টেক্সট হিসেবে খোলার সময় পারফরম্যান্সের সমস্যা তৈরি করতে পারে।",
|
||||
"fileNotFoundAndRemoved": "\"{{name}}\" ফাইলটি পাওয়া যায়নি এবং সাম্প্রতিক/পিন করা ফাইলগুলি থেকে সরানো হয়েছে।",
|
||||
"largeFileWarningDesc": "এই ফাইলটি {{size}} আকারের, যা টেক্সট হিসেবে খোলার সময় কর্মক্ষমতা সংক্রান্ত সমস্যা সৃষ্টি করতে পারে।",
|
||||
"fileNotFoundAndRemoved": "\"{{name}}\" ফাইলটি পাওয়া যায়নি এবং সাম্প্রতিক/পিন করা ফাইলগুলি থেকে সরানো হয়েছে",
|
||||
"failedToLoadFile": "ফাইল লোড করতে ব্যর্থ: {{error}}",
|
||||
"serverErrorOccurred": "সার্ভার ত্রুটি ঘটেছে। অনুগ্রহ করে পরে আবার চেষ্টা করুন।",
|
||||
"autoSaveFailed": "অটো-সেভ ব্যর্থ হয়েছে",
|
||||
"fileAutoSaved": "ফাইল স্বয়ংক্রিয়ভাবে সংরক্ষিত হয়েছে",
|
||||
"moveFileFailed": "{{name}} সরানো যায়নি",
|
||||
"moveFileFailed": "সরানো যায়নি {{name}}",
|
||||
"moveOperationFailed": "সরানোর কাজ ব্যর্থ হয়েছে",
|
||||
"canOnlyCompareFiles": "শুধুমাত্র দুটি ফাইলের তুলনা করা যাবে",
|
||||
"comparingFiles": "ফাইলগুলির তুলনা: {{file1}} এবং {{file2}}",
|
||||
"comparingFiles": "ফাইল তুলনা করা হচ্ছে: {{file1}} এবং {{file2}}",
|
||||
"dragFailed": "টেনে আনার কাজ ব্যর্থ হয়েছে",
|
||||
"filePinnedSuccessfully": "\"{{name}}}\" ফাইলটি সফলভাবে পিন করা হয়েছে",
|
||||
"filePinnedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে পিন করা হয়েছে",
|
||||
"pinFileFailed": "ফাইল পিন করা যায়নি",
|
||||
"fileUnpinnedSuccessfully": "\"{{name}}}\" ফাইলটি সফলভাবে আনপিন করা হয়েছে",
|
||||
"fileUnpinnedSuccessfully": "\"{{name}}\" ফাইলটি সফলভাবে আনপিন করা হয়েছে",
|
||||
"unpinFileFailed": "ফাইল আনপিন করা যায়নি",
|
||||
"shortcutAddedSuccessfully": "ফোল্ডার শর্টকাট \"{{name}}\" সফলভাবে যোগ করা হয়েছে",
|
||||
"shortcutAddedSuccessfully": "\"{{name}}\" ফোল্ডারের শর্টকাট সফলভাবে যোগ করা হয়েছে",
|
||||
"addShortcutFailed": "শর্টকাট যোগ করা যায়নি",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}}টি আইটেম সফলভাবে সংগ্রহ করা হয়েছে",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} আইটেমগুলি সফলভাবে",
|
||||
"operationCompleted": "{{operation}} {{count}} আইটেম",
|
||||
"downloadFileSuccess": "{{name}} ফাইলটি সফলভাবে ডাউনলোড করা হয়েছে",
|
||||
"downloadFileFailed": "ডাউনলোড ব্যর্থ হয়েছে",
|
||||
"moveTo": "{{name}} এ যান",
|
||||
"diffCompareWith": "{{name}} এর সাথে পার্থক্য তুলনা করুন",
|
||||
"moveTo": "{{name}}এ যান",
|
||||
"diffCompareWith": "{{name}}এর সাথে পার্থক্য তুলনা করুন",
|
||||
"dragOutsideToDownload": "({{count}} ফাইল) ডাউনলোড করতে উইন্ডোর বাইরে টেনে আনুন",
|
||||
"newFolderDefault": "নতুন ফোল্ডার",
|
||||
"newFileDefault": "নতুন ফাইল.টেক্সট",
|
||||
"successfullyMovedItems": "{{count}} টি আইটেম সফলভাবে {{target}} এ সরানো হয়েছে",
|
||||
"successfullyMovedItems": "{{count}} আইটেমগুলিকে {{target}}এ সফলভাবে সরানো হয়েছে",
|
||||
"move": "সরান",
|
||||
"searchInFile": "ফাইলে অনুসন্ধান করুন (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "কীবোর্ড শর্টকাটগুলি দেখান",
|
||||
"showKeyboardShortcuts": "কীবোর্ড শর্টকাট দেখান",
|
||||
"startWritingMarkdown": "তোমার মার্কডাউন কন্টেন্ট লেখা শুরু করো...",
|
||||
"loadingFileComparison": "ফাইল তুলনা লোড হচ্ছে...",
|
||||
"reload": "পুনরায় লোড করুন",
|
||||
@@ -1529,7 +1529,7 @@
|
||||
"inline": "ইনলাইন",
|
||||
"fileComparison": "ফাইল তুলনা: {{file1}} বনাম {{file2}}",
|
||||
"fileTooLarge": "ফাইলটি খুব বড়: {{error}}",
|
||||
"sshConnectionFailed": "SSH সংযোগ ব্যর্থ হয়েছে। অনুগ্রহ করে {{name}} ({{ip}}:{{port}}) এ আপনার সংযোগ পরীক্ষা করুন।",
|
||||
"sshConnectionFailed": "SSH সংযোগ ব্যর্থ হয়েছে। অনুগ্রহ করে আপনার সংযোগ {{name}} ({{ip}}:{{port}}) এ পরীক্ষা করুন।",
|
||||
"loadFileFailed": "ফাইল লোড করতে ব্যর্থ: {{error}}",
|
||||
"connectedSuccessfully": "সফলভাবে সংযুক্ত হয়েছে",
|
||||
"totpVerificationFailed": "TOTP যাচাইকরণ ব্যর্থ হয়েছে",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "সংযোগ বিচ্ছিন্ন করুন",
|
||||
"cancel": "বাতিল করুন",
|
||||
"port": "বন্দর",
|
||||
"attempt": "{{current}} এর {{max}} প্রচেষ্টা",
|
||||
"attempt": "{{current}} এর {{max}}প্রচেষ্টা",
|
||||
"nextRetryIn": "পরবর্তী চেষ্টা {{seconds}} সেকেন্ডের মধ্যে",
|
||||
"checkDockerLogs": "ত্রুটির কারণে আপনার ডকার লগগুলি পরীক্ষা করুন, যোগদান করুন",
|
||||
"orCreate": "অথবা একটি তৈরি করুন",
|
||||
"checkDockerLogs": "ত্রুটির কারণের জন্য আপনার ডকার লগগুলি পরীক্ষা করুন, যোগদান করুন",
|
||||
"orCreate": "অথবা একটি তৈরি করুন ",
|
||||
"noTunnelConnections": "কোনও টানেল সংযোগ কনফিগার করা হয়নি",
|
||||
"tunnelConnections": "টানেল সংযোগ",
|
||||
"addTunnel": "টানেল যোগ করুন",
|
||||
@@ -1650,7 +1650,7 @@
|
||||
"totpInvalidCode": "অবৈধ যাচাইকরণ কোড",
|
||||
"totpCancelled": "মেট্রিক্স সংগ্রহ বাতিল করা হয়েছে",
|
||||
"authenticationFailed": "প্রমাণীকরণ ব্যর্থ হয়েছে",
|
||||
"noneAuthNotSupported": "সার্ভার পরিসংখ্যান 'কিছুই নয়' প্রমাণীকরণ প্রকার সমর্থন করে না।",
|
||||
"noneAuthNotSupported": "সার্ভার স্ট্যাটস 'কিছুই নয়' প্রমাণীকরণ প্রকার সমর্থন করে না।",
|
||||
"load": "লোড",
|
||||
"editLayout": "লেআউট সম্পাদনা করুন",
|
||||
"cancelEdit": "বাতিল করুন",
|
||||
@@ -1678,11 +1678,11 @@
|
||||
"noRecentLoginData": "কোনও সাম্প্রতিক লগইন ডেটা নেই",
|
||||
"from": "থেকে",
|
||||
"quickActions": "দ্রুত পদক্ষেপ",
|
||||
"executeQuickAction": "{{name}} কার্যকর করুন",
|
||||
"executingQuickAction": "{{name}} কার্যকর করা হচ্ছে...",
|
||||
"executeQuickAction": "কার্যকর করুন {{name}}",
|
||||
"executingQuickAction": "কার্যকর করা হচ্ছে {{name}}...",
|
||||
"quickActionSuccess": "{{name}} সফলভাবে সম্পন্ন হয়েছে",
|
||||
"quickActionFailed": "{{name}} ব্যর্থ হয়েছে",
|
||||
"quickActionError": "{{name}} কার্যকর করা যায়নি"
|
||||
"quickActionError": "{{name}}চালানো যায়নি"
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "SSH সার্ভার ম্যানেজার",
|
||||
@@ -1696,7 +1696,7 @@
|
||||
"registerButton": "নিবন্ধন",
|
||||
"forgotPassword": "পাসওয়ার্ড ভুলে গেছেন?",
|
||||
"rememberMe": "আমাকে মনে রেখো",
|
||||
"noAccount": "আপনার কি কোন অ্যাকাউন্ট নেই?",
|
||||
"noAccount": "কোন অ্যাকাউন্ট নেই?",
|
||||
"hasAccount": "ইতিমধ্যে একটি অ্যাকাউন্ট আছে?",
|
||||
"loginSuccess": "লগইন সফল হয়েছে",
|
||||
"loginFailed": "লগইন ব্যর্থ হয়েছে",
|
||||
@@ -1800,7 +1800,7 @@
|
||||
"forbidden": "অ্যাক্সেস নিষিদ্ধ",
|
||||
"serverError": "সার্ভার ত্রুটি",
|
||||
"networkError": "নেটওয়ার্ক ত্রুটি",
|
||||
"databaseConnection": "ডাটাবেসের সাথে সংযোগ করা যায়নি।",
|
||||
"databaseConnection": "ডাটাবেসের সাথে সংযোগ স্থাপন করা যায়নি।",
|
||||
"unknownError": "অজানা ত্রুটি",
|
||||
"loginFailed": "লগইন ব্যর্থ হয়েছে",
|
||||
"failedPasswordReset": "পাসওয়ার্ড রিসেট শুরু করা যায়নি",
|
||||
@@ -1811,11 +1811,11 @@
|
||||
"failedUserInfo": "OIDC লগইন করার পরে ব্যবহারকারীর তথ্য পেতে ব্যর্থ হয়েছে।",
|
||||
"oidcAuthFailed": "OIDC প্রমাণীকরণ ব্যর্থ হয়েছে",
|
||||
"noTokenReceived": "লগইন থেকে কোনও টোকেন পাওয়া যায়নি",
|
||||
"invalidAuthUrl": "ব্যাকএন্ড থেকে অবৈধ অনুমোদন URL প্রাপ্ত হয়েছে",
|
||||
"invalidAuthUrl": "ব্যাকএন্ড থেকে অবৈধ অনুমোদনের URL পাওয়া গেছে",
|
||||
"invalidInput": "অবৈধ ইনপুট",
|
||||
"requiredField": "এই ক্ষেত্রটি আবশ্যক",
|
||||
"minLength": "সর্বনিম্ন দৈর্ঘ্য {{min}}",
|
||||
"maxLength": "সর্বোচ্চ দৈর্ঘ্য {{max}}",
|
||||
"minLength": "সর্বনিম্ন দৈর্ঘ্য হল {{min}}",
|
||||
"maxLength": "সর্বোচ্চ দৈর্ঘ্য হল {{max}}",
|
||||
"invalidEmail": "অবৈধ ইমেল ঠিকানা",
|
||||
"passwordMismatch": "পাসওয়ার্ড মিলছে না।",
|
||||
"passwordLoginDisabled": "ব্যবহারকারীর নাম/পাসওয়ার্ড লগইন বর্তমানে অক্ষম করা আছে।",
|
||||
@@ -1865,7 +1865,7 @@
|
||||
"local": "স্থানীয়",
|
||||
"external": "বাহ্যিক (OIDC)",
|
||||
"externalAndLocal": "দ্বৈত প্রমাণীকরণ",
|
||||
"selectPreferredLanguage": "ইন্টারফেসের জন্য আপনার পছন্দের ভাষা নির্বাচন করুন",
|
||||
"selectPreferredLanguage": "ইন্টারফেসের জন্য আপনার পছন্দের ভাষা নির্বাচন করুন।",
|
||||
"fileColorCoding": "ফাইলের রঙ কোডিং",
|
||||
"fileColorCodingDesc": "প্রকার অনুসারে রঙ-কোড ফাইল: ফোল্ডার (লাল), ফাইল (নীল), সিমলিঙ্ক (সবুজ)",
|
||||
"commandAutocomplete": "কমান্ড স্বয়ংসম্পূর্ণ",
|
||||
@@ -1942,7 +1942,7 @@
|
||||
"socks5Username": "প্রক্সি ব্যবহারকারীর নাম",
|
||||
"socks5Password": "প্রক্সি পাসওয়ার্ড",
|
||||
"socks5PresetName": "যেমন, ওয়ার্ক ভিপিএন চেইন",
|
||||
"socks5PresetDescription": "উদাহরণস্বরূপ, কাজের সার্ভার অ্যাক্সেস করার জন্য প্রক্সি চেইন",
|
||||
"socks5PresetDescription": "যেমন, কাজের সার্ভার অ্যাক্সেস করার জন্য প্রক্সি চেইন",
|
||||
"moshCommand": "মোশ ইউজার@সার্ভার",
|
||||
"defaultPort": "২২",
|
||||
"defaultEndpointPort": "২২৪",
|
||||
@@ -1955,16 +1955,16 @@
|
||||
"passwordRequired": "পাসওয়ার্ড প্রয়োজন।",
|
||||
"failedToDeleteAccount": "অ্যাকাউন্ট মুছে ফেলা যায়নি",
|
||||
"failedToMakeUserAdmin": "ব্যবহারকারীকে প্রশাসক করা যায়নি",
|
||||
"userIsNowAdmin": "ব্যবহারকারী {{username}} এখন একজন প্রশাসক",
|
||||
"removeAdminConfirm": "আপনি কি নিশ্চিত যে আপনি {{username}} থেকে অ্যাডমিন স্ট্যাটাসটি সরাতে চান?",
|
||||
"deleteUserConfirm": "আপনি কি নিশ্চিত যে আপনি {{username}} ব্যবহারকারী মুছে ফেলতে চান? এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"userIsNowAdmin": "ব্যবহারকারী {{username}} এখন একজন অ্যাডমিন",
|
||||
"removeAdminConfirm": "আপনি কি নিশ্চিত যে আপনি {{username}}থেকে অ্যাডমিন স্ট্যাটাসটি সরাতে চান?",
|
||||
"deleteUserConfirm": "আপনি কি নিশ্চিত যে আপনি ব্যবহারকারী {{username}}মুছে ফেলতে চান? এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"deleteAccount": "অ্যাকাউন্ট মুছুন",
|
||||
"closeDeleteAccount": "অ্যাকাউন্ট মুছুন বন্ধ করুন",
|
||||
"deleteAccountWarning": "এই কাজটি পূর্বাবস্থায় ফেরানো যাবে না। এটি আপনার অ্যাকাউন্ট এবং এর সাথে সম্পর্কিত সমস্ত ডেটা স্থায়ীভাবে মুছে ফেলবে।",
|
||||
"deleteAccountWarningDetails": "আপনার অ্যাকাউন্ট মুছে ফেললে SSH হোস্ট, কনফিগারেশন এবং সেটিংস সহ আপনার সমস্ত ডেটা মুছে যাবে। এই পদক্ষেপটি অপরিবর্তনীয়।",
|
||||
"deleteAccountWarningShort": "এই ক্রিয়াটি আর উল্টানো যাবে না এবং আপনার অ্যাকাউন্ট স্থায়ীভাবে মুছে ফেলা হবে।",
|
||||
"deleteAccountWarningShort": "এই ক্রিয়াটি আর উল্টানো যাবে না এবং আপনার অ্যাকাউন্ট স্থায়ীভাবে মুছে যাবে।",
|
||||
"cannotDeleteAccount": "অ্যাকাউন্ট মুছে ফেলা যাচ্ছে না",
|
||||
"lastAdminWarning": "আপনিই শেষ অ্যাডমিন ব্যবহারকারী। আপনি আপনার অ্যাকাউন্ট মুছে ফেলতে পারবেন না কারণ এতে সিস্টেমে কোনও অ্যাডমিনিস্ট্রেটর থাকবে না। অনুগ্রহ করে প্রথমে অন্য একজন ব্যবহারকারীকে অ্যাডমিন করুন, অথবা সিস্টেম সাপোর্টের সাথে যোগাযোগ করুন।",
|
||||
"lastAdminWarning": "আপনিই শেষ অ্যাডমিন ব্যবহারকারী। আপনি আপনার অ্যাকাউন্ট মুছে ফেলতে পারবেন না কারণ এটি সিস্টেমকে কোনও অ্যাডমিনিস্ট্রেটর ছাড়াই ছেড়ে দেবে। অনুগ্রহ করে প্রথমে অন্য একজন ব্যবহারকারীকে অ্যাডমিন করুন, অথবা সিস্টেম সহায়তার সাথে যোগাযোগ করুন।",
|
||||
"confirmPassword": "পাসওয়ার্ড নিশ্চিত করুন",
|
||||
"deleting": "মুছে ফেলা হচ্ছে...",
|
||||
"cancel": "বাতিল করুন"
|
||||
@@ -2149,12 +2149,12 @@
|
||||
"lastAccessed": "শেষবার অ্যাক্সেস করা হয়েছে",
|
||||
"accessCount": "অ্যাক্সেসের সংখ্যা",
|
||||
"revokeAccess": "অ্যাক্সেস প্রত্যাহার করুন",
|
||||
"confirmRevokeAccess": "আপনি কি নিশ্চিত যে আপনি {{username}} এর অ্যাক্সেস প্রত্যাহার করতে চান?",
|
||||
"hostSharedSuccessfully": "হোস্টটি {{username}} এর সাথে সফলভাবে শেয়ার করা হয়েছে",
|
||||
"confirmRevokeAccess": "আপনি কি নিশ্চিত যে আপনি {{username}}এর অ্যাক্সেস প্রত্যাহার করতে চান?",
|
||||
"hostSharedSuccessfully": "হোস্ট {{username}}এর সাথে সফলভাবে শেয়ার করা হয়েছে",
|
||||
"hostAccessUpdated": "হোস্ট অ্যাক্সেস আপডেট করা হয়েছে",
|
||||
"failedToShareHost": "হোস্ট শেয়ার করতে ব্যর্থ হয়েছে",
|
||||
"accessRevokedSuccessfully": "অ্যাক্সেস সফলভাবে প্রত্যাহার করা হয়েছে",
|
||||
"failedToRevokeAccess": "অ্যাক্সেস প্রত্যাহার করা যায়নি",
|
||||
"failedToRevokeAccess": "অ্যাক্সেস প্রত্যাহার করা যায়নিfdfg",
|
||||
"shared": "ভাগ করা হয়েছে",
|
||||
"sharedHosts": "শেয়ার্ড হোস্ট",
|
||||
"sharedWithMe": "আমার সাথে শেয়ার করা হয়েছে",
|
||||
@@ -2167,8 +2167,8 @@
|
||||
"manageAccessFor": "এর জন্য অ্যাক্সেস পরিচালনা করুন",
|
||||
"totalAccessRecords": "{{count}} অ্যাক্সেস রেকর্ড(গুলি)",
|
||||
"neverAccessed": "কখনোই না",
|
||||
"timesAccessed": "{{count}} বার",
|
||||
"daysRemaining": "{{days}} দিন",
|
||||
"timesAccessed": "{{count}} সময়(গুলি)",
|
||||
"daysRemaining": "{{days}} দিন(গুলি)",
|
||||
"hoursRemaining": "{{hours}} ঘন্টা",
|
||||
"failedToFetchAccessList": "অ্যাক্সেস তালিকা আনা যায়নি",
|
||||
"currentAccess": "বর্তমান অ্যাক্সেস",
|
||||
@@ -2177,7 +2177,7 @@
|
||||
"tempUserRecommended": "উন্নত নিরাপত্তার জন্য আমরা 'অস্থায়ী ব্যবহারকারী তৈরি করুন' সক্ষম করার পরামর্শ দিচ্ছি।",
|
||||
"roleManagement": "ভূমিকা ব্যবস্থাপনা",
|
||||
"manageRoles": "ভূমিকা পরিচালনা করুন",
|
||||
"manageRolesFor": "{{username}} এর জন্য ভূমিকা পরিচালনা করুন",
|
||||
"manageRolesFor": "{{username}}এর জন্য ভূমিকা পরিচালনা করুন",
|
||||
"assignRole": "ভূমিকা বরাদ্দ করুন",
|
||||
"removeRole": "ভূমিকা সরান",
|
||||
"userRoles": "ব্যবহারকারীর ভূমিকা",
|
||||
@@ -2211,10 +2211,10 @@
|
||||
"downloadRecording": "রেকর্ডিং ডাউনলোড করুন",
|
||||
"dangerousCommand": "বিপজ্জনক কমান্ড সনাক্ত করা হয়েছে",
|
||||
"commandBlocked": "কমান্ড ব্লক করা হয়েছে",
|
||||
"terminateSession": "সেশন বন্ধ করুন",
|
||||
"sessionTerminated": "হোস্ট মালিক সেশনটি সমাপ্ত করেছেন",
|
||||
"terminateSession": "সেশন শেষ করুন",
|
||||
"sessionTerminated": "হোস্ট মালিক সেশনটি বন্ধ করে দিয়েছেন",
|
||||
"sharedAccessExpired": "এই হোস্টে আপনার শেয়ার করা অ্যাক্সেসের মেয়াদ শেষ হয়ে গেছে",
|
||||
"sharedAccessExpiresIn": "শেয়ার করা অ্যাক্সেসের মেয়াদ {{hours}} ঘন্টার মধ্যে শেষ হয়ে যাবে",
|
||||
"sharedAccessExpiresIn": "শেয়ার করা অ্যাক্সেসের মেয়াদ {{hours}} ঘন্টার মধ্যে শেষ হবে",
|
||||
"roles": {
|
||||
"label": "ভূমিকা",
|
||||
"admin": "প্রশাসক",
|
||||
@@ -2310,16 +2310,16 @@
|
||||
"errorCode": "ত্রুটি কোড: {{code}}",
|
||||
"version": "ডকার {{version}}",
|
||||
"containerStarted": "কন্টেইনার {{name}} শুরু হয়েছে",
|
||||
"failedToStartContainer": "{{name}} কন্টেইনারটি চালু করতে ব্যর্থ হয়েছে",
|
||||
"containerStopped": "{{name}} কন্টেইনার থামানো হয়েছে",
|
||||
"failedToStartContainer": "কন্টেইনার চালু করতে ব্যর্থ হয়েছে {{name}}",
|
||||
"containerStopped": "কন্টেইনার {{name}} বন্ধ করা হয়েছে",
|
||||
"failedToStopContainer": "কন্টেইনার থামাতে ব্যর্থ হয়েছে {{name}}",
|
||||
"containerRestarted": "কন্টেইনার {{name}} পুনরায় চালু হয়েছে",
|
||||
"failedToRestartContainer": "{{name}} কন্টেইনারটি পুনরায় চালু করতে ব্যর্থ হয়েছে",
|
||||
"containerPaused": "{{name}} কন্টেইনার থামানো হয়েছে",
|
||||
"containerUnpaused": "{{name}} কন্টেইনারটি আনপজ করা হয়েছে",
|
||||
"failedToTogglePauseContainer": "{{name}} কন্টেইনারের জন্য পজ স্ট্যাটাস টগল করা যায়নি",
|
||||
"containerRemoved": "{{name}} কন্টেইনার সরানো হয়েছে",
|
||||
"failedToRemoveContainer": "{{name}} কন্টেইনার সরানো যায়নি",
|
||||
"failedToRestartContainer": "কন্টেইনারটি পুনরায় চালু করতে ব্যর্থ হয়েছে {{name}}",
|
||||
"containerPaused": "কন্টেইনার {{name}} থামানো হয়েছে",
|
||||
"containerUnpaused": "কন্টেইনার {{name}} অব্যবহৃত",
|
||||
"failedToTogglePauseContainer": "কন্টেইনারের জন্য পজ স্ট্যাটাস টগল করা যায়নি {{name}}",
|
||||
"containerRemoved": "কন্টেইনার {{name}} সরানো হয়েছে",
|
||||
"failedToRemoveContainer": "কন্টেইনার সরানো যায়নি {{name}}",
|
||||
"image": "ভাবমূর্তি",
|
||||
"idLabel": "আইডি",
|
||||
"ports": "বন্দর",
|
||||
@@ -2372,7 +2372,7 @@
|
||||
"authenticationRequired": "প্রমাণীকরণ প্রয়োজন",
|
||||
"verificationCodePrompt": "যাচাইকরণ কোড লিখুন",
|
||||
"totpVerificationFailed": "TOTP যাচাইকরণ ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।",
|
||||
"connectedTo": "{{containerName}} এর সাথে সংযুক্ত",
|
||||
"connectedTo": "{{containerName}}এর সাথে সংযুক্ত",
|
||||
"disconnected": "সংযোগ বিচ্ছিন্ন",
|
||||
"consoleError": "কনসোল ত্রুটি",
|
||||
"errorMessage": "ত্রুটি: {{message}}",
|
||||
@@ -2387,7 +2387,7 @@
|
||||
"disconnect": "সংযোগ বিচ্ছিন্ন করুন",
|
||||
"notConnected": "সংযুক্ত নেই",
|
||||
"clickToConnect": "শেল সেশন শুরু করতে সংযোগে ক্লিক করুন",
|
||||
"connectingTo": "{{containerName}} এর সাথে সংযোগ করা হচ্ছে...",
|
||||
"connectingTo": "{{containerName}}এর সাথে সংযুক্ত হচ্ছে ...",
|
||||
"containerNotFound": "কন্টেইনারটি পাওয়া যায়নি",
|
||||
"backToList": "তালিকায় ফিরে যান",
|
||||
"logs": "লগ",
|
||||
@@ -2397,6 +2397,6 @@
|
||||
},
|
||||
"theme": {
|
||||
"switchToLight": "আলোতে স্যুইচ করুন",
|
||||
"switchToDark": "ডার্ক এ স্যুইচ করুন"
|
||||
"switchToDark": "ডার্ক-এ স্যুইচ করুন"
|
||||
}
|
||||
}
|
||||
}
|
||||
2402
src/locales/translated/ca.json
Normal file
2402
src/locales/translated/ca.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/cs.json
Normal file
2402
src/locales/translated/cs.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/da.json
Normal file
2402
src/locales/translated/da.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/de.json
Normal file
2402
src/locales/translated/de.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/el.json
Normal file
2402
src/locales/translated/el.json
Normal file
File diff suppressed because it is too large
Load Diff
2406
src/locales/translated/en.json
Normal file
2406
src/locales/translated/en.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/es.json
Normal file
2402
src/locales/translated/es.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/fi.json
Normal file
2402
src/locales/translated/fi.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/fr.json
Normal file
2402
src/locales/translated/fr.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@
|
||||
"noCredentials": "אין אישורים",
|
||||
"noCredentialsMessage": "עדיין לא הוספת אישורים. לחץ על \"הוסף אישור\" כדי להתחיל.",
|
||||
"sshCredentials": "אישורי SSH",
|
||||
"credentialsCount": "פרטי גישה של {{count}}",
|
||||
"credentialsCount": "אישורים {{count}}",
|
||||
"refresh": "לְרַעֲנֵן",
|
||||
"passwordRequired": "נדרשת סיסמה",
|
||||
"sshKeyRequired": "נדרש מפתח SSH",
|
||||
@@ -136,12 +136,12 @@
|
||||
"listView": "רְשִׁימָה",
|
||||
"folderView": "תיקיות",
|
||||
"unknownCredential": "לֹא יְדוּעַ",
|
||||
"confirmRemoveFromFolder": "האם אתה בטוח שברצונך להסיר את \"{{name}}\" מהתיקייה \"{{folder}}\"? פרטי הגישה יועברו לתיקייה \"לא מסווג\".",
|
||||
"confirmRemoveFromFolder": "האם אתה בטוח שברצונך להסיר את \"{{name}}\" מהתיקייה \"{{folder}}\"? פרטי הכניסה יועברו לקטגוריה \"לא מסווג\".",
|
||||
"removedFromFolder": "פרטי הכניסה \"{{name}}\" הוסרו בהצלחה מהתיקייה",
|
||||
"failedToRemoveFromFolder": "הסרת האישורים מהתיקייה נכשלה",
|
||||
"folderRenamed": "שם התיקייה \"{{oldName}}\" שונה בהצלחה ל-\"{{newName}}\"",
|
||||
"folderRenamed": "תיקיית \"{{oldName}}\" שמה שונה בהצלחה ל- \"{{newName}}\"",
|
||||
"failedToRenameFolder": "נכשל שינוי שם התיקייה",
|
||||
"movedToFolder": "פרטי הכניסה \"{{name}}\" הועברו בהצלחה ל-\"{{folder}}\"",
|
||||
"movedToFolder": "פרטי הכניסה \"{{name}}\" הועברו בהצלחה ל- \"{{folder}}\"",
|
||||
"failedToMoveToFolder": "העברת האישורים לתיקייה נכשלה",
|
||||
"sshPublicKey": "מפתח ציבורי של SSH",
|
||||
"publicKeyNote": "מפתח ציבורי הוא אופציונלי אך מומלץ לאימות מפתח",
|
||||
@@ -187,9 +187,9 @@
|
||||
"dragIndicator": {
|
||||
"error": "שגיאה: {{error}}",
|
||||
"dragging": "גרירה {{fileName}}",
|
||||
"preparing": "מכין את {{fileName}}",
|
||||
"preparing": "מכין {{fileName}}",
|
||||
"readySingle": "מוכן להורדה {{fileName}}",
|
||||
"readyMultiple": "מוכן להוריד את הקבצים של {{count}}",
|
||||
"readyMultiple": "מוכן להוריד {{count}} קבצים",
|
||||
"batchDrag": "גרור {{count}} קבצים לשולחן העבודה",
|
||||
"dragToDesktop": "גרור לשולחן העבודה",
|
||||
"canDragAnywhere": "ניתן לגרור קבצים לכל מקום בשולחן העבודה"
|
||||
@@ -202,7 +202,7 @@
|
||||
"stopKeyRecording": "עצירת הקלטת מפתח",
|
||||
"selectTerminals": "בחר טרמינלים:",
|
||||
"typeCommands": "פקודות הקלדה (כל המקשים נתמכים):",
|
||||
"commandsWillBeSent": "פקודות יישלחו ל-{{count}} טרמינל(ים) שנבחר(ים).",
|
||||
"commandsWillBeSent": "פקודות יישלחו אל {{count}} הטרמינל/ים שנבחרו.",
|
||||
"settings": "הגדרות",
|
||||
"enableRightClickCopyPaste": "הפעלת העתקה/הדבקה באמצעות לחיצה ימנית",
|
||||
"shareIdeas": "יש לכם רעיונות לגבי מה שצריך לבוא בהמשך עבור כלי SSH? שתפו אותם ב",
|
||||
@@ -224,7 +224,7 @@
|
||||
"content": "פְּקוּדָה",
|
||||
"namePlaceholder": "לדוגמה, הפעל מחדש את Nginx",
|
||||
"descriptionPlaceholder": "תיאור אופציונלי",
|
||||
"contentPlaceholder": "לדוגמה, sudo systemctl restart nginx",
|
||||
"contentPlaceholder": "לדוגמה, sudo systemctl הפעל מחדש את nginx",
|
||||
"nameRequired": "שם נדרש",
|
||||
"contentRequired": "נדרשת פקודה",
|
||||
"createDescription": "צור קטע פקודה חדש לביצוע מהיר",
|
||||
@@ -256,7 +256,7 @@
|
||||
"updateFolderFailed": "עדכון התיקייה נכשל",
|
||||
"createFolderFailed": "יצירת התיקייה נכשלה",
|
||||
"selectTerminals": "בחירת טרמינלים (אופציונלי)",
|
||||
"executeOnSelected": "בצע ב-{{count}} טרמינלים נבחרים",
|
||||
"executeOnSelected": "בצע ב- {{count}} טרמינל/ים שנבחרו",
|
||||
"executeOnCurrent": "בצע במסוף הנוכחי (לחץ כדי לבחור מספר אפשרויות)",
|
||||
"folder": "תיקייה",
|
||||
"selectFolder": "בחר תיקייה או השאר ריק",
|
||||
@@ -335,7 +335,7 @@
|
||||
"saveConfig": "שמור תצורה",
|
||||
"helpText": "הזן את כתובת ה-URL שבה פועל שרת ה-Termix שלך (לדוגמה, http://localhost:30001 או https://your-server.com)",
|
||||
"warning": "אַזהָרָה",
|
||||
"notValidatedWarning": "כתובת ה-URL לא אומתה - ודא שהיא נכונה",
|
||||
"notValidatedWarning": "כתובת האתר לא אומתה - ודא שהיא נכונה",
|
||||
"changeServer": "שנה שרת",
|
||||
"mustIncludeProtocol": "כתובת השרת חייבת להתחיל ב-http:// או https://"
|
||||
},
|
||||
@@ -345,7 +345,7 @@
|
||||
"upToDate": "האפליקציה מעודכנת",
|
||||
"currentVersion": "אתה משתמש בגרסה {{version}}",
|
||||
"updateAvailable": "עדכון זמין",
|
||||
"newVersionAvailable": "גרסה חדשה זמינה! אתה משתמש ב-{{current}}, אך {{latest}} זמין.",
|
||||
"newVersionAvailable": "גרסה חדשה זמינה! אתה מפעיל {{current}}, אבל {{latest}} זמין.",
|
||||
"releasedOn": "יצא לאור בתאריך {{date}}",
|
||||
"downloadUpdate": "הורד עדכון",
|
||||
"dismiss": "לְפַטֵר",
|
||||
@@ -387,7 +387,7 @@
|
||||
"sshPath": "נתיב SSH",
|
||||
"localPath": "נתיב מקומי",
|
||||
"appName": "טרמיקס",
|
||||
"resetSidebarWidth": "איפוס רוחב הסרגל הצדדי",
|
||||
"resetSidebarWidth": "איפוס רוחב הצד",
|
||||
"dragToResizeSidebar": "גרור כדי לשנות את גודל הצד",
|
||||
"noAuthCredentials": "אין אישורי אימות זמינים עבור מארח SSH זה",
|
||||
"noReleases": "אין פרסומים",
|
||||
@@ -456,7 +456,7 @@
|
||||
"enterNewPassword": "הזן את הסיסמה החדשה שלך עבור המשתמש:",
|
||||
"passwordsDoNotMatch": "הסיסמאות אינן תואמות",
|
||||
"passwordMinLength": "הסיסמה חייבת להיות באורך של לפחות 6 תווים",
|
||||
"passwordResetSuccess": "איפוס הסיסמה הצליח! כעת תוכל להתחבר עם הסיסמה החדשה שלך.",
|
||||
"passwordResetSuccess": "איפוס הסיסמה בוצע בהצלחה! כעת תוכל להתחבר עם הסיסמה החדשה שלך.",
|
||||
"failedToInitiatePasswordReset": "נכשלה הפעלת איפוס הסיסמה",
|
||||
"failedToVerifyResetCode": "נכשל אימות קוד האיפוס",
|
||||
"failedToCompletePasswordReset": "נכשל השלמת איפוס הסיסמה",
|
||||
@@ -509,7 +509,7 @@
|
||||
"updateSettings": "עדכון הגדרות",
|
||||
"confirmDelete": "האם אתה בטוח שאתה רוצה למחוק את המשתמש הזה?",
|
||||
"confirmMakeAdmin": "האם אתה בטוח שאתה רוצה להפוך את {{username}} למנהל?",
|
||||
"confirmRemoveAdmin": "האם אתה בטוח שברצונך להסיר את סטטוס המנהל מ-{{username}}?",
|
||||
"confirmRemoveAdmin": "האם אתה בטוח שברצונך להסיר את סטטוס המנהל מ- {{username}}?",
|
||||
"externalAuthentication": "אימות חיצוני (OIDC)",
|
||||
"configureExternalProvider": "הגדר ספק זהויות חיצוני עבור אימות OIDC/OAuth2.",
|
||||
"userIdentifierPath": "נתיב מזהה המשתמש",
|
||||
@@ -549,8 +549,8 @@
|
||||
"enterUsernameToMakeAdmin": "הזן שם משתמש כדי להפוך למנהל",
|
||||
"userIsNowAdmin": "משתמש {{username}} הוא כעת מנהל",
|
||||
"failedToMakeUserAdmin": "נכשל בהפיכת המשתמש למנהל",
|
||||
"removeAdminStatus": "להסיר את סטטוס המנהל מ-{{username}}?",
|
||||
"adminStatusRemoved": "סטטוס מנהל הוסר מ-{{username}}",
|
||||
"removeAdminStatus": "להסיר סטטוס מנהל מ- {{username}}?",
|
||||
"adminStatusRemoved": "סטטוס מנהל הוסר מ- {{username}}",
|
||||
"failedToRemoveAdminStatus": "הסרת סטטוס מנהל נכשלה",
|
||||
"userDeletedSuccessfully": "משתמש {{username}} נמחק בהצלחה",
|
||||
"failedToDeleteUser": "מחיקת המשתמש נכשלה",
|
||||
@@ -564,7 +564,7 @@
|
||||
"sessionsRevokedSuccessfully": "הפעילויות בוטלו בהצלחה",
|
||||
"linkToPasswordAccount": "קישור לחשבון סיסמה",
|
||||
"linkOIDCDialogTitle": "קישור חשבון OIDC לחשבון סיסמה",
|
||||
"linkOIDCDialogDescription": "קשר את {{username}} (משתמש OIDC) לחשבון סיסמה קיים. פעולה זו תאפשר אימות כפול עבור חשבון הסיסמה.",
|
||||
"linkOIDCDialogDescription": "קשר {{username}} (משתמש OIDC) לחשבון סיסמה קיים. פעולה זו תאפשר אימות כפול עבור חשבון הסיסמה.",
|
||||
"createUser": "צור משתמש",
|
||||
"createUserDescription": "צור משתמש מקומי חדש עם שם משתמש וסיסמה",
|
||||
"enterUsername": "הזן שם משתמש",
|
||||
@@ -577,11 +577,11 @@
|
||||
"adminStatus": "סטטוס מנהל",
|
||||
"userId": "מזהה משתמש",
|
||||
"regularUser": "משתמש רגיל",
|
||||
"adminPrivileges": "הרשאות מנהל מערכת",
|
||||
"adminPrivileges": "הרשאות מנהל",
|
||||
"administratorRole": "תפקיד מנהל",
|
||||
"administratorRoleDescription": "הענקת גישה מלאה למערכת והרשאות ניהול",
|
||||
"passwordManagement": "ניהול סיסמאות",
|
||||
"passwordResetWarning": "איפוס סיסמת משתמש ימחק את כל הנתונים שלו (מארחי SSH, אישורים, הגדרות). פעולה זו אינה ניתנת לביטול.",
|
||||
"passwordResetWarning": "איפוס סיסמת משתמש ימחק את כל הנתונים שלו (מארחי SSH, פרטי כניסה, הגדרות). פעולה זו אינה ניתנת לביטול.",
|
||||
"resetUserPassword": "איפוס סיסמת משתמש",
|
||||
"resettingPassword": "איפוס...",
|
||||
"passwordResetInitiated": "איפוס סיסמה החל עבור {{username}}. קוד איפוס נשלח.",
|
||||
@@ -611,12 +611,12 @@
|
||||
"linkTargetUsernamePlaceholder": "הזן שם משתמש של סיסמת חשבון",
|
||||
"linkAccountsButton": "קישור חשבונות",
|
||||
"linkingAccounts": "מְקַשֵׁר...",
|
||||
"accountsLinkedSuccessfully": "משתמש OIDC {{oidcUsername}} קושר ל-{{targetUsername}}",
|
||||
"accountsLinkedSuccessfully": "משתמש OIDC {{oidcUsername}} קושר ל- {{targetUsername}}",
|
||||
"failedToLinkAccounts": "קישור החשבונות נכשל",
|
||||
"linkTargetUsernameRequired": "נדרש שם משתמש של היעד",
|
||||
"unlinkOIDCTitle": "ניתוק אימות OIDC",
|
||||
"unlinkOIDCDescription": "להסיר אימות OIDC מ-{{username}}? המשתמש יוכל להתחבר רק באמצעות שם משתמש/סיסמה לאחר מכן.",
|
||||
"unlinkOIDCSuccess": "OIDC נותק מ-{{username}}",
|
||||
"unlinkOIDCTitle": "ניתוק קישור אימות OIDC",
|
||||
"unlinkOIDCDescription": "להסיר אימות OIDC מ- {{username}}? המשתמש יוכל להתחבר רק באמצעות שם משתמש/סיסמה לאחר מכן.",
|
||||
"unlinkOIDCSuccess": "OIDC נותק מ- {{username}}",
|
||||
"failedToUnlinkOIDC": "נכשל ניתוק ה-OIDC",
|
||||
"databaseSecurity": "אבטחת מסד נתונים",
|
||||
"encryptionStatus": "סטטוס הצפנה",
|
||||
@@ -628,13 +628,13 @@
|
||||
"migrationStatus": "סטטוס הגירה",
|
||||
"migrationCompleted": "ההגירה הושלמה",
|
||||
"migrationRequired": "נדרשת הגירה",
|
||||
"deviceProtectedMasterKey": "מפתח ראשי מוגן סביבה",
|
||||
"deviceProtectedMasterKey": "מפתח ראשי מוגן לסביבה",
|
||||
"legacyKeyStorage": "אחסון מפתחות מדור קודם",
|
||||
"masterKeyEncryptedWithDeviceFingerprint": "מפתח ראשי מוצפן עם טביעת אצבע סביבתית (הגנת KEK פעילה)",
|
||||
"keyNotProtectedByDeviceBinding": "המפתח אינו מוגן על ידי קשירת סביבה (מומלץ לשדרג)",
|
||||
"valid": "תָקֵף",
|
||||
"initializeDatabaseEncryption": "אתחול הצפנת מסד נתונים",
|
||||
"enableAes256EncryptionWithDeviceBinding": "הפעל הצפנת AES-256 עם הגנה על מפתחות ראשיים תלוית סביבה. פעולה זו יוצרת אבטחה ברמה ארגונית עבור מפתחות SSH, סיסמאות ואסימוני אימות.",
|
||||
"enableAes256EncryptionWithDeviceBinding": "הפעל הצפנת AES-256 עם הגנה על מפתחות ראשיים תלוית סביבה. פעולה זו יוצרת אבטחה ברמה ארגונית עבור מפתחות SSH, סיסמאות וטוקני אימות.",
|
||||
"featuresEnabled": "תכונות מופעלות:",
|
||||
"aes256GcmAuthenticatedEncryption": "הצפנה מאומתת AES-256-GCM",
|
||||
"deviceFingerprintMasterKeyProtection": "הגנה סביבתית על מפתח ראשי באמצעות טביעות אצבע (KEK)",
|
||||
@@ -695,7 +695,7 @@
|
||||
"exportForMigration": "ייצוא לצורך הגירה",
|
||||
"exportDatabaseForHardwareMigration": "ייצוא מסד נתונים כקובץ SQLite עם נתונים מפוענחים לצורך הגירה לחומרה חדשה",
|
||||
"exportDatabase": "ייצוא מסד נתונים של SQLite",
|
||||
"exporting": "מייצא...",
|
||||
"exporting": "ייצוא...",
|
||||
"exportCreated": "ייצוא SQLite נוצר",
|
||||
"exportContainsDecryptedData": "ייצוא SQLite מכיל נתונים מפוענחים - יש לשמור על אבטחה!",
|
||||
"databaseExportedSuccessfully": "מסד הנתונים SQLite יוצא בהצלחה",
|
||||
@@ -756,7 +756,7 @@
|
||||
"revokeAllUserSessionsTitle": "ביטול כל ההפעלות עבור משתמש זה",
|
||||
"revokeAll": "בטל הכל",
|
||||
"linkOidcToPasswordAccount": "קישור חשבון OIDC לחשבון סיסמה",
|
||||
"linkOidcToPasswordAccountDescription": "קשר את {{username}} (משתמש OIDC) לחשבון סיסמה קיים. פעולה זו תאפשר אימות כפול עבור חשבון הסיסמה.",
|
||||
"linkOidcToPasswordAccountDescription": "קשר {{username}} (משתמש OIDC) לחשבון סיסמה קיים. פעולה זו תאפשר אימות כפול עבור חשבון הסיסמה.",
|
||||
"linkOidcWarningTitle": "אזהרה: נתוני משתמש OIDC יימחקו",
|
||||
"linkOidcWarningDescription": "פעולה זו תביא ל:",
|
||||
"linkOidcActionDeleteUser": "מחיקת חשבון המשתמש של OIDC וכל הנתונים שלו",
|
||||
@@ -777,23 +777,23 @@
|
||||
"retry": "נסה שוב",
|
||||
"refresh": "לְרַעֲנֵן",
|
||||
"optional": "אופציונלי",
|
||||
"hostsCount": "מארחים",
|
||||
"hostsCount": "{{count}} hosts",
|
||||
"importJson": "ייבוא JSON",
|
||||
"importing": "מייבא...",
|
||||
"importJsonTitle": "ייבוא מארחי SSH מ-JSON",
|
||||
"importJsonDesc": "העלה קובץ JSON לייבוא בכמות גדולה של מארחי SSH מרובים (מקסימום 100).",
|
||||
"downloadSample": "הורד דוגמה",
|
||||
"formatGuide": "מדריך פורמט",
|
||||
"exportCredentialWarning": "אזהרה: המארח \"{{count}}\" משתמש באימות אישורים. הקובץ המיוצא לא יכלול את נתוני האישורים ויהיה צורך להגדיר אותו מחדש באופן ידני לאחר הייבוא. האם ברצונך להמשיך?",
|
||||
"exportCredentialWarning": "אזהרה: המארח \"{{name}}\" משתמש באימות אישורים. הקובץ המיוצא לא יכלול את נתוני האישורים ויהיה צורך להגדיר אותו מחדש באופן ידני לאחר הייבוא. האם ברצונך להמשיך?",
|
||||
"exportSensitiveDataWarning": "אזהרה: המארח \"{{name}}\" מכיל נתוני אימות רגישים (סיסמה/מפתח SSH). הקובץ המיוצא יכלול נתונים אלה בטקסט רגיל. אנא שמור את הקובץ מאובטח ומחק אותו לאחר השימוש. האם ברצונך להמשיך?",
|
||||
"uncategorized": "ללא קטגוריה",
|
||||
"confirmDelete": "האם אתה בטוח שברצונך למחוק את \"{{name}}\"?",
|
||||
"confirmDelete": "האם אתה בטוח שאתה רוצה למחוק את \"{{name}}\"?",
|
||||
"failedToDeleteHost": "מחיקת המארח נכשלה",
|
||||
"failedToExportHost": "ייצוא המארח נכשל. אנא ודא שאתה מחובר ויש לך גישה לנתוני המארח.",
|
||||
"jsonMustContainHosts": "JSON חייב להכיל מערך של \"hosts\" או להיות מערך של hosts",
|
||||
"jsonMustContainHosts": "JSON חייב להכיל מערך \"hosts\" או להיות מערך של hosts",
|
||||
"noHostsInJson": "לא נמצאו מארחים בקובץ JSON",
|
||||
"maxHostsAllowed": "מקסימום 100 מארחים מותרים לכל ייבוא",
|
||||
"importCompleted": "ייבוא הושלם: {{name}} הצליח, {{success}} נכשל",
|
||||
"importCompleted": "ייבוא הושלם: {{success}} הצליח, {{failed}} נכשל",
|
||||
"importFailed": "הייבוא נכשל",
|
||||
"importError": "שגיאת ייבוא",
|
||||
"failedToImportJson": "ייבוא קובץ JSON נכשל",
|
||||
@@ -816,7 +816,7 @@
|
||||
"editHost": "עריכת מארח",
|
||||
"cloneHost": "מארח משוכפל",
|
||||
"updateHost": "עדכון מארח",
|
||||
"hostUpdatedSuccessfully": "המארח \"{{failed}}\" עודכן בהצלחה!",
|
||||
"hostUpdatedSuccessfully": "המארח \"{{name}}\" עודכן בהצלחה!",
|
||||
"hostAddedSuccessfully": "המארח \"{{name}}\" נוסף בהצלחה!",
|
||||
"hostDeletedSuccessfully": "המארח \"{{name}}\" נמחק בהצלחה!",
|
||||
"failedToSaveHost": "שמירת המארח נכשלה. אנא נסה שוב.",
|
||||
@@ -837,10 +837,10 @@
|
||||
"connection": "קֶשֶׁר",
|
||||
"remove": "לְהַסִיר",
|
||||
"sourcePort": "יציאת מקור",
|
||||
"sourcePortDesc": "(המקור מתייחס לפרטי החיבור הנוכחיים בלשונית כללי)",
|
||||
"sourcePortDesc": " (המקור מתייחס לפרטי החיבור הנוכחיים בלשונית כללי)",
|
||||
"endpointPort": "יציאת נקודת קצה",
|
||||
"endpointSshConfig": "תצורת SSH של נקודת קצה",
|
||||
"tunnelForwardDescription": "מנהרה זו תעביר תעבורה מפורט {{name}} במחשב המקור (פרטי החיבור הנוכחיים בכרטיסייה הכללית) לפורט {{sourcePort}} במחשב נקודת הקצה.",
|
||||
"tunnelForwardDescription": "מנהרה זו תעביר תעבורה מפורט {{sourcePort}} במחשב המקור (פרטי החיבור הנוכחיים בכרטיסייה הכללית) לפורט {{endpointPort}} במחשב נקודת הקצה.",
|
||||
"maxRetries": "מקסימום ניסיונות חוזרים",
|
||||
"maxRetriesDescription": "מספר מרבי של ניסיונות חוזרים עבור חיבור מנהרה.",
|
||||
"retryInterval": "מרווח זמן לניסיון חוזר (שניות)",
|
||||
@@ -871,7 +871,7 @@
|
||||
"selectCredential": "בחר אישור",
|
||||
"selectCredentialPlaceholder": "בחר אישור...",
|
||||
"credentialRequired": "נדרשת אישור בעת שימוש באימות אישורים",
|
||||
"credentialDescription": "בחירת פרטי כניסה תגרום להחלפת שם המשתמש הנוכחי ותשתמש בפרטי האימות של פרטי הכניסה.",
|
||||
"credentialDescription": "בחירת שם אישור תדרוס את שם המשתמש הנוכחי ותשתמש בפרטי האימות של שם האישור.",
|
||||
"cannotChangeAuthAsSharedUser": "לא ניתן לשנות אימות כמשתמש משותף",
|
||||
"sshPrivateKey": "מפתח פרטי SSH",
|
||||
"keyPassword": "סיסמת מפתח",
|
||||
@@ -916,10 +916,10 @@
|
||||
"customCommandsDesc": "הגדר פקודות כיבוי והפעלה מחדש מותאמות אישית עבור שרת זה",
|
||||
"shutdownCommand": "פקודת כיבוי",
|
||||
"rebootCommand": "פקודת אתחול מחדש",
|
||||
"confirmRemoveFromFolder": "האם אתה בטוח שברצונך להסיר את \"{{endpointPort}}\" מהתיקייה \"{{name}}\"? המארח יועבר ל-\"אין תיקייה\".",
|
||||
"removedFromFolder": "המארח \"{{folder}}\" הוסר בהצלחה מהתיקייה",
|
||||
"confirmRemoveFromFolder": "האם אתה בטוח שברצונך להסיר את \"{{name}}\" מהתיקייה \"{{folder}}\"? המארח יועבר ל\"אין תיקייה\".",
|
||||
"removedFromFolder": "המארח \"{{name}}\" הוסר בהצלחה מהתיקייה",
|
||||
"failedToRemoveFromFolder": "נכשלה הסרת המארח מהתיקייה",
|
||||
"folderRenamed": "שם התיקייה \"{{name}}\" שונה בהצלחה ל-\"{{oldName}}\"",
|
||||
"folderRenamed": "תיקיית \"{{oldName}}\" שמה שונה בהצלחה ל- \"{{newName}}\"",
|
||||
"failedToRenameFolder": "נכשל שינוי שם התיקייה",
|
||||
"editFolderAppearance": "עריכת מראה התיקייה",
|
||||
"editFolderAppearanceDesc": "התאם אישית את הצבע והסמל עבור התיקייה",
|
||||
@@ -929,10 +929,10 @@
|
||||
"folderAppearanceUpdated": "מראה התיקייה עודכן בהצלחה",
|
||||
"failedToUpdateFolderAppearance": "נכשל עדכון מראה התיקייה",
|
||||
"deleteAllHostsInFolder": "מחק את כל המארחים בתיקייה",
|
||||
"confirmDeleteAllHostsInFolder": "האם אתה בטוח שברצונך למחוק את כל המארחים {{newName}} בתיקייה \"{{count}}\"? לא ניתן לבטל פעולה זו.",
|
||||
"allHostsInFolderDeleted": "מחיקת {{folder}} מארחים מהתיקייה \"{{count}}\" הצליחה",
|
||||
"confirmDeleteAllHostsInFolder": "האם אתה בטוח שברצונך למחוק את כל המארחים {{count}} בתיקייה \"{{folder}}\"? לא ניתן לבטל פעולה זו.",
|
||||
"allHostsInFolderDeleted": "מחיקת {{count}} hosts מהתיקייה \"{{folder}}\" הצליחה",
|
||||
"failedToDeleteHostsInFolder": "נכשלה מחיקת המארחים בתיקייה",
|
||||
"movedToFolder": "המארח \"{{folder}}\" הועבר ל-\"{{name}}\" בהצלחה",
|
||||
"movedToFolder": "המארח \"{{name}}\" הועבר ל- \"{{folder}}\" בהצלחה",
|
||||
"failedToMoveToFolder": "נכשלה העברת המארח לתיקייה",
|
||||
"clickToRenameFolder": "לחץ כדי לשנות את שם התיקייה",
|
||||
"renameFolder": "שינוי שם התיקייה",
|
||||
@@ -943,7 +943,7 @@
|
||||
"cloneHostTooltip": "מארח משוכפל",
|
||||
"clickToEditHost": "לחץ כדי לערוך את המארח",
|
||||
"dragToMoveBetweenFolders": "גרור כדי לעבור בין תיקיות",
|
||||
"exportedHostConfig": "ייצוא תצורת מארח עבור {{folder}}",
|
||||
"exportedHostConfig": "ייצוא תצורת מארח עבור {{name}}",
|
||||
"openTerminal": "פתח את הטרמינל",
|
||||
"openFileManager": "פתח את מנהל הקבצים",
|
||||
"openTunnels": "מנהרות פתוחות",
|
||||
@@ -982,10 +982,10 @@
|
||||
"selectFont": "בחירת גופן",
|
||||
"selectFontDesc": "בחר את הגופן לשימוש בטרמינל",
|
||||
"fontSize": "גודל גופן",
|
||||
"fontSizeValue": "גודל גופן: {{name}} פיקסלים",
|
||||
"fontSizeValue": "גודל גופן: {{value}}פיקסלים",
|
||||
"adjustFontSize": "התאם את גודל הגופן של הטרמינל",
|
||||
"letterSpacing": "ריווח אותיות",
|
||||
"letterSpacingValue": "ריווח בין אותיות: {{value}}px",
|
||||
"letterSpacingValue": "ריווח בין אותיות: {{value}}פיקסלים",
|
||||
"adjustLetterSpacing": "התאמת מרווח בין תווים",
|
||||
"lineHeight": "גובה הקו",
|
||||
"lineHeightValue": "גובה שורה: {{value}}",
|
||||
@@ -1001,13 +1001,13 @@
|
||||
"scrollbackBuffer": "מאגר גלילה לאחור",
|
||||
"scrollbackBufferValue": "מאגר גלילה לאחור: {{value}} שורות",
|
||||
"scrollbackBufferDesc": "מספר השורות לשמירה בהיסטוריית הגלילה לאחור",
|
||||
"bellStyle": "סגנון בל",
|
||||
"bellStyle": "סגנון פעמון",
|
||||
"selectBellStyle": "בחר סגנון פעמון",
|
||||
"bellStyleNone": "אַף לֹא אֶחָד",
|
||||
"bellStyleSound": "קוֹל",
|
||||
"bellStyleVisual": "חָזוּתִי",
|
||||
"bellStyleBoth": "שְׁנֵיהֶם",
|
||||
"bellStyleDesc": "כיצד לטפל בפעמון הטרמינל (תו BEL, \\x07). תוכניות מפעילות זאת בעת השלמת משימות, נתקלות בשגיאות או לקבלת התראות. \"Sound\" משמיע צפצוף קולי, \"Visual\" מהבהב את המסך לזמן קצר, \"Both\" עושה את שניהם, \"None\" מבטל התראות פעמון.",
|
||||
"bellStyleDesc": "כיצד לטפל בפעמון הטרמינל (תו BEL, \\x07). תוכניות מפעילות זאת בעת השלמת משימות, נתקלות בשגיאות או לקבלת התראות. \"צליל\" משמיע צפצוף קולי, \"חזותי\" מהבהב את המסך לזמן קצר, \"שניהם\" עושה את שניהם, \"ללא\" מבטל התראות פעמון.",
|
||||
"rightClickSelectsWord": "לחיצה ימנית בוחרת מילה",
|
||||
"rightClickSelectsWordDesc": "לחיצה ימנית בוחרת את המילה שמתחת לסמן",
|
||||
"fastScrollModifier": "שינוי גלילה מהירה",
|
||||
@@ -1056,8 +1056,8 @@
|
||||
"socks5Port": "יציאת פרוקסי",
|
||||
"socks5Username": "שם משתמש פרוקסי",
|
||||
"socks5Password": "סיסמת פרוקסי",
|
||||
"socks5UsernameOptional": "אופציונלי: השאר ריק אם הפרוקסי אינו דורש אימות",
|
||||
"socks5PasswordOptional": "אופציונלי: השאר ריק אם הפרוקסי אינו דורש אימות",
|
||||
"socks5UsernameOptional": "אופציונלי: השאר ריק אם פרוקסי אינו דורש אימות",
|
||||
"socks5PasswordOptional": "אופציונלי: השאר ריק אם פרוקסי אינו דורש אימות",
|
||||
"socks5ProxyChain": "שרשרת פרוקסי",
|
||||
"socks5ProxyChainDescription": "הגדר שרשרת של פרוקסי SOCKS. כל פרוקסי בשרשרת יתחבר דרך הקודם.",
|
||||
"socks5ProxyMode": "מצב פרוקסי",
|
||||
@@ -1066,7 +1066,7 @@
|
||||
"socks5UsePreset": "השתמש בהגדרות קבועות מראש ששמרתי",
|
||||
"socks5SelectPreset": "בחר הגדרה קבועה מראש",
|
||||
"socks5ManagePresets": "ניהול הגדרות קבועות מראש",
|
||||
"socks5ProxyNode": "פרוקסי {{value}}",
|
||||
"socks5ProxyNode": "פרוקסי {{number}}",
|
||||
"socks5AddProxy": "הוסף פרוקסי לשרשרת",
|
||||
"socks5RemoveProxy": "הסר פרוקסי",
|
||||
"socks5ProxyType": "סוג פרוקסי",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "נוצרה הגדרת תצורה מוגדרת מראש של שרשרת פרוקסי",
|
||||
"socks5PresetUpdated": "הגדרת שרשרת פרוקסי עודכנה",
|
||||
"socks5PresetDeleted": "הגדרת שרשרת פרוקסי נמחקה",
|
||||
"socks5PresetSaved": "ההגדרה הקבועה מראש \"{{number}}\" נשמרה בהצלחה",
|
||||
"socks5PresetSaved": "ההגדרה הקבועה מראש \"{{name}}\" נשמרה בהצלחה",
|
||||
"socks5PresetSaveError": "נכשלה שמירת ההגדרה הקבועה מראש",
|
||||
"socks5PresetNameRequired": "נדרש שם מוגדר מראש",
|
||||
"socks5EmptyChainError": "לא ניתן לשמור שרשרת פרוקסי ריקה",
|
||||
@@ -1105,7 +1105,7 @@
|
||||
"socks5": "גרביים5",
|
||||
"executeSnippetOnConnect": "בצע קטע קוד כאשר הטרמינל מתחבר",
|
||||
"autoMosh": "אוטו-MOSH",
|
||||
"autoMoshDesc": "הפעלת פקודת MOSH באופן אוטומטי בעת התחברות",
|
||||
"autoMoshDesc": "הפעלת פקודת MOSH באופן אוטומטי בעת חיבור",
|
||||
"moshCommand": "פיקוד MOSH",
|
||||
"moshCommandDesc": "פקודת MOSH לביצוע",
|
||||
"environmentVariables": "משתני סביבה",
|
||||
@@ -1118,8 +1118,8 @@
|
||||
"notEnabled": "Docker אינו מופעל עבור מארח זה. הפעל אותו בהגדרות המארח כדי להשתמש בתכונות Docker.",
|
||||
"validating": "מאמת את Docker...",
|
||||
"error": "שְׁגִיאָה",
|
||||
"errorCode": "קוד שגיאה: {{name}}",
|
||||
"version": "דוקר גרסה {{code}}",
|
||||
"errorCode": "קוד שגיאה: {{code}}",
|
||||
"version": "דוקר נגד{{version}}",
|
||||
"current": "נוֹכְחִי",
|
||||
"used_limit": "בשימוש / מגבלה",
|
||||
"percentage": "אֲחוּזִים",
|
||||
@@ -1133,10 +1133,10 @@
|
||||
"console": "לְנַחֵם",
|
||||
"containerMustBeRunning": "המכולה חייבת לפעול כדי להתחבר לקונסולה",
|
||||
"authenticationRequired": "נדרש אימות",
|
||||
"connectedTo": "מחובר ל-{{version}}",
|
||||
"connectedTo": "מחובר אל {{containerName}}",
|
||||
"disconnected": "מְנוּתָק",
|
||||
"consoleError": "שגיאת קונסולה",
|
||||
"errorMessage": "שגיאה: {{containerName}}",
|
||||
"errorMessage": "שגיאה: {{message}}",
|
||||
"failedToConnect": "נכשלה ההתחברות לקונסולה",
|
||||
"disconnectedFromContainer": "ניתוק מקונסולת המכולה.",
|
||||
"containerNotRunning": "המכולה לא פועלת",
|
||||
@@ -1150,28 +1150,28 @@
|
||||
"disconnect": "לְנַתֵק",
|
||||
"notConnected": "לא מחובר",
|
||||
"clickToConnect": "לחץ על התחבר כדי להפעיל מעטפת אינטראקטיבית",
|
||||
"connectingTo": "מתחבר אל {{message}}...",
|
||||
"connectingTo": "מתחבר אל {{containerName}}...",
|
||||
"containerMustBeRunningToViewStats": "יש להפעיל את המיכל כדי להציג נתונים סטטיסטיים",
|
||||
"failedToFetchStats": "נכשלה שליפת הנתונים הסטטיסטיים",
|
||||
"noContainersFound": "לא נמצאו מכולות",
|
||||
"noContainersFoundHint": "התחל על ידי יצירת קונטיינרים בשרת שלך",
|
||||
"searchPlaceholder": "חיפוש לפי שם, תמונה או תעודת זהות...",
|
||||
"filterByStatusPlaceholder": "סנן לפי סטטוס",
|
||||
"allContainersCount": "הכל ({{containerName}})",
|
||||
"statusCount": "{{count}} ({{status}})",
|
||||
"allContainersCount": "הכל ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "אין מכולות התואמות את המסננים שלך",
|
||||
"noContainersMatchFiltersHint": "נסה להתאים את החיפוש או הסינון שלך",
|
||||
"containerStarted": "מיכל {{count}} הופעל",
|
||||
"failedToStartContainer": "נכשל בהפעלת המכולה: {{name}}",
|
||||
"containerStopped": "מיכל {{error}} נעצר",
|
||||
"failedToStopContainer": "עצירת המכולה נכשלה: {{name}}",
|
||||
"containerRestarted": "מיכל {{error}} הופעל מחדש",
|
||||
"failedToRestartContainer": "נכשלה ההפעלה מחדש של המכולה: {{name}}",
|
||||
"containerUnpaused": "מיכל {{error}} בוטל",
|
||||
"containerStarted": "מיכל {{name}} הופעל",
|
||||
"failedToStartContainer": "נכשל בהפעלת המכולה: {{error}}",
|
||||
"containerStopped": "מיכל {{name}} נעצר",
|
||||
"failedToStopContainer": "נכשלה עצירת המכולה: {{error}}",
|
||||
"containerRestarted": "מיכל {{name}} הופעל מחדש",
|
||||
"failedToRestartContainer": "נכשלה ההפעלה מחדש של המכולה: {{error}}",
|
||||
"containerUnpaused": "השהיית המיכל {{name}} בוטלה",
|
||||
"containerPaused": "מיכל {{name}} הושהה",
|
||||
"failedToTogglePauseContainer": "נכשל בביצוע {{name}} של המכולה: {{action}}",
|
||||
"containerRemoved": "מיכל {{error}} הוסר",
|
||||
"failedToRemoveContainer": "הסרת המיכל נכשלה: {{name}}",
|
||||
"failedToTogglePauseContainer": "נכשל ביצירת {{action}} של המכולה: {{error}}",
|
||||
"containerRemoved": "המיכל {{name}} הוסר",
|
||||
"failedToRemoveContainer": "נכשלה הסרת המיכל: {{error}}",
|
||||
"image": "תְמוּנָה:",
|
||||
"idLabel": "תְעוּדַת זֶהוּת:",
|
||||
"ports": "יציאות:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "הַפסָקָה",
|
||||
"restart": "הפעלה מחדש",
|
||||
"removeContainer": "הסר את המיכל",
|
||||
"confirmRemoveContainer": "האם אתה בטוח שברצונך להסיר את המיכל \"{{error}}\"?",
|
||||
"confirmRemoveContainer": "האם אתה בטוח שברצונך להסיר את המכולה \"{{name}}\"?",
|
||||
"runningContainerWarning": "אזהרה: מיכל זה פועל כעת ויוסר בכוח.",
|
||||
"removing": "הסרה:",
|
||||
"containerNotFound": "המיכל לא נמצא",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"logs": "יומני רישום",
|
||||
"stats": "סטטיסטיקות",
|
||||
"consoleTab": "לְנַחֵם",
|
||||
"failedToFetchLogs": "נכשלה אחזור היומנים: {{name}}",
|
||||
"failedToFetchLogs": "נכשלה אחזור הלוגים: {{error}}",
|
||||
"failedToDownloadLogs": "הורדת יומני רישום נכשלה: {{error}}",
|
||||
"linesToShow": "קווים להצגה",
|
||||
"last50Lines": "50 השורות האחרונות",
|
||||
@@ -1219,7 +1219,7 @@
|
||||
"reconnect": "התחבר מחדש",
|
||||
"sessionEnded": "הסשן הסתיים",
|
||||
"connectionLost": "החיבור אבד",
|
||||
"error": "שגיאה: {{error}}",
|
||||
"error": "שגיאה: {{message}}",
|
||||
"disconnected": "מְנוּתָק",
|
||||
"connectionClosed": "החיבור נסגר",
|
||||
"connectionError": "שגיאת חיבור: {{message}}",
|
||||
@@ -1230,13 +1230,13 @@
|
||||
"messageParseError": "נכשל בניתוח הודעת השרת",
|
||||
"websocketError": "שגיאת חיבור WebSocket",
|
||||
"connecting": "מְקַשֵׁר...",
|
||||
"reconnecting": "מתחבר מחדש... ({{message}}/{{attempt}})",
|
||||
"reconnecting": "מתחבר מחדש... ({{attempt}}/{{max}})",
|
||||
"reconnected": "התחבר מחדש בהצלחה",
|
||||
"maxReconnectAttemptsReached": "הגעת למספר המקסימלי של ניסיונות חיבור מחדש",
|
||||
"connectionTimeout": "זמן קצוב לחיבור",
|
||||
"terminalTitle": "טרמינל - {{max}}",
|
||||
"terminalWithPath": "טרמינל - {{host}}:{{host}}",
|
||||
"runTitle": "ריצה {{path}} - {{command}}",
|
||||
"terminalTitle": "טרמינל - {{host}}",
|
||||
"terminalWithPath": "טרמינל - {{host}}:{{path}}",
|
||||
"runTitle": "ריצה {{command}} - {{host}}",
|
||||
"totpRequired": "נדרש אימות דו-שלבי",
|
||||
"totpCodeLabel": "קוד אימות",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1254,26 +1254,26 @@
|
||||
"uploadFile": "העלאת קובץ",
|
||||
"downloadFile": "הורדה",
|
||||
"extractArchive": "ארכיון תמצית",
|
||||
"extractingArchive": "מחלץ את {{host}}...",
|
||||
"extractingArchive": "מחלץ {{name}}...",
|
||||
"archiveExtractedSuccessfully": "{{name}} חולץ בהצלחה",
|
||||
"extractFailed": "החילוץ נכשל",
|
||||
"compressFile": "דחיסת קובץ",
|
||||
"compressFiles": "דחיסת קבצים",
|
||||
"compressFilesDesc": "דחיסת {{name}} פריטים לתוך ארכיון",
|
||||
"compressFilesDesc": "דחיסת {{count}} פריטים לתוך ארכיון",
|
||||
"archiveName": "שם הארכיון",
|
||||
"enterArchiveName": "הזן שם ארכיון...",
|
||||
"compressionFormat": "פורמט דחיסה",
|
||||
"selectedFiles": "קבצים נבחרים",
|
||||
"andMoreFiles": "ועוד {{count}}...",
|
||||
"andMoreFiles": "ועוד {{count}} ...",
|
||||
"compress": "לִדחוֹס",
|
||||
"compressingFiles": "דחיסת {{count}} פריטים לתוך {{count}}...",
|
||||
"compressingFiles": "דחיסת {{count}} פריטים לתוך {{name}}...",
|
||||
"filesCompressedSuccessfully": "{{name}} נוצר בהצלחה",
|
||||
"compressFailed": "הדחיסה נכשלה",
|
||||
"edit": "לַעֲרוֹך",
|
||||
"preview": "תצוגה מקדימה",
|
||||
"previous": "קוֹדֵם",
|
||||
"next": "הַבָּא",
|
||||
"pageXOfY": "עמוד {{name}} מתוך {{current}}",
|
||||
"pageXOfY": "עמוד {{current}} מתוך {{total}}",
|
||||
"zoomOut": "התקרבות",
|
||||
"zoomIn": "לְהִתְמַקֵד",
|
||||
"newFile": "קובץ חדש",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "בחר קובץ",
|
||||
"uploading": "מעלה...",
|
||||
"downloading": "מוריד...",
|
||||
"uploadingFile": "מעלה את {{total}}...",
|
||||
"uploadingLargeFile": "מעלה קובץ גדול {{name}} ({{name}})...",
|
||||
"downloadingFile": "מוריד את {{size}}...",
|
||||
"creatingFile": "יוצר את {{name}}...",
|
||||
"creatingFolder": "יוצר את {{name}}...",
|
||||
"deletingItem": "מוחק את {{name}} {{type}}...",
|
||||
"renamingItem": "שינוי שם {{name}} {{type}} ל- {{oldName}}...",
|
||||
"uploadingFile": "מעלה {{name}}...",
|
||||
"uploadingLargeFile": "מעלה קובץ גדול {{name}} ({{size}})...",
|
||||
"downloadingFile": "מוריד {{name}}...",
|
||||
"creatingFile": "יוצר {{name}}...",
|
||||
"creatingFolder": "יוצר {{name}}...",
|
||||
"deletingItem": "מוחק {{type}} {{name}}...",
|
||||
"renamingItem": "שינוי השם של {{type}} {{oldName}} ל- {{newName}}...",
|
||||
"createNewFile": "צור קובץ חדש",
|
||||
"fileName": "שם הקובץ",
|
||||
"creating": "יוצר...",
|
||||
@@ -1311,7 +1311,7 @@
|
||||
"newName": "שם חדש",
|
||||
"thisIsDirectoryRename": "זוהי ספרייה",
|
||||
"renaming": "שינוי שם...",
|
||||
"fileUploadedSuccessfully": "הקובץ \"{{newName}}\" הועלה בהצלחה",
|
||||
"fileUploadedSuccessfully": "הקובץ \"{{name}}\" הועלה בהצלחה",
|
||||
"failedToUploadFile": "העלאת הקובץ נכשלה",
|
||||
"fileDownloadedSuccessfully": "הקובץ \"{{name}}\" הורד בהצלחה",
|
||||
"failedToDownloadFile": "הורדת הקובץ נכשלה",
|
||||
@@ -1319,18 +1319,18 @@
|
||||
"filePath": "נתיב הקובץ",
|
||||
"fileCreatedSuccessfully": "הקובץ \"{{name}}\" נוצר בהצלחה",
|
||||
"failedToCreateFile": "יצירת הקובץ נכשלה",
|
||||
"folderCreatedSuccessfully": "התיקייה \"{{name}}\" נוצרה בהצלחה",
|
||||
"folderCreatedSuccessfully": "תיקייה \"{{name}}\" נוצרה בהצלחה",
|
||||
"failedToCreateFolder": "יצירת התיקייה נכשלה",
|
||||
"failedToCreateItem": "יצירת הפריט נכשלה",
|
||||
"operationFailed": "פעולת {{name}} נכשלה עבור {{operation}}: {{name}}",
|
||||
"failedToResolveSymlink": "נכשל בפענוח הסימבילינק",
|
||||
"itemDeletedSuccessfully": "{{error}} נמחק בהצלחה",
|
||||
"itemsDeletedSuccessfully": "{{type}} פריטים נמחקו בהצלחה",
|
||||
"operationFailed": "הפעולה {{operation}} נכשלה עבור {{name}}: {{error}}",
|
||||
"failedToResolveSymlink": "נכשל בפענוח הקישור הסימלי",
|
||||
"itemDeletedSuccessfully": "{{type}} נמחק בהצלחה",
|
||||
"itemsDeletedSuccessfully": "{{count}} פריטים נמחקו בהצלחה",
|
||||
"failedToDeleteItems": "מחיקת הפריטים נכשלה",
|
||||
"dragFilesToUpload": "שחררו קבצים כאן כדי להעלות",
|
||||
"emptyFolder": "תיקייה זו ריקה",
|
||||
"itemCount": "פריטים",
|
||||
"selectedCount": "נבחרו",
|
||||
"itemCount": "פריטים {{count}}",
|
||||
"selectedCount": "{{count}} נבחר",
|
||||
"searchFiles": "חיפוש קבצים...",
|
||||
"upload": "העלאה",
|
||||
"selectHostToStart": "בחר מארח כדי להתחיל בניהול קבצים",
|
||||
@@ -1347,25 +1347,25 @@
|
||||
"delete": "לִמְחוֹק",
|
||||
"properties": "נכסים",
|
||||
"refresh": "לְרַעֲנֵן",
|
||||
"downloadFiles": "הורד קבצים לדפדפן",
|
||||
"downloadFiles": "הורד {{count}} קבצים לדפדפן",
|
||||
"copyFiles": "העתקת {{count}} פריטים",
|
||||
"cutFiles": "גזור {{count}} פריטים",
|
||||
"deleteFiles": "מחיקת {{count}} פריטים",
|
||||
"filesCopiedToClipboard": "פריטים הועתקו ללוח",
|
||||
"filesCopiedToClipboard": "{{count}} פריטים הועתקו ללוח",
|
||||
"filesCutToClipboard": "{{count}} פריטים נחתכו ללוח",
|
||||
"pathCopiedToClipboard": "הנתיב הועתק ללוח",
|
||||
"pathsCopiedToClipboard": "{{count}} נתיבים הועתקו ללוח",
|
||||
"pathsCopiedToClipboard": "נתיבים {{count}} הועתקו ללוח",
|
||||
"failedToCopyPath": "נכשלה העתקת הנתיב ללוח",
|
||||
"movedItems": "הועברו {{count}} פריטים",
|
||||
"movedItems": "הועבר {{count}} פריטים",
|
||||
"failedToDeleteItem": "מחיקת הפריט נכשלה",
|
||||
"itemRenamedSuccessfully": "שם השינוי של {{count}} הצליח",
|
||||
"itemRenamedSuccessfully": "שם השינוי של {{type}} הצליח",
|
||||
"failedToRenameItem": "שינוי שם הפריט נכשל",
|
||||
"download": "הורדה",
|
||||
"permissions": "הרשאות",
|
||||
"size": "גוֹדֶל",
|
||||
"modified": "שונה",
|
||||
"path": "נָתִיב",
|
||||
"confirmDelete": "האם אתה בטוח שאתה רוצה למחוק את {{count}}?",
|
||||
"confirmDelete": "האם אתה בטוח שאתה רוצה למחוק {{name}}?",
|
||||
"uploadSuccess": "הקובץ הועלה בהצלחה",
|
||||
"uploadFailed": "העלאת הקובץ נכשלה",
|
||||
"downloadSuccess": "הקובץ הורד בהצלחה",
|
||||
@@ -1388,10 +1388,10 @@
|
||||
"connectToServer": "התחברות לשרת",
|
||||
"selectServerToEdit": "בחר שרת מסרגל הצד כדי להתחיל לערוך קבצים",
|
||||
"fileOperations": "פעולות קבצים",
|
||||
"confirmDeleteMessage": "האם אתה בטוח שאתה רוצה למחוק את {{count}}?",
|
||||
"confirmDeleteSingleItem": "האם אתה בטוח שברצונך למחוק לצמיתות את \"{{count}}\"?",
|
||||
"confirmDeleteMessage": "האם אתה בטוח שאתה רוצה למחוק {{name}}?",
|
||||
"confirmDeleteSingleItem": "האם אתה בטוח שברצונך למחוק לצמיתות את \"{{name}}\"?",
|
||||
"confirmDeleteMultipleItems": "האם אתה בטוח שברצונך למחוק לצמיתות {{count}} פריטים?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "האם אתה בטוח שברצונך למחוק לצמיתות את הפריטים {{type}}? זה כולל תיקיות ותוכן שלהן.",
|
||||
"confirmDeleteMultipleItemsWithFolders": "האם אתה בטוח שברצונך למחוק לצמיתות את הפריטים {{count}} ? זה כולל תיקיות ותוכן שלהן.",
|
||||
"confirmDeleteFolder": "האם אתה בטוח שברצונך למחוק לצמיתות את התיקייה \"{{name}}\" ואת כל תוכנה?",
|
||||
"deleteDirectoryWarning": "פעולה זו תמחק את התיקייה וכל תוכנה.",
|
||||
"actionCannotBeUndone": "לא ניתן לבטל פעולה זו.",
|
||||
@@ -1421,18 +1421,18 @@
|
||||
"selectLocationToSave": "בחר מיקום לשמירה",
|
||||
"openTerminalInFolder": "פתח את הטרמינל בתיקייה זו",
|
||||
"openTerminalInFileLocation": "פתיחת מסוף במיקום הקובץ",
|
||||
"terminalWithPath": "טרמינל - {{name}}:{{name}}",
|
||||
"runningFile": "ריצה - {{count}}",
|
||||
"terminalWithPath": "טרמינל - {{host}}:{{path}}",
|
||||
"runningFile": "ריצה - {{file}}",
|
||||
"onlyRunExecutableFiles": "יכול להריץ רק קבצי הפעלה",
|
||||
"noHostSelected": "לא נבחר מארח",
|
||||
"starred": "מסומן בכוכב",
|
||||
"shortcuts": "קיצורי דרך",
|
||||
"directories": "מדריכים",
|
||||
"removedFromRecentFiles": "הוסר \"{{count}}\" מהקבצים האחרונים",
|
||||
"removedFromRecentFiles": "הוסר \"{{name}}\" מהקבצים האחרונים",
|
||||
"removeFailed": "ההסרה נכשלה",
|
||||
"unpinnedSuccessfully": "ביטול ההצמדה של \"{{name}}\" בוטל בהצלחה",
|
||||
"unpinFailed": "ביטול ההצמדה נכשל",
|
||||
"removedShortcut": "קיצור הדרך \"{{host}}\" הוסר",
|
||||
"removedShortcut": "קיצור הדרך \"{{name}}\" הוסר",
|
||||
"removeShortcutFailed": "הסרת קיצור הדרך נכשלה",
|
||||
"clearedAllRecentFiles": "ניקה את כל הקבצים האחרונים",
|
||||
"clearFailed": "ניקוי נכשל",
|
||||
@@ -1440,16 +1440,16 @@
|
||||
"clearAllRecentFiles": "נקה את כל הקבצים האחרונים",
|
||||
"unpinFile": "ביטול הצמדת קובץ",
|
||||
"removeShortcut": "הסר קיצור דרך",
|
||||
"saveFilesToSystem": "שמור {{path}} קבצים כ...",
|
||||
"saveFilesToSystem": "שמור {{count}} קבצים בתור...",
|
||||
"pinFile": "קובץ הצמדה",
|
||||
"addToShortcuts": "הוסף לקיצורי דרך",
|
||||
"downloadToDefaultLocation": "הורדה למיקום ברירת המחדל",
|
||||
"pasteFailed": "ההדבקה נכשלה",
|
||||
"noUndoableActions": "אין פעולות שניתן לבטל",
|
||||
"undoCopySuccess": "פעולת העתקה שבוטלה: מחיקת {{file}} קבצים שהועתקו",
|
||||
"undoCopySuccess": "פעולת העתקה שבוטלה: מחיקת {{count}} קבצים שהועתקו",
|
||||
"undoCopyFailedDelete": "ביטול נכשל: לא ניתן היה למחוק קבצים שהועתקו",
|
||||
"undoCopyFailedNoInfo": "ביטול נכשל: לא ניתן היה למצוא את פרטי הקובץ שהועתק",
|
||||
"undoMoveSuccess": "פעולת העברה בוטלה: העבירו {{name}} קבצים בחזרה למיקום המקורי",
|
||||
"undoMoveSuccess": "פעולת העברה שבוטלה: העבירו {{count}} קבצים חזרה למיקום המקורי",
|
||||
"undoMoveFailedMove": "ביטול נכשל: לא ניתן היה להעביר קבצים בחזרה",
|
||||
"undoMoveFailedNoInfo": "ביטול נכשל: לא ניתן היה למצוא מידע על הקובץ שהועבר",
|
||||
"undoDeleteNotSupported": "לא ניתן לבטל את פעולת המחיקה: הקבצים נמחקו לצמיתות מהשרת",
|
||||
@@ -1480,7 +1480,7 @@
|
||||
"goToLine": "עבור אל שורה",
|
||||
"moveLineUp": "הזזת שורה למעלה",
|
||||
"moveLineDown": "הזזת שורה למטה",
|
||||
"toggleComment": "הפעלה/כיבוי תגובה",
|
||||
"toggleComment": "החלף/הפעל תגובה",
|
||||
"indent": "לְשַׁנֵן",
|
||||
"outdent": "הזחה החוצה",
|
||||
"autoComplete": "השלמה אוטומטית",
|
||||
@@ -1491,33 +1491,33 @@
|
||||
"unknownSize": "גודל לא ידוע",
|
||||
"fileIsEmpty": "הקובץ ריק",
|
||||
"largeFileWarning": "אזהרת קובץ גדול",
|
||||
"largeFileWarningDesc": "קובץ זה בגודל {{name}}, דבר שעשוי לגרום לבעיות ביצועים בעת פתיחה כטקסט.",
|
||||
"largeFileWarningDesc": "קובץ זה הוא בגודל {{size}} , דבר שעלול לגרום לבעיות ביצועים בעת פתיחתו כטקסט.",
|
||||
"fileNotFoundAndRemoved": "הקובץ \"{{name}}\" לא נמצא והוסר מהקבצים האחרונים/המוצמדים",
|
||||
"failedToLoadFile": "טעינת הקובץ נכשלה: {{count}}",
|
||||
"failedToLoadFile": "טעינת הקובץ נכשלה: {{error}}",
|
||||
"serverErrorOccurred": "אירעה שגיאת שרת. אנא נסה שוב מאוחר יותר.",
|
||||
"autoSaveFailed": "השמירה האוטומטית נכשלה",
|
||||
"fileAutoSaved": "קובץ נשמר אוטומטית",
|
||||
"moveFileFailed": "נכשל בהזזת {{count}}",
|
||||
"moveFileFailed": "נכשל בהזזת {{name}}",
|
||||
"moveOperationFailed": "פעולת ההעברה נכשלה",
|
||||
"canOnlyCompareFiles": "ניתן להשוות רק שני קבצים",
|
||||
"comparingFiles": "השוואת קבצים: {{count}} ו-{{size}}",
|
||||
"comparingFiles": "השוואת קבצים: {{file1}} ו- {{file2}}",
|
||||
"dragFailed": "פעולת הגרירה נכשלה",
|
||||
"filePinnedSuccessfully": "הקובץ \"{{name}}\" הוצמד בהצלחה",
|
||||
"pinFileFailed": "נכשל בהצמדת הקובץ",
|
||||
"fileUnpinnedSuccessfully": "הקובץ \"{{error}}\" נותק בהצלחה",
|
||||
"fileUnpinnedSuccessfully": "הקובץ \"{{name}}\" נותק בהצלחה",
|
||||
"unpinFileFailed": "נכשל ניתוק הקובץ",
|
||||
"shortcutAddedSuccessfully": "קיצור הדרך לתיקייה \"{{name}}\" נוסף בהצלחה",
|
||||
"shortcutAddedSuccessfully": "קיצור דרך לתיקייה \"{{name}}\" נוסף בהצלחה",
|
||||
"addShortcutFailed": "הוספת קיצור דרך נכשלה",
|
||||
"operationCompletedSuccessfully": "פריטים {{file1}} {{file2}} בהצלחה",
|
||||
"operationCompleted": "פריטים",
|
||||
"downloadFileSuccess": "קובץ {{name}} הורד בהצלחה",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} פריטים הצליחו",
|
||||
"operationCompleted": "{{operation}} {{count}} פריטים",
|
||||
"downloadFileSuccess": "הקובץ {{name}} הורד בהצלחה",
|
||||
"downloadFileFailed": "ההורדה נכשלה",
|
||||
"moveTo": "העבר אל {{name}}",
|
||||
"diffCompareWith": "השוואה שונה עם {{name}}",
|
||||
"dragOutsideToDownload": "גרור את הקבצים אל מחוץ לחלון כדי להוריד אותם ({{operation}} קבצים)",
|
||||
"moveTo": "מעבר אל {{name}}",
|
||||
"diffCompareWith": "השוואת הבדלים עם {{name}}",
|
||||
"dragOutsideToDownload": "גרור את הקבצים אל מחוץ לחלון כדי להוריד אותם ({{count}} )",
|
||||
"newFolderDefault": "תיקייה חדשה",
|
||||
"newFileDefault": "קובץ חדש.txt",
|
||||
"successfullyMovedItems": "הועבר בהצלחה {{count}} פריטים אל {{operation}}",
|
||||
"successfullyMovedItems": "הועבר בהצלחה {{count}} פריטים אל {{target}}",
|
||||
"move": "מַהֲלָך",
|
||||
"searchInFile": "חיפוש בקובץ (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "הצג קיצורי מקלדת",
|
||||
@@ -1527,10 +1527,10 @@
|
||||
"compare": "לְהַשְׁווֹת",
|
||||
"sideBySide": "זֶה בְּצַד זֶה",
|
||||
"inline": "מוטבע",
|
||||
"fileComparison": "השוואת קבצים: {{count}} לעומת {{name}}",
|
||||
"fileTooLarge": "קובץ גדול מדי: {{name}}",
|
||||
"sshConnectionFailed": "חיבור SSH נכשל. אנא בדוק את החיבור שלך אל {{name}} ({{count}}:{{count}})",
|
||||
"loadFileFailed": "טעינת הקובץ נכשלה: {{target}}",
|
||||
"fileComparison": "השוואת קבצים: {{file1}} לעומת {{file2}}",
|
||||
"fileTooLarge": "קובץ גדול מדי: {{error}}",
|
||||
"sshConnectionFailed": "חיבור SSH נכשל. אנא בדוק את החיבור שלך אל {{name}} ({{ip}}:{{port}})",
|
||||
"loadFileFailed": "טעינת הקובץ נכשלה: {{error}}",
|
||||
"connectedSuccessfully": "התחבר בהצלחה",
|
||||
"totpVerificationFailed": "אימות TOTP נכשל",
|
||||
"verificationCodePrompt": "קוד אימות:",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "לְנַתֵק",
|
||||
"cancel": "לְבַטֵל",
|
||||
"port": "נָמָל",
|
||||
"attempt": "ניסיון {{file1}} מתוך {{file2}}",
|
||||
"nextRetryIn": "ניסיון חוזר הבא בעוד {{error}} שניות",
|
||||
"attempt": "ניסיון {{current}} מתוך {{max}}",
|
||||
"nextRetryIn": "ניסיון חוזר הבא בעוד {{seconds}} שניות",
|
||||
"checkDockerLogs": "בדוק את יומני ה-Docker שלך כדי למצוא את סיבת השגיאה, הצטרף ל-",
|
||||
"orCreate": "או ליצור",
|
||||
"orCreate": "או ליצור ",
|
||||
"noTunnelConnections": "לא הוגדרו חיבורי מנהרה",
|
||||
"tunnelConnections": "חיבורי מנהרה",
|
||||
"addTunnel": "הוסף מנהרה",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"remote": "מְרוּחָק",
|
||||
"dynamic": "דִינָמִי",
|
||||
"unknownConnectionStatus": "לֹא יְדוּעַ",
|
||||
"portMapping": "פורט {{name}} → {{ip}}:{{port}}",
|
||||
"portMapping": "פורט {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"endpointHostNotFound": "מארח נקודת הקצה לא נמצא",
|
||||
"discord": "מַחֲלוֹקֶת",
|
||||
"githubIssue": "בעיית GitHub",
|
||||
@@ -1611,7 +1611,7 @@
|
||||
"disk": "דִיסק",
|
||||
"network": "רֶשֶׁת",
|
||||
"uptime": "זמן פעולה",
|
||||
"loadAverage": "ממוצע: {{error}}, {{current}}, {{max}}",
|
||||
"loadAverage": "ממוצע: {{avg1}}, {{avg5}}, {{avg15}}",
|
||||
"processes": "תהליכים",
|
||||
"connections": "חיבורים",
|
||||
"usage": "נוֹהָג",
|
||||
@@ -1624,8 +1624,8 @@
|
||||
"refreshStatus": "רענון סטטוס",
|
||||
"fileManagerAlreadyOpen": "מנהל הקבצים כבר פתוח עבור מארח זה",
|
||||
"openFileManager": "פתח את מנהל הקבצים",
|
||||
"cpuCores_one": "מעבד {{seconds}}",
|
||||
"cpuCores_other": "מעבדים (CPUs)",
|
||||
"cpuCores_one": "מעבד {{count}}",
|
||||
"cpuCores_other": "מעבדים {{count}}",
|
||||
"naCpus": "מעבדים לא רלוונטיים",
|
||||
"loadAverageNA": "ממוצע: לא רלוונטי",
|
||||
"cpuUsage": "שימוש במעבד",
|
||||
@@ -1645,12 +1645,12 @@
|
||||
"cannotFetchMetrics": "לא ניתן לאחזר מדדים משרת לא מקוון",
|
||||
"totpRequired": "נדרש אימות TOTP",
|
||||
"totpUnavailable": "סטטיסטיקות שרת אינן זמינות עבור שרתים התומכים ב-TOTP",
|
||||
"totpVerified": "TOTP אומת, איסוף המדדים החל",
|
||||
"totpVerified": "TOTP אומת, איסוף מדדים החל",
|
||||
"totpFailed": "אימות TOTP נכשל",
|
||||
"totpInvalidCode": "קוד אימות לא תקין",
|
||||
"totpCancelled": "איסוף המדדים בוטל",
|
||||
"authenticationFailed": "האימות נכשל",
|
||||
"noneAuthNotSupported": "סטטיסטיקות השרת אינן תומכות בסוג האימות 'ללא'.",
|
||||
"noneAuthNotSupported": "סטטיסטיקות השרת אינן תומכות בסוג אימות 'ללא'.",
|
||||
"load": "לִטעוֹן",
|
||||
"editLayout": "עריכת פריסה",
|
||||
"cancelEdit": "לְבַטֵל",
|
||||
@@ -1678,11 +1678,11 @@
|
||||
"noRecentLoginData": "אין נתוני התחברות אחרונים",
|
||||
"from": "מִן",
|
||||
"quickActions": "פעולות מהירות",
|
||||
"executeQuickAction": "בצע {{sourcePort}}",
|
||||
"executingQuickAction": "מבצע את {{endpointHost}}...",
|
||||
"quickActionSuccess": "{{endpointPort}} הושלם בהצלחה",
|
||||
"quickActionFailed": "{{avg1}} נכשל",
|
||||
"quickActionError": "נכשל בביצוע {{avg5}}"
|
||||
"executeQuickAction": "בצע {{name}}",
|
||||
"executingQuickAction": "מבצע {{name}}...",
|
||||
"quickActionSuccess": "{{name}} הושלם בהצלחה",
|
||||
"quickActionFailed": "{{name}} נכשל",
|
||||
"quickActionError": "נכשל בביצוע {{name}}"
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "מנהל שרתי SSH",
|
||||
@@ -1765,7 +1765,7 @@
|
||||
"enableTwoFactorButton": "הפעל אימות דו-שלבי",
|
||||
"addExtraSecurityLayer": "הוסף שכבת אבטחה נוספת לחשבונך",
|
||||
"firstUser": "משתמש ראשון",
|
||||
"firstUserMessage": "אתה המשתמש הראשון ותהפוך למנהל. תוכל לצפות בהגדרות מנהל המערכת בתפריט הנפתח של המשתמשים בסרגל הצד. אם אתה חושב שזו טעות, בדוק את יומני ה-docker או צור בעיה ב-GitHub.",
|
||||
"firstUserMessage": "אתה המשתמש הראשון ותהפוך למנהל. תוכל לצפות בהגדרות מנהל המערכת בתפריט הנפתח של המשתמש בסרגל הצד. אם אתה חושב שזו טעות, בדוק את יומני ה-docker או צור בעיה ב-GitHub.",
|
||||
"external": "חִיצוֹנִי",
|
||||
"loginWithExternal": "התחברות עם ספק חיצוני",
|
||||
"loginWithExternalDesc": "התחבר באמצעות ספק הזהויות החיצוני שתצורתו נקבעה",
|
||||
@@ -1788,7 +1788,7 @@
|
||||
"loggingInToDesktopAppViaWeb": "כניסה לאפליקציית שולחן העבודה דרך ממשק האינטרנט",
|
||||
"loadingServer": "טוען שרת...",
|
||||
"authenticating": "מאמת...",
|
||||
"dataLossWarning": "איפוס הסיסמה שלך בדרך זו ימחק את כל מארחי ה-SSH השמורים, פרטי הגישה ונתונים מוצפנים אחרים. לא ניתן לבטל פעולה זו. השתמש באפשרות זו רק אם שכחת את הסיסמה שלך ואינך מחובר.",
|
||||
"dataLossWarning": "איפוס הסיסמה שלך בדרך זו ימחק את כל מארחי ה-SSH השמורים, פרטי הגישה ונתונים מוצפנים אחרים. פעולה זו אינה ניתנת לביטול. השתמש באפשרות זו רק אם שכחת את הסיסמה שלך ואינך מחובר.",
|
||||
"authenticationDisabled": "אימות מושבת",
|
||||
"authenticationDisabledDesc": "כל שיטות האימות מושבתות כעת. אנא צור קשר עם מנהל המערכת שלך.",
|
||||
"passwordResetSuccess": "איפוס הסיסמה הצליח",
|
||||
@@ -1814,8 +1814,8 @@
|
||||
"invalidAuthUrl": "כתובת URL לא חוקית להרשאה התקבלה מה-backend",
|
||||
"invalidInput": "קלט לא חוקי",
|
||||
"requiredField": "שדה זה נדרש",
|
||||
"minLength": "אורך מינימלי הוא {{avg15}}",
|
||||
"maxLength": "האורך המקסימלי הוא {{count}}",
|
||||
"minLength": "אורך מינימלי הוא {{min}}",
|
||||
"maxLength": "האורך המקסימלי הוא {{max}}",
|
||||
"invalidEmail": "כתובת דוא\"ל לא חוקית",
|
||||
"passwordMismatch": "הסיסמאות אינן תואמות",
|
||||
"passwordLoginDisabled": "כניסה באמצעות שם משתמש/סיסמה מושבתת כעת",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"updateError": "העדכון נכשל",
|
||||
"copySuccess": "הועתק ללוח",
|
||||
"copyError": "ההעתקה נכשלה",
|
||||
"copiedToClipboard": "{{count}} הועתק ללוח",
|
||||
"copiedToClipboard": "{{item}} הועתק ללוח",
|
||||
"connectionEstablished": "נוצר חיבור",
|
||||
"connectionClosed": "החיבור נסגר",
|
||||
"reconnecting": "מתחבר מחדש...",
|
||||
@@ -1955,9 +1955,9 @@
|
||||
"passwordRequired": "נדרשת סיסמה",
|
||||
"failedToDeleteAccount": "מחיקת החשבון נכשלה",
|
||||
"failedToMakeUserAdmin": "נכשל בהפיכת המשתמש למנהל",
|
||||
"userIsNowAdmin": "משתמש {{name}} הוא כעת מנהל",
|
||||
"removeAdminConfirm": "האם אתה בטוח שברצונך להסיר את סטטוס המנהל מ-{{name}}?",
|
||||
"deleteUserConfirm": "האם אתה בטוח שברצונך למחוק את המשתמש {{name}}? פעולה זו אינה ניתנת לביטול.",
|
||||
"userIsNowAdmin": "משתמש {{username}} הוא כעת מנהל",
|
||||
"removeAdminConfirm": "האם אתה בטוח שברצונך להסיר את סטטוס המנהל מ- {{username}}?",
|
||||
"deleteUserConfirm": "האם אתה בטוח שברצונך למחוק את המשתמש {{username}}? פעולה זו אינה ניתנת לביטול.",
|
||||
"deleteAccount": "מחיקת חשבון",
|
||||
"closeDeleteAccount": "סגור מחק חשבון",
|
||||
"deleteAccountWarning": "לא ניתן לבטל פעולה זו. פעולה זו תמחק לצמיתות את חשבונך ואת כל הנתונים המשויכים.",
|
||||
@@ -1997,7 +1997,7 @@
|
||||
"error": "שְׁגִיאָה",
|
||||
"warning": "אַזהָרָה",
|
||||
"deleteAccount": "מחיקת חשבון",
|
||||
"closeDeleteAccount": "סגור מחיקת חשבון",
|
||||
"closeDeleteAccount": "סגור מחק חשבון",
|
||||
"cannotDeleteAccount": "לא ניתן למחוק חשבון",
|
||||
"confirmPassword": "אשר סיסמה",
|
||||
"deleting": "מוחק...",
|
||||
@@ -2079,7 +2079,7 @@
|
||||
"selectHostToStart": "בחר מארח כדי להתחיל את הפעלת הטרמינל שלך",
|
||||
"limitedSupportMessage": "תמיכת האתר בנייד עדיין בעיצומה. השתמשו באפליקציה לנייד לחוויית משתמש טובה יותר.",
|
||||
"mobileAppInProgress": "אפליקציית מובייל נמצאת בתהליך פיתוח",
|
||||
"mobileAppInProgressDesc": "אנחנו עובדים על אפליקציה ייעודית לנייד כדי לספק חוויית שימוש טובה יותר במכשירים ניידים.",
|
||||
"mobileAppInProgressDesc": "אנחנו עובדים על אפליקציה ייעודית למובייל כדי לספק חוויה טובה יותר במכשירים ניידים.",
|
||||
"viewMobileAppDocs": "התקנת אפליקציה לנייד",
|
||||
"mobileAppDocumentation": "תיעוד אפליקציה לנייד"
|
||||
},
|
||||
@@ -2137,22 +2137,22 @@
|
||||
"fullDesc": "אין הגבלות (לא מומלץ)"
|
||||
},
|
||||
"blockedCommands": "פקודות חסומות",
|
||||
"blockedCommandsPlaceholder": "הזן פקודות לחסימה, לדוגמה, passwd, rm, dd",
|
||||
"maxSessionDuration": "משך זמן מקסימלי של סשן (דקות)",
|
||||
"blockedCommandsPlaceholder": "הזן פקודות לחסימה, למשל, passwd, rm, dd",
|
||||
"maxSessionDuration": "משך מקסימלי של סשן (בדקות)",
|
||||
"createTempUser": "צור משתמש זמני",
|
||||
"createTempUserDesc": "יוצר משתמש מוגבל בשרת במקום לשתף את פרטי הגישה שלך. דורש גישת sudo. האפשרות הבטוחה ביותר.",
|
||||
"expiresAt": "פג תוקף ב",
|
||||
"expiresIn": "פג תוקף בעוד {{name}} שעות",
|
||||
"expiresIn": "פג תוקף בעוד {{hours}} שעות",
|
||||
"expired": "פג תוקף",
|
||||
"grantedBy": "הוענק על ידי",
|
||||
"accessLevel": "רמת גישה",
|
||||
"lastAccessed": "גישה אחרונה",
|
||||
"accessCount": "ספירת גישה",
|
||||
"revokeAccess": "ביטול גישה",
|
||||
"confirmRevokeAccess": "האם אתה בטוח שברצונך לבטל גישה עבור {{name}}?",
|
||||
"hostSharedSuccessfully": "מארח שותף בהצלחה עם {{min}}",
|
||||
"confirmRevokeAccess": "האם אתה בטוח שברצונך לבטל את הגישה עבור {{username}}?",
|
||||
"hostSharedSuccessfully": "מארח שותף בהצלחה עם {{username}}",
|
||||
"hostAccessUpdated": "גישת המארח עודכנה",
|
||||
"failedToShareHost": "נכשל בשיתוף המארח",
|
||||
"failedToShareHost": "נכשל שיתוף המארח",
|
||||
"accessRevokedSuccessfully": "הגישה בוטלה בהצלחה",
|
||||
"failedToRevokeAccess": "ביטול הגישה נכשל",
|
||||
"shared": "מְשׁוּתָף",
|
||||
@@ -2165,16 +2165,16 @@
|
||||
"noAccessGranted": "לא הוענקה גישה למארח זה",
|
||||
"noAccessGrantedMessage": "אף משתמש לא קיבל עדיין גישה למארח זה",
|
||||
"manageAccessFor": "ניהול גישה עבור",
|
||||
"totalAccessRecords": "רשומות גישה {{max}}",
|
||||
"totalAccessRecords": "{{count}} גישה לרשומות",
|
||||
"neverAccessed": "לְעוֹלָם לֹא",
|
||||
"timesAccessed": "{{item}} פעמים",
|
||||
"daysRemaining": "{{username}} יום(ים)",
|
||||
"hoursRemaining": "שעה (225)",
|
||||
"timesAccessed": "{{count}} זמן/פעמים",
|
||||
"daysRemaining": "{{days}} day(s)",
|
||||
"hoursRemaining": "שעה/שעות {{hours}}",
|
||||
"failedToFetchAccessList": "נכשלה אחזור רשימת הגישה",
|
||||
"currentAccess": "גישה נוכחית",
|
||||
"securityWarning": "אזהרת אבטחה",
|
||||
"securityWarningMessage": "שיתוף אישורים מעניק למשתמש גישה מלאה לביצוע כל פעולה בשרת, כולל שינוי סיסמאות ומחיקת קבצים. יש לשתף רק עם משתמשים מהימנים.",
|
||||
"tempUserRecommended": "אנו ממליצים להפעיל את האפשרות 'צור משתמש זמני' לשיפור האבטחה.",
|
||||
"tempUserRecommended": "אנו ממליצים להפעיל את 'צור משתמש זמני' לשיפור האבטחה.",
|
||||
"roleManagement": "ניהול תפקידים",
|
||||
"manageRoles": "ניהול תפקידים",
|
||||
"manageRolesFor": "ניהול תפקידים עבור {{username}}",
|
||||
@@ -2184,9 +2184,9 @@
|
||||
"permissions": "הרשאות",
|
||||
"systemRole": "תפקיד המערכת",
|
||||
"customRole": "תפקיד מותאם אישית",
|
||||
"roleAssignedSuccessfully": "תפקיד שהוקצה ל-{{username}} בהצלחה",
|
||||
"roleAssignedSuccessfully": "תפקיד שהוקצה בהצלחה ל- {{username}}",
|
||||
"failedToAssignRole": "הקצאת התפקיד נכשלה",
|
||||
"roleRemovedSuccessfully": "התפקיד הוסר בהצלחה מ-{{hours}}",
|
||||
"roleRemovedSuccessfully": "התפקיד הוסר בהצלחה מ- {{username}}",
|
||||
"failedToRemoveRole": "הסרת התפקיד נכשלה",
|
||||
"cannotRemoveSystemRole": "לא ניתן להסיר את תפקיד המערכת",
|
||||
"cannotShareWithSelf": "לא ניתן לשתף את המארח עם עצמך",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "סיום סשן",
|
||||
"sessionTerminated": "הסשן הסתיים על ידי בעל המארח",
|
||||
"sharedAccessExpired": "הגישה המשותפת שלך למארח זה פגה",
|
||||
"sharedAccessExpiresIn": "תוקף הגישה המשותפת פג בעוד {{username}} שעות",
|
||||
"sharedAccessExpiresIn": "תוקף הגישה המשותפת פג בעוד {{hours}} שעות",
|
||||
"roles": {
|
||||
"label": "תפקידים",
|
||||
"admin": "מְנַהֵל",
|
||||
@@ -2244,15 +2244,15 @@
|
||||
"failedToSaveRole": "שמירת התפקיד נכשלה",
|
||||
"failedToDeleteRole": "מחיקת התפקיד נכשלה",
|
||||
"roleDisplayNameRequired": "נדרש שם תצוגה של התפקיד",
|
||||
"roleNameRequired": "נדרש שם תפקיד",
|
||||
"roleNameRequired": "שם תפקיד נדרש",
|
||||
"roleNameHint": "השתמשו רק באותיות קטנות, מספרים, קווים תחתונים ומקפים",
|
||||
"displayNamePlaceholder": "מפתח",
|
||||
"descriptionPlaceholder": "מפתחי תוכנה ומהנדסים",
|
||||
"confirmDeleteRole": "מחיקת תפקיד",
|
||||
"confirmDeleteRoleDescription": "האם אתה בטוח שברצונך למחוק את התפקיד '{{username}}'? לא ניתן לבטל פעולה זו.",
|
||||
"confirmDeleteRoleDescription": "האם אתה בטוח שברצונך למחוק את התפקיד '{{name}}'? לא ניתן לבטל פעולה זו.",
|
||||
"confirmRemoveRole": "הסר תפקיד",
|
||||
"confirmRemoveRoleDescription": "האם אתה בטוח שברצונך להסיר את התפקיד הזה מהמשתמש?",
|
||||
"editRoleDescription": "עדכון פרטי תפקיד",
|
||||
"editRoleDescription": "עדכון פרטי התפקיד",
|
||||
"createRoleDescription": "צור תפקיד מותאם אישית חדש לקיבוץ משתמשים",
|
||||
"assignRolesDescription": "ניהול הקצאות תפקידים עבור משתמשים",
|
||||
"noRoles": "לא נמצאו תפקידים",
|
||||
@@ -2307,19 +2307,19 @@
|
||||
"validating": "מאמת את Docker...",
|
||||
"connectingToHost": "מתחבר למארח...",
|
||||
"error": "שְׁגִיאָה",
|
||||
"errorCode": "קוד שגיאה: {{count}}",
|
||||
"version": "דוקר {{count}}",
|
||||
"containerStarted": "מיכל {{days}} הופעל",
|
||||
"failedToStartContainer": "נכשל בהפעלת המכולה {{hours}}",
|
||||
"containerStopped": "מיכל {{username}} נעצר",
|
||||
"failedToStopContainer": "נכשלה עצירת המכולה {{username}}",
|
||||
"containerRestarted": "מיכל {{username}} הופעל מחדש",
|
||||
"failedToRestartContainer": "נכשל בהפעלה מחדש של המיכל {{hours}}",
|
||||
"errorCode": "קוד שגיאה: {{code}}",
|
||||
"version": "דוקר {{version}}",
|
||||
"containerStarted": "מיכל {{name}} הופעל",
|
||||
"failedToStartContainer": "נכשל בהפעלת המכולה {{name}}",
|
||||
"containerStopped": "מיכל {{name}} נעצר",
|
||||
"failedToStopContainer": "נכשלה עצירת המכולה {{name}}",
|
||||
"containerRestarted": "מיכל {{name}} הופעל מחדש",
|
||||
"failedToRestartContainer": "נכשלה ההפעלה מחדש של המכולה {{name}}",
|
||||
"containerPaused": "מיכל {{name}} הושהה",
|
||||
"containerUnpaused": "מיכל {{code}} בוטל",
|
||||
"failedToTogglePauseContainer": "נכשל בהחלפת מצב השהייה עבור המכולה {{version}}",
|
||||
"containerRemoved": "מיכל {{name}} הוסר",
|
||||
"failedToRemoveContainer": "הסרת המיכל {{name}} נכשלה",
|
||||
"containerUnpaused": "השהיית המיכל {{name}} בוטלה",
|
||||
"failedToTogglePauseContainer": "נכשל הניסיון להחליף את מצב ההשהיה עבור המכולה {{name}}",
|
||||
"containerRemoved": "המיכל {{name}} הוסר",
|
||||
"failedToRemoveContainer": "נכשלה הסרת המיכל {{name}}",
|
||||
"image": "תְמוּנָה",
|
||||
"idLabel": "תְעוּדַת זֶהוּת",
|
||||
"ports": "נמלים",
|
||||
@@ -2340,8 +2340,8 @@
|
||||
"noContainersFoundHint": "אין מכולות Docker זמינות במארח זה",
|
||||
"searchPlaceholder": "חיפוש מכולות...",
|
||||
"filterByStatusPlaceholder": "סנן לפי סטטוס",
|
||||
"allContainersCount": "הכל ({{name}})",
|
||||
"statusCount": "{{name}} ({{name}})",
|
||||
"allContainersCount": "הכל ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "אין מכולות התואמות את המסננים שלך",
|
||||
"noContainersMatchFiltersHint": "נסה להתאים את קריטריוני החיפוש או הסינון שלך",
|
||||
"containerMustBeRunningToViewStats": "יש להפעיל את המכולה כדי להציג נתונים סטטיסטיים",
|
||||
@@ -2372,10 +2372,10 @@
|
||||
"authenticationRequired": "נדרש אימות",
|
||||
"verificationCodePrompt": "הזן קוד אימות",
|
||||
"totpVerificationFailed": "אימות TOTP נכשל. אנא נסה שוב.",
|
||||
"connectedTo": "מחובר ל-{{name}}",
|
||||
"connectedTo": "מחובר אל {{containerName}}",
|
||||
"disconnected": "מְנוּתָק",
|
||||
"consoleError": "שגיאת קונסולה",
|
||||
"errorMessage": "שגיאה: {{name}}",
|
||||
"errorMessage": "שגיאה: {{message}}",
|
||||
"failedToConnect": "נכשל החיבור למכולה",
|
||||
"console": "לְנַחֵם",
|
||||
"selectShell": "בחר מעטפת",
|
||||
@@ -2387,7 +2387,7 @@
|
||||
"disconnect": "לְנַתֵק",
|
||||
"notConnected": "לא מחובר",
|
||||
"clickToConnect": "לחץ על התחבר כדי להתחיל סשן מעטפת",
|
||||
"connectingTo": "מתחבר אל {{name}}...",
|
||||
"connectingTo": "מתחבר אל {{containerName}}...",
|
||||
"containerNotFound": "המיכל לא נמצא",
|
||||
"backToList": "חזרה לרשימה",
|
||||
"logs": "יומני רישום",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "מעבר לתאורה",
|
||||
"switchToDark": "עבור למצב כהה"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
"refresh": "ताज़ा करना",
|
||||
"passwordRequired": "पासवर्ड आवश्यक है",
|
||||
"sshKeyRequired": "SSH कुंजी आवश्यक है",
|
||||
"credentialAddedSuccessfully": "क्रेडेंशियल \"{{name}}\" सफलतापूर्वक जोड़ दिया गया",
|
||||
"credentialAddedSuccessfully": "क्रेडेंशियल \"{{name}}\" सफलतापूर्वक जोड़ा गया",
|
||||
"general": "सामान्य",
|
||||
"description": "विवरण",
|
||||
"folder": "फ़ोल्डर",
|
||||
@@ -128,7 +128,7 @@
|
||||
"created": "बनाया था",
|
||||
"lastModified": "अंतिम बार संशोधित",
|
||||
"usageStatistics": "उपयोग के आँकड़े",
|
||||
"copiedToClipboard": "{{field}} क्लिपबोर्ड पर कॉपी किया गया",
|
||||
"copiedToClipboard": "{{field}} क्लिपबोर्ड पर कॉपी हो गया",
|
||||
"failedToCopy": "क्लिपबोर्ड पर कॉपी करने में विफल",
|
||||
"sshKey": "एसएसएच कुंजी",
|
||||
"createCredentialDescription": "सुरक्षित पहुँच के लिए एक नया SSH क्रेडेंशियल बनाएँ",
|
||||
@@ -139,9 +139,9 @@
|
||||
"confirmRemoveFromFolder": "क्या आप वाकई \"{{name}}\" को फ़ोल्डर \"{{folder}}\" से हटाना चाहते हैं? क्रेडेंशियल को \"अवर्गीकृत\" में स्थानांतरित कर दिया जाएगा।",
|
||||
"removedFromFolder": "क्रेडेंशियल \"{{name}}\" फ़ोल्डर से सफलतापूर्वक हटा दिया गया",
|
||||
"failedToRemoveFromFolder": "फ़ोल्डर से क्रेडेंशियल हटाने में विफल।",
|
||||
"folderRenamed": "फ़ोल्डर \"{{oldName}}\" का नाम सफलतापूर्वक बदलकर \"{{newName}}\" कर दिया गया है।",
|
||||
"folderRenamed": "फ़ोल्डर \"{{oldName}}\" का नाम बदलकर \"{{newName}}\" सफलतापूर्वक कर दिया गया है",
|
||||
"failedToRenameFolder": "फ़ोल्डर का नाम बदलने में विफल",
|
||||
"movedToFolder": "क्रेडेंशियल \"{{name}}\" को सफलतापूर्वक \"{{folder}}\" में स्थानांतरित कर दिया गया है।",
|
||||
"movedToFolder": "क्रेडेंशियल \"{{name}}\" सफलतापूर्वक \"{{folder}}\" में स्थानांतरित हो गया",
|
||||
"failedToMoveToFolder": "क्रेडेंशियल को फ़ोल्डर में स्थानांतरित करने में विफल।",
|
||||
"sshPublicKey": "एसएसएच सार्वजनिक कुंजी",
|
||||
"publicKeyNote": "सार्वजनिक कुंजी वैकल्पिक है लेकिन कुंजी सत्यापन के लिए इसकी अनुशंसा की जाती है।",
|
||||
@@ -189,7 +189,7 @@
|
||||
"dragging": "खींचना {{fileName}}",
|
||||
"preparing": "तैयारी {{fileName}}",
|
||||
"readySingle": "डाउनलोड करने के लिए तैयार {{fileName}}",
|
||||
"readyMultiple": "{{count}} फ़ाइलें डाउनलोड करने के लिए तैयार हैं",
|
||||
"readyMultiple": "डाउनलोड करने के लिए तैयार {{count}} फ़ाइलें",
|
||||
"batchDrag": "{{count}} फ़ाइलों को डेस्कटॉप पर खींचें",
|
||||
"dragToDesktop": "डेस्कटॉप पर खींचें",
|
||||
"canDragAnywhere": "आप फ़ाइलों को अपने डेस्कटॉप पर कहीं भी खींच सकते हैं।"
|
||||
@@ -202,7 +202,7 @@
|
||||
"stopKeyRecording": "रिकॉर्डिंग रोकें",
|
||||
"selectTerminals": "टर्मिनल चुनें:",
|
||||
"typeCommands": "कमांड टाइप करें (सभी कुंजियाँ समर्थित हैं):",
|
||||
"commandsWillBeSent": "कमांड {{count}} चयनित टर्मिनल(ओं) को भेजे जाएंगे।",
|
||||
"commandsWillBeSent": "Commands will be sent to {{count}} selected terminal(s).",
|
||||
"settings": "सेटिंग्स",
|
||||
"enableRightClickCopyPaste": "दाएँ क्लिक करके कॉपी/पेस्ट करने की सुविधा चालू करें",
|
||||
"shareIdeas": "SSH टूल्स के लिए आगे क्या होना चाहिए, इस बारे में आपके पास कोई विचार हैं? उन्हें साझा करें।",
|
||||
@@ -240,7 +240,7 @@
|
||||
"failedToFetch": "स्निपेट लाने में विफल",
|
||||
"executeSuccess": "निष्पादन: {{name}}",
|
||||
"copySuccess": "क्लिपबोर्ड पर \"{{name}}\" कॉपी किया गया",
|
||||
"runTooltip": "इस कोड स्निपेट को टर्मिनल में चलाएँ।",
|
||||
"runTooltip": "टर्मिनल में इस कोड स्निपेट को चलाएँ।",
|
||||
"copyTooltip": "इस अंश को क्लिपबोर्ड पर कॉपी करें",
|
||||
"editTooltip": "इस अंश को संपादित करें",
|
||||
"deleteTooltip": "इस अंश को हटा दें",
|
||||
@@ -280,7 +280,7 @@
|
||||
"empty": "अभी तक कोई कमांड हिस्ट्री उपलब्ध नहीं है",
|
||||
"emptyHint": "टर्मिनल का इतिहास बनाने के लिए सक्रिय टर्मिनल में कमांड निष्पादित करें।",
|
||||
"noResults": "कोई कमांड नहीं मिली",
|
||||
"noResultsHint": "\"{{query}}\" से मेल खाने वाले कोई कमांड नहीं हैं",
|
||||
"noResultsHint": "\"{{query}}\" से मेल खाने वाली कोई कमांड नहीं है",
|
||||
"deleteSuccess": "कमांड इतिहास से हटा दी गई",
|
||||
"deleteFailed": "कमांड को हटाने में विफलता।",
|
||||
"deleteTooltip": "डिलीट कमांड",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "स्प्लिट स्क्रीन साफ़ हो गई",
|
||||
"error": {
|
||||
"noAssignments": "कृपया लेआउट में कम से कम एक टैब असाइन करें",
|
||||
"fillAllSlots": "आवेदन करने से पहले कृपया सभी {{count}} स्लॉट भरें।"
|
||||
"fillAllSlots": "आवेदन करने से पहले कृपया सभी {{count}} रिक्त स्थान भरें"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -333,7 +333,7 @@
|
||||
"saveError": "कॉन्फ़िगरेशन सहेजने में त्रुटि",
|
||||
"saving": "सहेजा जा रहा है...",
|
||||
"saveConfig": "कॉन्फ़िगरेशन सहेजें",
|
||||
"helpText": "उस URL को दर्ज करें जहां आपका टर्मिक्स सर्वर चल रहा है (उदाहरण के लिए, http://localhost:30001 या https://your-server.com)",
|
||||
"helpText": "वह URL दर्ज करें जहां आपका टर्मिक्स सर्वर चल रहा है (उदाहरण के लिए, http://localhost:30001 या https://your-server.com)",
|
||||
"warning": "चेतावनी",
|
||||
"notValidatedWarning": "यूआरएल सत्यापित नहीं हुआ है - कृपया सुनिश्चित करें कि यह सही है।",
|
||||
"changeServer": "सर्वर बदलें",
|
||||
@@ -343,10 +343,10 @@
|
||||
"error": "संस्करण जाँच त्रुटि",
|
||||
"checkFailed": "अपडेट की जाँच करने में विफल",
|
||||
"upToDate": "ऐप अपडेटेड है",
|
||||
"currentVersion": "आप संस्करण {{version}} चला रहे हैं",
|
||||
"currentVersion": "आप संस्करण {{version}}चला रहे हैं",
|
||||
"updateAvailable": "उपलब्ध अद्यतन",
|
||||
"newVersionAvailable": "एक नया संस्करण उपलब्ध है! आप {{current}} चला रहे हैं, लेकिन {{latest}} उपलब्ध है।",
|
||||
"releasedOn": "{{date}} को जारी किया गया",
|
||||
"newVersionAvailable": "एक नया संस्करण उपलब्ध है! आप {{current}}चला रहे हैं, लेकिन {{latest}} भी उपलब्ध है।",
|
||||
"releasedOn": "{{date}}को जारी किया गया",
|
||||
"downloadUpdate": "अपडेट डाउनलोड करें",
|
||||
"dismiss": "नकार देना",
|
||||
"checking": "अपडेट के लिए जांच कर रहा है...",
|
||||
@@ -498,7 +498,7 @@
|
||||
"userManagement": "प्रयोक्ता प्रबंधन",
|
||||
"makeAdmin": "व्यवस्थापक बनाएं",
|
||||
"removeAdmin": "व्यवस्थापक को हटाएँ",
|
||||
"deleteUser": "उपयोगकर्ता {{username}} को हटाएँ? इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"deleteUser": "उपयोगकर्ता {{username}}को हटाएँ? इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"allowRegistration": "पंजीकरण की अनुमति दें",
|
||||
"oidcSettings": "ओआईडीसी सेटिंग्स",
|
||||
"clientId": "क्लाइंट आईडी",
|
||||
@@ -508,8 +508,8 @@
|
||||
"tokenUrl": "टोकन यूआरएल",
|
||||
"updateSettings": "सेटिंग्स अपडेट करें",
|
||||
"confirmDelete": "क्या आप वाकई इस उपयोगकर्ता को हटाना चाहते हैं?",
|
||||
"confirmMakeAdmin": "क्या आप वाकई {{username}} को व्यवस्थापक बनाना चाहते हैं?",
|
||||
"confirmRemoveAdmin": "क्या आप वाकई {{username}} से व्यवस्थापक का दर्जा हटाना चाहते हैं?",
|
||||
"confirmMakeAdmin": "क्या आप वाकई {{username}} को एडमिन बनाना चाहते हैं?",
|
||||
"confirmRemoveAdmin": "क्या आप वाकई {{username}}से व्यवस्थापक का दर्जा हटाना चाहते हैं?",
|
||||
"externalAuthentication": "बाह्य प्रमाणीकरण (OIDC)",
|
||||
"configureExternalProvider": "OIDC/OAuth2 प्रमाणीकरण के लिए बाहरी पहचान प्रदाता को कॉन्फ़िगर करें।",
|
||||
"userIdentifierPath": "उपयोगकर्ता पहचानकर्ता पथ",
|
||||
@@ -549,8 +549,8 @@
|
||||
"enterUsernameToMakeAdmin": "व्यवस्थापक बनने के लिए उपयोगकर्ता नाम दर्ज करें",
|
||||
"userIsNowAdmin": "उपयोगकर्ता {{username}} अब व्यवस्थापक है",
|
||||
"failedToMakeUserAdmin": "उपयोगकर्ता को व्यवस्थापक बनाने में विफल",
|
||||
"removeAdminStatus": "{{username}} से व्यवस्थापक का दर्जा हटाएँ?",
|
||||
"adminStatusRemoved": "{{username}} से व्यवस्थापक का दर्जा हटा दिया गया है",
|
||||
"removeAdminStatus": "{{username}}से व्यवस्थापक का दर्जा हटाएँ?",
|
||||
"adminStatusRemoved": "{{username}}से व्यवस्थापक का दर्जा हटा दिया गया है",
|
||||
"failedToRemoveAdminStatus": "व्यवस्थापक का दर्जा हटाने में विफल",
|
||||
"userDeletedSuccessfully": "उपयोगकर्ता {{username}} सफलतापूर्वक हटा दिया गया",
|
||||
"failedToDeleteUser": "उपयोगकर्ता को हटाने में विफल",
|
||||
@@ -584,7 +584,7 @@
|
||||
"passwordResetWarning": "किसी उपयोगकर्ता का पासवर्ड रीसेट करने से उनका सारा डेटा (SSH होस्ट, क्रेडेंशियल, सेटिंग्स) डिलीट हो जाएगा। इस कार्रवाई को पूर्ववत नहीं किया जा सकता है।",
|
||||
"resetUserPassword": "उपयोगकर्ता पासवर्ड रीसेट करें",
|
||||
"resettingPassword": "रीसेट हो रहा है...",
|
||||
"passwordResetInitiated": "{{username}} के लिए पासवर्ड रीसेट शुरू किया गया। रीसेट कोड भेजा गया।",
|
||||
"passwordResetInitiated": "{{username}}के लिए पासवर्ड रीसेट शुरू किया गया। रीसेट कोड भेजा गया।",
|
||||
"failedToResetPassword": "पासवर्ड रीसेट शुरू करने में विफल",
|
||||
"sessionManagement": "सत्र प्रबंधन",
|
||||
"revokeAllSessions": "सभी सत्र रद्द करें",
|
||||
@@ -611,12 +611,12 @@
|
||||
"linkTargetUsernamePlaceholder": "पासवर्ड खाते का उपयोगकर्ता नाम दर्ज करें",
|
||||
"linkAccountsButton": "खाते लिंक करें",
|
||||
"linkingAccounts": "लिंक हो रहा है...",
|
||||
"accountsLinkedSuccessfully": "OIDC उपयोगकर्ता {{oidcUsername}} को {{targetUsername}} से जोड़ा गया है।",
|
||||
"accountsLinkedSuccessfully": "OIDC उपयोगकर्ता {{oidcUsername}} को {{targetUsername}}से लिंक किया गया है",
|
||||
"failedToLinkAccounts": "खातों को लिंक करने में विफल",
|
||||
"linkTargetUsernameRequired": "लक्षित उपयोगकर्ता नाम आवश्यक है",
|
||||
"unlinkOIDCTitle": "OIDC प्रमाणीकरण को अनलिंक करें",
|
||||
"unlinkOIDCDescription": "{{username}} से OIDC प्रमाणीकरण हटाएँ? इसके बाद उपयोगकर्ता केवल उपयोगकर्ता नाम/पासवर्ड से ही लॉगिन कर पाएगा।",
|
||||
"unlinkOIDCSuccess": "OIDC {{username}} से अनलिंक हो गया",
|
||||
"unlinkOIDCDescription": "{{username}}से OIDC प्रमाणीकरण हटाएँ? इसके बाद उपयोगकर्ता केवल उपयोगकर्ता नाम/पासवर्ड से ही लॉगिन कर पाएगा।",
|
||||
"unlinkOIDCSuccess": "OIDC को {{username}}से अनलिंक कर दिया गया है",
|
||||
"failedToUnlinkOIDC": "OIDC को अनलिंक करने में विफल",
|
||||
"databaseSecurity": "डेटाबेस सुरक्षा",
|
||||
"encryptionStatus": "एन्क्रिप्शन स्थिति",
|
||||
@@ -661,7 +661,7 @@
|
||||
"loadingEncryptionStatus": "एन्क्रिप्शन स्थिति लोड हो रही है...",
|
||||
"testMigrationDescription": "यह सुनिश्चित करें कि मौजूदा डेटा को बिना किसी बदलाव के सुरक्षित रूप से एन्क्रिप्टेड फॉर्मेट में माइग्रेट किया जा सकता है।",
|
||||
"serverMigrationGuide": "सर्वर माइग्रेशन गाइड",
|
||||
"migrationInstructions": "एन्क्रिप्टेड डेटा को नए सर्वर पर माइग्रेट करने के लिए: 1) डेटाबेस फ़ाइलों का बैकअप लें, 2) नए सर्वर पर DB_ENCRYPTION_KEY=\"आपकी कुंजी\" नामक पर्यावरण चर सेट करें, 3) डेटाबेस फ़ाइलों को पुनर्स्थापित करें।",
|
||||
"migrationInstructions": "एन्क्रिप्टेड डेटा को नए सर्वर पर माइग्रेट करने के लिए: 1) डेटाबेस फ़ाइलों का बैकअप लें, 2) नए सर्वर पर DB_ENCRYPTION_KEY=\"your-key\" नामक पर्यावरण चर सेट करें, 3) डेटाबेस फ़ाइलों को पुनर्स्थापित करें।",
|
||||
"environmentProtection": "पर्यावरण संरक्षण",
|
||||
"environmentProtectionDesc": "सर्वर परिवेश संबंधी जानकारी (होस्टनेम, पाथ आदि) के आधार पर एन्क्रिप्शन कुंजियों की सुरक्षा करता है, जिन्हें परिवेश चर के माध्यम से स्थानांतरित किया जा सकता है।",
|
||||
"verificationCompleted": "संगतता सत्यापन पूर्ण हो गया - कोई डेटा परिवर्तित नहीं हुआ",
|
||||
@@ -743,7 +743,7 @@
|
||||
"passwordLoginAndRegistrationDisabled": "पासवर्ड लॉगिन और नए खाते का पंजीकरण सफलतापूर्वक अक्षम कर दिया गया है।",
|
||||
"requiresPasswordLogin": "पासवर्ड लॉगिन सक्षम होना आवश्यक है",
|
||||
"passwordLoginDisabledWarning": "पासवर्ड लॉगिन अक्षम है। सुनिश्चित करें कि OIDC ठीक से कॉन्फ़िगर किया गया है, अन्यथा आप Termix में लॉगिन नहीं कर पाएंगे।",
|
||||
"oidcRequiredWarning": "महत्वपूर्ण: पासवर्ड लॉगिन अक्षम है। यदि आप OIDC को रीसेट या गलत तरीके से कॉन्फ़िगर करते हैं, तो आप Termix तक अपनी पहुँच खो देंगे और आपका इंस्टेंस खराब हो जाएगा। केवल तभी आगे बढ़ें जब आप पूरी तरह से आश्वस्त हों।",
|
||||
"oidcRequiredWarning": "गंभीर चेतावनी: पासवर्ड लॉगिन अक्षम है। यदि आप OIDC को रीसेट या गलत तरीके से कॉन्फ़िगर करते हैं, तो आप Termix तक पूरी पहुँच खो देंगे और आपका इंस्टेंस खराब हो जाएगा। केवल तभी आगे बढ़ें जब आप पूरी तरह से आश्वस्त हों।",
|
||||
"confirmDisableOIDCWarning": "चेतावनी: आप पासवर्ड लॉगिन को अक्षम करते हुए OIDC को अक्षम करने जा रहे हैं। इससे आपका Termix इंस्टेंस पूरी तरह से क्षतिग्रस्त हो जाएगा और आप सभी एक्सेस खो देंगे। क्या आप आगे बढ़ना चाहते हैं?",
|
||||
"failedToUpdatePasswordLoginStatus": "पासवर्ड लॉगिन स्थिति अपडेट करने में विफल",
|
||||
"loadingSessions": "सेशन लोड हो रहे हैं...",
|
||||
@@ -785,15 +785,15 @@
|
||||
"downloadSample": "नमूना डाउनलोड करें",
|
||||
"formatGuide": "प्रारूप मार्गदर्शिका",
|
||||
"exportCredentialWarning": "चेतावनी: होस्ट \"{{name}}\" क्रेडेंशियल प्रमाणीकरण का उपयोग करता है। निर्यात की गई फ़ाइल में क्रेडेंशियल डेटा शामिल नहीं होगा और आयात के बाद इसे मैन्युअल रूप से पुनः कॉन्फ़िगर करना होगा। क्या आप जारी रखना चाहते हैं?",
|
||||
"exportSensitiveDataWarning": "चेतावनी: होस्ट \"{{name}}\" में संवेदनशील प्रमाणीकरण डेटा (पासवर्ड/एसएसएच कुंजी) शामिल है। निर्यात की गई फ़ाइल में यह डेटा सादे टेक्स्ट में होगा। कृपया फ़ाइल को सुरक्षित रखें और उपयोग के बाद इसे हटा दें। क्या आप जारी रखना चाहते हैं?",
|
||||
"exportSensitiveDataWarning": "चेतावनी: होस्ट \"{{name}}\" में संवेदनशील प्रमाणीकरण डेटा (पासवर्ड/एसएसएच कुंजी) मौजूद है। निर्यात की गई फ़ाइल में यह डेटा सादे टेक्स्ट में शामिल होगा। कृपया फ़ाइल को सुरक्षित रखें और उपयोग के बाद इसे हटा दें। क्या आप जारी रखना चाहते हैं?",
|
||||
"uncategorized": "अवर्गीकृत",
|
||||
"confirmDelete": "क्या आप वाकई \"{{name}}\" को हटाना चाहते हैं?",
|
||||
"failedToDeleteHost": "होस्ट को हटाने में विफल",
|
||||
"failedToExportHost": "होस्ट को निर्यात करने में विफलता। कृपया सुनिश्चित करें कि आप लॉग इन हैं और आपके पास होस्ट डेटा तक पहुंच है।",
|
||||
"jsonMustContainHosts": "JSON में एक \"होस्ट\" ऐरे होना चाहिए या वह होस्ट्स का ऐरे होना चाहिए।",
|
||||
"jsonMustContainHosts": "JSON में \"होस्ट\" ऐरे होना चाहिए या वह होस्ट्स का ऐरे होना चाहिए।",
|
||||
"noHostsInJson": "JSON फ़ाइल में कोई होस्ट नहीं मिला",
|
||||
"maxHostsAllowed": "प्रति आयात अधिकतम 100 होस्ट की अनुमति है",
|
||||
"importCompleted": "आयात पूर्ण हुआ: {{success}} सफल, {{failed}} असफल",
|
||||
"importCompleted": "Import completed: {{success}} successful, {{failed}} failed",
|
||||
"importFailed": "आयात विफल",
|
||||
"importError": "आयात त्रुटि",
|
||||
"failedToImportJson": "JSON फ़ाइल आयात करने में विफल",
|
||||
@@ -837,7 +837,7 @@
|
||||
"connection": "संबंध",
|
||||
"remove": "निकालना",
|
||||
"sourcePort": "स्रोत पोर्ट",
|
||||
"sourcePortDesc": "(स्रोत से तात्पर्य सामान्य टैब में वर्तमान कनेक्शन विवरण से है)",
|
||||
"sourcePortDesc": " (स्रोत से तात्पर्य सामान्य टैब में वर्तमान कनेक्शन विवरण से है)",
|
||||
"endpointPort": "एंडपॉइंट पोर्ट",
|
||||
"endpointSshConfig": "एंडपॉइंट एसएसएच कॉन्फ़िगरेशन",
|
||||
"tunnelForwardDescription": "यह टनल स्रोत मशीन पर पोर्ट {{sourcePort}} (सामान्य टैब में वर्तमान कनेक्शन विवरण) से एंडपॉइंट मशीन पर पोर्ट {{endpointPort}} तक ट्रैफ़िक अग्रेषित करेगा।",
|
||||
@@ -848,7 +848,7 @@
|
||||
"autoStartContainer": "कंटेनर लॉन्च होने पर ऑटो स्टार्ट",
|
||||
"autoStartDesc": "कंटेनर लॉन्च होने पर यह टनल स्वचालित रूप से शुरू हो जाएगी",
|
||||
"addConnection": "टनल कनेक्शन जोड़ें",
|
||||
"sshpassRequired": "पासवर्ड प्रमाणीकरण के लिए एसएसएचपीएएसएस आवश्यक है",
|
||||
"sshpassRequired": "पासवर्ड प्रमाणीकरण के लिए एसएसएचपास आवश्यक है",
|
||||
"sshpassRequiredDesc": "टनल में पासवर्ड प्रमाणीकरण के लिए, सिस्टम पर sshpass स्थापित होना आवश्यक है।",
|
||||
"otherInstallMethods": "स्थापना के अन्य तरीके:",
|
||||
"debianUbuntuEquivalent": "(डेबियन/उबंटू) या आपके ऑपरेटिंग सिस्टम के लिए समकक्ष संस्करण।",
|
||||
@@ -916,10 +916,10 @@
|
||||
"customCommandsDesc": "इस सर्वर के लिए कस्टम शटडाउन और रीबूट कमांड परिभाषित करें",
|
||||
"shutdownCommand": "शटडाउन कमांड",
|
||||
"rebootCommand": "रिबूट कमांड",
|
||||
"confirmRemoveFromFolder": "क्या आप वाकई \"{{name}}\" को फ़ोल्डर \"{{folder}}\" से हटाना चाहते हैं? होस्ट को \"नो फ़ोल्डर\" में ले जाया जाएगा।",
|
||||
"confirmRemoveFromFolder": "क्या आप वाकई \"{{name}}\" को फ़ोल्डर \"{{folder}}\" से हटाना चाहते हैं? होस्ट को \"नो फ़ोल्डर\" में स्थानांतरित कर दिया जाएगा।",
|
||||
"removedFromFolder": "होस्ट \"{{name}}\" फ़ोल्डर से सफलतापूर्वक हटा दिया गया",
|
||||
"failedToRemoveFromFolder": "फ़ोल्डर से होस्ट को हटाने में विफल",
|
||||
"folderRenamed": "फ़ोल्डर \"{{oldName}}\" का नाम सफलतापूर्वक बदलकर \"{{newName}}\" कर दिया गया है।",
|
||||
"folderRenamed": "फ़ोल्डर \"{{oldName}}\" का नाम बदलकर \"{{newName}}\" सफलतापूर्वक कर दिया गया है",
|
||||
"failedToRenameFolder": "फ़ोल्डर का नाम बदलने में विफल",
|
||||
"editFolderAppearance": "फ़ोल्डर का स्वरूप संपादित करें",
|
||||
"editFolderAppearanceDesc": "फ़ोल्डर के लिए रंग और आइकन को अनुकूलित करें",
|
||||
@@ -929,10 +929,10 @@
|
||||
"folderAppearanceUpdated": "फ़ोल्डर का स्वरूप सफलतापूर्वक अपडेट हो गया",
|
||||
"failedToUpdateFolderAppearance": "फ़ोल्डर की दिखावट को अपडेट करने में विफलता",
|
||||
"deleteAllHostsInFolder": "फ़ोल्डर में मौजूद सभी होस्ट को हटा दें",
|
||||
"confirmDeleteAllHostsInFolder": "क्या आप वाकई फ़ोल्डर \"{{count}}\" में मौजूद सभी होस्ट को हटाना चाहते हैं? यह कार्रवाई पूर्ववत नहीं की जा सकती।",
|
||||
"allHostsInFolderDeleted": "फ़ोल्डर \"{{folder}}\" से {{count}} होस्ट सफलतापूर्वक हटा दिए गए।",
|
||||
"confirmDeleteAllHostsInFolder": "क्या आप वाकई फोल्डर \"{{folder}}\" में मौजूद सभी {{count}} होस्ट को हटाना चाहते हैं? यह कार्रवाई पूर्ववत नहीं की जा सकती।",
|
||||
"allHostsInFolderDeleted": "फ़ोल्डर \"{{folder}}\" से {{count}} होस्ट सफलतापूर्वक हटा दिए गए",
|
||||
"failedToDeleteHostsInFolder": "फ़ोल्डर में होस्ट को हटाने में विफल रहा",
|
||||
"movedToFolder": "होस्ट \"{{folder}}\" सफलतापूर्वक \"{{name}}\" पर स्थानांतरित हो गया।",
|
||||
"movedToFolder": "होस्ट \"{{name}}\" सफलतापूर्वक \"{{folder}}\" पर स्थानांतरित हो गया",
|
||||
"failedToMoveToFolder": "होस्ट को फ़ोल्डर में ले जाने में विफल",
|
||||
"clickToRenameFolder": "फ़ोल्डर का नाम बदलने के लिए क्लिक करें",
|
||||
"renameFolder": "फ़ोल्डर का नाम बदलें",
|
||||
@@ -943,7 +943,7 @@
|
||||
"cloneHostTooltip": "क्लोन होस्ट",
|
||||
"clickToEditHost": "होस्ट को संपादित करने के लिए क्लिक करें",
|
||||
"dragToMoveBetweenFolders": "फ़ोल्डरों के बीच जाने के लिए ड्रैग करें",
|
||||
"exportedHostConfig": "{{folder}} के लिए निर्यातित होस्ट कॉन्फ़िगरेशन",
|
||||
"exportedHostConfig": "{{name}}के लिए निर्यातित होस्ट कॉन्फ़िगरेशन",
|
||||
"openTerminal": "टर्मिनल खोलें",
|
||||
"openFileManager": "फ़ाइल प्रबंधक खोलें",
|
||||
"openTunnels": "खुली सुरंगें",
|
||||
@@ -961,7 +961,7 @@
|
||||
"metricsEnabled": "मैट्रिक्स मॉनिटरिंग सक्षम करें",
|
||||
"metricsEnabledDesc": "सीपीयू, रैम, डिस्क और अन्य सिस्टम सांख्यिकी एकत्र करें",
|
||||
"metricsInterval": "मैट्रिक्स संग्रह अंतराल",
|
||||
"metricsIntervalDesc": "सर्वर सांख्यिकी कितनी बार एकत्र करें (5 सेकंड - 1 घंटा)",
|
||||
"metricsIntervalDesc": "सर्वर सांख्यिकी को कितनी बार एकत्र करना है (5 सेकंड - 1 घंटा)",
|
||||
"intervalSeconds": "सेकंड",
|
||||
"intervalMinutes": "मिनट",
|
||||
"intervalValidation": "निगरानी अंतराल 5 सेकंड और 1 घंटे (3600 सेकंड) के बीच होना चाहिए।",
|
||||
@@ -982,13 +982,13 @@
|
||||
"selectFont": "फ़ॉन्ट चुनें",
|
||||
"selectFontDesc": "टर्मिनल में उपयोग करने के लिए फ़ॉन्ट का चयन करें",
|
||||
"fontSize": "फ़ॉन्ट आकार",
|
||||
"fontSizeValue": "फ़ॉन्ट का आकार: {{name}}px",
|
||||
"fontSizeValue": "फ़ॉन्ट आकार: {{value}}px",
|
||||
"adjustFontSize": "टर्मिनल फ़ॉन्ट का आकार समायोजित करें",
|
||||
"letterSpacing": "पत्र अंतराल",
|
||||
"letterSpacingValue": "अक्षरों के बीच की दूरी: {{value}}px",
|
||||
"adjustLetterSpacing": "अक्षरों के बीच की दूरी समायोजित करें",
|
||||
"lineHeight": "ऊंची लाईन",
|
||||
"lineHeightValue": "पंक्ति की ऊँचाई: {{value}}",
|
||||
"lineHeightValue": "लाइन की ऊँचाई: {{value}}",
|
||||
"adjustLineHeight": "पंक्तियों के बीच की दूरी समायोजित करें",
|
||||
"cursorStyle": "कर्सर शैली",
|
||||
"selectCursorStyle": "कर्सर शैली का चयन करें",
|
||||
@@ -997,7 +997,7 @@
|
||||
"cursorStyleBar": "छड़",
|
||||
"chooseCursorAppearance": "कर्सर का स्वरूप चुनें",
|
||||
"cursorBlink": "कर्सर ब्लिंक",
|
||||
"enableCursorBlink": "कर्सर ब्लिंकिंग एनीमेशन को सक्षम करें",
|
||||
"enableCursorBlink": "कर्सर ब्लिंकिंग एनीमेशन सक्षम करें",
|
||||
"scrollbackBuffer": "स्क्रॉलबैक बफर",
|
||||
"scrollbackBufferValue": "स्क्रॉलबैक बफर: {{value}} पंक्तियाँ",
|
||||
"scrollbackBufferDesc": "स्क्रॉलबैक इतिहास में रखी जाने वाली पंक्तियों की संख्या",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "आवाज़",
|
||||
"bellStyleVisual": "तस्वीर",
|
||||
"bellStyleBoth": "दोनों",
|
||||
"bellStyleDesc": "टर्मिनल बेल (BEL कैरेक्टर, \\x07) को कैसे हैंडल करें। प्रोग्राम कार्य पूरा होने, त्रुटियाँ आने या सूचनाओं के लिए इसे ट्रिगर करते हैं। \"साउंड\" एक ऑडियो बीप बजाता है, \"विजुअल\" स्क्रीन को थोड़ी देर के लिए फ्लैश करता है, \"बोथ\" दोनों करता है, और \"नन\" बेल अलर्ट को निष्क्रिय कर देता है।",
|
||||
"bellStyleDesc": "टर्मिनल बेल (BEL कैरेक्टर, \\x07) को कैसे हैंडल करें। प्रोग्राम कार्य पूरा होने पर, त्रुटियाँ आने पर या सूचनाओं के लिए इसे ट्रिगर करते हैं। \"साउंड\" एक ऑडियो बीप बजाता है, \"विजुअल\" स्क्रीन को थोड़ी देर के लिए फ्लैश करता है, \"बोथ\" दोनों करता है, और \"नन\" बेल अलर्ट को डिसेबल कर देता है।",
|
||||
"rightClickSelectsWord": "दायाँ क्लिक करने पर वर्ड का चयन होता है",
|
||||
"rightClickSelectsWordDesc": "दाएँ क्लिक करने से कर्सर के नीचे का शब्द चयनित हो जाता है।",
|
||||
"fastScrollModifier": "फास्ट स्क्रॉल मॉडिफायर",
|
||||
@@ -1066,7 +1066,7 @@
|
||||
"socks5UsePreset": "सहेजे गए प्रीसेट का उपयोग करें",
|
||||
"socks5SelectPreset": "प्रीसेट चुनें",
|
||||
"socks5ManagePresets": "प्रीसेट प्रबंधित करें",
|
||||
"socks5ProxyNode": "प्रॉक्सी {{value}}",
|
||||
"socks5ProxyNode": "प्रॉक्सी {{number}}",
|
||||
"socks5AddProxy": "चेन में प्रॉक्सी जोड़ें",
|
||||
"socks5RemoveProxy": "प्रॉक्सी हटाएं",
|
||||
"socks5ProxyType": "प्रॉक्सी प्रकार",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "प्रॉक्सी चेन प्रीसेट बनाया गया",
|
||||
"socks5PresetUpdated": "प्रॉक्सी चेन प्रीसेट अपडेट किया गया",
|
||||
"socks5PresetDeleted": "प्रॉक्सी चेन प्रीसेट हटा दिया गया",
|
||||
"socks5PresetSaved": "प्रीसेट \"{{number}}\" सफलतापूर्वक सहेजा गया",
|
||||
"socks5PresetSaved": "प्रीसेट \"{{name}}\" सफलतापूर्वक सहेजा गया",
|
||||
"socks5PresetSaveError": "प्रीसेट सहेजने में विफल",
|
||||
"socks5PresetNameRequired": "प्रीसेट नाम आवश्यक है",
|
||||
"socks5EmptyChainError": "खाली प्रॉक्सी चेन को सहेजा नहीं जा सकता",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"socks5HostDescription": "SOCKS प्रॉक्सी सर्वर का होस्टनाम या IP पता",
|
||||
"socks5PortDescription": "SOCKS प्रॉक्सी सर्वर का पोर्ट नंबर (डिफ़ॉल्ट: 1080)",
|
||||
"addProxyNode": "प्रॉक्सी नोड जोड़ें",
|
||||
"noProxyNodes": "कोई प्रॉक्सी नोड कॉन्फ़िगर नहीं किया गया है। एक प्रॉक्सी नोड जोड़ने के लिए \"प्रॉक्सी नोड जोड़ें\" पर क्लिक करें।",
|
||||
"noProxyNodes": "कोई प्रॉक्सी नोड कॉन्फ़िगर नहीं किया गया है। एक प्रॉक्सी नोड जोड़ने के लिए 'प्रॉक्सी नोड जोड़ें' पर क्लिक करें।",
|
||||
"proxyNode": "प्रॉक्सी नोड",
|
||||
"proxyType": "प्रॉक्सी प्रकार",
|
||||
"quickActions": "त्वरित कार्रवाइयां",
|
||||
@@ -1118,8 +1118,8 @@
|
||||
"notEnabled": "इस होस्ट के लिए डॉकर सक्षम नहीं है। डॉकर सुविधाओं का उपयोग करने के लिए इसे होस्ट सेटिंग्स में सक्षम करें।",
|
||||
"validating": "डॉकर का सत्यापन किया जा रहा है...",
|
||||
"error": "गलती",
|
||||
"errorCode": "त्रुटि कोड: {{name}}",
|
||||
"version": "डॉकर v{{code}}",
|
||||
"errorCode": "त्रुटि कोड: {{code}}",
|
||||
"version": "डॉकर v{{version}}",
|
||||
"current": "मौजूदा",
|
||||
"used_limit": "उपयोग किया गया / सीमा",
|
||||
"percentage": "को PERCENTAGE",
|
||||
@@ -1133,10 +1133,10 @@
|
||||
"console": "सांत्वना देना",
|
||||
"containerMustBeRunning": "कंसोल से कनेक्ट करने के लिए कंटेनर का चालू होना आवश्यक है।",
|
||||
"authenticationRequired": "प्रमाणित करना",
|
||||
"connectedTo": "{{version}} से जुड़ा हुआ है",
|
||||
"connectedTo": "{{containerName}}से जुड़ा हुआ",
|
||||
"disconnected": "डिस्कनेक्ट किया गया",
|
||||
"consoleError": "कंसोल त्रुटि",
|
||||
"errorMessage": "त्रुटि: {{containerName}}",
|
||||
"errorMessage": "त्रुटि: {{message}}",
|
||||
"failedToConnect": "कंसोल से कनेक्ट करने में विफल",
|
||||
"disconnectedFromContainer": "कंटेनर कंसोल से संपर्क टूट गया।",
|
||||
"containerNotRunning": "कंटेनर नहीं चल रहा है",
|
||||
@@ -1150,28 +1150,28 @@
|
||||
"disconnect": "डिस्कनेक्ट",
|
||||
"notConnected": "जुड़े नहीं हैं",
|
||||
"clickToConnect": "इंटरेक्टिव शेल शुरू करने के लिए कनेक्ट पर क्लिक करें",
|
||||
"connectingTo": "{{message}} से कनेक्ट हो रहा है...",
|
||||
"connectingTo": "{{containerName}}से कनेक्ट हो रहा है...",
|
||||
"containerMustBeRunningToViewStats": "आंकड़े देखने के लिए कंटेनर का चालू होना आवश्यक है।",
|
||||
"failedToFetchStats": "आंकड़े प्राप्त करने में विफल",
|
||||
"noContainersFound": "कोई कंटेनर नहीं मिला",
|
||||
"noContainersFoundHint": "सबसे पहले अपने सर्वर पर कंटेनर बनाएं।",
|
||||
"searchPlaceholder": "नाम, छवि या आईडी के आधार पर खोजें...",
|
||||
"filterByStatusPlaceholder": "स्थिति के अनुसार फ़िल्टर करें",
|
||||
"allContainersCount": "सभी ({{containerName}})",
|
||||
"statusCount": "{{count}} ({{status}})",
|
||||
"allContainersCount": "सभी ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "आपके फ़िल्टर से कोई कंटेनर मेल नहीं खाता।",
|
||||
"noContainersMatchFiltersHint": "अपनी खोज या फ़िल्टर को समायोजित करने का प्रयास करें",
|
||||
"containerStarted": "कंटेनर {{count}} शुरू हो गया",
|
||||
"failedToStartContainer": "कंटेनर शुरू करने में विफल: {{name}}",
|
||||
"containerStopped": "कंटेनर {{error}} रुक गया",
|
||||
"failedToStopContainer": "कंटेनर को रोकने में विफल: {{name}}",
|
||||
"containerRestarted": "कंटेनर {{error}} पुनः आरंभ हो गया",
|
||||
"failedToRestartContainer": "कंटेनर को पुनः आरंभ करने में विफल: {{name}}",
|
||||
"containerUnpaused": "कंटेनर {{error}} अनपॉज़ किया गया",
|
||||
"containerStarted": "कंटेनर {{name}} शुरू हो गया",
|
||||
"failedToStartContainer": "कंटेनर शुरू करने में विफल: {{error}}",
|
||||
"containerStopped": "कंटेनर {{name}} रुक गया",
|
||||
"failedToStopContainer": "कंटेनर को रोकने में विफल: {{error}}",
|
||||
"containerRestarted": "कंटेनर {{name}} पुनः आरंभ हुआ",
|
||||
"failedToRestartContainer": "कंटेनर को पुनः आरंभ करने में विफल: {{error}}",
|
||||
"containerUnpaused": "कंटेनर {{name}} अनपॉज़ किया गया",
|
||||
"containerPaused": "कंटेनर {{name}} रुका हुआ है",
|
||||
"failedToTogglePauseContainer": "{{name}} कंटेनर विफल: {{action}}",
|
||||
"containerRemoved": "कंटेनर {{error}} हटा दिया गया",
|
||||
"failedToRemoveContainer": "कंटेनर हटाने में विफल: {{name}}",
|
||||
"failedToTogglePauseContainer": "{{action}} कंटेनर में प्रवेश करने में विफल: {{error}}",
|
||||
"containerRemoved": "कंटेनर {{name}} हटा दिया गया",
|
||||
"failedToRemoveContainer": "कंटेनर हटाने में विफल: {{error}}",
|
||||
"image": "छवि:",
|
||||
"idLabel": "पहचान:",
|
||||
"ports": "बंदरगाह:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "विराम",
|
||||
"restart": "पुनः आरंभ करें",
|
||||
"removeContainer": "कंटेनर हटाएँ",
|
||||
"confirmRemoveContainer": "क्या आप वाकई कंटेनर \"{{error}}\" को हटाना चाहते हैं?",
|
||||
"confirmRemoveContainer": "क्या आप वाकई कंटेनर \"{{name}}\" को हटाना चाहते हैं?",
|
||||
"runningContainerWarning": "चेतावनी: यह कंटेनर वर्तमान में चल रहा है और इसे जबरन हटा दिया जाएगा।",
|
||||
"removing": "हटाना:",
|
||||
"containerNotFound": "कंटेनर नहीं मिला",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"logs": "लॉग्स",
|
||||
"stats": "आँकड़े",
|
||||
"consoleTab": "सांत्वना देना",
|
||||
"failedToFetchLogs": "लॉग प्राप्त करने में विफल: {{name}}",
|
||||
"failedToFetchLogs": "लॉग प्राप्त करने में विफल: {{error}}",
|
||||
"failedToDownloadLogs": "लॉग डाउनलोड करने में विफल: {{error}}",
|
||||
"linesToShow": "दिखाने के लिए रेखाएँ",
|
||||
"last50Lines": "अंतिम 50 पंक्तियाँ",
|
||||
@@ -1219,7 +1219,7 @@
|
||||
"reconnect": "रिकनेक्ट",
|
||||
"sessionEnded": "सत्र समाप्त हुआ",
|
||||
"connectionLost": "कनेक्शन टूट गया",
|
||||
"error": "त्रुटि: {{error}}",
|
||||
"error": "त्रुटि: {{message}}",
|
||||
"disconnected": "डिस्कनेक्ट किया गया",
|
||||
"connectionClosed": "कनेक्शन बंद हो गया",
|
||||
"connectionError": "कनेक्शन त्रुटि: {{message}}",
|
||||
@@ -1230,13 +1230,13 @@
|
||||
"messageParseError": "सर्वर संदेश को पार्स करने में विफल",
|
||||
"websocketError": "वेबसॉकेट कनेक्शन त्रुटि",
|
||||
"connecting": "कनेक्ट हो रहा है...",
|
||||
"reconnecting": "पुनः कनेक्ट हो रहा है... ({{message}}/{{attempt}})",
|
||||
"reconnecting": "पुनः कनेक्ट हो रहा है... ({{attempt}}/{{max}})",
|
||||
"reconnected": "सफलतापूर्वक पुनः कनेक्ट हो गया",
|
||||
"maxReconnectAttemptsReached": "अधिकतम पुनः कनेक्शन प्रयासों की सीमा पूरी हो गई है।",
|
||||
"connectionTimeout": "रिश्तों का समय बाहर",
|
||||
"terminalTitle": "टर्मिनल - {{max}}",
|
||||
"terminalWithPath": "टर्मिनल - {{host}}:{{host}}",
|
||||
"runTitle": "चल रहा है {{path}} - {{command}}",
|
||||
"terminalTitle": "टर्मिनल - {{host}}",
|
||||
"terminalWithPath": "टर्मिनल - {{host}}:{{path}}",
|
||||
"runTitle": "चल रहा है {{command}} - {{host}}",
|
||||
"totpRequired": "दो-कारक प्रमाणीकरण आवश्यक है",
|
||||
"totpCodeLabel": "सत्यापन कोड",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1254,26 +1254,26 @@
|
||||
"uploadFile": "फ़ाइल अपलोड करें",
|
||||
"downloadFile": "डाउनलोड करना",
|
||||
"extractArchive": "संग्रह निकालें",
|
||||
"extractingArchive": "{{host}} को निकाला जा रहा है...",
|
||||
"extractingArchive": "{{name}}का निष्कर्षण ...",
|
||||
"archiveExtractedSuccessfully": "{{name}} सफलतापूर्वक निकाला गया",
|
||||
"extractFailed": "निष्कर्षण विफल रहा",
|
||||
"compressFile": "फ़ाइल को संपीड़ित करें",
|
||||
"compressFiles": "फ़ाइलों को संपीड़ित करें",
|
||||
"compressFilesDesc": "{{name}} आइटमों को एक संग्रह में संपीड़ित करें",
|
||||
"compressFilesDesc": "{{count}} आइटमों को एक संग्रह में संपीड़ित करें",
|
||||
"archiveName": "संग्रह नाम",
|
||||
"enterArchiveName": "आर्काइव का नाम दर्ज करें...",
|
||||
"compressionFormat": "संपीड़न प्रारूप",
|
||||
"selectedFiles": "चयनित फ़ाइलें",
|
||||
"andMoreFiles": "और {{count}} और...",
|
||||
"andMoreFiles": "और {{count}} अधिक...",
|
||||
"compress": "संकुचित करें",
|
||||
"compressingFiles": "{{count}} आइटमों को {{count}} में संपीड़ित किया जा रहा है...",
|
||||
"filesCompressedSuccessfully": "{{name}} सफलतापूर्वक बनाया गया",
|
||||
"compressingFiles": "{{count}} आइटमों को {{name}}में संपीड़ित करना...",
|
||||
"filesCompressedSuccessfully": "{{name}} सफलतापूर्वक निर्मित",
|
||||
"compressFailed": "संपीड़न विफल रहा",
|
||||
"edit": "संपादन करना",
|
||||
"preview": "पूर्व दर्शन",
|
||||
"previous": "पहले का",
|
||||
"next": "अगला",
|
||||
"pageXOfY": "पृष्ठ {{name}} का {{current}}",
|
||||
"pageXOfY": "पृष्ठ {{current}} का {{total}}",
|
||||
"zoomOut": "ज़ूम आउट",
|
||||
"zoomIn": "ज़ूम इन",
|
||||
"newFile": "नई फ़ाइल",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "फाइलें चुनें",
|
||||
"uploading": "अपलोड हो रहा है...",
|
||||
"downloading": "डाउनलोड हो रहा है...",
|
||||
"uploadingFile": "{{total}} अपलोड हो रहा है...",
|
||||
"uploadingLargeFile": "बड़ी फ़ाइल {{name}} ({{name}}) अपलोड की जा रही है...",
|
||||
"downloadingFile": "{{size}} डाउनलोड हो रहा है...",
|
||||
"creatingFile": "{{name}} का निर्माण हो रहा है...",
|
||||
"creatingFolder": "{{name}} का निर्माण हो रहा है...",
|
||||
"deletingItem": "{{name}} {{type}} को हटाया जा रहा है...",
|
||||
"renamingItem": "{{name}} {{type}} का नाम बदलकर {{oldName}} किया जा रहा है...",
|
||||
"uploadingFile": "अपलोड हो रहा है {{name}}...",
|
||||
"uploadingLargeFile": "बड़ी फ़ाइल अपलोड हो रही है {{name}} ({{size}})...",
|
||||
"downloadingFile": "डाउनलोड हो रहा है {{name}}...",
|
||||
"creatingFile": "{{name}}का निर्माण हो रहा है...",
|
||||
"creatingFolder": "{{name}}का निर्माण हो रहा है...",
|
||||
"deletingItem": "{{type}} {{name}}को हटा रहा है...",
|
||||
"renamingItem": "{{type}} {{oldName}} का नाम बदलकर {{newName}}किया जा रहा है...",
|
||||
"createNewFile": "नई फ़ाइल बनाएँ",
|
||||
"fileName": "फ़ाइल नाम",
|
||||
"creating": "सृजन...",
|
||||
@@ -1311,7 +1311,7 @@
|
||||
"newName": "नया नाम",
|
||||
"thisIsDirectoryRename": "यह एक निर्देशिका है",
|
||||
"renaming": "नाम बदला जा रहा है...",
|
||||
"fileUploadedSuccessfully": "फ़ाइल \"{{newName}}\" सफलतापूर्वक अपलोड हो गई",
|
||||
"fileUploadedSuccessfully": "फ़ाइल \"{{name}}\" सफलतापूर्वक अपलोड हो गई",
|
||||
"failedToUploadFile": "फ़ाइल अपलोड करने में विफल",
|
||||
"fileDownloadedSuccessfully": "फ़ाइल \"{{name}}\" सफलतापूर्वक डाउनलोड हो गई",
|
||||
"failedToDownloadFile": "फ़ाइल डाउनलोड करने में विफल",
|
||||
@@ -1322,10 +1322,10 @@
|
||||
"folderCreatedSuccessfully": "फ़ोल्डर \"{{name}}\" सफलतापूर्वक बनाया गया",
|
||||
"failedToCreateFolder": "फ़ोल्डर बनाने में विफल",
|
||||
"failedToCreateItem": "आइटम बनाने में विफल",
|
||||
"operationFailed": "{{name}} ऑपरेशन {{operation}} के लिए विफल रहा: {{name}}",
|
||||
"operationFailed": "{{operation}} ऑपरेशन {{name}}के लिए विफल रहा : {{error}}",
|
||||
"failedToResolveSymlink": "सिम्लिंक को हल करने में विफल",
|
||||
"itemDeletedSuccessfully": "{{error}} सफलतापूर्वक हटा दिया गया",
|
||||
"itemsDeletedSuccessfully": "{{type}} आइटम सफलतापूर्वक हटा दिए गए",
|
||||
"itemDeletedSuccessfully": "{{type}} सफलतापूर्वक हटा दिया गया",
|
||||
"itemsDeletedSuccessfully": "{{count}} आइटम सफलतापूर्वक हटा दिए गए",
|
||||
"failedToDeleteItems": "आइटम हटाने में विफल",
|
||||
"dragFilesToUpload": "फ़ाइलें अपलोड करने के लिए उन्हें यहाँ ड्रॉप करें",
|
||||
"emptyFolder": "यह फ़ोल्डर खाली है",
|
||||
@@ -1335,7 +1335,7 @@
|
||||
"upload": "अपलोड करें",
|
||||
"selectHostToStart": "फ़ाइल प्रबंधन शुरू करने के लिए एक होस्ट चुनें",
|
||||
"failedToConnect": "एसएसएच से कनेक्ट करने में विफल",
|
||||
"failedToLoadDirectory": "डायरेक्टरी लोड करने में विफल",
|
||||
"failedToLoadDirectory": "निर्देशिका लोड करने में विफल",
|
||||
"noSSHConnection": "कोई SSH कनेक्शन उपलब्ध नहीं है",
|
||||
"enterFolderName": "फ़ोल्डर का नाम दर्ज करें:",
|
||||
"enterFileName": "फ़ाइल का नाम दर्ज करें:",
|
||||
@@ -1348,24 +1348,24 @@
|
||||
"properties": "गुण",
|
||||
"refresh": "ताज़ा करना",
|
||||
"downloadFiles": "ब्राउज़र में {{count}} फ़ाइलें डाउनलोड करें",
|
||||
"copyFiles": "{{count}} आइटम कॉपी करें",
|
||||
"copyFiles": "आइटम कॉपी करें {{count}}",
|
||||
"cutFiles": "{{count}} आइटम काटें",
|
||||
"deleteFiles": "{{count}} आइटम हटाएं",
|
||||
"filesCopiedToClipboard": "{{count}} आइटम क्लिपबोर्ड पर कॉपी किए गए",
|
||||
"filesCutToClipboard": "क्लिपबोर्ड पर {{count}} आइटम काटे गए",
|
||||
"filesCopiedToClipboard": "{{count}} आइटम क्लिपबोर्ड पर कॉपी हो गए",
|
||||
"filesCutToClipboard": "{{count}} आइटम क्लिपबोर्ड पर सेव हो गए",
|
||||
"pathCopiedToClipboard": "पथ क्लिपबोर्ड पर कॉपी हो गया",
|
||||
"pathsCopiedToClipboard": "क्लिपबोर्ड पर {{count}} पथ कॉपी किए गए",
|
||||
"pathsCopiedToClipboard": "{{count}} पथ क्लिपबोर्ड पर कॉपी किए गए",
|
||||
"failedToCopyPath": "क्लिपबोर्ड पर पथ कॉपी करने में विफल",
|
||||
"movedItems": "{{count}} आइटम स्थानांतरित किए गए",
|
||||
"failedToDeleteItem": "आइटम हटाने में विफल",
|
||||
"itemRenamedSuccessfully": "{{count}} का नाम सफलतापूर्वक बदल दिया गया",
|
||||
"itemRenamedSuccessfully": "{{type}} का नाम सफलतापूर्वक बदल दिया गया",
|
||||
"failedToRenameItem": "आइटम का नाम बदलने में विफल",
|
||||
"download": "डाउनलोड करना",
|
||||
"permissions": "अनुमतियां",
|
||||
"size": "आकार",
|
||||
"modified": "संशोधित",
|
||||
"path": "पथ",
|
||||
"confirmDelete": "क्या आप वाकई {{type}} को हटाना चाहते हैं?",
|
||||
"confirmDelete": "क्या आप वाकई {{name}}को हटाना चाहते हैं?",
|
||||
"uploadSuccess": "फ़ाइल सफलतापूर्वक अपलोड की गई",
|
||||
"uploadFailed": "फ़ाइल अपलोड विफल",
|
||||
"downloadSuccess": "फ़ाइल सफलतापूर्वक डाउनलोड हो गई",
|
||||
@@ -1388,11 +1388,11 @@
|
||||
"connectToServer": "सर्वर से कनेक्ट करें",
|
||||
"selectServerToEdit": "फ़ाइलों को संपादित करना शुरू करने के लिए साइडबार से एक सर्वर चुनें।",
|
||||
"fileOperations": "फ़ाइल संचालन",
|
||||
"confirmDeleteMessage": "क्या आप वाकई {{name}} को हटाना चाहते हैं?",
|
||||
"confirmDeleteMessage": "क्या आप वाकई {{name}}को हटाना चाहते हैं?",
|
||||
"confirmDeleteSingleItem": "क्या आप वाकई \"{{name}}\" को स्थायी रूप से हटाना चाहते हैं?",
|
||||
"confirmDeleteMultipleItems": "क्या आप वाकई {{name}} आइटम को स्थायी रूप से हटाना चाहते हैं?",
|
||||
"confirmDeleteMultipleItems": "क्या आप वाकई {{count}} आइटम को स्थायी रूप से हटाना चाहते हैं?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "क्या आप वाकई {{count}} आइटम को स्थायी रूप से हटाना चाहते हैं? इसमें फ़ोल्डर और उनकी सामग्री शामिल है।",
|
||||
"confirmDeleteFolder": "क्या आप वाकई फ़ोल्डर \"{{count}}\" और उसकी सभी सामग्री को स्थायी रूप से हटाना चाहते हैं?",
|
||||
"confirmDeleteFolder": "क्या आप वाकई फोल्डर \"{{name}}\" और उसकी सभी सामग्री को स्थायी रूप से हटाना चाहते हैं?",
|
||||
"deleteDirectoryWarning": "इससे फोल्डर और उसके अंदर की सभी सामग्री डिलीट हो जाएगी।",
|
||||
"actionCannotBeUndone": "इस एक्शन को वापस नहीं किया जा सकता।",
|
||||
"permanentDeleteWarning": "यह कार्रवाई पूर्ववत नहीं की जा सकती। आइटम सर्वर से स्थायी रूप से हटा दिए जाएंगे।",
|
||||
@@ -1421,14 +1421,14 @@
|
||||
"selectLocationToSave": "सहेजने के लिए स्थान चुनें",
|
||||
"openTerminalInFolder": "इस फ़ोल्डर में टर्मिनल खोलें",
|
||||
"openTerminalInFileLocation": "फ़ाइल स्थान पर टर्मिनल खोलें",
|
||||
"terminalWithPath": "टर्मिनल - {{name}}:{{host}}",
|
||||
"runningFile": "चल रहा है - {{path}}",
|
||||
"terminalWithPath": "टर्मिनल - {{host}}:{{path}}",
|
||||
"runningFile": "दौड़ना - {{file}}",
|
||||
"onlyRunExecutableFiles": "केवल निष्पादन योग्य फ़ाइलें ही चला सकते हैं",
|
||||
"noHostSelected": "कोई होस्ट चयनित नहीं है",
|
||||
"starred": "तारांकित",
|
||||
"shortcuts": "शॉर्टकट",
|
||||
"directories": "निर्देशिका",
|
||||
"removedFromRecentFiles": "हाल की फ़ाइलों से \"{{file}}\" हटा दिया गया",
|
||||
"removedFromRecentFiles": "हाल की फ़ाइलों से \"{{name}}\" हटा दिया गया है",
|
||||
"removeFailed": "हटाने में विफलता",
|
||||
"unpinnedSuccessfully": "\"{{name}}\" को सफलतापूर्वक अनपिन कर दिया गया",
|
||||
"unpinFailed": "अनपिन विफल",
|
||||
@@ -1437,10 +1437,10 @@
|
||||
"clearedAllRecentFiles": "सभी हालिया फ़ाइलें हटा दी गईं",
|
||||
"clearFailed": "क्लियर विफल",
|
||||
"removeFromRecentFiles": "हाल की फ़ाइलों से हटाएँ",
|
||||
"clearAllRecentFiles": "सभी हाल की फ़ाइलें साफ़ करें",
|
||||
"clearAllRecentFiles": "सभी हालिया फ़ाइलें साफ़ करें",
|
||||
"unpinFile": "फ़ाइल को अनपिन करें",
|
||||
"removeShortcut": "शॉर्टकट हटाएँ",
|
||||
"saveFilesToSystem": "{{name}} फ़ाइलों को इस रूप में सहेजें...",
|
||||
"saveFilesToSystem": "{{count}} फ़ाइलों को इस रूप में सहेजें...",
|
||||
"pinFile": "पिन फ़ाइल",
|
||||
"addToShortcuts": "शॉर्टकट में जोड़ें",
|
||||
"downloadToDefaultLocation": "डिफ़ॉल्ट स्थान पर डाउनलोड करें",
|
||||
@@ -1449,7 +1449,7 @@
|
||||
"undoCopySuccess": "कॉपी करने की प्रक्रिया पूर्ववत की गई: कॉपी की गई {{count}} फ़ाइलें हटाई गईं",
|
||||
"undoCopyFailedDelete": "पूर्ववत करने का प्रयास विफल: प्रतिलिपि की गई कोई भी फ़ाइल हटाई नहीं जा सकी",
|
||||
"undoCopyFailedNoInfo": "पूर्ववत करने में विफल: प्रतिलिपि की गई फ़ाइल की जानकारी नहीं मिल सकी",
|
||||
"undoMoveSuccess": "स्थानांतरण प्रक्रिया को पूर्ववत किया गया: {{count}} फ़ाइलें वापस मूल स्थान पर स्थानांतरित कर दी गईं",
|
||||
"undoMoveSuccess": "स्थानांतरण प्रक्रिया को पूर्ववत किया गया: {{count}} फ़ाइलों को वापस मूल स्थान पर स्थानांतरित कर दिया गया",
|
||||
"undoMoveFailedMove": "पूर्ववत करने में विफल: कोई भी फ़ाइल वापस नहीं ले जा सका",
|
||||
"undoMoveFailedNoInfo": "पूर्ववत करने में विफल: स्थानांतरित फ़ाइल की जानकारी नहीं मिल सकी",
|
||||
"undoDeleteNotSupported": "डिलीट ऑपरेशन को पूर्ववत नहीं किया जा सकता: फ़ाइलें सर्वर से स्थायी रूप से हटा दी गई हैं।",
|
||||
@@ -1491,33 +1491,33 @@
|
||||
"unknownSize": "अज्ञात आकार",
|
||||
"fileIsEmpty": "फ़ाइल खाली है",
|
||||
"largeFileWarning": "बड़ी फ़ाइल संबंधी चेतावनी",
|
||||
"largeFileWarningDesc": "इस फ़ाइल का आकार {{count}} है, जिससे टेक्स्ट के रूप में खोलने पर प्रदर्शन संबंधी समस्याएँ उत्पन्न हो सकती हैं।",
|
||||
"fileNotFoundAndRemoved": "फ़ाइल \"{{size}}\" नहीं मिली और इसे हाल ही में/पिन की गई फ़ाइलों से हटा दिया गया है।",
|
||||
"failedToLoadFile": "फ़ाइल लोड करने में विफल: {{name}}",
|
||||
"largeFileWarningDesc": "इस फ़ाइल का आकार {{size}} है, जिससे टेक्स्ट के रूप में खोलने पर प्रदर्शन संबंधी समस्याएँ उत्पन्न हो सकती हैं।",
|
||||
"fileNotFoundAndRemoved": "फ़ाइल \"{{name}}\" नहीं मिली और इसे हाल ही में/पिन की गई फ़ाइलों से हटा दिया गया है",
|
||||
"failedToLoadFile": "फ़ाइल लोड करने में विफल: {{error}}",
|
||||
"serverErrorOccurred": "सर्वर में त्रुटि आ गई है। कृपया बाद में पुनः प्रयास करें।",
|
||||
"autoSaveFailed": "ऑटो-सेव विफल रहा",
|
||||
"fileAutoSaved": "फ़ाइल स्वतः सहेजी गई",
|
||||
"moveFileFailed": "{{error}} को स्थानांतरित करने में विफल",
|
||||
"moveFileFailed": "{{name}}को स्थानांतरित करने में विफल",
|
||||
"moveOperationFailed": "स्थानांतरण प्रक्रिया विफल रही",
|
||||
"canOnlyCompareFiles": "केवल दो फाइलों की तुलना की जा सकती है",
|
||||
"comparingFiles": "फ़ाइलों की तुलना: {{name}} और {{file1}}",
|
||||
"comparingFiles": "फ़ाइलों की तुलना: {{file1}} और {{file2}}",
|
||||
"dragFailed": "ड्रैग ऑपरेशन विफल रहा",
|
||||
"filePinnedSuccessfully": "फ़ाइल \"{{file2}}\" सफलतापूर्वक पिन हो गई",
|
||||
"filePinnedSuccessfully": "फ़ाइल \"{{name}}\" सफलतापूर्वक पिन कर दी गई",
|
||||
"pinFileFailed": "फ़ाइल को पिन करने में विफल",
|
||||
"fileUnpinnedSuccessfully": "फ़ाइल \"{{name}}\" सफलतापूर्वक अनपिन कर दी गई।",
|
||||
"fileUnpinnedSuccessfully": "फ़ाइल \"{{name}}\" सफलतापूर्वक अनपिन कर दी गई",
|
||||
"unpinFileFailed": "फ़ाइल को अनपिन करने में विफल",
|
||||
"shortcutAddedSuccessfully": "फ़ोल्डर शॉर्टकट \"{{name}}\" सफलतापूर्वक जोड़ दिया गया",
|
||||
"addShortcutFailed": "शॉर्टकट जोड़ने में विफल",
|
||||
"operationCompletedSuccessfully": "{{name}} {{operation}} आइटम सफलतापूर्वक",
|
||||
"operationCompleted": "{{count}} {{operation}} आइटम",
|
||||
"downloadFileSuccess": "फ़ाइल {{count}} सफलतापूर्वक डाउनलोड हो गई",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} आइटम सफलतापूर्वक",
|
||||
"operationCompleted": "{{operation}} {{count}} आइटम",
|
||||
"downloadFileSuccess": "फ़ाइल {{name}} सफलतापूर्वक डाउनलोड हो गई",
|
||||
"downloadFileFailed": "डाउनलोड विफल रहा",
|
||||
"moveTo": "{{name}} पर जाएँ",
|
||||
"diffCompareWith": "{{name}} के साथ अंतर की तुलना करें",
|
||||
"dragOutsideToDownload": "डाउनलोड करने के लिए विंडो के बाहर खींचें ({{name}} फ़ाइलें)",
|
||||
"moveTo": "{{name}}पर जाएँ",
|
||||
"diffCompareWith": "{{name}}के साथ अंतर की तुलना करें",
|
||||
"dragOutsideToDownload": "फ़ाइलें डाउनलोड करने के लिए विंडो के बाहर खींचें ({{count}} फ़ाइलें)",
|
||||
"newFolderDefault": "नया फ़ोल्डर",
|
||||
"newFileDefault": "NewFile.txt",
|
||||
"successfullyMovedItems": "{{count}} आइटम सफलतापूर्वक {{count}} में स्थानांतरित कर दिए गए।",
|
||||
"successfullyMovedItems": "{{count}} आइटम सफलतापूर्वक {{target}}में स्थानांतरित कर दिए गए हैं।",
|
||||
"move": "कदम",
|
||||
"searchInFile": "फ़ाइल में खोजें (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "कीबोर्ड शॉर्टकट दिखाएँ",
|
||||
@@ -1527,10 +1527,10 @@
|
||||
"compare": "तुलना करना",
|
||||
"sideBySide": "अगल बगल",
|
||||
"inline": "इन - लाइन",
|
||||
"fileComparison": "फ़ाइल तुलना: {{target}} बनाम {{file1}}",
|
||||
"fileTooLarge": "फ़ाइल का आकार बहुत बड़ा है: {{file2}}",
|
||||
"sshConnectionFailed": "SSH कनेक्शन विफल हो गया। कृपया {{error}} ({{name}}:{{ip}}) से अपना कनेक्शन जांचें।",
|
||||
"loadFileFailed": "फ़ाइल लोड करने में विफल: {{port}}",
|
||||
"fileComparison": "फ़ाइल तुलना: {{file1}} बनाम {{file2}}",
|
||||
"fileTooLarge": "फ़ाइल बहुत बड़ी है: {{error}}",
|
||||
"sshConnectionFailed": "SSH कनेक्शन विफल हो गया। कृपया {{name}} ({{ip}}:{{port}}) से अपना कनेक्शन जांचें।",
|
||||
"loadFileFailed": "फ़ाइल लोड करने में विफल: {{error}}",
|
||||
"connectedSuccessfully": "सफलतापूर्वक कनेक्ट हो गया",
|
||||
"totpVerificationFailed": "टीओटीपी सत्यापन विफल रहा",
|
||||
"verificationCodePrompt": "सत्यापन कोड:",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "डिस्कनेक्ट",
|
||||
"cancel": "रद्द करना",
|
||||
"port": "पत्तन",
|
||||
"attempt": "{{error}} का प्रयास {{current}}",
|
||||
"nextRetryIn": "अगला प्रयास {{max}} सेकंड में होगा",
|
||||
"attempt": "प्रयास {{current}} का {{max}}",
|
||||
"nextRetryIn": "अगला प्रयास {{seconds}} सेकंड में होगा",
|
||||
"checkDockerLogs": "त्रुटि का कारण जानने के लिए अपने डॉकर लॉग की जाँच करें, और फिर शामिल हों।",
|
||||
"orCreate": "या बनाएँ",
|
||||
"orCreate": "या बनाएँ ",
|
||||
"noTunnelConnections": "कोई टनल कनेक्शन कॉन्फ़िगर नहीं किया गया है",
|
||||
"tunnelConnections": "सुरंग कनेक्शन",
|
||||
"addTunnel": "सुरंग जोड़ें",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"remote": "दूर",
|
||||
"dynamic": "गतिशील",
|
||||
"unknownConnectionStatus": "अज्ञात",
|
||||
"portMapping": "पोर्ट {{seconds}} → {{sourcePort}}:{{endpointHost}}",
|
||||
"portMapping": "पोर्ट {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"endpointHostNotFound": "एंडपॉइंट होस्ट नहीं मिला",
|
||||
"discord": "कलह",
|
||||
"githubIssue": "GitHub समस्या",
|
||||
@@ -1611,7 +1611,7 @@
|
||||
"disk": "डिस्क",
|
||||
"network": "नेटवर्क",
|
||||
"uptime": "अपटाइम",
|
||||
"loadAverage": "औसत: {{endpointPort}}, {{avg1}}, {{avg5}}",
|
||||
"loadAverage": "औसत: {{avg1}}, {{avg5}}, {{avg15}}",
|
||||
"processes": "प्रक्रियाओं",
|
||||
"connections": "कनेक्शन",
|
||||
"usage": "प्रयोग",
|
||||
@@ -1624,7 +1624,7 @@
|
||||
"refreshStatus": "स्थिति रीफ़्रेश करें",
|
||||
"fileManagerAlreadyOpen": "इस होस्ट के लिए फ़ाइल प्रबंधक पहले से ही खुला हुआ है।",
|
||||
"openFileManager": "फ़ाइल प्रबंधक खोलें",
|
||||
"cpuCores_one": "{{avg15}} सीपीयू",
|
||||
"cpuCores_one": "{{count}} सीपीयू",
|
||||
"cpuCores_other": "{{count}} सीपीयू",
|
||||
"naCpus": "लागू नहीं सीपीयू(ओं)",
|
||||
"loadAverageNA": "औसत: लागू नहीं",
|
||||
@@ -1678,11 +1678,11 @@
|
||||
"noRecentLoginData": "हाल ही में लॉगिन का कोई डेटा उपलब्ध नहीं है",
|
||||
"from": "से",
|
||||
"quickActions": "त्वरित कार्रवाइयां",
|
||||
"executeQuickAction": "निष्पादित करें {{count}}",
|
||||
"executingQuickAction": "{{name}} निष्पादित हो रहा है...",
|
||||
"quickActionSuccess": "{{name}} सफलतापूर्वक पूर्ण हुआ",
|
||||
"executeQuickAction": "{{name}}निष्पादित करें",
|
||||
"executingQuickAction": "{{name}}निष्पादित किया जा रहा है...",
|
||||
"quickActionSuccess": "{{name}} सफलतापूर्वक पूरा हुआ",
|
||||
"quickActionFailed": "{{name}} असफल",
|
||||
"quickActionError": "{{name}} को निष्पादित करने में विफल रहा"
|
||||
"quickActionError": "{{name}}को निष्पादित करने में विफल"
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "एसएसएच सर्वर प्रबंधक",
|
||||
@@ -1804,7 +1804,7 @@
|
||||
"unknownError": "अज्ञात त्रुटि",
|
||||
"loginFailed": "लॉगिन विफल",
|
||||
"failedPasswordReset": "पासवर्ड रीसेट शुरू करने में विफल",
|
||||
"failedVerifyCode": "रीसेट कोड सत्यापित करने में विफल",
|
||||
"failedVerifyCode": "रीसेट कोड को सत्यापित करने में विफल",
|
||||
"failedCompleteReset": "पासवर्ड रीसेट करने में विफलता",
|
||||
"invalidTotpCode": "अमान्य टीओटीपी कोड",
|
||||
"failedOidcLogin": "OIDC लॉगिन शुरू करने में विफल",
|
||||
@@ -1814,8 +1814,8 @@
|
||||
"invalidAuthUrl": "बैकएंड से अमान्य प्राधिकरण यूआरएल प्राप्त हुआ।",
|
||||
"invalidInput": "अमान्य निवेश",
|
||||
"requiredField": "यह फ़ील्ड आवश्यक है",
|
||||
"minLength": "न्यूनतम लंबाई {{name}} है",
|
||||
"maxLength": "अधिकतम लंबाई {{min}} है",
|
||||
"minLength": "न्यूनतम लंबाई {{min}}है",
|
||||
"maxLength": "अधिकतम लंबाई {{max}}है",
|
||||
"invalidEmail": "अमान्य ईमेल पता",
|
||||
"passwordMismatch": "सांकेतिक शब्द मेल नहीं खाते",
|
||||
"passwordLoginDisabled": "उपयोगकर्ता नाम/पासवर्ड लॉगिन वर्तमान में अक्षम है",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"updateError": "अपडेट करने में विफल",
|
||||
"copySuccess": "क्लिपबोर्ड पर कॉपी हो गया",
|
||||
"copyError": "कॉपी करने में विफल",
|
||||
"copiedToClipboard": "{{max}} क्लिपबोर्ड पर कॉपी हो गया",
|
||||
"copiedToClipboard": "{{item}} क्लिपबोर्ड पर कॉपी हो गया",
|
||||
"connectionEstablished": "कनेक्शन स्थापित हो गया",
|
||||
"connectionClosed": "कनेक्शन बंद हो गया",
|
||||
"reconnecting": "पुनः संपर्क स्थापित हो रहा है...",
|
||||
@@ -1845,7 +1845,7 @@
|
||||
"databaseConnected": "डेटाबेस सफलतापूर्वक कनेक्ट हो गया",
|
||||
"databaseConnectionFailed": "डेटाबेस सर्वर से कनेक्ट करने में विफल।",
|
||||
"checkServerConnection": "कृपया अपने सर्वर कनेक्शन की जांच करें और पुनः प्रयास करें।",
|
||||
"resetCodeSent": "रीसेट कोड डॉकर लॉग्स में भेजा गया",
|
||||
"resetCodeSent": "रीसेट कोड डॉकर लॉग्स को भेजा गया",
|
||||
"codeVerified": "कोड सफलतापूर्वक सत्यापित हो गया",
|
||||
"passwordResetSuccess": "पासवर्ड सफलतापूर्वक रीसेट हो गया",
|
||||
"loginSuccess": "लॉग इन सफल",
|
||||
@@ -1871,13 +1871,13 @@
|
||||
"commandAutocomplete": "कमांड ऑटो-कंप्लीट",
|
||||
"commandAutocompleteDesc": "अपने कमांड इतिहास के आधार पर टर्मिनल कमांड के लिए टैब कुंजी स्वतः पूर्ण होने के सुझाव सक्षम करें",
|
||||
"defaultSnippetFoldersCollapsed": "डिफ़ॉल्ट रूप से स्निपेट फ़ोल्डर को संक्षिप्त करें",
|
||||
"defaultSnippetFoldersCollapsedDesc": "जब यह विकल्प चालू होगा, तो स्निपेट टैब खोलने पर सभी स्निपेट फ़ोल्डर सिकुड़े हुए दिखाई देंगे।",
|
||||
"defaultSnippetFoldersCollapsedDesc": "इस विकल्प को चालू करने पर, स्निपेट टैब खोलने पर सभी स्निपेट फ़ोल्डर सिकुड़ जाएंगे।",
|
||||
"terminalSyntaxHighlighting": "टर्मिनल सिंटैक्स हाइलाइटिंग",
|
||||
"showHostTags": "शो होस्ट टैग",
|
||||
"showHostTagsDesc": "साइडबार में प्रत्येक होस्ट के नीचे टैग प्रदर्शित करें। सभी टैग छिपाने के लिए इसे अक्षम करें।",
|
||||
"account": "खाता",
|
||||
"appearance": "उपस्थिति",
|
||||
"languageLocalization": "भाषा एवं स्थानीयकरण",
|
||||
"languageLocalization": "भाषा और स्थानीयकरण",
|
||||
"fileManagerSettings": "फ़ाइल मैनेजर",
|
||||
"terminalSettings": "टर्मिनल",
|
||||
"hostSidebarSettings": "होस्ट और साइडबार",
|
||||
@@ -1955,9 +1955,9 @@
|
||||
"passwordRequired": "पासवर्ड आवश्यक है",
|
||||
"failedToDeleteAccount": "खाता हटाने में विफल",
|
||||
"failedToMakeUserAdmin": "उपयोगकर्ता को व्यवस्थापक बनाने में विफल",
|
||||
"userIsNowAdmin": "उपयोगकर्ता {{item}} अब व्यवस्थापक है",
|
||||
"removeAdminConfirm": "क्या आप वाकई {{username}} से व्यवस्थापक का दर्जा हटाना चाहते हैं?",
|
||||
"deleteUserConfirm": "क्या आप वाकई उपयोगकर्ता {{username}} को हटाना चाहते हैं? यह कार्रवाई पूर्ववत नहीं की जा सकती।",
|
||||
"userIsNowAdmin": "उपयोगकर्ता {{username}} अब व्यवस्थापक है",
|
||||
"removeAdminConfirm": "क्या आप वाकई {{username}}से व्यवस्थापक का दर्जा हटाना चाहते हैं?",
|
||||
"deleteUserConfirm": "क्या आप वाकई उपयोगकर्ता {{username}}को हटाना चाहते हैं? यह कार्रवाई पूर्ववत नहीं की जा सकती।",
|
||||
"deleteAccount": "खाता हटा दो",
|
||||
"closeDeleteAccount": "खाता बंद करें हटाएं",
|
||||
"deleteAccountWarning": "यह कार्रवाई पूर्ववत नहीं की जा सकती। इससे आपका खाता और उससे संबंधित सभी डेटा स्थायी रूप से हटा दिया जाएगा।",
|
||||
@@ -2056,7 +2056,7 @@
|
||||
"webServerProduction": "वेब सर्वर - उत्पादन",
|
||||
"unknownError": "अज्ञात त्रुटि",
|
||||
"failedToInitiatePasswordReset": "पासवर्ड रीसेट शुरू करने में विफल",
|
||||
"failedToVerifyResetCode": "रीसेट कोड को सत्यापित करने में विफल",
|
||||
"failedToVerifyResetCode": "रीसेट कोड सत्यापित करने में विफल",
|
||||
"failedToCompletePasswordReset": "पासवर्ड रीसेट करने में विफलता",
|
||||
"invalidTotpCode": "अमान्य टीओटीपी कोड",
|
||||
"failedToStartOidcLogin": "OIDC लॉगिन शुरू करने में विफल",
|
||||
@@ -2140,17 +2140,17 @@
|
||||
"blockedCommandsPlaceholder": "ब्लॉक करने के लिए कमांड दर्ज करें, उदाहरण के लिए, passwd, rm, dd",
|
||||
"maxSessionDuration": "अधिकतम सत्र अवधि (मिनटों में)",
|
||||
"createTempUser": "अस्थायी उपयोगकर्ता बनाएँ",
|
||||
"createTempUserDesc": "यह आपके क्रेडेंशियल्स को साझा करने के बजाय सर्वर पर एक प्रतिबंधित उपयोगकर्ता बनाता है। इसके लिए sudo एक्सेस आवश्यक है। यह सबसे सुरक्षित विकल्प है।",
|
||||
"createTempUserDesc": "यह आपके क्रेडेंशियल्स साझा करने के बजाय सर्वर पर एक प्रतिबंधित उपयोगकर्ता बनाता है। इसके लिए sudo एक्सेस आवश्यक है। यह सबसे सुरक्षित विकल्प है।",
|
||||
"expiresAt": "समाप्ति तिथि",
|
||||
"expiresIn": "{{username}} घंटों में समाप्त हो जाएगा",
|
||||
"expiresIn": "{{hours}} घंटों में समाप्त हो जाएगा",
|
||||
"expired": "खत्म हो चुका",
|
||||
"grantedBy": "अनुमती देना",
|
||||
"accessLevel": "पहुँच स्तर",
|
||||
"lastAccessed": "अंतिम बार देखा गया",
|
||||
"accessCount": "पहुँच गणना",
|
||||
"revokeAccess": "एक्सेस अक्षम करें",
|
||||
"confirmRevokeAccess": "क्या आप वाकई {{hours}} के लिए पहुँच रद्द करना चाहते हैं?",
|
||||
"hostSharedSuccessfully": "होस्ट ने {{username}} के साथ सफलतापूर्वक साझा किया",
|
||||
"confirmRevokeAccess": "क्या आप वाकई {{username}}के लिए पहुँच रद्द करना चाहते हैं?",
|
||||
"hostSharedSuccessfully": "होस्ट ने {{username}}के साथ सफलतापूर्वक साझा किया",
|
||||
"hostAccessUpdated": "होस्ट एक्सेस अपडेट किया गया",
|
||||
"failedToShareHost": "होस्ट साझा करने में विफल",
|
||||
"accessRevokedSuccessfully": "पहुँच सफलतापूर्वक रद्द कर दी गई",
|
||||
@@ -2165,11 +2165,11 @@
|
||||
"noAccessGranted": "इस होस्ट के लिए कोई एक्सेस प्रदान नहीं किया गया है।",
|
||||
"noAccessGrantedMessage": "अभी तक किसी भी उपयोगकर्ता को इस होस्ट तक पहुंच प्रदान नहीं की गई है।",
|
||||
"manageAccessFor": "इसके लिए पहुंच प्रबंधित करें",
|
||||
"totalAccessRecords": "{{username}} एक्सेस रिकॉर्ड(ओं)",
|
||||
"totalAccessRecords": "{{count}} रिकॉर्ड तक पहुंचें",
|
||||
"neverAccessed": "कभी नहीं",
|
||||
"timesAccessed": "{{count}} बार",
|
||||
"daysRemaining": "{{count}} दिन",
|
||||
"hoursRemaining": "{{days}} घंटे",
|
||||
"timesAccessed": "{{count}} बार(s)",
|
||||
"daysRemaining": "{{days}} दिन(दिन)",
|
||||
"hoursRemaining": "{{hours}} घंटे",
|
||||
"failedToFetchAccessList": "एक्सेस सूची प्राप्त करने में विफल",
|
||||
"currentAccess": "वर्तमान पहुंच",
|
||||
"securityWarning": "सुरक्षा चेतावनी",
|
||||
@@ -2177,7 +2177,7 @@
|
||||
"tempUserRecommended": "बेहतर सुरक्षा के लिए हम 'अस्थायी उपयोगकर्ता बनाएं' विकल्प को सक्षम करने की सलाह देते हैं।",
|
||||
"roleManagement": "भूमिका प्रबंधन",
|
||||
"manageRoles": "भूमिकाएँ प्रबंधित करें",
|
||||
"manageRolesFor": "{{hours}} के लिए भूमिकाएँ प्रबंधित करें",
|
||||
"manageRolesFor": "{{username}}के लिए भूमिकाएँ प्रबंधित करें",
|
||||
"assignRole": "भूमिका सौंपें",
|
||||
"removeRole": "भूमिका हटाएँ",
|
||||
"userRoles": "उपयोगकर्ता भूमिका",
|
||||
@@ -2213,8 +2213,8 @@
|
||||
"commandBlocked": "कमांड अवरुद्ध",
|
||||
"terminateSession": "सत्र समाप्त करें",
|
||||
"sessionTerminated": "होस्ट के मालिक द्वारा सत्र समाप्त कर दिया गया",
|
||||
"sharedAccessExpired": "इस होस्ट पर आपकी साझा पहुंच समाप्त हो गई है।",
|
||||
"sharedAccessExpiresIn": "साझा पहुंच {{username}} घंटों में समाप्त हो जाएगी",
|
||||
"sharedAccessExpired": "इस होस्ट तक आपकी साझा पहुंच समाप्त हो गई है।",
|
||||
"sharedAccessExpiresIn": "साझा पहुंच {{hours}} घंटों में समाप्त हो जाएगी",
|
||||
"roles": {
|
||||
"label": "भूमिकाएँ",
|
||||
"admin": "प्रशासक",
|
||||
@@ -2249,7 +2249,7 @@
|
||||
"displayNamePlaceholder": "डेवलपर",
|
||||
"descriptionPlaceholder": "सॉफ्टवेयर डेवलपर और इंजीनियर",
|
||||
"confirmDeleteRole": "भूमिका हटाएं",
|
||||
"confirmDeleteRoleDescription": "क्या आप वाकई '{{hours}}' भूमिका को हटाना चाहते हैं? यह क्रिया पूर्ववत नहीं की जा सकती।",
|
||||
"confirmDeleteRoleDescription": "क्या आप वाकई '{{name}}' भूमिका को हटाना चाहते हैं? यह कार्रवाई पूर्ववत नहीं की जा सकती।",
|
||||
"confirmRemoveRole": "भूमिका हटाएँ",
|
||||
"confirmRemoveRoleDescription": "क्या आप वाकई इस भूमिका को उपयोगकर्ता से हटाना चाहते हैं?",
|
||||
"editRoleDescription": "भूमिका संबंधी जानकारी अपडेट करें",
|
||||
@@ -2307,19 +2307,19 @@
|
||||
"validating": "डॉकर का सत्यापन किया जा रहा है...",
|
||||
"connectingToHost": "होस्ट से कनेक्ट हो रहा है...",
|
||||
"error": "गलती",
|
||||
"errorCode": "त्रुटि कोड: {{name}}",
|
||||
"version": "डॉकर {{code}}",
|
||||
"containerStarted": "कंटेनर {{version}} शुरू हो गया",
|
||||
"failedToStartContainer": "कंटेनर {{name}} को प्रारंभ करने में विफल",
|
||||
"errorCode": "त्रुटि कोड: {{code}}",
|
||||
"version": "डॉकर {{version}}",
|
||||
"containerStarted": "कंटेनर {{name}} शुरू हो गया",
|
||||
"failedToStartContainer": "कंटेनर {{name}}को प्रारंभ करने में विफल",
|
||||
"containerStopped": "कंटेनर {{name}} रुक गया",
|
||||
"failedToStopContainer": "कंटेनर {{name}} को रोकने में विफल",
|
||||
"containerRestarted": "कंटेनर {{name}} पुनः आरंभ हो गया",
|
||||
"failedToRestartContainer": "कंटेनर {{name}} को पुनः आरंभ करने में विफल रहा",
|
||||
"failedToStopContainer": "कंटेनर {{name}}को रोकने में विफल",
|
||||
"containerRestarted": "कंटेनर {{name}} पुनः आरंभ हुआ",
|
||||
"failedToRestartContainer": "कंटेनर {{name}}को पुनः आरंभ करने में विफल रहा",
|
||||
"containerPaused": "कंटेनर {{name}} रुका हुआ है",
|
||||
"containerUnpaused": "कंटेनर {{name}} अनपॉज़ किया गया",
|
||||
"failedToTogglePauseContainer": "कंटेनर {{name}} के लिए पॉज़ स्थिति को टॉगल करने में विफल।",
|
||||
"failedToTogglePauseContainer": "कंटेनर {{name}}के लिए पॉज़ स्थिति को टॉगल करने में विफल।",
|
||||
"containerRemoved": "कंटेनर {{name}} हटा दिया गया",
|
||||
"failedToRemoveContainer": "कंटेनर {{name}} को हटाने में विफल रहा",
|
||||
"failedToRemoveContainer": "कंटेनर {{name}}को हटाने में विफल",
|
||||
"image": "छवि",
|
||||
"idLabel": "पहचान",
|
||||
"ports": "बंदरगाहों",
|
||||
@@ -2340,8 +2340,8 @@
|
||||
"noContainersFoundHint": "इस होस्ट पर कोई डॉकर कंटेनर उपलब्ध नहीं हैं।",
|
||||
"searchPlaceholder": "कंटेनर खोजें...",
|
||||
"filterByStatusPlaceholder": "स्थिति के अनुसार फ़िल्टर करें",
|
||||
"allContainersCount": "सभी ({{name}})",
|
||||
"statusCount": "{{count}} ({{status}})",
|
||||
"allContainersCount": "सभी ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "आपके फ़िल्टर से कोई कंटेनर मेल नहीं खाता।",
|
||||
"noContainersMatchFiltersHint": "अपनी खोज या फ़िल्टर के मानदंडों को समायोजित करने का प्रयास करें",
|
||||
"containerMustBeRunningToViewStats": "आंकड़े देखने के लिए कंटेनर का चालू होना आवश्यक है।",
|
||||
@@ -2372,10 +2372,10 @@
|
||||
"authenticationRequired": "प्रमाणित करना",
|
||||
"verificationCodePrompt": "सत्यापन कोड दर्ज करें",
|
||||
"totpVerificationFailed": "टीओटीपी सत्यापन विफल रहा। कृपया पुनः प्रयास करें।",
|
||||
"connectedTo": "{{count}} से जुड़ा हुआ है",
|
||||
"connectedTo": "{{containerName}}से जुड़ा हुआ",
|
||||
"disconnected": "डिस्कनेक्ट किया गया",
|
||||
"consoleError": "कंसोल त्रुटि",
|
||||
"errorMessage": "त्रुटि: {{containerName}}",
|
||||
"errorMessage": "त्रुटि: {{message}}",
|
||||
"failedToConnect": "कंटेनर से कनेक्ट करने में विफल",
|
||||
"console": "सांत्वना देना",
|
||||
"selectShell": "शेल का चयन करें",
|
||||
@@ -2387,7 +2387,7 @@
|
||||
"disconnect": "डिस्कनेक्ट",
|
||||
"notConnected": "जुड़े नहीं हैं",
|
||||
"clickToConnect": "शेल सेशन शुरू करने के लिए कनेक्ट पर क्लिक करें",
|
||||
"connectingTo": "{{message}} से कनेक्ट हो रहा है...",
|
||||
"connectingTo": "{{containerName}}से कनेक्ट हो रहा है...",
|
||||
"containerNotFound": "कंटेनर नहीं मिला",
|
||||
"backToList": "सूची पर वापस जाएं",
|
||||
"logs": "लॉग्स",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "लाइट पर स्विच करें",
|
||||
"switchToDark": "डार्क मोड पर स्विच करें"
|
||||
}
|
||||
}
|
||||
}
|
||||
2402
src/locales/translated/hu.json
Normal file
2402
src/locales/translated/hu.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -76,7 +76,7 @@
|
||||
"passwordAuthDescription": "Gunakan autentikasi kata sandi.",
|
||||
"sshKeyAuthDescription": "Gunakan autentikasi kunci SSH",
|
||||
"passwordIsRequired": "Kata sandi diperlukan",
|
||||
"sshKeyIsRequired": "Kunci SSH diperlukan",
|
||||
"sshKeyIsRequired": "Kunci SSH diperlukan.",
|
||||
"sshKeyType": "Jenis Kunci SSH",
|
||||
"privateKey": "Kunci Pribadi",
|
||||
"enterPassword": "Masukkan kata sandi",
|
||||
@@ -139,7 +139,7 @@
|
||||
"confirmRemoveFromFolder": "Apakah Anda yakin ingin menghapus \"{{name}}\" dari folder \"{{folder}}\"? Kredensial akan dipindahkan ke \"Tidak Berkategori\".",
|
||||
"removedFromFolder": "Kredensial \"{{name}}\" berhasil dihapus dari folder",
|
||||
"failedToRemoveFromFolder": "Gagal menghapus kredensial dari folder.",
|
||||
"folderRenamed": "Folder \"{{{oldName}}\" berhasil diganti namanya menjadi \"{{{newName}}\"",
|
||||
"folderRenamed": "Folder \"{{oldName}}\" berhasil diganti namanya menjadi \"{{newName}}\"",
|
||||
"failedToRenameFolder": "Gagal mengganti nama folder",
|
||||
"movedToFolder": "Kredensial \"{{name}}\" berhasil dipindahkan ke \"{{folder}}\"",
|
||||
"failedToMoveToFolder": "Gagal memindahkan kredensial ke folder.",
|
||||
@@ -187,10 +187,10 @@
|
||||
"dragIndicator": {
|
||||
"error": "Kesalahan: {{error}}",
|
||||
"dragging": "Menyeret {{fileName}}",
|
||||
"preparing": "Mempersiapkan 14",
|
||||
"preparing": "Mempersiapkan {{fileName}}",
|
||||
"readySingle": "Siap untuk diunduh {{fileName}}",
|
||||
"readyMultiple": "Siap mengunduh {{fileName}} file",
|
||||
"batchDrag": "Seret {{count}} berkas ke desktop",
|
||||
"readyMultiple": "Siap mengunduh {{count}} file",
|
||||
"batchDrag": "Seret {{count}} file ke desktop",
|
||||
"dragToDesktop": "Seret ke desktop",
|
||||
"canDragAnywhere": "Anda dapat menyeret file ke mana saja di desktop Anda."
|
||||
},
|
||||
@@ -222,7 +222,7 @@
|
||||
"name": "Nama",
|
||||
"description": "Keterangan",
|
||||
"content": "Memerintah",
|
||||
"namePlaceholder": "Contoh: Restart Nginx",
|
||||
"namePlaceholder": "misalnya, Restart Nginx",
|
||||
"descriptionPlaceholder": "Deskripsi opsional",
|
||||
"contentPlaceholder": "misalnya, sudo systemctl restart nginx",
|
||||
"nameRequired": "Nama wajib diisi.",
|
||||
@@ -230,7 +230,7 @@
|
||||
"createDescription": "Buat cuplikan perintah baru untuk eksekusi cepat.",
|
||||
"editDescription": "Edit cuplikan perintah ini",
|
||||
"deleteConfirmTitle": "Hapus Cuplikan",
|
||||
"deleteConfirmDescription": "Apakah Anda yakin ingin menghapus \"{{count}}\"?",
|
||||
"deleteConfirmDescription": "Apakah Anda yakin ingin menghapus \"{{name}}\"?",
|
||||
"createSuccess": "Cuplikan berhasil dibuat.",
|
||||
"updateSuccess": "Cuplikan berhasil diperbarui.",
|
||||
"deleteSuccess": "Cuplikan berhasil dihapus",
|
||||
@@ -256,7 +256,7 @@
|
||||
"updateFolderFailed": "Gagal memperbarui folder",
|
||||
"createFolderFailed": "Gagal membuat folder",
|
||||
"selectTerminals": "Pilih Terminal (opsional)",
|
||||
"executeOnSelected": "Jalankan pada {{name}} terminal yang dipilih",
|
||||
"executeOnSelected": "Jalankan pada {{count}} terminal yang dipilih",
|
||||
"executeOnCurrent": "Jalankan di terminal saat ini (klik untuk memilih beberapa)",
|
||||
"folder": "Map",
|
||||
"selectFolder": "Pilih folder atau biarkan kosong.",
|
||||
@@ -280,7 +280,7 @@
|
||||
"empty": "Belum ada riwayat perintah.",
|
||||
"emptyHint": "Jalankan perintah di terminal aktif untuk membangun riwayatnya.",
|
||||
"noResults": "Tidak ada perintah yang ditemukan",
|
||||
"noResultsHint": "Tidak ada perintah yang cocok dengan \"{{{count}}\"",
|
||||
"noResultsHint": "Tidak ada perintah yang cocok dengan \"{{query}}\"",
|
||||
"deleteSuccess": "Perintah dihapus dari riwayat",
|
||||
"deleteFailed": "Perintah penghapusan gagal.",
|
||||
"deleteTooltip": "Perintah hapus",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "Layar terpisah telah dibersihkan.",
|
||||
"error": {
|
||||
"noAssignments": "Harap tetapkan setidaknya satu tab ke tata letak.",
|
||||
"fillAllSlots": "Harap isi semua {{query}} slot sebelum mendaftar."
|
||||
"fillAllSlots": "Harap isi semua {{count}} slot sebelum mendaftar"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -343,10 +343,10 @@
|
||||
"error": "Kesalahan Pemeriksaan Versi",
|
||||
"checkFailed": "Gagal memeriksa pembaruan.",
|
||||
"upToDate": "Aplikasi sudah diperbarui.",
|
||||
"currentVersion": "Anda menjalankan versi {{count}}",
|
||||
"currentVersion": "Anda menjalankan versi {{version}}",
|
||||
"updateAvailable": "Pembaruan Tersedia",
|
||||
"newVersionAvailable": "Versi baru tersedia! Anda menjalankan {{version}}, tetapi {{current}} tersedia.",
|
||||
"releasedOn": "Dirilis pada {{latest}}",
|
||||
"newVersionAvailable": "Versi baru tersedia! Anda menjalankan {{current}}, tetapi {{latest}} tersedia.",
|
||||
"releasedOn": "Dirilis pada {{date}}",
|
||||
"downloadUpdate": "Unduh Pembaruan",
|
||||
"dismiss": "Membubarkan",
|
||||
"checking": "Memeriksa pembaruan...",
|
||||
@@ -354,7 +354,7 @@
|
||||
"checkingUpdates": "Memeriksa pembaruan...",
|
||||
"refresh": "Menyegarkan",
|
||||
"updateRequired": "Pembaruan Diperlukan",
|
||||
"updateDismissed": "Pemberitahuan pembaruan ditolak",
|
||||
"updateDismissed": "Pemberitahuan pembaruan ditolak.",
|
||||
"noUpdatesFound": "Tidak ada pembaruan yang ditemukan."
|
||||
},
|
||||
"common": {
|
||||
@@ -382,7 +382,7 @@
|
||||
"home": "Rumah",
|
||||
"expired": "Kedaluwarsa",
|
||||
"expiresToday": "Berakhir hari ini",
|
||||
"expiresTomorrow": "Berakhir dalam {{date}} hari",
|
||||
"expiresTomorrow": "Berakhir dalam {{days}} hari",
|
||||
"updateAvailable": "Pembaruan Tersedia",
|
||||
"sshPath": "Jalur SSH",
|
||||
"localPath": "Jalur Lokal",
|
||||
@@ -392,7 +392,7 @@
|
||||
"noAuthCredentials": "Tidak ada kredensial otentikasi yang tersedia untuk host SSH ini.",
|
||||
"noReleases": "Tidak ada rilis",
|
||||
"updatesAndReleases": "Pembaruan & Rilis",
|
||||
"newVersionAvailable": "Versi baru ({{days}}) tersedia.",
|
||||
"newVersionAvailable": "Versi baru ({{version}}) tersedia.",
|
||||
"failedToFetchUpdateInfo": "Gagal mengambil informasi pembaruan.",
|
||||
"preRelease": "Pra-rilis",
|
||||
"loginFailed": "Login gagal.",
|
||||
@@ -489,7 +489,7 @@
|
||||
"hostManager": "Manajer Host",
|
||||
"cannotSplitTab": "Tidak dapat memisahkan tab ini",
|
||||
"tabNavigation": "Navigasi Tab",
|
||||
"hostTabTitle": "{{version}}@{{username}}:{{ip}}"
|
||||
"hostTabTitle": "{{username}}@{{ip}}:{{port}}"
|
||||
},
|
||||
"admin": {
|
||||
"title": "Pengaturan Admin",
|
||||
@@ -498,7 +498,7 @@
|
||||
"userManagement": "Manajemen Pengguna",
|
||||
"makeAdmin": "Jadikan Admin",
|
||||
"removeAdmin": "Hapus Admin",
|
||||
"deleteUser": "Hapus pengguna {{port}}? Tindakan ini tidak dapat dibatalkan.",
|
||||
"deleteUser": "Hapus pengguna {{username}}? Tindakan ini tidak dapat dibatalkan.",
|
||||
"allowRegistration": "Izinkan Pendaftaran",
|
||||
"oidcSettings": "Pengaturan OIDC",
|
||||
"clientId": "ID Klien",
|
||||
@@ -537,7 +537,7 @@
|
||||
"userRegistration": "Pendaftaran Pengguna",
|
||||
"allowNewAccountRegistration": "Izinkan pendaftaran akun baru",
|
||||
"allowPasswordLogin": "Izinkan login menggunakan nama pengguna/kata sandi.",
|
||||
"missingRequiredFields": "Kolom yang wajib diisi belum terisi: {{username}}",
|
||||
"missingRequiredFields": "Kolom yang wajib diisi belum terisi: {{fields}}",
|
||||
"oidcConfigurationUpdated": "Konfigurasi OIDC berhasil diperbarui!",
|
||||
"failedToFetchOidcConfig": "Gagal mengambil konfigurasi OIDC",
|
||||
"failedToFetchRegistrationStatus": "Gagal mengambil status pendaftaran",
|
||||
@@ -547,7 +547,7 @@
|
||||
"failedToUpdateOidcConfig": "Gagal memperbarui konfigurasi OIDC",
|
||||
"failedToDisableOidcConfig": "Gagal menonaktifkan konfigurasi OIDC.",
|
||||
"enterUsernameToMakeAdmin": "Masukkan nama pengguna untuk menjadi admin",
|
||||
"userIsNowAdmin": "Pengguna {{fields}} sekarang menjadi admin",
|
||||
"userIsNowAdmin": "Pengguna {{username}} sekarang menjadi admin",
|
||||
"failedToMakeUserAdmin": "Gagal menjadikan pengguna sebagai admin.",
|
||||
"removeAdminStatus": "Hapus status admin dari {{username}}?",
|
||||
"adminStatusRemoved": "Status admin dihapus dari {{username}}",
|
||||
@@ -611,11 +611,11 @@
|
||||
"linkTargetUsernamePlaceholder": "Masukkan nama pengguna atau kata sandi akun Anda.",
|
||||
"linkAccountsButton": "Tautkan Akun",
|
||||
"linkingAccounts": "Menghubungkan...",
|
||||
"accountsLinkedSuccessfully": "Pengguna OIDC {{username}} telah dihubungkan ke {{oidcUsername}}",
|
||||
"accountsLinkedSuccessfully": "Pengguna OIDC {{oidcUsername}} telah dihubungkan ke {{targetUsername}}",
|
||||
"failedToLinkAccounts": "Gagal menautkan akun",
|
||||
"linkTargetUsernameRequired": "Nama pengguna target wajib diisi.",
|
||||
"unlinkOIDCTitle": "Lepaskan Otentikasi OIDC",
|
||||
"unlinkOIDCDescription": "Hapus otentikasi OIDC dari {{targetUsername}}? Pengguna hanya akan dapat masuk dengan nama pengguna/kata sandi setelah ini.",
|
||||
"unlinkOIDCDescription": "Hapus otentikasi OIDC dari {{username}}? Pengguna hanya akan dapat masuk dengan nama pengguna/kata sandi setelah ini.",
|
||||
"unlinkOIDCSuccess": "OIDC tidak terhubung dari {{username}}",
|
||||
"failedToUnlinkOIDC": "Gagal melepaskan tautan OIDC",
|
||||
"databaseSecurity": "Keamanan Basis Data",
|
||||
@@ -661,7 +661,7 @@
|
||||
"loadingEncryptionStatus": "Memuat status enkripsi...",
|
||||
"testMigrationDescription": "Pastikan bahwa data yang ada dapat dimigrasikan dengan aman ke format terenkripsi tanpa benar-benar memodifikasi data apa pun.",
|
||||
"serverMigrationGuide": "Panduan Migrasi Server",
|
||||
"migrationInstructions": "Untuk memigrasikan data terenkripsi ke server baru: 1) Cadangkan file basis data, 2) Atur variabel lingkungan DB_ENCRYPTION_KEY=\"kunci-Anda\" pada server baru, 3) Pulihkan file basis data",
|
||||
"migrationInstructions": "Untuk memindahkan data terenkripsi ke server baru: 1) Cadangkan file basis data, 2) Atur variabel lingkungan DB_ENCRYPTION_KEY=\"kunci-Anda\" pada server baru, 3) Pulihkan file basis data",
|
||||
"environmentProtection": "Perlindungan Lingkungan",
|
||||
"environmentProtectionDesc": "Melindungi kunci enkripsi berdasarkan informasi lingkungan server (nama host, jalur, dll.), dapat dipindahkan melalui variabel lingkungan.",
|
||||
"verificationCompleted": "Verifikasi kompatibilitas selesai - tidak ada data yang diubah.",
|
||||
@@ -777,23 +777,23 @@
|
||||
"retry": "Mencoba kembali",
|
||||
"refresh": "Menyegarkan",
|
||||
"optional": "Opsional",
|
||||
"hostsCount": "{{username}} tuan rumah",
|
||||
"hostsCount": "{{count}} tuan rumah",
|
||||
"importJson": "Impor JSON",
|
||||
"importing": "Pengimporan...",
|
||||
"importJsonTitle": "Impor Host SSH dari JSON",
|
||||
"importJsonDesc": "Unggah file JSON untuk mengimpor beberapa host SSH secara massal (maksimal 100).",
|
||||
"downloadSample": "Unduh Sampel",
|
||||
"formatGuide": "Panduan Format",
|
||||
"exportCredentialWarning": "Peringatan: Host \"{{count}}\" menggunakan otentikasi kredensial. File yang diekspor tidak akan menyertakan data kredensial dan perlu dikonfigurasi ulang secara manual setelah impor. Apakah Anda ingin melanjutkan?",
|
||||
"exportCredentialWarning": "Peringatan: Host \"{{name}}\" menggunakan otentikasi kredensial. File yang diekspor tidak akan menyertakan data kredensial dan perlu dikonfigurasi ulang secara manual setelah impor. Apakah Anda ingin melanjutkan?",
|
||||
"exportSensitiveDataWarning": "Peringatan: Host \"{{name}}\" berisi data otentikasi sensitif (kata sandi/kunci SSH). File yang diekspor akan menyertakan data ini dalam bentuk teks biasa. Harap simpan file ini dengan aman dan hapus setelah digunakan. Apakah Anda ingin melanjutkan?",
|
||||
"uncategorized": "Tidak dikategorikan",
|
||||
"confirmDelete": "Apakah Anda yakin ingin menghapus \"{{name}}\"?",
|
||||
"confirmDelete": "Apakah Anda yakin ingin menghapus \"{{name}}\" ?",
|
||||
"failedToDeleteHost": "Gagal menghapus host",
|
||||
"failedToExportHost": "Ekspor host gagal. Pastikan Anda sudah login dan memiliki akses ke data host.",
|
||||
"jsonMustContainHosts": "JSON harus berisi array \"hosts\" atau berupa array host.",
|
||||
"noHostsInJson": "Tidak ditemukan host dalam file JSON.",
|
||||
"maxHostsAllowed": "Maksimal 100 host diperbolehkan per impor.",
|
||||
"importCompleted": "Impor selesai: {{name}} berhasil, {{success}} gagal",
|
||||
"importCompleted": "Impor selesai: {{success}} berhasil, {{failed}} gagal",
|
||||
"importFailed": "Impor gagal",
|
||||
"importError": "Kesalahan impor",
|
||||
"failedToImportJson": "Gagal mengimpor file JSON",
|
||||
@@ -816,9 +816,9 @@
|
||||
"editHost": "Edit Host",
|
||||
"cloneHost": "Kloning Host",
|
||||
"updateHost": "Perbarui Host",
|
||||
"hostUpdatedSuccessfully": "Host \"{{{failed}}\" berhasil diperbarui!",
|
||||
"hostAddedSuccessfully": "Host \"{{{name}}\" berhasil ditambahkan!",
|
||||
"hostDeletedSuccessfully": "Host \"{{{name}}\" berhasil dihapus!",
|
||||
"hostUpdatedSuccessfully": "Host \"{{name}}\" berhasil diperbarui!",
|
||||
"hostAddedSuccessfully": "Host \"{{name}}\" berhasil ditambahkan!",
|
||||
"hostDeletedSuccessfully": "Host \"{{name}}\" berhasil dihapus!",
|
||||
"failedToSaveHost": "Gagal menyimpan host. Silakan coba lagi.",
|
||||
"savingHost": "Menyimpan host...",
|
||||
"updatingHost": "Memperbarui host...",
|
||||
@@ -837,10 +837,10 @@
|
||||
"connection": "Koneksi",
|
||||
"remove": "Menghapus",
|
||||
"sourcePort": "Port Sumber",
|
||||
"sourcePortDesc": "(Sumber mengacu pada Detail Koneksi Saat Ini di tab Umum)",
|
||||
"sourcePortDesc": " (Sumber mengacu pada Detail Koneksi Saat Ini di tab Umum)",
|
||||
"endpointPort": "Port Titik Akhir",
|
||||
"endpointSshConfig": "Konfigurasi SSH Titik Akhir",
|
||||
"tunnelForwardDescription": "Terowongan ini akan meneruskan lalu lintas dari port {{name}} pada mesin sumber (detail koneksi saat ini di tab umum) ke port {{sourcePort}} pada mesin titik akhir.",
|
||||
"endpointSshConfig": "Konfigurasi Endpoint SSH",
|
||||
"tunnelForwardDescription": "Terowongan ini akan meneruskan lalu lintas dari port {{sourcePort}} pada mesin sumber (detail koneksi saat ini di tab umum) ke port {{endpointPort}} pada mesin titik akhir.",
|
||||
"maxRetries": "Jumlah Percobaan Maksimum",
|
||||
"maxRetriesDescription": "Jumlah maksimum percobaan ulang untuk koneksi terowongan.",
|
||||
"retryInterval": "Interval Percobaan Ulang (detik)",
|
||||
@@ -916,10 +916,10 @@
|
||||
"customCommandsDesc": "Tetapkan perintah pematian dan memulai ulang khusus untuk server ini.",
|
||||
"shutdownCommand": "Perintah Matikan",
|
||||
"rebootCommand": "Perintah Reboot",
|
||||
"confirmRemoveFromFolder": "Apakah Anda yakin ingin menghapus \"{{endpointPort}}\" dari folder \"{{name}}\"? Host akan dipindahkan ke \"Tidak Ada Folder\".",
|
||||
"removedFromFolder": "Host \"{{{folder}}\" berhasil dihapus dari folder",
|
||||
"confirmRemoveFromFolder": "Apakah Anda yakin ingin menghapus \"{{name}}\" dari folder \"{{folder}}\"? Host akan dipindahkan ke \"Tidak Ada Folder\".",
|
||||
"removedFromFolder": "Host \"{{name}}\" berhasil dihapus dari folder",
|
||||
"failedToRemoveFromFolder": "Gagal menghapus host dari folder.",
|
||||
"folderRenamed": "Folder \"{{{name}}\" berhasil diganti namanya menjadi \"{{{oldName}}\"",
|
||||
"folderRenamed": "Folder \"{{oldName}}\" berhasil diganti namanya menjadi \"{{newName}}\"",
|
||||
"failedToRenameFolder": "Gagal mengganti nama folder",
|
||||
"editFolderAppearance": "Edit Tampilan Folder",
|
||||
"editFolderAppearanceDesc": "Sesuaikan warna dan ikon untuk folder.",
|
||||
@@ -929,21 +929,21 @@
|
||||
"folderAppearanceUpdated": "Tampilan folder berhasil diperbarui.",
|
||||
"failedToUpdateFolderAppearance": "Gagal memperbarui tampilan folder",
|
||||
"deleteAllHostsInFolder": "Hapus Semua Host di Folder",
|
||||
"confirmDeleteAllHostsInFolder": "Apakah Anda yakin ingin menghapus semua {{newName}} host di folder \"{{count}}\"? Tindakan ini tidak dapat dibatalkan.",
|
||||
"allHostsInFolderDeleted": "Host sebanyak {{folder}} dari folder \"{{count}}\" berhasil dihapus.",
|
||||
"confirmDeleteAllHostsInFolder": "Apakah Anda yakin ingin menghapus semua host {{count}} di folder \"{{folder}}\"? Tindakan ini tidak dapat dibatalkan.",
|
||||
"allHostsInFolderDeleted": "Host {{count}} dari folder \"{{folder}}\" berhasil dihapus",
|
||||
"failedToDeleteHostsInFolder": "Gagal menghapus host di dalam folder.",
|
||||
"movedToFolder": "Host \"{{folder}}\" berhasil dipindahkan ke \"{{name}}\"",
|
||||
"movedToFolder": "Host \"{{name}}\" berhasil dipindahkan ke \"{{folder}}\"",
|
||||
"failedToMoveToFolder": "Gagal memindahkan host ke folder",
|
||||
"clickToRenameFolder": "Klik untuk mengganti nama folder",
|
||||
"renameFolder": "Ganti nama folder",
|
||||
"removeFromFolder": "Hapus dari folder \"{{{folder}}\"",
|
||||
"removeFromFolder": "Hapus dari folder \"{{folder}}\"",
|
||||
"editHostTooltip": "Edit host",
|
||||
"deleteHostTooltip": "Hapus host",
|
||||
"exportHostTooltip": "Ekspor host",
|
||||
"cloneHostTooltip": "Kloning host",
|
||||
"clickToEditHost": "Klik untuk mengedit host",
|
||||
"dragToMoveBetweenFolders": "Seret untuk berpindah antar folder",
|
||||
"exportedHostConfig": "Konfigurasi host yang diekspor untuk {{folder}}",
|
||||
"exportedHostConfig": "Konfigurasi host yang diekspor untuk {{name}}",
|
||||
"openTerminal": "Terminal Terbuka",
|
||||
"openFileManager": "Buka Pengelola File",
|
||||
"openTunnels": "Terowongan Terbuka",
|
||||
@@ -982,7 +982,7 @@
|
||||
"selectFont": "Pilih font",
|
||||
"selectFontDesc": "Pilih font yang akan digunakan di terminal.",
|
||||
"fontSize": "Ukuran Huruf",
|
||||
"fontSizeValue": "Ukuran Huruf: {{name}}px",
|
||||
"fontSizeValue": "Ukuran Huruf: {{value}}px",
|
||||
"adjustFontSize": "Sesuaikan ukuran font terminal",
|
||||
"letterSpacing": "Jarak Antar Huruf",
|
||||
"letterSpacingValue": "Jarak Antar Huruf: {{value}}px",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "Suara",
|
||||
"bellStyleVisual": "Visual",
|
||||
"bellStyleBoth": "Keduanya",
|
||||
"bellStyleDesc": "Cara menangani bel terminal (karakter BEL, \\x07). Program memicu ini saat menyelesaikan tugas, menemukan kesalahan, atau untuk pemberitahuan. \"Sound\" memutar bunyi bip audio, \"Visual\" membuat layar berkedip sebentar, \"Both\" melakukan keduanya, \"None\" menonaktifkan peringatan bel.",
|
||||
"bellStyleDesc": "Cara menangani bel terminal (karakter BEL, \\x07). Program memicu ini saat menyelesaikan tugas, menemukan kesalahan, atau untuk pemberitahuan. \"Suara\" memutar bunyi bip audio, \"Visual\" membuat layar berkedip sebentar, \"Keduanya\" melakukan keduanya, \"Tidak ada\" menonaktifkan peringatan bel.",
|
||||
"rightClickSelectsWord": "Klik kanan memilih Word",
|
||||
"rightClickSelectsWordDesc": "Mengklik kanan akan memilih kata di bawah kursor.",
|
||||
"fastScrollModifier": "Pengubah Gulir Cepat",
|
||||
@@ -1066,7 +1066,7 @@
|
||||
"socks5UsePreset": "Gunakan Preset yang Tersimpan",
|
||||
"socks5SelectPreset": "Pilih Preset",
|
||||
"socks5ManagePresets": "Kelola Preset",
|
||||
"socks5ProxyNode": "Proksi {{value}}",
|
||||
"socks5ProxyNode": "Proksi {{number}}",
|
||||
"socks5AddProxy": "Tambahkan Proxy ke Rantai",
|
||||
"socks5RemoveProxy": "Hapus Proxy",
|
||||
"socks5ProxyType": "Jenis Proksi",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "Preset rantai proxy telah dibuat.",
|
||||
"socks5PresetUpdated": "Preset rantai proxy telah diperbarui.",
|
||||
"socks5PresetDeleted": "Pengaturan awal rantai proxy telah dihapus.",
|
||||
"socks5PresetSaved": "Preset \"{{{number}}\" berhasil disimpan",
|
||||
"socks5PresetSaved": "Preset \"{{name}}\" berhasil disimpan",
|
||||
"socks5PresetSaveError": "Gagal menyimpan preset.",
|
||||
"socks5PresetNameRequired": "Nama preset wajib diisi.",
|
||||
"socks5EmptyChainError": "Tidak dapat menyimpan rantai proksi kosong.",
|
||||
@@ -1118,8 +1118,8 @@
|
||||
"notEnabled": "Docker belum diaktifkan untuk host ini. Aktifkan di Pengaturan Host untuk menggunakan fitur Docker.",
|
||||
"validating": "Memvalidasi Docker...",
|
||||
"error": "Kesalahan",
|
||||
"errorCode": "Kode kesalahan: {{name}}",
|
||||
"version": "Docker v{{code}}",
|
||||
"errorCode": "Kode kesalahan: {{code}}",
|
||||
"version": "Docker v{{version}}",
|
||||
"current": "Saat ini",
|
||||
"used_limit": "Digunakan / Batas",
|
||||
"percentage": "Persentase",
|
||||
@@ -1133,10 +1133,10 @@
|
||||
"console": "Menghibur",
|
||||
"containerMustBeRunning": "Kontainer harus berjalan agar dapat terhubung ke konsol.",
|
||||
"authenticationRequired": "Diperlukan otentikasi.",
|
||||
"connectedTo": "Terhubung ke {{version}}",
|
||||
"connectedTo": "Terhubung ke {{containerName}}",
|
||||
"disconnected": "Terputus",
|
||||
"consoleError": "Kesalahan konsol",
|
||||
"errorMessage": "Kesalahan: {{containerName}}",
|
||||
"errorMessage": "Kesalahan: {{message}}",
|
||||
"failedToConnect": "Gagal terhubung ke konsol",
|
||||
"disconnectedFromContainer": "Terputus dari konsol kontainer.",
|
||||
"containerNotRunning": "Kontainer tidak berjalan",
|
||||
@@ -1150,28 +1150,28 @@
|
||||
"disconnect": "Memutuskan",
|
||||
"notConnected": "Tidak terhubung",
|
||||
"clickToConnect": "Klik Sambungkan untuk memulai shell interaktif.",
|
||||
"connectingTo": "Menghubungkan ke {{message}}...",
|
||||
"connectingTo": "Menghubungkan ke {{containerName}}...",
|
||||
"containerMustBeRunningToViewStats": "Kontainer harus berjalan agar statistik dapat dilihat.",
|
||||
"failedToFetchStats": "Gagal mengambil statistik.",
|
||||
"noContainersFound": "Tidak ditemukan wadah apa pun",
|
||||
"noContainersFoundHint": "Mulailah dengan membuat kontainer di server Anda.",
|
||||
"searchPlaceholder": "Cari berdasarkan nama, gambar, atau ID...",
|
||||
"filterByStatusPlaceholder": "Saring berdasarkan status",
|
||||
"allContainersCount": "Semua ({{containerName}})",
|
||||
"statusCount": "{{count}} ({{status}})",
|
||||
"allContainersCount": "Semua ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "Tidak ada wadah yang sesuai dengan filter Anda.",
|
||||
"noContainersMatchFiltersHint": "Cobalah menyesuaikan pencarian atau filter Anda.",
|
||||
"containerStarted": "Kontainer {{count}} dimulai",
|
||||
"failedToStartContainer": "Gagal memulai kontainer: {{name}}",
|
||||
"containerStopped": "Kontainer {{error}} berhenti",
|
||||
"failedToStopContainer": "Gagal menghentikan kontainer: {{name}}",
|
||||
"containerRestarted": "Kontainer {{error}} dimulai ulang",
|
||||
"failedToRestartContainer": "Gagal memulai ulang kontainer: {{name}}",
|
||||
"containerUnpaused": "Kontainer {{error}} tidak dijeda",
|
||||
"containerPaused": "Kontainer {{name}} berhenti sementara",
|
||||
"failedToTogglePauseContainer": "Gagal ke kontainer {{name}}: {{action}}",
|
||||
"containerRemoved": "Kontainer {{error}} dihapus",
|
||||
"failedToRemoveContainer": "Gagal menghapus kontainer: {{name}}",
|
||||
"containerStarted": "Kontainer {{name}} dimulai",
|
||||
"failedToStartContainer": "Gagal memulai kontainer: {{error}}",
|
||||
"containerStopped": "Kontainer {{name}} berhenti",
|
||||
"failedToStopContainer": "Gagal menghentikan kontainer: {{error}}",
|
||||
"containerRestarted": "Kontainer {{name}} dimulai ulang",
|
||||
"failedToRestartContainer": "Gagal memulai ulang kontainer: {{error}}",
|
||||
"containerUnpaused": "Kontainer {{name}} tidak dijeda",
|
||||
"containerPaused": "Kontainer {{name}} berhenti",
|
||||
"failedToTogglePauseContainer": "Gagal ke kontainer {{action}} : {{error}}",
|
||||
"containerRemoved": "Kontainer {{name}} dihapus",
|
||||
"failedToRemoveContainer": "Gagal menghapus kontainer: {{error}}",
|
||||
"image": "Gambar:",
|
||||
"idLabel": "PENGENAL:",
|
||||
"ports": "Pelabuhan:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "Berhenti sebentar",
|
||||
"restart": "Mulai ulang",
|
||||
"removeContainer": "Lepaskan Kontainer",
|
||||
"confirmRemoveContainer": "Apakah Anda yakin ingin menghapus kontainer \"{{error}}\"?",
|
||||
"confirmRemoveContainer": "Apakah Anda yakin ingin menghapus kontainer \"{{name}}\"?",
|
||||
"runningContainerWarning": "Peringatan: Kontainer ini sedang berjalan dan akan dihapus secara paksa.",
|
||||
"removing": "Menghapus:",
|
||||
"containerNotFound": "Kontainer tidak ditemukan",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"logs": "Log",
|
||||
"stats": "Statistik",
|
||||
"consoleTab": "Menghibur",
|
||||
"failedToFetchLogs": "Gagal mengambil log: {{name}}",
|
||||
"failedToFetchLogs": "Gagal mengambil log: {{error}}",
|
||||
"failedToDownloadLogs": "Gagal mengunduh log: {{error}}",
|
||||
"linesToShow": "Garis untuk menunjukkan",
|
||||
"last50Lines": "50 baris terakhir",
|
||||
@@ -1219,7 +1219,7 @@
|
||||
"reconnect": "Terhubung kembali",
|
||||
"sessionEnded": "Sesi Berakhir",
|
||||
"connectionLost": "Koneksi Terputus",
|
||||
"error": "KESALAHAN: {{error}}",
|
||||
"error": "KESALAHAN: {{message}}",
|
||||
"disconnected": "Terputus",
|
||||
"connectionClosed": "Koneksi terputus",
|
||||
"connectionError": "Kesalahan koneksi: {{message}}",
|
||||
@@ -1230,18 +1230,18 @@
|
||||
"messageParseError": "Gagal mengurai pesan server",
|
||||
"websocketError": "Kesalahan koneksi WebSocket",
|
||||
"connecting": "Menghubungkan...",
|
||||
"reconnecting": "Menghubungkan kembali... ({{message}}/{{attempt}})",
|
||||
"reconnecting": "Menghubungkan kembali... ({{attempt}}/{{max}})",
|
||||
"reconnected": "Berhasil terhubung kembali",
|
||||
"maxReconnectAttemptsReached": "Upaya penyambungan kembali maksimum telah tercapai.",
|
||||
"connectionTimeout": "Waktu habis koneksi",
|
||||
"terminalTitle": "Terminal - {{max}}",
|
||||
"terminalWithPath": "Terminal - {{host}}:{{host}}",
|
||||
"runTitle": "Menjalankan {{path}} - {{command}}",
|
||||
"terminalTitle": "Terminal - {{host}}",
|
||||
"terminalWithPath": "Terminal - {{host}}:{{path}}",
|
||||
"runTitle": "Menjalankan {{command}} - {{host}}",
|
||||
"totpRequired": "Diperlukan Otentikasi Dua Faktor",
|
||||
"totpCodeLabel": "Kode Verifikasi",
|
||||
"totpPlaceholder": "000000",
|
||||
"totpVerify": "Memeriksa",
|
||||
"sudoPasswordPopupTitle": "Masukkan Kata Sandi?",
|
||||
"sudoPasswordPopupTitle": "Masukkan kata sandi?",
|
||||
"sudoPasswordPopupHint": "Tekan Enter untuk memasukkan, Esc untuk menutup.",
|
||||
"sudoPasswordPopupConfirm": "Menyisipkan",
|
||||
"sudoPasswordPopupDismiss": "Membubarkan"
|
||||
@@ -1254,26 +1254,26 @@
|
||||
"uploadFile": "Unggah File",
|
||||
"downloadFile": "Unduh",
|
||||
"extractArchive": "Ekstrak Arsip",
|
||||
"extractingArchive": "Mengekstrak {{host}}...",
|
||||
"extractingArchive": "Mengekstrak {{name}}...",
|
||||
"archiveExtractedSuccessfully": "{{name}} berhasil diekstrak",
|
||||
"extractFailed": "Ekstraksi gagal",
|
||||
"compressFile": "Kompres File",
|
||||
"compressFiles": "Kompres File",
|
||||
"compressFilesDesc": "Kompres {{name}} item ke dalam arsip",
|
||||
"compressFilesDesc": "Kompres {{count}} item ke dalam arsip",
|
||||
"archiveName": "Nama Arsip",
|
||||
"enterArchiveName": "Masukkan nama arsip...",
|
||||
"compressionFormat": "Format Kompresi",
|
||||
"selectedFiles": "File terpilih",
|
||||
"andMoreFiles": "dan {{count}} lainnya...",
|
||||
"andMoreFiles": "dan {{count}} lagi...",
|
||||
"compress": "Kompres",
|
||||
"compressingFiles": "Mengompres {{count}} item menjadi {{count}}...",
|
||||
"compressingFiles": "Mengompres {{count}} item menjadi {{name}}...",
|
||||
"filesCompressedSuccessfully": "{{name}} berhasil dibuat",
|
||||
"compressFailed": "Kompresi gagal",
|
||||
"edit": "Edit",
|
||||
"preview": "Pratinjau",
|
||||
"previous": "Sebelumnya",
|
||||
"next": "Berikutnya",
|
||||
"pageXOfY": "Halaman {{name}} dari {{current}}",
|
||||
"pageXOfY": "Halaman {{current}} dari {{total}}",
|
||||
"zoomOut": "Perkecil tampilan",
|
||||
"zoomIn": "Perbesar",
|
||||
"newFile": "Berkas Baru",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "Pilih File",
|
||||
"uploading": "Sedang mengunggah...",
|
||||
"downloading": "Sedang mengunduh...",
|
||||
"uploadingFile": "Mengunggah {{total}}...",
|
||||
"uploadingLargeFile": "Mengunggah file besar {{name}} ({{name}})...",
|
||||
"downloadingFile": "Mengunduh {{size}}...",
|
||||
"uploadingFile": "Mengunggah {{name}}...",
|
||||
"uploadingLargeFile": "Mengunggah file besar {{name}} ({{size}})...",
|
||||
"downloadingFile": "Mengunduh {{name}}...",
|
||||
"creatingFile": "Membuat {{name}}...",
|
||||
"creatingFolder": "Membuat {{name}}...",
|
||||
"deletingItem": "Menghapus {{name}} {{type}}...",
|
||||
"renamingItem": "Mengganti nama {{name}} {{type}} menjadi {{oldName}}...",
|
||||
"deletingItem": "Menghapus {{type}} {{name}}...",
|
||||
"renamingItem": "Mengganti nama {{type}} {{oldName}} menjadi {{newName}}...",
|
||||
"createNewFile": "Buat File Baru",
|
||||
"fileName": "Nama File",
|
||||
"creating": "Membuat...",
|
||||
@@ -1311,21 +1311,21 @@
|
||||
"newName": "Nama Baru",
|
||||
"thisIsDirectoryRename": "Ini adalah direktori",
|
||||
"renaming": "Mengganti nama...",
|
||||
"fileUploadedSuccessfully": "Berkas \"{{{newName}}\" berhasil diunggah",
|
||||
"fileUploadedSuccessfully": "Berkas \"{{name}}\" berhasil diunggah",
|
||||
"failedToUploadFile": "Gagal mengunggah file",
|
||||
"fileDownloadedSuccessfully": "Berkas \"{{{name}}\" berhasil diunduh",
|
||||
"fileDownloadedSuccessfully": "File \"{{name}}\" berhasil diunduh",
|
||||
"failedToDownloadFile": "Gagal mengunduh file",
|
||||
"noFileContent": "Tidak ada konten file yang diterima.",
|
||||
"filePath": "Jalur File",
|
||||
"fileCreatedSuccessfully": "Berkas \"{{{name}}\" berhasil dibuat",
|
||||
"fileCreatedSuccessfully": "File \"{{name}}\" berhasil dibuat",
|
||||
"failedToCreateFile": "Gagal membuat file",
|
||||
"folderCreatedSuccessfully": "Folder \"{{{name}}\" berhasil dibuat",
|
||||
"folderCreatedSuccessfully": "Folder \"{{name}}\" berhasil dibuat",
|
||||
"failedToCreateFolder": "Gagal membuat folder",
|
||||
"failedToCreateItem": "Gagal membuat item",
|
||||
"operationFailed": "Operasi {{name}} gagal untuk {{operation}}: {{name}}",
|
||||
"operationFailed": "Operasi {{operation}} gagal untuk {{name}}: {{error}}",
|
||||
"failedToResolveSymlink": "Gagal menyelesaikan symlink",
|
||||
"itemDeletedSuccessfully": "{{error}} berhasil dihapus",
|
||||
"itemsDeletedSuccessfully": "{{type}} item berhasil dihapus",
|
||||
"itemDeletedSuccessfully": "{{type}} berhasil dihapus",
|
||||
"itemsDeletedSuccessfully": "{{count}} item berhasil dihapus",
|
||||
"failedToDeleteItems": "Gagal menghapus item",
|
||||
"dragFilesToUpload": "Seret file ke sini untuk mengunggah",
|
||||
"emptyFolder": "Folder ini kosong",
|
||||
@@ -1347,25 +1347,25 @@
|
||||
"delete": "Menghapus",
|
||||
"properties": "Properti",
|
||||
"refresh": "Menyegarkan",
|
||||
"downloadFiles": "Unduh {{count}} berkas ke Browser",
|
||||
"downloadFiles": "Unduh {{count}} file ke Browser",
|
||||
"copyFiles": "Salin {{count}} item",
|
||||
"cutFiles": "Potong {{count}} item",
|
||||
"deleteFiles": "Hapus {{count}} item",
|
||||
"filesCopiedToClipboard": "{{count}} item disalin ke papan klip",
|
||||
"filesCutToClipboard": "{{count}} item disalin ke papan klip",
|
||||
"filesCutToClipboard": "{{count}} item dipotong ke papan klip",
|
||||
"pathCopiedToClipboard": "Jalur disalin ke papan klip",
|
||||
"pathsCopiedToClipboard": "{{count}} jalur disalin ke papan klip",
|
||||
"failedToCopyPath": "Gagal menyalin jalur ke papan klip.",
|
||||
"movedItems": "Memindahkan {{count}} item",
|
||||
"failedToDeleteItem": "Gagal menghapus item",
|
||||
"itemRenamedSuccessfully": "{{count}} berhasil diganti namanya",
|
||||
"itemRenamedSuccessfully": "{{type}} berhasil diganti namanya",
|
||||
"failedToRenameItem": "Gagal mengganti nama item",
|
||||
"download": "Unduh",
|
||||
"permissions": "Izin",
|
||||
"size": "Ukuran",
|
||||
"modified": "Dimodifikasi",
|
||||
"path": "Jalur",
|
||||
"confirmDelete": "Apakah Anda yakin ingin menghapus {{type}}?",
|
||||
"confirmDelete": "Apakah Anda yakin ingin menghapus {{name}}?",
|
||||
"uploadSuccess": "File berhasil diunggah.",
|
||||
"uploadFailed": "Unggahan berkas gagal",
|
||||
"downloadSuccess": "File berhasil diunduh.",
|
||||
@@ -1390,9 +1390,9 @@
|
||||
"fileOperations": "Operasi File",
|
||||
"confirmDeleteMessage": "Apakah Anda yakin ingin menghapus {{name}}?",
|
||||
"confirmDeleteSingleItem": "Apakah Anda yakin ingin menghapus \"{{name}}\" secara permanen?",
|
||||
"confirmDeleteMultipleItems": "Apakah Anda yakin ingin menghapus {{name}} item secara permanen?",
|
||||
"confirmDeleteMultipleItems": "Apakah Anda yakin ingin menghapus {{count}} item secara permanen?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "Apakah Anda yakin ingin menghapus {{count}} item secara permanen? Ini termasuk folder dan isinya.",
|
||||
"confirmDeleteFolder": "Apakah Anda yakin ingin menghapus folder \"{{count}}{{name}}\" dan seluruh isinya secara permanen?",
|
||||
"confirmDeleteFolder": "Apakah Anda yakin ingin menghapus folder \"{{name}}\" beserta seluruh isinya secara permanen?",
|
||||
"deleteDirectoryWarning": "Ini akan menghapus folder dan semua isinya.",
|
||||
"actionCannotBeUndone": "Tindakan ini tidak dapat dibatalkan.",
|
||||
"permanentDeleteWarning": "Tindakan ini tidak dapat dibatalkan. Item tersebut akan dihapus secara permanen dari server.",
|
||||
@@ -1433,7 +1433,7 @@
|
||||
"unpinnedSuccessfully": "Pin \"{{name}}\" berhasil dilepas",
|
||||
"unpinFailed": "Gagal membuka pin",
|
||||
"removedShortcut": "Pintasan \"{{name}}\" telah dihapus",
|
||||
"removeShortcutFailed": "Penghapusan pintasan gagal",
|
||||
"removeShortcutFailed": "Penghapusan pintasan gagal.",
|
||||
"clearedAllRecentFiles": "Semua file terbaru telah dihapus.",
|
||||
"clearFailed": "Hapus gagal",
|
||||
"removeFromRecentFiles": "Hapus dari berkas terbaru",
|
||||
@@ -1449,7 +1449,7 @@
|
||||
"undoCopySuccess": "Batalkan operasi penyalinan: Menghapus {{count}} file yang disalin",
|
||||
"undoCopyFailedDelete": "Pembatalan gagal: Tidak dapat menghapus file yang disalin.",
|
||||
"undoCopyFailedNoInfo": "Pembatalan gagal: Informasi file yang disalin tidak ditemukan.",
|
||||
"undoMoveSuccess": "Operasi pemindahan dibatalkan: Memindahkan {{count}} file kembali ke lokasi semula",
|
||||
"undoMoveSuccess": "Operasi pemindahan dibatalkan: {{count}} berkas dipindahkan kembali ke lokasi semula",
|
||||
"undoMoveFailedMove": "Pembatalan gagal: Tidak dapat memindahkan file apa pun kembali.",
|
||||
"undoMoveFailedNoInfo": "Pembatalan gagal: Informasi file yang dipindahkan tidak ditemukan.",
|
||||
"undoDeleteNotSupported": "Operasi penghapusan tidak dapat dibatalkan: File telah dihapus secara permanen dari server.",
|
||||
@@ -1491,7 +1491,7 @@
|
||||
"unknownSize": "Ukuran tidak diketahui",
|
||||
"fileIsEmpty": "Berkas kosong",
|
||||
"largeFileWarning": "Peringatan Ukuran File Besar",
|
||||
"largeFileWarningDesc": "File ini berukuran {{size}}, yang dapat menyebabkan masalah kinerja saat dibuka sebagai teks.",
|
||||
"largeFileWarningDesc": "File ini berukuran {{size}} , yang dapat menyebabkan masalah kinerja saat dibuka sebagai teks.",
|
||||
"fileNotFoundAndRemoved": "Berkas \"{{name}}\" tidak ditemukan dan telah dihapus dari berkas terbaru/yang disematkan",
|
||||
"failedToLoadFile": "Gagal memuat file: {{error}}",
|
||||
"serverErrorOccurred": "Terjadi kesalahan server. Silakan coba lagi nanti.",
|
||||
@@ -1502,22 +1502,22 @@
|
||||
"canOnlyCompareFiles": "Hanya dapat membandingkan dua file.",
|
||||
"comparingFiles": "Membandingkan berkas: {{file1}} dan {{file2}}",
|
||||
"dragFailed": "Operasi seret gagal",
|
||||
"filePinnedSuccessfully": "Berkas \"{{{name}}\" berhasil disematkan",
|
||||
"filePinnedSuccessfully": "Berkas \"{{name}}\" berhasil disematkan",
|
||||
"pinFileFailed": "Gagal menyematkan file",
|
||||
"fileUnpinnedSuccessfully": "Berkas \"{{{name}}\" berhasil dilepas pinnya",
|
||||
"fileUnpinnedSuccessfully": "Berkas \"{{name}}\" berhasil dilepas pinnya",
|
||||
"unpinFileFailed": "Gagal melepaskan pin file",
|
||||
"shortcutAddedSuccessfully": "Pintasan folder \"{{{name}}\" berhasil ditambahkan",
|
||||
"shortcutAddedSuccessfully": "Pintasan folder \"{{name}}\" berhasil ditambahkan",
|
||||
"addShortcutFailed": "Gagal menambahkan pintasan",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} item berhasil",
|
||||
"operationCompleted": "{{operation}} {{count}} item",
|
||||
"downloadFileSuccess": "Berkas {{name}} berhasil diunduh",
|
||||
"downloadFileSuccess": "File {{name}} berhasil diunduh",
|
||||
"downloadFileFailed": "Pengunduhan gagal",
|
||||
"moveTo": "Pindah ke {{name}}",
|
||||
"diffCompareWith": "Bandingkan perbedaan dengan {{name}}",
|
||||
"dragOutsideToDownload": "Seret ke luar jendela untuk mengunduh (187 file)",
|
||||
"dragOutsideToDownload": "Seret ke luar jendela untuk mengunduh ({{count}} file)",
|
||||
"newFolderDefault": "Folder Baru",
|
||||
"newFileDefault": "File Baru.txt",
|
||||
"successfullyMovedItems": "Berhasil memindahkan {{count}} item ke {{count}}",
|
||||
"successfullyMovedItems": "Berhasil memindahkan {{count}} item ke {{target}}",
|
||||
"move": "Bergerak",
|
||||
"searchInFile": "Cari di dalam file (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "Tampilkan pintasan keyboard",
|
||||
@@ -1527,10 +1527,10 @@
|
||||
"compare": "Membandingkan",
|
||||
"sideBySide": "Berdampingan",
|
||||
"inline": "Sejajar",
|
||||
"fileComparison": "Perbandingan Berkas: {{target}} vs {{file1}}",
|
||||
"fileTooLarge": "Ukuran berkas terlalu besar: {{file2}}",
|
||||
"sshConnectionFailed": "Koneksi SSH gagal. Silakan periksa koneksi Anda ke {{error}} ({{name}}:{{ip}})",
|
||||
"loadFileFailed": "Gagal memuat file: {{port}}",
|
||||
"fileComparison": "Perbandingan File: {{file1}} vs {{file2}}",
|
||||
"fileTooLarge": "Ukuran file terlalu besar: {{error}}",
|
||||
"sshConnectionFailed": "Koneksi SSH gagal. Silakan periksa koneksi Anda ke {{name}} ({{ip}}:{{port}})",
|
||||
"loadFileFailed": "Gagal memuat file: {{error}}",
|
||||
"connectedSuccessfully": "Terhubung berhasil",
|
||||
"totpVerificationFailed": "Verifikasi TOTP gagal",
|
||||
"verificationCodePrompt": "Kode verifikasi:",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "Memutuskan",
|
||||
"cancel": "Membatalkan",
|
||||
"port": "Pelabuhan",
|
||||
"attempt": "Percobaan {{error}} dari {{current}}",
|
||||
"nextRetryIn": "Percobaan berikutnya dalam {{max}} detik",
|
||||
"attempt": "Percobaan {{current}} dari {{max}}",
|
||||
"nextRetryIn": "Percobaan berikutnya dalam {{seconds}} detik",
|
||||
"checkDockerLogs": "Periksa log Docker Anda untuk mengetahui penyebab kesalahan, bergabunglah dengan",
|
||||
"orCreate": "atau membuat",
|
||||
"orCreate": "atau membuat ",
|
||||
"noTunnelConnections": "Tidak ada koneksi terowongan yang dikonfigurasi.",
|
||||
"tunnelConnections": "Koneksi Terowongan",
|
||||
"addTunnel": "Tambahkan Terowongan",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"remote": "Terpencil",
|
||||
"dynamic": "Dinamis",
|
||||
"unknownConnectionStatus": "Tidak dikenal",
|
||||
"portMapping": "Pelabuhan {{seconds}} → {{sourcePort}}:{{endpointHost}}",
|
||||
"portMapping": "Port {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"endpointHostNotFound": "Host titik akhir tidak ditemukan",
|
||||
"discord": "Perselisihan",
|
||||
"githubIssue": "Masalah GitHub",
|
||||
@@ -1611,7 +1611,7 @@
|
||||
"disk": "Disk",
|
||||
"network": "Jaringan",
|
||||
"uptime": "Waktu aktif",
|
||||
"loadAverage": "Rata-rata: {{endpointPort}}, {{avg1}}, {{avg5}}",
|
||||
"loadAverage": "Rata-rata: {{avg1}}, {{avg5}}, {{avg15}}",
|
||||
"processes": "Proses",
|
||||
"connections": "Koneksi",
|
||||
"usage": "Penggunaan",
|
||||
@@ -1624,8 +1624,8 @@
|
||||
"refreshStatus": "Perbarui Status",
|
||||
"fileManagerAlreadyOpen": "Pengelola berkas sudah terbuka untuk host ini.",
|
||||
"openFileManager": "Buka Pengelola File",
|
||||
"cpuCores_one": "CPU 206",
|
||||
"cpuCores_other": "{{avg15}} CPU",
|
||||
"cpuCores_one": "{{count}} CPU",
|
||||
"cpuCores_other": "{{count}} CPU",
|
||||
"naCpus": "CPU tidak tersedia",
|
||||
"loadAverageNA": "Rata-rata: Tidak tersedia",
|
||||
"cpuUsage": "Penggunaan CPU",
|
||||
@@ -1650,7 +1650,7 @@
|
||||
"totpInvalidCode": "Kode verifikasi tidak valid",
|
||||
"totpCancelled": "Pengumpulan metrik dibatalkan",
|
||||
"authenticationFailed": "Autentikasi gagal",
|
||||
"noneAuthNotSupported": "Statistik Server tidak mendukung tipe otentikasi 'none'.",
|
||||
"noneAuthNotSupported": "Statistik Server tidak mendukung tipe autentikasi 'none'.",
|
||||
"load": "Memuat",
|
||||
"editLayout": "Edit Tata Letak",
|
||||
"cancelEdit": "Membatalkan",
|
||||
@@ -1669,7 +1669,7 @@
|
||||
"noInterfacesFound": "Tidak ditemukan antarmuka jaringan.",
|
||||
"totalProcesses": "Proses Total",
|
||||
"running": "Berlari",
|
||||
"noProcessesFound": "Tidak ada proses yang ditemukan",
|
||||
"noProcessesFound": "Tidak ada proses yang ditemukan.",
|
||||
"loginStats": "Statistik Login SSH",
|
||||
"totalLogins": "Total Login",
|
||||
"uniqueIPs": "IP Unik",
|
||||
@@ -1678,8 +1678,8 @@
|
||||
"noRecentLoginData": "Tidak ada data login terbaru.",
|
||||
"from": "dari",
|
||||
"quickActions": "Tindakan Cepat",
|
||||
"executeQuickAction": "Jalankan {{count}}",
|
||||
"executingQuickAction": "Menjalankan {{count}}...",
|
||||
"executeQuickAction": "Eksekusi {{name}}",
|
||||
"executingQuickAction": "Menjalankan {{name}}...",
|
||||
"quickActionSuccess": "{{name}} berhasil diselesaikan",
|
||||
"quickActionFailed": "{{name}} gagal",
|
||||
"quickActionError": "Gagal mengeksekusi {{name}}"
|
||||
@@ -1695,7 +1695,7 @@
|
||||
"loginButton": "Login",
|
||||
"registerButton": "Daftar",
|
||||
"forgotPassword": "Lupa kata sandi?",
|
||||
"rememberMe": "Ingat Aku",
|
||||
"rememberMe": "Ingatlah Aku",
|
||||
"noAccount": "Belum punya akun?",
|
||||
"hasAccount": "Sudah punya akun?",
|
||||
"loginSuccess": "Login berhasil.",
|
||||
@@ -1745,7 +1745,7 @@
|
||||
"sshNoKeyboardInteractiveDescription": "Server ini tidak mendukung autentikasi interaktif keyboard. Harap berikan kata sandi atau kunci SSH Anda.",
|
||||
"sshAuthFailedDescription": "Kredensial yang diberikan salah. Silakan coba lagi dengan kredensial yang valid.",
|
||||
"sshTimeoutDescription": "Upaya otentikasi telah habis waktu. Silakan coba lagi.",
|
||||
"sshProvideCredentialsDescription": "Harap berikan kredensial SSH Anda untuk terhubung ke server ini.",
|
||||
"sshProvideCredentialsDescription": "Silakan berikan kredensial SSH Anda untuk terhubung ke server ini.",
|
||||
"sshPasswordDescription": "Masukkan kata sandi untuk koneksi SSH ini.",
|
||||
"sshKeyPasswordDescription": "Jika kunci SSH Anda dienkripsi, masukkan kata sandi di sini.",
|
||||
"step1ScanQR": "Langkah 1: Pindai kode QR dengan aplikasi otentikasi Anda",
|
||||
@@ -1786,7 +1786,7 @@
|
||||
"desktopApp": "Aplikasi Desktop",
|
||||
"loggingInToDesktopApp": "Masuk ke aplikasi desktop",
|
||||
"loggingInToDesktopAppViaWeb": "Masuk ke aplikasi desktop melalui antarmuka web.",
|
||||
"loadingServer": "Memuat server...",
|
||||
"loadingServer": "Sedang memuat server...",
|
||||
"authenticating": "Sedang melakukan autentikasi...",
|
||||
"dataLossWarning": "Mengatur ulang kata sandi Anda dengan cara ini akan menghapus semua host SSH, kredensial, dan data terenkripsi lainnya yang telah Anda simpan. Tindakan ini tidak dapat dibatalkan. Gunakan cara ini hanya jika Anda lupa kata sandi dan belum masuk.",
|
||||
"authenticationDisabled": "Autentikasi Dinonaktifkan",
|
||||
@@ -1814,8 +1814,8 @@
|
||||
"invalidAuthUrl": "URL otorisasi yang diterima dari backend tidak valid.",
|
||||
"invalidInput": "Masukan tidak valid",
|
||||
"requiredField": "Kolom ini wajib diisi.",
|
||||
"minLength": "Panjang minimumnya adalah {{name}}",
|
||||
"maxLength": "Panjang maksimumnya adalah {{name}}",
|
||||
"minLength": "Panjang minimum adalah {{min}}",
|
||||
"maxLength": "Panjang maksimumnya adalah {{max}}",
|
||||
"invalidEmail": "Alamat email tidak valid",
|
||||
"passwordMismatch": "Kata sandi tidak cocok",
|
||||
"passwordLoginDisabled": "Login menggunakan nama pengguna/kata sandi saat ini dinonaktifkan.",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"updateError": "Pembaruan gagal",
|
||||
"copySuccess": "Disalin ke papan klip",
|
||||
"copyError": "Gagal menyalin",
|
||||
"copiedToClipboard": "{{min}} disalin ke papan klip",
|
||||
"copiedToClipboard": "{{item}} disalin ke papan klip",
|
||||
"connectionEstablished": "Koneksi berhasil terjalin.",
|
||||
"connectionClosed": "Koneksi terputus",
|
||||
"reconnecting": "Menghubungkan kembali...",
|
||||
@@ -1866,7 +1866,7 @@
|
||||
"external": "Eksternal (OIDC)",
|
||||
"externalAndLocal": "Otorisasi Ganda",
|
||||
"selectPreferredLanguage": "Pilih bahasa pilihan Anda untuk antarmuka.",
|
||||
"fileColorCoding": "Pengkodean Warna Berkas",
|
||||
"fileColorCoding": "Pengkodean Warna File",
|
||||
"fileColorCodingDesc": "Beri kode warna pada file berdasarkan jenisnya: folder (merah), file (biru), symlink (hijau)",
|
||||
"commandAutocomplete": "Pelengkapan Otomatis Perintah",
|
||||
"commandAutocompleteDesc": "Aktifkan saran pelengkapan otomatis tombol Tab untuk perintah terminal berdasarkan riwayat perintah Anda.",
|
||||
@@ -1883,7 +1883,7 @@
|
||||
"hostSidebarSettings": "Host & Sidebar",
|
||||
"snippetsSettings": "Cuplikan",
|
||||
"currentPassword": "Kata Sandi Saat Ini",
|
||||
"passwordChangedSuccess": "Kata sandi berhasil diubah! Silakan masuk lagi.",
|
||||
"passwordChangedSuccess": "Kata sandi berhasil diubah! Silakan masuk kembali.",
|
||||
"failedToChangePassword": "Perubahan kata sandi gagal. Silakan periksa kata sandi Anda saat ini dan coba lagi.",
|
||||
"theme": "Tema",
|
||||
"themeLight": "Lampu",
|
||||
@@ -1939,10 +1939,10 @@
|
||||
"currentPath": "Masukkan jalur saat ini ke item",
|
||||
"newName": "Masukkan nama baru",
|
||||
"socks5Host": "127.0.0.1",
|
||||
"socks5Username": "nama pengguna proksi",
|
||||
"socks5Username": "nama pengguna proxy",
|
||||
"socks5Password": "kata sandi proxy",
|
||||
"socks5PresetName": "misalnya, Rantai VPN Kantor",
|
||||
"socks5PresetDescription": "misalnya, Rantai proxy untuk mengakses server kerja",
|
||||
"socks5PresetDescription": "Contoh: Rantai proxy untuk mengakses server kerja",
|
||||
"moshCommand": "mosh user@server",
|
||||
"defaultPort": "22",
|
||||
"defaultEndpointPort": "224",
|
||||
@@ -1955,8 +1955,8 @@
|
||||
"passwordRequired": "Kata sandi diperlukan",
|
||||
"failedToDeleteAccount": "Gagal menghapus akun",
|
||||
"failedToMakeUserAdmin": "Gagal menjadikan pengguna sebagai admin.",
|
||||
"userIsNowAdmin": "Pengguna {{max}} sekarang menjadi admin",
|
||||
"removeAdminConfirm": "Apakah Anda yakin ingin menghapus status admin dari {{item}}?",
|
||||
"userIsNowAdmin": "Pengguna {{username}} sekarang menjadi admin",
|
||||
"removeAdminConfirm": "Apakah Anda yakin ingin menghapus status admin dari {{username}}?",
|
||||
"deleteUserConfirm": "Apakah Anda yakin ingin menghapus pengguna {{username}}? Tindakan ini tidak dapat dibatalkan.",
|
||||
"deleteAccount": "Hapus Akun",
|
||||
"closeDeleteAccount": "Tutup Hapus Akun",
|
||||
@@ -2142,7 +2142,7 @@
|
||||
"createTempUser": "Buat Pengguna Sementara",
|
||||
"createTempUserDesc": "Membuat pengguna terbatas di server sebagai pengganti berbagi kredensial Anda. Membutuhkan akses sudo. Opsi paling aman.",
|
||||
"expiresAt": "Berakhir pada",
|
||||
"expiresIn": "Berakhir dalam {{username}} jam",
|
||||
"expiresIn": "Berakhir dalam {{hours}} jam",
|
||||
"expired": "Kedaluwarsa",
|
||||
"grantedBy": "Diberikan Oleh",
|
||||
"accessLevel": "Tingkat Akses",
|
||||
@@ -2150,10 +2150,10 @@
|
||||
"accessCount": "Jumlah Akses",
|
||||
"revokeAccess": "Cabut Akses",
|
||||
"confirmRevokeAccess": "Apakah Anda yakin ingin mencabut akses untuk {{username}}?",
|
||||
"hostSharedSuccessfully": "Host berhasil berbagi dengan {{hours}}",
|
||||
"hostSharedSuccessfully": "Host berhasil berbagi dengan {{username}}",
|
||||
"hostAccessUpdated": "Akses host diperbarui",
|
||||
"failedToShareHost": "Gagal berbagi host",
|
||||
"accessRevokedSuccessfully": "Akses berhasil dicabut",
|
||||
"accessRevokedSuccessfully": "Akses berhasil dicabut.",
|
||||
"failedToRevokeAccess": "Gagal mencabut akses",
|
||||
"shared": "Dibagikan",
|
||||
"sharedHosts": "Penyedia Layanan Hosting Bersama",
|
||||
@@ -2165,26 +2165,26 @@
|
||||
"noAccessGranted": "Akses belum diberikan untuk host ini.",
|
||||
"noAccessGrantedMessage": "Belum ada pengguna yang diberikan akses ke host ini.",
|
||||
"manageAccessFor": "Kelola akses untuk",
|
||||
"totalAccessRecords": "{{username}} catatan akses",
|
||||
"totalAccessRecords": "{{count}} catatan akses",
|
||||
"neverAccessed": "Tidak pernah",
|
||||
"timesAccessed": "{{username}} kali",
|
||||
"daysRemaining": "{{count}} hari",
|
||||
"hoursRemaining": "{{count}} jam",
|
||||
"timesAccessed": "{{count}} waktu",
|
||||
"daysRemaining": "{{days}} hari",
|
||||
"hoursRemaining": "{{hours}} jam",
|
||||
"failedToFetchAccessList": "Gagal mengambil daftar akses",
|
||||
"currentAccess": "Akses Saat Ini",
|
||||
"securityWarning": "Peringatan Keamanan",
|
||||
"securityWarningMessage": "Berbagi kredensial memberi pengguna akses penuh untuk melakukan operasi apa pun di server, termasuk mengubah kata sandi dan menghapus file. Bagikan hanya dengan pengguna tepercaya.",
|
||||
"tempUserRecommended": "Kami menyarankan untuk mengaktifkan 'Buat Pengguna Sementara' untuk keamanan yang lebih baik.",
|
||||
"tempUserRecommended": "Kami menyarankan untuk mengaktifkan 'Buat Pengguna Sementara' demi keamanan yang lebih baik.",
|
||||
"roleManagement": "Manajemen Peran",
|
||||
"manageRoles": "Kelola Peran",
|
||||
"manageRolesFor": "Kelola peran untuk {{days}}",
|
||||
"manageRolesFor": "Kelola peran untuk {{username}}",
|
||||
"assignRole": "Tetapkan Peran",
|
||||
"removeRole": "Hapus Peran",
|
||||
"userRoles": "Peran Pengguna",
|
||||
"permissions": "Izin",
|
||||
"systemRole": "Peran Sistem",
|
||||
"customRole": "Peran Kustom",
|
||||
"roleAssignedSuccessfully": "Peran berhasil diberikan kepada {{hours}}",
|
||||
"roleAssignedSuccessfully": "Peran berhasil diberikan kepada {{username}}",
|
||||
"failedToAssignRole": "Gagal menetapkan peran",
|
||||
"roleRemovedSuccessfully": "Peran berhasil dihapus dari {{username}}",
|
||||
"failedToRemoveRole": "Gagal menghapus peran",
|
||||
@@ -2193,7 +2193,7 @@
|
||||
"noCustomRolesToAssign": "Tidak ada peran khusus yang tersedia. Peran sistem ditetapkan secara otomatis.",
|
||||
"credentialSharingWarning": "Autentikasi Kredensial Tidak Didukung untuk Berbagi",
|
||||
"credentialRequired": "Kredensial diperlukan saat berbagi host.",
|
||||
"credentialRequiredDescription": "Host ini tidak menggunakan autentikasi berbasis kredensial. Untuk berbagi host, karena enkripsi per pengguna, host harus menggunakan autentikasi berbasis kredensial.",
|
||||
"credentialRequiredDescription": "Host ini tidak menggunakan autentikasi berbasis kredensial. Untuk dapat berbagi host, karena enkripsi per pengguna, host harus menggunakan autentikasi berbasis kredensial.",
|
||||
"auditLogs": "Catatan Audit",
|
||||
"viewAuditLogs": "Lihat Log Audit",
|
||||
"action": "Tindakan",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "Akhiri Sesi",
|
||||
"sessionTerminated": "Sesi diakhiri oleh pemilik host.",
|
||||
"sharedAccessExpired": "Akses bersama Anda ke host ini telah kedaluwarsa.",
|
||||
"sharedAccessExpiresIn": "Akses bersama akan berakhir dalam {{username}} jam",
|
||||
"sharedAccessExpiresIn": "Akses bersama akan berakhir dalam {{hours}} jam",
|
||||
"roles": {
|
||||
"label": "Peran",
|
||||
"admin": "Administrator",
|
||||
@@ -2249,7 +2249,7 @@
|
||||
"displayNamePlaceholder": "Pengembang",
|
||||
"descriptionPlaceholder": "Pengembang dan insinyur perangkat lunak",
|
||||
"confirmDeleteRole": "Hapus Peran",
|
||||
"confirmDeleteRoleDescription": "Apakah Anda yakin ingin menghapus peran '{{username}}'? Tindakan ini tidak dapat dibatalkan.",
|
||||
"confirmDeleteRoleDescription": "Apakah Anda yakin ingin menghapus peran '{{name}}'? Tindakan ini tidak dapat dibatalkan.",
|
||||
"confirmRemoveRole": "Hapus Peran",
|
||||
"confirmRemoveRoleDescription": "Apakah Anda yakin ingin menghapus peran ini dari pengguna?",
|
||||
"editRoleDescription": "Perbarui informasi peran",
|
||||
@@ -2307,15 +2307,15 @@
|
||||
"validating": "Memvalidasi Docker...",
|
||||
"connectingToHost": "Menghubungkan ke host...",
|
||||
"error": "Kesalahan",
|
||||
"errorCode": "Kode kesalahan: {{hours}}",
|
||||
"version": "Docker {{name}}",
|
||||
"containerStarted": "Kontainer {{code}} dimulai",
|
||||
"failedToStartContainer": "Gagal memulai kontainer {{version}}",
|
||||
"errorCode": "Kode kesalahan: {{code}}",
|
||||
"version": "Docker {{version}}",
|
||||
"containerStarted": "Kontainer {{name}} dimulai",
|
||||
"failedToStartContainer": "Gagal memulai kontainer {{name}}",
|
||||
"containerStopped": "Kontainer {{name}} berhenti",
|
||||
"failedToStopContainer": "Gagal menghentikan kontainer {{name}}",
|
||||
"containerRestarted": "Kontainer {{name}} dihidupkan kembali",
|
||||
"containerRestarted": "Kontainer {{name}} dimulai ulang",
|
||||
"failedToRestartContainer": "Gagal memulai ulang kontainer {{name}}",
|
||||
"containerPaused": "Kontainer {{name}} berhenti sementara",
|
||||
"containerPaused": "Kontainer {{name}} berhenti",
|
||||
"containerUnpaused": "Kontainer {{name}} tidak dijeda",
|
||||
"failedToTogglePauseContainer": "Gagal mengubah status jeda untuk kontainer {{name}}",
|
||||
"containerRemoved": "Kontainer {{name}} dihapus",
|
||||
@@ -2340,8 +2340,8 @@
|
||||
"noContainersFoundHint": "Tidak ada kontainer Docker yang tersedia di host ini.",
|
||||
"searchPlaceholder": "Cari kontainer...",
|
||||
"filterByStatusPlaceholder": "Saring berdasarkan status",
|
||||
"allContainersCount": "Semua ({{name}})",
|
||||
"statusCount": "{{name}} ({{count}})",
|
||||
"allContainersCount": "Semua ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "Tidak ada wadah yang sesuai dengan filter Anda.",
|
||||
"noContainersMatchFiltersHint": "Cobalah menyesuaikan kriteria pencarian atau filter Anda.",
|
||||
"containerMustBeRunningToViewStats": "Kontainer harus berjalan agar statistik dapat dilihat.",
|
||||
@@ -2372,10 +2372,10 @@
|
||||
"authenticationRequired": "Diperlukan otentikasi.",
|
||||
"verificationCodePrompt": "Masukkan kode verifikasi",
|
||||
"totpVerificationFailed": "Verifikasi TOTP gagal. Silakan coba lagi.",
|
||||
"connectedTo": "Terhubung ke {{status}}",
|
||||
"connectedTo": "Terhubung ke {{containerName}}",
|
||||
"disconnected": "Terputus",
|
||||
"consoleError": "Kesalahan konsol",
|
||||
"errorMessage": "Kesalahan: {{count}}",
|
||||
"errorMessage": "Kesalahan: {{message}}",
|
||||
"failedToConnect": "Gagal terhubung ke kontainer",
|
||||
"console": "Menghibur",
|
||||
"selectShell": "Pilih cangkang",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "Beralih ke Cahaya",
|
||||
"switchToDark": "Beralih ke Gelap"
|
||||
}
|
||||
}
|
||||
}
|
||||
2402
src/locales/translated/it.json
Normal file
2402
src/locales/translated/it.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/ja.json
Normal file
2402
src/locales/translated/ja.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -128,7 +128,7 @@
|
||||
"created": "생성됨",
|
||||
"lastModified": "최종 수정일",
|
||||
"usageStatistics": "사용 통계",
|
||||
"copiedToClipboard": "{{field}}이 클립보드에 복사되었습니다",
|
||||
"copiedToClipboard": "{{field}} 클립보드에 복사됨",
|
||||
"failedToCopy": "클립보드에 복사하는 데 실패했습니다.",
|
||||
"sshKey": "SSH 키",
|
||||
"createCredentialDescription": "안전한 접속을 위해 새 SSH 자격 증명을 생성하세요.",
|
||||
@@ -136,7 +136,7 @@
|
||||
"listView": "목록",
|
||||
"folderView": "폴더",
|
||||
"unknownCredential": "알려지지 않은",
|
||||
"confirmRemoveFromFolder": "\"{{name}}\"를 \"{{folder}}\" 폴더에서 제거하시겠습니까? 자격 증명은 \"분류되지 않음\"으로 이동됩니다.",
|
||||
"confirmRemoveFromFolder": "\"{{folder}}\" 폴더에서 \"{{name}}\"을 삭제하시겠습니까? 자격 증명은 \"분류되지 않음\"으로 이동됩니다.",
|
||||
"removedFromFolder": "자격 증명 \"{{name}}\"이 폴더에서 성공적으로 제거되었습니다.",
|
||||
"failedToRemoveFromFolder": "폴더에서 자격 증명을 제거하는 데 실패했습니다.",
|
||||
"folderRenamed": "폴더 \"{{oldName}}\"의 이름이 \"{{newName}}\"로 성공적으로 변경되었습니다.",
|
||||
@@ -186,11 +186,11 @@
|
||||
},
|
||||
"dragIndicator": {
|
||||
"error": "오류: {{error}}",
|
||||
"dragging": "{{fileName}}을 끌어당기기",
|
||||
"preparing": "{{fileName}} 준비 중",
|
||||
"dragging": "드래그 중 {{fileName}}",
|
||||
"preparing": "{{fileName}}준비 중",
|
||||
"readySingle": "다운로드 준비 완료 {{fileName}}",
|
||||
"readyMultiple": "{{count}}개의 파일을 다운로드할 준비가 되었습니다.",
|
||||
"batchDrag": "{{count}}개의 파일을 바탕 화면으로 드래그하세요.",
|
||||
"readyMultiple": "{{count}} 파일을 다운로드할 준비가 되었습니다.",
|
||||
"batchDrag": "{{count}} 파일을 바탕 화면으로 드래그하세요.",
|
||||
"dragToDesktop": "바탕화면으로 드래그하세요",
|
||||
"canDragAnywhere": "바탕화면 어디든 파일을 드래그해서 옮길 수 있습니다."
|
||||
},
|
||||
@@ -202,7 +202,7 @@
|
||||
"stopKeyRecording": "키 녹음 중지",
|
||||
"selectTerminals": "터미널을 선택하세요:",
|
||||
"typeCommands": "명령어를 입력하세요(모든 키 지원):",
|
||||
"commandsWillBeSent": "명령은 선택된 {{count}}개의 터미널로 전송됩니다.",
|
||||
"commandsWillBeSent": "명령은 {{count}} 선택된 터미널로 전송됩니다.",
|
||||
"settings": "설정",
|
||||
"enableRightClickCopyPaste": "마우스 오른쪽 버튼을 클릭하여 복사/붙여넣기를 활성화합니다.",
|
||||
"shareIdeas": "SSH 도구의 향후 기능에 대한 아이디어가 있으신가요? 공유해 주세요!",
|
||||
@@ -230,7 +230,7 @@
|
||||
"createDescription": "빠른 실행을 위해 새로운 명령 스니펫을 만드세요.",
|
||||
"editDescription": "이 명령 조각을 편집하세요",
|
||||
"deleteConfirmTitle": "코드 조각 삭제",
|
||||
"deleteConfirmDescription": "\"{{name}}\"를 정말로 삭제하시겠습니까?",
|
||||
"deleteConfirmDescription": "\"{{name}}\"을 삭제하시겠습니까?",
|
||||
"createSuccess": "코드 조각이 성공적으로 생성되었습니다.",
|
||||
"updateSuccess": "코드 조각이 성공적으로 업데이트되었습니다.",
|
||||
"deleteSuccess": "스니펫이 성공적으로 삭제되었습니다.",
|
||||
@@ -239,7 +239,7 @@
|
||||
"deleteFailed": "코드 조각을 삭제하는 데 실패했습니다.",
|
||||
"failedToFetch": "코드 조각을 가져오는 데 실패했습니다.",
|
||||
"executeSuccess": "실행 중: {{name}}",
|
||||
"copySuccess": "\"{{name}}\"을 클립보드에 복사했습니다.",
|
||||
"copySuccess": "\"{{name}}\"를 클립보드에 복사했습니다.",
|
||||
"runTooltip": "터미널에서 다음 코드 조각을 실행하세요.",
|
||||
"copyTooltip": "코드 조각을 클립보드에 복사합니다",
|
||||
"editTooltip": "이 코드 조각을 수정하세요",
|
||||
@@ -248,7 +248,7 @@
|
||||
"reorderSameFolder": "같은 폴더 내에서만 스니펫 순서를 변경할 수 있습니다.",
|
||||
"reorderSuccess": "스니펫 순서가 성공적으로 재정렬되었습니다.",
|
||||
"reorderFailed": "스니펫 순서 변경에 실패했습니다.",
|
||||
"deleteFolderConfirm": "폴더 \"{{name}}\"를 삭제하세요. 모든 스니펫은 미분류로 이동합니다.",
|
||||
"deleteFolderConfirm": "\"{{name}}\" 폴더를 삭제하시겠습니까? 모든 스니펫은 미분류로 이동됩니다.",
|
||||
"deleteFolderSuccess": "폴더가 성공적으로 삭제되었습니다.",
|
||||
"deleteFolderFailed": "폴더 삭제에 실패했습니다",
|
||||
"updateFolderSuccess": "폴더가 성공적으로 업데이트되었습니다.",
|
||||
@@ -256,7 +256,7 @@
|
||||
"updateFolderFailed": "폴더 업데이트에 실패했습니다",
|
||||
"createFolderFailed": "폴더 생성에 실패했습니다",
|
||||
"selectTerminals": "터미널 선택 (선택 사항)",
|
||||
"executeOnSelected": "선택한 터미널 {{count}}개에서 실행합니다.",
|
||||
"executeOnSelected": "{{count}} 선택된 터미널에서 실행",
|
||||
"executeOnCurrent": "현재 터미널에서 실행 (여러 개를 선택하려면 클릭하세요)",
|
||||
"folder": "접는 사람",
|
||||
"selectFolder": "폴더를 선택하거나 비워 두세요.",
|
||||
@@ -274,13 +274,13 @@
|
||||
},
|
||||
"commandHistory": {
|
||||
"title": "역사",
|
||||
"searchPlaceholder": "검색 명령어...",
|
||||
"searchPlaceholder": "검색 명령...",
|
||||
"noTerminal": "활성화된 단말기 없음",
|
||||
"noTerminalHint": "터미널을 열어 명령 기록을 확인하세요.",
|
||||
"empty": "아직 명령 기록이 없습니다.",
|
||||
"emptyHint": "현재 실행 중인 터미널에서 명령어를 실행하여 터미널의 히스토리를 구축합니다.",
|
||||
"noResults": "명령어를 찾을 수 없습니다.",
|
||||
"noResultsHint": "\"{{query}}\"와 일치하는 명령이 없습니다.",
|
||||
"noResultsHint": "\"{{query}}\" 와 일치하는 명령이 없습니다.",
|
||||
"deleteSuccess": "명령이 기록에서 삭제되었습니다.",
|
||||
"deleteFailed": "삭제 명령에 실패했습니다.",
|
||||
"deleteTooltip": "삭제 명령",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "분할 화면이 지워졌습니다",
|
||||
"error": {
|
||||
"noAssignments": "레이아웃에 최소 하나 이상의 탭을 지정해 주세요.",
|
||||
"fillAllSlots": "지원하시려면 {{count}}개의 슬롯을 모두 채우신 후 지원해 주세요."
|
||||
"fillAllSlots": "지원하시려면 {{count}} 칸을 모두 채우신 후 지원해 주세요."
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -343,9 +343,9 @@
|
||||
"error": "버전 확인 오류",
|
||||
"checkFailed": "업데이트 확인에 실패했습니다.",
|
||||
"upToDate": "앱이 최신 버전입니다.",
|
||||
"currentVersion": "현재 버전 {{version}}을 실행 중입니다.",
|
||||
"currentVersion": "현재 {{version}}버전을 실행 중입니다.",
|
||||
"updateAvailable": "업데이트 가능",
|
||||
"newVersionAvailable": "새 버전이 출시되었습니다! 현재 {{current}} 버전을 사용 중이지만 {{latest}} 버전을 사용할 수 있습니다.",
|
||||
"newVersionAvailable": "새 버전이 나왔습니다! 현재 {{current}}을 실행 중이지만 {{latest}} 을 사용할 수 있습니다.",
|
||||
"releasedOn": "{{date}}에 출시됨",
|
||||
"downloadUpdate": "업데이트 다운로드",
|
||||
"dismiss": "해고하다",
|
||||
@@ -382,7 +382,7 @@
|
||||
"home": "집",
|
||||
"expired": "만료됨",
|
||||
"expiresToday": "오늘 만료됩니다",
|
||||
"expiresTomorrow": "{{days}}일 후에 만료됩니다",
|
||||
"expiresTomorrow": "{{days}} 일 후에 만료됩니다",
|
||||
"updateAvailable": "업데이트 가능",
|
||||
"sshPath": "SSH 경로",
|
||||
"localPath": "로컬 경로",
|
||||
@@ -508,8 +508,8 @@
|
||||
"tokenUrl": "토큰 URL",
|
||||
"updateSettings": "업데이트 설정",
|
||||
"confirmDelete": "이 사용자를 삭제하시겠습니까?",
|
||||
"confirmMakeAdmin": "{{username}}을 관리자로 지정하시겠습니까?",
|
||||
"confirmRemoveAdmin": "{{username}}에서 관리자 상태를 제거하시겠습니까?",
|
||||
"confirmMakeAdmin": "{{username}} 님을 관리자로 지정하시겠습니까?",
|
||||
"confirmRemoveAdmin": "{{username}}에서 관리자 권한을 제거하시겠습니까?",
|
||||
"externalAuthentication": "외부 인증(OIDC)",
|
||||
"configureExternalProvider": "OIDC/OAuth2 인증을 위해 외부 ID 공급자를 구성합니다.",
|
||||
"userIdentifierPath": "사용자 식별자 경로",
|
||||
@@ -547,12 +547,12 @@
|
||||
"failedToUpdateOidcConfig": "OIDC 구성 업데이트에 실패했습니다.",
|
||||
"failedToDisableOidcConfig": "OIDC 구성을 비활성화하는 데 실패했습니다.",
|
||||
"enterUsernameToMakeAdmin": "관리자 권한을 얻으려면 사용자 이름을 입력하세요.",
|
||||
"userIsNowAdmin": "사용자 {{username}}님이 이제 관리자입니다.",
|
||||
"userIsNowAdmin": "사용자 {{username}} 님이 이제 관리자입니다.",
|
||||
"failedToMakeUserAdmin": "사용자를 관리자로 만드는 데 실패했습니다.",
|
||||
"removeAdminStatus": "{{username}}에서 관리자 상태를 제거하시겠습니까?",
|
||||
"adminStatusRemoved": "{{username}}에서 관리자 상태가 제거되었습니다.",
|
||||
"failedToRemoveAdminStatus": "관리자 권한 제거에 실패했습니다.",
|
||||
"userDeletedSuccessfully": "사용자 {{username}}님이 성공적으로 삭제했습니다.",
|
||||
"userDeletedSuccessfully": "사용자 {{username}} 님이 성공적으로 삭제했습니다.",
|
||||
"failedToDeleteUser": "사용자 삭제에 실패했습니다",
|
||||
"overrideUserInfoUrl": "사용자 정보 URL 재정의 (필수 아님)",
|
||||
"failedToFetchSessions": "세션을 가져오는 데 실패했습니다.",
|
||||
@@ -564,12 +564,12 @@
|
||||
"sessionsRevokedSuccessfully": "세션이 성공적으로 취소되었습니다.",
|
||||
"linkToPasswordAccount": "비밀번호 계정 링크",
|
||||
"linkOIDCDialogTitle": "OIDC 계정을 비밀번호 계정에 연결",
|
||||
"linkOIDCDialogDescription": "{{username}}(OIDC 사용자)을 기존 암호 계정에 연결합니다. 이렇게 하면 암호 계정에 대한 이중 인증이 활성화됩니다.",
|
||||
"linkOIDCDialogDescription": "{{username}} (OIDC 사용자)를 기존 암호 계정에 연결합니다. 이렇게 하면 암호 계정에 이중 인증이 활성화됩니다.",
|
||||
"createUser": "사용자 생성",
|
||||
"createUserDescription": "사용자 이름과 비밀번호를 사용하여 새 로컬 사용자를 생성합니다.",
|
||||
"enterUsername": "사용자 이름을 입력하세요",
|
||||
"enterPassword": "비밀번호를 입력하세요",
|
||||
"userCreatedSuccessfully": "사용자 {{username}}님이 성공적으로 생성되었습니다.",
|
||||
"userCreatedSuccessfully": "사용자 {{username}} 님이 성공적으로 생성했습니다.",
|
||||
"failedToCreateUser": "사용자 생성에 실패했습니다",
|
||||
"manageUser": "사용자 관리",
|
||||
"manageUserDescription": "사용자 설정, 역할 및 권한을 관리합니다.",
|
||||
@@ -581,7 +581,7 @@
|
||||
"administratorRole": "관리자 역할",
|
||||
"administratorRoleDescription": "전체 시스템 접근 권한 및 관리 권한을 부여하십시오.",
|
||||
"passwordManagement": "비밀번호 관리",
|
||||
"passwordResetWarning": "사용자 암호를 재설정하면 해당 사용자의 모든 데이터(SSH 호스트, 자격 증명, 설정)가 삭제됩니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"passwordResetWarning": "사용자 비밀번호를 재설정하면 해당 사용자의 모든 데이터(SSH 호스트, 자격 증명, 설정)가 삭제됩니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"resetUserPassword": "사용자 비밀번호 재설정",
|
||||
"resettingPassword": "재설정 중...",
|
||||
"passwordResetInitiated": "{{username}}에 대한 비밀번호 재설정이 시작되었습니다. 재설정 코드가 전송되었습니다.",
|
||||
@@ -611,12 +611,12 @@
|
||||
"linkTargetUsernamePlaceholder": "사용자 이름과 비밀번호를 입력하세요.",
|
||||
"linkAccountsButton": "계정 연동",
|
||||
"linkingAccounts": "연결 중...",
|
||||
"accountsLinkedSuccessfully": "OIDC 사용자 {{oidcUsername}}이 {{targetUsername}}에 연결되었습니다.",
|
||||
"accountsLinkedSuccessfully": "OIDC 사용자 {{oidcUsername}} 가 {{targetUsername}}에 연결되었습니다.",
|
||||
"failedToLinkAccounts": "계정 연결에 실패했습니다",
|
||||
"linkTargetUsernameRequired": "대상 사용자 이름은 필수입니다.",
|
||||
"unlinkOIDCTitle": "OIDC 인증 연결 해제",
|
||||
"unlinkOIDCDescription": "{{username}}에서 OIDC 인증을 제거하시겠습니까? 이렇게 하면 사용자는 사용자 이름/비밀번호로만 로그인할 수 있습니다.",
|
||||
"unlinkOIDCSuccess": "OIDC는 {{username}}에서 연결이 해제되었습니다.",
|
||||
"unlinkOIDCSuccess": "OIDC가 {{username}}에서 연결 해제되었습니다.",
|
||||
"failedToUnlinkOIDC": "OIDC 연결 해제에 실패했습니다.",
|
||||
"databaseSecurity": "데이터베이스 보안",
|
||||
"encryptionStatus": "암호화 상태",
|
||||
@@ -756,9 +756,9 @@
|
||||
"revokeAllUserSessionsTitle": "이 사용자에 대한 모든 세션을 취소합니다.",
|
||||
"revokeAll": "모두 취소",
|
||||
"linkOidcToPasswordAccount": "OIDC 계정을 비밀번호 계정에 연결",
|
||||
"linkOidcToPasswordAccountDescription": "{{username}}(OIDC 사용자)를 기존 암호 계정에 연결합니다. 이렇게 하면 암호 계정에 대한 이중 인증이 활성화됩니다.",
|
||||
"linkOidcToPasswordAccountDescription": "{{username}} (OIDC 사용자)를 기존 암호 계정에 연결합니다. 이렇게 하면 암호 계정에 이중 인증이 활성화됩니다.",
|
||||
"linkOidcWarningTitle": "경고: OIDC 사용자 데이터가 삭제됩니다.",
|
||||
"linkOidcWarningDescription": "이 조치는 다음과 같은 결과를 가져올 것입니다:",
|
||||
"linkOidcWarningDescription": "이 작업은 다음과 같은 결과를 가져올 것입니다:",
|
||||
"linkOidcActionDeleteUser": "OIDC 사용자 계정과 해당 계정의 모든 데이터를 삭제하세요.",
|
||||
"linkOidcActionAddCapability": "대상 암호 계정에 OIDC 로그인 기능을 추가합니다.",
|
||||
"linkOidcActionDualAuth": "비밀번호 계정이 비밀번호와 OIDC 모두를 사용하여 로그인할 수 있도록 허용합니다.",
|
||||
@@ -787,7 +787,7 @@
|
||||
"exportCredentialWarning": "경고: 호스트 \"{{name}}\"는 자격 증명 인증을 사용합니다. 내보낸 파일에는 자격 증명 데이터가 포함되지 않으므로 가져온 후 수동으로 다시 구성해야 합니다. 계속하시겠습니까?",
|
||||
"exportSensitiveDataWarning": "경고: 호스트 \"{{name}}\"에 민감한 인증 데이터(암호/SSH 키)가 포함되어 있습니다. 내보낸 파일에는 이 데이터가 평문으로 포함됩니다. 파일을 안전하게 보관하고 사용 후 삭제하십시오. 계속하시겠습니까?",
|
||||
"uncategorized": "분류되지 않음",
|
||||
"confirmDelete": "\"{{name}}\"를 정말로 삭제하시겠습니까?",
|
||||
"confirmDelete": "\"{{name}}\" 을 정말로 삭제하시겠습니까?",
|
||||
"failedToDeleteHost": "호스트 삭제에 실패했습니다",
|
||||
"failedToExportHost": "호스트 내보내기에 실패했습니다. 로그인되어 있고 호스트 데이터에 접근 권한이 있는지 확인하십시오.",
|
||||
"jsonMustContainHosts": "JSON에는 \"hosts\" 배열이 포함되어 있거나 호스트 배열이어야 합니다.",
|
||||
@@ -837,10 +837,10 @@
|
||||
"connection": "연결",
|
||||
"remove": "제거하다",
|
||||
"sourcePort": "소스 포트",
|
||||
"sourcePortDesc": "(출처는 일반 탭의 현재 연결 세부 정보입니다.)",
|
||||
"sourcePortDesc": " (출처는 일반 탭의 현재 연결 세부 정보입니다.)",
|
||||
"endpointPort": "엔드포인트 포트",
|
||||
"endpointSshConfig": "엔드포인트 SSH 구성",
|
||||
"tunnelForwardDescription": "이 터널은 소스 머신(일반 탭의 현재 연결 세부 정보)의 포트 {{sourcePort}}에서 엔드포인트 머신의 포트 {{endpointPort}}로 트래픽을 전달합니다.",
|
||||
"tunnelForwardDescription": "이 터널은 소스 머신(일반 탭의 현재 연결 세부 정보 참조)의 포트 {{sourcePort}} 에서 엔드포인트 머신의 포트 {{endpointPort}} 로 트래픽을 전달합니다.",
|
||||
"maxRetries": "최대 재시도 횟수",
|
||||
"maxRetriesDescription": "터널 연결에 대한 최대 재시도 횟수입니다.",
|
||||
"retryInterval": "재시도 간격(초)",
|
||||
@@ -916,7 +916,7 @@
|
||||
"customCommandsDesc": "이 서버에 대한 사용자 지정 종료 및 재부팅 명령을 정의하십시오.",
|
||||
"shutdownCommand": "종료 명령",
|
||||
"rebootCommand": "재부팅 명령",
|
||||
"confirmRemoveFromFolder": "\"{{name}}\"를 \"{{folder}}\" 폴더에서 제거하시겠습니까? 호스트가 \"폴더 없음\"으로 이동됩니다.",
|
||||
"confirmRemoveFromFolder": "\"{{folder}}\" 폴더에서 \"{{name}}\"를 삭제하시겠습니까? 호스트가 \"폴더 없음\"으로 이동됩니다.",
|
||||
"removedFromFolder": "호스트 \"{{name}}\"가 폴더에서 성공적으로 제거되었습니다.",
|
||||
"failedToRemoveFromFolder": "호스트를 폴더에서 제거하는 데 실패했습니다.",
|
||||
"folderRenamed": "폴더 \"{{oldName}}\"의 이름이 \"{{newName}}\"로 성공적으로 변경되었습니다.",
|
||||
@@ -929,10 +929,10 @@
|
||||
"folderAppearanceUpdated": "폴더 모양이 성공적으로 업데이트되었습니다.",
|
||||
"failedToUpdateFolderAppearance": "폴더 모양 업데이트에 실패했습니다.",
|
||||
"deleteAllHostsInFolder": "폴더 안의 모든 호스트를 삭제합니다",
|
||||
"confirmDeleteAllHostsInFolder": "폴더 \"{{count}}\"에 있는 모든 {{folder}} 호스트를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"allHostsInFolderDeleted": "폴더 \"{{count}}\"에서 호스트 {{folder}}개를 성공적으로 삭제했습니다.",
|
||||
"confirmDeleteAllHostsInFolder": "\"{{folder}}\" 폴더에 있는 모든 {{count}} 호스트를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"allHostsInFolderDeleted": "폴더 \"{{folder}}\"에서 {{count}} 호스트를 성공적으로 삭제했습니다.",
|
||||
"failedToDeleteHostsInFolder": "폴더에서 호스트를 삭제하는 데 실패했습니다.",
|
||||
"movedToFolder": "호스트 \"{{name}}\"이 \"{{folder}}\"으로 성공적으로 이동했습니다.",
|
||||
"movedToFolder": "호스트 \"{{name}}\"가 \"{{folder}}\"로 성공적으로 이동했습니다.",
|
||||
"failedToMoveToFolder": "호스트를 폴더로 이동하는 데 실패했습니다.",
|
||||
"clickToRenameFolder": "폴더 이름을 바꾸려면 클릭하세요",
|
||||
"renameFolder": "폴더 이름 변경",
|
||||
@@ -982,13 +982,13 @@
|
||||
"selectFont": "글꼴을 선택하세요",
|
||||
"selectFontDesc": "터미널에서 사용할 글꼴을 선택하세요.",
|
||||
"fontSize": "글꼴 크기",
|
||||
"fontSizeValue": "글꼴 크기: {{value}}px",
|
||||
"fontSizeValue": "글꼴 크기: {{value}}픽셀",
|
||||
"adjustFontSize": "터미널 글꼴 크기를 조정하세요",
|
||||
"letterSpacing": "글자 간격",
|
||||
"letterSpacingValue": "글자 간격: {{value}}px",
|
||||
"letterSpacingValue": "글자 간격: {{value}}픽셀",
|
||||
"adjustLetterSpacing": "문자 간 간격을 조정하세요",
|
||||
"lineHeight": "선 높이",
|
||||
"lineHeightValue": "줄 높이: {{value}}",
|
||||
"lineHeightValue": "선 높이: {{value}}",
|
||||
"adjustLineHeight": "줄 간격을 조정하세요",
|
||||
"cursorStyle": "커서 스타일",
|
||||
"selectCursorStyle": "커서 스타일을 선택하세요",
|
||||
@@ -999,7 +999,7 @@
|
||||
"cursorBlink": "커서 깜빡임",
|
||||
"enableCursorBlink": "커서 깜빡임 애니메이션 활성화",
|
||||
"scrollbackBuffer": "스크롤백 버퍼",
|
||||
"scrollbackBufferValue": "스크롤백 버퍼: {{value}}줄",
|
||||
"scrollbackBufferValue": "스크롤백 버퍼: {{value}} 줄",
|
||||
"scrollbackBufferDesc": "스크롤백 기록에 유지할 줄 수",
|
||||
"bellStyle": "벨 스타일",
|
||||
"selectBellStyle": "벨 스타일을 선택하세요",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "소리",
|
||||
"bellStyleVisual": "시각",
|
||||
"bellStyleBoth": "둘 다",
|
||||
"bellStyleDesc": "터미널 알림음(BEL 문자, \\x07)을 처리하는 방법입니다. 프로그램은 작업 완료, 오류 발생 또는 알림 시 이 알림음을 발생시킵니다. \"소리\"는 알림음을 재생하고, \"시각\"은 화면을 잠시 깜빡이게 하며, \"둘 다\"는 소리와 깜빡임 모두를 표시하고, \"없음\"은 알림음을 비활성화합니다.",
|
||||
"bellStyleDesc": "터미널 알림음(BEL 문자, \\x07)을 처리하는 방법입니다. 프로그램은 작업 완료, 오류 발생 또는 알림 시 이 알림음을 발생시킵니다. \"소리\"는 경고음을 재생하고, \"시각\"은 화면을 잠깐 깜빡이게 하며, \"둘 다\"는 경고음과 화면 깜빡임을 모두 표시하고, \"없음\"은 알림음을 비활성화합니다.",
|
||||
"rightClickSelectsWord": "마우스 오른쪽 버튼을 클릭하고 단어를 선택하세요.",
|
||||
"rightClickSelectsWordDesc": "마우스 오른쪽 버튼을 클릭하면 커서 아래에 있는 단어가 선택됩니다.",
|
||||
"fastScrollModifier": "빠른 스크롤 수정자",
|
||||
@@ -1030,7 +1030,7 @@
|
||||
"backspaceModeControlH": "컨트롤-H (^H)",
|
||||
"backspaceModeDesc": "호환성을 위한 백스페이스 키 동작",
|
||||
"startupSnippet": "스타트업 스니펫",
|
||||
"selectSnippet": "코드 조각을 선택하세요",
|
||||
"selectSnippet": "스니펫을 선택하세요",
|
||||
"searchSnippets": "검색 스니펫...",
|
||||
"snippetNone": "없음",
|
||||
"noneAuthTitle": "키보드 인터랙티브 인증",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"socks5HostDescription": "SOCKS 프록시 서버의 호스트 이름 또는 IP 주소",
|
||||
"socks5PortDescription": "SOCKS 프록시 서버의 포트 번호(기본값: 1080)",
|
||||
"addProxyNode": "프록시 노드 추가",
|
||||
"noProxyNodes": "구성된 프록시 노드가 없습니다. 프록시 노드를 추가하려면 '프록시 노드 추가'를 클릭하십시오.",
|
||||
"noProxyNodes": "구성된 프록시 노드가 없습니다. '프록시 노드 추가'를 클릭하여 추가하세요.",
|
||||
"proxyNode": "프록시 노드",
|
||||
"proxyType": "프록시 유형",
|
||||
"quickActions": "빠른 조치",
|
||||
@@ -1100,7 +1100,7 @@
|
||||
"sudoPasswordAutoFill": "Sudo 비밀번호 자동 완성",
|
||||
"sudoPasswordAutoFillDesc": "sudo 명령어가 암호를 입력하라는 메시지를 표시할 때 SSH 암호를 자동으로 입력하도록 제안합니다.",
|
||||
"sudoPassword": "Sudo 비밀번호",
|
||||
"sudoPasswordDesc": "sudo 명령어에 사용할 수 있는 선택적 암호 (키 인증 시 유용)",
|
||||
"sudoPasswordDesc": "sudo 명령어에 사용할 선택적 암호 (키 인증 시 유용)",
|
||||
"socks4": "양말4개",
|
||||
"socks5": "양말5",
|
||||
"executeSnippetOnConnect": "터미널이 연결될 때 코드 조각을 실행합니다.",
|
||||
@@ -1140,7 +1140,7 @@
|
||||
"failedToConnect": "콘솔에 연결하지 못했습니다.",
|
||||
"disconnectedFromContainer": "컨테이너 콘솔 연결이 끊어졌습니다.",
|
||||
"containerNotRunning": "컨테이너가 실행 중이 아닙니다.",
|
||||
"startContainerToAccess": "콘솔에 접속하려면 컨테이너를 시작하세요.",
|
||||
"startContainerToAccess": "콘솔에 접근하려면 컨테이너를 시작하세요.",
|
||||
"selectShell": "쉘을 선택하세요",
|
||||
"bash": "세게 때리다",
|
||||
"sh": "쉿",
|
||||
@@ -1160,17 +1160,17 @@
|
||||
"allContainersCount": "모두 ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "필터 조건에 맞는 컨테이너가 없습니다.",
|
||||
"noContainersMatchFiltersHint": "검색 또는 필터 조건을 조정해 보세요.",
|
||||
"noContainersMatchFiltersHint": "검색 또는 필터 설정을 조정해 보세요.",
|
||||
"containerStarted": "컨테이너 {{name}} 시작됨",
|
||||
"failedToStartContainer": "컨테이너 시작 실패: {{error}}",
|
||||
"containerStopped": "컨테이너 {{name}}가 중지되었습니다.",
|
||||
"failedToStopContainer": "컨테이너를 중지하는 데 실패했습니다: {{error}}",
|
||||
"containerRestarted": "컨테이너 {{name}}가 재시작되었습니다.",
|
||||
"containerStopped": "컨테이너 {{name}} 가 중지되었습니다.",
|
||||
"failedToStopContainer": "컨테이너 {{error}}를 중지하는 데 실패했습니다.",
|
||||
"containerRestarted": "컨테이너 {{name}} 가 재시작되었습니다.",
|
||||
"failedToRestartContainer": "컨테이너 재시작 실패: {{error}}",
|
||||
"containerUnpaused": "컨테이너 {{name}} 일시 중지 해제됨",
|
||||
"containerPaused": "컨테이너 {{name}} 일시 중지됨",
|
||||
"failedToTogglePauseContainer": "컨테이너 {{action}}에 실패했습니다: {{error}}",
|
||||
"containerRemoved": "컨테이너 {{name}}이 제거되었습니다.",
|
||||
"failedToTogglePauseContainer": "{{action}} 컨테이너에 실패했습니다: {{error}}",
|
||||
"containerRemoved": "컨테이너 {{name}} 가 제거되었습니다.",
|
||||
"failedToRemoveContainer": "컨테이너 {{error}}를 제거하는 데 실패했습니다.",
|
||||
"image": "영상:",
|
||||
"idLabel": "ID:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "정지시키다",
|
||||
"restart": "재시작",
|
||||
"removeContainer": "컨테이너를 제거하세요",
|
||||
"confirmRemoveContainer": "컨테이너 \"{{name}}\"을 정말로 제거하시겠습니까?",
|
||||
"confirmRemoveContainer": "컨테이너 \"{{name}}\"를 정말로 제거하시겠습니까?",
|
||||
"runningContainerWarning": "경고: 이 컨테이너는 현재 실행 중이며 강제로 제거될 예정입니다.",
|
||||
"removing": "풀이:",
|
||||
"containerNotFound": "컨테이너를 찾을 수 없습니다",
|
||||
@@ -1236,7 +1236,7 @@
|
||||
"connectionTimeout": "연결 시간 초과",
|
||||
"terminalTitle": "터미널 - {{host}}",
|
||||
"terminalWithPath": "터미널 - {{host}}:{{path}}",
|
||||
"runTitle": "{{command}} - {{host}} 실행 중",
|
||||
"runTitle": "{{command}} - {{host}}실행 중",
|
||||
"totpRequired": "2단계 인증이 필요합니다",
|
||||
"totpCodeLabel": "인증 코드",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1254,26 +1254,26 @@
|
||||
"uploadFile": "파일 업로드",
|
||||
"downloadFile": "다운로드",
|
||||
"extractArchive": "압축 해제",
|
||||
"extractingArchive": "{{name}} 추출 중...",
|
||||
"archiveExtractedSuccessfully": "{{name}}이 성공적으로 추출되었습니다.",
|
||||
"extractingArchive": "{{name}}추출 중...",
|
||||
"archiveExtractedSuccessfully": "{{name}} 추출 성공",
|
||||
"extractFailed": "추출 실패",
|
||||
"compressFile": "파일 압축",
|
||||
"compressFiles": "파일 압축",
|
||||
"compressFilesDesc": "{{count}}개의 항목을 아카이브로 압축합니다.",
|
||||
"compressFilesDesc": "{{count}} 항목을 아카이브로 압축합니다.",
|
||||
"archiveName": "아카이브 이름",
|
||||
"enterArchiveName": "아카이브 이름을 입력하세요...",
|
||||
"compressionFormat": "압축 형식",
|
||||
"selectedFiles": "선택된 파일",
|
||||
"andMoreFiles": "그리고 {{count}}개 더...",
|
||||
"andMoreFiles": "그리고 {{count}} 더 보기...",
|
||||
"compress": "압박 붕대",
|
||||
"compressingFiles": "{{count}}개의 항목을 {{name}}개로 압축 중...",
|
||||
"filesCompressedSuccessfully": "{{name}}가 성공적으로 생성되었습니다.",
|
||||
"compressingFiles": "{{count}} 항목을 {{name}}로 압축 중...",
|
||||
"filesCompressedSuccessfully": "{{name}} 이 성공적으로 생성되었습니다",
|
||||
"compressFailed": "압축 실패",
|
||||
"edit": "편집하다",
|
||||
"preview": "시사",
|
||||
"previous": "이전의",
|
||||
"next": "다음",
|
||||
"pageXOfY": "{{current}} 페이지 {{total}}",
|
||||
"pageXOfY": "{{total}}의 페이지 {{current}}",
|
||||
"zoomOut": "축소하기",
|
||||
"zoomIn": "확대",
|
||||
"newFile": "새 파일",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "파일을 선택하세요",
|
||||
"uploading": "업로드 중...",
|
||||
"downloading": "다운로드 중...",
|
||||
"uploadingFile": "{{name}} 업로드 중...",
|
||||
"uploadingLargeFile": "대용량 파일 {{name}} ({{size}}) 업로드 중...",
|
||||
"downloadingFile": "{{name}} 다운로드 중...",
|
||||
"creatingFile": "{{name}}를 생성하는 중...",
|
||||
"creatingFolder": "{{name}}을 생성하는 중...",
|
||||
"deletingItem": "{{type}} {{name}} 삭제 중...",
|
||||
"renamingItem": "{{type}} {{oldName}}를 {{newName}}로 이름 변경 중...",
|
||||
"uploadingFile": "{{name}}업로드 중...",
|
||||
"uploadingLargeFile": "대용량 파일 {{name}} ({{size}} ) 업로드 중...",
|
||||
"downloadingFile": "{{name}}다운로드 중...",
|
||||
"creatingFile": "{{name}}생성 중...",
|
||||
"creatingFolder": "{{name}}생성 중...",
|
||||
"deletingItem": "{{type}} {{name}}삭제 중...",
|
||||
"renamingItem": "{{type}} {{oldName}} 를 {{newName}}로 이름 변경 중...",
|
||||
"createNewFile": "새 파일 만들기",
|
||||
"fileName": "파일 이름",
|
||||
"creating": "생성 중...",
|
||||
@@ -1314,23 +1314,23 @@
|
||||
"fileUploadedSuccessfully": "파일 \"{{name}}\"이 성공적으로 업로드되었습니다.",
|
||||
"failedToUploadFile": "파일 업로드에 실패했습니다",
|
||||
"fileDownloadedSuccessfully": "파일 \"{{name}}\"이 성공적으로 다운로드되었습니다.",
|
||||
"failedToDownloadFile": "파일 다운로드에 실패했습니다.",
|
||||
"failedToDownloadFile": "파일 다운로드에 실패했습니다",
|
||||
"noFileContent": "파일 내용이 수신되지 않았습니다.",
|
||||
"filePath": "파일 경로",
|
||||
"fileCreatedSuccessfully": "파일 \"{{name}}\"이 성공적으로 생성되었습니다.",
|
||||
"failedToCreateFile": "파일 생성에 실패했습니다.",
|
||||
"folderCreatedSuccessfully": "폴더 \"{{name}}\"가 성공적으로 생성되었습니다.",
|
||||
"folderCreatedSuccessfully": "폴더 \"{{name}}\"이 성공적으로 생성되었습니다.",
|
||||
"failedToCreateFolder": "폴더 생성에 실패했습니다",
|
||||
"failedToCreateItem": "아이템 생성에 실패했습니다",
|
||||
"operationFailed": "{{operation}} 작업이 {{name}}에 대해 실패했습니다: {{error}}",
|
||||
"operationFailed": "{{operation}} 작업이 {{name}}에 대해 실패했습니다 : {{error}}",
|
||||
"failedToResolveSymlink": "심볼릭 링크를 해결할 수 없습니다.",
|
||||
"itemDeletedSuccessfully": "{{type}}이 성공적으로 삭제되었습니다.",
|
||||
"itemsDeletedSuccessfully": "{{count}}개의 항목이 성공적으로 삭제되었습니다.",
|
||||
"itemDeletedSuccessfully": "{{type}} 성공적으로 삭제되었습니다",
|
||||
"itemsDeletedSuccessfully": "{{count}} 항목이 성공적으로 삭제되었습니다",
|
||||
"failedToDeleteItems": "항목 삭제에 실패했습니다",
|
||||
"dragFilesToUpload": "파일을 여기에 드롭하여 업로드하세요",
|
||||
"emptyFolder": "이 폴더는 비어 있습니다",
|
||||
"itemCount": "{{count}}개 항목",
|
||||
"selectedCount": "{{count}}명이 선택했습니다",
|
||||
"itemCount": "{{count}} 항목",
|
||||
"selectedCount": "{{count}} 선택됨",
|
||||
"searchFiles": "파일을 검색하세요...",
|
||||
"upload": "업로드",
|
||||
"selectHostToStart": "파일 관리를 시작할 호스트를 선택하십시오.",
|
||||
@@ -1347,28 +1347,28 @@
|
||||
"delete": "삭제",
|
||||
"properties": "속성",
|
||||
"refresh": "새로 고치다",
|
||||
"downloadFiles": "브라우저에 {{count}}개의 파일을 다운로드하세요",
|
||||
"copyFiles": "{{count}}개 항목을 복사합니다.",
|
||||
"cutFiles": "{{count}}개 항목을 잘라냅니다.",
|
||||
"deleteFiles": "{{count}}개 항목을 삭제합니다.",
|
||||
"filesCopiedToClipboard": "{{count}}개의 항목이 클립보드에 복사되었습니다.",
|
||||
"filesCutToClipboard": "{{count}}개의 항목이 클립보드에 잘렸습니다.",
|
||||
"downloadFiles": "브라우저로 {{count}} 파일을 다운로드하세요",
|
||||
"copyFiles": "{{count}} 항목을 복사하세요",
|
||||
"cutFiles": "{{count}} 항목을 잘라내세요",
|
||||
"deleteFiles": "{{count}} 항목을 삭제합니다.",
|
||||
"filesCopiedToClipboard": "{{count}} 항목이 클립보드에 복사되었습니다",
|
||||
"filesCutToClipboard": "{{count}} 항목을 클립보드에 복사합니다",
|
||||
"pathCopiedToClipboard": "경로가 클립보드에 복사되었습니다",
|
||||
"pathsCopiedToClipboard": "{{count}}개의 경로가 클립보드에 복사되었습니다.",
|
||||
"pathsCopiedToClipboard": "{{count}} 경로가 클립보드에 복사되었습니다",
|
||||
"failedToCopyPath": "클립보드에 경로를 복사하는 데 실패했습니다.",
|
||||
"movedItems": "{{count}}개의 항목을 이동했습니다.",
|
||||
"movedItems": "{{count}} 항목을 이동했습니다.",
|
||||
"failedToDeleteItem": "항목 삭제에 실패했습니다",
|
||||
"itemRenamedSuccessfully": "{{type}} 이름이 성공적으로 변경되었습니다.",
|
||||
"itemRenamedSuccessfully": "{{type}} 이름이 성공적으로 변경되었습니다",
|
||||
"failedToRenameItem": "항목 이름 변경에 실패했습니다",
|
||||
"download": "다운로드",
|
||||
"permissions": "권한",
|
||||
"size": "크기",
|
||||
"modified": "수정됨",
|
||||
"path": "길",
|
||||
"confirmDelete": "{{name}}을 삭제하시겠습니까?",
|
||||
"confirmDelete": "{{name}}를 정말로 삭제하시겠습니까?",
|
||||
"uploadSuccess": "파일 업로드 완료",
|
||||
"uploadFailed": "파일 업로드 실패",
|
||||
"downloadSuccess": "파일 다운로드가 완료되었습니다.",
|
||||
"downloadSuccess": "파일 다운로드 완료",
|
||||
"downloadFailed": "파일 다운로드 실패",
|
||||
"permissionDenied": "권한이 거부되었습니다",
|
||||
"checkDockerLogs": "자세한 오류 정보는 Docker 로그를 확인하세요.",
|
||||
@@ -1388,11 +1388,11 @@
|
||||
"connectToServer": "서버에 연결",
|
||||
"selectServerToEdit": "사이드바에서 서버를 선택하여 파일 편집을 시작하세요.",
|
||||
"fileOperations": "파일 작업",
|
||||
"confirmDeleteMessage": "{{name}}을 정말로 삭제하시겠습니까?",
|
||||
"confirmDeleteMessage": "{{name}}를 정말로 삭제하시겠습니까?",
|
||||
"confirmDeleteSingleItem": "\"{{name}}\"을 영구적으로 삭제하시겠습니까?",
|
||||
"confirmDeleteMultipleItems": "{{count}}개의 항목을 영구적으로 삭제하시겠습니까?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "{{count}}개의 항목을 영구적으로 삭제하시겠습니까? 여기에는 폴더와 그 내용물이 포함됩니다.",
|
||||
"confirmDeleteFolder": "폴더 \"{{name}}\"와 그 안에 있는 모든 내용을 영구적으로 삭제하시겠습니까?",
|
||||
"confirmDeleteMultipleItems": "{{count}} 항목을 영구적으로 삭제하시겠습니까?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "{{count}} 항목을 영구적으로 삭제하시겠습니까? 폴더와 그 내용물이 모두 포함됩니다.",
|
||||
"confirmDeleteFolder": "폴더 \"{{name}}\"와 그 안의 모든 내용을 영구적으로 삭제하시겠습니까?",
|
||||
"deleteDirectoryWarning": "이렇게 하면 폴더와 그 안에 있는 모든 내용이 삭제됩니다.",
|
||||
"actionCannotBeUndone": "이 작업은 되돌릴 수 없습니다.",
|
||||
"permanentDeleteWarning": "이 작업은 되돌릴 수 없습니다. 해당 항목은 서버에서 영구적으로 삭제됩니다.",
|
||||
@@ -1430,9 +1430,9 @@
|
||||
"directories": "디렉토리",
|
||||
"removedFromRecentFiles": "최근 파일에서 \"{{name}}\"를 제거했습니다.",
|
||||
"removeFailed": "제거 실패",
|
||||
"unpinnedSuccessfully": "고정 해제됨 \"{{name}}\" 성공적으로",
|
||||
"unpinnedSuccessfully": "\"{{name}}\" 고정 해제 성공",
|
||||
"unpinFailed": "핀 해제 실패",
|
||||
"removedShortcut": "바로가기 \"{{name}}\"을 제거했습니다.",
|
||||
"removedShortcut": "바로가기 \"{{name}}\"를 제거했습니다.",
|
||||
"removeShortcutFailed": "바로가기 제거 실패",
|
||||
"clearedAllRecentFiles": "최근 파일을 모두 삭제했습니다.",
|
||||
"clearFailed": "지우기 실패",
|
||||
@@ -1440,16 +1440,16 @@
|
||||
"clearAllRecentFiles": "최근 파일을 모두 삭제합니다.",
|
||||
"unpinFile": "파일 고정 해제",
|
||||
"removeShortcut": "바로가기 제거",
|
||||
"saveFilesToSystem": "{{count}}개의 파일을 다음과 같이 저장하세요...",
|
||||
"saveFilesToSystem": "{{count}} 파일을 다음과 같이 저장하세요...",
|
||||
"pinFile": "핀 파일",
|
||||
"addToShortcuts": "바로가기에 추가",
|
||||
"downloadToDefaultLocation": "기본 위치로 다운로드",
|
||||
"pasteFailed": "붙여넣기 실패",
|
||||
"noUndoableActions": "되돌릴 수 없는 작업",
|
||||
"undoCopySuccess": "실행 취소된 복사 작업: 복사된 파일 {{count}}개가 삭제되었습니다.",
|
||||
"undoCopySuccess": "실행 취소된 복사 작업: {{count}} 개의 복사된 파일이 삭제되었습니다.",
|
||||
"undoCopyFailedDelete": "실행 취소 실패: 복사된 파일을 삭제할 수 없습니다.",
|
||||
"undoCopyFailedNoInfo": "실행 취소 실패: 복사된 파일 정보를 찾을 수 없습니다.",
|
||||
"undoMoveSuccess": "이동 취소 작업: {{count}}개의 파일을 원래 위치로 되돌렸습니다.",
|
||||
"undoMoveSuccess": "이동 취소 작업: {{count}} 파일을 원래 위치로 되돌렸습니다.",
|
||||
"undoMoveFailedMove": "실행 취소 실패: 파일을 되돌릴 수 없습니다.",
|
||||
"undoMoveFailedNoInfo": "실행 취소 실패: 이동된 파일 정보를 찾을 수 없습니다.",
|
||||
"undoDeleteNotSupported": "삭제 작업은 되돌릴 수 없습니다. 파일이 서버에서 영구적으로 삭제되었습니다.",
|
||||
@@ -1491,8 +1491,8 @@
|
||||
"unknownSize": "크기 미상",
|
||||
"fileIsEmpty": "파일이 비어 있습니다",
|
||||
"largeFileWarning": "대용량 파일 경고",
|
||||
"largeFileWarningDesc": "이 파일의 크기는 {{size}}이므로 텍스트로 열면 성능 문제가 발생할 수 있습니다.",
|
||||
"fileNotFoundAndRemoved": "파일 \"{{name}}\"을 찾을 수 없어 최근/고정된 파일 목록에서 제거되었습니다.",
|
||||
"largeFileWarningDesc": "이 파일의 크기는 {{size}} 이므로 텍스트 모드로 열면 성능 문제가 발생할 수 있습니다.",
|
||||
"fileNotFoundAndRemoved": "파일 \"{{name}}\"을(를) 찾을 수 없어 최근/고정된 파일 목록에서 제거되었습니다.",
|
||||
"failedToLoadFile": "파일 로드 실패: {{error}}",
|
||||
"serverErrorOccurred": "서버 오류가 발생했습니다. 나중에 다시 시도해 주세요.",
|
||||
"autoSaveFailed": "자동 저장 실패",
|
||||
@@ -1504,22 +1504,22 @@
|
||||
"dragFailed": "드래그 작업이 실패했습니다.",
|
||||
"filePinnedSuccessfully": "파일 \"{{name}}\"이 성공적으로 고정되었습니다.",
|
||||
"pinFileFailed": "파일 고정 실패",
|
||||
"fileUnpinnedSuccessfully": "파일 \"{{name}}\"의 고정 해제가 성공적으로 완료되었습니다.",
|
||||
"fileUnpinnedSuccessfully": "파일 \"{{name}}\"이 성공적으로 고정 해제되었습니다.",
|
||||
"unpinFileFailed": "파일 고정 해제에 실패했습니다.",
|
||||
"shortcutAddedSuccessfully": "폴더 바로가기 \"{{name}}\"가 성공적으로 추가되었습니다.",
|
||||
"addShortcutFailed": "바로가기 추가에 실패했습니다",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}}개 항목이 성공적으로 완료되었습니다.",
|
||||
"operationCompleted": "{{operation}} {{count}}개",
|
||||
"downloadFileSuccess": "파일 {{name}}이 성공적으로 다운로드되었습니다.",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} 항목이 성공적으로 완료되었습니다",
|
||||
"operationCompleted": "{{operation}} {{count}} 항목",
|
||||
"downloadFileSuccess": "파일 {{name}} 이 성공적으로 다운로드되었습니다.",
|
||||
"downloadFileFailed": "다운로드 실패",
|
||||
"moveTo": "{{name}}로 이동",
|
||||
"diffCompareWith": "{{name}}과 비교",
|
||||
"dragOutsideToDownload": "다운로드하려면 창 밖으로 드래그하세요({{count}}개 파일)",
|
||||
"diffCompareWith": "{{name}}와 차이점을 비교합니다.",
|
||||
"dragOutsideToDownload": "다운로드하려면 창 바깥쪽으로 드래그하세요({{count}} 파일).",
|
||||
"newFolderDefault": "새 폴더",
|
||||
"newFileDefault": "NewFile.txt",
|
||||
"successfullyMovedItems": "{{count}}개의 항목을 {{target}}로 성공적으로 이동했습니다.",
|
||||
"successfullyMovedItems": "{{count}} 항목을 {{target}}로 성공적으로 이동했습니다.",
|
||||
"move": "이동하다",
|
||||
"searchInFile": "파일 내 검색(Ctrl+F)",
|
||||
"searchInFile": "파일에서 검색(Ctrl+F)",
|
||||
"showKeyboardShortcuts": "키보드 단축키 표시",
|
||||
"startWritingMarkdown": "마크다운 콘텐츠 작성을 시작하세요...",
|
||||
"loadingFileComparison": "파일 비교 로딩 중...",
|
||||
@@ -1529,7 +1529,7 @@
|
||||
"inline": "인라인",
|
||||
"fileComparison": "파일 비교: {{file1}} vs {{file2}}",
|
||||
"fileTooLarge": "파일 크기가 너무 큽니다: {{error}}",
|
||||
"sshConnectionFailed": "SSH 연결에 실패했습니다. {{name}}({{ip}}:{{port}})에 대한 연결을 확인하십시오.",
|
||||
"sshConnectionFailed": "SSH 연결에 실패했습니다. {{name}} ({{ip}}:{{port}})에 대한 연결을 확인하십시오.",
|
||||
"loadFileFailed": "파일 로드 실패: {{error}}",
|
||||
"connectedSuccessfully": "성공적으로 연결되었습니다",
|
||||
"totpVerificationFailed": "TOTP 인증 실패",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "연결을 끊으세요",
|
||||
"cancel": "취소",
|
||||
"port": "포트",
|
||||
"attempt": "{{current}}의 시도 {{max}}",
|
||||
"nextRetryIn": "다음 재시도까지 {{seconds}}초 소요",
|
||||
"attempt": "{{max}}의 {{current}} 시도",
|
||||
"nextRetryIn": "다음 재시도 후 {{seconds}} 초",
|
||||
"checkDockerLogs": "오류 원인을 확인하려면 Docker 로그를 확인하고, 참여하세요.",
|
||||
"orCreate": "또는 생성하다",
|
||||
"orCreate": "또는 생성 ",
|
||||
"noTunnelConnections": "구성된 터널 연결이 없습니다.",
|
||||
"tunnelConnections": "터널 연결",
|
||||
"addTunnel": "터널 추가",
|
||||
@@ -1586,7 +1586,7 @@
|
||||
"localPort": "현지 항구",
|
||||
"remoteHost": "원격 호스트",
|
||||
"remotePort": "원격 포트",
|
||||
"autoStart": "자동 시동",
|
||||
"autoStart": "자동 시작",
|
||||
"status": "상태",
|
||||
"active": "활동적인",
|
||||
"inactive": "비활성화됨",
|
||||
@@ -1650,7 +1650,7 @@
|
||||
"totpInvalidCode": "잘못된 인증 코드입니다.",
|
||||
"totpCancelled": "데이터 수집이 취소되었습니다",
|
||||
"authenticationFailed": "인증 실패",
|
||||
"noneAuthNotSupported": "서버 통계는 'none' 인증 유형을 지원하지 않습니다.",
|
||||
"noneAuthNotSupported": "서버 통계는 '없음' 인증 유형을 지원하지 않습니다.",
|
||||
"load": "짐",
|
||||
"editLayout": "레이아웃 편집",
|
||||
"cancelEdit": "취소",
|
||||
@@ -1678,11 +1678,11 @@
|
||||
"noRecentLoginData": "최근 로그인 데이터가 없습니다.",
|
||||
"from": "~에서",
|
||||
"quickActions": "빠른 조치",
|
||||
"executeQuickAction": "{{name}}을 실행하세요",
|
||||
"executingQuickAction": "{{name}} 실행 중...",
|
||||
"quickActionSuccess": "{{name}}이 성공적으로 완료되었습니다.",
|
||||
"executeQuickAction": "{{name}}를 실행하세요",
|
||||
"executingQuickAction": "{{name}}실행 중...",
|
||||
"quickActionSuccess": "{{name}} 성공적으로 완료되었습니다",
|
||||
"quickActionFailed": "{{name}} 실패",
|
||||
"quickActionError": "{{name}} 실행에 실패했습니다."
|
||||
"quickActionError": "{{name}}실행에 실패했습니다."
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "SSH 서버 관리자",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"updateError": "업데이트에 실패했습니다",
|
||||
"copySuccess": "클립보드에 복사됨",
|
||||
"copyError": "복사에 실패했습니다",
|
||||
"copiedToClipboard": "{{item}}가 클립보드에 복사되었습니다.",
|
||||
"copiedToClipboard": "{{item}} 클립보드에 복사됨",
|
||||
"connectionEstablished": "연결이 설정되었습니다.",
|
||||
"connectionClosed": "연결이 종료되었습니다",
|
||||
"reconnecting": "다시 연결 중...",
|
||||
@@ -1880,7 +1880,7 @@
|
||||
"languageLocalization": "언어 및 현지화",
|
||||
"fileManagerSettings": "파일 관리자",
|
||||
"terminalSettings": "단말기",
|
||||
"hostSidebarSettings": "호스트 & 사이드바",
|
||||
"hostSidebarSettings": "호스트 및 사이드바",
|
||||
"snippetsSettings": "짧은 발췌",
|
||||
"currentPassword": "현재 비밀번호",
|
||||
"passwordChangedSuccess": "비밀번호가 변경되었습니다! 다시 로그인해 주세요.",
|
||||
@@ -1942,7 +1942,7 @@
|
||||
"socks5Username": "프록시 사용자 이름",
|
||||
"socks5Password": "프록시 비밀번호",
|
||||
"socks5PresetName": "예: 업무용 VPN 체인",
|
||||
"socks5PresetDescription": "예: 작업 서버 접속용 프록시 체인",
|
||||
"socks5PresetDescription": "예: 업무 서버 접속을 위한 프록시 체인",
|
||||
"moshCommand": "mosh 사용자@서버",
|
||||
"defaultPort": "22",
|
||||
"defaultEndpointPort": "224",
|
||||
@@ -1955,9 +1955,9 @@
|
||||
"passwordRequired": "비밀번호가 필요합니다",
|
||||
"failedToDeleteAccount": "계정 삭제에 실패했습니다",
|
||||
"failedToMakeUserAdmin": "사용자를 관리자로 만드는 데 실패했습니다.",
|
||||
"userIsNowAdmin": "사용자 {{username}}님이 이제 관리자입니다.",
|
||||
"removeAdminConfirm": "{{username}}에서 관리자 상태를 제거하시겠습니까?",
|
||||
"deleteUserConfirm": "사용자 {{username}}을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"userIsNowAdmin": "사용자 {{username}} 님이 이제 관리자입니다.",
|
||||
"removeAdminConfirm": "{{username}}에서 관리자 권한을 제거하시겠습니까?",
|
||||
"deleteUserConfirm": "사용자 {{username}}를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"deleteAccount": "계정 삭제",
|
||||
"closeDeleteAccount": "닫기 계정 삭제",
|
||||
"deleteAccountWarning": "이 작업은 되돌릴 수 없습니다. 계정과 관련된 모든 데이터가 영구적으로 삭제됩니다.",
|
||||
@@ -2142,15 +2142,15 @@
|
||||
"createTempUser": "임시 사용자 생성",
|
||||
"createTempUserDesc": "자격 증명을 공유하는 대신 서버에 제한된 사용자 계정을 생성합니다. sudo 권한이 필요하며, 가장 안전한 옵션입니다.",
|
||||
"expiresAt": "만료일",
|
||||
"expiresIn": "{{hours}}시간 후에 만료됩니다",
|
||||
"expiresIn": "{{hours}} 시간 후에 만료됩니다",
|
||||
"expired": "만료됨",
|
||||
"grantedBy": "승인자:",
|
||||
"accessLevel": "접근 수준",
|
||||
"lastAccessed": "최근 접속일",
|
||||
"accessCount": "접근 횟수",
|
||||
"revokeAccess": "접근 권한 취소",
|
||||
"confirmRevokeAccess": "{{username}}에 대한 액세스 권한을 취소하시겠습니까?",
|
||||
"hostSharedSuccessfully": "호스트가 {{username}}과 성공적으로 공유되었습니다.",
|
||||
"confirmRevokeAccess": "{{username}}에 대한 접근 권한을 취소하시겠습니까?",
|
||||
"hostSharedSuccessfully": "호스트가 {{username}}와 성공적으로 공유되었습니다.",
|
||||
"hostAccessUpdated": "호스트 액세스가 업데이트되었습니다.",
|
||||
"failedToShareHost": "호스트 공유에 실패했습니다",
|
||||
"accessRevokedSuccessfully": "접근 권한이 성공적으로 취소되었습니다.",
|
||||
@@ -2165,11 +2165,11 @@
|
||||
"noAccessGranted": "이 호스트에 대한 액세스 권한이 부여되지 않았습니다.",
|
||||
"noAccessGrantedMessage": "아직 이 호스트에 대한 접근 권한이 부여된 사용자는 없습니다.",
|
||||
"manageAccessFor": "액세스 관리",
|
||||
"totalAccessRecords": "{{count}} 액세스 레코드",
|
||||
"totalAccessRecords": "{{count}} 액세스 레코드(들)",
|
||||
"neverAccessed": "절대",
|
||||
"timesAccessed": "{{count}}번",
|
||||
"daysRemaining": "{{days}}일",
|
||||
"hoursRemaining": "{{hours}}시간",
|
||||
"timesAccessed": "{{count}} 시간(초)",
|
||||
"daysRemaining": "{{days}} 일",
|
||||
"hoursRemaining": "{{hours}} 시간(초)",
|
||||
"failedToFetchAccessList": "접근 권한 목록을 가져오는 데 실패했습니다.",
|
||||
"currentAccess": "현재 액세스",
|
||||
"securityWarning": "보안 경고",
|
||||
@@ -2184,9 +2184,9 @@
|
||||
"permissions": "권한",
|
||||
"systemRole": "시스템 역할",
|
||||
"customRole": "사용자 지정 역할",
|
||||
"roleAssignedSuccessfully": "{{username}}에게 역할이 성공적으로 할당되었습니다.",
|
||||
"roleAssignedSuccessfully": "{{username}} 에 역할이 성공적으로 할당되었습니다.",
|
||||
"failedToAssignRole": "역할 할당에 실패했습니다",
|
||||
"roleRemovedSuccessfully": "{{username}}에서 역할이 성공적으로 제거되었습니다.",
|
||||
"roleRemovedSuccessfully": "{{username}} 에서 역할이 성공적으로 제거되었습니다.",
|
||||
"failedToRemoveRole": "역할 제거에 실패했습니다",
|
||||
"cannotRemoveSystemRole": "시스템 역할을 제거할 수 없습니다",
|
||||
"cannotShareWithSelf": "본인과 호스트를 공유할 수 없습니다.",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "세션 종료",
|
||||
"sessionTerminated": "호스트 소유자에 의해 세션이 종료되었습니다.",
|
||||
"sharedAccessExpired": "이 호스트에 대한 공유 액세스 권한이 만료되었습니다.",
|
||||
"sharedAccessExpiresIn": "공유 액세스는 {{hours}}시간 후에 만료됩니다.",
|
||||
"sharedAccessExpiresIn": "공유 액세스는 {{hours}} 시간 후에 만료됩니다.",
|
||||
"roles": {
|
||||
"label": "역할",
|
||||
"admin": "관리자",
|
||||
@@ -2249,7 +2249,7 @@
|
||||
"displayNamePlaceholder": "개발자",
|
||||
"descriptionPlaceholder": "소프트웨어 개발자 및 엔지니어",
|
||||
"confirmDeleteRole": "역할 삭제",
|
||||
"confirmDeleteRoleDescription": "역할 '{{name}}'을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"confirmDeleteRoleDescription": "'{{name}}' 역할을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||
"confirmRemoveRole": "역할 제거",
|
||||
"confirmRemoveRoleDescription": "이 사용자에게서 해당 역할을 제거하시겠습니까?",
|
||||
"editRoleDescription": "역할 정보 업데이트",
|
||||
@@ -2310,16 +2310,16 @@
|
||||
"errorCode": "오류 코드: {{code}}",
|
||||
"version": "도커 {{version}}",
|
||||
"containerStarted": "컨테이너 {{name}} 시작됨",
|
||||
"failedToStartContainer": "컨테이너 {{name}} 시작에 실패했습니다.",
|
||||
"containerStopped": "컨테이너 {{name}}가 중지되었습니다.",
|
||||
"failedToStartContainer": "컨테이너 {{name}}시작에 실패했습니다.",
|
||||
"containerStopped": "컨테이너 {{name}} 가 중지되었습니다.",
|
||||
"failedToStopContainer": "컨테이너 {{name}}를 중지하는 데 실패했습니다.",
|
||||
"containerRestarted": "컨테이너 {{name}}가 재시작되었습니다.",
|
||||
"failedToRestartContainer": "컨테이너 {{name}} 재시작에 실패했습니다.",
|
||||
"containerRestarted": "컨테이너 {{name}} 가 재시작되었습니다.",
|
||||
"failedToRestartContainer": "컨테이너 {{name}}재시작에 실패했습니다.",
|
||||
"containerPaused": "컨테이너 {{name}} 일시 중지됨",
|
||||
"containerUnpaused": "컨테이너 {{name}} 일시 중지 해제됨",
|
||||
"failedToTogglePauseContainer": "컨테이너 {{name}}의 일시 정지 상태를 전환하는 데 실패했습니다.",
|
||||
"containerRemoved": "컨테이너 {{name}}가 제거되었습니다.",
|
||||
"failedToRemoveContainer": "컨테이너 {{name}}을 제거하는 데 실패했습니다.",
|
||||
"containerRemoved": "컨테이너 {{name}} 가 제거되었습니다.",
|
||||
"failedToRemoveContainer": "컨테이너 {{name}}를 제거하는 데 실패했습니다.",
|
||||
"image": "영상",
|
||||
"idLabel": "ID",
|
||||
"ports": "항구",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "조명으로 전환",
|
||||
"switchToDark": "어둡게 전환"
|
||||
}
|
||||
}
|
||||
}
|
||||
2402
src/locales/translated/nl.json
Normal file
2402
src/locales/translated/nl.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/no.json
Normal file
2402
src/locales/translated/no.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/pl.json
Normal file
2402
src/locales/translated/pl.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/pt.json
Normal file
2402
src/locales/translated/pt.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/ro.json
Normal file
2402
src/locales/translated/ro.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/ru.json
Normal file
2402
src/locales/translated/ru.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/sr.json
Normal file
2402
src/locales/translated/sr.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/translated/sv.json
Normal file
2402
src/locales/translated/sv.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -39,11 +39,11 @@
|
||||
"noCredentials": "ไม่มีข้อมูลประจำตัว",
|
||||
"noCredentialsMessage": "คุณยังไม่ได้เพิ่มข้อมูลประจำตัวใดๆ คลิก \"เพิ่มข้อมูลประจำตัว\" เพื่อเริ่มต้น",
|
||||
"sshCredentials": "ข้อมูลรับรอง SSH",
|
||||
"credentialsCount": "ข้อมูลประจำตัว {{count}}",
|
||||
"credentialsCount": "{{count}} ข้อมูลประจำตัว",
|
||||
"refresh": "รีเฟรช",
|
||||
"passwordRequired": "ต้องใส่รหัสผ่าน",
|
||||
"sshKeyRequired": "จำเป็นต้องใช้คีย์ SSH",
|
||||
"credentialAddedSuccessfully": "ข้อมูลประจำตัว \"{{name}}\" ถูกเพิ่มสำเร็จแล้ว",
|
||||
"credentialAddedSuccessfully": "เพิ่มข้อมูลประจำตัว \"{{name}}\" สำเร็จแล้ว",
|
||||
"general": "ทั่วไป",
|
||||
"description": "คำอธิบาย",
|
||||
"folder": "โฟลเดอร์",
|
||||
@@ -114,7 +114,7 @@
|
||||
"usage": "การใช้งาน",
|
||||
"securityDetails": "รายละเอียดด้านความปลอดภัย",
|
||||
"securityDetailsDescription": "ดูข้อมูลประจำตัวที่เข้ารหัส",
|
||||
"credentialSecured": "ข้อมูลประจำตัวได้รับการรักษาความปลอดภัยแล้ว",
|
||||
"credentialSecured": "ยืนยันตัวตนเรียบร้อยแล้ว",
|
||||
"credentialSecuredDescription": "ข้อมูลสำคัญทั้งหมดจะถูกเข้ารหัสด้วย AES-256",
|
||||
"passwordAuthentication": "การตรวจสอบรหัสผ่าน",
|
||||
"keyAuthentication": "การตรวจสอบสิทธิ์ด้วยคีย์",
|
||||
@@ -128,7 +128,7 @@
|
||||
"created": "สร้าง",
|
||||
"lastModified": "แก้ไขล่าสุด",
|
||||
"usageStatistics": "สถิติการใช้งาน",
|
||||
"copiedToClipboard": "{{field}} คัดลอกไปยังคลิปบอร์ด",
|
||||
"copiedToClipboard": "{{field}} คัดลอกไปยังคลิปบอร์ดแล้ว",
|
||||
"failedToCopy": "ไม่สามารถคัดลอกไปยังคลิปบอร์ดได้",
|
||||
"sshKey": "คีย์ SSH",
|
||||
"createCredentialDescription": "สร้างข้อมูลรับรอง SSH ใหม่สำหรับการเข้าถึงที่ปลอดภัย",
|
||||
@@ -136,7 +136,7 @@
|
||||
"listView": "รายการ",
|
||||
"folderView": "โฟลเดอร์",
|
||||
"unknownCredential": "ไม่ทราบ",
|
||||
"confirmRemoveFromFolder": "คุณแน่ใจหรือไม่ว่าต้องการลบ \"{{name}}\" ออกจากโฟลเดอร์ \"{{folder}}\" ข้อมูลประจำตัวจะถูกย้ายไปยัง \"ไม่มีหมวดหมู่\"",
|
||||
"confirmRemoveFromFolder": "คุณแน่ใจหรือไม่ว่าต้องการลบ \"{{name}}\" ออกจากโฟลเดอร์ \"{{folder}}\"? ข้อมูลรับรองจะถูกย้ายไปยัง \"ไม่มีหมวดหมู่\"",
|
||||
"removedFromFolder": "ข้อมูลประจำตัว \"{{name}}\" ถูกลบออกจากโฟลเดอร์เรียบร้อยแล้ว",
|
||||
"failedToRemoveFromFolder": "ไม่สามารถลบข้อมูลประจำตัวออกจากโฟลเดอร์ได้",
|
||||
"folderRenamed": "เปลี่ยนชื่อโฟลเดอร์ \"{{oldName}}\" เป็น \"{{newName}}\" สำเร็จแล้ว",
|
||||
@@ -166,7 +166,7 @@
|
||||
"keyTypeDsa": "ดีเอสเอ (เอสเอช)",
|
||||
"keyTypeRsaSha256": "อาร์เอสเอ-เอสเอชเอ2-256",
|
||||
"keyTypeRsaSha512": "อาร์เอสเอ-เอสเอชเอ2-512",
|
||||
"keyPairGeneratedSuccessfully": "สร้างคู่คีย์ {{keyType}} สำเร็จแล้ว",
|
||||
"keyPairGeneratedSuccessfully": "{{keyType}} สร้างคู่คีย์สำเร็จแล้ว",
|
||||
"failedToGenerateKeyPair": "ไม่สามารถสร้างคู่คีย์ได้",
|
||||
"generateKeyPairNote": "สร้างคู่คีย์ SSH ใหม่โดยตรง ซึ่งจะแทนที่คีย์ที่มีอยู่เดิมในรูปแบบเดิม",
|
||||
"invalidKey": "คีย์ไม่ถูกต้อง",
|
||||
@@ -187,10 +187,10 @@
|
||||
"dragIndicator": {
|
||||
"error": "ข้อผิดพลาด: {{error}}",
|
||||
"dragging": "การลาก {{fileName}}",
|
||||
"preparing": "การเตรียม {{fileName}}",
|
||||
"preparing": "กำลังเตรียม {{fileName}}",
|
||||
"readySingle": "พร้อมดาวน์โหลด {{fileName}}",
|
||||
"readyMultiple": "พร้อมดาวน์โหลดไฟล์ {{count}} ไฟล์",
|
||||
"batchDrag": "ลากไฟล์ {{count}} ไฟล์ไปยังเดสก์ท็อป",
|
||||
"readyMultiple": "พร้อมดาวน์โหลดไฟล์ {{count}} แล้ว",
|
||||
"batchDrag": "ลากไฟล์ {{count}} ไปยังเดสก์ท็อป",
|
||||
"dragToDesktop": "ลากไปที่เดสก์ท็อป",
|
||||
"canDragAnywhere": "คุณสามารถลากไฟล์ไปที่ใดก็ได้บนเดสก์ท็อปของคุณ"
|
||||
},
|
||||
@@ -202,7 +202,7 @@
|
||||
"stopKeyRecording": "หยุดการบันทึกคีย์",
|
||||
"selectTerminals": "เลือกเทอร์มินัล:",
|
||||
"typeCommands": "พิมพ์คำสั่ง (รองรับทุกปุ่ม):",
|
||||
"commandsWillBeSent": "คำสั่งจะถูกส่งไปยังเทอร์มินัลที่เลือกไว้ {{count}} เครื่อง",
|
||||
"commandsWillBeSent": "คำสั่งจะถูกส่งไปยังเทอร์มินัลที่เลือก {{count}} เครื่อง",
|
||||
"settings": "การตั้งค่า",
|
||||
"enableRightClickCopyPaste": "เปิดใช้งานการคัดลอก/วางโดยคลิกขวา",
|
||||
"shareIdeas": "มีไอเดียเกี่ยวกับสิ่งที่จะเกิดขึ้นต่อไปสำหรับเครื่องมือ SSH บ้างไหม? แชร์ไอเดียของคุณได้ที่นี่",
|
||||
@@ -248,7 +248,7 @@
|
||||
"reorderSameFolder": "สามารถจัดเรียงลำดับข้อความใหม่ได้เฉพาะภายในโฟลเดอร์เดียวกันเท่านั้น",
|
||||
"reorderSuccess": "เรียงลำดับส่วนย่อยใหม่สำเร็จแล้ว",
|
||||
"reorderFailed": "ไม่สามารถเรียงลำดับส่วนย่อยใหม่ได้",
|
||||
"deleteFolderConfirm": "ลบโฟลเดอร์ \"{{name}}\" หรือไม่? โค้ดทั้งหมดจะถูกย้ายไปยังหมวดหมู่ที่ไม่มีการจัดหมวดหมู่",
|
||||
"deleteFolderConfirm": "ลบโฟลเดอร์ \"{{name}}\"? ข้อความย่อทั้งหมดจะถูกย้ายไปยังหมวดหมู่ที่ไม่มีการจัดหมวดหมู่",
|
||||
"deleteFolderSuccess": "ลบโฟลเดอร์สำเร็จแล้ว",
|
||||
"deleteFolderFailed": "ไม่สามารถลบโฟลเดอร์ได้",
|
||||
"updateFolderSuccess": "อัปเดตโฟลเดอร์สำเร็จแล้ว",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "หน้าจอแบ่งครึ่งถูกเคลียร์แล้ว",
|
||||
"error": {
|
||||
"noAssignments": "โปรดกำหนดแท็บอย่างน้อยหนึ่งแท็บให้กับเค้าโครง",
|
||||
"fillAllSlots": "โปรดกรอกข้อมูลในช่องทั้งหมด {{count}} ช่องก่อนสมัคร"
|
||||
"fillAllSlots": "กรุณากรอกข้อมูลในช่อง {{count}} ทั้งหมดก่อนสมัคร"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -345,8 +345,8 @@
|
||||
"upToDate": "แอปได้รับการอัปเดตแล้ว",
|
||||
"currentVersion": "คุณกำลังใช้งานเวอร์ชัน {{version}}",
|
||||
"updateAvailable": "มีการอัปเดตแล้ว",
|
||||
"newVersionAvailable": "มีเวอร์ชันใหม่ให้ใช้งานแล้ว! คุณกำลังใช้งาน {{current}} อยู่ แต่มี {{latest}} ให้ใช้งานแล้ว",
|
||||
"releasedOn": "วางจำหน่ายเมื่อ {{date}}",
|
||||
"newVersionAvailable": "มีเวอร์ชันใหม่ให้ใช้งานแล้ว! คุณกำลังใช้งาน {{current}}อยู่ แต่มี {{latest}} ให้ใช้งานแล้ว",
|
||||
"releasedOn": "เผยแพร่เมื่อ {{date}}",
|
||||
"downloadUpdate": "ดาวน์โหลดการอัปเดต",
|
||||
"dismiss": "อนุญาตให้ออกไป",
|
||||
"checking": "กำลังตรวจสอบการอัปเดต...",
|
||||
@@ -459,7 +459,7 @@
|
||||
"passwordResetSuccess": "รีเซ็ตรหัสผ่านสำเร็จแล้ว! คุณสามารถเข้าสู่ระบบด้วยรหัสผ่านใหม่ของคุณได้แล้ว",
|
||||
"failedToInitiatePasswordReset": "ไม่สามารถเริ่มการรีเซ็ตรหัสผ่านได้",
|
||||
"failedToVerifyResetCode": "ไม่สามารถตรวจสอบรหัสรีเซ็ตได้",
|
||||
"failedToCompletePasswordReset": "ไม่สามารถทำการรีเซ็ตรหัสผ่านให้เสร็จสมบูรณ์ได้",
|
||||
"failedToCompletePasswordReset": "การรีเซ็ตรหัสผ่านล้มเหลว",
|
||||
"documentation": "เอกสารประกอบ",
|
||||
"retry": "ลองใหม่อีกครั้ง",
|
||||
"checking": "กำลังตรวจสอบ...",
|
||||
@@ -498,7 +498,7 @@
|
||||
"userManagement": "การจัดการผู้ใช้",
|
||||
"makeAdmin": "ตั้งค่าผู้ดูแลระบบ",
|
||||
"removeAdmin": "ลบผู้ดูแลระบบ",
|
||||
"deleteUser": "ลบผู้ใช้ {{username}} แล้ว แต่ไม่สามารถยกเลิกได้",
|
||||
"deleteUser": "ลบผู้ใช้ {{username}}? ไม่สามารถยกเลิกได้",
|
||||
"allowRegistration": "อนุญาตการลงทะเบียน",
|
||||
"oidcSettings": "การตั้งค่า OIDC",
|
||||
"clientId": "รหัสลูกค้า",
|
||||
@@ -537,7 +537,7 @@
|
||||
"userRegistration": "การลงทะเบียนผู้ใช้",
|
||||
"allowNewAccountRegistration": "อนุญาตให้ลงทะเบียนบัญชีใหม่",
|
||||
"allowPasswordLogin": "อนุญาตให้เข้าสู่ระบบด้วยชื่อผู้ใช้/รหัสผ่าน",
|
||||
"missingRequiredFields": "ช่องข้อมูลที่จำเป็นไม่ครบถ้วน: {{fields}}",
|
||||
"missingRequiredFields": "กรอกข้อมูลในช่องที่จำเป็นไม่ครบถ้วน: {{fields}}",
|
||||
"oidcConfigurationUpdated": "การกำหนดค่า OIDC ได้รับการอัปเดตเรียบร้อยแล้ว!",
|
||||
"failedToFetchOidcConfig": "ไม่สามารถดึงข้อมูลการกำหนดค่า OIDC ได้",
|
||||
"failedToFetchRegistrationStatus": "ไม่สามารถดึงสถานะการลงทะเบียนได้",
|
||||
@@ -549,7 +549,7 @@
|
||||
"enterUsernameToMakeAdmin": "ป้อนชื่อผู้ใช้เพื่อเข้าเป็นผู้ดูแลระบบ",
|
||||
"userIsNowAdmin": "ผู้ใช้ {{username}} ตอนนี้เป็นผู้ดูแลระบบแล้ว",
|
||||
"failedToMakeUserAdmin": "ไม่สามารถทำให้ผู้ใช้เป็นผู้ดูแลระบบได้",
|
||||
"removeAdminStatus": "ลบสถานะผู้ดูแลระบบออกจาก {{username}} หรือไม่?",
|
||||
"removeAdminStatus": "ลบสถานะผู้ดูแลระบบออกจาก {{username}}?",
|
||||
"adminStatusRemoved": "สถานะผู้ดูแลระบบถูกลบออกจาก {{username}}",
|
||||
"failedToRemoveAdminStatus": "ไม่สามารถลบสถานะผู้ดูแลระบบได้",
|
||||
"userDeletedSuccessfully": "ผู้ใช้ {{username}} ถูกลบสำเร็จแล้ว",
|
||||
@@ -559,12 +559,12 @@
|
||||
"sessionRevokedSuccessfully": "การยกเลิกเซสชันสำเร็จแล้ว",
|
||||
"failedToRevokeSession": "ไม่สามารถยกเลิกเซสชันได้",
|
||||
"confirmRevokeSession": "คุณแน่ใจหรือไม่ว่าต้องการยกเลิกเซสชั่นนี้?",
|
||||
"confirmRevokeAllSessions": "คุณแน่ใจหรือไม่ว่าต้องการยกเลิกการใช้งานทั้งหมดสำหรับผู้ใช้รายนี้?",
|
||||
"confirmRevokeAllSessions": "คุณแน่ใจหรือไม่ว่าต้องการยกเลิกเซสชันทั้งหมดสำหรับผู้ใช้รายนี้?",
|
||||
"failedToRevokeSessions": "ไม่สามารถยกเลิกเซสชันได้",
|
||||
"sessionsRevokedSuccessfully": "การยกเลิกเซสชันสำเร็จแล้ว",
|
||||
"linkToPasswordAccount": "เชื่อมโยงไปยังบัญชีรหัสผ่าน",
|
||||
"linkOIDCDialogTitle": "เชื่อมโยงบัญชี OIDC กับบัญชีรหัสผ่าน",
|
||||
"linkOIDCDialogDescription": "เชื่อมโยง {{username}} (ผู้ใช้ OIDC) กับบัญชีรหัสผ่านที่มีอยู่แล้ว ซึ่งจะทำให้สามารถตรวจสอบสิทธิ์แบบสองทางสำหรับบัญชีรหัสผ่านได้",
|
||||
"linkOIDCDialogDescription": "เชื่อมโยง {{username}} (ผู้ใช้ OIDC) กับบัญชีรหัสผ่านที่มีอยู่แล้ว การทำเช่นนี้จะเปิดใช้งานการตรวจสอบสิทธิ์แบบสองขั้นตอนสำหรับบัญชีรหัสผ่าน",
|
||||
"createUser": "สร้างผู้ใช้",
|
||||
"createUserDescription": "สร้างผู้ใช้ภายในเครื่องใหม่ โดยระบุชื่อผู้ใช้และรหัสผ่าน",
|
||||
"enterUsername": "ป้อนชื่อผู้ใช้",
|
||||
@@ -584,7 +584,7 @@
|
||||
"passwordResetWarning": "การรีเซ็ตรหัสผ่านของผู้ใช้จะลบข้อมูลทั้งหมดของผู้ใช้ (โฮสต์ SSH ข้อมูลประจำตัว การตั้งค่า) การกระทำนี้ไม่สามารถย้อนกลับได้",
|
||||
"resetUserPassword": "รีเซ็ตรหัสผ่านผู้ใช้",
|
||||
"resettingPassword": "กำลังรีเซ็ต...",
|
||||
"passwordResetInitiated": "เริ่มการรีเซ็ตรหัสผ่านสำหรับ {{username}} ส่งรหัสรีเซ็ตแล้ว",
|
||||
"passwordResetInitiated": "เริ่มการรีเซ็ต mật khẩu สำหรับ {{username}}ส่งรหัสรีเซ็ตแล้ว",
|
||||
"failedToResetPassword": "ไม่สามารถเริ่มการรีเซ็ตรหัสผ่านได้",
|
||||
"sessionManagement": "การจัดการเซสชัน",
|
||||
"revokeAllSessions": "ยกเลิกเซสชันทั้งหมด",
|
||||
@@ -611,11 +611,11 @@
|
||||
"linkTargetUsernamePlaceholder": "ป้อนชื่อผู้ใช้หรือรหัสผ่านของบัญชี",
|
||||
"linkAccountsButton": "เชื่อมโยงบัญชี",
|
||||
"linkingAccounts": "กำลังเชื่อมโยง...",
|
||||
"accountsLinkedSuccessfully": "ผู้ใช้ OIDC {{oidcUsername}} ได้รับการเชื่อมโยงกับ {{targetUsername}}",
|
||||
"accountsLinkedSuccessfully": "ผู้ใช้ OIDC {{oidcUsername}} ได้ถูกเชื่อมโยงกับ {{targetUsername}}แล้ว",
|
||||
"failedToLinkAccounts": "ไม่สามารถเชื่อมโยงบัญชีได้",
|
||||
"linkTargetUsernameRequired": "จำเป็นต้องระบุชื่อผู้ใช้เป้าหมาย",
|
||||
"unlinkOIDCTitle": "ยกเลิกการเชื่อมโยงการตรวจสอบสิทธิ์ OIDC",
|
||||
"unlinkOIDCDescription": "ลบการตรวจสอบสิทธิ์ OIDC ออกจาก {{username}} หรือไม่? ผู้ใช้จะสามารถเข้าสู่ระบบได้เฉพาะด้วยชื่อผู้ใช้/รหัสผ่านหลังจากนี้เท่านั้น",
|
||||
"unlinkOIDCDescription": "ลบการตรวจสอบสิทธิ์ OIDC ออกจาก {{username}}หรือไม่? หลังจากนี้ผู้ใช้จะสามารถเข้าสู่ระบบได้เฉพาะด้วยชื่อผู้ใช้/รหัสผ่านเท่านั้น",
|
||||
"unlinkOIDCSuccess": "OIDC ถูกตัดการเชื่อมต่อจาก {{username}}",
|
||||
"failedToUnlinkOIDC": "ไม่สามารถยกเลิกการเชื่อมโยง OIDC ได้",
|
||||
"databaseSecurity": "ความปลอดภัยของฐานข้อมูล",
|
||||
@@ -737,13 +737,13 @@
|
||||
"exportDescription": "ส่งออกข้อมูลโฮสต์และข้อมูลรับรอง SSH ไปยังไฟล์ SQLite",
|
||||
"importDescription": "นำเข้าไฟล์ SQLite ด้วยการผสานแบบเพิ่มทีละส่วน (ข้ามข้อมูลที่ซ้ำกัน)",
|
||||
"criticalWarning": "คำเตือนที่สำคัญ",
|
||||
"cannotDisablePasswordLoginWithoutOIDC": "ไม่สามารถปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่านได้หากไม่ได้กำหนดค่า OIDC! คุณต้องกำหนดค่าการตรวจสอบสิทธิ์ OIDC ก่อนจึงจะสามารถปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่านได้ มิเช่นนั้นคุณจะไม่สามารถเข้าถึง Termix ได้",
|
||||
"cannotDisablePasswordLoginWithoutOIDC": "ไม่สามารถปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่านได้หากไม่ได้กำหนดค่า OIDC! คุณต้องกำหนดค่าการตรวจสอบสิทธิ์ OIDC ก่อนจึงจะปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่านได้ มิเช่นนั้นคุณจะไม่สามารถเข้าถึง Termix ได้",
|
||||
"confirmDisablePasswordLogin": "คุณแน่ใจหรือไม่ว่าต้องการปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่าน? โปรดตรวจสอบให้แน่ใจว่า OIDC ได้รับการกำหนดค่าอย่างถูกต้องและทำงานได้อย่างถูกต้องก่อนดำเนินการต่อ มิเช่นนั้นคุณจะไม่สามารถเข้าถึงอินสแตนซ์ Termix ของคุณได้",
|
||||
"passwordLoginDisabled": "การเข้าสู่ระบบด้วยรหัสผ่านถูกปิดใช้งานสำเร็จแล้ว",
|
||||
"passwordLoginAndRegistrationDisabled": "การเข้าสู่ระบบด้วยรหัสผ่านและการลงทะเบียนบัญชีใหม่ถูกปิดใช้งานเรียบร้อยแล้ว",
|
||||
"requiresPasswordLogin": "ต้องเปิดใช้งานการเข้าสู่ระบบด้วยรหัสผ่าน",
|
||||
"passwordLoginDisabledWarning": "การเข้าสู่ระบบด้วยรหัสผ่านถูกปิดใช้งาน โปรดตรวจสอบให้แน่ใจว่าได้กำหนดค่า OIDC อย่างถูกต้อง มิเช่นนั้นคุณจะไม่สามารถเข้าสู่ระบบ Termix ได้",
|
||||
"oidcRequiredWarning": "คำเตือนสำคัญ: การเข้าสู่ระบบด้วยรหัสผ่านถูกปิดใช้งาน หากคุณรีเซ็ตหรือกำหนดค่า OIDC ผิดพลาด คุณจะสูญเสียการเข้าถึง Termix ทั้งหมดและทำให้ระบบของคุณใช้งานไม่ได้ โปรดดำเนินการต่อเฉพาะเมื่อคุณแน่ใจอย่างยิ่งเท่านั้น",
|
||||
"oidcRequiredWarning": "คำเตือนสำคัญ: การเข้าสู่ระบบด้วยรหัสผ่านถูกปิดใช้งาน หากคุณรีเซ็ตหรือกำหนดค่า OIDC ผิดพลาด คุณจะสูญเสียการเข้าถึง Termix ทั้งหมดและทำให้ระบบของคุณใช้งานไม่ได้ โปรดดำเนินการต่อเมื่อคุณแน่ใจอย่างยิ่งเท่านั้น",
|
||||
"confirmDisableOIDCWarning": "คำเตือน: คุณกำลังจะปิดใช้งาน OIDC ในขณะที่การเข้าสู่ระบบด้วยรหัสผ่านก็ถูกปิดใช้งานอยู่เช่นกัน การกระทำนี้จะทำให้ระบบ Termix ของคุณใช้งานไม่ได้ และคุณจะสูญเสียการเข้าถึงทั้งหมด คุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ?",
|
||||
"failedToUpdatePasswordLoginStatus": "ไม่สามารถอัปเดตสถานะการเข้าสู่ระบบด้วยรหัสผ่านได้",
|
||||
"loadingSessions": "กำลังโหลดเซสชัน...",
|
||||
@@ -756,7 +756,7 @@
|
||||
"revokeAllUserSessionsTitle": "ยกเลิกเซสชันทั้งหมดสำหรับผู้ใช้รายนี้",
|
||||
"revokeAll": "เพิกถอนทั้งหมด",
|
||||
"linkOidcToPasswordAccount": "เชื่อมโยงบัญชี OIDC กับบัญชีรหัสผ่าน",
|
||||
"linkOidcToPasswordAccountDescription": "เชื่อมโยง {{username}} (ผู้ใช้ OIDC) กับบัญชีรหัสผ่านที่มีอยู่แล้ว การทำเช่นนี้จะเปิดใช้งานการตรวจสอบสิทธิ์แบบสองทางสำหรับบัญชีรหัสผ่าน",
|
||||
"linkOidcToPasswordAccountDescription": "เชื่อมโยง {{username}} (ผู้ใช้ OIDC) กับบัญชีรหัสผ่านที่มีอยู่แล้ว การทำเช่นนี้จะเปิดใช้งานการตรวจสอบสิทธิ์แบบสองขั้นตอนสำหรับบัญชีรหัสผ่าน",
|
||||
"linkOidcWarningTitle": "คำเตือน: ข้อมูลผู้ใช้ OIDC จะถูกลบ",
|
||||
"linkOidcWarningDescription": "การกระทำนี้จะส่งผลให้:",
|
||||
"linkOidcActionDeleteUser": "ลบบัญชีผู้ใช้ OIDC และข้อมูลทั้งหมดของผู้ใช้รายนั้น",
|
||||
@@ -785,9 +785,9 @@
|
||||
"downloadSample": "ดาวน์โหลดตัวอย่าง",
|
||||
"formatGuide": "คู่มือรูปแบบ",
|
||||
"exportCredentialWarning": "คำเตือน: โฮสต์ \"{{name}}\" ใช้การตรวจสอบสิทธิ์ด้วยข้อมูลประจำตัว ไฟล์ที่ส่งออกจะไม่รวมข้อมูลประจำตัว และจะต้องกำหนดค่าใหม่ด้วยตนเองหลังจากนำเข้า คุณต้องการดำเนินการต่อหรือไม่",
|
||||
"exportSensitiveDataWarning": "คำเตือน: โฮสต์ \"{{name}}\" มีข้อมูลการตรวจสอบสิทธิ์ที่ละเอียดอ่อน (รหัสผ่าน/คีย์ SSH) ไฟล์ที่ส่งออกจะรวมข้อมูลนี้ในรูปแบบข้อความธรรมดา โปรดเก็บไฟล์ให้ปลอดภัยและลบออกหลังจากใช้งาน คุณต้องการดำเนินการต่อหรือไม่",
|
||||
"exportSensitiveDataWarning": "คำเตือน: โฮสต์ \"{{name}}\" มีข้อมูลการตรวจสอบสิทธิ์ที่ละเอียดอ่อน (รหัสผ่าน/คีย์ SSH) ไฟล์ที่ส่งออกจะรวมข้อมูลนี้ในรูปแบบข้อความธรรมดา โปรดเก็บไฟล์ให้ปลอดภัยและลบหลังจากใช้งาน คุณต้องการดำเนินการต่อหรือไม่",
|
||||
"uncategorized": "ไม่มีหมวดหมู่",
|
||||
"confirmDelete": "คุณแน่ใจหรือไม่ว่าต้องการลบ \"{{name}}\"?",
|
||||
"confirmDelete": "คุณแน่ใจหรือไม่ว่าต้องการลบ \"{{name}}\" ?",
|
||||
"failedToDeleteHost": "ไม่สามารถลบโฮสต์ได้",
|
||||
"failedToExportHost": "ไม่สามารถส่งออกข้อมูลโฮสต์ได้ โปรดตรวจสอบให้แน่ใจว่าคุณได้เข้าสู่ระบบและมีสิทธิ์เข้าถึงข้อมูลโฮสต์แล้ว",
|
||||
"jsonMustContainHosts": "ไฟล์ JSON ต้องมีอาร์เรย์ \"hosts\" หรือเป็นอาร์เรย์ของ hosts",
|
||||
@@ -816,7 +816,7 @@
|
||||
"editHost": "แก้ไขโฮสต์",
|
||||
"cloneHost": "โคลนโฮสต์",
|
||||
"updateHost": "อัปเดตโฮสต์",
|
||||
"hostUpdatedSuccessfully": "โฮสต์ \"{{name}}\" ได้รับการอัปเดตสำเร็จแล้ว!",
|
||||
"hostUpdatedSuccessfully": "โฮสต์ \"{{name}}\" อัปเดตสำเร็จแล้ว!",
|
||||
"hostAddedSuccessfully": "เพิ่มโฮสต์ \"{{name}}\" สำเร็จแล้ว!",
|
||||
"hostDeletedSuccessfully": "โฮสต์ \"{{name}}\" ถูกลบสำเร็จแล้ว!",
|
||||
"failedToSaveHost": "ไม่สามารถบันทึกโฮสต์ได้ โปรดลองอีกครั้ง",
|
||||
@@ -837,7 +837,7 @@
|
||||
"connection": "การเชื่อมต่อ",
|
||||
"remove": "ลบ",
|
||||
"sourcePort": "พอร์ตต้นทาง",
|
||||
"sourcePortDesc": "(แหล่งที่มาหมายถึงรายละเอียดการเชื่อมต่อปัจจุบันในแท็บทั่วไป)",
|
||||
"sourcePortDesc": " (แหล่งที่มาหมายถึงรายละเอียดการเชื่อมต่อปัจจุบันในแท็บทั่วไป)",
|
||||
"endpointPort": "พอร์ตปลายทาง",
|
||||
"endpointSshConfig": "การกำหนดค่า SSH ปลายทาง",
|
||||
"tunnelForwardDescription": "อุโมงค์นี้จะส่งต่อทราฟฟิกจากพอร์ต {{sourcePort}} บนเครื่องต้นทาง (รายละเอียดการเชื่อมต่อปัจจุบันในแท็บทั่วไป) ไปยังพอร์ต {{endpointPort}} บนเครื่องปลายทาง",
|
||||
@@ -929,10 +929,10 @@
|
||||
"folderAppearanceUpdated": "การแสดงผลโฟลเดอร์ได้รับการอัปเดตเรียบร้อยแล้ว",
|
||||
"failedToUpdateFolderAppearance": "ไม่สามารถอัปเดตลักษณะการแสดงผลของโฟลเดอร์ได้",
|
||||
"deleteAllHostsInFolder": "ลบโฮสต์ทั้งหมดในโฟลเดอร์",
|
||||
"confirmDeleteAllHostsInFolder": "คุณแน่ใจหรือไม่ว่าต้องการลบโฮสต์ทั้งหมด {{count}} ในโฟลเดอร์ \"{{folder}}\"? การกระทำนี้ไม่สามารถย้อนกลับได้",
|
||||
"allHostsInFolderDeleted": "ลบโฮสต์ {{count}} รายการจากโฟลเดอร์ \"{{folder}}\" สำเร็จแล้ว",
|
||||
"confirmDeleteAllHostsInFolder": "คุณแน่ใจหรือไม่ว่าต้องการลบโฮสต์ {{count}} ทั้งหมดในโฟลเดอร์ \"{{folder}}\"? การกระทำนี้ไม่สามารถย้อนกลับได้",
|
||||
"allHostsInFolderDeleted": "ลบโฮสต์ {{count}} จากโฟลเดอร์ \"{{folder}}\" สำเร็จแล้ว",
|
||||
"failedToDeleteHostsInFolder": "ไม่สามารถลบโฮสต์ในโฟลเดอร์ได้",
|
||||
"movedToFolder": "โฮสต์ \"{{name}}\" ย้ายไปที่ \"{{folder}}\" สำเร็จแล้ว",
|
||||
"movedToFolder": "โฮสต์ \"{{name}}\" ย้ายไปยัง \"{{folder}}\" สำเร็จแล้ว",
|
||||
"failedToMoveToFolder": "ไม่สามารถย้ายโฮสต์ไปยังโฟลเดอร์ได้",
|
||||
"clickToRenameFolder": "คลิกเพื่อเปลี่ยนชื่อโฟลเดอร์",
|
||||
"renameFolder": "เปลี่ยนชื่อโฟลเดอร์",
|
||||
@@ -950,7 +950,7 @@
|
||||
"openServerDetails": "ดูรายละเอียดเซิร์ฟเวอร์",
|
||||
"statistics": "สถิติ",
|
||||
"enabledWidgets": "วิดเจ็ตที่เปิดใช้งาน",
|
||||
"openServerStats": "สถิติเซิร์ฟเวอร์แบบเปิด",
|
||||
"openServerStats": "เปิดสถิติเซิร์ฟเวอร์",
|
||||
"enabledWidgetsDesc": "เลือกวิดเจ็ตแสดงสถิติที่จะแสดงสำหรับโฮสต์นี้",
|
||||
"monitoringConfiguration": "การกำหนดค่าการตรวจสอบ",
|
||||
"monitoringConfigurationDesc": "ตั้งค่าความถี่ในการตรวจสอบสถิติและสถานะของเซิร์ฟเวอร์",
|
||||
@@ -982,13 +982,13 @@
|
||||
"selectFont": "เลือกแบบอักษร",
|
||||
"selectFontDesc": "เลือกแบบอักษรที่จะใช้ในเทอร์มินัล",
|
||||
"fontSize": "ขนาดตัวอักษร",
|
||||
"fontSizeValue": "ขนาดตัวอักษร: {{value}}px",
|
||||
"fontSizeValue": "ขนาดตัวอักษร: {{value}}พิกเซล",
|
||||
"adjustFontSize": "ปรับขนาดตัวอักษรของเทอร์มินัล",
|
||||
"letterSpacing": "ระยะห่างระหว่างตัวอักษร",
|
||||
"letterSpacingValue": "ระยะห่างระหว่างตัวอักษร: {{value}}px",
|
||||
"adjustLetterSpacing": "ปรับระยะห่างระหว่างตัวอักษร",
|
||||
"lineHeight": "ความสูงของเส้น",
|
||||
"lineHeightValue": "ความสูงของบรรทัด: {{value}}",
|
||||
"lineHeightValue": "ความสูงของเส้น: {{value}}",
|
||||
"adjustLineHeight": "ปรับระยะห่างระหว่างบรรทัด",
|
||||
"cursorStyle": "รูปแบบเคอร์เซอร์",
|
||||
"selectCursorStyle": "เลือกรูปแบบเคอร์เซอร์",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "เสียง",
|
||||
"bellStyleVisual": "ภาพ",
|
||||
"bellStyleBoth": "ทั้งคู่",
|
||||
"bellStyleDesc": "วิธีจัดการกับเสียงเตือนเมื่อสิ้นสุดโปรแกรม (อักขระ BEL, \\x07) โปรแกรมจะเรียกใช้เสียงเตือนนี้เมื่อทำงานเสร็จสิ้น พบข้อผิดพลาด หรือเพื่อแจ้งเตือน \"เสียง\" จะเล่นเสียงบี๊บ \"ภาพ\" จะแสดงภาพบนหน้าจอชั่วครู่ \"ทั้งสองอย่าง\" จะแสดงทั้งเสียงและภาพ \"ไม่มี\" จะปิดเสียงเตือนทั้งหมด",
|
||||
"bellStyleDesc": "วิธีจัดการกับเสียงเตือนเมื่อโปรแกรมทำงานเสร็จสิ้น (อักขระ BEL, \\x07) โปรแกรมจะเรียกใช้เสียงเตือนนี้เมื่อทำงานเสร็จสิ้น พบข้อผิดพลาด หรือเพื่อแจ้งเตือน \"เสียง\" จะเล่นเสียงบี๊บ \"ภาพ\" จะแสดงภาพบนหน้าจอชั่วครู่ \"ทั้งสองอย่าง\" จะแสดงทั้งเสียงและภาพ และ \"ไม่มี\" จะปิดการแจ้งเตือนด้วยเสียงเตือน",
|
||||
"rightClickSelectsWord": "คลิกขวาแล้วเลือก Word",
|
||||
"rightClickSelectsWordDesc": "การคลิกขวาจะเลือกคำที่อยู่ใต้เคอร์เซอร์",
|
||||
"fastScrollModifier": "ตัวแก้ไขการเลื่อนเร็ว",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "สร้างค่าที่ตั้งไว้ล่วงหน้าของห่วงโซ่พร็อกซีแล้ว",
|
||||
"socks5PresetUpdated": "อัปเดตค่าที่ตั้งไว้ล่วงหน้าของห่วงโซ่พร็อกซีแล้ว",
|
||||
"socks5PresetDeleted": "ลบการตั้งค่าล่วงหน้าของห่วงโซ่พร็อกซีแล้ว",
|
||||
"socks5PresetSaved": "ค่าที่ตั้งไว้ล่วงหน้า \"{{name}}\" ถูกบันทึกสำเร็จแล้ว",
|
||||
"socks5PresetSaved": "บันทึกค่าที่ตั้งไว้ล่วงหน้า \"{{name}}\" สำเร็จแล้ว",
|
||||
"socks5PresetSaveError": "ไม่สามารถบันทึกค่าที่ตั้งไว้ล่วงหน้าได้",
|
||||
"socks5PresetNameRequired": "ต้องระบุชื่อที่กำหนดไว้ล่วงหน้า",
|
||||
"socks5EmptyChainError": "ไม่สามารถบันทึกเชนพร็อกซีที่ว่างเปล่าได้",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"socks5HostDescription": "ชื่อโฮสต์หรือที่อยู่ IP ของเซิร์ฟเวอร์พร็อกซี SOCKS",
|
||||
"socks5PortDescription": "หมายเลขพอร์ตของเซิร์ฟเวอร์พร็อกซี SOCKS (ค่าเริ่มต้น: 1080)",
|
||||
"addProxyNode": "เพิ่มโหนดพร็อกซี",
|
||||
"noProxyNodes": "ยังไม่ได้กำหนดค่าโหนดพร็อกซี คลิก \"เพิ่มโหนดพร็อกซี\" เพื่อเพิ่มโหนดพร็อกซี",
|
||||
"noProxyNodes": "ไม่ได้กำหนดค่าโหนดพร็อกซี คลิก 'เพิ่มโหนดพร็อกซี' เพื่อเพิ่มโหนดพร็อกซี",
|
||||
"proxyNode": "โหนดพร็อกซี",
|
||||
"proxyType": "ประเภทพร็อกซี",
|
||||
"quickActions": "การดำเนินการด่วน",
|
||||
@@ -1119,7 +1119,7 @@
|
||||
"validating": "กำลังตรวจสอบความถูกต้องของ Docker...",
|
||||
"error": "ข้อผิดพลาด",
|
||||
"errorCode": "รหัสข้อผิดพลาด: {{code}}",
|
||||
"version": "ด็อกเกอร์ v{{version}}",
|
||||
"version": "Docker v{{version}}",
|
||||
"current": "ปัจจุบัน",
|
||||
"used_limit": "ใช้งานแล้ว / ขีดจำกัด",
|
||||
"percentage": "เปอร์เซ็นต์",
|
||||
@@ -1131,7 +1131,7 @@
|
||||
"id": "รหัสประจำตัว",
|
||||
"state": "สถานะ",
|
||||
"console": "คอนโซล",
|
||||
"containerMustBeRunning": "คอนเทนเนอร์ต้องทำงานอยู่จึงจะสามารถเชื่อมต่อกับคอนโซลได้",
|
||||
"containerMustBeRunning": "ต้องเปิดใช้งานคอนเทนเนอร์ก่อนจึงจะสามารถเชื่อมต่อกับคอนโซลได้",
|
||||
"authenticationRequired": "จำเป็นต้องยืนยันตัวตน",
|
||||
"connectedTo": "เชื่อมต่อกับ {{containerName}}",
|
||||
"disconnected": "ตัดการเชื่อมต่อ",
|
||||
@@ -1139,7 +1139,7 @@
|
||||
"errorMessage": "ข้อผิดพลาด: {{message}}",
|
||||
"failedToConnect": "ไม่สามารถเชื่อมต่อกับคอนโซลได้",
|
||||
"disconnectedFromContainer": "ตัดการเชื่อมต่อจากคอนโซลคอนเทนเนอร์แล้ว",
|
||||
"containerNotRunning": "คอนเทนเนอร์ไม่ได้ทำงาน",
|
||||
"containerNotRunning": "คอนเทนเนอร์ไม่ได้ทำงานอยู่",
|
||||
"startContainerToAccess": "เริ่มคอนเทนเนอร์เพื่อเข้าถึงคอนโซล",
|
||||
"selectShell": "เลือกเปลือกหอย",
|
||||
"bash": "ทุบตี",
|
||||
@@ -1163,13 +1163,13 @@
|
||||
"noContainersMatchFiltersHint": "ลองปรับการค้นหาหรือตัวกรองของคุณดู",
|
||||
"containerStarted": "คอนเทนเนอร์ {{name}} เริ่มทำงานแล้ว",
|
||||
"failedToStartContainer": "ไม่สามารถเริ่มต้นคอนเทนเนอร์ได้: {{error}}",
|
||||
"containerStopped": "คอนเทนเนอร์ {{name}} หยุดแล้ว",
|
||||
"containerStopped": "คอนเทนเนอร์ {{name}} หยุดทำงานแล้ว",
|
||||
"failedToStopContainer": "ไม่สามารถหยุดคอนเทนเนอร์ได้: {{error}}",
|
||||
"containerRestarted": "คอนเทนเนอร์ {{name}} รีสตาร์ทแล้ว",
|
||||
"failedToRestartContainer": "ไม่สามารถรีสตาร์ทคอนเทนเนอร์ได้: {{error}}",
|
||||
"containerUnpaused": "คอนเทนเนอร์ {{name}} ยกเลิกการหยุดชั่วคราว",
|
||||
"containerPaused": "คอนเทนเนอร์ {{name}} หยุดชั่วคราว",
|
||||
"failedToTogglePauseContainer": "ไม่สามารถสร้างคอนเทนเนอร์ {{action}} ได้: {{error}}",
|
||||
"failedToTogglePauseContainer": "ไม่สามารถ {{action}} คอนเทนเนอร์ได้: {{error}}",
|
||||
"containerRemoved": "คอนเทนเนอร์ {{name}} ถูกลบออกแล้ว",
|
||||
"failedToRemoveContainer": "ไม่สามารถลบคอนเทนเนอร์ได้: {{error}}",
|
||||
"image": "ภาพ:",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"logs": "บันทึก",
|
||||
"stats": "สถิติ",
|
||||
"consoleTab": "คอนโซล",
|
||||
"failedToFetchLogs": "ไม่สามารถดึงบันทึกได้: {{error}}",
|
||||
"failedToFetchLogs": "ไม่สามารถดึงข้อมูลบันทึกได้: {{error}}",
|
||||
"failedToDownloadLogs": "ไม่สามารถดาวน์โหลดบันทึกได้: {{error}}",
|
||||
"linesToShow": "เส้นเพื่อแสดง",
|
||||
"last50Lines": "50 บรรทัดสุดท้าย",
|
||||
@@ -1221,7 +1221,7 @@
|
||||
"connectionLost": "การเชื่อมต่อขาดหาย",
|
||||
"error": "ข้อผิดพลาด: {{message}}",
|
||||
"disconnected": "ตัดการเชื่อมต่อ",
|
||||
"connectionClosed": "การเชื่อมต่อถูกตัด",
|
||||
"connectionClosed": "การเชื่อมต่อถูกปิด",
|
||||
"connectionError": "ข้อผิดพลาดในการเชื่อมต่อ: {{message}}",
|
||||
"connected": "เชื่อมต่อแล้ว",
|
||||
"sshConnected": "การเชื่อมต่อ SSH สำเร็จแล้ว",
|
||||
@@ -1236,7 +1236,7 @@
|
||||
"connectionTimeout": "หมดเวลาการเชื่อมต่อ",
|
||||
"terminalTitle": "เทอร์มินัล - {{host}}",
|
||||
"terminalWithPath": "เทอร์มินัล - {{host}}:{{path}}",
|
||||
"runTitle": "วิ่ง {{command}} - {{host}}",
|
||||
"runTitle": "กำลังวิ่ง {{command}} - {{host}}",
|
||||
"totpRequired": "ต้องใช้การยืนยันตัวตนสองขั้นตอน",
|
||||
"totpCodeLabel": "รหัสยืนยัน",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1255,7 +1255,7 @@
|
||||
"downloadFile": "ดาวน์โหลด",
|
||||
"extractArchive": "แตกไฟล์เก็บถาวร",
|
||||
"extractingArchive": "กำลังดึงข้อมูล {{name}}...",
|
||||
"archiveExtractedSuccessfully": "{{name}} สกัดสำเร็จแล้ว",
|
||||
"archiveExtractedSuccessfully": "{{name}} ดึงข้อมูลสำเร็จแล้ว",
|
||||
"extractFailed": "การดึงข้อมูลล้มเหลว",
|
||||
"compressFile": "บีบอัดไฟล์",
|
||||
"compressFiles": "บีบอัดไฟล์",
|
||||
@@ -1264,9 +1264,9 @@
|
||||
"enterArchiveName": "ป้อนชื่อไฟล์เก็บถาวร...",
|
||||
"compressionFormat": "รูปแบบการบีบอัด",
|
||||
"selectedFiles": "ไฟล์ที่เลือก",
|
||||
"andMoreFiles": "และอีก {{count}} รายการ...",
|
||||
"andMoreFiles": "และ {{count}} เพิ่มเติม...",
|
||||
"compress": "บีบอัด",
|
||||
"compressingFiles": "บีบอัดรายการ {{count}} รายการให้เหลือ {{name}} รายการ...",
|
||||
"compressingFiles": "บีบอัดรายการ {{count}} รายการเป็น {{name}}รายการ ...",
|
||||
"filesCompressedSuccessfully": "{{name}} สร้างสำเร็จแล้ว",
|
||||
"compressFailed": "การบีบอัดล้มเหลว",
|
||||
"edit": "แก้ไข",
|
||||
@@ -1324,8 +1324,8 @@
|
||||
"failedToCreateItem": "ไม่สามารถสร้างรายการได้",
|
||||
"operationFailed": "การดำเนินการ {{operation}} ล้มเหลวสำหรับ {{name}}: {{error}}",
|
||||
"failedToResolveSymlink": "ไม่สามารถแก้ไขลิงก์สัญลักษณ์ได้",
|
||||
"itemDeletedSuccessfully": "{{type}} ถูกลบสำเร็จแล้ว",
|
||||
"itemsDeletedSuccessfully": "ลบรายการสำเร็จแล้ว {{count}} รายการ",
|
||||
"itemDeletedSuccessfully": "{{type}} ลบสำเร็จแล้ว",
|
||||
"itemsDeletedSuccessfully": "รายการ {{count}} ถูกลบสำเร็จแล้ว",
|
||||
"failedToDeleteItems": "ไม่สามารถลบรายการได้",
|
||||
"dragFilesToUpload": "ลากไฟล์มาวางที่นี่เพื่ออัปโหลด",
|
||||
"emptyFolder": "โฟลเดอร์นี้ว่างเปล่า",
|
||||
@@ -1347,14 +1347,14 @@
|
||||
"delete": "ลบ",
|
||||
"properties": "คุณสมบัติ",
|
||||
"refresh": "รีเฟรช",
|
||||
"downloadFiles": "ดาวน์โหลดไฟล์ {{count}} ไฟล์ไปยังเบราว์เซอร์",
|
||||
"copyFiles": "คัดลอก {{count}} รายการ",
|
||||
"cutFiles": "ตัด {{count}} รายการ",
|
||||
"downloadFiles": "ดาวน์โหลดไฟล์ {{count}} ไปยังเบราว์เซอร์",
|
||||
"copyFiles": "คัดลอกรายการ {{count}} รายการ",
|
||||
"cutFiles": "ตัดรายการ {{count}} รายการ",
|
||||
"deleteFiles": "ลบรายการ {{count}} รายการ",
|
||||
"filesCopiedToClipboard": "คัดลอกรายการไปยังคลิปบอร์ดแล้ว {{count}} รายการ",
|
||||
"filesCutToClipboard": "{{count}} รายการถูกตัดไปยังคลิปบอร์ด",
|
||||
"filesCopiedToClipboard": "{{count}} รายการถูกคัดลอกไปยังคลิปบอร์ด",
|
||||
"filesCutToClipboard": "{{count}} รายการที่ถูกตัดไปยังคลิปบอร์ด",
|
||||
"pathCopiedToClipboard": "คัดลอกเส้นทางไปยังคลิปบอร์ดแล้ว",
|
||||
"pathsCopiedToClipboard": "คัดลอกเส้นทางไปยังคลิปบอร์ดแล้ว {{count}} เส้นทาง",
|
||||
"pathsCopiedToClipboard": "{{count}} คัดลอกเส้นทางไปยังคลิปบอร์ดแล้ว",
|
||||
"failedToCopyPath": "ไม่สามารถคัดลอกเส้นทางไปยังคลิปบอร์ดได้",
|
||||
"movedItems": "ย้ายรายการ {{count}} รายการ",
|
||||
"failedToDeleteItem": "ไม่สามารถลบรายการได้",
|
||||
@@ -1390,7 +1390,7 @@
|
||||
"fileOperations": "การดำเนินการไฟล์",
|
||||
"confirmDeleteMessage": "คุณแน่ใจหรือไม่ว่าต้องการลบ {{name}}?",
|
||||
"confirmDeleteSingleItem": "คุณแน่ใจหรือไม่ว่าต้องการลบ \"{{name}}\" อย่างถาวร?",
|
||||
"confirmDeleteMultipleItems": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการจำนวน {{count}} รายการอย่างถาวร?",
|
||||
"confirmDeleteMultipleItems": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการ {{count}} อย่างถาวร?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการ {{count}} รายการอย่างถาวร ซึ่งรวมถึงโฟลเดอร์และเนื้อหาภายในโฟลเดอร์ด้วย",
|
||||
"confirmDeleteFolder": "คุณแน่ใจหรือไม่ว่าต้องการลบโฟลเดอร์ \"{{name}}\" และเนื้อหาทั้งหมดในนั้นอย่างถาวร?",
|
||||
"deleteDirectoryWarning": "การดำเนินการนี้จะลบโฟลเดอร์และเนื้อหาทั้งหมดภายในโฟลเดอร์นั้น",
|
||||
@@ -1428,25 +1428,25 @@
|
||||
"starred": "ดาว",
|
||||
"shortcuts": "ทางลัด",
|
||||
"directories": "รายชื่อ",
|
||||
"removedFromRecentFiles": "ลบ \"{{name}}\" ออกจากไฟล์ล่าสุด",
|
||||
"removedFromRecentFiles": "ลบ \"{{name}}\" ออกจากไฟล์ล่าสุดแล้ว",
|
||||
"removeFailed": "ลบสิ่งที่ล้มเหลว",
|
||||
"unpinnedSuccessfully": "ยกเลิกการตรึง \"{{name}}\" สำเร็จ",
|
||||
"unpinnedSuccessfully": "ยกเลิกการตรึง \"{{name}}\" สำเร็จแล้ว",
|
||||
"unpinFailed": "ยกเลิกการตรึงไม่สำเร็จ",
|
||||
"removedShortcut": "ลบทางลัด \"{{name}}\"",
|
||||
"removeShortcutFailed": "ลบทางลัดไม่สำเร็จ",
|
||||
"removedShortcut": "ลบทางลัด \"{{name}}\" ออกแล้ว",
|
||||
"removeShortcutFailed": "การลบทางลัดล้มเหลว",
|
||||
"clearedAllRecentFiles": "ลบไฟล์ล่าสุดทั้งหมดแล้ว",
|
||||
"clearFailed": "เคลียร์ล้มเหลว",
|
||||
"removeFromRecentFiles": "ลบออกจากไฟล์ล่าสุด",
|
||||
"clearAllRecentFiles": "ลบไฟล์ล่าสุดทั้งหมด",
|
||||
"unpinFile": "ยกเลิกการตรึงไฟล์",
|
||||
"removeShortcut": "ลบทางลัด",
|
||||
"saveFilesToSystem": "บันทึกไฟล์ {{count}} ไฟล์เป็น...",
|
||||
"saveFilesToSystem": "บันทึกไฟล์ {{count}} เป็น...",
|
||||
"pinFile": "ไฟล์พิน",
|
||||
"addToShortcuts": "เพิ่มไปยังทางลัด",
|
||||
"downloadToDefaultLocation": "ดาวน์โหลดไปยังตำแหน่งเริ่มต้น",
|
||||
"pasteFailed": "การวางล้มเหลว",
|
||||
"noUndoableActions": "ไม่มีการกระทำใดที่ย้อนกลับไม่ได้",
|
||||
"undoCopySuccess": "ยกเลิกการคัดลอก: ลบไฟล์ที่คัดลอกไว้ {{count}} ไฟล์",
|
||||
"undoCopySuccess": "ยกเลิกการคัดลอก: ลบไฟล์ที่คัดลอก {{count}} ไฟล์",
|
||||
"undoCopyFailedDelete": "การยกเลิกการกระทำล้มเหลว: ไม่สามารถลบไฟล์ที่คัดลอกไว้ได้",
|
||||
"undoCopyFailedNoInfo": "การยกเลิกการกระทำล้มเหลว: ไม่พบข้อมูลไฟล์ที่คัดลอกไว้",
|
||||
"undoMoveSuccess": "ยกเลิกการย้าย: ย้ายไฟล์ {{count}} ไฟล์กลับไปยังตำแหน่งเดิม",
|
||||
@@ -1490,25 +1490,25 @@
|
||||
"startTyping": "เริ่มพิมพ์...",
|
||||
"unknownSize": "ขนาดไม่ทราบแน่ชัด",
|
||||
"fileIsEmpty": "ไฟล์ว่างเปล่า",
|
||||
"largeFileWarning": "คำเตือนไฟล์ขนาดใหญ่",
|
||||
"largeFileWarning": "คำเตือนเกี่ยวกับไฟล์ขนาดใหญ่",
|
||||
"largeFileWarningDesc": "ไฟล์นี้มีขนาด {{size}} ซึ่งอาจทำให้เกิดปัญหาด้านประสิทธิภาพเมื่อเปิดเป็นข้อความ",
|
||||
"fileNotFoundAndRemoved": "ไม่พบไฟล์ \"{{name}}\" และไฟล์ดังกล่าวถูกลบออกจากไฟล์ล่าสุด/ไฟล์ปักหมุดแล้ว",
|
||||
"failedToLoadFile": "ไม่สามารถโหลดไฟล์ได้: {{error}}",
|
||||
"serverErrorOccurred": "เกิดข้อผิดพลาดของเซิร์ฟเวอร์ โปรดลองใหม่อีกครั้งในภายหลัง",
|
||||
"autoSaveFailed": "การบันทึกอัตโนมัติล้มเหลว",
|
||||
"fileAutoSaved": "ไฟล์ถูกบันทึกอัตโนมัติ",
|
||||
"moveFileFailed": "ไม่สามารถย้าย {{name}} ได้",
|
||||
"moveFileFailed": "การย้ายล้มเหลว {{name}}",
|
||||
"moveOperationFailed": "การดำเนินการย้ายล้มเหลว",
|
||||
"canOnlyCompareFiles": "สามารถเปรียบเทียบไฟล์ได้เพียงสองไฟล์เท่านั้น",
|
||||
"comparingFiles": "การเปรียบเทียบไฟล์: {{file1}} และ {{file2}}",
|
||||
"comparingFiles": "เปรียบเทียบไฟล์: {{file1}} และ {{file2}}",
|
||||
"dragFailed": "การดำเนินการลากล้มเหลว",
|
||||
"filePinnedSuccessfully": "ไฟล์ \"{{name}}\" ถูกตรึงสำเร็จแล้ว",
|
||||
"filePinnedSuccessfully": "ไฟล์ \"{{name}}\" ถูกปักหมุดสำเร็จแล้ว",
|
||||
"pinFileFailed": "ไม่สามารถตรึงไฟล์ได้",
|
||||
"fileUnpinnedSuccessfully": "ไฟล์ \"{{name}}\" ปลดตรึงสำเร็จแล้ว",
|
||||
"fileUnpinnedSuccessfully": "ไฟล์ \"{{name}}\" ถูกยกเลิกการตรึงเรียบร้อยแล้ว",
|
||||
"unpinFileFailed": "ไม่สามารถยกเลิกการตรึงไฟล์ได้",
|
||||
"shortcutAddedSuccessfully": "เพิ่มทางลัดโฟลเดอร์ \"{{name}}\" สำเร็จแล้ว",
|
||||
"addShortcutFailed": "ไม่สามารถเพิ่มทางลัดได้",
|
||||
"operationCompletedSuccessfully": "สำเร็จ {{operation}} {{count}} รายการ",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} รายการสำเร็จ",
|
||||
"operationCompleted": "{{operation}} {{count}} รายการ",
|
||||
"downloadFileSuccess": "ดาวน์โหลดไฟล์ {{name}} สำเร็จแล้ว",
|
||||
"downloadFileFailed": "การดาวน์โหลดล้มเหลว",
|
||||
@@ -1517,7 +1517,7 @@
|
||||
"dragOutsideToDownload": "ลากออกนอกหน้าต่างเพื่อดาวน์โหลดไฟล์ ({{count}} ไฟล์)",
|
||||
"newFolderDefault": "โฟลเดอร์ใหม่",
|
||||
"newFileDefault": "ไฟล์ใหม่.txt",
|
||||
"successfullyMovedItems": "ย้ายรายการ {{count}} รายการไปยัง {{target}} สำเร็จแล้ว",
|
||||
"successfullyMovedItems": "ย้ายรายการ {{count}} รายการไปยัง {{target}}สำเร็จแล้ว",
|
||||
"move": "เคลื่อนไหว",
|
||||
"searchInFile": "ค้นหาในไฟล์ (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "แสดงทางลัดแป้นพิมพ์",
|
||||
@@ -1554,7 +1554,7 @@
|
||||
"tunnels": {
|
||||
"title": "อุโมงค์ SSH",
|
||||
"noSshTunnels": "ไม่มีอุโมงค์ SSH",
|
||||
"createFirstTunnelMessage": "คุณยังไม่ได้สร้างอุโมงค์ SSH ใดๆ เลย ตั้งค่าการเชื่อมต่ออุโมงค์ใน Host Manager เพื่อเริ่มต้นใช้งาน",
|
||||
"createFirstTunnelMessage": "คุณยังไม่ได้สร้างอุโมงค์ SSH ใดๆ เลย กำหนดค่าการเชื่อมต่ออุโมงค์ใน Host Manager เพื่อเริ่มต้นใช้งาน",
|
||||
"connected": "เชื่อมต่อแล้ว",
|
||||
"disconnected": "ตัดการเชื่อมต่อ",
|
||||
"connecting": "กำลังเชื่อมต่อ...",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "ตัดการเชื่อมต่อ",
|
||||
"cancel": "ยกเลิก",
|
||||
"port": "ท่าเรือ",
|
||||
"attempt": "ความพยายาม {{current}} จาก {{max}}",
|
||||
"attempt": "ความพยายาม {{current}} ของ {{max}}",
|
||||
"nextRetryIn": "ลองใหม่อีกครั้งใน {{seconds}} วินาที",
|
||||
"checkDockerLogs": "ตรวจสอบบันทึก Docker ของคุณเพื่อดูสาเหตุของข้อผิดพลาด เข้าร่วมกลุ่มสนทนา",
|
||||
"orCreate": "หรือสร้าง",
|
||||
"orCreate": "หรือสร้าง ",
|
||||
"noTunnelConnections": "ไม่มีการกำหนดค่าการเชื่อมต่ออุโมงค์",
|
||||
"tunnelConnections": "การเชื่อมต่ออุโมงค์",
|
||||
"addTunnel": "เพิ่มอุโมงค์",
|
||||
@@ -1624,8 +1624,8 @@
|
||||
"refreshStatus": "รีเฟรชสถานะ",
|
||||
"fileManagerAlreadyOpen": "โปรแกรมจัดการไฟล์เปิดใช้งานอยู่แล้วสำหรับโฮสต์นี้",
|
||||
"openFileManager": "เปิดตัวจัดการไฟล์",
|
||||
"cpuCores_one": "ซีพียู {{count}}",
|
||||
"cpuCores_other": "ซีพียู {{count}}",
|
||||
"cpuCores_one": "{{count}} ซีพียู",
|
||||
"cpuCores_other": "{{count}} ซีพียู",
|
||||
"naCpus": "ไม่มีข้อมูล CPU",
|
||||
"loadAverageNA": "ค่าเฉลี่ย: ไม่มีข้อมูล",
|
||||
"cpuUsage": "การใช้งาน CPU",
|
||||
@@ -1682,7 +1682,7 @@
|
||||
"executingQuickAction": "กำลังดำเนินการ {{name}}...",
|
||||
"quickActionSuccess": "{{name}} เสร็จสมบูรณ์เรียบร้อยแล้ว",
|
||||
"quickActionFailed": "{{name}} ล้มเหลว",
|
||||
"quickActionError": "ไม่สามารถดำเนินการ {{name}} ได้"
|
||||
"quickActionError": "ไม่สามารถดำเนินการ {{name}}ได้"
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "ตัวจัดการเซิร์ฟเวอร์ SSH",
|
||||
@@ -1733,7 +1733,7 @@
|
||||
"disableTwoFactorWarning": "การปิดใช้งานการยืนยันตัวตนสองขั้นตอนจะทำให้บัญชีของคุณมีความปลอดภัยน้อยลง",
|
||||
"passwordOrTotpCode": "รหัสผ่านหรือรหัส TOTP",
|
||||
"or": "หรือ",
|
||||
"generateNewBackupCodesText": "สร้างรหัสสำรองใหม่หากคุณทำรหัสสำรองเดิมหาย",
|
||||
"generateNewBackupCodesText": "หากคุณทำรหัสสำรองเดิมหาย ให้สร้างรหัสสำรองใหม่",
|
||||
"generateNewBackupCodes": "สร้างรหัสสำรองข้อมูลใหม่",
|
||||
"yourBackupCodes": "รหัสสำรองข้อมูลของคุณ",
|
||||
"download": "ดาวน์โหลด",
|
||||
@@ -1830,14 +1830,14 @@
|
||||
"saveSuccess": "บันทึกสำเร็จแล้ว",
|
||||
"saveError": "บันทึกไม่สำเร็จ",
|
||||
"deleteSuccess": "ลบสำเร็จแล้ว",
|
||||
"deleteError": "ไม่สามารถลบได้",
|
||||
"deleteError": "ลบไม่สำเร็จ",
|
||||
"updateSuccess": "อัปเดตสำเร็จแล้ว",
|
||||
"updateError": "การอัปเดตล้มเหลว",
|
||||
"copySuccess": "คัดลอกไปยังคลิปบอร์ดแล้ว",
|
||||
"copyError": "การคัดลอกล้มเหลว",
|
||||
"copiedToClipboard": "{{item}} คัดลอกไปยังคลิปบอร์ด",
|
||||
"copiedToClipboard": "{{item}} คัดลอกไปยังคลิปบอร์ดแล้ว",
|
||||
"connectionEstablished": "การเชื่อมต่อสำเร็จแล้ว",
|
||||
"connectionClosed": "การเชื่อมต่อถูกตัด",
|
||||
"connectionClosed": "การเชื่อมต่อถูกปิด",
|
||||
"reconnecting": "กำลังเชื่อมต่อใหม่...",
|
||||
"processing": "กำลังประมวลผล...",
|
||||
"pleaseWait": "โปรดรอ...",
|
||||
@@ -1957,7 +1957,7 @@
|
||||
"failedToMakeUserAdmin": "ไม่สามารถทำให้ผู้ใช้เป็นผู้ดูแลระบบได้",
|
||||
"userIsNowAdmin": "ผู้ใช้ {{username}} ตอนนี้เป็นผู้ดูแลระบบแล้ว",
|
||||
"removeAdminConfirm": "คุณแน่ใจหรือไม่ว่าต้องการลบสถานะผู้ดูแลระบบออกจาก {{username}}?",
|
||||
"deleteUserConfirm": "คุณแน่ใจหรือไม่ว่าต้องการลบผู้ใช้ {{username}}? การกระทำนี้ไม่สามารถยกเลิกได้",
|
||||
"deleteUserConfirm": "คุณแน่ใจหรือไม่ว่าต้องการลบผู้ใช้ {{username}}การกระทำนี้ไม่สามารถยกเลิกได้",
|
||||
"deleteAccount": "ลบบัญชีผู้ใช้",
|
||||
"closeDeleteAccount": "ปิด ลบ บัญชี",
|
||||
"deleteAccountWarning": "การกระทำนี้ไม่สามารถย้อนกลับได้ การดำเนินการนี้จะลบบัญชีของคุณและข้อมูลที่เกี่ยวข้องทั้งหมดอย่างถาวร",
|
||||
@@ -2150,7 +2150,7 @@
|
||||
"accessCount": "จำนวนการเข้าชม",
|
||||
"revokeAccess": "เพิกถอนสิทธิ์การเข้าถึง",
|
||||
"confirmRevokeAccess": "คุณแน่ใจหรือไม่ว่าต้องการเพิกถอนสิทธิ์การเข้าถึงสำหรับ {{username}}?",
|
||||
"hostSharedSuccessfully": "แชร์โฮสต์สำเร็จแล้วกับ {{username}}",
|
||||
"hostSharedSuccessfully": "แชร์โฮสต์สำเร็จแล้วด้วย {{username}}",
|
||||
"hostAccessUpdated": "การเข้าถึงโฮสต์ได้รับการอัปเดตแล้ว",
|
||||
"failedToShareHost": "ไม่สามารถแชร์โฮสต์ได้",
|
||||
"accessRevokedSuccessfully": "สิทธิ์การเข้าถึงถูกยกเลิกเรียบร้อยแล้ว",
|
||||
@@ -2170,7 +2170,7 @@
|
||||
"timesAccessed": "{{count}} ครั้ง",
|
||||
"daysRemaining": "{{days}} วัน",
|
||||
"hoursRemaining": "{{hours}} ชั่วโมง",
|
||||
"failedToFetchAccessList": "ไม่สามารถดึงรายการการเข้าถึงได้",
|
||||
"failedToFetchAccessList": "ไม่สามารถดึงรายการสิทธิ์การเข้าถึงได้",
|
||||
"currentAccess": "การเข้าถึงปัจจุบัน",
|
||||
"securityWarning": "คำเตือนด้านความปลอดภัย",
|
||||
"securityWarningMessage": "การแชร์ข้อมูลประจำตัวจะทำให้ผู้ใช้มีสิทธิ์เข้าถึงและดำเนินการใดๆ บนเซิร์ฟเวอร์ได้อย่างเต็มที่ รวมถึงการเปลี่ยนรหัสผ่านและการลบไฟล์ ควรแชร์เฉพาะกับผู้ใช้ที่ไว้ใจได้เท่านั้น",
|
||||
@@ -2184,15 +2184,15 @@
|
||||
"permissions": "สิทธิ์การเข้าถึง",
|
||||
"systemRole": "บทบาทของระบบ",
|
||||
"customRole": "บทบาทที่กำหนดเอง",
|
||||
"roleAssignedSuccessfully": "บทบาทได้รับการมอบหมายให้กับ {{username}} เรียบร้อยแล้ว",
|
||||
"roleAssignedSuccessfully": "บทบาทได้รับการมอบหมายให้กับ {{username}} สำเร็จแล้ว",
|
||||
"failedToAssignRole": "ไม่สามารถกำหนดบทบาทได้",
|
||||
"roleRemovedSuccessfully": "บทบาทถูกลบออกจาก {{username}} สำเร็จแล้ว",
|
||||
"roleRemovedSuccessfully": "ลบบทบาทออกจาก {{username}} สำเร็จแล้ว",
|
||||
"failedToRemoveRole": "ไม่สามารถลบบทบาทได้",
|
||||
"cannotRemoveSystemRole": "ไม่สามารถลบบทบาทระบบได้",
|
||||
"cannotShareWithSelf": "ไม่สามารถแชร์โฮสต์กับตัวเองได้",
|
||||
"noCustomRolesToAssign": "ไม่มีบทบาทที่กำหนดเองได้ บทบาทของระบบจะถูกกำหนดโดยอัตโนมัติ",
|
||||
"credentialSharingWarning": "ไม่รองรับการตรวจสอบสิทธิ์ด้วยข้อมูลประจำตัวสำหรับการแชร์",
|
||||
"credentialRequired": "จำเป็นต้องระบุข้อมูลประจำตัวเมื่อแชร์โฮสต์",
|
||||
"credentialRequired": "จำเป็นต้องระบุข้อมูลรับรองเมื่อแชร์โฮสต์",
|
||||
"credentialRequiredDescription": "โฮสต์นี้ไม่ได้ใช้การตรวจสอบสิทธิ์แบบใช้ข้อมูลประจำตัว เพื่อให้สามารถแชร์โฮสต์ได้ เนื่องจากมีการเข้ารหัสแบบต่อผู้ใช้ โฮสต์จึงต้องใช้การตรวจสอบสิทธิ์แบบใช้ข้อมูลประจำตัว",
|
||||
"auditLogs": "บันทึกการตรวจสอบ",
|
||||
"viewAuditLogs": "ดูบันทึกการตรวจสอบ",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "ยุติเซสชัน",
|
||||
"sessionTerminated": "เซสชันถูกยุติโดยเจ้าของโฮสต์",
|
||||
"sharedAccessExpired": "สิทธิ์การเข้าถึงแบบแชร์ของคุณไปยังโฮสต์นี้หมดอายุแล้ว",
|
||||
"sharedAccessExpiresIn": "สิทธิ์การเข้าถึงแบบใช้ร่วมกันจะหมดอายุในอีก {{hours}} ชั่วโมง",
|
||||
"sharedAccessExpiresIn": "สิทธิ์การเข้าถึงแบบแชร์จะหมดอายุในอีก {{hours}} ชั่วโมง",
|
||||
"roles": {
|
||||
"label": "บทบาท",
|
||||
"admin": "ผู้ดูแลระบบ",
|
||||
@@ -2249,7 +2249,7 @@
|
||||
"displayNamePlaceholder": "นักพัฒนา",
|
||||
"descriptionPlaceholder": "นักพัฒนาซอฟต์แวร์และวิศวกร",
|
||||
"confirmDeleteRole": "ลบบทบาท",
|
||||
"confirmDeleteRoleDescription": "คุณแน่ใจหรือไม่ว่าต้องการลบบทบาท &{{name}}&apos? การกระทำนี้ไม่สามารถยกเลิกได้",
|
||||
"confirmDeleteRoleDescription": "คุณแน่ใจหรือไม่ว่าต้องการลบบทบาท '{{name}}'? การกระทำนี้ไม่สามารถยกเลิกได้",
|
||||
"confirmRemoveRole": "ลบบทบาท",
|
||||
"confirmRemoveRoleDescription": "คุณแน่ใจหรือไม่ว่าต้องการลบสิทธิ์นี้ออกจากผู้ใช้?",
|
||||
"editRoleDescription": "อัปเดตข้อมูลบทบาท",
|
||||
@@ -2310,16 +2310,16 @@
|
||||
"errorCode": "รหัสข้อผิดพลาด: {{code}}",
|
||||
"version": "ด็อกเกอร์ {{version}}",
|
||||
"containerStarted": "คอนเทนเนอร์ {{name}} เริ่มทำงานแล้ว",
|
||||
"failedToStartContainer": "ไม่สามารถเริ่มต้นคอนเทนเนอร์ {{name}} ได้",
|
||||
"failedToStartContainer": "ไม่สามารถเริ่มต้นคอนเทนเนอร์ได้ {{name}}",
|
||||
"containerStopped": "คอนเทนเนอร์ {{name}} หยุดทำงานแล้ว",
|
||||
"failedToStopContainer": "ไม่สามารถหยุดคอนเทนเนอร์ {{name}} ได้",
|
||||
"failedToStopContainer": "ไม่สามารถหยุดคอนเทนเนอร์ได้ {{name}}",
|
||||
"containerRestarted": "คอนเทนเนอร์ {{name}} รีสตาร์ทแล้ว",
|
||||
"failedToRestartContainer": "ไม่สามารถรีสตาร์ทคอนเทนเนอร์ {{name}}",
|
||||
"failedToRestartContainer": "ไม่สามารถรีสตาร์ทคอนเทนเนอร์ได้ {{name}}",
|
||||
"containerPaused": "คอนเทนเนอร์ {{name}} หยุดชั่วคราว",
|
||||
"containerUnpaused": "คอนเทนเนอร์ {{name}} ยกเลิกการหยุดชั่วคราว",
|
||||
"failedToTogglePauseContainer": "ไม่สามารถสลับสถานะหยุดชั่วคราวสำหรับคอนเทนเนอร์ {{name}} ได้",
|
||||
"failedToTogglePauseContainer": "ไม่สามารถสลับสถานะหยุดชั่วคราวสำหรับคอนเทนเนอร์ {{name}}ได้",
|
||||
"containerRemoved": "คอนเทนเนอร์ {{name}} ถูกลบออกแล้ว",
|
||||
"failedToRemoveContainer": "ไม่สามารถลบคอนเทนเนอร์ {{name}} ได้",
|
||||
"failedToRemoveContainer": "ไม่สามารถลบคอนเทนเนอร์ {{name}}ได้",
|
||||
"image": "ภาพ",
|
||||
"idLabel": "รหัสประจำตัว",
|
||||
"ports": "ท่าเรือ",
|
||||
@@ -2332,7 +2332,7 @@
|
||||
"restart": "เริ่มใหม่",
|
||||
"remove": "ลบ",
|
||||
"removeContainer": "นำภาชนะออก",
|
||||
"confirmRemoveContainer": "คุณแน่ใจหรือไม่ว่าต้องการลบคอนเทนเนอร์ &{{name}}'? การกระทำนี้ไม่สามารถย้อนกลับได้",
|
||||
"confirmRemoveContainer": "คุณแน่ใจหรือไม่ว่าต้องการลบคอนเทนเนอร์ '{{name}}'? การกระทำนี้ไม่สามารถย้อนกลับได้",
|
||||
"runningContainerWarning": "คำเตือน: ขณะนี้คอนเทนเนอร์นี้กำลังทำงานอยู่ การลบคอนเทนเนอร์นี้จะหยุดการทำงานของคอนเทนเนอร์ก่อน",
|
||||
"removing": "กำลังลบ...",
|
||||
"loadingContainers": "กำลังขนถ่ายตู้คอนเทนเนอร์...",
|
||||
@@ -2368,7 +2368,7 @@
|
||||
"id": "รหัสประจำตัว",
|
||||
"state": "สถานะ",
|
||||
"disconnectedFromContainer": "ตัดการเชื่อมต่อจากคอนเทนเนอร์",
|
||||
"containerMustBeRunning": "ต้องเปิดใช้งานคอนเทนเนอร์ก่อนจึงจะสามารถเข้าถึงคอนโซลได้",
|
||||
"containerMustBeRunning": "ต้องรอให้คอนเทนเนอร์ทำงานอยู่จึงจะสามารถเข้าถึงคอนโซลได้",
|
||||
"authenticationRequired": "จำเป็นต้องยืนยันตัวตน",
|
||||
"verificationCodePrompt": "ป้อนรหัสยืนยัน",
|
||||
"totpVerificationFailed": "การตรวจสอบ TOTP ล้มเหลว โปรดลองอีกครั้ง",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "เปลี่ยนเป็นโหมดสว่าง",
|
||||
"switchToDark": "เปลี่ยนเป็นโหมดมืด"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
"failedToFetchCredentials": "Kimlik bilgilerini alma işlemi başarısız oldu.",
|
||||
"credentialDeletedSuccessfully": "Kimlik bilgileri başarıyla silindi.",
|
||||
"failedToDeleteCredential": "Kimlik bilgilerini silme işlemi başarısız oldu.",
|
||||
"confirmDeleteCredential": "\"{{name}}\" kimlik bilgisini silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteCredential": "\"{{name}}\" kimlik bilgilerini silmek istediğinizden emin misiniz?",
|
||||
"credentialCreatedSuccessfully": "Kimlik doğrulama başarıyla oluşturuldu.",
|
||||
"credentialUpdatedSuccessfully": "Kimlik bilgileri başarıyla güncellendi.",
|
||||
"failedToSaveCredential": "Kimlik bilgilerini kaydetme başarısız oldu.",
|
||||
@@ -36,14 +36,14 @@
|
||||
"failedToFetchHostsUsing": "Bu kimlik bilgileri kullanılarak sunucular alınamadı.",
|
||||
"loadingCredentials": "Kimlik bilgileri yükleniyor...",
|
||||
"retry": "Tekrar dene",
|
||||
"noCredentials": "Kimlik Bilgisi Yok",
|
||||
"noCredentials": "Kimlik bilgileri yok",
|
||||
"noCredentialsMessage": "Henüz herhangi bir kimlik bilgisi eklemediniz. Başlamak için \"Kimlik Bilgisi Ekle\"ye tıklayın.",
|
||||
"sshCredentials": "SSH Kimlik Bilgileri",
|
||||
"credentialsCount": "{{count}} kimlik bilgileri",
|
||||
"refresh": "Yenile",
|
||||
"passwordRequired": "Şifre gereklidir.",
|
||||
"sshKeyRequired": "SSH anahtarı gereklidir.",
|
||||
"credentialAddedSuccessfully": "Kimlik bilgisi \"{{name}}\" başarıyla eklendi.",
|
||||
"credentialAddedSuccessfully": "Kimlik bilgisi \"{{name}}\" başarıyla eklendi",
|
||||
"general": "Genel",
|
||||
"description": "Tanım",
|
||||
"folder": "Dosya",
|
||||
@@ -137,11 +137,11 @@
|
||||
"folderView": "Klasörler",
|
||||
"unknownCredential": "Bilinmiyor",
|
||||
"confirmRemoveFromFolder": "\"{{name}}\" öğesini \"{{folder}}\" klasöründen kaldırmak istediğinizden emin misiniz? Kimlik bilgisi \"Kategorilenmemiş\" bölümüne taşınacaktır.",
|
||||
"removedFromFolder": "Kimlik bilgisi \"{{name}}\" klasörden başarıyla kaldırıldı.",
|
||||
"removedFromFolder": "\"{{name}}\" kimlik bilgisi klasörden başarıyla kaldırıldı.",
|
||||
"failedToRemoveFromFolder": "Klasörden kimlik bilgilerini kaldırma işlemi başarısız oldu.",
|
||||
"folderRenamed": "\"{{oldName}}\" klasörü başarıyla \"{{newName}}\" olarak yeniden adlandırıldı.",
|
||||
"failedToRenameFolder": "Klasörü yeniden adlandırma başarısız oldu.",
|
||||
"movedToFolder": "Kimlik bilgisi \"{{name}}\" başarıyla \"{{folder}}\"'a taşındı.",
|
||||
"movedToFolder": "Kimlik bilgisi \"{{name}}\" başarıyla \"{{folder}}\" konumuna taşındı",
|
||||
"failedToMoveToFolder": "Kimlik bilgilerini klasöre taşıma işlemi başarısız oldu.",
|
||||
"sshPublicKey": "SSH Genel Anahtarı",
|
||||
"publicKeyNote": "Herkese açık anahtar isteğe bağlıdır ancak anahtar doğrulaması için önerilir.",
|
||||
@@ -186,11 +186,11 @@
|
||||
},
|
||||
"dragIndicator": {
|
||||
"error": "Hata: {{error}}",
|
||||
"dragging": "{{fileName}} Sürükleme",
|
||||
"preparing": "{{fileName}}'ü hazırlamak",
|
||||
"dragging": "Sürükleme {{fileName}}",
|
||||
"preparing": "{{fileName}}hazırlanıyor",
|
||||
"readySingle": "İndirmeye hazır {{fileName}}",
|
||||
"readyMultiple": "{{count}} dosyayı indirmeye hazır",
|
||||
"batchDrag": "{{count}} dosyayı masaüstüne sürükleyin",
|
||||
"readyMultiple": "{{count}} dosyaları indirmeye hazır",
|
||||
"batchDrag": "{{count}} dosyaları masaüstüne sürükleyin",
|
||||
"dragToDesktop": "Masaüstüne sürükleyin",
|
||||
"canDragAnywhere": "Dosyaları masaüstünüzde istediğiniz yere sürükleyebilirsiniz."
|
||||
},
|
||||
@@ -202,12 +202,12 @@
|
||||
"stopKeyRecording": "Tuş Kaydını Durdur",
|
||||
"selectTerminals": "Terminalleri seçin:",
|
||||
"typeCommands": "Komutları yazın (tüm tuşlar desteklenir):",
|
||||
"commandsWillBeSent": "Komutlar seçilen {{count}} terminale gönderilecektir.",
|
||||
"commandsWillBeSent": "Komutlar {{count}} seçili terminale gönderilecektir.",
|
||||
"settings": "Ayarlar",
|
||||
"enableRightClickCopyPaste": "Sağ tıklama ile kopyala/yapıştır özelliğini etkinleştirin.",
|
||||
"shareIdeas": "SSH araçları için sırada ne olması gerektiğine dair fikirleriniz var mı? Bunları paylaşın.",
|
||||
"scripts": {
|
||||
"inputPlaceholder": "Örneğin, Sistem Komutları, Docker Komut Dosyaları"
|
||||
"inputPlaceholder": "Örneğin, Sistem Komutları, Docker Betikleri"
|
||||
}
|
||||
},
|
||||
"snippets": {
|
||||
@@ -230,7 +230,7 @@
|
||||
"createDescription": "Hızlı çalıştırma için yeni bir komut parçacığı oluşturun.",
|
||||
"editDescription": "Bu komut parçasını düzenleyin",
|
||||
"deleteConfirmTitle": "Kod parçasını sil",
|
||||
"deleteConfirmDescription": "\"{{name}}\"u silmek istediğinizden emin misiniz?",
|
||||
"deleteConfirmDescription": "\"{{name}}\" ifadesini silmek istediğinizden emin misiniz?",
|
||||
"createSuccess": "Kod parçası başarıyla oluşturuldu.",
|
||||
"updateSuccess": "Kod parçası başarıyla güncellendi.",
|
||||
"deleteSuccess": "Kod parçası başarıyla silindi.",
|
||||
@@ -248,7 +248,7 @@
|
||||
"reorderSameFolder": "Yalnızca aynı klasör içindeki kod parçacıklarının sırasını değiştirebilirsiniz.",
|
||||
"reorderSuccess": "Parçacıkların sıralaması başarıyla değiştirildi.",
|
||||
"reorderFailed": "Kod parçacıklarının yeniden sıralanması başarısız oldu.",
|
||||
"deleteFolderConfirm": "\"{{name}}\" klasörünü silmek mi istiyorsunuz? Tüm parçalar Kategorilenmemiş'e taşınacak.",
|
||||
"deleteFolderConfirm": "\"{{name}}\" klasörünü silmek mi istiyorsunuz? Tüm parçalar Kategorilenmemiş klasörüne taşınacak.",
|
||||
"deleteFolderSuccess": "Klasör başarıyla silindi.",
|
||||
"deleteFolderFailed": "Klasör silme işlemi başarısız oldu.",
|
||||
"updateFolderSuccess": "Klasör başarıyla güncellendi.",
|
||||
@@ -256,7 +256,7 @@
|
||||
"updateFolderFailed": "Klasör güncellemesi başarısız oldu.",
|
||||
"createFolderFailed": "Klasör oluşturulamadı.",
|
||||
"selectTerminals": "Terminalleri Seçin (isteğe bağlı)",
|
||||
"executeOnSelected": "Seçilen {{count}} terminalde yürütülecektir.",
|
||||
"executeOnSelected": "{{count}} seçili terminalde yürütülecek",
|
||||
"executeOnCurrent": "Geçerli terminalde çalıştır (birden fazlasını seçmek için tıklayın)",
|
||||
"folder": "Dosya",
|
||||
"selectFolder": "Bir klasör seçin veya boş bırakın.",
|
||||
@@ -300,7 +300,7 @@
|
||||
"dragTabsHint": "Sekmeleri aşağıdaki düzen hücrelerine sürükleyerek atayın.",
|
||||
"layout": "Bölünmüş Ekran Düzeni",
|
||||
"dropHere": "Sekmeyi buraya bırakın.",
|
||||
"apply": "Bölünmüş Uygula",
|
||||
"apply": "Split uygulayın",
|
||||
"clear": "Clear Split",
|
||||
"selectMode": "Bölünmüş ekran modunu seçin",
|
||||
"helpText": "Aynı anda kaç sekme görüntülemek istediğinizi seçin.",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "Bölünmüş ekran temizlendi",
|
||||
"error": {
|
||||
"noAssignments": "Lütfen düzene en az bir sekme atayın.",
|
||||
"fillAllSlots": "Başvurmadan önce lütfen tüm {{count}} boşluğu doldurun."
|
||||
"fillAllSlots": "Başvurmadan önce lütfen tüm {{count}} boşlukları doldurun."
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -343,10 +343,10 @@
|
||||
"error": "Sürüm Kontrol Hatası",
|
||||
"checkFailed": "Güncellemeleri kontrol etme başarısız oldu.",
|
||||
"upToDate": "Uygulama güncel.",
|
||||
"currentVersion": "Şu anda {{version}} sürümünü kullanıyorsunuz.",
|
||||
"currentVersion": "Şu anda {{version}}sürümünü çalıştırıyorsunuz.",
|
||||
"updateAvailable": "Güncelleme Mevcut",
|
||||
"newVersionAvailable": "Yeni bir sürüm mevcut! Şu anda {{current}} sürümünü kullanıyorsunuz, ancak {{latest}} sürümü de mevcut.",
|
||||
"releasedOn": "{{date}} tarihinde yayınlandı",
|
||||
"newVersionAvailable": "Yeni bir sürüm mevcut! Şu anda {{current}}çalıştırıyorsunuz, ancak {{latest}} kullanılabilir durumda.",
|
||||
"releasedOn": "{{date}}tarihinde yayınlandı",
|
||||
"downloadUpdate": "Güncellemeyi İndir",
|
||||
"dismiss": "Azletmek",
|
||||
"checking": "Güncellemeler kontrol ediliyor...",
|
||||
@@ -391,12 +391,12 @@
|
||||
"dragToResizeSidebar": "Kenar çubuğunu yeniden boyutlandırmak için sürükleyin.",
|
||||
"noAuthCredentials": "Bu SSH sunucusu için kullanılabilir kimlik doğrulama bilgisi bulunmamaktadır.",
|
||||
"noReleases": "Yayın Yok",
|
||||
"updatesAndReleases": "Güncellemeler ve Sürümler",
|
||||
"updatesAndReleases": "Güncellemeler ve Yayınlar",
|
||||
"newVersionAvailable": "Yeni bir sürüm ({{version}}) mevcuttur.",
|
||||
"failedToFetchUpdateInfo": "Güncelleme bilgilerini alma işlemi başarısız oldu.",
|
||||
"preRelease": "Ön yayın",
|
||||
"loginFailed": "giriş başarısız oldu",
|
||||
"noReleasesFound": "Yayınlanmış hiçbir içerik bulunamadı.",
|
||||
"noReleasesFound": "Yayınlanmış hiçbir dosya bulunamadı.",
|
||||
"yourBackupCodes": "Yedekleme Kodlarınız",
|
||||
"sendResetCode": "Sıfırlama kodunu gönder",
|
||||
"verifyCode": "Kodu Doğrula",
|
||||
@@ -498,18 +498,18 @@
|
||||
"userManagement": "Kullanıcı Yönetimi",
|
||||
"makeAdmin": "Yönetici Yap",
|
||||
"removeAdmin": "Yöneticiyi Kaldır",
|
||||
"deleteUser": "Kullanıcı {{username}} silinsin mi? Bu işlem geri alınamaz.",
|
||||
"deleteUser": "Kullanıcı {{username}}silinsin mi? Bu işlem geri alınamaz.",
|
||||
"allowRegistration": "Kayıt işlemine izin ver",
|
||||
"oidcSettings": "OIDC Ayarları",
|
||||
"clientId": "Müşteri Kimliği",
|
||||
"clientSecret": "Müşteri Sırrı",
|
||||
"clientSecret": "Müşteri Gizli Bilgileri",
|
||||
"issuerUrl": "Yayıncı URL'si",
|
||||
"authorizationUrl": "Yetkilendirme URL'si",
|
||||
"tokenUrl": "Token URL",
|
||||
"updateSettings": "Ayarları Güncelle",
|
||||
"confirmDelete": "Bu kullanıcıyı silmek istediğinizden emin misiniz?",
|
||||
"confirmMakeAdmin": "{{username}}'yı yönetici yapmak istediğinizden emin misiniz?",
|
||||
"confirmRemoveAdmin": "{{username}}'den yönetici statüsünü kaldırmak istediğinizden emin misiniz?",
|
||||
"confirmMakeAdmin": "{{username}} 'ı yönetici yapmak istediğinizden emin misiniz?",
|
||||
"confirmRemoveAdmin": "{{username}}'dan yönetici statüsünü kaldırmak istediğinizden emin misiniz?",
|
||||
"externalAuthentication": "Harici Kimlik Doğrulama (OIDC)",
|
||||
"configureExternalProvider": "OIDC/OAuth2 kimlik doğrulaması için harici kimlik sağlayıcısını yapılandırın.",
|
||||
"userIdentifierPath": "Kullanıcı Tanımlayıcı Yolu",
|
||||
@@ -549,10 +549,10 @@
|
||||
"enterUsernameToMakeAdmin": "Yönetici yapmak için kullanıcı adınızı girin.",
|
||||
"userIsNowAdmin": "Kullanıcı {{username}} artık yöneticidir.",
|
||||
"failedToMakeUserAdmin": "Kullanıcıyı yönetici yapma işlemi başarısız oldu.",
|
||||
"removeAdminStatus": "{{username}}'tan yönetici statüsünü kaldır?",
|
||||
"adminStatusRemoved": "Yönetici statüsü {{username}}'den kaldırıldı.",
|
||||
"removeAdminStatus": "{{username}}'dan yönetici statüsünü kaldır?",
|
||||
"adminStatusRemoved": "Yönetici statüsü {{username}}adresinden kaldırıldı.",
|
||||
"failedToRemoveAdminStatus": "Yönetici statüsünü kaldırma işlemi başarısız oldu.",
|
||||
"userDeletedSuccessfully": "Kullanıcı {{username}} başarıyla silindi.",
|
||||
"userDeletedSuccessfully": "Kullanıcı {{username}} başarıyla silindi",
|
||||
"failedToDeleteUser": "Kullanıcı silme işlemi başarısız oldu.",
|
||||
"overrideUserInfoUrl": "Kullanıcı Bilgisi URL'sini Geçersiz Kıl (gerekli değil)",
|
||||
"failedToFetchSessions": "Oturumları alma işlemi başarısız oldu.",
|
||||
@@ -564,12 +564,12 @@
|
||||
"sessionsRevokedSuccessfully": "Oturumlar başarıyla iptal edildi.",
|
||||
"linkToPasswordAccount": "Parola Hesabına Bağlantı",
|
||||
"linkOIDCDialogTitle": "OIDC Hesabını Parola Hesabına Bağla",
|
||||
"linkOIDCDialogDescription": "{{username}} (OIDC kullanıcısı)'nı mevcut bir parola hesabına bağlayın. Bu, parola hesabı için çift kimlik doğrulamayı etkinleştirecektir.",
|
||||
"linkOIDCDialogDescription": "{{username}} (OIDC kullanıcısı) öğesini mevcut bir parola hesabına bağlayın. Bu, parola hesabı için çift kimlik doğrulamayı etkinleştirecektir.",
|
||||
"createUser": "Kullanıcı Oluştur",
|
||||
"createUserDescription": "Kullanıcı adı ve şifre ile yeni bir yerel kullanıcı oluşturun.",
|
||||
"enterUsername": "Kullanıcı adınızı girin",
|
||||
"enterPassword": "Şifrenizi girin",
|
||||
"userCreatedSuccessfully": "Kullanıcı {{username}} başarıyla oluşturuldu.",
|
||||
"userCreatedSuccessfully": "Kullanıcı {{username}} başarıyla oluşturuldu",
|
||||
"failedToCreateUser": "Kullanıcı oluşturulamadı.",
|
||||
"manageUser": "Kullanıcıyı Yönet",
|
||||
"manageUserDescription": "Kullanıcı ayarlarını, rollerini ve izinlerini yönetin.",
|
||||
@@ -584,7 +584,7 @@
|
||||
"passwordResetWarning": "Bir kullanıcının parolasını sıfırlamak, tüm verilerini (SSH sunucuları, kimlik bilgileri, ayarlar) silecektir. Bu işlem geri alınamaz.",
|
||||
"resetUserPassword": "Kullanıcı Parolasını Sıfırla",
|
||||
"resettingPassword": "Sıfırlanıyor...",
|
||||
"passwordResetInitiated": "{{username}} için parola sıfırlama işlemi başlatıldı. Sıfırlama kodu gönderildi.",
|
||||
"passwordResetInitiated": "{{username}}için parola sıfırlama işlemi başlatıldı. Sıfırlama kodu gönderildi.",
|
||||
"failedToResetPassword": "Parola sıfırlama işlemi başlatılamadı.",
|
||||
"sessionManagement": "Oturum Yönetimi",
|
||||
"revokeAllSessions": "Tüm Oturumları İptal Et",
|
||||
@@ -611,12 +611,12 @@
|
||||
"linkTargetUsernamePlaceholder": "Kullanıcı adınızı ve şifrenizi girin.",
|
||||
"linkAccountsButton": "Hesapları Bağla",
|
||||
"linkingAccounts": "Bağlantı kuruluyor...",
|
||||
"accountsLinkedSuccessfully": "OIDC kullanıcısı {{oidcUsername}}, {{targetUsername}} ile ilişkilendirilmiştir.",
|
||||
"accountsLinkedSuccessfully": "OIDC kullanıcısı {{oidcUsername}} , {{targetUsername}}ile ilişkilendirildi.",
|
||||
"failedToLinkAccounts": "Hesapları bağlama başarısız oldu.",
|
||||
"linkTargetUsernameRequired": "Hedef kullanıcı adı gereklidir.",
|
||||
"unlinkOIDCTitle": "OIDC Kimlik Doğrulamasını Kaldır",
|
||||
"unlinkOIDCDescription": "{{username}}'den OIDC kimlik doğrulamasını kaldır? Kullanıcı bundan sonra yalnızca kullanıcı adı/şifre ile giriş yapabilecektir.",
|
||||
"unlinkOIDCSuccess": "OIDC, {{username}}'dan bağlantısı kesildi.",
|
||||
"unlinkOIDCDescription": "{{username}}'dan OIDC kimlik doğrulamasını kaldır? Bundan sonra kullanıcı yalnızca kullanıcı adı/şifre ile giriş yapabilecektir.",
|
||||
"unlinkOIDCSuccess": "OIDC bağlantısı {{username}}adresinden kaldırıldı.",
|
||||
"failedToUnlinkOIDC": "OIDC bağlantısını kaldırma işlemi başarısız oldu.",
|
||||
"databaseSecurity": "Veritabanı Güvenliği",
|
||||
"encryptionStatus": "Şifreleme Durumu",
|
||||
@@ -710,7 +710,7 @@
|
||||
"databaseImportedSuccessfully": "SQLite veritabanı başarıyla içe aktarıldı",
|
||||
"databaseImportFailed": "SQLite veritabanı içe aktarma işlemi başarısız oldu.",
|
||||
"manageEncryptionAndBackups": "Şifreleme anahtarlarını, veritabanı güvenliğini ve yedekleme işlemlerini yönetin.",
|
||||
"activeSecurityFeatures": "Şu anda aktif olan güvenlik önlemleri ve korumalar",
|
||||
"activeSecurityFeatures": "Şu anda aktif olan güvenlik önlemleri ve koruma yöntemleri",
|
||||
"deviceBindingTechnology": "Gelişmiş donanım tabanlı anahtar koruma teknolojisi",
|
||||
"backupAndRecovery": "Güvenli yedekleme oluşturma ve veritabanı kurtarma seçenekleri",
|
||||
"crossSystemDataTransfer": "Farklı sistemler arasında veritabanlarını dışa ve içe aktarma",
|
||||
@@ -756,7 +756,7 @@
|
||||
"revokeAllUserSessionsTitle": "Bu kullanıcıya ait tüm oturumları iptal et.",
|
||||
"revokeAll": "Tümünü İptal Et",
|
||||
"linkOidcToPasswordAccount": "OIDC Hesabını Parola Hesabına Bağla",
|
||||
"linkOidcToPasswordAccountDescription": "{{username}} (OIDC kullanıcısı)'nı mevcut bir parola hesabına bağlayın. Bu, parola hesabı için çift kimlik doğrulamayı etkinleştirecektir.",
|
||||
"linkOidcToPasswordAccountDescription": "{{username}} (OIDC kullanıcısı) öğesini mevcut bir parola hesabına bağlayın. Bu, parola hesabı için çift kimlik doğrulamayı etkinleştirecektir.",
|
||||
"linkOidcWarningTitle": "Uyarı: OIDC Kullanıcı Verileri Silinecektir",
|
||||
"linkOidcWarningDescription": "Bu işlem şunları sağlayacaktır:",
|
||||
"linkOidcActionDeleteUser": "OIDC kullanıcı hesabını ve tüm verilerini silin.",
|
||||
@@ -777,7 +777,7 @@
|
||||
"retry": "Tekrar dene",
|
||||
"refresh": "Yenile",
|
||||
"optional": "İsteğe bağlı",
|
||||
"hostsCount": "{{count}} ev sahibi",
|
||||
"hostsCount": "{{count}} sunucular",
|
||||
"importJson": "JSON'u içe aktar",
|
||||
"importing": "İçe aktarılıyor...",
|
||||
"importJsonTitle": "JSON dosyasından SSH sunucularını içe aktarın",
|
||||
@@ -790,7 +790,7 @@
|
||||
"confirmDelete": "\"{{name}}\" öğesini silmek istediğinizden emin misiniz?",
|
||||
"failedToDeleteHost": "Sunucuyu silme işlemi başarısız oldu.",
|
||||
"failedToExportHost": "Sunucu dışa aktarma işlemi başarısız oldu. Lütfen oturum açtığınızdan ve sunucu verilerine erişiminizin olduğundan emin olun.",
|
||||
"jsonMustContainHosts": "JSON verisi bir \"hosts\" dizisi içermeli veya hosts dizisi olmalıdır.",
|
||||
"jsonMustContainHosts": "JSON dosyası bir \"hosts\" dizisi içermeli veya hosts dizisi olmalıdır.",
|
||||
"noHostsInJson": "JSON dosyasında hiçbir sunucu bulunamadı.",
|
||||
"maxHostsAllowed": "İçe aktarma başına en fazla 100 sunucuya izin verilir.",
|
||||
"importCompleted": "İçe aktarma tamamlandı: {{success}} başarılı, {{failed}} başarısız",
|
||||
@@ -811,14 +811,14 @@
|
||||
"passwordRequired": "Parola tabanlı kimlik doğrulama kullanılırken parola gereklidir.",
|
||||
"sshKeyRequired": "Anahtar tabanlı kimlik doğrulama kullanılırken SSH özel anahtarı gereklidir.",
|
||||
"keyTypeRequired": "Anahtar tabanlı kimlik doğrulama kullanılırken Anahtar Türü gereklidir.",
|
||||
"mustSelectValidSshConfig": "Listeden geçerli bir SSH yapılandırması seçmelisiniz.",
|
||||
"mustSelectValidSshConfig": "Listeden geçerli bir SSH yapılandırması seçilmelidir.",
|
||||
"addHost": "Sunucu Ekle",
|
||||
"editHost": "Sunucuyu Düzenle",
|
||||
"cloneHost": "Klon Ana Bilgisayar",
|
||||
"updateHost": "Sunucuyu Güncelle",
|
||||
"hostUpdatedSuccessfully": "Sunucu \"{{name}}\" başarıyla güncellendi!",
|
||||
"hostAddedSuccessfully": "Sunucu \"{{name}}\" başarıyla eklendi!",
|
||||
"hostDeletedSuccessfully": "Sunucu \"{{name}}\" başarıyla silindi!",
|
||||
"hostAddedSuccessfully": "\"{{name}}\" sunucusu başarıyla eklendi!",
|
||||
"hostDeletedSuccessfully": "\"{{name}}\" sunucusu başarıyla silindi!",
|
||||
"failedToSaveHost": "Sunucu kaydedilemedi. Lütfen tekrar deneyin.",
|
||||
"savingHost": "Sunucuyu kaydediyorum...",
|
||||
"updatingHost": "Sunucu güncelleniyor...",
|
||||
@@ -837,10 +837,10 @@
|
||||
"connection": "Bağlantı",
|
||||
"remove": "Kaldırmak",
|
||||
"sourcePort": "Kaynak Bağlantı Noktası",
|
||||
"sourcePortDesc": "(Kaynak, Genel sekmesindeki Geçerli Bağlantı Ayrıntıları'na atıfta bulunmaktadır.)",
|
||||
"sourcePortDesc": " (Kaynak, Genel sekmesindeki Geçerli Bağlantı Ayrıntıları'na atıfta bulunmaktadır.)",
|
||||
"endpointPort": "Uç Nokta Bağlantı Noktası",
|
||||
"endpointSshConfig": "Uç Nokta SSH Yapılandırması",
|
||||
"tunnelForwardDescription": "Bu tünel, kaynak makinedeki {{sourcePort}} numaralı porttan (genel sekmesindeki mevcut bağlantı ayrıntıları) gelen trafiği uç nokta makinedeki {{endpointPort}} numaralı porta yönlendirecektir.",
|
||||
"tunnelForwardDescription": "Bu tünel, kaynak makinedeki {{sourcePort}} portundan (genel sekmesindeki mevcut bağlantı ayrıntıları) gelen trafiği uç nokta makinedeki {{endpointPort}} portuna yönlendirecektir.",
|
||||
"maxRetries": "Maksimum Yeniden Deneme Sayısı",
|
||||
"maxRetriesDescription": "Tünel bağlantısı için maksimum yeniden deneme sayısı.",
|
||||
"retryInterval": "Tekrar Deneme Aralığı (saniye)",
|
||||
@@ -916,8 +916,8 @@
|
||||
"customCommandsDesc": "Bu sunucu için özel kapatma ve yeniden başlatma komutları tanımlayın.",
|
||||
"shutdownCommand": "Kapatma Komutu",
|
||||
"rebootCommand": "Yeniden Başlatma Komutu",
|
||||
"confirmRemoveFromFolder": "\"{{name}}\" klasöründen \"{{folder}}\" öğesini kaldırmak istediğinizden emin misiniz? Sunucu \"Klasör Yok\" konumuna taşınacaktır.",
|
||||
"removedFromFolder": "Host \"{{name}}\" klasörden başarıyla kaldırıldı",
|
||||
"confirmRemoveFromFolder": "\"{{folder}}\" klasöründen \"{{name}}\" öğesini kaldırmak istediğinizden emin misiniz? Sunucu \"Klasör Yok\" konumuna taşınacaktır.",
|
||||
"removedFromFolder": "\"{{name}}\" sunucusu klasörden başarıyla kaldırıldı",
|
||||
"failedToRemoveFromFolder": "Ana bilgisayarı klasörden kaldırma işlemi başarısız oldu.",
|
||||
"folderRenamed": "\"{{oldName}}\" klasörü başarıyla \"{{newName}}\" olarak yeniden adlandırıldı.",
|
||||
"failedToRenameFolder": "Klasörü yeniden adlandırma başarısız oldu.",
|
||||
@@ -929,11 +929,11 @@
|
||||
"folderAppearanceUpdated": "Klasör görünümü başarıyla güncellendi.",
|
||||
"failedToUpdateFolderAppearance": "Klasör görünümünü güncelleme başarısız oldu.",
|
||||
"deleteAllHostsInFolder": "Klasördeki Tüm Sunucuları Sil",
|
||||
"confirmDeleteAllHostsInFolder": "\"{{count}}\" klasöründeki tüm {{folder}} ana bilgisayarları silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"allHostsInFolderDeleted": "\"{{count}}\" klasöründen {{folder}} ana bilgisayar başarıyla silindi.",
|
||||
"confirmDeleteAllHostsInFolder": "\"{{folder}}\" klasöründeki tüm {{count}} ana bilgisayarı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"allHostsInFolderDeleted": "\"{{folder}}\" klasöründen \" {{count}} \" ana bilgisayar başarıyla silindi.",
|
||||
"failedToDeleteHostsInFolder": "Klasördeki sunucuları silme işlemi başarısız oldu.",
|
||||
"movedToFolder": "Sunucu \"{{name}}\" başarıyla \"{{folder}}\" adresine taşındı.",
|
||||
"failedToMoveToFolder": "Sunucuyu klasöre taşıma başarısız oldu.",
|
||||
"movedToFolder": "Sunucu \"{{name}}\" başarıyla \"{{folder}}\" adresine taşındı",
|
||||
"failedToMoveToFolder": "Sunucu klasöre taşınamadı.",
|
||||
"clickToRenameFolder": "Klasörün adını değiştirmek için tıklayın.",
|
||||
"renameFolder": "Klasörü yeniden adlandır",
|
||||
"removeFromFolder": "\"{{folder}}\" klasöründen kaldır",
|
||||
@@ -943,7 +943,7 @@
|
||||
"cloneHostTooltip": "Klon konak",
|
||||
"clickToEditHost": "Sunucuyu düzenlemek için tıklayın",
|
||||
"dragToMoveBetweenFolders": "Klasörler arasında geçiş yapmak için sürükleyin.",
|
||||
"exportedHostConfig": "{{name}} için dışa aktarılan ana bilgisayar yapılandırması",
|
||||
"exportedHostConfig": "{{name}}için dışa aktarılan ana bilgisayar yapılandırması",
|
||||
"openTerminal": "Terminali açın",
|
||||
"openFileManager": "Dosya Yöneticisini Açın",
|
||||
"openTunnels": "Açık Tüneller",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "Ses",
|
||||
"bellStyleVisual": "Görsel",
|
||||
"bellStyleBoth": "İkisi birden",
|
||||
"bellStyleDesc": "Terminal zilini (BEL karakteri, \\x07) nasıl ele alacağınız aşağıda açıklanmıştır. Programlar, görevleri tamamladıklarında, hatalarla karşılaştıklarında veya bildirimler için bu zili tetikler. \"Sesli\" sesli bir bip sesi çalar, \"Görsel\" ekranı kısa süreliğine yanıp söndürür, \"Her ikisi\" hem sesli hem de görsel uyarı verir, \"Hiçbiri\" zil uyarılarını devre dışı bırakır.",
|
||||
"bellStyleDesc": "Terminal zilini (BEL karakteri, \\x07) nasıl ele alacağınız aşağıda açıklanmıştır. Programlar, görevleri tamamladıklarında, hatalarla karşılaştıklarında veya bildirimler için bu zili tetikler. \"Ses\" sesli bir bip sesi çıkarır, \"Görsel\" ekranı kısa süreliğine yanıp söndürür, \"Her ikisi\" hem sesli hem de görsel uyarı verir, \"Hiçbiri\" ise zil uyarılarını devre dışı bırakır.",
|
||||
"rightClickSelectsWord": "Sağ Tıklama Word Seçer",
|
||||
"rightClickSelectsWordDesc": "Sağ tıklama, imlecin altındaki kelimeyi seçer.",
|
||||
"fastScrollModifier": "Hızlı Kaydırma Değiştirici",
|
||||
@@ -1066,7 +1066,7 @@
|
||||
"socks5UsePreset": "Kaydedilmiş Ön Ayarı Kullan",
|
||||
"socks5SelectPreset": "Ön ayarı seçin",
|
||||
"socks5ManagePresets": "Ön Ayarları Yönet",
|
||||
"socks5ProxyNode": "Vekil {{number}}",
|
||||
"socks5ProxyNode": "Proxy {{number}}",
|
||||
"socks5AddProxy": "Zincire Proxy Ekle",
|
||||
"socks5RemoveProxy": "Proxy'yi Kaldır",
|
||||
"socks5ProxyType": "Vekil Türü",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "Proxy zinciri ön ayarı oluşturuldu",
|
||||
"socks5PresetUpdated": "Proxy zinciri ön ayarı güncellendi",
|
||||
"socks5PresetDeleted": "Proxy zinciri ön ayarı silindi",
|
||||
"socks5PresetSaved": "Ön ayar \"{{name}}\" başarıyla kaydedildi.",
|
||||
"socks5PresetSaved": "\"{{name}}\" ön ayarı başarıyla kaydedildi",
|
||||
"socks5PresetSaveError": "Ön ayar kaydedilemedi.",
|
||||
"socks5PresetNameRequired": "Ön ayar adı gereklidir.",
|
||||
"socks5EmptyChainError": "Boş bir proxy zinciri kaydedilemiyor.",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"socks5HostDescription": "SOCKS proxy sunucusunun ana bilgisayar adı veya IP adresi",
|
||||
"socks5PortDescription": "SOCKS proxy sunucusunun port numarası (varsayılan: 1080)",
|
||||
"addProxyNode": "Proxy Düğümü Ekle",
|
||||
"noProxyNodes": "Hiçbir proxy düğümü yapılandırılmadı. Bir tane eklemek için 'Proxy Düğümü Ekle'ye tıklayın.",
|
||||
"noProxyNodes": "Hiçbir proxy düğümü yapılandırılmamış. Bir tane eklemek için 'Proxy Düğümü Ekle'ye tıklayın.",
|
||||
"proxyNode": "Proxy Düğümü",
|
||||
"proxyType": "Vekil Türü",
|
||||
"quickActions": "Hızlı İşlemler",
|
||||
@@ -1133,7 +1133,7 @@
|
||||
"console": "Konsol",
|
||||
"containerMustBeRunning": "Konsola bağlanabilmek için konteynerin çalışır durumda olması gerekir.",
|
||||
"authenticationRequired": "Kimlik doğrulama gereklidir.",
|
||||
"connectedTo": "{{containerName}} ile bağlantılı",
|
||||
"connectedTo": "{{containerName}}ile bağlantılı",
|
||||
"disconnected": "Bağlantı kesildi",
|
||||
"consoleError": "Konsol hatası",
|
||||
"errorMessage": "Hata: {{message}}",
|
||||
@@ -1150,7 +1150,7 @@
|
||||
"disconnect": "Bağlantıyı kes",
|
||||
"notConnected": "Bağlı değil",
|
||||
"clickToConnect": "Etkileşimli bir kabuk başlatmak için Bağlan'a tıklayın.",
|
||||
"connectingTo": "{{containerName}} ile bağlantı kuruluyor...",
|
||||
"connectingTo": "{{containerName}}ile bağlantı kuruluyor...",
|
||||
"containerMustBeRunningToViewStats": "İstatistikleri görüntülemek için konteynerin çalışır durumda olması gerekir.",
|
||||
"failedToFetchStats": "İstatistikler alınamadı.",
|
||||
"noContainersFound": "Hiçbir konteyner bulunamadı.",
|
||||
@@ -1163,13 +1163,13 @@
|
||||
"noContainersMatchFiltersHint": "Arama veya filtre ayarlarınızı değiştirmeyi deneyin.",
|
||||
"containerStarted": "Konteyner {{name}} başlatıldı",
|
||||
"failedToStartContainer": "Konteyner başlatılamadı: {{error}}",
|
||||
"containerStopped": "Konteyner {{name}} durdu",
|
||||
"containerStopped": "Konteyner {{name}} durduruldu",
|
||||
"failedToStopContainer": "Konteyner durdurulamadı: {{error}}",
|
||||
"containerRestarted": "Konteyner {{name}} yeniden başlatıldı",
|
||||
"failedToRestartContainer": "Konteyner yeniden başlatılamadı: {{error}}",
|
||||
"containerUnpaused": "Konteyner {{name}} duraklatılmadı",
|
||||
"containerUnpaused": "Konteyner {{name}} duraklatılmamış",
|
||||
"containerPaused": "Konteyner {{name}} duraklatıldı",
|
||||
"failedToTogglePauseContainer": "{{action}} konteynerine erişilemedi: {{error}}",
|
||||
"failedToTogglePauseContainer": "{{action}} konteynerine erişim başarısız oldu: {{error}}",
|
||||
"containerRemoved": "Konteyner {{name}} kaldırıldı",
|
||||
"failedToRemoveContainer": "Konteyner kaldırılamadı: {{error}}",
|
||||
"image": "Resim:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "Duraklat",
|
||||
"restart": "Tekrar başlat",
|
||||
"removeContainer": "Kabı çıkarın",
|
||||
"confirmRemoveContainer": "\"{{name}}\" numaralı konteyneri kaldırmak istediğinizden emin misiniz?",
|
||||
"confirmRemoveContainer": "\"{{name}}\" kapsayıcısını kaldırmak istediğinizden emin misiniz?",
|
||||
"runningContainerWarning": "Uyarı: Bu konteyner şu anda çalışıyor ve zorla kaldırılacaktır.",
|
||||
"removing": "Kaldırılıyor:",
|
||||
"containerNotFound": "Konteyner bulunamadı.",
|
||||
@@ -1230,13 +1230,13 @@
|
||||
"messageParseError": "Sunucu mesajı ayrıştırma işlemi başarısız oldu.",
|
||||
"websocketError": "WebSocket bağlantı hatası",
|
||||
"connecting": "Bağlanıyor...",
|
||||
"reconnecting": "Yeniden bağlanıyor... ({{attempt}}/{{max}})",
|
||||
"reconnecting": "Yeniden bağlanılıyor... ({{attempt}}/{{max}})",
|
||||
"reconnected": "Bağlantı başarıyla yeniden kuruldu.",
|
||||
"maxReconnectAttemptsReached": "Maksimum yeniden bağlantı deneme sayısına ulaşıldı.",
|
||||
"connectionTimeout": "Bağlantı zaman aşımı",
|
||||
"terminalTitle": "Terminal - {{host}}",
|
||||
"terminalWithPath": "Terminal - {{host}}:{{path}}",
|
||||
"runTitle": "Koşu {{command}} - {{host}}",
|
||||
"runTitle": "Çalıştırılıyor {{command}} - {{host}}",
|
||||
"totpRequired": "İki Faktörlü Kimlik Doğrulama Gerekli",
|
||||
"totpCodeLabel": "Doğrulama Kodu",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1254,7 +1254,7 @@
|
||||
"uploadFile": "Dosya Yükle",
|
||||
"downloadFile": "İndirmek",
|
||||
"extractArchive": "Arşivden Çıkarma",
|
||||
"extractingArchive": "{{name}} çıkarılıyor...",
|
||||
"extractingArchive": "{{name}}çıkarılıyor...",
|
||||
"archiveExtractedSuccessfully": "{{name}} başarıyla çıkarıldı",
|
||||
"extractFailed": "Çıkarma işlemi başarısız oldu.",
|
||||
"compressFile": "Dosyayı Sıkıştır",
|
||||
@@ -1266,7 +1266,7 @@
|
||||
"selectedFiles": "Seçilen dosyalar",
|
||||
"andMoreFiles": "ve {{count}} daha fazlası...",
|
||||
"compress": "Kompres",
|
||||
"compressingFiles": "{{count}} öğeyi {{name}} öğeye sıkıştırılıyor...",
|
||||
"compressingFiles": "{{count}} öğeyi {{name}}öğeye sıkıştırılıyor...",
|
||||
"filesCompressedSuccessfully": "{{name}} başarıyla oluşturuldu",
|
||||
"compressFailed": "Sıkıştırma başarısız oldu",
|
||||
"edit": "Düzenlemek",
|
||||
@@ -1289,13 +1289,13 @@
|
||||
"chooseFile": "Dosya Seç",
|
||||
"uploading": "Yükleniyor...",
|
||||
"downloading": "İndiriliyor...",
|
||||
"uploadingFile": "{{name}} yükleniyor...",
|
||||
"uploadingFile": "{{name}}yükleniyor...",
|
||||
"uploadingLargeFile": "Büyük dosya yükleniyor {{name}} ({{size}})...",
|
||||
"downloadingFile": "{{name}} indiriliyor...",
|
||||
"creatingFile": "{{name}} oluşturuluyor...",
|
||||
"creatingFolder": "{{name}} oluşturuluyor...",
|
||||
"deletingItem": "{{type}} {{name}} siliniyor...",
|
||||
"renamingItem": "{{type}} {{oldName}} adını {{newName}} olarak yeniden adlandırma...",
|
||||
"downloadingFile": "{{name}}indiriliyor...",
|
||||
"creatingFile": "{{name}}oluşturuluyor...",
|
||||
"creatingFolder": "{{name}}oluşturuluyor...",
|
||||
"deletingItem": "{{type}} {{name}}siliniyor...",
|
||||
"renamingItem": "{{type}} {{oldName}} adını {{newName}}olarak yeniden adlandırma...",
|
||||
"createNewFile": "Yeni Dosya Oluştur",
|
||||
"fileName": "Dosya adı",
|
||||
"creating": "Oluşturuluyor...",
|
||||
@@ -1311,18 +1311,18 @@
|
||||
"newName": "Yeni İsim",
|
||||
"thisIsDirectoryRename": "Bu bir dizindir.",
|
||||
"renaming": "Yeniden adlandırılıyor...",
|
||||
"fileUploadedSuccessfully": "\"{{name}}\" dosyası başarıyla yüklendi.",
|
||||
"fileUploadedSuccessfully": "\"{{name}}\" dosyası başarıyla yüklendi",
|
||||
"failedToUploadFile": "Dosya yükleme başarısız oldu.",
|
||||
"fileDownloadedSuccessfully": "\"{{name}}\" dosyası başarıyla indirildi.",
|
||||
"fileDownloadedSuccessfully": "\"{{name}}\" dosyası başarıyla indirildi",
|
||||
"failedToDownloadFile": "Dosya indirme başarısız oldu.",
|
||||
"noFileContent": "Dosya içeriği alınamadı.",
|
||||
"filePath": "Dosya Yolu",
|
||||
"fileCreatedSuccessfully": "\"{{name}}\" dosyası başarıyla oluşturuldu.",
|
||||
"fileCreatedSuccessfully": "\"{{name}}\" dosyası başarıyla oluşturuldu",
|
||||
"failedToCreateFile": "Dosya oluşturulamadı.",
|
||||
"folderCreatedSuccessfully": "\"{{name}}\" klasörü başarıyla oluşturuldu.",
|
||||
"folderCreatedSuccessfully": "\"{{name}}\" klasörü başarıyla oluşturuldu",
|
||||
"failedToCreateFolder": "Klasör oluşturulamadı.",
|
||||
"failedToCreateItem": "Öğe oluşturulamadı.",
|
||||
"operationFailed": "{{operation}} işlemi {{name}} için başarısız oldu: {{error}}",
|
||||
"operationFailed": "{{operation}} işlemi {{name}}için başarısız oldu: {{error}}",
|
||||
"failedToResolveSymlink": "Sembolik bağlantı çözümlenemedi.",
|
||||
"itemDeletedSuccessfully": "{{type}} başarıyla silindi",
|
||||
"itemsDeletedSuccessfully": "{{count}} öğe başarıyla silindi",
|
||||
@@ -1354,7 +1354,7 @@
|
||||
"filesCopiedToClipboard": "{{count}} öğe panoya kopyalandı",
|
||||
"filesCutToClipboard": "{{count}} öğe panoya kopyalandı",
|
||||
"pathCopiedToClipboard": "Yol panoya kopyalandı",
|
||||
"pathsCopiedToClipboard": "{{count}} yol panoya kopyalandı",
|
||||
"pathsCopiedToClipboard": "{{count}} yollar panoya kopyalandı",
|
||||
"failedToCopyPath": "Yol kopyalanıp panoya aktarılamadı.",
|
||||
"movedItems": "{{count}} öğe taşındı",
|
||||
"failedToDeleteItem": "Öğeyi silme işlemi başarısız oldu.",
|
||||
@@ -1365,7 +1365,7 @@
|
||||
"size": "Boyut",
|
||||
"modified": "Değiştirildi",
|
||||
"path": "Yol",
|
||||
"confirmDelete": "{{name}}'yı silmek istediğinizden emin misiniz?",
|
||||
"confirmDelete": "{{name}}'ı silmek istediğinizden emin misiniz?",
|
||||
"uploadSuccess": "Dosya başarıyla yüklendi.",
|
||||
"uploadFailed": "Dosya yükleme başarısız oldu",
|
||||
"downloadSuccess": "Dosya başarıyla indirildi.",
|
||||
@@ -1388,7 +1388,7 @@
|
||||
"connectToServer": "Bir sunucuya bağlanın",
|
||||
"selectServerToEdit": "Dosyaları düzenlemeye başlamak için kenar çubuğundan bir sunucu seçin.",
|
||||
"fileOperations": "Dosya İşlemleri",
|
||||
"confirmDeleteMessage": "{{name}}'yi silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteMessage": "{{name}}'ı silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteSingleItem": "\"{{name}}\" öğesini kalıcı olarak silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteMultipleItems": "{{count}} öğeyi kalıcı olarak silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "{{count}} öğeyi kalıcı olarak silmek istediğinizden emin misiniz? Bu, klasörleri ve içeriklerini de içerir.",
|
||||
@@ -1422,7 +1422,7 @@
|
||||
"openTerminalInFolder": "Bu klasörde terminali açın.",
|
||||
"openTerminalInFileLocation": "Dosya konumunda terminali açın.",
|
||||
"terminalWithPath": "Terminal - {{host}}:{{path}}",
|
||||
"runningFile": "Koşu - {{file}}",
|
||||
"runningFile": "Koşuyor - {{file}}",
|
||||
"onlyRunExecutableFiles": "Yalnızca çalıştırılabilir dosyaları çalıştırabilir.",
|
||||
"noHostSelected": "Sunucu seçilmedi.",
|
||||
"starred": "Yıldızlı",
|
||||
@@ -1430,9 +1430,9 @@
|
||||
"directories": "Dizinler",
|
||||
"removedFromRecentFiles": "Son dosyalardan \"{{name}}\" kaldırıldı.",
|
||||
"removeFailed": "Kaldırma işlemi başarısız oldu.",
|
||||
"unpinnedSuccessfully": "\"{{name}}\" başarıyla sabitlenmemiş",
|
||||
"unpinnedSuccessfully": "\"{{name}}\" başarıyla sabitlenmiş öğe kaldırıldı",
|
||||
"unpinFailed": "Sabitlemeyi kaldırma başarısız oldu",
|
||||
"removedShortcut": "Kısayol kaldırıldı \"{{name}}\"",
|
||||
"removedShortcut": "\"{{name}}\" kısayolu kaldırıldı",
|
||||
"removeShortcutFailed": "Kısayol kaldırma işlemi başarısız oldu.",
|
||||
"clearedAllRecentFiles": "Son kullanılan tüm dosyalar silindi.",
|
||||
"clearFailed": "Temizleme başarısız oldu",
|
||||
@@ -1440,7 +1440,7 @@
|
||||
"clearAllRecentFiles": "Son kullanılan tüm dosyaları temizle",
|
||||
"unpinFile": "Dosyanın sabitlemesini kaldır",
|
||||
"removeShortcut": "Kısayolu kaldır",
|
||||
"saveFilesToSystem": "{{count}} dosyayı şu şekilde kaydet...",
|
||||
"saveFilesToSystem": "{{count}} dosyaları farklı kaydet...",
|
||||
"pinFile": "Pin dosyası",
|
||||
"addToShortcuts": "Kısayollara ekle",
|
||||
"downloadToDefaultLocation": "Varsayılan konuma indir",
|
||||
@@ -1482,7 +1482,7 @@
|
||||
"moveLineDown": "Satırı Aşağı Taşı",
|
||||
"toggleComment": "Yorumu Aç/Kapat",
|
||||
"indent": "Girinti",
|
||||
"outdent": "Girinti",
|
||||
"outdent": "Çıkıntı",
|
||||
"autoComplete": "Otomatik Tamamlama",
|
||||
"imageLoadError": "Görüntü yüklenemedi.",
|
||||
"rotate": "Döndür",
|
||||
@@ -1497,27 +1497,27 @@
|
||||
"serverErrorOccurred": "Sunucu hatası oluştu. Lütfen daha sonra tekrar deneyin.",
|
||||
"autoSaveFailed": "Otomatik kaydetme başarısız oldu.",
|
||||
"fileAutoSaved": "Dosya otomatik olarak kaydedildi",
|
||||
"moveFileFailed": "{{name}} taşınamadı",
|
||||
"moveFileFailed": "{{name}}taşınamadı",
|
||||
"moveOperationFailed": "Taşıma işlemi başarısız oldu",
|
||||
"canOnlyCompareFiles": "Yalnızca iki dosya karşılaştırılabilir.",
|
||||
"comparingFiles": "Dosyalar karşılaştırılıyor: {{file1}} ve {{file2}}",
|
||||
"comparingFiles": "Dosyaları karşılaştırma: {{file1}} ve {{file2}}",
|
||||
"dragFailed": "Sürükleme işlemi başarısız oldu",
|
||||
"filePinnedSuccessfully": "\"{{name}}\" dosyası başarıyla sabitlendi.",
|
||||
"filePinnedSuccessfully": "\"{{name}}\" dosyası başarıyla sabitlendi",
|
||||
"pinFileFailed": "Dosyayı sabitleme başarısız oldu.",
|
||||
"fileUnpinnedSuccessfully": "\"{{name}}\" dosyası başarıyla sabitlenmeden kaldırıldı.",
|
||||
"fileUnpinnedSuccessfully": "\"{{name}}\" dosyasının sabitlemesi başarıyla kaldırıldı.",
|
||||
"unpinFileFailed": "Dosyanın sabitlemesi kaldırılamadı.",
|
||||
"shortcutAddedSuccessfully": "Klasör kısayolu \"{{name}}\" başarıyla eklendi.",
|
||||
"shortcutAddedSuccessfully": "Klasör kısayolu \"{{name}}\" başarıyla eklendi",
|
||||
"addShortcutFailed": "Kısayol ekleme başarısız oldu.",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} öğe başarıyla",
|
||||
"operationCompleted": "{{operation}} {{count}} öğe",
|
||||
"downloadFileSuccess": "{{name}} numaralı dosya başarıyla indirildi.",
|
||||
"operationCompleted": "{{operation}} {{count}} öğeler",
|
||||
"downloadFileSuccess": "{{name}} dosyası başarıyla indirildi.",
|
||||
"downloadFileFailed": "İndirme başarısız oldu",
|
||||
"moveTo": "{{name}}'e geçin",
|
||||
"diffCompareWith": "{{name}} ile karşılaştırın",
|
||||
"moveTo": "{{name}}adresine geçin",
|
||||
"diffCompareWith": "{{name}}ile karşılaştırın",
|
||||
"dragOutsideToDownload": "İndirmek için pencerenin dışına sürükleyin ({{count}} dosya)",
|
||||
"newFolderDefault": "YeniKlasör",
|
||||
"newFileDefault": "YeniDosya.txt",
|
||||
"successfullyMovedItems": "{{count}} öğe başarıyla {{target}} konumuna taşındı.",
|
||||
"successfullyMovedItems": "{{count}} öğe başarıyla {{target}}konumuna taşındı.",
|
||||
"move": "Taşınmak",
|
||||
"searchInFile": "Dosyada arama yap (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "Klavye kısayollarını göster",
|
||||
@@ -1527,7 +1527,7 @@
|
||||
"compare": "Karşılaştırmak",
|
||||
"sideBySide": "Yan yana",
|
||||
"inline": "Çizgide",
|
||||
"fileComparison": "Dosya Karşılaştırması: {{file1}} ile {{file2}}",
|
||||
"fileComparison": "Dosya Karşılaştırması: {{file1}} ve {{file2}}",
|
||||
"fileTooLarge": "Dosya çok büyük: {{error}}",
|
||||
"sshConnectionFailed": "SSH bağlantısı başarısız oldu. Lütfen {{name}} ({{ip}}:{{port}}) adresine olan bağlantınızı kontrol edin.",
|
||||
"loadFileFailed": "Dosya yüklenemedi: {{error}}",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "Bağlantıyı kes",
|
||||
"cancel": "İptal etmek",
|
||||
"port": "Liman",
|
||||
"attempt": "{{current}}'in {{max}} numaralı denemesi",
|
||||
"attempt": "{{max}}'in {{current}} denemesi",
|
||||
"nextRetryIn": "Sonraki deneme {{seconds}} saniye sonra",
|
||||
"checkDockerLogs": "Hata nedenini öğrenmek için Docker günlüklerinizi kontrol edin, katılın.",
|
||||
"orCreate": "veya bir oluşturun",
|
||||
"orCreate": "veya bir oluşturun ",
|
||||
"noTunnelConnections": "Tünel bağlantısı yapılandırılmamış.",
|
||||
"tunnelConnections": "Tünel Bağlantıları",
|
||||
"addTunnel": "Tünel Ekle",
|
||||
@@ -1589,7 +1589,7 @@
|
||||
"autoStart": "Otomatik Başlatma",
|
||||
"status": "Durum",
|
||||
"active": "Aktif",
|
||||
"inactive": "Etkin değil",
|
||||
"inactive": "Aktif değil",
|
||||
"start": "Başlangıç",
|
||||
"stop": "Durmak",
|
||||
"restart": "Tekrar başlat",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"remote": "Uzak",
|
||||
"dynamic": "Dinamik",
|
||||
"unknownConnectionStatus": "Bilinmiyor",
|
||||
"portMapping": "Liman {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"portMapping": "Port {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"endpointHostNotFound": "Uç nokta ana bilgisayarı bulunamadı.",
|
||||
"discord": "Discord",
|
||||
"githubIssue": "GitHub sorunu",
|
||||
@@ -1650,7 +1650,7 @@
|
||||
"totpInvalidCode": "Geçersiz doğrulama kodu",
|
||||
"totpCancelled": "Ölçüm toplama işlemi iptal edildi",
|
||||
"authenticationFailed": "Kimlik doğrulama başarısız oldu",
|
||||
"noneAuthNotSupported": "Sunucu İstatistikleri, 'none' kimlik doğrulama türünü desteklemiyor.",
|
||||
"noneAuthNotSupported": "Sunucu İstatistikleri 'none' kimlik doğrulama türünü desteklemiyor.",
|
||||
"load": "Yük",
|
||||
"editLayout": "Düzeni Düzenle",
|
||||
"cancelEdit": "İptal etmek",
|
||||
@@ -1678,11 +1678,11 @@
|
||||
"noRecentLoginData": "Son oturum açma verisi yok.",
|
||||
"from": "itibaren",
|
||||
"quickActions": "Hızlı İşlemler",
|
||||
"executeQuickAction": "{{name}}'i yürüt",
|
||||
"executingQuickAction": "{{name}} yürütülüyor...",
|
||||
"executeQuickAction": "{{name}}komutunu yürüt",
|
||||
"executingQuickAction": "{{name}}yürütülüyor...",
|
||||
"quickActionSuccess": "{{name}} başarıyla tamamlandı",
|
||||
"quickActionFailed": "{{name}} başarısız oldu",
|
||||
"quickActionError": "{{name}} yürütülemedi"
|
||||
"quickActionError": "{{name}}yürütülemedi"
|
||||
},
|
||||
"auth": {
|
||||
"tagline": "SSH SUNUCU YÖNETİCİSİ",
|
||||
@@ -1814,8 +1814,8 @@
|
||||
"invalidAuthUrl": "Arka uçtan geçersiz yetkilendirme URL'si alındı.",
|
||||
"invalidInput": "Geçersiz giriş",
|
||||
"requiredField": "Bu alan zorunludur.",
|
||||
"minLength": "Minimum uzunluk {{min}}'tür.",
|
||||
"maxLength": "Maksimum uzunluk {{max}}'tür.",
|
||||
"minLength": "Minimum uzunluk {{min}}",
|
||||
"maxLength": "Maksimum uzunluk {{max}}",
|
||||
"invalidEmail": "Geçersiz e-posta adresi",
|
||||
"passwordMismatch": "Şifreler eşleşmiyor.",
|
||||
"passwordLoginDisabled": "Kullanıcı adı/şifre ile giriş şu anda devre dışı bırakılmıştır.",
|
||||
@@ -1845,7 +1845,7 @@
|
||||
"databaseConnected": "Veritabanı bağlantısı başarıyla kuruldu.",
|
||||
"databaseConnectionFailed": "Veritabanı sunucusuna bağlanılamadı.",
|
||||
"checkServerConnection": "Lütfen sunucu bağlantınızı kontrol edin ve tekrar deneyin.",
|
||||
"resetCodeSent": "Docker günlüklerine gönderilen sıfırlama kodu",
|
||||
"resetCodeSent": "Docker günlüklerine sıfırlama kodu gönderildi.",
|
||||
"codeVerified": "Kod başarıyla doğrulandı.",
|
||||
"passwordResetSuccess": "Parola sıfırlama işlemi başarıyla tamamlandı.",
|
||||
"loginSuccess": "Giriş başarılı",
|
||||
@@ -1880,7 +1880,7 @@
|
||||
"languageLocalization": "Dil ve Yerelleştirme",
|
||||
"fileManagerSettings": "Dosya Yöneticisi",
|
||||
"terminalSettings": "terminal",
|
||||
"hostSidebarSettings": "Sunucu ve Kenar Çubuğu",
|
||||
"hostSidebarSettings": "Sunucu ve Yan Menü",
|
||||
"snippetsSettings": "Kısa bölümler",
|
||||
"currentPassword": "Mevcut Şifre",
|
||||
"passwordChangedSuccess": "Şifre başarıyla değiştirildi! Lütfen tekrar giriş yapın.",
|
||||
@@ -1933,7 +1933,7 @@
|
||||
"searchHostsAny": "Sunucuları ara (deneyin: tag:prod, user:root, ip:192.168)...",
|
||||
"confirmPassword": "Onaylamak için şifrenizi girin.",
|
||||
"typeHere": "Buraya yazın",
|
||||
"fileName": "Dosya adını girin (örneğin, example.txt)",
|
||||
"fileName": "Dosya adını girin (örneğin, example.txt).",
|
||||
"folderName": "Klasör adını girin",
|
||||
"fullPath": "Öğeye giden tam yolu girin.",
|
||||
"currentPath": "Öğeye giden mevcut yolu girin.",
|
||||
@@ -1956,8 +1956,8 @@
|
||||
"failedToDeleteAccount": "Hesap silme işlemi başarısız oldu.",
|
||||
"failedToMakeUserAdmin": "Kullanıcıyı yönetici yapma işlemi başarısız oldu.",
|
||||
"userIsNowAdmin": "Kullanıcı {{username}} artık yöneticidir.",
|
||||
"removeAdminConfirm": "{{username}}'den yönetici statüsünü kaldırmak istediğinizden emin misiniz?",
|
||||
"deleteUserConfirm": "{{username}} kullanıcısını silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"removeAdminConfirm": "{{username}}'dan yönetici statüsünü kaldırmak istediğinizden emin misiniz?",
|
||||
"deleteUserConfirm": "{{username}}kullanıcısını silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"deleteAccount": "Hesabı Sil",
|
||||
"closeDeleteAccount": "Hesabı Kapat Sil",
|
||||
"deleteAccountWarning": "Bu işlem geri alınamaz. Bu, hesabınızı ve ilgili tüm verileri kalıcı olarak silecektir.",
|
||||
@@ -2149,8 +2149,8 @@
|
||||
"lastAccessed": "Son Erişim Tarihi",
|
||||
"accessCount": "Erişim Sayısı",
|
||||
"revokeAccess": "Erişimi İptal Et",
|
||||
"confirmRevokeAccess": "{{username}} kullanıcısının erişimini iptal etmek istediğinizden emin misiniz?",
|
||||
"hostSharedSuccessfully": "Sunucu, {{username}} ile başarıyla paylaşıldı.",
|
||||
"confirmRevokeAccess": "{{username}}için erişimi iptal etmek istediğinizden emin misiniz?",
|
||||
"hostSharedSuccessfully": "Sunucu başarıyla {{username}}ile paylaşıldı.",
|
||||
"hostAccessUpdated": "Sunucu erişimi güncellendi",
|
||||
"failedToShareHost": "Sunucuyu paylaşma başarısız oldu.",
|
||||
"accessRevokedSuccessfully": "Erişim başarıyla iptal edildi.",
|
||||
@@ -2177,16 +2177,16 @@
|
||||
"tempUserRecommended": "Daha iyi güvenlik için 'Geçici Kullanıcı Oluştur' seçeneğini etkinleştirmenizi öneririz.",
|
||||
"roleManagement": "Rol Yönetimi",
|
||||
"manageRoles": "Rolleri Yönet",
|
||||
"manageRolesFor": "{{username}} için rolleri yönetin",
|
||||
"manageRolesFor": "{{username}}için rolleri yönetin",
|
||||
"assignRole": "Rol Ata",
|
||||
"removeRole": "Rolü Kaldır",
|
||||
"userRoles": "Kullanıcı Rolleri",
|
||||
"permissions": "İzinler",
|
||||
"systemRole": "Sistem Rolü",
|
||||
"customRole": "Özel Rol",
|
||||
"roleAssignedSuccessfully": "{{username}}'ye rol başarıyla atandı.",
|
||||
"roleAssignedSuccessfully": "{{username}} 'a rol başarıyla atandı.",
|
||||
"failedToAssignRole": "Rol atama işlemi başarısız oldu.",
|
||||
"roleRemovedSuccessfully": "Rol, {{username}}'den başarıyla kaldırıldı.",
|
||||
"roleRemovedSuccessfully": "{{username}} 'dan rol başarıyla kaldırıldı.",
|
||||
"failedToRemoveRole": "Rolü kaldırma işlemi başarısız oldu.",
|
||||
"cannotRemoveSystemRole": "Sistem rolü kaldırılamıyor.",
|
||||
"cannotShareWithSelf": "Aynı sunucuyu kendinizle paylaşamazsınız.",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "Oturumu Sonlandır",
|
||||
"sessionTerminated": "Oturum sunucu sahibi tarafından sonlandırıldı.",
|
||||
"sharedAccessExpired": "Bu sunucuya olan paylaşımlı erişiminizin süresi doldu.",
|
||||
"sharedAccessExpiresIn": "Paylaşımlı erişim {{hours}} saat sonra sona eriyor",
|
||||
"sharedAccessExpiresIn": "Paylaşımlı erişim {{hours}} saat sonra sona eriyor.",
|
||||
"roles": {
|
||||
"label": "Roller",
|
||||
"admin": "Yönetici",
|
||||
@@ -2310,16 +2310,16 @@
|
||||
"errorCode": "Hata kodu: {{code}}",
|
||||
"version": "Docker {{version}}",
|
||||
"containerStarted": "Konteyner {{name}} başlatıldı",
|
||||
"failedToStartContainer": "{{name}} konteynerini başlatma başarısız oldu.",
|
||||
"containerStopped": "Konteyner {{name}} durdu",
|
||||
"failedToStopContainer": "{{name}} numaralı konteyneri durdurma işlemi başarısız oldu.",
|
||||
"failedToStartContainer": "{{name}}kapsayıcısı başlatılamadı.",
|
||||
"containerStopped": "Konteyner {{name}} durduruldu",
|
||||
"failedToStopContainer": "{{name}}kapsayıcısını durdurma başarısız oldu.",
|
||||
"containerRestarted": "Konteyner {{name}} yeniden başlatıldı",
|
||||
"failedToRestartContainer": "{{name}} numaralı konteyneri yeniden başlatma başarısız oldu.",
|
||||
"failedToRestartContainer": "{{name}}kapsayıcısını yeniden başlatma başarısız oldu.",
|
||||
"containerPaused": "Konteyner {{name}} duraklatıldı",
|
||||
"containerUnpaused": "Konteyner {{name}} duraklatılmadı",
|
||||
"failedToTogglePauseContainer": "{{name}} numaralı kapsayıcı için duraklatma durumunu değiştirme işlemi başarısız oldu.",
|
||||
"containerUnpaused": "Konteyner {{name}} duraklatılmamış",
|
||||
"failedToTogglePauseContainer": "{{name}}kapsayıcısı için duraklatma durumunu değiştirme başarısız oldu.",
|
||||
"containerRemoved": "Konteyner {{name}} kaldırıldı",
|
||||
"failedToRemoveContainer": "{{name}} numaralı konteyneri kaldırma işlemi başarısız oldu.",
|
||||
"failedToRemoveContainer": "{{name}}kapsayıcısını kaldırma işlemi başarısız oldu.",
|
||||
"image": "Görüntü",
|
||||
"idLabel": "İD",
|
||||
"ports": "Limanlar",
|
||||
@@ -2332,7 +2332,7 @@
|
||||
"restart": "Tekrar başlat",
|
||||
"remove": "Kaldırmak",
|
||||
"removeContainer": "Kabı çıkarın",
|
||||
"confirmRemoveContainer": "\"{{name}}\" konteynerini kaldırmak istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"confirmRemoveContainer": "'{{name}}' kapsayıcısını kaldırmak istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"runningContainerWarning": "Uyarı: Bu konteyner şu anda çalışıyor. Kaldırılması durumunda konteyner önce durdurulacaktır.",
|
||||
"removing": "Kaldırılıyor...",
|
||||
"loadingContainers": "Konteynerler yükleniyor...",
|
||||
@@ -2372,7 +2372,7 @@
|
||||
"authenticationRequired": "Kimlik doğrulama gereklidir.",
|
||||
"verificationCodePrompt": "Doğrulama kodunu girin",
|
||||
"totpVerificationFailed": "TOTP doğrulaması başarısız oldu. Lütfen tekrar deneyin.",
|
||||
"connectedTo": "{{containerName}} ile bağlantılı",
|
||||
"connectedTo": "{{containerName}}ile bağlantılı",
|
||||
"disconnected": "Bağlantı kesildi",
|
||||
"consoleError": "Konsol hatası",
|
||||
"errorMessage": "Hata: {{message}}",
|
||||
@@ -2387,7 +2387,7 @@
|
||||
"disconnect": "Bağlantıyı kes",
|
||||
"notConnected": "Bağlı değil",
|
||||
"clickToConnect": "Kabuk oturumu başlatmak için bağlan'a tıklayın.",
|
||||
"connectingTo": "{{containerName}}'ye bağlanılıyor...",
|
||||
"connectingTo": "{{containerName}}ile bağlantı kuruluyor...",
|
||||
"containerNotFound": "Konteyner bulunamadı.",
|
||||
"backToList": "Listeye geri dön",
|
||||
"logs": "Günlükler",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "Işığa geç",
|
||||
"switchToDark": "Koyu moda geç"
|
||||
}
|
||||
}
|
||||
}
|
||||
2402
src/locales/translated/uk.json
Normal file
2402
src/locales/translated/uk.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@
|
||||
"failedToFetchCredentials": "Không thể tải thông tin đăng nhập",
|
||||
"credentialDeletedSuccessfully": "Thông tin đăng nhập đã được xóa thành công.",
|
||||
"failedToDeleteCredential": "Không thể xóa thông tin đăng nhập",
|
||||
"confirmDeleteCredential": "Bạn có chắc chắn muốn xóa thông tin xác thực \"{{name}}\" không?",
|
||||
"confirmDeleteCredential": "Bạn có chắc chắn muốn xóa thông tin đăng nhập \"{{name}}\" không?",
|
||||
"credentialCreatedSuccessfully": "Thông tin xác thực đã được tạo thành công",
|
||||
"credentialUpdatedSuccessfully": "Thông tin đăng nhập đã được cập nhật thành công.",
|
||||
"failedToSaveCredential": "Không thể lưu thông tin đăng nhập",
|
||||
@@ -43,7 +43,7 @@
|
||||
"refresh": "Làm cho khỏe lại",
|
||||
"passwordRequired": "Cần có mật khẩu.",
|
||||
"sshKeyRequired": "Cần có khóa SSH.",
|
||||
"credentialAddedSuccessfully": "Thông tin xác thực \"{{name}}\" đã được thêm thành công.",
|
||||
"credentialAddedSuccessfully": "Thông tin xác thực \"{{name}}\" đã được thêm thành công",
|
||||
"general": "Tổng quan",
|
||||
"description": "Sự miêu tả",
|
||||
"folder": "Thư mục",
|
||||
@@ -128,7 +128,7 @@
|
||||
"created": "Tạo",
|
||||
"lastModified": "Lần sửa đổi cuối cùng",
|
||||
"usageStatistics": "Thống kê sử dụng",
|
||||
"copiedToClipboard": "{{field}} đã được sao chép vào clipboard",
|
||||
"copiedToClipboard": "{{field}} đã sao chép vào clipboard",
|
||||
"failedToCopy": "Không thể sao chép vào clipboard",
|
||||
"sshKey": "Khóa SSH",
|
||||
"createCredentialDescription": "Tạo thông tin đăng nhập SSH mới để truy cập an toàn.",
|
||||
@@ -137,11 +137,11 @@
|
||||
"folderView": "Thư mục",
|
||||
"unknownCredential": "Không rõ",
|
||||
"confirmRemoveFromFolder": "Bạn có chắc chắn muốn xóa \"{{name}}\" khỏi thư mục \"{{folder}}\" không? Thông tin đăng nhập sẽ được chuyển đến thư mục \"Chưa được phân loại\".",
|
||||
"removedFromFolder": "Thông tin xác thực \"{{name}}\" đã được xóa khỏi thư mục thành công.",
|
||||
"removedFromFolder": "Thông tin xác thực \"{{name}}\" đã được xóa khỏi thư mục thành công",
|
||||
"failedToRemoveFromFolder": "Không thể xóa thông tin đăng nhập khỏi thư mục.",
|
||||
"folderRenamed": "Thư mục \"{{oldName}}\" đã được đổi tên thành \"{{newName}}\" thành công.",
|
||||
"folderRenamed": "Thư mục \"{{oldName}}\" đã được đổi tên thành \"{{newName}}\" thành công",
|
||||
"failedToRenameFolder": "Không thể đổi tên thư mục.",
|
||||
"movedToFolder": "Thông tin xác thực \"{{name}}\" đã được chuyển sang \"{{folder}}\" thành công.",
|
||||
"movedToFolder": "Thông tin xác thực \"{{name}}\" đã được chuyển thành công sang \"{{folder}}\"",
|
||||
"failedToMoveToFolder": "Không thể chuyển thông tin đăng nhập vào thư mục.",
|
||||
"sshPublicKey": "Khóa công khai SSH",
|
||||
"publicKeyNote": "Khóa công khai là tùy chọn nhưng được khuyến nghị để xác thực khóa.",
|
||||
@@ -166,7 +166,7 @@
|
||||
"keyTypeDsa": "DSA (SSH)",
|
||||
"keyTypeRsaSha256": "RSA-SHA2-256",
|
||||
"keyTypeRsaSha512": "RSA-SHA2-512",
|
||||
"keyPairGeneratedSuccessfully": "Cặp khóa {{keyType}} được tạo thành công",
|
||||
"keyPairGeneratedSuccessfully": "Cặp khóa {{keyType}} đã được tạo thành công",
|
||||
"failedToGenerateKeyPair": "Không thể tạo cặp khóa",
|
||||
"generateKeyPairNote": "Tạo cặp khóa SSH mới trực tiếp. Thao tác này sẽ thay thế mọi khóa hiện có.",
|
||||
"invalidKey": "Khóa không hợp lệ",
|
||||
@@ -187,9 +187,9 @@
|
||||
"dragIndicator": {
|
||||
"error": "Lỗi: {{error}}",
|
||||
"dragging": "Kéo {{fileName}}",
|
||||
"preparing": "Chuẩn bị {{fileName}}",
|
||||
"preparing": "Đang chuẩn bị {{fileName}}",
|
||||
"readySingle": "Sẵn sàng tải xuống {{fileName}}",
|
||||
"readyMultiple": "Sẵn sàng tải xuống {{count}} tệp",
|
||||
"readyMultiple": "Sẵn sàng tải xuống các tệp {{count}}",
|
||||
"batchDrag": "Kéo {{count}} tập tin ra màn hình nền",
|
||||
"dragToDesktop": "Kéo vào màn hình nền",
|
||||
"canDragAnywhere": "Bạn có thể kéo thả các tập tin đến bất kỳ vị trí nào trên màn hình máy tính."
|
||||
@@ -205,9 +205,9 @@
|
||||
"commandsWillBeSent": "Các lệnh sẽ được gửi đến {{count}} thiết bị đầu cuối đã chọn.",
|
||||
"settings": "Cài đặt",
|
||||
"enableRightClickCopyPaste": "Cho phép sao chép/dán bằng chuột phải.",
|
||||
"shareIdeas": "Bạn có ý tưởng nào về những tính năng tiếp theo cho các công cụ SSH không? Hãy chia sẻ chúng trên",
|
||||
"shareIdeas": "Bạn có ý tưởng nào về những tính năng tiếp theo cho các công cụ SSH không? Hãy chia sẻ chúng trên đây!",
|
||||
"scripts": {
|
||||
"inputPlaceholder": "Ví dụ: Lệnh hệ thống, Tập lệnh Docker"
|
||||
"inputPlaceholder": "Ví dụ: Lệnh hệ thống, tập lệnh Docker"
|
||||
}
|
||||
},
|
||||
"snippets": {
|
||||
@@ -248,7 +248,7 @@
|
||||
"reorderSameFolder": "Chỉ có thể sắp xếp lại các đoạn mã trong cùng một thư mục.",
|
||||
"reorderSuccess": "Các đoạn trích đã được sắp xếp lại thành công",
|
||||
"reorderFailed": "Không thể sắp xếp lại các đoạn mã.",
|
||||
"deleteFolderConfirm": "Xóa thư mục \"{{name}}\"? Tất cả các đoạn trích sẽ được chuyển đến thư mục Chưa được phân loại.",
|
||||
"deleteFolderConfirm": "Xóa thư mục \"{{name}}\"? Tất cả các đoạn mã sẽ được chuyển đến thư mục Chưa được phân loại.",
|
||||
"deleteFolderSuccess": "Thư mục đã được xóa thành công",
|
||||
"deleteFolderFailed": "Không thể xóa thư mục",
|
||||
"updateFolderSuccess": "Thư mục đã được cập nhật thành công.",
|
||||
@@ -308,7 +308,7 @@
|
||||
"cleared": "Màn hình chia đôi đã được xóa",
|
||||
"error": {
|
||||
"noAssignments": "Vui lòng chỉ định ít nhất một tab cho bố cục.",
|
||||
"fillAllSlots": "Vui lòng điền đầy đủ {{count}} ô trước khi nộp đơn."
|
||||
"fillAllSlots": "Vui lòng điền đầy đủ tất cả {{count}} ô trước khi ứng tuyển."
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
@@ -346,7 +346,7 @@
|
||||
"currentVersion": "Bạn đang sử dụng phiên bản {{version}}",
|
||||
"updateAvailable": "Đã có bản cập nhật",
|
||||
"newVersionAvailable": "Phiên bản mới đã có sẵn! Bạn đang sử dụng {{current}}, nhưng {{latest}} đã có sẵn.",
|
||||
"releasedOn": "Phát hành vào ngày {{date}}",
|
||||
"releasedOn": "Phát hành vào {{date}}",
|
||||
"downloadUpdate": "Tải xuống bản cập nhật",
|
||||
"dismiss": "Miễn nhiệm",
|
||||
"checking": "Đang kiểm tra cập nhật...",
|
||||
@@ -508,8 +508,8 @@
|
||||
"tokenUrl": "URL mã thông báo",
|
||||
"updateSettings": "Cập nhật cài đặt",
|
||||
"confirmDelete": "Bạn có chắc chắn muốn xóa người dùng này không?",
|
||||
"confirmMakeAdmin": "Bạn có chắc chắn muốn đặt {{username}} làm quản trị viên không?",
|
||||
"confirmRemoveAdmin": "Bạn có chắc chắn muốn xóa quyền quản trị khỏi {{username}} không?",
|
||||
"confirmMakeAdmin": "Bạn có chắc chắn muốn phong {{username}} làm quản trị viên không?",
|
||||
"confirmRemoveAdmin": "Bạn có chắc chắn muốn xóa quyền quản trị khỏi {{username}}không?",
|
||||
"externalAuthentication": "Xác thực bên ngoài (OIDC)",
|
||||
"configureExternalProvider": "Cấu hình nhà cung cấp định danh bên ngoài cho xác thực OIDC/OAuth2.",
|
||||
"userIdentifierPath": "Đường dẫn định danh người dùng",
|
||||
@@ -546,10 +546,10 @@
|
||||
"oidcConfigurationDisabled": "Cấu hình OIDC đã bị vô hiệu hóa thành công!",
|
||||
"failedToUpdateOidcConfig": "Không thể cập nhật cấu hình OIDC.",
|
||||
"failedToDisableOidcConfig": "Không thể vô hiệu hóa cấu hình OIDC.",
|
||||
"enterUsernameToMakeAdmin": "Nhập tên người dùng để trở thành quản trị viên",
|
||||
"enterUsernameToMakeAdmin": "Nhập tên người dùng để trở thành quản trị viên.",
|
||||
"userIsNowAdmin": "Người dùng {{username}} hiện là quản trị viên",
|
||||
"failedToMakeUserAdmin": "Không thể cấp quyền quản trị cho người dùng.",
|
||||
"removeAdminStatus": "Xóa trạng thái quản trị viên khỏi {{username}}?",
|
||||
"removeAdminStatus": "Xóa quyền quản trị khỏi {{username}}?",
|
||||
"adminStatusRemoved": "Trạng thái quản trị viên đã bị xóa khỏi {{username}}",
|
||||
"failedToRemoveAdminStatus": "Không thể xóa trạng thái quản trị viên.",
|
||||
"userDeletedSuccessfully": "Người dùng {{username}} đã bị xóa thành công",
|
||||
@@ -615,7 +615,7 @@
|
||||
"failedToLinkAccounts": "Không thể liên kết tài khoản",
|
||||
"linkTargetUsernameRequired": "Tên người dùng mục tiêu là bắt buộc",
|
||||
"unlinkOIDCTitle": "Hủy liên kết xác thực OIDC",
|
||||
"unlinkOIDCDescription": "Xóa xác thực OIDC khỏi {{username}}? Sau đó, người dùng chỉ có thể đăng nhập bằng tên người dùng/mật khẩu.",
|
||||
"unlinkOIDCDescription": "Xóa xác thực OIDC khỏi {{username}}? Sau thao tác này, người dùng chỉ có thể đăng nhập bằng tên người dùng/mật khẩu.",
|
||||
"unlinkOIDCSuccess": "OIDC đã bị ngắt kết nối khỏi {{username}}",
|
||||
"failedToUnlinkOIDC": "Không thể hủy liên kết OIDC",
|
||||
"databaseSecurity": "Bảo mật cơ sở dữ liệu",
|
||||
@@ -661,7 +661,7 @@
|
||||
"loadingEncryptionStatus": "Đang tải trạng thái mã hóa...",
|
||||
"testMigrationDescription": "Xác minh rằng dữ liệu hiện có có thể được chuyển đổi an toàn sang định dạng mã hóa mà không cần sửa đổi bất kỳ dữ liệu nào.",
|
||||
"serverMigrationGuide": "Hướng dẫn di chuyển máy chủ",
|
||||
"migrationInstructions": "Để di chuyển dữ liệu được mã hóa sang máy chủ mới: 1) Sao lưu các tệp cơ sở dữ liệu, 2) Đặt biến môi trường DB_ENCRYPTION_KEY=\"your-key\" trên máy chủ mới, 3) Khôi phục các tệp cơ sở dữ liệu.",
|
||||
"migrationInstructions": "Để di chuyển dữ liệu được mã hóa sang máy chủ mới: 1) Sao lưu các tệp cơ sở dữ liệu, 2) Đặt biến môi trường DB_ENCRYPTION_KEY=\"khóa của bạn\" trên máy chủ mới, 3) Khôi phục các tệp cơ sở dữ liệu.",
|
||||
"environmentProtection": "Bảo vệ môi trường",
|
||||
"environmentProtectionDesc": "Bảo vệ các khóa mã hóa dựa trên thông tin môi trường máy chủ (tên máy chủ, đường dẫn, v.v.), có thể di chuyển thông qua các biến môi trường.",
|
||||
"verificationCompleted": "Quá trình xác minh tính tương thích đã hoàn tất - không có dữ liệu nào bị thay đổi.",
|
||||
@@ -684,7 +684,7 @@
|
||||
"bothFieldAndFileEncryptionActive": "Cả mã hóa cấp trường và cấp tệp hiện đều được kích hoạt để đảm bảo an ninh tối đa.",
|
||||
"fieldLevelAes256Encryption": "Mã hóa AES-256 cấp trường cho dữ liệu nhạy cảm",
|
||||
"fileLevelDatabaseEncryption": "Mã hóa cơ sở dữ liệu cấp độ tệp với liên kết phần cứng",
|
||||
"hardwareBoundFileKeys": "Khóa mã hóa tập tin gắn liền với phần cứng",
|
||||
"hardwareBoundFileKeys": "Khóa mã hóa tệp tin gắn liền với phần cứng",
|
||||
"automaticEncryptedBackups": "Tạo bản sao lưu được mã hóa tự động",
|
||||
"createEncryptedBackup": "Tạo bản sao lưu được mã hóa",
|
||||
"creatingBackup": "Đang tạo bản sao lưu...",
|
||||
@@ -741,7 +741,7 @@
|
||||
"confirmDisablePasswordLogin": "Bạn có chắc chắn muốn vô hiệu hóa đăng nhập bằng mật khẩu không? Hãy đảm bảo rằng OIDC đã được cấu hình đúng cách và hoạt động bình thường trước khi tiếp tục, nếu không bạn sẽ mất quyền truy cập vào phiên bản Termix của mình.",
|
||||
"passwordLoginDisabled": "Đăng nhập bằng mật khẩu đã bị vô hiệu hóa thành công.",
|
||||
"passwordLoginAndRegistrationDisabled": "Đăng nhập bằng mật khẩu và đăng ký tài khoản mới đã bị vô hiệu hóa thành công.",
|
||||
"requiresPasswordLogin": "Yêu cầu đăng nhập bằng mật khẩu.",
|
||||
"requiresPasswordLogin": "Yêu cầu bật đăng nhập bằng mật khẩu.",
|
||||
"passwordLoginDisabledWarning": "Chức năng đăng nhập bằng mật khẩu đã bị vô hiệu hóa. Hãy đảm bảo OIDC được cấu hình đúng cách, nếu không bạn sẽ không thể đăng nhập vào Termix.",
|
||||
"oidcRequiredWarning": "QUAN TRỌNG: Chức năng đăng nhập bằng mật khẩu đã bị vô hiệu hóa. Nếu bạn đặt lại hoặc cấu hình sai OIDC, bạn sẽ mất toàn bộ quyền truy cập vào Termix và làm hỏng phiên bản của mình. Chỉ tiếp tục nếu bạn hoàn toàn chắc chắn.",
|
||||
"confirmDisableOIDCWarning": "CẢNH BÁO: Bạn sắp vô hiệu hóa OIDC trong khi đăng nhập bằng mật khẩu cũng bị vô hiệu hóa. Điều này sẽ làm hỏng hệ thống Termix của bạn và bạn sẽ mất toàn bộ quyền truy cập. Bạn có hoàn toàn chắc chắn muốn tiếp tục không?",
|
||||
@@ -837,7 +837,7 @@
|
||||
"connection": "Sự liên quan",
|
||||
"remove": "Di dời",
|
||||
"sourcePort": "Cổng nguồn",
|
||||
"sourcePortDesc": "(Nguồn tham khảo là Chi tiết kết nối hiện tại trong tab Chung)",
|
||||
"sourcePortDesc": " (Nguồn tham khảo là Chi tiết kết nối hiện tại trong tab Chung)",
|
||||
"endpointPort": "Cổng điểm cuối",
|
||||
"endpointSshConfig": "Cấu hình SSH điểm cuối",
|
||||
"tunnelForwardDescription": "Đường hầm này sẽ chuyển tiếp lưu lượng truy cập từ cổng {{sourcePort}} trên máy nguồn (chi tiết kết nối hiện tại trong tab chung) đến cổng {{endpointPort}} trên máy đích.",
|
||||
@@ -917,9 +917,9 @@
|
||||
"shutdownCommand": "Lệnh tắt máy",
|
||||
"rebootCommand": "Lệnh khởi động lại",
|
||||
"confirmRemoveFromFolder": "Bạn có chắc chắn muốn xóa \"{{name}}\" khỏi thư mục \"{{folder}}\" không? Máy chủ sẽ được chuyển đến \"Không có thư mục\".",
|
||||
"removedFromFolder": "Máy chủ \"{{name}}\" đã được xóa khỏi thư mục thành công.",
|
||||
"removedFromFolder": "Máy chủ \"{{name}}\" đã được xóa khỏi thư mục thành công",
|
||||
"failedToRemoveFromFolder": "Không thể xóa máy chủ khỏi thư mục.",
|
||||
"folderRenamed": "Thư mục \"{{oldName}}\" đã được đổi tên thành \"{{newName}}\" thành công.",
|
||||
"folderRenamed": "Thư mục \"{{oldName}}\" đã được đổi tên thành \"{{newName}}\" thành công",
|
||||
"failedToRenameFolder": "Không thể đổi tên thư mục.",
|
||||
"editFolderAppearance": "Chỉnh sửa giao diện thư mục",
|
||||
"editFolderAppearanceDesc": "Tùy chỉnh màu sắc và biểu tượng cho thư mục",
|
||||
@@ -929,23 +929,23 @@
|
||||
"folderAppearanceUpdated": "Giao diện thư mục đã được cập nhật thành công.",
|
||||
"failedToUpdateFolderAppearance": "Không thể cập nhật giao diện thư mục.",
|
||||
"deleteAllHostsInFolder": "Xóa tất cả máy chủ trong thư mục",
|
||||
"confirmDeleteAllHostsInFolder": "Bạn có chắc chắn muốn xóa tất cả {{count}} máy chủ trong thư mục \"{{folder}}\" không? Hành động này không thể hoàn tác.",
|
||||
"allHostsInFolderDeleted": "Đã xóa thành công {{count}} máy chủ khỏi thư mục \"{{folder}}\".",
|
||||
"confirmDeleteAllHostsInFolder": "Bạn có chắc chắn muốn xóa tất cả các máy chủ {{count}} trong thư mục \"{{folder}}\" không? Hành động này không thể hoàn tác.",
|
||||
"allHostsInFolderDeleted": "Đã xóa {{count}} máy chủ khỏi thư mục \"{{folder}}\" thành công",
|
||||
"failedToDeleteHostsInFolder": "Không thể xóa các máy chủ trong thư mục.",
|
||||
"movedToFolder": "Máy chủ \"{{name}}\" đã được chuyển sang \"{{folder}}\" thành công.",
|
||||
"movedToFolder": "Máy chủ \"{{name}}\" đã được chuyển đến \"{{folder}}\" thành công",
|
||||
"failedToMoveToFolder": "Không thể di chuyển máy chủ vào thư mục.",
|
||||
"clickToRenameFolder": "Nhấp chuột để đổi tên thư mục",
|
||||
"renameFolder": "Đổi tên thư mục",
|
||||
"removeFromFolder": "Xóa khỏi thư mục \"{{folder}}\"",
|
||||
"editHostTooltip": "Chỉnh sửa máy chủ",
|
||||
"deleteHostTooltip": "Xóa máy chủ",
|
||||
"exportHostTooltip": "Máy chủ xuất",
|
||||
"exportHostTooltip": "Máy chủ xuất khẩu",
|
||||
"cloneHostTooltip": "Máy chủ nhân bản",
|
||||
"clickToEditHost": "Nhấp chuột để chỉnh sửa máy chủ",
|
||||
"dragToMoveBetweenFolders": "Kéo để di chuyển giữa các thư mục",
|
||||
"exportedHostConfig": "Đã xuất cấu hình máy chủ cho {{name}}",
|
||||
"openTerminal": "Mở thiết bị đầu cuối",
|
||||
"openFileManager": "Mở Trình quản lý tệp",
|
||||
"openFileManager": "Mở trình quản lý tệp",
|
||||
"openTunnels": "Đường hầm mở",
|
||||
"openServerDetails": "Chi tiết máy chủ mở",
|
||||
"statistics": "Thống kê",
|
||||
@@ -985,7 +985,7 @@
|
||||
"fontSizeValue": "Kích thước phông chữ: {{value}}px",
|
||||
"adjustFontSize": "Điều chỉnh kích thước phông chữ của cửa sổ terminal",
|
||||
"letterSpacing": "Khoảng cách giữa các chữ",
|
||||
"letterSpacingValue": "Khoảng cách giữa các chữ: {{value}}px",
|
||||
"letterSpacingValue": "Khoảng cách giữa các chữ cái: {{value}}px",
|
||||
"adjustLetterSpacing": "Điều chỉnh khoảng cách giữa các ký tự",
|
||||
"lineHeight": "Chiều cao dòng",
|
||||
"lineHeightValue": "Chiều cao dòng: {{value}}",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
"bellStyleSound": "Âm thanh",
|
||||
"bellStyleVisual": "Thị giác",
|
||||
"bellStyleBoth": "Cả hai",
|
||||
"bellStyleDesc": "Cách xử lý tín hiệu chuông của thiết bị đầu cuối (ký tự BEL, \\x07). Các chương trình kích hoạt tín hiệu này khi hoàn thành tác vụ, gặp lỗi hoặc để thông báo. \"Âm thanh\" phát ra tiếng bíp, \"Hình ảnh\" nhấp nháy màn hình trong giây lát, \"Cả hai\" thực hiện cả hai, \"Không\" tắt cảnh báo chuông.",
|
||||
"bellStyleDesc": "Cách xử lý tín hiệu chuông của thiết bị đầu cuối (ký tự BEL, \\x07). Các chương trình kích hoạt tín hiệu này khi hoàn thành tác vụ, gặp lỗi hoặc để nhận thông báo. \"Âm thanh\" phát ra tiếng bíp, \"Hình ảnh\" nhấp nháy màn hình trong giây lát, \"Cả hai\" thực hiện cả hai, \"Không\" tắt cảnh báo chuông.",
|
||||
"rightClickSelectsWord": "Nhấp chuột phải chọn Word",
|
||||
"rightClickSelectsWordDesc": "Nhấp chuột phải sẽ chọn từ nằm dưới con trỏ.",
|
||||
"fastScrollModifier": "Bộ điều chỉnh cuộn nhanh",
|
||||
@@ -1041,7 +1041,7 @@
|
||||
"overrideCredentialUsername": "Ghi đè tên người dùng xác thực",
|
||||
"overrideCredentialUsernameDesc": "Hãy sử dụng tên người dùng khác với tên người dùng đã lưu trong thông tin đăng nhập. Điều này cho phép bạn sử dụng cùng một thông tin đăng nhập với các tên người dùng khác nhau.",
|
||||
"jumpHosts": "Người dẫn chương trình nhảy",
|
||||
"jumpHostsDescription": "Máy chủ trung gian (còn được gọi là máy chủ bảo vệ) cho phép bạn kết nối đến máy chủ đích thông qua một hoặc nhiều máy chủ trung gian. Điều này rất hữu ích khi truy cập các máy chủ nằm sau tường lửa hoặc trong mạng riêng.",
|
||||
"jumpHostsDescription": "Máy chủ trung gian (còn được gọi là máy chủ bảo vệ) cho phép bạn kết nối đến máy chủ mục tiêu thông qua một hoặc nhiều máy chủ trung gian. Điều này hữu ích khi truy cập các máy chủ nằm sau tường lửa hoặc trong mạng riêng.",
|
||||
"jumpHostChain": "Chuỗi máy chủ nhảy",
|
||||
"addJumpHost": "Thêm Jump Host",
|
||||
"selectServer": "Chọn máy chủ",
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"socks5PresetCreated": "Chuỗi proxy được thiết lập sẵn",
|
||||
"socks5PresetUpdated": "Cài đặt sẵn chuỗi proxy đã được cập nhật",
|
||||
"socks5PresetDeleted": "Chuỗi proxy đã bị xóa cài đặt sẵn",
|
||||
"socks5PresetSaved": "Cài đặt sẵn \"{{name}}\" đã được lưu thành công.",
|
||||
"socks5PresetSaved": "Cài đặt sẵn \"{{name}}\" đã được lưu thành công",
|
||||
"socks5PresetSaveError": "Không thể lưu cài đặt trước",
|
||||
"socks5PresetNameRequired": "Tên cài đặt sẵn là bắt buộc",
|
||||
"socks5EmptyChainError": "Không thể lưu chuỗi proxy trống.",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"socks5HostDescription": "Tên máy chủ hoặc địa chỉ IP của máy chủ proxy SOCKS",
|
||||
"socks5PortDescription": "Số cổng của máy chủ proxy SOCKS (mặc định: 1080)",
|
||||
"addProxyNode": "Thêm nút Proxy",
|
||||
"noProxyNodes": "Chưa có nút proxy nào được cấu hình. Nhấp vào \"Thêm nút Proxy\" để thêm một nút.",
|
||||
"noProxyNodes": "Chưa có nút proxy nào được cấu hình. Nhấp vào 'Thêm nút Proxy' để thêm một nút.",
|
||||
"proxyNode": "Nút ủy quyền",
|
||||
"proxyType": "Loại Proxy",
|
||||
"quickActions": "Thao tác nhanh",
|
||||
@@ -1103,7 +1103,7 @@
|
||||
"sudoPasswordDesc": "Mật khẩu tùy chọn cho các lệnh sudo (hữu ích khi xác thực bằng khóa)",
|
||||
"socks4": "TẤT 4",
|
||||
"socks5": "TẤT 5",
|
||||
"executeSnippetOnConnect": "Thực thi đoạn mã khi thiết bị đầu cuối kết nối.",
|
||||
"executeSnippetOnConnect": "Thực thi đoạn mã khi thiết bị đầu cuối được kết nối.",
|
||||
"autoMosh": "Auto-MOSH",
|
||||
"autoMoshDesc": "Tự động chạy lệnh MOSH khi kết nối",
|
||||
"moshCommand": "Bộ chỉ huy MOSH",
|
||||
@@ -1167,11 +1167,11 @@
|
||||
"failedToStopContainer": "Không thể dừng container: {{error}}",
|
||||
"containerRestarted": "Container {{name}} đã khởi động lại",
|
||||
"failedToRestartContainer": "Không thể khởi động lại container: {{error}}",
|
||||
"containerUnpaused": "Container {{name}} đã được bỏ tạm dừng",
|
||||
"containerUnpaused": "Container {{name}} unpaused",
|
||||
"containerPaused": "Container {{name}} tạm dừng",
|
||||
"failedToTogglePauseContainer": "Không thể tải xuống container {{action}}: {{error}}",
|
||||
"failedToTogglePauseContainer": "Không thể tải xuống container {{action}} : {{error}}",
|
||||
"containerRemoved": "Container {{name}} đã bị xóa",
|
||||
"failedToRemoveContainer": "Không thể xóa container: {{error}}",
|
||||
"failedToRemoveContainer": "Không thể xóa vùng chứa: {{error}}",
|
||||
"image": "Hình ảnh:",
|
||||
"idLabel": "NHẬN DẠNG:",
|
||||
"ports": "Cảng:",
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"pause": "Tạm dừng",
|
||||
"restart": "Khởi động lại",
|
||||
"removeContainer": "Tháo thùng chứa",
|
||||
"confirmRemoveContainer": "Bạn có chắc chắn muốn xóa container \"{{name}}\" không?",
|
||||
"confirmRemoveContainer": "Bạn có chắc chắn muốn xóa vùng chứa \"{{name}}\" không?",
|
||||
"runningContainerWarning": "Cảnh báo: Container này hiện đang chạy và sẽ bị buộc phải gỡ bỏ.",
|
||||
"removing": "Đang xóa:",
|
||||
"containerNotFound": "Không tìm thấy container",
|
||||
@@ -1195,7 +1195,7 @@
|
||||
"failedToDownloadLogs": "Không thể tải xuống nhật ký: {{error}}",
|
||||
"linesToShow": "Các dòng để hiển thị",
|
||||
"last50Lines": "50 dòng cuối",
|
||||
"last100Lines": "100 dòng cuối",
|
||||
"last100Lines": "100 dòng cuối cùng",
|
||||
"last500Lines": "500 dòng cuối",
|
||||
"last1000Lines": "1000 dòng cuối cùng",
|
||||
"allLogs": "Tất cả nhật ký",
|
||||
@@ -1234,9 +1234,9 @@
|
||||
"reconnected": "Đã kết nối lại thành công",
|
||||
"maxReconnectAttemptsReached": "Đã đạt số lần thử kết nối lại tối đa.",
|
||||
"connectionTimeout": "Hết thời gian chờ kết nối",
|
||||
"terminalTitle": "Nhà ga - {{host}}",
|
||||
"terminalWithPath": "Nhà ga - {{host}}:{{path}}",
|
||||
"runTitle": "Chạy {{command}} - {{host}}",
|
||||
"terminalTitle": "Thiết bị đầu cuối - {{host}}",
|
||||
"terminalWithPath": "Thiết bị đầu cuối - {{host}}:{{path}}",
|
||||
"runTitle": "Đang chạy {{command}} - {{host}}",
|
||||
"totpRequired": "Yêu cầu xác thực hai yếu tố",
|
||||
"totpCodeLabel": "Mã xác minh",
|
||||
"totpPlaceholder": "000000",
|
||||
@@ -1255,16 +1255,16 @@
|
||||
"downloadFile": "Tải xuống",
|
||||
"extractArchive": "Trích xuất tệp lưu trữ",
|
||||
"extractingArchive": "Đang trích xuất {{name}}...",
|
||||
"archiveExtractedSuccessfully": "{{name}} đã được trích xuất thành công",
|
||||
"archiveExtractedSuccessfully": "{{name}} đã trích xuất thành công",
|
||||
"extractFailed": "Trích xuất thất bại",
|
||||
"compressFile": "Nén tệp",
|
||||
"compressFiles": "Nén tệp",
|
||||
"compressFilesDesc": "Nén {{count}} mục thành một tệp lưu trữ",
|
||||
"compressFilesDesc": "Nén {{count}} mục vào kho lưu trữ",
|
||||
"archiveName": "Tên kho lưu trữ",
|
||||
"enterArchiveName": "Nhập tên kho lưu trữ...",
|
||||
"compressionFormat": "Định dạng nén",
|
||||
"selectedFiles": "Các tệp đã chọn",
|
||||
"andMoreFiles": "và {{count}} nữa...",
|
||||
"andMoreFiles": "và {{count}} nhiều hơn nữa...",
|
||||
"compress": "Nén",
|
||||
"compressingFiles": "Nén {{count}} mục thành {{name}}...",
|
||||
"filesCompressedSuccessfully": "{{name}} đã được tạo thành công",
|
||||
@@ -1311,9 +1311,9 @@
|
||||
"newName": "Tên mới",
|
||||
"thisIsDirectoryRename": "Đây là một thư mục",
|
||||
"renaming": "Đổi tên...",
|
||||
"fileUploadedSuccessfully": "Tệp \"{{name}}\" đã được tải lên thành công.",
|
||||
"fileUploadedSuccessfully": "Tệp \"{{name}}\" đã được tải lên thành công",
|
||||
"failedToUploadFile": "Không thể tải tệp lên.",
|
||||
"fileDownloadedSuccessfully": "Tệp \"{{name}}\" đã được tải xuống thành công.",
|
||||
"fileDownloadedSuccessfully": "Tệp \"{{name}}\" đã được tải xuống thành công",
|
||||
"failedToDownloadFile": "Không thể tải xuống tệp.",
|
||||
"noFileContent": "Không nhận được nội dung tệp nào.",
|
||||
"filePath": "Đường dẫn tệp",
|
||||
@@ -1322,10 +1322,10 @@
|
||||
"folderCreatedSuccessfully": "Thư mục \"{{name}}\" đã được tạo thành công",
|
||||
"failedToCreateFolder": "Không thể tạo thư mục",
|
||||
"failedToCreateItem": "Không thể tạo mục",
|
||||
"operationFailed": "Thao tác {{operation}} đã thất bại đối với {{name}}: {{error}}",
|
||||
"operationFailed": "Thao tác {{operation}} thất bại đối với {{name}}: {{error}}",
|
||||
"failedToResolveSymlink": "Không thể giải quyết liên kết tượng trưng",
|
||||
"itemDeletedSuccessfully": "{{type}} đã được xóa thành công",
|
||||
"itemsDeletedSuccessfully": "Đã xóa thành công 144 mục",
|
||||
"itemDeletedSuccessfully": "{{type}} đã xóa thành công",
|
||||
"itemsDeletedSuccessfully": "{{count}} mục đã được xóa thành công",
|
||||
"failedToDeleteItems": "Không thể xóa các mục",
|
||||
"dragFilesToUpload": "Kéo thả tệp vào đây để tải lên",
|
||||
"emptyFolder": "Thư mục này trống",
|
||||
@@ -1347,25 +1347,25 @@
|
||||
"delete": "Xóa bỏ",
|
||||
"properties": "Của cải",
|
||||
"refresh": "Làm cho khỏe lại",
|
||||
"downloadFiles": "Tải xuống {{count}} tập tin vào Trình duyệt",
|
||||
"copyFiles": "Sao chép {{count}} mục",
|
||||
"cutFiles": "Cắt {{count}} mục",
|
||||
"downloadFiles": "Tải xuống các tệp {{count}} vào Trình duyệt",
|
||||
"copyFiles": "Sao chép các mục {{count}}",
|
||||
"cutFiles": "Cắt các mục {{count}}",
|
||||
"deleteFiles": "Xóa {{count}} mục",
|
||||
"filesCopiedToClipboard": "{{count}} mục đã được sao chép vào clipboard",
|
||||
"filesCutToClipboard": "{{count}} mục đã được cắt vào clipboard",
|
||||
"filesCutToClipboard": "{{count}} các mục đã được cắt vào clipboard",
|
||||
"pathCopiedToClipboard": "Đường dẫn đã được sao chép vào clipboard",
|
||||
"pathsCopiedToClipboard": "{{count}} đường dẫn đã được sao chép vào clipboard",
|
||||
"pathsCopiedToClipboard": "{{count}} Đường dẫn đã được sao chép vào clipboard",
|
||||
"failedToCopyPath": "Không thể sao chép đường dẫn vào clipboard",
|
||||
"movedItems": "Đã di chuyển {{count}} mục",
|
||||
"failedToDeleteItem": "Không thể xóa mục",
|
||||
"itemRenamedSuccessfully": "{{count}} đã được đổi tên thành công",
|
||||
"itemRenamedSuccessfully": "{{type}} đã đổi tên thành công",
|
||||
"failedToRenameItem": "Không thể đổi tên mục",
|
||||
"download": "Tải xuống",
|
||||
"permissions": "Quyền hạn",
|
||||
"size": "Kích cỡ",
|
||||
"modified": "Đã sửa đổi",
|
||||
"path": "Con đường",
|
||||
"confirmDelete": "Bạn có chắc chắn muốn xóa {{type}} không?",
|
||||
"confirmDelete": "Bạn có chắc chắn muốn xóa {{name}}không?",
|
||||
"uploadSuccess": "Tệp đã được tải lên thành công.",
|
||||
"uploadFailed": "Tải lên tệp không thành công",
|
||||
"downloadSuccess": "Tệp đã được tải xuống thành công.",
|
||||
@@ -1388,11 +1388,11 @@
|
||||
"connectToServer": "Kết nối với máy chủ",
|
||||
"selectServerToEdit": "Chọn máy chủ từ thanh bên để bắt đầu chỉnh sửa tệp.",
|
||||
"fileOperations": "Thao tác tệp",
|
||||
"confirmDeleteMessage": "Bạn có chắc chắn muốn xóa {{name}} không?",
|
||||
"confirmDeleteMessage": "Bạn có chắc chắn muốn xóa {{name}}không?",
|
||||
"confirmDeleteSingleItem": "Bạn có chắc chắn muốn xóa vĩnh viễn \"{{name}}\" không?",
|
||||
"confirmDeleteMultipleItems": "Bạn có chắc chắn muốn xóa vĩnh viễn {{name}} mục không?",
|
||||
"confirmDeleteMultipleItems": "Bạn có chắc chắn muốn xóa vĩnh viễn {{count}} mục không?",
|
||||
"confirmDeleteMultipleItemsWithFolders": "Bạn có chắc chắn muốn xóa vĩnh viễn {{count}} mục không? Việc này bao gồm cả thư mục và nội dung bên trong chúng.",
|
||||
"confirmDeleteFolder": "Bạn có chắc chắn muốn xóa vĩnh viễn thư mục \"{{count}}\" và tất cả nội dung bên trong không?",
|
||||
"confirmDeleteFolder": "Bạn có chắc chắn muốn xóa vĩnh viễn thư mục \"{{name}}\" và tất cả nội dung bên trong không?",
|
||||
"deleteDirectoryWarning": "Thao tác này sẽ xóa thư mục và toàn bộ nội dung bên trong.",
|
||||
"actionCannotBeUndone": "Hành động này không thể đảo ngược.",
|
||||
"permanentDeleteWarning": "Thao tác này không thể hoàn tác. Mục (các mục) sẽ bị xóa vĩnh viễn khỏi máy chủ.",
|
||||
@@ -1421,16 +1421,16 @@
|
||||
"selectLocationToSave": "Chọn vị trí lưu",
|
||||
"openTerminalInFolder": "Mở cửa sổ dòng lệnh trong thư mục này",
|
||||
"openTerminalInFileLocation": "Mở cửa sổ dòng lệnh tại vị trí tệp",
|
||||
"terminalWithPath": "Nhà ga - {{name}}:{{host}}",
|
||||
"runningFile": "Đang chạy - {{path}}",
|
||||
"terminalWithPath": "Thiết bị đầu cuối - {{host}}:{{path}}",
|
||||
"runningFile": "Đang chạy - {{file}}",
|
||||
"onlyRunExecutableFiles": "Chỉ có thể chạy các tệp thực thi.",
|
||||
"noHostSelected": "Chưa chọn máy chủ nào",
|
||||
"starred": "Đã đóng dấu sao",
|
||||
"shortcuts": "Phím tắt",
|
||||
"directories": "Danh mục",
|
||||
"removedFromRecentFiles": "Đã xóa \"{{file}}\" khỏi các tệp gần đây",
|
||||
"removedFromRecentFiles": "Đã xóa \"{{name}}\" khỏi các tệp gần đây",
|
||||
"removeFailed": "Xóa không thành công",
|
||||
"unpinnedSuccessfully": "Đã gỡ ghim thành công \"{{name}}\"",
|
||||
"unpinnedSuccessfully": "Đã gỡ ghim \"{{name}}\" thành công",
|
||||
"unpinFailed": "Gỡ ghim không thành công",
|
||||
"removedShortcut": "Đã xóa lối tắt \"{{name}}\"",
|
||||
"removeShortcutFailed": "Xóa lối tắt không thành công",
|
||||
@@ -1440,7 +1440,7 @@
|
||||
"clearAllRecentFiles": "Xóa tất cả các tệp gần đây",
|
||||
"unpinFile": "Gỡ ghim tệp",
|
||||
"removeShortcut": "Xóa lối tắt",
|
||||
"saveFilesToSystem": "Lưu {{name}} tập tin dưới dạng...",
|
||||
"saveFilesToSystem": "Lưu các tập tin {{count}} dưới dạng...",
|
||||
"pinFile": "Tệp ghim",
|
||||
"addToShortcuts": "Thêm vào lối tắt",
|
||||
"downloadToDefaultLocation": "Tải xuống vị trí mặc định",
|
||||
@@ -1466,7 +1466,7 @@
|
||||
"replaceAll": "Thay thế tất cả",
|
||||
"downloadInstead": "Tải xuống thay vì",
|
||||
"keyboardShortcuts": "Phím tắt",
|
||||
"searchAndReplace": "Tìm kiếm & Thay thế",
|
||||
"searchAndReplace": "Tìm kiếm và thay thế",
|
||||
"editing": "Chỉnh sửa",
|
||||
"navigation": "Điều hướng",
|
||||
"code": "Mã số",
|
||||
@@ -1491,33 +1491,33 @@
|
||||
"unknownSize": "Kích thước không xác định",
|
||||
"fileIsEmpty": "Tệp tin trống",
|
||||
"largeFileWarning": "Cảnh báo về tệp tin lớn",
|
||||
"largeFileWarningDesc": "Tệp này có kích thước {{count}}, có thể gây ra sự cố về hiệu năng khi mở dưới dạng văn bản.",
|
||||
"fileNotFoundAndRemoved": "Tệp \"{{size}}\" không được tìm thấy và đã bị xóa khỏi các tệp gần đây/được ghim.",
|
||||
"failedToLoadFile": "Không thể tải tệp: {{name}}",
|
||||
"largeFileWarningDesc": "Tệp này có kích thước {{size}} , có thể gây ra sự cố về hiệu năng khi mở dưới dạng văn bản.",
|
||||
"fileNotFoundAndRemoved": "Tệp \"{{name}}\" không được tìm thấy và đã bị xóa khỏi các tệp gần đây/được ghim.",
|
||||
"failedToLoadFile": "Không thể tải tệp: {{error}}",
|
||||
"serverErrorOccurred": "Đã xảy ra lỗi máy chủ. Vui lòng thử lại sau.",
|
||||
"autoSaveFailed": "Lưu tự động thất bại",
|
||||
"fileAutoSaved": "Tệp đã được tự động lưu",
|
||||
"moveFileFailed": "Không thể di chuyển {{error}}",
|
||||
"moveFileFailed": "Không thể di chuyển {{name}}",
|
||||
"moveOperationFailed": "Thao tác di chuyển thất bại",
|
||||
"canOnlyCompareFiles": "Chỉ có thể so sánh hai tệp",
|
||||
"comparingFiles": "So sánh các tập tin: {{name}} và {{file1}}",
|
||||
"comparingFiles": "So sánh các tập tin: {{file1}} và {{file2}}",
|
||||
"dragFailed": "Thao tác kéo thả thất bại",
|
||||
"filePinnedSuccessfully": "Tệp \"{{file2}}\" đã được ghim thành công",
|
||||
"filePinnedSuccessfully": "Tệp \"{{name}}\" đã được ghim thành công",
|
||||
"pinFileFailed": "Không thể ghim tệp",
|
||||
"fileUnpinnedSuccessfully": "Tệp \"{{name}}\" đã được gỡ ghim thành công",
|
||||
"unpinFileFailed": "Không thể bỏ ghim tệp.",
|
||||
"shortcutAddedSuccessfully": "Thêm lối tắt thư mục \"{{name}}\" thành công",
|
||||
"addShortcutFailed": "Không thể thêm lối tắt",
|
||||
"operationCompletedSuccessfully": "{{name}} {{operation}} mục thành công",
|
||||
"operationCompleted": "{{count}} {{operation}} mục",
|
||||
"downloadFileSuccess": "Tệp {{count}} đã được tải xuống thành công",
|
||||
"operationCompletedSuccessfully": "{{operation}} {{count}} mục thành công",
|
||||
"operationCompleted": "{{operation}} {{count}} mục",
|
||||
"downloadFileSuccess": "Tệp {{name}} đã được tải xuống thành công",
|
||||
"downloadFileFailed": "Tải xuống thất bại",
|
||||
"moveTo": "Di chuyển tới {{name}}",
|
||||
"moveTo": "Di chuyển đến {{name}}",
|
||||
"diffCompareWith": "So sánh khác biệt với {{name}}",
|
||||
"dragOutsideToDownload": "Kéo chuột ra ngoài cửa sổ để tải xuống (187 tập tin)",
|
||||
"dragOutsideToDownload": "Kéo chuột ra ngoài cửa sổ để tải xuống ({{count}} tập tin)",
|
||||
"newFolderDefault": "Thư mục mới",
|
||||
"newFileDefault": "NewFile.txt",
|
||||
"successfullyMovedItems": "Đã chuyển thành công {{name}} mục đến {{count}}",
|
||||
"successfullyMovedItems": "Đã chuyển thành công {{count}} mục đến {{target}}",
|
||||
"move": "Di chuyển",
|
||||
"searchInFile": "Tìm kiếm trong tệp (Ctrl+F)",
|
||||
"showKeyboardShortcuts": "Hiển thị các phím tắt",
|
||||
@@ -1527,10 +1527,10 @@
|
||||
"compare": "So sánh",
|
||||
"sideBySide": "Cạnh nhau",
|
||||
"inline": "Nội tuyến",
|
||||
"fileComparison": "So sánh tập tin: {{count}} so với {{target}}",
|
||||
"fileTooLarge": "Tệp quá lớn: {{file1}}",
|
||||
"sshConnectionFailed": "Kết nối SSH thất bại. Vui lòng kiểm tra kết nối của bạn tới {{file2}} ({{error}}:{{name}})",
|
||||
"loadFileFailed": "Không thể tải tệp: {{ip}}",
|
||||
"fileComparison": "So sánh tập tin: {{file1}} so với {{file2}}",
|
||||
"fileTooLarge": "Tệp quá lớn: {{error}}",
|
||||
"sshConnectionFailed": "Kết nối SSH thất bại. Vui lòng kiểm tra kết nối của bạn tới {{name}} ({{ip}}:{{port}})",
|
||||
"loadFileFailed": "Không thể tải tệp: {{error}}",
|
||||
"connectedSuccessfully": "Kết nối thành công",
|
||||
"totpVerificationFailed": "Xác thực TOTP thất bại",
|
||||
"verificationCodePrompt": "Mã xác minh:",
|
||||
@@ -1573,10 +1573,10 @@
|
||||
"disconnect": "Ngắt kết nối",
|
||||
"cancel": "Hủy bỏ",
|
||||
"port": "Cảng",
|
||||
"attempt": "Lần thử {{port}} trong số {{error}}",
|
||||
"nextRetryIn": "Lần thử lại tiếp theo sau {{current}} giây",
|
||||
"attempt": "Lần thử {{current}} của {{max}}",
|
||||
"nextRetryIn": "Lần thử lại tiếp theo sau {{seconds}} giây",
|
||||
"checkDockerLogs": "Kiểm tra nhật ký Docker để tìm nguyên nhân lỗi, tham gia nhóm.",
|
||||
"orCreate": "hoặc tạo một",
|
||||
"orCreate": "hoặc tạo một ",
|
||||
"noTunnelConnections": "Không có kết nối đường hầm nào được cấu hình.",
|
||||
"tunnelConnections": "Kết nối đường hầm",
|
||||
"addTunnel": "Thêm đường hầm",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"remote": "Xa",
|
||||
"dynamic": "Năng động",
|
||||
"unknownConnectionStatus": "Không rõ",
|
||||
"portMapping": "Cổng {{max}} → {{seconds}}:{{sourcePort}}",
|
||||
"portMapping": "Cổng {{sourcePort}} → {{endpointHost}}:{{endpointPort}}",
|
||||
"endpointHostNotFound": "Không tìm thấy máy chủ điểm cuối",
|
||||
"discord": "Discord",
|
||||
"githubIssue": "Sự cố trên GitHub",
|
||||
@@ -1611,7 +1611,7 @@
|
||||
"disk": "Đĩa",
|
||||
"network": "Mạng",
|
||||
"uptime": "Thời gian hoạt động",
|
||||
"loadAverage": "Trung bình: {{endpointHost}}, {{endpointPort}}, {{avg1}}",
|
||||
"loadAverage": "Trung bình: {{avg1}}, {{avg5}}, {{avg15}}",
|
||||
"processes": "Quy trình",
|
||||
"connections": "Kết nối",
|
||||
"usage": "Cách sử dụng",
|
||||
@@ -1623,9 +1623,9 @@
|
||||
"refreshStatusAndMetrics": "Cập nhật trạng thái và số liệu",
|
||||
"refreshStatus": "Làm mới trạng thái",
|
||||
"fileManagerAlreadyOpen": "Trình quản lý tập tin đã được mở cho máy chủ này.",
|
||||
"openFileManager": "Mở Trình quản lý tệp",
|
||||
"cpuCores_one": "CPU {{avg5}}",
|
||||
"cpuCores_other": "CPU {{avg15}}",
|
||||
"openFileManager": "Mở trình quản lý tệp",
|
||||
"cpuCores_one": "{{count}} CPU",
|
||||
"cpuCores_other": "{{count}} CPU",
|
||||
"naCpus": "Không áp dụng CPU",
|
||||
"loadAverageNA": "Trung bình: Không xác định",
|
||||
"cpuUsage": "Mức sử dụng CPU",
|
||||
@@ -1650,7 +1650,7 @@
|
||||
"totpInvalidCode": "Mã xác minh không hợp lệ",
|
||||
"totpCancelled": "Việc thu thập số liệu đã bị hủy bỏ.",
|
||||
"authenticationFailed": "Xác thực thất bại",
|
||||
"noneAuthNotSupported": "Server Stats không hỗ trợ loại xác thực 'none'.",
|
||||
"noneAuthNotSupported": "Server Stats không hỗ trợ loại xác thực 'non'.",
|
||||
"load": "Trọng tải",
|
||||
"editLayout": "Chỉnh sửa bố cục",
|
||||
"cancelEdit": "Hủy bỏ",
|
||||
@@ -1678,8 +1678,8 @@
|
||||
"noRecentLoginData": "Không có dữ liệu đăng nhập gần đây",
|
||||
"from": "từ",
|
||||
"quickActions": "Thao tác nhanh",
|
||||
"executeQuickAction": "Thực thi {{count}}",
|
||||
"executingQuickAction": "Đang thực thi {{count}}...",
|
||||
"executeQuickAction": "Thực thi {{name}}",
|
||||
"executingQuickAction": "Đang thực thi {{name}}...",
|
||||
"quickActionSuccess": "{{name}} đã hoàn thành thành công",
|
||||
"quickActionFailed": "{{name}} thất bại",
|
||||
"quickActionError": "Không thể thực thi {{name}}"
|
||||
@@ -1733,7 +1733,7 @@
|
||||
"disableTwoFactorWarning": "Việc vô hiệu hóa xác thực hai yếu tố sẽ khiến tài khoản của bạn kém an toàn hơn.",
|
||||
"passwordOrTotpCode": "Mật khẩu hoặc mã TOTP",
|
||||
"or": "Hoặc",
|
||||
"generateNewBackupCodesText": "Tạo mã sao lưu mới nếu bạn đã làm mất mã hiện có.",
|
||||
"generateNewBackupCodesText": "Hãy tạo mã sao lưu mới nếu bạn đã mất mã hiện có.",
|
||||
"generateNewBackupCodes": "Tạo mã sao lưu mới",
|
||||
"yourBackupCodes": "Mã sao lưu của bạn",
|
||||
"download": "Tải xuống",
|
||||
@@ -1814,8 +1814,8 @@
|
||||
"invalidAuthUrl": "URL xác thực không hợp lệ được nhận từ máy chủ phụ trợ.",
|
||||
"invalidInput": "Đầu vào không hợp lệ",
|
||||
"requiredField": "Trường này là bắt buộc",
|
||||
"minLength": "Độ dài tối thiểu là {{name}}",
|
||||
"maxLength": "Độ dài tối đa là {{name}}",
|
||||
"minLength": "Độ dài tối thiểu là {{min}}",
|
||||
"maxLength": "Độ dài tối đa là {{max}}",
|
||||
"invalidEmail": "Địa chỉ email không hợp lệ",
|
||||
"passwordMismatch": "Mật khẩu không khớp",
|
||||
"passwordLoginDisabled": "Chức năng đăng nhập bằng tên người dùng/mật khẩu hiện đang bị vô hiệu hóa.",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"updateError": "Cập nhật không thành công",
|
||||
"copySuccess": "Đã sao chép vào clipboard",
|
||||
"copyError": "Không thể sao chép",
|
||||
"copiedToClipboard": "{{min}} đã được sao chép vào clipboard",
|
||||
"copiedToClipboard": "{{item}} đã sao chép vào clipboard",
|
||||
"connectionEstablished": "Kết nối đã được thiết lập",
|
||||
"connectionClosed": "Kết nối đã bị đóng",
|
||||
"reconnecting": "Đang kết nối lại...",
|
||||
@@ -1926,7 +1926,7 @@
|
||||
"usernameField": "tên",
|
||||
"scopes": "hồ sơ email openid",
|
||||
"userinfoUrl": "https://your-provider.com/application/o/userinfo/",
|
||||
"enterUsername": "Nhập tên người dùng để trở thành quản trị viên",
|
||||
"enterUsername": "Nhập tên người dùng để trở thành quản trị viên.",
|
||||
"searchHosts": "Tìm kiếm máy chủ theo tên, tên người dùng, địa chỉ IP, thư mục, thẻ...",
|
||||
"enterPassword": "Nhập mật khẩu của bạn",
|
||||
"totpCode": "Mã TOTP 6 chữ số",
|
||||
@@ -1942,7 +1942,7 @@
|
||||
"socks5Username": "tên người dùng ủy quyền",
|
||||
"socks5Password": "mật khẩu proxy",
|
||||
"socks5PresetName": "Ví dụ: Chuỗi VPN công việc",
|
||||
"socks5PresetDescription": "Ví dụ: Chuỗi proxy để truy cập máy chủ làm việc",
|
||||
"socks5PresetDescription": "Ví dụ: Chuỗi proxy để truy cập máy chủ công việc",
|
||||
"moshCommand": "người dùng mosh@máy chủ",
|
||||
"defaultPort": "22",
|
||||
"defaultEndpointPort": "224",
|
||||
@@ -1955,9 +1955,9 @@
|
||||
"passwordRequired": "Cần có mật khẩu.",
|
||||
"failedToDeleteAccount": "Không thể xóa tài khoản",
|
||||
"failedToMakeUserAdmin": "Không thể cấp quyền quản trị cho người dùng.",
|
||||
"userIsNowAdmin": "Người dùng {{max}} hiện là quản trị viên",
|
||||
"removeAdminConfirm": "Bạn có chắc chắn muốn xóa quyền quản trị khỏi {{item}} không?",
|
||||
"deleteUserConfirm": "Bạn có chắc chắn muốn xóa người dùng {{username}} không? Hành động này không thể hoàn tác.",
|
||||
"userIsNowAdmin": "Người dùng {{username}} hiện là quản trị viên",
|
||||
"removeAdminConfirm": "Bạn có chắc chắn muốn xóa quyền quản trị khỏi {{username}}không?",
|
||||
"deleteUserConfirm": "Bạn có chắc chắn muốn xóa người dùng {{username}}không? Hành động này không thể hoàn tác.",
|
||||
"deleteAccount": "Xóa tài khoản",
|
||||
"closeDeleteAccount": "Đóng Xóa tài khoản",
|
||||
"deleteAccountWarning": "Thao tác này không thể hoàn tác. Thao tác này sẽ xóa vĩnh viễn tài khoản của bạn và tất cả dữ liệu liên quan.",
|
||||
@@ -2142,15 +2142,15 @@
|
||||
"createTempUser": "Tạo người dùng tạm thời",
|
||||
"createTempUserDesc": "Tạo một người dùng bị hạn chế quyền truy cập trên máy chủ thay vì chia sẻ thông tin đăng nhập của bạn. Yêu cầu quyền sudo. Đây là tùy chọn an toàn nhất.",
|
||||
"expiresAt": "Hết hạn vào lúc",
|
||||
"expiresIn": "Hết hạn sau {{username}} giờ",
|
||||
"expiresIn": "Hết hạn sau {{hours}} giờ",
|
||||
"expired": "Hết hạn",
|
||||
"grantedBy": "Được cấp bởi",
|
||||
"accessLevel": "Cấp độ truy cập",
|
||||
"lastAccessed": "Lần truy cập cuối cùng",
|
||||
"accessCount": "Số lượt truy cập",
|
||||
"revokeAccess": "Thu hồi quyền truy cập",
|
||||
"confirmRevokeAccess": "Bạn có chắc chắn muốn thu hồi quyền truy cập cho {{username}} không?",
|
||||
"hostSharedSuccessfully": "Máy chủ đã chia sẻ thành công với {{hours}}",
|
||||
"confirmRevokeAccess": "Bạn có chắc chắn muốn thu hồi quyền truy cập cho {{username}}không?",
|
||||
"hostSharedSuccessfully": "Máy chủ đã chia sẻ thành công với {{username}}",
|
||||
"hostAccessUpdated": "Cập nhật quyền truy cập máy chủ",
|
||||
"failedToShareHost": "Không thể chia sẻ máy chủ",
|
||||
"accessRevokedSuccessfully": "Quyền truy cập đã bị thu hồi thành công.",
|
||||
@@ -2165,26 +2165,26 @@
|
||||
"noAccessGranted": "Không có quyền truy cập nào được cấp cho máy chủ này.",
|
||||
"noAccessGrantedMessage": "Chưa có người dùng nào được cấp quyền truy cập vào máy chủ này.",
|
||||
"manageAccessFor": "Quản lý quyền truy cập cho",
|
||||
"totalAccessRecords": "{{username}} bản ghi truy cập",
|
||||
"totalAccessRecords": "{{count}} truy cập bản ghi(các)",
|
||||
"neverAccessed": "Không bao giờ",
|
||||
"timesAccessed": "{{username}} lần",
|
||||
"daysRemaining": "{{count}} ngày",
|
||||
"hoursRemaining": "{{count}} giờ",
|
||||
"timesAccessed": "{{count}} thời gian",
|
||||
"daysRemaining": "{{days}} ngày",
|
||||
"hoursRemaining": "{{hours}} giờ",
|
||||
"failedToFetchAccessList": "Không thể tải danh sách truy cập",
|
||||
"currentAccess": "Truy cập hiện tại",
|
||||
"securityWarning": "Cảnh báo an ninh",
|
||||
"securityWarningMessage": "Chia sẻ thông tin đăng nhập cho phép người dùng có toàn quyền thực hiện mọi thao tác trên máy chủ, bao gồm thay đổi mật khẩu và xóa tập tin. Chỉ chia sẻ với những người dùng đáng tin cậy.",
|
||||
"tempUserRecommended": "Chúng tôi khuyến nghị bạn nên bật tùy chọn \"Tạo người dùng tạm thời\" để tăng cường bảo mật.",
|
||||
"tempUserRecommended": "Chúng tôi khuyên bạn nên bật tùy chọn 'Tạo người dùng tạm thời' để tăng cường bảo mật.",
|
||||
"roleManagement": "Quản lý vai trò",
|
||||
"manageRoles": "Quản lý vai trò",
|
||||
"manageRolesFor": "Quản lý vai trò cho {{days}}",
|
||||
"manageRolesFor": "Quản lý vai trò cho {{username}}",
|
||||
"assignRole": "Phân công vai trò",
|
||||
"removeRole": "Xóa vai trò",
|
||||
"userRoles": "Vai trò người dùng",
|
||||
"permissions": "Quyền hạn",
|
||||
"systemRole": "Vai trò hệ thống",
|
||||
"customRole": "Vai trò tùy chỉnh",
|
||||
"roleAssignedSuccessfully": "Vai trò được giao cho {{hours}} thành công",
|
||||
"roleAssignedSuccessfully": "Vai trò được giao cho {{username}} thành công",
|
||||
"failedToAssignRole": "Không thể gán vai trò",
|
||||
"roleRemovedSuccessfully": "Vai trò đã được xóa khỏi {{username}} thành công",
|
||||
"failedToRemoveRole": "Không thể xóa vai trò",
|
||||
@@ -2214,7 +2214,7 @@
|
||||
"terminateSession": "Kết thúc phiên",
|
||||
"sessionTerminated": "Phiên làm việc bị chấm dứt bởi chủ sở hữu máy chủ.",
|
||||
"sharedAccessExpired": "Quyền truy cập dùng chung của bạn vào máy chủ này đã hết hạn.",
|
||||
"sharedAccessExpiresIn": "Quyền truy cập dùng chung sẽ hết hạn sau {{username}} giờ",
|
||||
"sharedAccessExpiresIn": "Quyền truy cập dùng chung sẽ hết hạn sau {{hours}} giờ",
|
||||
"roles": {
|
||||
"label": "Vai trò",
|
||||
"admin": "Quản trị viên",
|
||||
@@ -2249,7 +2249,7 @@
|
||||
"displayNamePlaceholder": "Nhà phát triển",
|
||||
"descriptionPlaceholder": "Các nhà phát triển và kỹ sư phần mềm",
|
||||
"confirmDeleteRole": "Xóa vai trò",
|
||||
"confirmDeleteRoleDescription": "Bạn có chắc chắn muốn xóa vai trò '{{username}}' không? Hành động này không thể hoàn tác.",
|
||||
"confirmDeleteRoleDescription": "Bạn có chắc chắn muốn xóa vai trò '{{name}}' không? Hành động này không thể hoàn tác.",
|
||||
"confirmRemoveRole": "Xóa vai trò",
|
||||
"confirmRemoveRoleDescription": "Bạn có chắc chắn muốn xóa vai trò này khỏi người dùng không?",
|
||||
"editRoleDescription": "Cập nhật thông tin vai trò",
|
||||
@@ -2289,7 +2289,7 @@
|
||||
"updateLog": "Nhật ký cập nhật",
|
||||
"hosts": "Người dẫn chương trình",
|
||||
"openServerDetails": "Chi tiết máy chủ mở",
|
||||
"openFileManager": "Mở Trình quản lý tệp",
|
||||
"openFileManager": "Mở trình quản lý tệp",
|
||||
"edit": "Biên tập",
|
||||
"links": "Liên kết",
|
||||
"github": "GitHub",
|
||||
@@ -2307,16 +2307,16 @@
|
||||
"validating": "Đang xác thực Docker...",
|
||||
"connectingToHost": "Đang kết nối với máy chủ...",
|
||||
"error": "Lỗi",
|
||||
"errorCode": "Mã lỗi: {{hours}}",
|
||||
"version": "Docker {{name}}",
|
||||
"containerStarted": "Container {{code}} đã khởi động",
|
||||
"failedToStartContainer": "Không thể khởi động container {{version}}",
|
||||
"errorCode": "Mã lỗi: {{code}}",
|
||||
"version": "Docker {{version}}",
|
||||
"containerStarted": "Container {{name}} đã khởi động",
|
||||
"failedToStartContainer": "Không thể khởi động container {{name}}",
|
||||
"containerStopped": "Container {{name}} đã dừng",
|
||||
"failedToStopContainer": "Không thể dừng container {{name}}",
|
||||
"containerRestarted": "Container {{name}} đã khởi động lại",
|
||||
"failedToRestartContainer": "Không thể khởi động lại container {{name}}",
|
||||
"containerPaused": "Container {{name}} tạm dừng",
|
||||
"containerUnpaused": "Container {{name}} chưa tạm dừng",
|
||||
"containerUnpaused": "Container {{name}} unpaused",
|
||||
"failedToTogglePauseContainer": "Không thể chuyển đổi trạng thái tạm dừng cho vùng chứa {{name}}",
|
||||
"containerRemoved": "Container {{name}} đã bị xóa",
|
||||
"failedToRemoveContainer": "Không thể xóa container {{name}}",
|
||||
@@ -2340,8 +2340,8 @@
|
||||
"noContainersFoundHint": "Hiện không có container Docker nào khả dụng trên máy chủ này.",
|
||||
"searchPlaceholder": "Tìm kiếm container...",
|
||||
"filterByStatusPlaceholder": "Lọc theo trạng thái",
|
||||
"allContainersCount": "Tất cả ({{name}})",
|
||||
"statusCount": "{{name}} ({{count}})",
|
||||
"allContainersCount": "Tất cả ({{count}})",
|
||||
"statusCount": "{{status}} ({{count}})",
|
||||
"noContainersMatchFilters": "Không có hộp đựng nào phù hợp với bộ lọc của bạn.",
|
||||
"noContainersMatchFiltersHint": "Hãy thử điều chỉnh tiêu chí tìm kiếm hoặc lọc của bạn.",
|
||||
"containerMustBeRunningToViewStats": "Container phải đang chạy để xem số liệu thống kê.",
|
||||
@@ -2372,10 +2372,10 @@
|
||||
"authenticationRequired": "Cần xác thực",
|
||||
"verificationCodePrompt": "Nhập mã xác minh",
|
||||
"totpVerificationFailed": "Xác thực TOTP không thành công. Vui lòng thử lại.",
|
||||
"connectedTo": "Đã kết nối với {{status}}",
|
||||
"connectedTo": "Đã kết nối với {{containerName}}",
|
||||
"disconnected": "Đã ngắt kết nối",
|
||||
"consoleError": "Lỗi bảng điều khiển",
|
||||
"errorMessage": "Lỗi: {{count}}",
|
||||
"errorMessage": "Lỗi: {{message}}",
|
||||
"failedToConnect": "Không thể kết nối với container",
|
||||
"console": "Bảng điều khiển",
|
||||
"selectShell": "Chọn vỏ",
|
||||
@@ -2399,4 +2399,4 @@
|
||||
"switchToLight": "Chuyển sang chế độ sáng",
|
||||
"switchToDark": "Chuyển sang chế độ Tối"
|
||||
}
|
||||
}
|
||||
}
|
||||
2406
src/locales/translated/zh.json
Normal file
2406
src/locales/translated/zh.json
Normal file
File diff suppressed because it is too large
Load Diff
2402
src/locales/uk.json
2402
src/locales/uk.json
File diff suppressed because it is too large
Load Diff
2402
src/locales/zh.json
2402
src/locales/zh.json
File diff suppressed because it is too large
Load Diff
30
src/main.tsx
30
src/main.tsx
@@ -8,6 +8,23 @@ import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { ElectronVersionCheck } from "@/ui/desktop/user/ElectronVersionCheck.tsx";
|
||||
import "./i18n/i18n";
|
||||
import { isElectron } from "./ui/main-axios.ts";
|
||||
import HostManagerApp from "./ui/desktop/apps/HostManagerApp.tsx";
|
||||
import NetworkGraphApp from "./ui/desktop/apps/NetworkGraphApp.tsx";
|
||||
|
||||
const FullscreenApp: React.FC = () => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const view = searchParams.get('view');
|
||||
|
||||
switch (view) {
|
||||
case 'host-manager':
|
||||
return <HostManagerApp />;
|
||||
case 'network-graph':
|
||||
return <NetworkGraphApp />;
|
||||
default:
|
||||
return <DesktopApp />;
|
||||
}
|
||||
};
|
||||
import { useServiceWorker } from "@/hooks/use-service-worker";
|
||||
|
||||
function useWindowWidth() {
|
||||
const [width, setWidth] = useState(window.innerWidth);
|
||||
@@ -58,11 +75,21 @@ function RootApp() {
|
||||
const isMobile = width < 768;
|
||||
const [showVersionCheck, setShowVersionCheck] = useState(true);
|
||||
|
||||
// PWA Service Worker registration (production web only)
|
||||
useServiceWorker();
|
||||
|
||||
const userAgent =
|
||||
navigator.userAgent || navigator.vendor || (window as any).opera || "";
|
||||
const isTermixMobile = /Termix-Mobile/.test(userAgent);
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const isFullscreen = searchParams.has('view');
|
||||
|
||||
const renderApp = () => {
|
||||
if (isFullscreen) {
|
||||
return <FullscreenApp />;
|
||||
}
|
||||
|
||||
if (isElectron()) {
|
||||
return <DesktopApp />;
|
||||
}
|
||||
@@ -94,7 +121,7 @@ function RootApp() {
|
||||
}}
|
||||
/>
|
||||
<div className="relative min-h-screen" style={{ zIndex: 1 }}>
|
||||
{isElectron() && showVersionCheck ? (
|
||||
{isElectron() && showVersionCheck && !isFullscreen ? (
|
||||
<ElectronVersionCheck
|
||||
onContinue={() => setShowVersionCheck(false)}
|
||||
isAuthenticated={false}
|
||||
@@ -114,3 +141,4 @@ createRoot(document.getElementById("root")!).render(
|
||||
</ThemeProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ export interface SSHHost {
|
||||
enableTunnel: boolean;
|
||||
enableFileManager: boolean;
|
||||
enableDocker: boolean;
|
||||
showTerminalInSidebar: boolean;
|
||||
showFileManagerInSidebar: boolean;
|
||||
showTunnelInSidebar: boolean;
|
||||
showDockerInSidebar: boolean;
|
||||
showServerStatsInSidebar: boolean;
|
||||
defaultPath: string;
|
||||
tunnelConnections: TunnelConnection[];
|
||||
jumpHosts?: JumpHost[];
|
||||
@@ -102,6 +107,11 @@ export interface SSHHostData {
|
||||
enableTunnel?: boolean;
|
||||
enableFileManager?: boolean;
|
||||
enableDocker?: boolean;
|
||||
showTerminalInSidebar?: boolean;
|
||||
showFileManagerInSidebar?: boolean;
|
||||
showTunnelInSidebar?: boolean;
|
||||
showDockerInSidebar?: boolean;
|
||||
showServerStatsInSidebar?: boolean;
|
||||
defaultPath?: string;
|
||||
forceKeyboardInteractive?: boolean;
|
||||
tunnelConnections?: TunnelConnection[];
|
||||
@@ -193,6 +203,7 @@ export interface CredentialData {
|
||||
// ============================================================================
|
||||
|
||||
export interface TunnelConnection {
|
||||
tunnelType?: "local" | "remote";
|
||||
sourcePort: number;
|
||||
endpointPort: number;
|
||||
endpointHost: string;
|
||||
@@ -210,6 +221,7 @@ export interface TunnelConnection {
|
||||
|
||||
export interface TunnelConfig {
|
||||
name: string;
|
||||
tunnelType?: "local" | "remote";
|
||||
|
||||
sourceHostId: number;
|
||||
tunnelIndex: number;
|
||||
|
||||
@@ -6,7 +6,48 @@ export type WidgetType =
|
||||
| "uptime"
|
||||
| "processes"
|
||||
| "system"
|
||||
| "login_stats";
|
||||
| "login_stats"
|
||||
| "ports"
|
||||
| "firewall";
|
||||
|
||||
export interface ListeningPort {
|
||||
protocol: "tcp" | "udp";
|
||||
localAddress: string;
|
||||
localPort: number;
|
||||
state?: string;
|
||||
pid?: number;
|
||||
process?: string;
|
||||
}
|
||||
|
||||
export interface PortsMetrics {
|
||||
source: "ss" | "netstat" | "none";
|
||||
ports: ListeningPort[];
|
||||
}
|
||||
|
||||
export interface FirewallRule {
|
||||
chain: string;
|
||||
target: string;
|
||||
protocol: string;
|
||||
source: string;
|
||||
destination: string;
|
||||
dport?: string;
|
||||
sport?: string;
|
||||
state?: string;
|
||||
interface?: string;
|
||||
extra?: string;
|
||||
}
|
||||
|
||||
export interface FirewallChain {
|
||||
name: string;
|
||||
policy: string;
|
||||
rules: FirewallRule[];
|
||||
}
|
||||
|
||||
export interface FirewallMetrics {
|
||||
type: "iptables" | "nftables" | "none";
|
||||
status: "active" | "inactive" | "unknown";
|
||||
chains: FirewallChain[];
|
||||
}
|
||||
|
||||
export interface StatsConfig {
|
||||
enabledWidgets: WidgetType[];
|
||||
|
||||
@@ -11,12 +11,17 @@ import { TopNavbar } from "@/ui/desktop/navigation/TopNavbar.tsx";
|
||||
import { CommandHistoryProvider } from "@/ui/desktop/apps/features/terminal/command-history/CommandHistoryContext.tsx";
|
||||
import { AdminSettings } from "@/ui/desktop/apps/admin/AdminSettings.tsx";
|
||||
import { UserProfile } from "@/ui/desktop/user/UserProfile.tsx";
|
||||
import { NetworkGraphCard } from "@/ui/desktop/apps/dashboard/cards/NetworkGraphCard";
|
||||
import { Toaster } from "@/components/ui/sonner.tsx";
|
||||
import { toast } from "sonner";
|
||||
import { CommandPalette } from "@/ui/desktop/apps/command-palette/CommandPalette.tsx";
|
||||
import { getUserInfo } from "@/ui/main-axios.ts";
|
||||
import { getUserInfo, logoutUser, isElectron } from "@/ui/main-axios.ts";
|
||||
import { useTheme } from "@/components/theme-provider";
|
||||
import { dbHealthMonitor } from "@/lib/db-health-monitor.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function AppContent() {
|
||||
const { t } = useTranslation();
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [username, setUsername] = useState<string | null>(null);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
@@ -29,11 +34,12 @@ function AppContent() {
|
||||
const [transitionPhase, setTransitionPhase] = useState<
|
||||
"idle" | "fadeOut" | "fadeIn"
|
||||
>("idle");
|
||||
const { currentTab, tabs, updateTab } = useTabs();
|
||||
const { currentTab, tabs, updateTab, addTab } = useTabs();
|
||||
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false);
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [rightSidebarOpen, setRightSidebarOpen] = useState(false);
|
||||
const [rightSidebarWidth, setRightSidebarWidth] = useState(400);
|
||||
const [dbConnectionFailed, setDbConnectionFailed] = useState(false);
|
||||
|
||||
const isDarkMode =
|
||||
theme === "dark" ||
|
||||
@@ -45,12 +51,49 @@ function AppContent() {
|
||||
|
||||
const lastAltPressTime = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleDatabaseConnectionLost = () => {
|
||||
setDbConnectionFailed(true);
|
||||
setIsAuthenticated(false);
|
||||
};
|
||||
|
||||
const handleDatabaseConnectionRestored = () => {
|
||||
setDbConnectionFailed(false);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
dbHealthMonitor.on(
|
||||
"database-connection-lost",
|
||||
handleDatabaseConnectionLost,
|
||||
);
|
||||
dbHealthMonitor.on(
|
||||
"database-connection-restored",
|
||||
handleDatabaseConnectionRestored,
|
||||
);
|
||||
|
||||
return () => {
|
||||
dbHealthMonitor.off(
|
||||
"database-connection-lost",
|
||||
handleDatabaseConnectionLost,
|
||||
);
|
||||
dbHealthMonitor.off(
|
||||
"database-connection-restored",
|
||||
handleDatabaseConnectionRestored,
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.code === "ShiftLeft") {
|
||||
if (event.repeat) {
|
||||
return;
|
||||
}
|
||||
const shortcutEnabled =
|
||||
localStorage.getItem("commandPaletteShortcutEnabled") !== "false";
|
||||
if (!shortcutEnabled) {
|
||||
return;
|
||||
}
|
||||
const now = Date.now();
|
||||
if (now - lastShiftPressTime.current < 300) {
|
||||
setIsCommandPaletteOpen((isOpen) => !isOpen);
|
||||
@@ -86,6 +129,52 @@ function AppContent() {
|
||||
};
|
||||
}, [theme, setTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
const path = window.location.pathname;
|
||||
// New format: /terminal/{hostNameOrId}
|
||||
const terminalMatch = path.match(/^\/terminal\/([a-zA-Z0-9_-]+)$/);
|
||||
// Legacy format: /hosts/{id}/terminal (backward compatible)
|
||||
const legacyMatch = path.match(/^\/hosts\/([a-zA-Z0-9_-]+)\/terminal$/);
|
||||
const hostIdentifier = terminalMatch?.[1] || legacyMatch?.[1];
|
||||
|
||||
if (hostIdentifier) {
|
||||
const openTerminal = async () => {
|
||||
try {
|
||||
const { getSSHHostById, getSSHHosts } =
|
||||
await import("@/ui/main-axios.ts");
|
||||
let host = null;
|
||||
|
||||
// Pure numeric → lookup by ID
|
||||
if (/^\d+$/.test(hostIdentifier)) {
|
||||
host = await getSSHHostById(parseInt(hostIdentifier, 10));
|
||||
} else {
|
||||
// Non-numeric → lookup by name (first match)
|
||||
const hosts = await getSSHHosts();
|
||||
host =
|
||||
hosts.find((h: { name?: string }) => h.name === hostIdentifier) ||
|
||||
null;
|
||||
}
|
||||
|
||||
if (host) {
|
||||
addTab({
|
||||
type: "terminal",
|
||||
title: host.name || host.ip,
|
||||
data: { host, initialCommand: "" },
|
||||
});
|
||||
// Clean URL to prevent re-opening on refresh
|
||||
window.history.replaceState({}, "", "/");
|
||||
} else {
|
||||
toast.error(`Host "${hostIdentifier}" not found`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to open terminal:", error);
|
||||
toast.error("Failed to open terminal for host");
|
||||
}
|
||||
};
|
||||
openTerminal();
|
||||
}
|
||||
}, [addTab]);
|
||||
|
||||
useEffect(() => {
|
||||
const checkAuth = () => {
|
||||
setAuthLoading(true);
|
||||
@@ -131,8 +220,6 @@ function AppContent() {
|
||||
localStorage.setItem("topNavbarOpen", JSON.stringify(isTopbarOpen));
|
||||
}, [isTopbarOpen]);
|
||||
|
||||
const handleSelectView = () => {};
|
||||
|
||||
const handleAuthSuccess = useCallback(
|
||||
(authData: {
|
||||
isAdmin: boolean;
|
||||
@@ -163,7 +250,6 @@ function AppContent() {
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const { logoutUser, isElectron } = await import("@/ui/main-axios.ts");
|
||||
await logoutUser();
|
||||
|
||||
if (isElectron()) {
|
||||
@@ -188,11 +274,12 @@ function AppContent() {
|
||||
const showSshManager = currentTabData?.type === "ssh_manager";
|
||||
const showAdmin = currentTabData?.type === "admin";
|
||||
const showProfile = currentTabData?.type === "user_profile";
|
||||
const showNetworkGraph = currentTabData?.type === "network_graph";
|
||||
|
||||
if (authLoading) {
|
||||
if (authLoading && !dbConnectionFailed) {
|
||||
return (
|
||||
<div
|
||||
className="h-screen w-screen flex items-center justify-center"
|
||||
className="fixed inset-0 flex items-center justify-center"
|
||||
style={{
|
||||
background: "var(--bg-elevated)",
|
||||
backgroundImage: `repeating-linear-gradient(
|
||||
@@ -204,13 +291,44 @@ function AppContent() {
|
||||
)`,
|
||||
}}
|
||||
>
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 border-4 border-primary/30 border-t-primary rounded-full animate-spin mx-auto" />
|
||||
<div className="w-[420px] max-w-full p-8 flex flex-col backdrop-blur-sm bg-card/50 rounded-2xl shadow-xl border-2 border-edge overflow-y-auto thin-scrollbar my-2 animate-in fade-in zoom-in-95 duration-300">
|
||||
<div className="flex items-center justify-center h-32">
|
||||
<div className="text-center">
|
||||
<div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||
<p className="text-muted-foreground">
|
||||
{t("common.checkingAuthentication")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (dbConnectionFailed) {
|
||||
return (
|
||||
<div className="h-screen w-screen overflow-hidden bg-background">
|
||||
<div className="fixed inset-0 flex items-center justify-center z-[10000] bg-background">
|
||||
<Dashboard
|
||||
isAuthenticated={false}
|
||||
authLoading={false}
|
||||
onAuthSuccess={handleAuthSuccess}
|
||||
isTopbarOpen={isTopbarOpen}
|
||||
onSelectView={() => {}}
|
||||
initialDbError="Database connection failed"
|
||||
/>
|
||||
</div>
|
||||
<Toaster
|
||||
position="bottom-right"
|
||||
richColors={false}
|
||||
closeButton
|
||||
duration={5000}
|
||||
offset={20}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen w-screen overflow-hidden bg-background">
|
||||
<CommandPalette
|
||||
@@ -220,7 +338,6 @@ function AppContent() {
|
||||
{!isAuthenticated && (
|
||||
<div className="fixed inset-0 flex items-center justify-center z-[10000] bg-background">
|
||||
<Dashboard
|
||||
onSelectView={handleSelectView}
|
||||
isAuthenticated={isAuthenticated}
|
||||
authLoading={authLoading}
|
||||
onAuthSuccess={handleAuthSuccess}
|
||||
@@ -231,7 +348,6 @@ function AppContent() {
|
||||
|
||||
{isAuthenticated && (
|
||||
<LeftSidebar
|
||||
onSelectView={handleSelectView}
|
||||
disabled={!isAuthenticated || authLoading}
|
||||
isAdmin={isAdmin}
|
||||
username={username}
|
||||
@@ -251,7 +367,6 @@ function AppContent() {
|
||||
{showHome && (
|
||||
<div className="h-screen w-full visible pointer-events-auto static overflow-hidden">
|
||||
<Dashboard
|
||||
onSelectView={handleSelectView}
|
||||
isAuthenticated={isAuthenticated}
|
||||
authLoading={authLoading}
|
||||
onAuthSuccess={handleAuthSuccess}
|
||||
@@ -265,7 +380,6 @@ function AppContent() {
|
||||
{showSshManager && (
|
||||
<div className="h-screen w-full visible pointer-events-auto static overflow-hidden">
|
||||
<HostManager
|
||||
onSelectView={handleSelectView}
|
||||
isTopbarOpen={isTopbarOpen}
|
||||
initialTab={currentTabData?.initialTab}
|
||||
hostConfig={currentTabData?.hostConfig}
|
||||
@@ -298,6 +412,16 @@ function AppContent() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showNetworkGraph && (
|
||||
<div className="h-screen w-full visible pointer-events-auto static overflow-hidden">
|
||||
<NetworkGraphCard
|
||||
isTopbarOpen={isTopbarOpen}
|
||||
rightSidebarOpen={rightSidebarOpen}
|
||||
rightSidebarWidth={rightSidebarWidth}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<TopNavbar
|
||||
isTopbarOpen={isTopbarOpen}
|
||||
setIsTopbarOpen={setIsTopbarOpen}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user