mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-06-10 05:04:35 +02:00
Compare commits
70 Commits
keyboard-s
...
1.4.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c86d46162 | ||
|
|
e87797418f | ||
|
|
78a3a2aeb9 | ||
|
|
e18cf7a245 | ||
|
|
50d5823ef5 | ||
|
|
518296f257 | ||
|
|
3217125dd3 | ||
|
|
00032854eb | ||
|
|
d99ddf6816 | ||
|
|
32c6e32e04 | ||
|
|
c55b1f3359 | ||
|
|
fabeae4180 | ||
|
|
5eed50961d | ||
|
|
bed0976eb9 | ||
|
|
70d92d9b07 | ||
|
|
fb4ba31504 | ||
|
|
152c5c71b1 | ||
|
|
fa369365a5 | ||
|
|
7345366ba7 | ||
|
|
6151ea7128 | ||
|
|
440ab26b69 | ||
|
|
caadd72ab2 | ||
|
|
d59d543ec1 | ||
|
|
58d1109510 | ||
|
|
9c52e25a6a | ||
|
|
62a44c5a09 | ||
|
|
e5fa40e903 | ||
|
|
8177083992 | ||
|
|
4bfd8e9f61 | ||
|
|
81e7d27ec8 | ||
|
|
f3fc0b5ac2 | ||
|
|
fb7bca436b | ||
|
|
c19a0ceba2 | ||
|
|
1f26e452fc | ||
|
|
0af6b7ede9 | ||
|
|
6ad56075d6 | ||
|
|
b81ae6c894 | ||
|
|
546e9f1702 | ||
|
|
bb51c6aa42 | ||
|
|
78e8134ad5 | ||
|
|
bc2c36215d | ||
|
|
377547fa11 | ||
|
|
472c4fc03a | ||
|
|
9f8f726f12 | ||
|
|
701a9c6cdc | ||
|
|
0d40cf2101 | ||
|
|
dd265dadd7 | ||
|
|
fe5a8cb2ad | ||
|
|
b6caa1a7b2 | ||
|
|
55c9707639 | ||
|
|
d8808baa83 | ||
|
|
1978020d27 | ||
|
|
0e4b91b8d7 | ||
|
|
9c831dc59b | ||
|
|
b757e97c11 | ||
|
|
9df486a689 | ||
|
|
72d27c3c47 | ||
|
|
6c20fc936d | ||
|
|
5439ec38b6 | ||
|
|
8b8a64f870 | ||
|
|
92509f8e8a | ||
|
|
0221634a4d | ||
|
|
9d1f86fbc6 | ||
|
|
f29dec7b13 | ||
|
|
d5d0b01266 | ||
|
|
5abae617dc | ||
|
|
52d62da002 | ||
|
|
253d632709 | ||
|
|
383a5c3478 | ||
|
|
d4a1430c27 |
12
.github/workflows/bridge.yml
vendored
12
.github/workflows/bridge.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -49,25 +49,25 @@ jobs:
|
||||
wget
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: bridge-${{ matrix.job.os }}
|
||||
|
||||
- name: Cache Bridge
|
||||
id: cache-bridge
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c # v3
|
||||
with:
|
||||
path: /tmp/flutter_rust_bridge
|
||||
key: vcpkg-${{ matrix.job.arch }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
cp ./flutter/macos/Runner/bridge_generated.h ./flutter/ios/Runner/bridge_generated.h
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: |
|
||||
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -29,13 +29,13 @@ jobs:
|
||||
# name: Ensure 'cargo fmt' has been run
|
||||
# runs-on: ubuntu-20.04
|
||||
# steps:
|
||||
# - uses: actions-rs/toolchain@v1
|
||||
# - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1
|
||||
# with:
|
||||
# toolchain: stable
|
||||
# default: true
|
||||
# profile: minimal
|
||||
# components: rustfmt
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
||||
# - run: cargo fmt -- --check
|
||||
|
||||
# min_version:
|
||||
@@ -43,24 +43,24 @@ jobs:
|
||||
# runs-on: ubuntu-20.04
|
||||
# steps:
|
||||
# - name: Checkout source code
|
||||
# uses: actions/checkout@v3
|
||||
# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
||||
# with:
|
||||
# submodules: recursive
|
||||
|
||||
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
|
||||
# uses: actions-rs/toolchain@v1
|
||||
# uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1
|
||||
# with:
|
||||
# toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
|
||||
# default: true
|
||||
# profile: minimal # minimal component installation (ie, no documentation)
|
||||
# components: clippy
|
||||
# - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
|
||||
# uses: actions-rs/cargo@v1
|
||||
# uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
|
||||
# with:
|
||||
# command: clippy
|
||||
# args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
|
||||
# - name: Run tests
|
||||
# uses: actions-rs/cargo@v1
|
||||
# uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
|
||||
# with:
|
||||
# command: test
|
||||
# args: --locked
|
||||
@@ -86,9 +86,9 @@ jobs:
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
if: runner.os == 'Linux'
|
||||
# jlumbroso/free-disk-space@main is used in .github\workflows\flutter-build.yml
|
||||
# jlumbroso/free-disk-space@v1.3.1 is used in .github\workflows\flutter-build.yml
|
||||
# But pinning to a specific version to avoid unexpected issues is preferred.
|
||||
uses: jlumbroso/free-disk-space@v1.3.1
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
@@ -99,14 +99,14 @@ jobs:
|
||||
swap-storage: false
|
||||
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
esac
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: /opt/artifacts/vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: ${{ matrix.job.target }}
|
||||
@@ -172,10 +172,10 @@ jobs:
|
||||
cargo -V
|
||||
rustc -V
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
|
||||
with:
|
||||
use-cross: ${{ matrix.job.use-cross }}
|
||||
command: build
|
||||
@@ -243,7 +243,7 @@ jobs:
|
||||
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run tests
|
||||
uses: actions-rs/cargo@v1
|
||||
uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
|
||||
with:
|
||||
use-cross: ${{ matrix.job.use-cross }}
|
||||
command: test
|
||||
|
||||
4
.github/workflows/clear-cache.yml
vendored
4
.github/workflows/clear-cache.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clear cache
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
||||
with:
|
||||
script: |
|
||||
console.log("About to clear")
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
console.log("Clear completed")
|
||||
|
||||
- name: Purge cache # Above seems not clear thouroughly, so add this to double clear
|
||||
uses: MyAlbum/purge-cache@v2
|
||||
uses: MyAlbum/purge-cache@881eb5957687193fa612bf74c0042adc78ea5e54 # v2
|
||||
with:
|
||||
accessed: true # Purge caches by their last accessed time (default)
|
||||
created: false # Purge caches by their created time (default)
|
||||
|
||||
2
.github/workflows/fdroid.yml
vendored
2
.github/workflows/fdroid.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Publish RustDesk version file
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: "fdroid-version"
|
||||
|
||||
213
.github/workflows/flutter-build.yml
vendored
213
.github/workflows/flutter-build.yml
vendored
@@ -39,7 +39,7 @@ env:
|
||||
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
|
||||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
|
||||
VERSION: "1.4.6"
|
||||
VERSION: "1.4.7"
|
||||
NDK_VERSION: "r28c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
@@ -81,30 +81,30 @@ jobs:
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2022, arch: aarch64 }
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
uses: KyleMayes/install-llvm-action@1a3da29f56261a1e1f937ec88f0856a9b8321d7e # v1
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
|
||||
uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # v2.12.0; https://github.com/subosito/flutter-action/issues/277
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
@@ -126,18 +126,18 @@ jobs:
|
||||
[[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.SCITER_RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: C:\vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -220,7 +220,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Download RustDeskTempTopMostWindow artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
with:
|
||||
name: topmostwindow-artifacts
|
||||
@@ -228,7 +228,7 @@ jobs:
|
||||
|
||||
- name: Upload unsigned
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-windows-${{ matrix.job.arch }}
|
||||
path: rustdesk
|
||||
@@ -253,7 +253,7 @@ jobs:
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.exe
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
|
||||
|
||||
- name: Build msi
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
@@ -272,7 +272,7 @@ jobs:
|
||||
BASE_URL=${{ env.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./SignOutput
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
prerelease: true
|
||||
@@ -302,35 +302,35 @@ jobs:
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2022 }
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: rustdesk-org/install-llvm-action-32bit@master
|
||||
uses: rustdesk-org/install-llvm-action-32bit@6aa7d9ad3df84dff01cd4596dd0fc880a7f47fce # no release tag; commit 2026-05-26
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: nightly-2023-10-13-${{ matrix.job.target }} # must use nightly here, because of abi_thiscall feature required
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}-sciter
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: C:\vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -363,7 +363,8 @@ jobs:
|
||||
python3 res/inline-sciter.py
|
||||
# Patch sciter x86
|
||||
sed -i 's/branch = "dyn"/branch = "dyn_x86"/g' ./Cargo.toml
|
||||
cargo build --features inline,vram,hwcodec --release --bins
|
||||
cargo update -p sciter-rs --precise 674e07d3066ca9a92ced3816203ab6b652629d1e
|
||||
cargo build --locked --features inline,vram,hwcodec --release --bins
|
||||
mkdir -p ./Release
|
||||
mv ./target/release/rustdesk.exe ./Release/rustdesk.exe
|
||||
curl -LJ -o ./Release/sciter.dll https://github.com/c-smile/sciter-sdk/raw/master/bin.win/x32/sciter.dll
|
||||
@@ -394,7 +395,7 @@ jobs:
|
||||
|
||||
- name: Upload unsigned
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-windows-${{ matrix.job.arch }}
|
||||
path: Release
|
||||
@@ -424,7 +425,7 @@ jobs:
|
||||
BASE_URL=${{ env.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./SignOutput/
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
prerelease: true
|
||||
@@ -449,7 +450,7 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
@@ -459,12 +460,12 @@ jobs:
|
||||
run: |
|
||||
brew install nasm yasm
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
@@ -475,7 +476,7 @@ jobs:
|
||||
[[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
@@ -499,19 +500,19 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache-ios
|
||||
key: ${{ matrix.job.target }}
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
@@ -519,10 +520,10 @@ jobs:
|
||||
- name: Build rustdesk lib
|
||||
run: |
|
||||
rustup target add ${{ matrix.job.target }}
|
||||
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
|
||||
cargo build --locked --features flutter,hwcodec --release --target aarch64-apple-ios --lib
|
||||
|
||||
- name: Upload liblibrustdesk.a Artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: liblibrustdesk.a
|
||||
path: target/aarch64-apple-ios/release/liblibrustdesk.a
|
||||
@@ -537,14 +538,14 @@ jobs:
|
||||
|
||||
# - name: Upload Artifacts
|
||||
# # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: actions/upload-artifact@master
|
||||
# uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
# with:
|
||||
# name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
|
||||
# path: flutter/build/ios/ipa/*.ipa
|
||||
|
||||
# - name: Publish ipa package
|
||||
# # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
# with:
|
||||
# prerelease: true
|
||||
# tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -577,20 +578,20 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Import the codesign cert
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071 # v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_P12_BASE64 }}
|
||||
p12-password: ${{ secrets.MACOS_P12_PASSWORD }}
|
||||
@@ -604,7 +605,7 @@ jobs:
|
||||
|
||||
- name: Import notarize key
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
uses: timheuer/base64-to-file@adaa40c0c581f276132199d4cf60afa07ce60eac # v1.2
|
||||
with:
|
||||
# https://gregoryszorc.com/docs/apple-codesign/stable/apple_codesign_rcodesign.html#notarizing-and-stapling
|
||||
fileName: rustdesk.json
|
||||
@@ -643,7 +644,7 @@ jobs:
|
||||
nasm --version
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
@@ -662,24 +663,24 @@ jobs:
|
||||
grep -n '_setFramesEnabledState(false);' ../packages/flutter/lib/src/scheduler/binding.dart
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.MAC_RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
@@ -731,7 +732,7 @@ jobs:
|
||||
|
||||
- name: Upload unsigned macOS app
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-macos-${{ matrix.job.arch }}
|
||||
path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.dmg # can not upload the directory directly or tar.gz, which destroy the link structure, causing the codesign failed
|
||||
@@ -763,7 +764,7 @@ jobs:
|
||||
|
||||
- name: Publish DMG package
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -779,25 +780,25 @@ jobs:
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-macos-x86_64
|
||||
path: ./
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-macos-aarch64
|
||||
path: ./
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-windows-x86_64
|
||||
path: ./windows-x86_64/
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-unsigned-windows-x86
|
||||
path: ./windows-x86/
|
||||
@@ -807,7 +808,7 @@ jobs:
|
||||
tar czf rustdesk-${{ env.VERSION }}-unsigned.tar.gz *.dmg windows-x86_64 windows-x86
|
||||
|
||||
- name: Publish unsigned app
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -844,7 +845,7 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
||||
with:
|
||||
tool-cache: false
|
||||
android: false
|
||||
@@ -855,7 +856,7 @@ jobs:
|
||||
swap-storage: false
|
||||
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
@@ -897,12 +898,12 @@ jobs:
|
||||
wget
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
|
||||
@@ -912,14 +913,14 @@ jobs:
|
||||
cd $(dirname $(dirname $(which flutter)))
|
||||
[[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- uses: nttld/setup-ndk@v1
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: ${{ env.NDK_VERSION }}
|
||||
add-to-path: true
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: /opt/artifacts/vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -954,18 +955,18 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache-android # TODO: drop '-android' part after caches are invalidated
|
||||
key: ${{ matrix.job.target }}
|
||||
@@ -1001,7 +1002,7 @@ jobs:
|
||||
esac
|
||||
|
||||
- name: Upload Rustdesk library to Artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: librustdesk.so.${{ matrix.job.target }}
|
||||
path: ./target/${{ matrix.job.target }}/release/liblibrustdesk.so
|
||||
@@ -1066,7 +1067,7 @@ jobs:
|
||||
echo "ANDROID_SIGN_TOOL_VERSION=$BUILD_TOOL_VERSION" >> $GITHUB_ENV
|
||||
echo Last build tool version is: $BUILD_TOOL_VERSION
|
||||
|
||||
- uses: r0adkll/sign-android-release@v1
|
||||
- uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
||||
name: Sign app APK
|
||||
if: env.ANDROID_SIGNING_KEY != null
|
||||
id: sign-rustdesk
|
||||
@@ -1082,14 +1083,14 @@ jobs:
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
|
||||
path: ${{steps.sign-rustdesk.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Publish signed apk package
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1098,7 +1099,7 @@ jobs:
|
||||
|
||||
- name: Publish unsigned apk package
|
||||
if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1116,7 +1117,7 @@ jobs:
|
||||
suffix: ""
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
||||
with:
|
||||
tool-cache: false
|
||||
android: false
|
||||
@@ -1127,7 +1128,7 @@ jobs:
|
||||
swap-storage: false
|
||||
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
@@ -1169,12 +1170,12 @@ jobs:
|
||||
wget
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
|
||||
@@ -1185,32 +1186,32 @@ jobs:
|
||||
[[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Download Rustdesk library from Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: librustdesk.so.aarch64-linux-android
|
||||
path: ./flutter/android/app/src/main/jniLibs/arm64-v8a
|
||||
|
||||
- name: Download Rustdesk library from Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: librustdesk.so.armv7-linux-androideabi
|
||||
path: ./flutter/android/app/src/main/jniLibs/armeabi-v7a
|
||||
|
||||
- name: Download Rustdesk library from Artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: librustdesk.so.x86_64-linux-android
|
||||
path: ./flutter/android/app/src/main/jniLibs/x86_64
|
||||
|
||||
- name: Download Rustdesk library from Artifacts
|
||||
if: ${{ env.reltype == 'debug' }}
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: librustdesk.so.i686-linux-android
|
||||
path: ./flutter/android/app/src/main/jniLibs/x86
|
||||
@@ -1250,7 +1251,7 @@ jobs:
|
||||
echo "ANDROID_SIGN_TOOL_VERSION=$BUILD_TOOL_VERSION" >> $GITHUB_ENV
|
||||
echo Last build tool version is: $BUILD_TOOL_VERSION
|
||||
|
||||
- uses: r0adkll/sign-android-release@v1
|
||||
- uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
||||
name: Sign app APK
|
||||
if: env.ANDROID_SIGNING_KEY != null
|
||||
id: sign-rustdesk
|
||||
@@ -1266,14 +1267,14 @@ jobs:
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
|
||||
path: ${{steps.sign-rustdesk.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Publish signed apk package
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1282,7 +1283,7 @@ jobs:
|
||||
|
||||
- name: Publish unsigned apk package
|
||||
if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1316,7 +1317,7 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
@@ -1334,13 +1335,13 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set Swap Space
|
||||
if: ${{ matrix.job.arch == 'x86_64' }}
|
||||
uses: pierotofy/set-swap-space@master
|
||||
uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
|
||||
@@ -1350,7 +1351,7 @@ jobs:
|
||||
free -m
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
@@ -1369,14 +1370,14 @@ jobs:
|
||||
|
||||
- name: Restore bridge files
|
||||
if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: /opt/artifacts/vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -1404,12 +1405,12 @@ jobs:
|
||||
|
||||
- name: Restore bridge files
|
||||
if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- uses: rustdesk-org/run-on-arch-action@amd64-support
|
||||
- uses: rustdesk-org/run-on-arch-action@d3fcfbb632b84cf7f6bc772bfaaa2c2f4f8789a8 # no release tag; commit 2026-05-26
|
||||
name: Build rustdesk
|
||||
id: vcpkg
|
||||
if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
|
||||
@@ -1491,7 +1492,7 @@ jobs:
|
||||
export JOBS=""
|
||||
fi
|
||||
echo $JOBS
|
||||
cargo build --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
|
||||
cargo build --locked --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
|
||||
rm -rf target/release/deps target/release/build
|
||||
rm -rf ~/.cargo
|
||||
|
||||
@@ -1583,7 +1584,7 @@ jobs:
|
||||
|
||||
- name: Publish debian/rpm package
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1592,7 +1593,7 @@ jobs:
|
||||
rustdesk-*.rpm
|
||||
|
||||
- name: Upload deb
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
|
||||
@@ -1611,7 +1612,7 @@ jobs:
|
||||
|
||||
- name: Build archlinux package
|
||||
if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: rustdesk-org/arch-makepkg-action@master
|
||||
uses: rustdesk-org/arch-makepkg-action@04200739ed1d0bf6f2188b6736b26a767c57a7f9 # no release tag; commit 2026-05-26
|
||||
with:
|
||||
packages:
|
||||
scripts: |
|
||||
@@ -1619,7 +1620,7 @@ jobs:
|
||||
|
||||
- name: Publish archlinux package
|
||||
if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1657,14 +1658,14 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -1682,7 +1683,7 @@ jobs:
|
||||
free -m
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.SCITER_RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
@@ -1693,7 +1694,7 @@ jobs:
|
||||
RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
|
||||
echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- uses: rustdesk-org/run-on-arch-action@amd64-support
|
||||
- uses: rustdesk-org/run-on-arch-action@d3fcfbb632b84cf7f6bc772bfaaa2c2f4f8789a8 # no release tag; commit 2026-05-26
|
||||
name: Build rustdesk sciter binary for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
@@ -1821,7 +1822,7 @@ jobs:
|
||||
# build rustdesk
|
||||
python3 ./res/inline-sciter.py
|
||||
export CARGO_INCREMENTAL=0
|
||||
cargo build --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
|
||||
cargo build --locked --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
|
||||
# make debian package
|
||||
mkdir -p ./Release
|
||||
mv ./target/release/rustdesk ./Release/rustdesk
|
||||
@@ -1839,7 +1840,7 @@ jobs:
|
||||
|
||||
- name: Publish debian package
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1847,7 +1848,7 @@ jobs:
|
||||
rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb
|
||||
|
||||
- name: Upload deb
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb
|
||||
@@ -1866,12 +1867,12 @@ jobs:
|
||||
- { target: aarch64-unknown-linux-gnu, arch: aarch64 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Download Binary
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
|
||||
path: .
|
||||
@@ -1896,7 +1897,7 @@ jobs:
|
||||
|
||||
- name: Publish appimage package
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -1939,12 +1940,12 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Download Binary
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.deb
|
||||
path: .
|
||||
@@ -1953,7 +1954,7 @@ jobs:
|
||||
run: |
|
||||
mv rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.deb flatpak/rustdesk.deb
|
||||
|
||||
- uses: rustdesk-org/run-on-arch-action@amd64-support
|
||||
- uses: rustdesk-org/run-on-arch-action@d3fcfbb632b84cf7f6bc772bfaaa2c2f4f8789a8 # no release tag; commit 2026-05-26
|
||||
name: Build rustdesk flatpak package for ${{ matrix.job.arch }}
|
||||
id: flatpak
|
||||
with:
|
||||
@@ -1981,7 +1982,7 @@ jobs:
|
||||
flatpak build-bundle ./repo rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.flatpak com.rustdesk.RustDesk
|
||||
|
||||
- name: Publish flatpak package
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -2000,7 +2001,7 @@ jobs:
|
||||
RELEASE_NAME: web-basic
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -2010,7 +2011,7 @@ jobs:
|
||||
sudo apt-get install -y wget npm
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
|
||||
uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # v2.12.0; https://github.com/subosito/flutter-action/issues/277
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
@@ -2054,7 +2055,7 @@ jobs:
|
||||
|
||||
- name: Publish web
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
|
||||
36
.github/workflows/playground.yml
vendored
36
.github/workflows/playground.yml
vendored
@@ -17,7 +17,7 @@ env:
|
||||
TAG_NAME: "nightly"
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||
VERSION: "1.4.6"
|
||||
VERSION: "1.4.7"
|
||||
NDK_VERSION: "r26d"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
@@ -79,21 +79,21 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
||||
with:
|
||||
ref: ${{ matrix.job.ref }}
|
||||
submodules: recursive
|
||||
|
||||
- name: Import the codesign cert
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071 # v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_P12_BASE64 }}
|
||||
p12-password: ${{ secrets.MACOS_P12_PASSWORD }}
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
|
||||
- name: Import notarize key
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
uses: timheuer/base64-to-file@adaa40c0c581f276132199d4cf60afa07ce60eac # v1.2
|
||||
with:
|
||||
# https://gregoryszorc.com/docs/apple-codesign/stable/apple_codesign_rcodesign.html#notarizing-and-stapling
|
||||
fileName: rustdesk.json
|
||||
@@ -129,19 +129,19 @@ jobs:
|
||||
brew install llvm create-dmg nasm pkg-config
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ matrix.job.flutter }}
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
$VCPKG_ROOT/vcpkg install --x-install-root="$VCPKG_ROOT/installed"
|
||||
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
uses: lukka/run-vcpkg@8a5116de2b552d6fc8894e9774aacaf2e5db4823 # v7 2026-05-26
|
||||
if: false
|
||||
with:
|
||||
setupOnly: true
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Publish DMG package
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@@ -247,7 +247,7 @@ jobs:
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
||||
with:
|
||||
ref: ${{ matrix.job.ref }}
|
||||
submodules: recursive
|
||||
@@ -290,13 +290,13 @@ jobs:
|
||||
wget
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
components: "rustfmt"
|
||||
@@ -310,14 +310,14 @@ jobs:
|
||||
pushd flutter ; flutter pub get ; popd
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
|
||||
- uses: nttld/setup-ndk@v1
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: ${{ env.NDK_VERSION }}
|
||||
add-to-path: true
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: /opt/artifacts/vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
@@ -395,7 +395,7 @@ jobs:
|
||||
mkdir -p signed-apk; pushd signed-apk
|
||||
mv ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk ./rustdesk-test-${{ matrix.job.ref }}-${{ matrix.job.ndk }}.apk
|
||||
|
||||
- uses: r0adkll/sign-android-release@v1
|
||||
- uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
||||
name: Sign app APK
|
||||
if: env.ANDROID_SIGNING_KEY != null
|
||||
id: sign-rustdesk
|
||||
@@ -410,7 +410,7 @@ jobs:
|
||||
BUILD_TOOLS_VERSION: "30.0.2"
|
||||
|
||||
- name: Publish signed apk package
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
build_output_dir: RustDeskTempTopMostWindow/WindowInjection/${{ inputs.platform }}/${{ inputs.configuration }}
|
||||
steps:
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
|
||||
|
||||
- name: Download the source code
|
||||
run: |
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
msbuild ${{ env.project_path }} -p:Configuration=${{ inputs.configuration }} -p:Platform=${{ inputs.platform }} /p:TargetVersion=${{ inputs.target_version }}
|
||||
|
||||
- name: Archive build artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
with:
|
||||
name: topmostwindow-artifacts
|
||||
|
||||
85
.github/workflows/wf-cliprdr-ci.yml
vendored
Normal file
85
.github/workflows/wf-cliprdr-ci.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: wf-cliprdr CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- "libs/clipboard/src/windows/**"
|
||||
- "tests/test_invariant_wf_cliprdr.c"
|
||||
- ".github/workflows/wf-cliprdr-ci.yml"
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "libs/clipboard/src/windows/**"
|
||||
- "tests/test_invariant_wf_cliprdr.c"
|
||||
- ".github/workflows/wf-cliprdr-ci.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: wf_cliprdr invariant test
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up MSVC
|
||||
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: Setup vcpkg with GitHub Actions binary cache
|
||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
||||
with:
|
||||
vcpkgDirectory: C:\vcpkg
|
||||
doNotCache: false
|
||||
|
||||
- name: Install vcpkg dependency
|
||||
shell: pwsh
|
||||
run: |
|
||||
& "$env:VCPKG_ROOT\vcpkg.exe" install check:x64-windows --classic --x-install-root="$env:VCPKG_ROOT\installed"
|
||||
|
||||
- name: Build test
|
||||
shell: pwsh
|
||||
run: |
|
||||
$testRoot = Join-Path $env:GITHUB_WORKSPACE 'build\wf-cliprdr'
|
||||
New-Item -ItemType Directory -Force $testRoot | Out-Null
|
||||
|
||||
$testSource = (($env:GITHUB_WORKSPACE -replace '\\', '/') + '/tests/test_invariant_wf_cliprdr.c')
|
||||
$cmakeLists = @(
|
||||
'cmake_minimum_required(VERSION 3.20)'
|
||||
'project(test_invariant_wf_cliprdr C)'
|
||||
''
|
||||
'set(CMAKE_C_STANDARD 11)'
|
||||
'set(CMAKE_C_STANDARD_REQUIRED ON)'
|
||||
'set(CMAKE_C_EXTENSIONS OFF)'
|
||||
''
|
||||
'find_package(check CONFIG REQUIRED)'
|
||||
''
|
||||
'add_executable(test_invariant_wf_cliprdr'
|
||||
' "TEST_SOURCE"'
|
||||
')'
|
||||
''
|
||||
'target_link_libraries(test_invariant_wf_cliprdr PRIVATE'
|
||||
' $<$<TARGET_EXISTS:Check::check>:Check::check>'
|
||||
' $<$<NOT:$<TARGET_EXISTS:Check::check>>:Check::checkShared>'
|
||||
')'
|
||||
) -join [Environment]::NewLine
|
||||
$cmakeLists.Replace('TEST_SOURCE', $testSource) | Set-Content -NoNewline (Join-Path $testRoot 'CMakeLists.txt')
|
||||
|
||||
cmake -S $testRoot -B (Join-Path $testRoot 'out') -G "Visual Studio 17 2022" -A x64 -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows
|
||||
cmake --build (Join-Path $testRoot 'out') --config Release
|
||||
|
||||
- name: Run test
|
||||
shell: pwsh
|
||||
run: .\build\wf-cliprdr\out\Release\test_invariant_wf_cliprdr.exe
|
||||
24
AGENTS.md
24
AGENTS.md
@@ -60,3 +60,27 @@
|
||||
* Do not refactor unrelated code.
|
||||
* Do not make formatting-only changes.
|
||||
* Keep naming/style consistent with nearby code.
|
||||
|
||||
## Localization (`src/lang/*.rs`)
|
||||
|
||||
Each file is a `HashMap<key, translation>`. Layout:
|
||||
|
||||
* `template.rs` is the master list of every key. **Never edit it** as part of translation work.
|
||||
* `en.rs` holds only the keys whose English display text differs from the key itself.
|
||||
* Every other file (`de.rs`, `fr.rs`, …) carries the full key set; an untranslated entry has an empty value: `("key", "")`.
|
||||
|
||||
### Finding the English source for a key
|
||||
|
||||
When filling an empty entry, determine the source English text with this rule:
|
||||
|
||||
* If `key` exists in `en.rs` **with a non-empty value**, that value is the source text (look it up in `en.rs`).
|
||||
* Otherwise the **key string itself is the source text** (the key is already plain English).
|
||||
|
||||
Then translate that source into the file's target language (infer the language from the file's existing non-empty entries / filename).
|
||||
|
||||
### Translation hygiene
|
||||
|
||||
* Only fill empty values. Never change keys, and never touch existing non-empty translations.
|
||||
* Preserve placeholders (`{}`) and escape sequences (`\n`, `\"`) exactly as in the source.
|
||||
* Do not translate brand or technical tokens: `RustDesk`, `Socks5`, `TLS`, `UAC`, `Wayland`, `X11`, `TCP`, `UDP`, `2FA`, `RDP`, `D3D`, etc.
|
||||
* Copy URL values (e.g. `doc_*` keys) verbatim from `en.rs`.
|
||||
|
||||
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -5996,8 +5996,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-tokio-ipc"
|
||||
version = "0.7.3-5"
|
||||
source = "git+https://github.com/rustdesk-org/parity-tokio-ipc#c8c8bbcbabf9be1201c53afb0269b92b9b02d291"
|
||||
version = "0.7.3-6"
|
||||
source = "git+https://github.com/rustdesk-org/parity-tokio-ipc#d0ae39bffe5d5a3e8d82a1b6bcb1ca5a9b2f1c01"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"libc",
|
||||
@@ -7270,7 +7270,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustdesk"
|
||||
version = "1.4.6"
|
||||
version = "1.4.7"
|
||||
dependencies = [
|
||||
"android-wakelock",
|
||||
"android_logger",
|
||||
@@ -7385,7 +7385,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustdesk-portable-packer"
|
||||
version = "1.4.6"
|
||||
version = "1.4.7"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"dirs 5.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustdesk"
|
||||
version = "1.4.6"
|
||||
version = "1.4.7"
|
||||
authors = ["rustdesk <info@rustdesk.com>"]
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
|
||||
@@ -18,7 +18,7 @@ AppDir:
|
||||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.4.6
|
||||
version: 1.4.7
|
||||
exec: usr/share/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
|
||||
@@ -18,7 +18,7 @@ AppDir:
|
||||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.4.6
|
||||
version: 1.4.7
|
||||
exec: usr/share/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
|
||||
24
build.py
24
build.py
@@ -172,7 +172,7 @@ def generate_build_script_for_docker():
|
||||
# flutter_rust_bridge
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd
|
||||
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd
|
||||
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . --locked && popd
|
||||
pushd flutter && flutter pub get && popd
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
# install vcpkg
|
||||
@@ -299,7 +299,7 @@ Version: %s
|
||||
Architecture: %s
|
||||
Maintainer: rustdesk <info@rustdesk.com>
|
||||
Homepage: https://rustdesk.com
|
||||
Depends: libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s
|
||||
Depends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s
|
||||
Recommends: libayatana-appindicator3-1
|
||||
Description: A remote control software.
|
||||
|
||||
@@ -317,7 +317,7 @@ def ffi_bindgen_function_refactor():
|
||||
|
||||
def build_flutter_deb(version, features):
|
||||
if not skip_cargo:
|
||||
system2(f'cargo build --features {features} --lib --release')
|
||||
system2(f'cargo build --locked --features {features} --lib --release')
|
||||
ffi_bindgen_function_refactor()
|
||||
os.chdir('flutter')
|
||||
system2('flutter build linux --release')
|
||||
@@ -405,7 +405,7 @@ def build_flutter_dmg(version, features):
|
||||
if not skip_cargo:
|
||||
# set minimum osx build target, now is 10.14, which is the same as the flutter xcode project
|
||||
system2(
|
||||
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --release')
|
||||
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --locked --features {features} --release')
|
||||
# copy dylib
|
||||
system2(
|
||||
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
|
||||
@@ -422,7 +422,7 @@ def build_flutter_dmg(version, features):
|
||||
|
||||
def build_flutter_arch_manjaro(version, features):
|
||||
if not skip_cargo:
|
||||
system2(f'cargo build --features {features} --lib --release')
|
||||
system2(f'cargo build --locked --features {features} --lib --release')
|
||||
ffi_bindgen_function_refactor()
|
||||
os.chdir('flutter')
|
||||
system2('flutter build linux --release')
|
||||
@@ -433,7 +433,7 @@ def build_flutter_arch_manjaro(version, features):
|
||||
|
||||
def build_flutter_windows(version, features, skip_portable_pack):
|
||||
if not skip_cargo:
|
||||
system2(f'cargo build --features {features} --lib --release')
|
||||
system2(f'cargo build --locked --features {features} --lib --release')
|
||||
if not os.path.exists("target/release/librustdesk.dll"):
|
||||
print("cargo build failed, please check rust source code.")
|
||||
exit(-1)
|
||||
@@ -489,13 +489,13 @@ def main():
|
||||
if windows:
|
||||
# build virtual display dynamic library
|
||||
os.chdir('libs/virtual_display/dylib')
|
||||
system2('cargo build --release')
|
||||
system2('cargo build --locked --release')
|
||||
os.chdir('../../..')
|
||||
|
||||
if flutter:
|
||||
build_flutter_windows(version, features, args.skip_portable_pack)
|
||||
return
|
||||
system2('cargo build --release --features ' + features)
|
||||
system2('cargo build --locked --release --features ' + features)
|
||||
# system2('upx.exe target/release/rustdesk.exe')
|
||||
system2('mv target/release/rustdesk.exe target/release/RustDesk.exe')
|
||||
pa = os.environ.get('P')
|
||||
@@ -519,7 +519,7 @@ def main():
|
||||
if flutter:
|
||||
build_flutter_arch_manjaro(version, features)
|
||||
else:
|
||||
system2('cargo build --release --features ' + features)
|
||||
system2('cargo build --locked --release --features ' + features)
|
||||
system2('git checkout src/ui/common.tis')
|
||||
system2('strip target/release/rustdesk')
|
||||
system2('ln -s res/pacman_install && ln -s res/PKGBUILD')
|
||||
@@ -528,7 +528,7 @@ def main():
|
||||
version, version))
|
||||
# pacman -U ./rustdesk.pkg.tar.zst
|
||||
elif os.path.isfile('/usr/bin/yum'):
|
||||
system2('cargo build --release --features ' + features)
|
||||
system2('cargo build --locked --release --features ' + features)
|
||||
system2('strip target/release/rustdesk')
|
||||
system2(
|
||||
"sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version)
|
||||
@@ -538,7 +538,7 @@ def main():
|
||||
version, version))
|
||||
# yum localinstall rustdesk.rpm
|
||||
elif os.path.isfile('/usr/bin/zypper'):
|
||||
system2('cargo build --release --features ' + features)
|
||||
system2('cargo build --locked --release --features ' + features)
|
||||
system2('strip target/release/rustdesk')
|
||||
system2(
|
||||
"sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version)
|
||||
@@ -557,7 +557,7 @@ def main():
|
||||
# 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb')
|
||||
build_flutter_deb(version, features)
|
||||
else:
|
||||
system2('cargo bundle --release --features ' + features)
|
||||
system2('cargo --locked bundle --release --features ' + features)
|
||||
if osx:
|
||||
system2(
|
||||
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<p align="center">
|
||||
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#빌드를 위한 원시 단계">빌드</a> •
|
||||
<a href="#Docker로 빌드하는 방법">Docker</a> •
|
||||
<a href="#파일 구조">구조</a> •
|
||||
<a href="#스크린샷">스냇샷</a><br>
|
||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>] | [<a href="README-NO.md">Norsk</a>]<br>
|
||||
<a href="#빌드를_위한_원시_단계">빌드</a> •
|
||||
<a href="#Docker로_빌드하는_방법">Docker</a> •
|
||||
<a href="#파일_구조">구조</a> •
|
||||
<a href="#스크린샷">스냅샷</a><br>
|
||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>] | [<a href="README-NO.md">Norsk</a>] | [<a href="README-RO.md">Română</a>]<br>
|
||||
<b>이 README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> 및 <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk 문서</a>를 귀하의 모국어로 번역하는 데 도움이 필요합니다</b>
|
||||
</p>
|
||||
|
||||
@@ -46,9 +46,9 @@ Sciter 동적 라이브러리를 직접 다운로드하세요.
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## 빌드를 위한 원시 단계
|
||||
## 빌드를_위한_원시_단계
|
||||
|
||||
- Rust 개발 환경과 C++ 빌드 환경을 준비합니다
|
||||
- Rust 개발 환경과 C++ 빌드 환경 준비
|
||||
|
||||
- [vcpkg](https://github.com/microsoft/vcpkg)를 설치하고 `VCPKG_ROOT` 환경 변수를 올바르게 설정합니다
|
||||
|
||||
@@ -125,7 +125,7 @@ mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
## Docker로 빌드하는 방법
|
||||
## Docker로_빌드하는_방법
|
||||
|
||||
먼저 리포지토리를 복제하고 Docker 컨테이너를 빌드합니다:
|
||||
|
||||
@@ -156,7 +156,7 @@ target/release/rustdesk
|
||||
|
||||
RustDesk 리포지토리의 루트에서 이러한 명령을 실행하고 있는지 확인하세요. 그렇지 않으면 응용 프로그램이 필요한 리소스를 찾지 못할 수 있습니다. 또한 `install` 또는 `run` 과 같은 다른 cargo 하위 명령은 호스트가 아닌 컨테이너 내부에 프로그램을 설치하거나 실행하므로 현재 이 방법을 통해 지원되지 않는다는 점에 유의하세요.
|
||||
|
||||
## 파일 구조
|
||||
## 파일_구조
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 비디오 코덱, 구성, tcp/udp wrapper, protobuf, 파일 전송을 위한 fs 함수 및 기타 유틸리티 함수
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: 화면 캡쳐
|
||||
|
||||
@@ -1,55 +1,82 @@
|
||||
<p align="center">
|
||||
<img src="../res/logo-header.svg" alt="RustDesk - Seu desktop remoto"><br>
|
||||
<a href="#servidores-públicos-grátis">Servidores</a> •
|
||||
<a href="#compilação-crua">Compilar</a> •
|
||||
<a href="#como-compilar-com-docker">Docker</a> •
|
||||
<a href="#compilar">Compilar</a> •
|
||||
<a href="#como-compilar-com-o-docker">Docker</a> •
|
||||
<a href="#estrutura-de-arquivos">Estrutura</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
|
||||
<b>Precisamos de sua ajuda para traduzir este README e a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI do RustDesk</a> para sua língua nativa</b>
|
||||
<a href="#capturas-de-tela">Capturas de Tela</a><br>
|
||||
[<a href="../README.md">Inglês</a>] | [<a href="docs/README-UA.md">Ucraniano</a>] | [<a href="docs/README-CS.md">Tcheco</a>] | [<a href="docs/README-ZH.md">Chinês</a>] | [<a href="docs/README-HU.md">Húngaro</a>] | [<a href="docs/README-ES.md">Espanhol</a>] | [<a href="docs/README-FA.md">Persa</a>] | [<a href="docs/README-FR.md">Francês</a>] | [<a href="docs/README-DE.md">Alemão</a>] | [<a href="docs/README-PL.md">Polonês</a>] | [<a href="docs/README-ID.md">Indonésio</a>] | [<a href="docs/README-FI.md">Finlandês</a>] | [<a href="docs/README-ML.md">Malaiala</a>] | [<a href="docs/README-JP.md">Japonês</a>] | [<a href="docs/README-NL.md">Holandês</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Russo</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">Coreano</a>] | [<a href="docs/README-AR.md">Árabe</a>] | [<a href="docs/README-VN.md">Vietnamita</a>] | [<a href="docs/README-DA.md">Dinamarquês</a>] | [<a href="docs/README-GR.md">Grego</a>] | [<a href="docs/README-TR.md">Turco</a>] | [<a href="docs/README-NO.md">Norueguês</a>] | [<a href="docs/README-RO.md">Romeno</a>]<br>
|
||||
<b>Precisamos da sua ajuda para traduzir este README, a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">Interface do RustDesk</a> e a <a href="https://github.com/rustdesk/doc.rustdesk.com">Documentação do RustDesk</a> para o seu idioma nativo</b>
|
||||
</p>
|
||||
|
||||
> [!Caution]
|
||||
> **Aviso de Isenção de Responsabilidade por Uso Indevido:** <br>
|
||||
> Os desenvolvedores do RustDesk não toleram ou apoiam qualquer uso antiético ou ilegal deste software. O uso indevido, como acesso não autorizado, controle ou invasão de privacidade, viola estritamente nossas diretrizes. Os autores não são responsáveis por qualquer uso indevido do aplicativo.
|
||||
|
||||
|
||||
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
|
||||
|
||||
[](https://rustdesk.com/pricing.html)
|
||||
[](https://rustdesk.com/pricing.html)
|
||||
|
||||
Mais um software de desktop remoto, escrito em Rust. Funciona por padrão, sem necessidade de configuração. Você tem completo controle de seus dados, sem se preocupar com segurança. Você pode usar nossos servidores de rendezvous/relay, [configurar seu próprio](https://rustdesk.com/server), ou [escrever seu próprio servidor de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
Mais uma solução de desktop remoto, escrita em Rust. Funciona imediatamente, sem necessidade de configuração. Você tem controle total dos seus dados, sem preocupações com segurança. Você pode usar nosso servidor de conexão/retransmissão (rendezvous/relay), [configurar o seu próprio](https://rustdesk.com/server) ou [escrever seu próprio servidor de conexão/retransmissão](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk acolhe contribuições de todos. Leia [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) para ver como começar.
|
||||

|
||||
|
||||
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
|
||||
O RustDesk acolhe a contribuição de todos. Veja [CONTRIBUTING.md](docs/CONTRIBUTING.md) para ajuda em como começar.
|
||||
|
||||
[**Perguntas Frequentes (FAQ)**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||
|
||||
[**DOWNLOAD DOS BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
[**VERSÕES NIGHTLY (EM DESENVOLVIMENTO)**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||
|
||||
[<img src="https://f-droid.org/badge/get-it-on.png"
|
||||
alt="Baixe no F-Droid"
|
||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||
[<img src="https://flathub.org/api/badge?svg&locale=en"
|
||||
alt="Baixe no Flathub"
|
||||
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
|
||||
|
||||
## Dependências
|
||||
|
||||
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
|
||||
As versões de desktop usam Flutter ou Sciter (descontinuado) para a interface gráfica (GUI). Este tutorial é apenas para o Sciter, por ser mais fácil e amigável para começar. Verifique nosso [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) para instruções de compilação da versão em Flutter.
|
||||
|
||||
Por favor, faça o download da biblioteca dinâmica do Sciter por conta própria.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Compilação crua
|
||||
## Passos básicos para compilar
|
||||
|
||||
- Prepare seu ambiente de desenvolvimento Rust e ambiente de compilação C++
|
||||
- Prepare seu ambiente de desenvolvimento Rust e o ambiente de compilação C++
|
||||
|
||||
- Instale [vcpkg](https://github.com/microsoft/vcpkg), e configure a variável de ambiente `VCPKG_ROOT` corretamente
|
||||
- Instale o [vcpkg](https://github.com/microsoft/vcpkg) e configure a variável de ambiente `VCPKG_ROOT` corretamente
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus aom
|
||||
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static`
|
||||
- Linux/macOS: `vcpkg install libvpx libyuv opus aom`
|
||||
|
||||
- Execute `cargo run`
|
||||
|
||||
## Como compilar no Linux
|
||||
## [Compilar](https://rustdesk.com/docs/en/dev/build/)
|
||||
|
||||
## Como Compilar no Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
|
||||
```
|
||||
|
||||
### openSUSE Tumbleweed
|
||||
|
||||
```sh
|
||||
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
@@ -58,7 +85,7 @@ sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
|
||||
```
|
||||
|
||||
### Instale vcpkg
|
||||
### Instalar o vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
@@ -70,7 +97,7 @@ export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||
```
|
||||
|
||||
### Conserte libvpx (Para o Fedora)
|
||||
### Corrigir o libvpx (Para Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
@@ -83,12 +110,12 @@ cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Compile
|
||||
### Compilar
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
@@ -96,57 +123,57 @@ mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
## Como compilar com Docker
|
||||
## Como compilar com o Docker
|
||||
|
||||
Comece clonando o repositório e montando o container docker:
|
||||
Comece clonando o repositório e construindo o contêiner Docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
git submodule update --init --recursive
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Então, sempre que precisar compilar a aplicação, execute este comando:
|
||||
Depois, cada vez que precisar compilar o aplicativo, execute o seguinte comando:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Note que a primeira compilação pode demorar mais antes que as dependências sejam armazenadas em cache, as compilações subsequentes serão mais rápidas. Adicionalmente, se você precisar especificar argumentos diferentes para o comando de compilação, você pode fazê-lo ao final do comando na posição do `<OPTIONAL-ARGS>`. Por exemplo, se você gostaria de compilar uma versão de release otimizada, você executaria o comando acima seguido de `--release`. O executável gerado estará disponível no diretório alvo no seu sistema, e pode ser executado com:
|
||||
Note que a primeira compilação pode demorar mais até que as dependências sejam armazenadas em cache; as compilações subsequentes serão mais rápidas. Além disso, se você precisar especificar argumentos diferentes para o comando de compilação, poderá fazê-lo ao final do comando na posição `<ARGUMENTOS-OPCIONAIS>`. Por exemplo, se você quiser compilar uma versão de lançamento (release) otimizada, executaria o comando acima seguido de `--release`. O executável resultante estará disponível na pasta `target` do seu sistema e pode ser executado com:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Ou, se estiver rodando um executável de release:
|
||||
Ou, se estiver executando o executável de lançamento:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Por favor verifique que está executando estes comandos da raiz do repositório do RustDesk, senão a aplicação pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo como `install` ou `run` não são suportados atualmente via este método, já que eles iriam instalar ou rodar o programa dentro do container ao invés do host.
|
||||
Certifique-se de executar esses comandos a partir da raiz do repositório do RustDesk, do contrário o aplicativo pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo, como `install` ou `run`, não são suportados atualmente por este método, pois instalariam ou executariam o programa dentro do contêiner em vez de no sistema hospedeiro.
|
||||
|
||||
## Estrutura de arquivos
|
||||
## Estrutura de Arquivos
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configurações, wrapper de tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos, e outras funções utilitárias
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico a cada plataforma
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo, e conexões de rede
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: iniciar uma conexão "peer to peer"
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicação com [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguardar pela conexão remota direta (TCP hole punching) ou conexão indireta (relayed)
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico a cada plataforma
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configuração, encapsulador (wrapper) tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos e algumas outras funções utilitárias.
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela.
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico de cada plataforma.
|
||||
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: implementação de copiar e colar arquivos para Windows, Linux e macOS.
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interface Sciter antiga (descontinuada).
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo e conexões de rede.
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: inicia uma conexão direta (peer connection).
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica-se com o [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguarda por conexão remota direta (perfuração de túnel TCP / hole punching) ou retransmitida.
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma.
|
||||
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: código Flutter para desktop e dispositivos móveis.
|
||||
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript para o cliente web do Flutter.
|
||||
|
||||
> [!Cuidadob]
|
||||
> **Aviso de uso indevido:** <br>
|
||||
> Os desenvolvedores do RustDesk não aprovam nem apoiam qualquer uso antiético ou ilegal deste software. O uso indevido, como acesso não autorizado, controle ou invasão de privacidade, é estritamente contra nossas diretrizes. Os autores não são responsáveis por qualquer uso indevido da aplicação.
|
||||
## Capturas de Tela
|
||||
|
||||
## Screenshots
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
@@ -33,4 +33,4 @@ if [ -z $release ]; then
|
||||
fi
|
||||
set -f
|
||||
#shellcheck disable=2086
|
||||
VCPKG_ROOT=/vcpkg cargo build $argv
|
||||
VCPKG_ROOT=/vcpkg cargo build --locked $argv
|
||||
|
||||
@@ -460,6 +460,7 @@ build)
|
||||
--target "${RUST_TARGET}" \
|
||||
--bindgen \
|
||||
build \
|
||||
--locked \
|
||||
--release \
|
||||
--features "${RUSTDESK_FEATURES}"
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
|
||||
cargo build --locked --features flutter,hwcodec --release --target aarch64-apple-ios --lib
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
cargo build --features flutter --release --target x86_64-apple-ios --lib
|
||||
cargo build --locked --features flutter --release --target x86_64-apple-ios --lib
|
||||
|
||||
@@ -716,6 +716,17 @@ closeConnection({String? id}) {
|
||||
stateGlobal.isInMainPage = true;
|
||||
} else {
|
||||
final controller = Get.find<DesktopTabController>();
|
||||
if (controller.tabType == DesktopTabType.terminal &&
|
||||
controller.onCloseWindow != null) {
|
||||
// Terminal windows are scoped to one peer. The optional id passed to
|
||||
// closeConnection() is that peer id, not a terminal tab key
|
||||
// (${peerId}_${terminalId}). Closing from terminal dialogs should close
|
||||
// the peer's whole terminal window, including all terminal tabs.
|
||||
unawaited(controller.onCloseWindow!().catchError((e, _) {
|
||||
debugPrint('[closeConnection] Failed to close terminal window: $e');
|
||||
}));
|
||||
return;
|
||||
}
|
||||
controller.closeBy(id);
|
||||
}
|
||||
}
|
||||
@@ -4179,8 +4190,7 @@ Widget? buildAvatarWidget({
|
||||
width: size,
|
||||
height: size,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) =>
|
||||
fallback ?? SizedBox.shrink(),
|
||||
errorBuilder: (_, __, ___) => fallback ?? SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,70 @@ import 'package:flutter_hbb/models/model.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
bool isEditOsPassword = false;
|
||||
const String kPeerOptionAllowWaylandKeyboard = 'allow-wayland-keyboard';
|
||||
const String kWaylandKeyboardIssueUrl =
|
||||
'https://github.com/rustdesk/rustdesk/issues/14586';
|
||||
final Set<String> _waylandKeyboardPromptSuppressedConnectionIds = <String>{};
|
||||
|
||||
Future<bool> openWaylandKeyboardIssueUrl() {
|
||||
return launchUrl(
|
||||
Uri.parse(kWaylandKeyboardIssueUrl),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
}
|
||||
|
||||
bool isWaylandKeyboardPromptSuppressedForConnection(String connectionId) {
|
||||
return _waylandKeyboardPromptSuppressedConnectionIds.contains(connectionId);
|
||||
}
|
||||
|
||||
void setWaylandKeyboardPromptSuppressedForConnection(
|
||||
String connectionId, bool suppressed) {
|
||||
if (suppressed) {
|
||||
_waylandKeyboardPromptSuppressedConnectionIds.add(connectionId);
|
||||
} else {
|
||||
_waylandKeyboardPromptSuppressedConnectionIds.remove(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
void clearWaylandKeyboardPromptSuppressedForConnection(String connectionId) {
|
||||
_waylandKeyboardPromptSuppressedConnectionIds.remove(connectionId);
|
||||
}
|
||||
|
||||
bool shouldShowWaylandKeyboardPrompt({
|
||||
required String connectionId,
|
||||
required bool isWaylandPeer,
|
||||
required bool allowWaylandKeyboardRemembered,
|
||||
}) {
|
||||
return isWaylandPeer &&
|
||||
!allowWaylandKeyboardRemembered &&
|
||||
!isWaylandKeyboardPromptSuppressedForConnection(connectionId);
|
||||
}
|
||||
|
||||
Widget waylandKeyboardScopeChip(BuildContext context, String text) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: colorScheme.primary.withOpacity(0.35)),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// macOS privacy mode blacks out all online displays, so switching the remote
|
||||
// display does not weaken the local privacy protection.
|
||||
bool allowDisplaySwitchInPrivacyMode(PeerInfo pi) {
|
||||
return pi.platform == kPeerPlatformMacOS;
|
||||
}
|
||||
|
||||
class TTextMenu {
|
||||
final Widget child;
|
||||
@@ -87,12 +149,179 @@ handleOsPasswordAction(
|
||||
}
|
||||
}
|
||||
|
||||
void showWaylandKeyboardInputWarningDialog(
|
||||
{required String id,
|
||||
required String connectionId,
|
||||
required FFI ffi,
|
||||
required Future<void> Function() onEnable}) {
|
||||
bool remember = false;
|
||||
bool consentInProgress = false;
|
||||
bool dialogClosed = false;
|
||||
|
||||
final dialogFuture = ffi.dialogManager.show((setState, close, context) {
|
||||
void safeSetState(VoidCallback fn) {
|
||||
if (dialogClosed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setState(fn);
|
||||
} catch (e) {
|
||||
debugPrint('Ignore setState after dialog disposal: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void closeDialog() {
|
||||
if (dialogClosed) {
|
||||
return;
|
||||
}
|
||||
dialogClosed = true;
|
||||
close();
|
||||
}
|
||||
|
||||
Future<void> enableAndContinue() async {
|
||||
if (consentInProgress || dialogClosed) {
|
||||
return;
|
||||
}
|
||||
consentInProgress = true;
|
||||
safeSetState(() {});
|
||||
try {
|
||||
await onEnable();
|
||||
} catch (e, st) {
|
||||
debugPrint('Failed to enable Wayland keyboard input consent: $e');
|
||||
debugPrintStack(stackTrace: st);
|
||||
consentInProgress = false;
|
||||
safeSetState(() {});
|
||||
return;
|
||||
}
|
||||
|
||||
ffi.inputModel.keyboardInputAllowed = true;
|
||||
var rememberPersisted = true;
|
||||
if (remember) {
|
||||
try {
|
||||
await bind.mainSetPeerOption(
|
||||
id: id,
|
||||
key: kPeerOptionAllowWaylandKeyboard,
|
||||
value: bool2option(kPeerOptionAllowWaylandKeyboard, true));
|
||||
} catch (e) {
|
||||
rememberPersisted = false;
|
||||
debugPrint('Failed to persist Wayland keyboard input consent: $e');
|
||||
}
|
||||
}
|
||||
// Always suppress prompt for current connection after explicit consent.
|
||||
setWaylandKeyboardPromptSuppressedForConnection(connectionId, true);
|
||||
closeDialog();
|
||||
if (remember && !rememberPersisted) {
|
||||
// It's a rare edge case that persisting the user's choice fails.
|
||||
// Failed to persist the user's choice, but still allow keyboard input for current session.
|
||||
showToast(translate('Failed'));
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
if (consentInProgress) {
|
||||
return;
|
||||
}
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: null,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
msgboxContent(
|
||||
'',
|
||||
'wayland-keyboard-input-disabled-tip',
|
||||
'wayland-keyboard-input-consent-tip',
|
||||
),
|
||||
SizedBox(height: isMobile ? 2 : 6),
|
||||
if (isMobile) ...[
|
||||
Text(
|
||||
translate('wayland-keyboard-input-applies-to-tip'),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||
).marginOnly(bottom: 6),
|
||||
Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 6,
|
||||
children: [
|
||||
waylandKeyboardScopeChip(
|
||||
context, translate('Send clipboard keystrokes')),
|
||||
waylandKeyboardScopeChip(
|
||||
context, translate('wayland-soft-keyboard-input-label')),
|
||||
],
|
||||
).marginOnly(bottom: 10),
|
||||
],
|
||||
TextButton(
|
||||
onPressed: consentInProgress
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
final opened = await openWaylandKeyboardIssueUrl();
|
||||
if (!opened) {
|
||||
// Opening this optional help link almost never fails in
|
||||
// normal desktop environments. Keep the result handled
|
||||
// for review hygiene, but avoid a low-value user toast.
|
||||
debugPrint('Failed to open Wayland keyboard issue URL');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Failed to open Wayland keyboard issue URL: $e');
|
||||
}
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.blue,
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: Size.zero,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: Text(
|
||||
translate('Why this happens'),
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
).marginOnly(bottom: 6),
|
||||
CheckboxListTile(
|
||||
value: remember,
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(translate('remember-wayland-keyboard-choice-tip')),
|
||||
onChanged: consentInProgress
|
||||
? null
|
||||
: (v) {
|
||||
safeSetState(() => remember = v == true);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
dialogButton(
|
||||
'Cancel',
|
||||
onPressed: consentInProgress ? null : cancel,
|
||||
isOutline: true,
|
||||
),
|
||||
dialogButton(
|
||||
'OK',
|
||||
onPressed:
|
||||
consentInProgress ? null : () => unawaited(enableAndContinue()),
|
||||
),
|
||||
],
|
||||
onCancel: consentInProgress ? null : cancel,
|
||||
onSubmit: consentInProgress ? null : () => unawaited(enableAndContinue()),
|
||||
);
|
||||
}, clickMaskDismiss: false, backDismiss: false);
|
||||
unawaited(dialogFuture.whenComplete(() => dialogClosed = true));
|
||||
}
|
||||
|
||||
List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
final ffiModel = ffi.ffiModel;
|
||||
final pi = ffiModel.pi;
|
||||
final perms = ffiModel.permissions;
|
||||
final sessionId = ffi.sessionId;
|
||||
final isDefaultConn = ffi.connType == ConnType.defaultConn;
|
||||
final isWaylandPeer = pi.platform == kPeerPlatformLinux && pi.isWayland;
|
||||
|
||||
List<TTextMenu> v = [];
|
||||
// elevation
|
||||
@@ -142,11 +371,60 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
v.add(TTextMenu(
|
||||
child: Text(translate('Send clipboard keystrokes')),
|
||||
onPressed: () async {
|
||||
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
if (data != null && data.text != null) {
|
||||
bind.sessionInputString(
|
||||
sessionId: sessionId, value: data.text ?? "");
|
||||
Future<void> sendClipboardKeystrokes() async {
|
||||
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
if (data != null && data.text != null) {
|
||||
bind.sessionInputString(
|
||||
sessionId: sessionId, value: data.text ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
final allowWaylandKeyboard =
|
||||
mainGetPeerBoolOptionSync(id, kPeerOptionAllowWaylandKeyboard);
|
||||
if (shouldShowWaylandKeyboardPrompt(
|
||||
connectionId: sessionId.toString(),
|
||||
isWaylandPeer: isWaylandPeer,
|
||||
allowWaylandKeyboardRemembered: allowWaylandKeyboard,
|
||||
)) {
|
||||
ffi.inputModel.keyboardInputAllowed = false;
|
||||
showWaylandKeyboardInputWarningDialog(
|
||||
id: id,
|
||||
connectionId: sessionId.toString(),
|
||||
ffi: ffi,
|
||||
onEnable: sendClipboardKeystrokes,
|
||||
);
|
||||
return;
|
||||
}
|
||||
await sendClipboardKeystrokes();
|
||||
}));
|
||||
}
|
||||
if (isDefaultConn &&
|
||||
isWaylandPeer &&
|
||||
(mainGetPeerBoolOptionSync(id, kPeerOptionAllowWaylandKeyboard) ||
|
||||
isWaylandKeyboardPromptSuppressedForConnection(
|
||||
sessionId.toString()))) {
|
||||
v.add(TTextMenu(
|
||||
child: Text(translate('wayland-keyboard-input-reset-choice-tip')),
|
||||
onPressed: () async {
|
||||
var persistedCleared = false;
|
||||
try {
|
||||
await bind.mainSetPeerOption(
|
||||
id: id,
|
||||
key: kPeerOptionAllowWaylandKeyboard,
|
||||
value: bool2option(kPeerOptionAllowWaylandKeyboard, false));
|
||||
persistedCleared = true;
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Failed to clear persisted Wayland keyboard permission: $e');
|
||||
} finally {
|
||||
clearWaylandKeyboardPromptSuppressedForConnection(
|
||||
sessionId.toString());
|
||||
ffi.inputModel.keyboardInputAllowed = false;
|
||||
if (isMobile) {
|
||||
await ffi.invokeMethod("enable_soft_keyboard", false);
|
||||
}
|
||||
}
|
||||
showToast(translate(persistedCleared ? 'Successful' : 'Failed'));
|
||||
}));
|
||||
}
|
||||
// reset canvas
|
||||
@@ -684,8 +962,9 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
|
||||
child: Text(translate('Lock after session end'))));
|
||||
}
|
||||
|
||||
final privacyModeState = PrivacyModeState.find(id);
|
||||
if (pi.isSupportMultiDisplay &&
|
||||
PrivacyModeState.find(id).isEmpty &&
|
||||
(privacyModeState.isEmpty || allowDisplaySwitchInPrivacyMode(pi)) &&
|
||||
pi.displaysCount.value > 1 &&
|
||||
bind.mainGetUserDefaultOption(key: kKeyShowMonitorsToolbar) == 'Y') {
|
||||
final value =
|
||||
@@ -759,15 +1038,26 @@ List<TToggleMenu> toolbarPrivacyMode(
|
||||
final ffiModel = ffi.ffiModel;
|
||||
final pi = ffiModel.pi;
|
||||
final sessionId = ffi.sessionId;
|
||||
final hasPrivacyModePermission =
|
||||
ffiModel.permissions['privacy_mode'] != false;
|
||||
|
||||
// Backend revocation already attempts to turn privacy mode off.
|
||||
// Still keep this menu when privacy mode is active, so users can turn it off
|
||||
// if there is a sync delay, version mismatch, or off attempt failure.
|
||||
if (!hasPrivacyModePermission && privacyModeState.isEmpty) {
|
||||
return []; // No permission and not active, hide options.
|
||||
}
|
||||
|
||||
getDefaultMenu(Future<void> Function(SessionID sid, String opt) toggleFunc) {
|
||||
final enabled = !ffi.ffiModel.viewOnly;
|
||||
final enabled = !ffiModel.viewOnly &&
|
||||
(hasPrivacyModePermission || privacyModeState.isNotEmpty);
|
||||
return TToggleMenu(
|
||||
value: privacyModeState.isNotEmpty,
|
||||
onChanged: enabled
|
||||
? (value) {
|
||||
if (value == null) return;
|
||||
if (ffiModel.pi.currentDisplay != 0 &&
|
||||
if (!allowDisplaySwitchInPrivacyMode(pi) &&
|
||||
ffiModel.pi.currentDisplay != 0 &&
|
||||
ffiModel.pi.currentDisplay != kAllDisplayValue) {
|
||||
msgBox(
|
||||
sessionId,
|
||||
@@ -810,18 +1100,29 @@ List<TToggleMenu> toolbarPrivacyMode(
|
||||
})
|
||||
];
|
||||
} else {
|
||||
return privacyModeImpls.map((e) {
|
||||
final visibleImpls = hasPrivacyModePermission
|
||||
? privacyModeImpls
|
||||
: privacyModeImpls.where((e) {
|
||||
final implKey = (e as List<dynamic>)[0] as String;
|
||||
return privacyModeState.value == implKey;
|
||||
}).toList();
|
||||
return visibleImpls.map((e) {
|
||||
final implKey = (e as List<dynamic>)[0] as String;
|
||||
final implName = (e)[1] as String;
|
||||
final enabled = !ffiModel.viewOnly &&
|
||||
(hasPrivacyModePermission || privacyModeState.value == implKey);
|
||||
return TToggleMenu(
|
||||
child: Text(translate(implName)),
|
||||
value: privacyModeState.value == implKey,
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
togglePrivacyModeTime = DateTime.now();
|
||||
bind.sessionTogglePrivacyMode(
|
||||
sessionId: sessionId, implKey: implKey, on: value);
|
||||
});
|
||||
onChanged: enabled
|
||||
? (value) {
|
||||
if (value == null) return;
|
||||
if (value && !hasPrivacyModePermission) return;
|
||||
togglePrivacyModeTime = DateTime.now();
|
||||
bind.sessionTogglePrivacyMode(
|
||||
sessionId: sessionId, implKey: implKey, on: value);
|
||||
}
|
||||
: null);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ const String kOptionTerminalPersistent = "terminal-persistent";
|
||||
const String kOptionEnableTunnel = "enable-tunnel";
|
||||
const String kOptionEnableRemoteRestart = "enable-remote-restart";
|
||||
const String kOptionEnableBlockInput = "enable-block-input";
|
||||
const String kOptionEnablePrivacyMode = "enable-privacy-mode";
|
||||
const String kOptionEnablePermChangeInAcceptWindow =
|
||||
"enable-perm-change-in-accept-window";
|
||||
const String kOptionAllowRemoteConfigModification =
|
||||
"allow-remote-config-modification";
|
||||
const String kOptionVerificationMethod = "verification-method";
|
||||
@@ -139,6 +142,10 @@ const String kOptionSwapLeftRightMouse = "swap-left-right-mouse";
|
||||
const String kOptionCodecPreference = "codec-preference";
|
||||
const String kOptionRemoteMenubarDragLeft = "remote-menubar-drag-left";
|
||||
const String kOptionRemoteMenubarDragRight = "remote-menubar-drag-right";
|
||||
const String kOptionRemoteMenubarEdge = "remote-menubar-edge";
|
||||
const String kOptionRemoteMenubarFraction = "remote-menubar-frac";
|
||||
const String kOptionAllowMultiEdgeToolbarDock =
|
||||
"allow-multi-edge-toolbar-dock";
|
||||
const String kOptionHideAbTagsPanel = "hideAbTagsPanel";
|
||||
const String kOptionRemoteMenubarState = "remoteMenubarState";
|
||||
const String kOptionPeerSorting = "peer-sorting";
|
||||
|
||||
@@ -488,6 +488,16 @@ class _GeneralState extends State<_General> {
|
||||
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
|
||||
kOptionEnableConfirmClosingTabs,
|
||||
isServer: false),
|
||||
if (!bind.isIncomingOnly())
|
||||
_OptionCheckBox(
|
||||
context,
|
||||
'allow-remote-toolbar-docking-any-edge',
|
||||
kOptionAllowMultiEdgeToolbarDock,
|
||||
isServer: false,
|
||||
update: (_) {
|
||||
reloadAllWindows();
|
||||
},
|
||||
),
|
||||
_OptionCheckBox(context, 'Adaptive bitrate', kOptionEnableAbr),
|
||||
if (!isWeb) wallpaper(),
|
||||
if (!isWeb && !bind.isIncomingOnly()) ...[
|
||||
@@ -1062,6 +1072,10 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
||||
_OptionCheckBox(context, 'Enable blocking user input',
|
||||
kOptionEnableBlockInput,
|
||||
enabled: enabled, fakeValue: fakeValue),
|
||||
if (bind.mainSupportedPrivacyModeImpls() != '[]')
|
||||
_OptionCheckBox(
|
||||
context, 'Enable privacy mode', kOptionEnablePrivacyMode,
|
||||
enabled: enabled, fakeValue: fakeValue),
|
||||
_OptionCheckBox(context, 'Enable remote configuration modification',
|
||||
kOptionAllowRemoteConfigModification,
|
||||
enabled: enabled, fakeValue: fakeValue),
|
||||
|
||||
@@ -101,6 +101,9 @@ class _RemotePageState extends State<RemotePage>
|
||||
Function(bool)? _onEnterOrLeaveImage4Toolbar;
|
||||
|
||||
late FFI _ffi;
|
||||
Worker? _waylandKeyboardModeWorker;
|
||||
bool _waylandKeyboardModeNormalized = false;
|
||||
bool _waylandKeyboardModeNormalizing = false;
|
||||
|
||||
SessionID get sessionId => _ffi.sessionId;
|
||||
|
||||
@@ -178,6 +181,48 @@ class _RemotePageState extends State<RemotePage>
|
||||
// Register callback to cancel debounce timer when relative mouse mode is disabled
|
||||
_ffi.inputModel.onRelativeMouseModeDisabled =
|
||||
_cancelPointerLockCenterDebounceTimer;
|
||||
|
||||
_waylandKeyboardModeWorker = ever(_ffi.ffiModel.pi.isSet, (bool isSet) {
|
||||
if (isSet) {
|
||||
unawaited(_normalizeWaylandKeyboardModeIfNeeded());
|
||||
}
|
||||
});
|
||||
if (_ffi.ffiModel.pi.isSet.value) {
|
||||
unawaited(_normalizeWaylandKeyboardModeIfNeeded());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _normalizeWaylandKeyboardModeIfNeeded() async {
|
||||
if (!mounted ||
|
||||
_waylandKeyboardModeNormalized ||
|
||||
_waylandKeyboardModeNormalizing) {
|
||||
return;
|
||||
}
|
||||
_waylandKeyboardModeNormalizing = true;
|
||||
try {
|
||||
final pi = _ffi.ffiModel.pi;
|
||||
if (pi.platform != kPeerPlatformLinux || !pi.isWayland) return;
|
||||
final mapSupported = bind.sessionIsKeyboardModeSupported(
|
||||
sessionId: sessionId, mode: kKeyMapMode);
|
||||
if (!mapSupported) return;
|
||||
final current = await bind.sessionGetKeyboardMode(sessionId: sessionId);
|
||||
if (!mounted) return;
|
||||
if (current == kKeyMapMode) {
|
||||
_waylandKeyboardModeNormalized = true;
|
||||
return;
|
||||
}
|
||||
await bind.sessionSetKeyboardMode(
|
||||
sessionId: sessionId, value: kKeyMapMode);
|
||||
if (!mounted) return;
|
||||
await _ffi.inputModel.updateKeyboardMode();
|
||||
if (!mounted) return;
|
||||
_waylandKeyboardModeNormalized = true;
|
||||
} catch (e, st) {
|
||||
debugPrint('Failed to normalize Wayland keyboard mode: $e');
|
||||
debugPrintStack(stackTrace: st);
|
||||
} finally {
|
||||
_waylandKeyboardModeNormalizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel the pointer lock center debounce timer
|
||||
@@ -318,6 +363,7 @@ class _RemotePageState extends State<RemotePage>
|
||||
|
||||
_pointerLockCenterDebounceTimer?.cancel();
|
||||
_pointerLockCenterDebounceTimer = null;
|
||||
_waylandKeyboardModeWorker?.dispose();
|
||||
// Clear callback reference to prevent memory leaks and stale references
|
||||
_ffi.inputModel.onRelativeMouseModeDisabled = null;
|
||||
// Relative mouse mode cleanup is centralized in FFI.close(closeSession: ...).
|
||||
@@ -331,6 +377,9 @@ class _RemotePageState extends State<RemotePage>
|
||||
_ffi.imageModel.disposeImage();
|
||||
_ffi.cursorModel.disposeImages();
|
||||
_rawKeyFocusNode.dispose();
|
||||
if (closeSession) {
|
||||
clearWaylandKeyboardPromptSuppressedForConnection(sessionId.toString());
|
||||
}
|
||||
await _ffi.close(closeSession: closeSession);
|
||||
_timer?.cancel();
|
||||
_ffi.dialogManager.dismissAll();
|
||||
|
||||
@@ -610,19 +610,24 @@ class _PrivilegeBoard extends StatefulWidget {
|
||||
class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
late final client = widget.client;
|
||||
Widget buildPermissionIcon(bool enabled, IconData iconData,
|
||||
Function(bool)? onTap, String tooltipText) {
|
||||
Function(bool)? onTap, String tooltipText,
|
||||
{required bool canModify}) {
|
||||
return Tooltip(
|
||||
message: "$tooltipText: ${enabled ? "ON" : "OFF"}",
|
||||
waitDuration: Duration.zero,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: enabled ? MyTheme.accent : Colors.grey[700],
|
||||
color: enabled
|
||||
? (canModify ? MyTheme.accent : MyTheme.accent.withOpacity(0.6))
|
||||
: Colors.grey[700],
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () =>
|
||||
checkClickTime(widget.client.id, () => onTap?.call(!enabled)),
|
||||
onTap: canModify
|
||||
? () =>
|
||||
checkClickTime(widget.client.id, () => onTap?.call(!enabled))
|
||||
: null,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
@@ -643,6 +648,9 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
Widget build(BuildContext context) {
|
||||
final crossAxisCount = 4;
|
||||
final spacing = 10.0;
|
||||
final canModifyPermission =
|
||||
bind.mainGetBuildinOption(key: kOptionEnablePermChangeInAcceptWindow) !=
|
||||
'N';
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 160.0,
|
||||
@@ -689,6 +697,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable audio'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.recording,
|
||||
@@ -703,6 +712,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable recording session'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
]
|
||||
: [
|
||||
@@ -719,6 +729,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable keyboard/mouse'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.clipboard,
|
||||
@@ -733,6 +744,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable clipboard'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.audio,
|
||||
@@ -747,6 +759,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable audio'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.file,
|
||||
@@ -761,6 +774,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable file copy and paste'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.restart,
|
||||
@@ -775,6 +789,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable remote restart'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
buildPermissionIcon(
|
||||
client.recording,
|
||||
@@ -789,6 +804,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable recording session'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
// only windows support block input
|
||||
if (isWindows)
|
||||
@@ -805,6 +821,23 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
||||
});
|
||||
},
|
||||
translate('Enable blocking user input'),
|
||||
canModify: canModifyPermission,
|
||||
),
|
||||
if (bind.mainSupportedPrivacyModeImpls() != '[]')
|
||||
buildPermissionIcon(
|
||||
client.privacyMode,
|
||||
Icons.visibility_off,
|
||||
(enabled) {
|
||||
bind.cmSwitchPermission(
|
||||
connId: client.id,
|
||||
name: "privacy_mode",
|
||||
enabled: enabled);
|
||||
setState(() {
|
||||
client.privacyMode = enabled;
|
||||
});
|
||||
},
|
||||
translate('Enable privacy mode'),
|
||||
canModify: canModifyPermission,
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -27,6 +27,7 @@ class TerminalPage extends StatefulWidget {
|
||||
final bool? isSharedPassword;
|
||||
final String? connToken;
|
||||
final int terminalId;
|
||||
|
||||
/// Tab key for focus management, passed from parent to avoid duplicate construction
|
||||
final String tabKey;
|
||||
final SimpleWrapper<State<TerminalPage>?> _lastState = SimpleWrapper(null);
|
||||
@@ -43,6 +44,9 @@ class TerminalPage extends StatefulWidget {
|
||||
|
||||
class _TerminalPageState extends State<TerminalPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
static const EdgeInsets _defaultTerminalPadding =
|
||||
EdgeInsets.symmetric(horizontal: 5.0, vertical: 2.0);
|
||||
|
||||
late FFI _ffi;
|
||||
late TerminalModel _terminalModel;
|
||||
double? _cellHeight;
|
||||
@@ -155,13 +159,27 @@ class _TerminalPageState extends State<TerminalPage>
|
||||
// extra space left after dividing the available height by the height of a single
|
||||
// terminal row (`_cellHeight`) and distributing it evenly as top and bottom padding.
|
||||
EdgeInsets _calculatePadding(double heightPx) {
|
||||
if (_cellHeight == null) {
|
||||
return const EdgeInsets.symmetric(horizontal: 5.0, vertical: 2.0);
|
||||
final cellHeight = _cellHeight;
|
||||
if (!heightPx.isFinite ||
|
||||
heightPx <= 0 ||
|
||||
cellHeight == null ||
|
||||
!cellHeight.isFinite ||
|
||||
cellHeight <= 0) {
|
||||
return _defaultTerminalPadding;
|
||||
}
|
||||
final rows = (heightPx / cellHeight).floor();
|
||||
if (rows <= 0) {
|
||||
return _defaultTerminalPadding;
|
||||
}
|
||||
final extraSpace = heightPx - rows * cellHeight;
|
||||
if (!extraSpace.isFinite || extraSpace < 0) {
|
||||
return _defaultTerminalPadding;
|
||||
}
|
||||
final rows = (heightPx / _cellHeight!).floor();
|
||||
final extraSpace = heightPx - rows * _cellHeight!;
|
||||
final topBottom = extraSpace / 2.0;
|
||||
return EdgeInsets.symmetric(horizontal: 5.0, vertical: topBottom);
|
||||
return EdgeInsets.symmetric(
|
||||
horizontal: _defaultTerminalPadding.horizontal / 2,
|
||||
vertical: topBottom,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -46,6 +46,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
.setTitle(getWindowNameWithId(id));
|
||||
};
|
||||
tabController.onRemoved = (_, id) => onRemoveId(id);
|
||||
tabController.onCloseWindow = _closeWindowFromConnection;
|
||||
final terminalId = params['terminalId'] ?? _nextTerminalId++;
|
||||
tabController.add(_createTerminalTab(
|
||||
peerId: params['id'],
|
||||
@@ -144,6 +145,8 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
_windowClosing = true;
|
||||
final tabKeys = tabController.state.value.tabs.map((t) => t.key).toList();
|
||||
// Remove all UI tabs immediately (same instant behavior as the old tabController.clear())
|
||||
// Keep the cleanup target lookup below synchronous before its first await:
|
||||
// it relies on the current frame still retaining each TerminalPage's FFI/model.
|
||||
tabController.clear();
|
||||
// Run session cleanup in parallel with bounded timeout (closeTerminal() has internal 3s timeout).
|
||||
// Skip tabs already being closed by a concurrent _closeTab() to avoid duplicate FFI calls.
|
||||
@@ -368,8 +371,34 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
final persistentSessions =
|
||||
args['persistent_sessions'] as List<dynamic>? ?? [];
|
||||
final sortedSessions = persistentSessions.whereType<int>().toList()..sort();
|
||||
var peerId = args['peer_id'] as String? ?? '';
|
||||
if (peerId.isEmpty) {
|
||||
if (tabController.state.value.tabs.isEmpty ||
|
||||
tabController.state.value.selected >=
|
||||
tabController.state.value.tabs.length) {
|
||||
debugPrint('[TerminalTabPage] Skip restore: no selected tab');
|
||||
return;
|
||||
}
|
||||
final currentTab = tabController.state.value.selectedTabInfo;
|
||||
final parsed = _parseTabKey(currentTab.key);
|
||||
if (parsed == null) return;
|
||||
peerId = parsed.$1;
|
||||
}
|
||||
final existingTerminalIds = tabController.state.value.tabs
|
||||
.map((tab) => _parseTabKey(tab.key))
|
||||
.where((parsed) => parsed != null && parsed.$1 == peerId)
|
||||
.map((parsed) => parsed!.$2)
|
||||
.toSet();
|
||||
if (existingTerminalIds.isEmpty) {
|
||||
debugPrint(
|
||||
'[TerminalTabPage] Skip restore: no seed tab for peer $peerId');
|
||||
return;
|
||||
}
|
||||
for (final terminalId in sortedSessions) {
|
||||
_addNewTerminalForCurrentPeer(terminalId: terminalId);
|
||||
if (!existingTerminalIds.add(terminalId)) {
|
||||
continue;
|
||||
}
|
||||
_addNewTerminal(peerId, terminalId: terminalId);
|
||||
// A delay is required to ensure the UI has sufficient time to update
|
||||
// before adding the next terminal. Without this delay, `_TerminalPageState::dispose()`
|
||||
// may be called prematurely while the tab widget is still in the tab controller.
|
||||
@@ -546,6 +575,11 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _closeWindowFromConnection() async {
|
||||
await _closeAllTabs();
|
||||
await WindowController.fromWindowId(windowId()).close();
|
||||
}
|
||||
|
||||
int windowId() {
|
||||
return widget.params["windowId"];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -99,6 +99,7 @@ class DesktopTabController {
|
||||
/// index, key
|
||||
Function(int, String)? onRemoved;
|
||||
Function(String)? onSelected;
|
||||
Future<void> Function()? onCloseWindow;
|
||||
|
||||
DesktopTabController(
|
||||
{required this.tabType, this.onRemoved, this.onSelected});
|
||||
@@ -592,13 +593,13 @@ class _DesktopTabState extends State<DesktopTab>
|
||||
}
|
||||
|
||||
Widget _buildBar() {
|
||||
final isIncomingHomePage = bind.isIncomingOnly() && isInHomePage();
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
// custom double tap handler
|
||||
onTap: !(bind.isIncomingOnly() && isInHomePage()) &&
|
||||
showMaximize
|
||||
onTap: !isIncomingHomePage && showMaximize
|
||||
? () {
|
||||
final current = DateTime.now().millisecondsSinceEpoch;
|
||||
final elapsed = current - _lastClickTime;
|
||||
@@ -609,7 +610,7 @@ class _DesktopTabState extends State<DesktopTab>
|
||||
.then((value) => stateGlobal.setMaximized(value));
|
||||
}
|
||||
}
|
||||
: null,
|
||||
: (isIncomingHomePage ? () {} : null), // Keep tap recognizer for Windows touch.
|
||||
onPanStart: (_) => startDragging(isMainWindow),
|
||||
onPanCancel: () {
|
||||
// We want to disable dragging of the tab area in the tab bar.
|
||||
|
||||
@@ -27,6 +27,7 @@ import 'common.dart';
|
||||
import 'consts.dart';
|
||||
import 'mobile/pages/home_page.dart';
|
||||
import 'mobile/pages/server_page.dart';
|
||||
import 'mobile/widgets/deploy_dialog.dart';
|
||||
import 'models/platform_model.dart';
|
||||
|
||||
import 'package:flutter_hbb/plugin/handlers.dart'
|
||||
@@ -575,6 +576,14 @@ _registerEventHandler() {
|
||||
NativeUiHandler.instance.onEvent(evt);
|
||||
});
|
||||
}
|
||||
if (isAndroid) {
|
||||
platformFFI.registerEventHandler(
|
||||
'android_needs_deploy', 'android_needs_deploy', (_) async {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showDeployPromptDialog();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget keyListenerBuilder(BuildContext context, Widget? child) {
|
||||
|
||||
@@ -75,6 +75,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
final FocusNode _physicalFocusNode = FocusNode();
|
||||
var _showEdit = false; // use soft keyboard
|
||||
|
||||
Worker? _waylandKeyboardGateWorker;
|
||||
bool _waylandKeyboardGateInitialized = false;
|
||||
|
||||
InputModel get inputModel => gFFI.inputModel;
|
||||
SessionID get sessionId => gFFI.sessionId;
|
||||
|
||||
@@ -121,11 +124,33 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
isKeyboardVisible: keyboardVisibilityController.isVisible);
|
||||
});
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
inputModel.keyboardInputAllowed = true;
|
||||
|
||||
// Wayland sessions may use clipboard-based text input on the controlled side.
|
||||
// Require explicit user confirmation before allowing soft-keyboard and
|
||||
// clipboard-assisted text input. Physical keyboard events are not gated here.
|
||||
_waylandKeyboardGateWorker = ever(gFFI.ffiModel.pi.isSet, (bool isSet) {
|
||||
if (isSet) {
|
||||
_initWaylandKeyboardGateIfNeeded();
|
||||
}
|
||||
});
|
||||
if (gFFI.ffiModel.pi.isSet.value) {
|
||||
_initWaylandKeyboardGateIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
// Close the session up-front. `gFFI.close()` below only calls `sessionClose`
|
||||
// after several awaits (canvas save, image update, the `enable_soft_keyboard`
|
||||
// platform call), so if the app is backgrounded while this page is disposing,
|
||||
// dispose can be suspended before reaching it and the connection is never torn
|
||||
// down. The reconnect then re-attaches to the leaked session and is stuck on
|
||||
// "Connecting...". Dispatching it here makes teardown happen synchronously on
|
||||
// pop; the `sessionClose` in `gFFI.close()` becomes a no-op once removed.
|
||||
unawaited(bind.sessionClose(sessionId: sessionId));
|
||||
// https://github.com/flutter/flutter/issues/64935
|
||||
super.dispose();
|
||||
gFFI.dialogManager.hideMobileActionsOverlay(store: false);
|
||||
@@ -135,6 +160,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
await gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||
_mobileFocusNode.dispose();
|
||||
_physicalFocusNode.dispose();
|
||||
clearWaylandKeyboardPromptSuppressedForConnection(sessionId.toString());
|
||||
_waylandKeyboardGateWorker?.dispose();
|
||||
inputModel.keyboardInputAllowed = true;
|
||||
await gFFI.close();
|
||||
_timer?.cancel();
|
||||
_iosKeyboardWorkaroundTimer?.cancel();
|
||||
@@ -163,6 +191,40 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
gFFI.invokeMethod("try_sync_clipboard");
|
||||
}
|
||||
|
||||
bool _shouldGateKeyboardForWayland() {
|
||||
if (!(isAndroid || isIOS)) return false;
|
||||
final pi = gFFI.ffiModel.pi;
|
||||
return pi.platform == kPeerPlatformLinux && pi.isWayland;
|
||||
}
|
||||
|
||||
void _initWaylandKeyboardGateIfNeeded() {
|
||||
if (!mounted) return;
|
||||
if (_waylandKeyboardGateInitialized) return;
|
||||
if (!_shouldGateKeyboardForWayland()) return;
|
||||
|
||||
_waylandKeyboardGateInitialized = true;
|
||||
|
||||
final allowWaylandKeyboard =
|
||||
mainGetPeerBoolOptionSync(widget.id, kPeerOptionAllowWaylandKeyboard);
|
||||
if (!shouldShowWaylandKeyboardPrompt(
|
||||
connectionId: sessionId.toString(),
|
||||
isWaylandPeer: _shouldGateKeyboardForWayland(),
|
||||
allowWaylandKeyboardRemembered: allowWaylandKeyboard,
|
||||
)) {
|
||||
inputModel.keyboardInputAllowed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
inputModel.keyboardInputAllowed = false;
|
||||
|
||||
// Ensure soft keyboard is not active before user confirms.
|
||||
_showEdit = false;
|
||||
gFFI.invokeMethod("enable_soft_keyboard", false);
|
||||
_mobileFocusNode.unfocus();
|
||||
_physicalFocusNode.requestFocus();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
// to-do: It should be better to use transparent color instead of the bgColor.
|
||||
// But for now, the transparent color will cause the canvas to be white.
|
||||
// I'm sure that the white color is caused by the Overlay widget in BlockableOverlay.
|
||||
@@ -294,7 +356,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
content == '【】')) {
|
||||
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input
|
||||
bind.sessionInputString(sessionId: sessionId, value: content);
|
||||
openKeyboard();
|
||||
_openKeyboardUnlocked();
|
||||
return;
|
||||
}
|
||||
bind.sessionInputString(sessionId: sessionId, value: content);
|
||||
@@ -306,6 +368,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
|
||||
// handle mobile virtual keyboard
|
||||
void handleSoftKeyboardInput(String newValue) {
|
||||
if (!inputModel.keyboardInputAllowed) {
|
||||
return;
|
||||
}
|
||||
if (isIOS) {
|
||||
_handleIOSSoftKeyboardInput(newValue);
|
||||
} else {
|
||||
@@ -314,6 +379,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void inputChar(String char) {
|
||||
if (!inputModel.keyboardInputAllowed) {
|
||||
return;
|
||||
}
|
||||
if (char == '\n') {
|
||||
char = 'VK_RETURN';
|
||||
} else if (char == ' ') {
|
||||
@@ -323,6 +391,29 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void openKeyboard() {
|
||||
final allowWaylandKeyboard =
|
||||
mainGetPeerBoolOptionSync(widget.id, kPeerOptionAllowWaylandKeyboard);
|
||||
if (shouldShowWaylandKeyboardPrompt(
|
||||
connectionId: sessionId.toString(),
|
||||
isWaylandPeer: _shouldGateKeyboardForWayland(),
|
||||
allowWaylandKeyboardRemembered: allowWaylandKeyboard,
|
||||
)) {
|
||||
inputModel.keyboardInputAllowed = false;
|
||||
showWaylandKeyboardInputWarningDialog(
|
||||
id: widget.id,
|
||||
connectionId: sessionId.toString(),
|
||||
ffi: gFFI,
|
||||
onEnable: () async {
|
||||
_openKeyboardUnlocked();
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
_openKeyboardUnlocked();
|
||||
}
|
||||
|
||||
void _openKeyboardUnlocked() {
|
||||
inputModel.keyboardInputAllowed = true;
|
||||
gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||
// destroy first, so that our _value trick can work
|
||||
_value = initText;
|
||||
@@ -1183,7 +1274,8 @@ void showOptions(
|
||||
List<TToggleMenu> privacyModeList = [];
|
||||
// privacy mode
|
||||
final privacyModeState = PrivacyModeState.find(id);
|
||||
if (gFFI.ffiModel.keyboard && gFFI.ffiModel.pi.features.privacyMode) {
|
||||
if ((gFFI.ffiModel.pi.features.privacyMode && gFFI.ffiModel.keyboard) ||
|
||||
privacyModeState.isNotEmpty) {
|
||||
privacyModeList = toolbarPrivacyMode(privacyModeState, context, id, gFFI);
|
||||
if (privacyModeList.length == 1) {
|
||||
displayToggles.add(privacyModeList[0]);
|
||||
|
||||
@@ -583,9 +583,16 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
Widget build(BuildContext context) {
|
||||
final serverModel = Provider.of<ServerModel>(context);
|
||||
final hasAudioPermission = androidVersion >= 30;
|
||||
final hideStopService =
|
||||
isAndroid &&
|
||||
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
|
||||
final hideStopService = isAndroid &&
|
||||
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
|
||||
final allowPermChangeInAcceptWindow = option2bool(
|
||||
kOptionEnablePermChangeInAcceptWindow,
|
||||
bind.mainGetBuildinOption(
|
||||
key: kOptionEnablePermChangeInAcceptWindow,
|
||||
));
|
||||
final permissionChangeLocked = isAndroid &&
|
||||
serverModel.clients.any((c) => !c.disconnected) &&
|
||||
!allowPermChangeInAcceptWindow;
|
||||
return PaddingCard(
|
||||
title: translate("Permissions"),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
@@ -608,13 +615,21 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
bind.mainGetLocalOption(key: "show-scam-warning") != "N"
|
||||
? () => showScamWarning(context, serverModel)
|
||||
: serverModel.toggleService),
|
||||
PermissionRow(translate("Input Control"), serverModel.inputOk,
|
||||
serverModel.toggleInput),
|
||||
PermissionRow(translate("Transfer file"), serverModel.fileOk,
|
||||
serverModel.toggleFile),
|
||||
PermissionRow(
|
||||
translate("Input Control"),
|
||||
serverModel.inputOk,
|
||||
serverModel.toggleInput,
|
||||
),
|
||||
PermissionRow(
|
||||
translate("Transfer file"),
|
||||
serverModel.fileOk,
|
||||
serverModel.toggleFile,
|
||||
enabled: !permissionChangeLocked,
|
||||
),
|
||||
hasAudioPermission
|
||||
? PermissionRow(translate("Audio Capture"), serverModel.audioOk,
|
||||
serverModel.toggleAudio)
|
||||
serverModel.toggleAudio,
|
||||
enabled: !permissionChangeLocked)
|
||||
: Row(children: [
|
||||
Icon(Icons.info_outline).marginOnly(right: 15),
|
||||
Expanded(
|
||||
@@ -623,19 +638,25 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
style: const TextStyle(color: MyTheme.darkGray),
|
||||
))
|
||||
]),
|
||||
PermissionRow(translate("Enable clipboard"), serverModel.clipboardOk,
|
||||
serverModel.toggleClipboard),
|
||||
PermissionRow(
|
||||
translate("Enable clipboard"),
|
||||
serverModel.clipboardOk,
|
||||
serverModel.toggleClipboard,
|
||||
enabled: !permissionChangeLocked,
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionRow extends StatelessWidget {
|
||||
const PermissionRow(this.name, this.isOk, this.onPressed, {Key? key})
|
||||
const PermissionRow(this.name, this.isOk, this.onPressed,
|
||||
{Key? key, this.enabled = true})
|
||||
: super(key: key);
|
||||
|
||||
final String name;
|
||||
final bool isOk;
|
||||
final VoidCallback onPressed;
|
||||
final bool enabled;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -644,9 +665,11 @@ class PermissionRow extends StatelessWidget {
|
||||
contentPadding: EdgeInsets.all(0),
|
||||
title: Text(name),
|
||||
value: isOk,
|
||||
onChanged: (bool value) {
|
||||
onPressed();
|
||||
});
|
||||
onChanged: enabled
|
||||
? (bool value) {
|
||||
onPressed();
|
||||
}
|
||||
: null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import '../../common/widgets/login.dart';
|
||||
import '../../consts.dart';
|
||||
import '../../models/model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../widgets/deploy_dialog.dart';
|
||||
import '../widgets/dialog.dart';
|
||||
import 'home_page.dart';
|
||||
import 'scan_page.dart';
|
||||
@@ -728,6 +729,13 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||
onPressed: (context) {
|
||||
changeSocks5Proxy();
|
||||
}),
|
||||
if (isAndroid && !bind.isOutgoingOnly())
|
||||
SettingsTile(
|
||||
title: Text(translate('Deploy')),
|
||||
leading: Icon(Icons.cloud_upload),
|
||||
onPressed: (context) {
|
||||
showDeployDialog();
|
||||
}),
|
||||
if (!disabledSettings && !_hideNetwork && !_hideWebSocket)
|
||||
SettingsTile.switchTile(
|
||||
title: Text(translate('Use WebSocket')),
|
||||
|
||||
114
flutter/lib/mobile/widgets/deploy_dialog.dart
Normal file
114
flutter/lib/mobile/widgets/deploy_dialog.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
|
||||
const _deployDialogTag = 'android-deploy-device';
|
||||
|
||||
void showDeployPromptDialog() {
|
||||
gFFI.dialogManager.dismissByTag(_deployDialogTag);
|
||||
gFFI.dialogManager.show<bool>((setState, close, context) {
|
||||
submit() => close(true);
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Deploy")),
|
||||
content: Text(translate("server_requires_deployment_tip")),
|
||||
actions: [
|
||||
dialogButton("Cancel", onPressed: close, isOutline: true),
|
||||
dialogButton("OK", onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
}, tag: _deployDialogTag).then((deploy) {
|
||||
if (deploy == true) {
|
||||
showDeployDialog();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void showDeployDialog() {
|
||||
gFFI.dialogManager.dismissByTag(_deployDialogTag);
|
||||
final tokenController = TextEditingController();
|
||||
final idController = TextEditingController();
|
||||
var errorText = "";
|
||||
var isInProgress = false;
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
if (isInProgress) return;
|
||||
final token = tokenController.text.trim();
|
||||
if (token.isEmpty) {
|
||||
setState(() {
|
||||
errorText = translate("token is required!");
|
||||
});
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
errorText = "";
|
||||
isInProgress = true;
|
||||
});
|
||||
String res;
|
||||
try {
|
||||
res = await bind.mainDeployDevice(
|
||||
token: token, id: idController.text.trim());
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
errorText = translate(e.toString());
|
||||
isInProgress = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (res.isEmpty) {
|
||||
close();
|
||||
await gFFI.serverModel.fetchID();
|
||||
showToast(translate("Successful"));
|
||||
} else {
|
||||
setState(() {
|
||||
errorText = translate(res.toString());
|
||||
isInProgress = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Deploy")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: tokenController,
|
||||
decoration: InputDecoration(labelText: translate("API Token")),
|
||||
obscureText: true,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
autofocus: true,
|
||||
).workaroundFreezeLinuxMint(),
|
||||
TextField(
|
||||
controller: idController,
|
||||
decoration:
|
||||
InputDecoration(labelText: translate("Custom ID (optional)")),
|
||||
).workaroundFreezeLinuxMint(),
|
||||
if (errorText.isNotEmpty)
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SelectableText(
|
||||
errorText,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
fontSize: 12,
|
||||
),
|
||||
).paddingOnly(top: 8),
|
||||
),
|
||||
if (isInProgress) const LinearProgressIndicator().paddingOnly(top: 8),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
dialogButton("Cancel",
|
||||
onPressed: isInProgress ? null : close, isOutline: true),
|
||||
dialogButton("OK", onPressed: isInProgress ? null : submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: isInProgress ? null : close,
|
||||
);
|
||||
}, tag: _deployDialogTag);
|
||||
}
|
||||
@@ -391,14 +391,30 @@ class FileController {
|
||||
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
|
||||
final dir = (await bind.sessionGetPeerOption(
|
||||
final savedDir = (await bind.sessionGetPeerOption(
|
||||
sessionId: sessionId, name: isLocal ? "local_dir" : "remote_dir"));
|
||||
openDirectory(dir.isEmpty ? options.value.home : dir);
|
||||
Future<bool> tryOpenReadyDirs() async {
|
||||
final dirs = <String>{
|
||||
if (directory.value.path.isNotEmpty) directory.value.path,
|
||||
if (savedDir.isNotEmpty) savedDir,
|
||||
options.value.home,
|
||||
};
|
||||
for (final dir in dirs) {
|
||||
if (await _openDirectoryPath(dir, isBack: true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var opened = await tryOpenReadyDirs();
|
||||
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
|
||||
if (directory.value.path.isEmpty) {
|
||||
openDirectory(options.value.home);
|
||||
if (!opened) {
|
||||
// The peer may become ready during the reconnect delay, so retry the
|
||||
// same candidates instead of only retrying the default home directory.
|
||||
await tryOpenReadyDirs();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,19 +445,23 @@ class FileController {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
await openDirectory(directory.value.path);
|
||||
Future<bool> refresh() async {
|
||||
// "." can be both a refresh command and a real remote directory path.
|
||||
// Refresh must bypass openDirectory's command dispatch to avoid recursion.
|
||||
return await _openDirectoryPath(directory.value.path, isBack: true);
|
||||
}
|
||||
|
||||
Future<void> openDirectory(String path, {bool isBack = false}) async {
|
||||
if (path == ".") {
|
||||
refresh();
|
||||
return;
|
||||
Future<bool> openDirectory(String path, {bool isBack = false}) async {
|
||||
if (!isBack && path == ".") {
|
||||
return await refresh();
|
||||
}
|
||||
if (path == "..") {
|
||||
goToParentDirectory();
|
||||
return;
|
||||
if (!isBack && path == "..") {
|
||||
return await _goToParentDirectory(isBack: isBack);
|
||||
}
|
||||
return await _openDirectoryPath(path, isBack: isBack);
|
||||
}
|
||||
|
||||
Future<bool> _openDirectoryPath(String path, {bool isBack = false}) async {
|
||||
if (!isBack) {
|
||||
pushHistory();
|
||||
}
|
||||
@@ -458,8 +478,10 @@ class FileController {
|
||||
final fd = await fileFetcher.fetchDirectory(path, isLocal, showHidden);
|
||||
fd.format(isWindows, sort: sortBy.value);
|
||||
directory.value = fd;
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Failed to openDirectory $path: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,19 +509,22 @@ class FileController {
|
||||
goBack();
|
||||
return;
|
||||
}
|
||||
openDirectory(path, isBack: true);
|
||||
unawaited(_openDirectoryPath(path, isBack: true).then<void>((_) {}));
|
||||
}
|
||||
|
||||
void goToParentDirectory() {
|
||||
unawaited(_goToParentDirectory().then<void>((_) {}));
|
||||
}
|
||||
|
||||
Future<bool> _goToParentDirectory({bool isBack = false}) async {
|
||||
final isWindows = options.value.isWindows;
|
||||
final dirPath = directory.value.path;
|
||||
var parent = PathUtil.dirname(dirPath, isWindows);
|
||||
// specially for C:\, D:\, goto '/'
|
||||
if (parent == dirPath && isWindows) {
|
||||
openDirectory('/');
|
||||
return;
|
||||
return await _openDirectoryPath('/', isBack: isBack);
|
||||
}
|
||||
openDirectory(parent);
|
||||
return await _openDirectoryPath(parent, isBack: isBack);
|
||||
}
|
||||
|
||||
// TODO deprecated this
|
||||
|
||||
@@ -346,7 +346,7 @@ class InputModel {
|
||||
/// which runs per-engine, so each isolate registers its own handler tied
|
||||
/// to its own set of InputModels.
|
||||
static void initSideButtonChannel() {
|
||||
if (!Platform.isLinux) return;
|
||||
if (!isLinux) return;
|
||||
if (_sideButtonChannelInitialized) return;
|
||||
_sideButtonChannelInitialized = true;
|
||||
|
||||
@@ -474,6 +474,10 @@ class InputModel {
|
||||
|
||||
late final SessionID sessionId;
|
||||
|
||||
// Local gate for clipboard-assisted input flows on mobile Wayland dialogs.
|
||||
// It should not block physical keyboard events.
|
||||
bool keyboardInputAllowed = true;
|
||||
|
||||
bool get keyboardPerm => parent.target!.ffiModel.keyboard;
|
||||
String get id => parent.target?.id ?? '';
|
||||
String? get peerPlatform => parent.target?.ffiModel.pi.platform;
|
||||
|
||||
@@ -298,7 +298,7 @@ class ServerModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
toggleAudio() async {
|
||||
if (clients.isNotEmpty) {
|
||||
if (clients.any((c) => !c.disconnected)) {
|
||||
await showClientsMayNotBeChangedAlert(parent.target);
|
||||
}
|
||||
if (!_audioOk && !await AndroidPermissionManager.check(kRecordAudio)) {
|
||||
@@ -316,7 +316,7 @@ class ServerModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
toggleFile() async {
|
||||
if (clients.isNotEmpty) {
|
||||
if (clients.any((c) => !c.disconnected)) {
|
||||
await showClientsMayNotBeChangedAlert(parent.target);
|
||||
}
|
||||
if (!_fileOk &&
|
||||
@@ -345,7 +345,7 @@ class ServerModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
toggleInput() async {
|
||||
if (clients.isNotEmpty) {
|
||||
if (clients.any((c) => !c.disconnected)) {
|
||||
await showClientsMayNotBeChangedAlert(parent.target);
|
||||
}
|
||||
if (_inputOk) {
|
||||
@@ -549,10 +549,19 @@ class ServerModel with ChangeNotifier {
|
||||
if (index < 0) {
|
||||
_clients.add(client);
|
||||
} else {
|
||||
if (_clients[index].authorized) {
|
||||
_clients[index].privacyMode = client.privacyMode;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
_clients[index].authorized = true;
|
||||
_clients[index].privacyMode = client.privacyMode;
|
||||
}
|
||||
} else {
|
||||
if (_clients.any((c) => c.id == client.id)) {
|
||||
final index = _clients.indexWhere((c) => c.id == client.id);
|
||||
if (index >= 0) {
|
||||
_clients[index].privacyMode = client.privacyMode;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
_clients.add(client);
|
||||
@@ -818,6 +827,7 @@ class Client {
|
||||
bool restart = false;
|
||||
bool recording = false;
|
||||
bool blockInput = false;
|
||||
bool privacyMode = false;
|
||||
bool disconnected = false;
|
||||
bool fromSwitch = false;
|
||||
bool inVoiceCall = false;
|
||||
@@ -846,6 +856,7 @@ class Client {
|
||||
restart = json['restart'];
|
||||
recording = json['recording'];
|
||||
blockInput = json['block_input'];
|
||||
privacyMode = json['privacy_mode'] ?? privacyMode;
|
||||
disconnected = json['disconnected'];
|
||||
fromSwitch = json['from_switch'];
|
||||
inVoiceCall = json['in_voice_call'];
|
||||
@@ -870,6 +881,7 @@ class Client {
|
||||
data['restart'] = restart;
|
||||
data['recording'] = recording;
|
||||
data['block_input'] = blockInput;
|
||||
data['privacy_mode'] = privacyMode;
|
||||
data['disconnected'] = disconnected;
|
||||
data['from_switch'] = fromSwitch;
|
||||
data['in_voice_call'] = inVoiceCall;
|
||||
|
||||
@@ -27,25 +27,30 @@ class TerminalModel with ChangeNotifier {
|
||||
// Buffer for output data received before terminal view has valid dimensions.
|
||||
// This prevents NaN errors when writing to terminal before layout is complete.
|
||||
final _pendingOutputChunks = <String>[];
|
||||
final _pendingOutputSuppressFlags = <bool>[];
|
||||
int _pendingOutputSize = 0;
|
||||
static const int _kMaxOutputBufferChars = 8 * 1024;
|
||||
// View ready state: true when terminal has valid dimensions, safe to write
|
||||
bool _terminalViewReady = false;
|
||||
|
||||
bool get isPeerWindows => parent.ffiModel.pi.platform == kPeerPlatformWindows;
|
||||
bool _markViewReadyScheduled = false;
|
||||
bool _suppressTerminalOutput = false;
|
||||
bool _suppressNextTerminalDataOutput = false;
|
||||
|
||||
void Function(int w, int h, int pw, int ph)? onResizeExternal;
|
||||
|
||||
Future<void> _handleInput(String data) async {
|
||||
// If we press the `Enter` button on Android,
|
||||
// `data` can be '\r' or '\n' when using different keyboards.
|
||||
// Android -> Windows. '\r' works, but '\n' does not. '\n' is just a newline.
|
||||
// Android -> Linux. Both '\r' and '\n' work as expected (execute a command).
|
||||
// So when we receive '\n', we may need to convert it to '\r' to ensure compatibility.
|
||||
// Desktop -> Desktop works fine.
|
||||
// Check if we are on mobile or web(mobile), and convert '\n' to '\r'.
|
||||
// Soft keyboards (notably iOS) emit '\n' when Enter is pressed, while a
|
||||
// real keyboard's Enter sends '\r'. Some Android keyboards also emit '\n'.
|
||||
// - Peer Windows: '\r' works, '\n' is just a newline.
|
||||
// - Peer Linux: canonical-mode shells accept both, but raw-mode apps
|
||||
// (readline, prompt_toolkit, vim, TUI frameworks) expect '\r'.
|
||||
// - Peer macOS: same as Linux, raw-mode apps expect '\r'
|
||||
// (https://github.com/rustdesk/rustdesk/issues/14907).
|
||||
// So on mobile / web-mobile, always normalize a lone '\n' to '\r'.
|
||||
// We deliberately do not touch multi-character payloads (e.g. pasted text)
|
||||
// so embedded newlines in pasted content are preserved.
|
||||
final isMobileOrWebMobile = (isMobile || (isWeb && !isWebDesktop));
|
||||
if (isMobileOrWebMobile && isPeerWindows && data == '\n') {
|
||||
if (isMobileOrWebMobile && data == '\n') {
|
||||
data = '\r';
|
||||
}
|
||||
if (_terminalOpened) {
|
||||
@@ -70,7 +75,10 @@ class TerminalModel with ChangeNotifier {
|
||||
terminalController = TerminalController();
|
||||
|
||||
// Setup terminal callbacks
|
||||
terminal.onOutput = _handleInput;
|
||||
terminal.onOutput = (data) {
|
||||
if (_suppressTerminalOutput) return;
|
||||
_handleInput(data);
|
||||
};
|
||||
|
||||
terminal.onResize = (w, h, pw, ph) async {
|
||||
// Validate all dimensions before using them
|
||||
@@ -84,7 +92,7 @@ class TerminalModel with ChangeNotifier {
|
||||
// Mark terminal view as ready and flush any buffered output on first valid resize.
|
||||
// Must be after onResizeExternal so the view layer has valid dimensions before flushing.
|
||||
if (!_terminalViewReady) {
|
||||
_markViewReady();
|
||||
_scheduleMarkViewReady();
|
||||
}
|
||||
|
||||
if (_terminalOpened) {
|
||||
@@ -110,14 +118,16 @@ class TerminalModel with ChangeNotifier {
|
||||
void onReady() {
|
||||
parent.dialogManager.dismissAll();
|
||||
|
||||
// Fire and forget - don't block onReady
|
||||
openTerminal().catchError((e) {
|
||||
// Fire and forget - don't block onReady. If the transport reconnects while
|
||||
// this model is still open, re-send OpenTerminal so the remote service marks
|
||||
// the persistent session active again and resumes output streaming.
|
||||
openTerminal(force: _terminalOpened).catchError((e) {
|
||||
debugPrint('[TerminalModel] Error opening terminal: $e');
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> openTerminal() async {
|
||||
if (_terminalOpened) return;
|
||||
Future<void> openTerminal({bool force = false}) async {
|
||||
if (_terminalOpened && !force) return;
|
||||
// Request the remote side to open a terminal with default shell
|
||||
// The remote side will decide which shell to use based on its OS
|
||||
|
||||
@@ -275,9 +285,12 @@ class TerminalModel with ChangeNotifier {
|
||||
if (success) {
|
||||
_terminalOpened = true;
|
||||
|
||||
// On reconnect ("Reconnected to existing terminal"), server may replay recent output.
|
||||
// If this TerminalView instance is reused (not rebuilt), duplicate lines can appear.
|
||||
// We intentionally accept this tradeoff for now to keep logic simple.
|
||||
// On reconnect, the server may replay recent output. That replay can include
|
||||
// terminal queries like DSR/DA; xterm answers them through onOutput as
|
||||
// "^[[1;1R^[[2;2R^[[>0;0;0c", which must not be sent back to the peer.
|
||||
final replayTerminalOutput = evt['replay_terminal_output'];
|
||||
_suppressNextTerminalDataOutput = replayTerminalOutput == true ||
|
||||
message == 'Reconnected to existing terminal with pending output';
|
||||
|
||||
// Fallback: if terminal view is not yet ready but already has valid
|
||||
// dimensions (e.g. layout completed before open response arrived),
|
||||
@@ -285,7 +298,7 @@ class TerminalModel with ChangeNotifier {
|
||||
if (!_terminalViewReady &&
|
||||
terminal.viewWidth > 0 &&
|
||||
terminal.viewHeight > 0) {
|
||||
_markViewReady();
|
||||
_scheduleMarkViewReady();
|
||||
}
|
||||
|
||||
// Process any buffered input
|
||||
@@ -297,12 +310,16 @@ class TerminalModel with ChangeNotifier {
|
||||
});
|
||||
|
||||
final persistentSessions =
|
||||
evt['persistent_sessions'] as List<dynamic>? ?? [];
|
||||
(evt['persistent_sessions'] as List<dynamic>? ?? [])
|
||||
.whereType<int>()
|
||||
.where((id) => !parent.terminalModels.containsKey(id))
|
||||
.toList();
|
||||
if (kWindowId != null && persistentSessions.isNotEmpty) {
|
||||
DesktopMultiWindow.invokeMethod(
|
||||
kWindowId!,
|
||||
kWindowEventRestoreTerminalSessions,
|
||||
jsonEncode({
|
||||
'peer_id': id,
|
||||
'persistent_sessions': persistentSessions,
|
||||
}));
|
||||
}
|
||||
@@ -332,6 +349,8 @@ class TerminalModel with ChangeNotifier {
|
||||
final data = evt['data'];
|
||||
|
||||
if (data != null) {
|
||||
final suppressTerminalOutput = _suppressNextTerminalDataOutput;
|
||||
_suppressNextTerminalDataOutput = false;
|
||||
try {
|
||||
String text = '';
|
||||
if (data is String) {
|
||||
@@ -351,7 +370,7 @@ class TerminalModel with ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
_writeToTerminal(text);
|
||||
_writeToTerminal(text, suppressTerminalOutput: suppressTerminalOutput);
|
||||
} catch (e) {
|
||||
debugPrint('[TerminalModel] Failed to process terminal data: $e');
|
||||
}
|
||||
@@ -361,7 +380,10 @@ class TerminalModel with ChangeNotifier {
|
||||
/// Write text to terminal, buffering if the view is not yet ready.
|
||||
/// All terminal output should go through this method to avoid NaN errors
|
||||
/// from writing before the terminal view has valid layout dimensions.
|
||||
void _writeToTerminal(String text) {
|
||||
void _writeToTerminal(
|
||||
String text, {
|
||||
bool suppressTerminalOutput = false,
|
||||
}) {
|
||||
if (!_terminalViewReady) {
|
||||
// If a single chunk exceeds the cap, keep only its tail.
|
||||
// Note: truncation may split a multi-byte ANSI escape sequence,
|
||||
@@ -373,34 +395,73 @@ class TerminalModel with ChangeNotifier {
|
||||
_pendingOutputChunks
|
||||
..clear()
|
||||
..add(truncated);
|
||||
_pendingOutputSuppressFlags
|
||||
..clear()
|
||||
..add(suppressTerminalOutput);
|
||||
_pendingOutputSize = truncated.length;
|
||||
} else {
|
||||
_pendingOutputChunks.add(text);
|
||||
_pendingOutputSuppressFlags.add(suppressTerminalOutput);
|
||||
_pendingOutputSize += text.length;
|
||||
// Drop oldest chunks if exceeds limit (whole chunks to preserve ANSI sequences)
|
||||
while (_pendingOutputSize > _kMaxOutputBufferChars &&
|
||||
_pendingOutputChunks.length > 1) {
|
||||
final removed = _pendingOutputChunks.removeAt(0);
|
||||
_pendingOutputSuppressFlags.removeAt(0);
|
||||
_pendingOutputSize -= removed.length;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
terminal.write(text);
|
||||
_writeTerminalChunk(text, suppressTerminalOutput: suppressTerminalOutput);
|
||||
}
|
||||
|
||||
void _flushOutputBuffer() {
|
||||
if (_pendingOutputChunks.isEmpty) return;
|
||||
debugPrint(
|
||||
'[TerminalModel] Flushing $_pendingOutputSize buffered chars (${_pendingOutputChunks.length} chunks)');
|
||||
for (final chunk in _pendingOutputChunks) {
|
||||
terminal.write(chunk);
|
||||
for (var i = 0; i < _pendingOutputChunks.length; i++) {
|
||||
_writeTerminalChunk(
|
||||
_pendingOutputChunks[i],
|
||||
suppressTerminalOutput: _pendingOutputSuppressFlags[i],
|
||||
);
|
||||
}
|
||||
_pendingOutputChunks.clear();
|
||||
_pendingOutputSuppressFlags.clear();
|
||||
_pendingOutputSize = 0;
|
||||
}
|
||||
|
||||
void _writeTerminalChunk(
|
||||
String text, {
|
||||
required bool suppressTerminalOutput,
|
||||
}) {
|
||||
if (!suppressTerminalOutput) {
|
||||
terminal.write(text);
|
||||
return;
|
||||
}
|
||||
final previous = _suppressTerminalOutput;
|
||||
_suppressTerminalOutput = true;
|
||||
try {
|
||||
terminal.write(text);
|
||||
} finally {
|
||||
_suppressTerminalOutput = previous;
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark terminal view as ready and flush buffered output.
|
||||
void _scheduleMarkViewReady() {
|
||||
if (_disposed || _terminalViewReady || _markViewReadyScheduled) return;
|
||||
_markViewReadyScheduled = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_markViewReadyScheduled = false;
|
||||
if (_disposed || _terminalViewReady) return;
|
||||
if (terminal.viewWidth > 0 && terminal.viewHeight > 0) {
|
||||
_markViewReady();
|
||||
}
|
||||
});
|
||||
WidgetsBinding.instance.ensureVisualUpdate();
|
||||
}
|
||||
|
||||
void _markViewReady() {
|
||||
if (_terminalViewReady) return;
|
||||
_terminalViewReady = true;
|
||||
@@ -426,7 +487,10 @@ class TerminalModel with ChangeNotifier {
|
||||
// Clear buffers to free memory
|
||||
_inputBuffer.clear();
|
||||
_pendingOutputChunks.clear();
|
||||
_pendingOutputSuppressFlags.clear();
|
||||
_pendingOutputSize = 0;
|
||||
_markViewReadyScheduled = false;
|
||||
_suppressNextTerminalDataOutput = false;
|
||||
// Terminal cleanup is handled server-side when service closes
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -1729,7 +1729,7 @@ class RustdeskImpl {
|
||||
}
|
||||
|
||||
String mainSupportedPrivacyModeImpls({dynamic hint}) {
|
||||
throw UnimplementedError("mainSupportedPrivacyModeImpls");
|
||||
return '[]';
|
||||
}
|
||||
|
||||
String mainSupportedInputSource({dynamic hint}) {
|
||||
@@ -2034,7 +2034,14 @@ class RustdeskImpl {
|
||||
}
|
||||
|
||||
String mainResolveAvatarUrl({required String avatar, dynamic hint}) {
|
||||
return js.context.callMethod('getByName', ['resolve_avatar_url', avatar])?.toString() ?? avatar;
|
||||
return js.context.callMethod(
|
||||
'getByName', ['resolve_avatar_url', avatar])?.toString() ??
|
||||
avatar;
|
||||
}
|
||||
|
||||
Future<String> mainDeployDevice(
|
||||
{required String token, required String id, dynamic hint}) {
|
||||
throw UnimplementedError("mainDeployDevice");
|
||||
}
|
||||
|
||||
void dispose() {}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
cargo ndk --platform 21 --target armv7-linux-androideabi build --release --features flutter,hwcodec
|
||||
cargo ndk --platform 21 --target armv7-linux-androideabi build --locked --release --features flutter,hwcodec
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
cargo ndk --platform 21 --target aarch64-linux-android build --release --features flutter,hwcodec
|
||||
cargo ndk --platform 21 --target aarch64-linux-android build --locked --release --features flutter,hwcodec
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
cargo ndk --platform 21 --target x86_64-linux-android build --release --features flutter
|
||||
cargo ndk --platform 21 --target x86_64-linux-android build --locked --release --features flutter
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
export CFLAGS="-DBROKEN_CLANG_ATOMICS"
|
||||
export CXXFLAGS="-DBROKEN_CLANG_ATOMICS"
|
||||
|
||||
cargo ndk --platform 21 --target i686-linux-android build --release --features flutter
|
||||
cargo ndk --platform 21 --target i686-linux-android build --locked --release --features flutter
|
||||
|
||||
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# 1.1.9-1 works for android, but for ios it becomes 1.1.91, need to set it to 1.1.9-a.1 for iOS, will get 1.1.9.1, but iOS store not allow 4 numbers
|
||||
version: 1.4.6+64
|
||||
version: 1.4.7+65
|
||||
|
||||
environment:
|
||||
sdk: '^3.1.0'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid
|
||||
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
|
||||
flutter pub get
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ../src/flutter_ffi.rs --dart-output ./lib/generated_bridge.dart --c-output ./macos/Runner/bridge_generated.h
|
||||
# call `flutter clean` if cargo build fails
|
||||
# export LLVM_HOME=/Library/Developer/CommandLineTools/usr/
|
||||
cargo build --features flutter
|
||||
cargo build --locked --features flutter
|
||||
flutter run $@
|
||||
|
||||
@@ -39,6 +39,28 @@
|
||||
|
||||
#define CLIPRDR_SVC_CHANNEL_NAME "cliprdr"
|
||||
|
||||
/* Maximum number of clipboard streams accepted from a remote peer (integer overflow / DoS guard) */
|
||||
#define WF_CLIPRDR_MAX_STREAMS 16384
|
||||
|
||||
/* Validates the remote descriptor array size after cItems has been read safely. */
|
||||
static BOOL wf_cliprdr_file_group_descriptor_size_valid(SIZE_T size, UINT count)
|
||||
{
|
||||
SIZE_T header_size = offsetof(FILEGROUPDESCRIPTORW, fgd);
|
||||
SIZE_T descriptors_size;
|
||||
|
||||
if (count == 0 || count > WF_CLIPRDR_MAX_STREAMS)
|
||||
return FALSE;
|
||||
|
||||
if (size < header_size)
|
||||
return FALSE;
|
||||
|
||||
if ((SIZE_T)count > (((SIZE_T)-1) - header_size) / sizeof(FILEDESCRIPTORW))
|
||||
return FALSE;
|
||||
|
||||
descriptors_size = header_size + (SIZE_T)count * sizeof(FILEDESCRIPTORW);
|
||||
return size >= descriptors_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clipboard Formats
|
||||
*/
|
||||
@@ -224,6 +246,7 @@ struct wf_clipboard
|
||||
|
||||
HWND hwnd;
|
||||
HANDLE hmem;
|
||||
SIZE_T hmem_data_len;
|
||||
HANDLE thread;
|
||||
HANDLE formatDataRespEvent;
|
||||
BOOL formatDataRespReceived;
|
||||
@@ -624,10 +647,55 @@ void CliprdrStream_Delete(CliprdrStream *instance)
|
||||
if (instance)
|
||||
{
|
||||
free(instance->iStream.lpVtbl);
|
||||
instance->iStream.lpVtbl = NULL;
|
||||
free(instance);
|
||||
}
|
||||
}
|
||||
|
||||
static void wf_cliprdr_release_streams(IStream **streams, ULONG count)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
if (!streams)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (streams[i])
|
||||
CliprdrStream_Release(streams[i]);
|
||||
}
|
||||
|
||||
free(streams);
|
||||
}
|
||||
|
||||
static void wf_cliprdr_reset_streams(CliprdrDataObject *instance)
|
||||
{
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
wf_cliprdr_release_streams(instance->m_pStream, instance->m_nStreams);
|
||||
instance->m_pStream = NULL;
|
||||
instance->m_nStreams = 0;
|
||||
}
|
||||
|
||||
/* Only call after clipboard->hmem has been locked by GlobalLock. */
|
||||
static HRESULT wf_cliprdr_fail_locked_file_descriptor_data(wfClipboard *clipboard,
|
||||
STGMEDIUM *medium,
|
||||
CliprdrDataObject *instance,
|
||||
IStream **streams,
|
||||
ULONG stream_count,
|
||||
HRESULT error)
|
||||
{
|
||||
GlobalUnlock(clipboard->hmem);
|
||||
GlobalFree(clipboard->hmem);
|
||||
clipboard->hmem = NULL;
|
||||
clipboard->hmem_data_len = 0;
|
||||
medium->hGlobal = NULL;
|
||||
wf_cliprdr_release_streams(streams, stream_count);
|
||||
wf_cliprdr_reset_streams(instance);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* IDataObject
|
||||
*/
|
||||
@@ -746,6 +814,9 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
|
||||
{
|
||||
// FILEGROUPDESCRIPTOR *dsc;
|
||||
FILEGROUPDESCRIPTORW *dsc;
|
||||
IStream **streams = NULL;
|
||||
UINT stream_count = 0;
|
||||
SIZE_T hmem_size;
|
||||
// DWORD remote_format_id = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat);
|
||||
// FIXME: origin code may be failed here???
|
||||
if (cliprdr_send_data_request(instance->m_connID, clipboard, instance->m_pFormatEtc[idx].cfFormat) != 0)
|
||||
@@ -763,40 +834,48 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
|
||||
* is the number of FILEDESCRIPTOR's */
|
||||
// dsc = (FILEGROUPDESCRIPTOR *)GlobalLock(clipboard->hmem);
|
||||
dsc = (FILEGROUPDESCRIPTORW *)GlobalLock(clipboard->hmem);
|
||||
instance->m_nStreams = dsc->cItems;
|
||||
GlobalUnlock(clipboard->hmem);
|
||||
|
||||
if (instance->m_nStreams > 0)
|
||||
if (!dsc)
|
||||
{
|
||||
if (!instance->m_pStream)
|
||||
{
|
||||
instance->m_pStream = (LPSTREAM *)calloc(instance->m_nStreams, sizeof(LPSTREAM));
|
||||
|
||||
if (instance->m_pStream)
|
||||
{
|
||||
for (i = 0; i < instance->m_nStreams; i++)
|
||||
{
|
||||
instance->m_pStream[i] =
|
||||
(IStream *)CliprdrStream_New(instance->m_connID, i, clipboard, &dsc->fgd[i]);
|
||||
|
||||
if (!instance->m_pStream[i])
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance->m_pStream)
|
||||
{
|
||||
if (clipboard->hmem)
|
||||
{
|
||||
GlobalFree(clipboard->hmem);
|
||||
clipboard->hmem = NULL;
|
||||
}
|
||||
|
||||
pMedium->hGlobal = NULL;
|
||||
return E_OUTOFMEMORY;
|
||||
GlobalFree(clipboard->hmem);
|
||||
clipboard->hmem = NULL;
|
||||
clipboard->hmem_data_len = 0;
|
||||
wf_cliprdr_reset_streams(instance);
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
hmem_size = clipboard->hmem_data_len;
|
||||
/* cItems is remote-controlled; verify the fixed header exists before reading it. */
|
||||
if (hmem_size < offsetof(FILEGROUPDESCRIPTORW, fgd))
|
||||
return wf_cliprdr_fail_locked_file_descriptor_data(
|
||||
clipboard, pMedium, instance, NULL, 0, E_UNEXPECTED);
|
||||
|
||||
stream_count = dsc->cItems;
|
||||
if (!wf_cliprdr_file_group_descriptor_size_valid(hmem_size, stream_count))
|
||||
return wf_cliprdr_fail_locked_file_descriptor_data(
|
||||
clipboard, pMedium, instance, NULL, 0, E_UNEXPECTED);
|
||||
|
||||
streams = (IStream **)calloc(stream_count, sizeof(IStream *));
|
||||
if (!streams)
|
||||
return wf_cliprdr_fail_locked_file_descriptor_data(
|
||||
clipboard, pMedium, instance, NULL, 0, E_OUTOFMEMORY);
|
||||
|
||||
for (i = 0; i < stream_count; i++)
|
||||
{
|
||||
streams[i] =
|
||||
(IStream *)CliprdrStream_New(instance->m_connID, i, clipboard, &dsc->fgd[i]);
|
||||
if (!streams[i])
|
||||
{
|
||||
return wf_cliprdr_fail_locked_file_descriptor_data(
|
||||
clipboard, pMedium, instance, streams, i, E_OUTOFMEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUnlock(clipboard->hmem);
|
||||
wf_cliprdr_reset_streams(instance);
|
||||
instance->m_pStream = streams;
|
||||
instance->m_nStreams = stream_count;
|
||||
return S_OK;
|
||||
}
|
||||
else if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat(CFSTR_FILECONTENTS))
|
||||
{
|
||||
@@ -2160,16 +2239,16 @@ static BOOL wf_cliprdr_add_to_file_arrays(wfClipboard *clipboard, WCHAR *full_fi
|
||||
return FALSE;
|
||||
|
||||
/* add to name array */
|
||||
clipboard->file_names[clipboard->nFiles] = (LPWSTR)malloc(MAX_PATH * 2);
|
||||
|
||||
if (!clipboard->file_names[clipboard->nFiles])
|
||||
return FALSE;
|
||||
|
||||
// `MAX_PATH` is long enough for the file name.
|
||||
// So we just return FALSE if the file name is too long, which is not a normal case.
|
||||
if ((wcslen(full_file_name) + 1) > MAX_PATH)
|
||||
return FALSE;
|
||||
|
||||
clipboard->file_names[clipboard->nFiles] = (LPWSTR)calloc(MAX_PATH, sizeof(WCHAR));
|
||||
|
||||
if (!clipboard->file_names[clipboard->nFiles])
|
||||
return FALSE;
|
||||
|
||||
wcsncpy_s(clipboard->file_names[clipboard->nFiles], MAX_PATH, full_file_name, wcslen(full_file_name) + 1);
|
||||
/* add to descriptor array */
|
||||
clipboard->fileDescriptor[clipboard->nFiles] =
|
||||
@@ -2777,6 +2856,7 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
|
||||
break;
|
||||
}
|
||||
clipboard->hmem = NULL;
|
||||
clipboard->hmem_data_len = 0;
|
||||
|
||||
if (formatDataResponse->msgFlags != CB_RESPONSE_OK)
|
||||
{
|
||||
@@ -2810,6 +2890,7 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
|
||||
break;
|
||||
}
|
||||
|
||||
clipboard->hmem_data_len = formatDataResponse->dataLen;
|
||||
clipboard->hmem = hMem;
|
||||
rc = CHANNEL_RC_OK;
|
||||
} while (0);
|
||||
|
||||
Submodule libs/hbb_common updated: 87b11a7959...df6badca5b
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustdesk-portable-packer"
|
||||
version = "1.4.6"
|
||||
version = "1.4.7"
|
||||
edition = "2021"
|
||||
description = "RustDesk Remote Desktop"
|
||||
|
||||
|
||||
@@ -67,9 +67,9 @@ def write_app_metadata(output_folder: str):
|
||||
def build_portable(output_folder: str, target: str):
|
||||
os.chdir(output_folder)
|
||||
if target:
|
||||
os.system("cargo build --release --target " + target)
|
||||
os.system("cargo build --locked --release --target " + target)
|
||||
else:
|
||||
os.system("cargo build --release")
|
||||
os.system("cargo build --locked --release")
|
||||
|
||||
# Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
|
||||
# Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe
|
||||
|
||||
@@ -276,12 +276,21 @@ impl PipeWireRecorder {
|
||||
// see: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/982
|
||||
src.set_property("always-copy", &true)?;
|
||||
|
||||
// COSMIC/Wayland fix: insert videoconvert between pipewiresrc and appsink.
|
||||
// xdg-desktop-portal-cosmic's modifier negotiation fails when the downstream
|
||||
// format set is too narrow (appsink only accepts BGRx/RGBx), producing
|
||||
// "no more output formats" / not-negotiated (-4). videoconvert accepts any
|
||||
// system-memory video/x-raw format, widening negotiation so the portal can
|
||||
// settle on a format it can deliver via its SHM path.
|
||||
let convert = gst::ElementFactory::make("videoconvert", None)?;
|
||||
|
||||
let sink = gst::ElementFactory::make("appsink", None)?;
|
||||
sink.set_property("drop", &true)?;
|
||||
sink.set_property("max-buffers", &1u32)?;
|
||||
|
||||
pipeline.add_many(&[&src, &sink])?;
|
||||
src.link(&sink)?;
|
||||
pipeline.add_many(&[&src, &convert, &sink])?;
|
||||
src.link(&convert)?;
|
||||
convert.link(&sink)?;
|
||||
|
||||
let appsink = sink
|
||||
.dynamic_cast::<AppSink>()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pkgname=rustdesk
|
||||
pkgver=1.4.6
|
||||
pkgver=1.4.7
|
||||
pkgrel=0
|
||||
epoch=
|
||||
pkgdesc=""
|
||||
|
||||
@@ -31,17 +31,17 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
// Helper function to safely delete a file or directory using handle-based deletion.
|
||||
// This avoids TOCTOU (Time-Of-Check-Time-Of-Use) race conditions.
|
||||
// Helper function to safely delete a file using handle-based deletion.
|
||||
// Directories are refused after opening the handle.
|
||||
BOOL SafeDeleteItem(LPCWSTR fullPath)
|
||||
{
|
||||
// Open the file/directory with DELETE access and FILE_FLAG_OPEN_REPARSE_POINT
|
||||
// Open the file/directory with delete and attribute-read access plus FILE_FLAG_OPEN_REPARSE_POINT
|
||||
// to prevent following symlinks.
|
||||
// Use shared access to allow deletion even when other processes have the file open.
|
||||
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
HANDLE hFile = CreateFileW(
|
||||
fullPath,
|
||||
DELETE,
|
||||
DELETE | FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // Allow shared access
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
@@ -55,6 +55,21 @@ BOOL SafeDeleteItem(LPCWSTR fullPath)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION fileInfo;
|
||||
if (FALSE == GetFileInformationByHandle(hFile, &fileInfo))
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "SafeDeleteItem: Failed to inspect '%ls'. Error: %lu", fullPath, GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "SafeDeleteItem: Refusing to delete directory '%ls'.", fullPath);
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Use SetFileInformationByHandle to mark for deletion.
|
||||
// The file will be deleted when the handle is closed.
|
||||
FILE_DISPOSITION_INFO dispInfo;
|
||||
@@ -77,98 +92,74 @@ BOOL SafeDeleteItem(LPCWSTR fullPath)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper function to recursively delete a directory's contents with detailed logging.
|
||||
void RecursiveDelete(LPCWSTR path)
|
||||
BOOL PathEndsWithSlash(LPCWSTR path)
|
||||
{
|
||||
// Ensure the path is not empty or null.
|
||||
if (path == NULL || path[0] == L'\0')
|
||||
size_t length = 0;
|
||||
HRESULT hr = StringCchLengthW(path, MAX_PATH, &length);
|
||||
if (FAILED(hr) || length == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR last = path[length - 1];
|
||||
return last == L'\\' || last == L'/';
|
||||
}
|
||||
|
||||
void ClearReadOnlyAttribute(LPCWSTR fullPath, DWORD attributes)
|
||||
{
|
||||
if (!(attributes & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Extra safety: never operate directly on a root path.
|
||||
if (PathIsRootW(path))
|
||||
DWORD writableAttributes = attributes & ~FILE_ATTRIBUTE_READONLY;
|
||||
if (writableAttributes == 0)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: refusing to operate on root path '%ls'.", path);
|
||||
writableAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
if (SetFileAttributesW(fullPath, writableAttributes))
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup cleared read-only attribute for '%ls'.", fullPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// MAX_PATH is enough here since the installer should not be using longer paths.
|
||||
// No need to handle extended-length paths (\\?\) in this context.
|
||||
WCHAR searchPath[MAX_PATH];
|
||||
HRESULT hr = StringCchPrintfW(searchPath, MAX_PATH, L"%s\\*", path);
|
||||
if (FAILED(hr)) {
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: Path too long to enumerate: %ls", path);
|
||||
return;
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup failed to clear read-only attribute for '%ls'. Error: %lu", fullPath, GetLastError());
|
||||
}
|
||||
|
||||
BOOL DeleteRuntimeGeneratedFile(LPCWSTR installFolder, LPCWSTR fileName)
|
||||
{
|
||||
WCHAR fullPath[MAX_PATH];
|
||||
LPCWSTR separator = PathEndsWithSlash(installFolder) ? L"" : L"\\";
|
||||
HRESULT hr = StringCchPrintfW(fullPath, MAX_PATH, L"%s%s%s", installFolder, separator, fileName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup path is too long for '%ls'.", fileName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATAW findData;
|
||||
HANDLE hFind = FindFirstFileW(searchPath, &findData);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
DWORD attributes = GetFileAttributesW(fullPath);
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
// This can happen if the directory is empty or doesn't exist, which is not an error in our case.
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: Failed to enumerate directory '%ls'. It may be missing or inaccessible. Error: %lu", path, GetLastError());
|
||||
return;
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup cannot stat '%ls'. Error: %lu", fullPath, error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do
|
||||
if (attributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
// Skip '.' and '..' directories.
|
||||
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// MAX_PATH is enough here since the installer should not be using longer paths.
|
||||
// No need to handle extended-length paths (\\?\) in this context.
|
||||
WCHAR fullPath[MAX_PATH];
|
||||
hr = StringCchPrintfW(fullPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
|
||||
if (FAILED(hr)) {
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: Path too long for item '%ls' in '%ls', skipping.", findData.cFileName, path);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Before acting, ensure the read-only attribute is not set.
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
{
|
||||
if (FALSE == SetFileAttributesW(fullPath, findData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: Failed to remove read-only attribute. Error: %lu", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
// Check for reparse points (symlinks/junctions) to prevent directory traversal attacks.
|
||||
// Do not follow reparse points, only remove the link itself.
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: Not recursing into reparse point (symlink/junction), deleting link itself: %ls", fullPath);
|
||||
SafeDeleteItem(fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recursively delete directory contents first
|
||||
RecursiveDelete(fullPath);
|
||||
// Then delete the directory itself
|
||||
SafeDeleteItem(fullPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete file using safe handle-based deletion
|
||||
SafeDeleteItem(fullPath);
|
||||
}
|
||||
} while (FindNextFileW(hFind, &findData) != 0);
|
||||
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "RecursiveDelete: FindNextFileW failed with error %lu", lastError);
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup skipped directory '%ls'.", fullPath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FindClose(hFind);
|
||||
ClearReadOnlyAttribute(fullPath, attributes);
|
||||
WcaLog(LOGMSG_STANDARD, "Runtime cleanup deleting '%ls'.", fullPath);
|
||||
return SafeDeleteItem(fullPath);
|
||||
}
|
||||
|
||||
// See `Package.wxs` for the sequence of this custom action.
|
||||
@@ -178,13 +169,13 @@ void RecursiveDelete(LPCWSTR path)
|
||||
// 2. RemoveExistingProducts
|
||||
// ├─ TerminateProcesses
|
||||
// ├─ TryStopDeleteService
|
||||
// ├─ RemoveInstallFolder - <-- Here
|
||||
// ├─ RemoveRuntimeGeneratedFiles - <-- Here
|
||||
// └─ RemoveFiles
|
||||
// 3. InstallValidate
|
||||
// 4. InstallFiles
|
||||
// 5. InstallExecute
|
||||
// 6. InstallFinalize
|
||||
UINT __stdcall RemoveInstallFolder(
|
||||
UINT __stdcall RemoveRuntimeGeneratedFiles(
|
||||
__in MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
@@ -194,7 +185,7 @@ UINT __stdcall RemoveInstallFolder(
|
||||
LPWSTR pwz = NULL;
|
||||
LPWSTR pwzData = NULL;
|
||||
|
||||
hr = WcaInitialize(hInstall, "RemoveInstallFolder");
|
||||
hr = WcaInitialize(hInstall, "RemoveRuntimeGeneratedFiles");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &pwzData);
|
||||
@@ -202,24 +193,20 @@ UINT __stdcall RemoveInstallFolder(
|
||||
|
||||
pwz = pwzData;
|
||||
hr = WcaReadStringFromCaData(&pwz, &installFolder);
|
||||
ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
|
||||
ExitOnFailure(hr, "failed to read install folder from custom action data: %ls", pwz);
|
||||
|
||||
if (installFolder == NULL || installFolder[0] == L'\0') {
|
||||
WcaLog(LOGMSG_STANDARD, "Install folder path is empty, skipping recursive delete.");
|
||||
WcaLog(LOGMSG_STANDARD, "Install folder path is empty, skipping runtime cleanup.");
|
||||
goto LExit;
|
||||
}
|
||||
|
||||
if (PathIsRootW(installFolder)) {
|
||||
WcaLog(LOGMSG_STANDARD, "Refusing to recursively delete root folder '%ls'.", installFolder);
|
||||
WcaLog(LOGMSG_STANDARD, "Refusing runtime cleanup in root folder '%ls'.", installFolder);
|
||||
goto LExit;
|
||||
}
|
||||
|
||||
WcaLog(LOGMSG_STANDARD, "Attempting to recursively delete contents of install folder: %ls", installFolder);
|
||||
|
||||
RecursiveDelete(installFolder);
|
||||
|
||||
// The standard MSI 'RemoveFolders' action will take care of removing the (now empty) directories.
|
||||
// We don't need to call RemoveDirectoryW on installFolder itself, as it might still be in use by the installer.
|
||||
WcaLog(LOGMSG_STANDARD, "Removing runtime-generated files from install folder: %ls", installFolder);
|
||||
DeleteRuntimeGeneratedFile(installFolder, L"RuntimeBroker_rustdesk.exe");
|
||||
|
||||
LExit:
|
||||
ReleaseStr(pwzData);
|
||||
|
||||
@@ -2,7 +2,7 @@ LIBRARY "CustomActions"
|
||||
|
||||
EXPORTS
|
||||
CustomActionHello
|
||||
RemoveInstallFolder
|
||||
RemoveRuntimeGeneratedFiles
|
||||
TerminateProcesses
|
||||
AddFirewallRules
|
||||
SetPropertyIsServiceRunning
|
||||
|
||||
@@ -16,8 +16,15 @@
|
||||
<!-- If a command line value was stored, restore it after the registry search has been performed -->
|
||||
<SetProperty Action="RestoreSavedInstallFolderValue" Id="INSTALLFOLDER" Value="[SavedInstallFolderCmdLineValue]" After="AppSearch" Sequence="first" Condition="SavedInstallFolderCmdLineValue" />
|
||||
|
||||
<!-- If a command line value or registry value was set, update the main properties with the value -->
|
||||
<SetProperty Id="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER]" After="RestoreSavedInstallFolderValue" Sequence="first" Condition="INSTALLFOLDER" />
|
||||
<!-- Normalize INSTALLFOLDER from the command line or registry before assigning INSTALLFOLDER_INNER. -->
|
||||
<!-- Case 1: already ends with \$(var.Product)\, keep it unchanged. -->
|
||||
<SetProperty Action="SetInstallFolderInnerFromProductDir" Id="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER]" After="RestoreSavedInstallFolderValue" Sequence="first" Condition="INSTALLFOLDER AND INSTALLFOLDER ~>> "\$(var.Product)\"" />
|
||||
<!-- Case 2: already ends with \$(var.Product) but has no trailing slash, add the slash. -->
|
||||
<SetProperty Action="SetInstallFolderInnerFromProductDirNoSlash" Id="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER]\" After="RestoreSavedInstallFolderValue" Sequence="first" Condition="INSTALLFOLDER AND INSTALLFOLDER ~>> "\$(var.Product)"" />
|
||||
<!-- Case 3: ends with a slash but not \$(var.Product)\, append $(var.Product)\. -->
|
||||
<SetProperty Action="SetInstallFolderInnerAppendProduct" Id="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER]$(var.Product)\" After="RestoreSavedInstallFolderValue" Sequence="first" Condition="INSTALLFOLDER AND INSTALLFOLDER ~>> "\" AND NOT (INSTALLFOLDER ~>> "\$(var.Product)\" OR INSTALLFOLDER ~>> "\$(var.Product)")" />
|
||||
<!-- Case 4: has no trailing slash and does not end with \$(var.Product), append \$(var.Product)\. -->
|
||||
<SetProperty Action="SetInstallFolderInnerAppendSlashProduct" Id="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER]\$(var.Product)\" After="RestoreSavedInstallFolderValue" Sequence="first" Condition="INSTALLFOLDER AND NOT INSTALLFOLDER ~>> "\" AND NOT (INSTALLFOLDER ~>> "\$(var.Product)\" OR INSTALLFOLDER ~>> "\$(var.Product)")" />
|
||||
|
||||
<!-- INSTALLFOLDER_INNER is defined for compatibility with previous versions of the installer. -->
|
||||
<!-- Because we need to use INSTALLFOLDER as the command line argument. -->
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<CustomAction Id="RemoveInstallFolder.SetParam" Return="check" Property="RemoveInstallFolder" Value="[INSTALLFOLDER_INNER]" />
|
||||
<CustomAction Id="RemoveRuntimeGeneratedFiles.SetParam" Return="check" Property="RemoveRuntimeGeneratedFiles" Value="[INSTALLFOLDER_INNER]" />
|
||||
<CustomAction Id="AddFirewallRules.SetParam" Return="check" Property="AddFirewallRules" Value="1[INSTALLFOLDER_INNER]$(var.Product).exe" />
|
||||
<CustomAction Id="RemoveFirewallRules.SetParam" Return="check" Property="RemoveFirewallRules" Value="0[INSTALLFOLDER_INNER]$(var.Product).exe" />
|
||||
<CustomAction Id="CreateStartService.SetParam" Return="check" Property="CreateStartService" Value="$(var.Product);"[INSTALLFOLDER_INNER]$(var.Product).exe" --service" />
|
||||
@@ -77,21 +77,21 @@
|
||||
|
||||
<Custom Action="AddRegSoftwareSASGeneration" Before="InstallFinalize" Condition="NOT (Installed AND REMOVE AND NOT UPGRADINGPRODUCTCODE) AND (NOT CC_CONNECTION_TYPE="outgoing")"/>
|
||||
|
||||
<Custom Action="RemoveInstallFolder" Before="RemoveFiles"/>
|
||||
<Custom Action="RemoveInstallFolder.SetParam" Before="RemoveInstallFolder"/>
|
||||
<Custom Action="TryStopDeleteService" Before="RemoveInstallFolder.SetParam" />
|
||||
<Custom Action="RemoveRuntimeGeneratedFiles" Before="RemoveFiles" Condition="Installed AND (REMOVE="ALL" OR UPGRADINGPRODUCTCODE)"/>
|
||||
<Custom Action="RemoveRuntimeGeneratedFiles.SetParam" Before="RemoveRuntimeGeneratedFiles" Condition="Installed AND (REMOVE="ALL" OR UPGRADINGPRODUCTCODE)"/>
|
||||
<Custom Action="TryStopDeleteService" Before="RemoveRuntimeGeneratedFiles.SetParam" />
|
||||
<Custom Action="TryStopDeleteService.SetParam" Before="TryStopDeleteService" />
|
||||
|
||||
<Custom Action="RemoveFirewallRules" Before="RemoveFiles"/>
|
||||
<Custom Action="RemoveFirewallRules.SetParam" Before="RemoveFirewallRules"/>
|
||||
|
||||
<Custom Action="UninstallPrinter" Before="RemoveInstallFolder" Condition="VersionNT >= 603" />
|
||||
<Custom Action="UninstallPrinter" Before="RemoveRuntimeGeneratedFiles" Condition="VersionNT >= 603" />
|
||||
|
||||
<Custom Action="TerminateProcesses" Before="RemoveInstallFolder"/>
|
||||
<Custom Action="TerminateProcesses" Before="RemoveRuntimeGeneratedFiles"/>
|
||||
<Custom Action="TerminateProcesses.SetParam" Before="TerminateProcesses"/>
|
||||
<Custom Action="TerminateBrokers" Before="RemoveInstallFolder"/>
|
||||
<Custom Action="TerminateBrokers" Before="RemoveRuntimeGeneratedFiles"/>
|
||||
<Custom Action="TerminateBrokers.SetParam" Before="TerminateBrokers"/>
|
||||
<Custom Action="RemoveAmyuniIdd" Before="RemoveInstallFolder"/>
|
||||
<Custom Action="RemoveAmyuniIdd" Before="RemoveRuntimeGeneratedFiles"/>
|
||||
<Custom Action="RemoveAmyuniIdd.SetParam" Before="RemoveAmyuniIdd"/>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Binary Id="Custom_Actions_Dll" SourceFile="$(var.CustomActions.TargetDir)$(var.CustomActions.TargetName).dll" />
|
||||
|
||||
<CustomAction Id="CustomActionHello" DllEntry="CustomActionHello" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
<CustomAction Id="RemoveInstallFolder" DllEntry="RemoveInstallFolder" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
<CustomAction Id="RemoveRuntimeGeneratedFiles" DllEntry="RemoveRuntimeGeneratedFiles" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
<CustomAction Id="TerminateProcesses" DllEntry="TerminateProcesses" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
<CustomAction Id="TerminateBrokers" DllEntry="TerminateProcesses" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
<CustomAction Id="AddFirewallRules" DllEntry="AddFirewallRules" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
|
||||
|
||||
@@ -23,12 +23,13 @@ Patch dialog sequence:
|
||||
-->
|
||||
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
|
||||
<?include ../Includes.wxi?>
|
||||
<?foreach WIXUIARCH in X86;X64;A64 ?>
|
||||
<Fragment>
|
||||
<UI Id="UI_MyInstallDialog_$(WIXUIARCH)">
|
||||
<Publish Dialog="LicenseAgreementDlg" Control="Print" Event="DoAction" Value="WixUIPrintEula_$(WIXUIARCH)" />
|
||||
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath_$(WIXUIARCH)" Order="3" Condition="NOT WIXUI_DONTVALIDATEPATH" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath_$(WIXUIARCH)" Order="2" Condition="NOT WIXUI_DONTVALIDATEPATH" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath_$(WIXUIARCH)" Order="5" Condition="NOT WIXUI_DONTVALIDATEPATH" />
|
||||
</UI>
|
||||
|
||||
<UIRef Id="UI_MyInstallDialog" />
|
||||
@@ -64,9 +65,16 @@ Patch dialog sequence:
|
||||
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="MyInstallDirDlg" Condition="LicenseAccepted = "1"" />
|
||||
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3" Condition="NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4" Condition="WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"" />
|
||||
<!-- Normalize INSTALLFOLDER_INNER before SetTargetPath and WixUIValidatePath run. -->
|
||||
<!-- UI case 1: already ends with \$(var.Product) but has no trailing slash, add the slash. -->
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Property="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER_INNER]\" Order="1" Condition="INSTALLFOLDER_INNER AND INSTALLFOLDER_INNER ~>> "\$(var.Product)"" />
|
||||
<!-- UI case 2: ends with a slash but not \$(var.Product)\, append $(var.Product)\. -->
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Property="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER_INNER]$(var.Product)\" Order="2" Condition="INSTALLFOLDER_INNER AND INSTALLFOLDER_INNER ~>> "\" AND NOT (INSTALLFOLDER_INNER ~>> "\$(var.Product)\" OR INSTALLFOLDER_INNER ~>> "\$(var.Product)")" />
|
||||
<!-- UI case 3: has no trailing slash and does not end with \$(var.Product), append \$(var.Product)\. -->
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Property="INSTALLFOLDER_INNER" Value="[INSTALLFOLDER_INNER]\$(var.Product)\" Order="3" Condition="INSTALLFOLDER_INNER AND NOT INSTALLFOLDER_INNER ~>> "\" AND NOT (INSTALLFOLDER_INNER ~>> "\$(var.Product)\" OR INSTALLFOLDER_INNER ~>> "\$(var.Product)")" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="4" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="6" Condition="NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="7" Condition="WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1" />
|
||||
<Publish Dialog="MyInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2" />
|
||||
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MyInstallDirDlg" Order="1" Condition="NOT Installed" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo $MACOS_CODESIGN_IDENTITY
|
||||
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid
|
||||
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
|
||||
cd flutter; flutter pub get; cd -
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h
|
||||
./build.py --flutter
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rustdesk
|
||||
Version: 1.4.6
|
||||
Version: 1.4.7
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rustdesk
|
||||
Version: 1.4.6
|
||||
Version: 1.4.7
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rustdesk
|
||||
Version: 1.4.6
|
||||
Version: 1.4.7
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
||||
@@ -1745,6 +1745,9 @@ pub struct LoginConfigHandler {
|
||||
pub direct: Option<bool>,
|
||||
pub received: bool,
|
||||
switch_uuid: Option<String>,
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
switch_back_allowed: bool,
|
||||
pub save_ab_password_to_recent: bool, // true: connected with ab password
|
||||
pub other_server: Option<(String, String, String)>,
|
||||
pub custom_fps: Arc<Mutex<Option<usize>>>,
|
||||
@@ -1861,6 +1864,11 @@ impl LoginConfigHandler {
|
||||
|
||||
self.direct = None;
|
||||
self.received = false;
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
self.switch_back_allowed = false;
|
||||
}
|
||||
self.switch_uuid = switch_uuid;
|
||||
self.adapter_luid = adapter_luid;
|
||||
self.selected_windows_session_id = None;
|
||||
@@ -1874,6 +1882,23 @@ impl LoginConfigHandler {
|
||||
self.is_terminal_admin = is_terminal_admin;
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub fn allow_switch_back_once(&mut self) {
|
||||
self.switch_back_allowed = true;
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub fn consume_switch_back_permission(&mut self) -> bool {
|
||||
if self.switch_back_allowed {
|
||||
self.switch_back_allowed = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the client should auto login.
|
||||
/// Return password if the client should auto login, otherwise return empty string.
|
||||
pub fn should_auto_login(&self) -> String {
|
||||
@@ -3377,6 +3402,36 @@ pub fn handle_login_error(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
async fn consume_local_switch_sides_uuid(id: &str, uuid: &Uuid) -> bool {
|
||||
let Ok(mut conn) = crate::ipc::connect(1000, "").await else {
|
||||
return false;
|
||||
};
|
||||
let uuid = uuid.to_string();
|
||||
if conn
|
||||
.send(&crate::ipc::Data::SwitchSidesUuid(
|
||||
uuid.clone(),
|
||||
id.to_owned(),
|
||||
None,
|
||||
))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
match conn.next_timeout(1000).await {
|
||||
Ok(Some(crate::ipc::Data::SwitchSidesUuid(
|
||||
returned_uuid,
|
||||
returned_id,
|
||||
Some(true),
|
||||
))) => {
|
||||
returned_uuid == uuid && returned_id == id
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle hash message sent by peer.
|
||||
/// Hash will be used for login.
|
||||
///
|
||||
@@ -3397,12 +3452,22 @@ pub async fn handle_hash(
|
||||
// Take care of password application order
|
||||
|
||||
// switch_uuid
|
||||
let uuid = lc.write().unwrap().switch_uuid.take();
|
||||
if let Some(uuid) = uuid {
|
||||
if let Ok(uuid) = uuid::Uuid::from_str(&uuid) {
|
||||
send_switch_login_request(lc.clone(), peer, uuid).await;
|
||||
lc.write().unwrap().password_source = Default::default();
|
||||
return;
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
let uuid = lc.write().unwrap().switch_uuid.take();
|
||||
if let Some(uuid) = uuid {
|
||||
if let Ok(uuid) = uuid::Uuid::from_str(&uuid) {
|
||||
let id = lc.read().unwrap().id.clone();
|
||||
if !consume_local_switch_sides_uuid(&id, &uuid).await {
|
||||
log::warn!("Ignored untrusted switch_uuid");
|
||||
} else {
|
||||
lc.write().unwrap().allow_switch_back_once();
|
||||
send_switch_login_request(lc.clone(), peer, uuid).await;
|
||||
lc.write().unwrap().password_source = Default::default();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// last password
|
||||
|
||||
@@ -1797,6 +1797,9 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
Ok(Permission::BlockInput) => {
|
||||
self.handler.set_permission("block_input", p.enabled);
|
||||
}
|
||||
Ok(Permission::PrivacyMode) => {
|
||||
self.handler.set_permission("privacy_mode", p.enabled);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -1920,9 +1923,23 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Some(misc::Union::SwitchBack(_)) => {
|
||||
#[cfg(feature = "flutter")]
|
||||
self.handler.switch_back(&self.handler.get_id());
|
||||
let allow_switch_back = self
|
||||
.handler
|
||||
.lc
|
||||
.write()
|
||||
.unwrap()
|
||||
.consume_switch_back_permission();
|
||||
if allow_switch_back {
|
||||
self.handler.switch_back(&self.handler.get_id());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Ignored unsolicited SwitchBack from {}",
|
||||
self.handler.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use arboard::{ClipboardData, ClipboardFormat};
|
||||
#[cfg(target_os = "linux")]
|
||||
use arboard::{LinuxClipboardKind, SetExtLinux};
|
||||
use hbb_common::{bail, log, message_proto::*, ResultType};
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
@@ -54,6 +56,27 @@ pub fn check_clipboard(
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<Message> {
|
||||
let (msg, clipboards) = read_clipboard_message(ctx, side, force)?;
|
||||
*LAST_MULTI_CLIPBOARDS.lock().unwrap() = clipboards;
|
||||
Some(msg)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn peek_clipboard(
|
||||
ctx: &mut Option<ClipboardContext>,
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<Message> {
|
||||
let (msg, _) = read_clipboard_message(ctx, side, force)?;
|
||||
Some(msg)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn read_clipboard_message(
|
||||
ctx: &mut Option<ClipboardContext>,
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<(Message, MultiClipboards)> {
|
||||
if ctx.is_none() {
|
||||
*ctx = ClipboardContext::new().ok();
|
||||
}
|
||||
@@ -64,8 +87,7 @@ pub fn check_clipboard(
|
||||
let mut msg = Message::new();
|
||||
let clipboards = proto::create_multi_clipboards(content);
|
||||
msg.set_multi_clipboards(clipboards.clone());
|
||||
*LAST_MULTI_CLIPBOARDS.lock().unwrap() = clipboards;
|
||||
return Some(msg);
|
||||
return Some((msg, clipboards));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -219,10 +241,7 @@ fn do_update_clipboard_(mut to_update_data: Vec<ClipboardData>, side: ClipboardS
|
||||
}
|
||||
}
|
||||
if let Some(ctx) = ctx.as_mut() {
|
||||
to_update_data.push(ClipboardData::Special((
|
||||
RUSTDESK_CLIPBOARD_OWNER_FORMAT.to_owned(),
|
||||
side.get_owner_data(),
|
||||
)));
|
||||
to_update_data = append_owner_marker(to_update_data, side);
|
||||
if let Err(e) = ctx.set(&to_update_data) {
|
||||
log::debug!("Failed to set clipboard: {}", e);
|
||||
} else {
|
||||
@@ -231,6 +250,29 @@ fn do_update_clipboard_(mut to_update_data: Vec<ClipboardData>, side: ClipboardS
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn append_owner_marker(mut data: Vec<ClipboardData>, side: ClipboardSide) -> Vec<ClipboardData> {
|
||||
data.push(ClipboardData::Special((
|
||||
RUSTDESK_CLIPBOARD_OWNER_FORMAT.to_owned(),
|
||||
side.get_owner_data(),
|
||||
)));
|
||||
data
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn set_text_clipboard_with_owner_sync(text: &str, side: ClipboardSide) -> ResultType<()> {
|
||||
let mut ctx = CLIPBOARD_CTX.lock().unwrap();
|
||||
if ctx.is_none() {
|
||||
*ctx = Some(ClipboardContext::new()?);
|
||||
}
|
||||
let clipboard_ctx = match ctx.as_mut() {
|
||||
Some(ctx) => ctx,
|
||||
None => bail!("Failed to create clipboard context"),
|
||||
};
|
||||
let data = append_owner_marker(vec![ClipboardData::Text(text.to_owned())], side);
|
||||
clipboard_ctx.set_with_owner_marker_for_linux(&data)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn update_clipboard(multi_clipboards: Vec<Clipboard>, side: ClipboardSide) {
|
||||
std::thread::spawn(move || {
|
||||
@@ -382,6 +424,24 @@ impl ClipboardContext {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn set_with_owner_marker_for_linux(&mut self, data: &[ClipboardData]) -> ResultType<()> {
|
||||
let _lock = ARBOARD_MTX.lock().unwrap();
|
||||
self.inner
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Clipboard)
|
||||
.formats(data)?;
|
||||
if let Err(e) = self
|
||||
.inner
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Primary)
|
||||
.formats(data)
|
||||
{
|
||||
log::warn!("Failed to set PRIMARY clipboard with owner marker: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unix-file-copy-paste", target_os = "macos"))]
|
||||
fn get_file_urls_set_by_rustdesk(
|
||||
data: Vec<ClipboardData>,
|
||||
|
||||
137
src/core_main.rs
137
src/core_main.rs
@@ -146,7 +146,13 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
crate::portable_service::client::set_quick_support(_is_quick_support);
|
||||
}
|
||||
let mut log_name = "".to_owned();
|
||||
if args.len() > 0 && args[0].starts_with("--") {
|
||||
// Keep portable-service logs under a stable directory name.
|
||||
let has_portable_service_shmem_arg = args
|
||||
.iter()
|
||||
.any(|arg| arg.starts_with("--portable-service-shmem-name="));
|
||||
if has_portable_service_shmem_arg {
|
||||
log_name = "portable-service".to_owned();
|
||||
} else if args.len() > 0 && args[0].starts_with("--") {
|
||||
let name = args[0].replace("--", "");
|
||||
if !name.is_empty() {
|
||||
log_name = name;
|
||||
@@ -193,6 +199,20 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
std::thread::spawn(move || crate::start_server(false, no_server));
|
||||
} else {
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
// Root CLI management commands must talk to the user `--server` main IPC.
|
||||
// Example: `sudo rustdesk --option custom-rendezvous-server` should query the
|
||||
// user's IPC instead of root's `/tmp/<app>-0/ipc`; `connect()` still limits this
|
||||
// routing to empty-postfix main IPC only.
|
||||
let _user_main_ipc_scope = if crate::platform::is_installed()
|
||||
&& is_root()
|
||||
&& is_user_main_ipc_scope_cli_command(&args)
|
||||
{
|
||||
Some(crate::ipc::UserMainIpcScope::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use crate::platform;
|
||||
@@ -412,7 +432,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
return None;
|
||||
} else if args[0] == "--password" {
|
||||
if config::is_disable_settings() {
|
||||
if is_cli_setting_change_disabled() {
|
||||
println!("Settings are disabled!");
|
||||
return None;
|
||||
}
|
||||
@@ -454,7 +474,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
println!("{}", crate::ipc::get_id());
|
||||
return None;
|
||||
} else if args[0] == "--set-id" {
|
||||
if config::is_disable_settings() {
|
||||
if is_cli_setting_change_disabled() {
|
||||
println!("Settings are disabled!");
|
||||
return None;
|
||||
}
|
||||
@@ -501,7 +521,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
return None;
|
||||
} else if args[0] == "--option" {
|
||||
if config::is_disable_settings() {
|
||||
if is_cli_setting_change_disabled() {
|
||||
println!("Settings are disabled!");
|
||||
return None;
|
||||
}
|
||||
@@ -621,6 +641,56 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
println!("Installation and administrative privileges required!");
|
||||
}
|
||||
return None;
|
||||
} else if args[0] == "--deploy" {
|
||||
if config::Config::no_register_device() {
|
||||
println!("Cannot deploy an unregistrable device!");
|
||||
} else if config::is_outgoing_only() {
|
||||
println!("Cannot deploy Outgoing-only clients.");
|
||||
} else if crate::platform::is_installed() && is_root() {
|
||||
let max = args.len() - 1;
|
||||
let pos = args.iter().position(|x| x == "--token").unwrap_or(max);
|
||||
if pos >= max {
|
||||
println!("--token is required!");
|
||||
return None;
|
||||
}
|
||||
let token = args[pos + 1].to_owned();
|
||||
let get_value = |c: &str| {
|
||||
let pos = args.iter().position(|x| x == c).unwrap_or(max);
|
||||
if pos < max {
|
||||
Some(args[pos + 1].to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
let new_id = get_value("--id");
|
||||
match crate::ui_interface::deploy_device(token, new_id) {
|
||||
crate::ui_interface::DeployResult::Ok => {
|
||||
println!("Device deployed.");
|
||||
}
|
||||
crate::ui_interface::DeployResult::NotEnabled => {
|
||||
println!("Server does not require deployment.");
|
||||
std::process::exit(3);
|
||||
}
|
||||
crate::ui_interface::DeployResult::InvalidInput => {
|
||||
println!("Invalid input.");
|
||||
std::process::exit(5);
|
||||
}
|
||||
crate::ui_interface::DeployResult::IdTaken(id) => {
|
||||
println!(
|
||||
"Id `{}` is already used by another machine on the server.",
|
||||
id
|
||||
);
|
||||
std::process::exit(6);
|
||||
}
|
||||
crate::ui_interface::DeployResult::Error(err) => {
|
||||
println!("{}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Installation and administrative privileges required!");
|
||||
}
|
||||
return None;
|
||||
} else if args[0] == "--check-hwcodec-config" {
|
||||
#[cfg(feature = "hwcodec")]
|
||||
crate::ipc::hwcodec_process();
|
||||
@@ -840,6 +910,65 @@ fn is_root() -> bool {
|
||||
crate::platform::is_root()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", test))]
|
||||
fn is_user_main_ipc_scope_cli_command(args: &[String]) -> bool {
|
||||
matches!(
|
||||
args.first().map(String::as_str),
|
||||
Some("--password")
|
||||
| Some("--set-unlock-pin")
|
||||
| Some("--get-id")
|
||||
| Some("--set-id")
|
||||
| Some("--config")
|
||||
| Some("--option")
|
||||
| Some("--assign")
|
||||
| Some("--deploy")
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_cli_setting_change_disabled() -> bool {
|
||||
let option = config::keys::OPTION_ALLOW_COMMAND_LINE_SETTINGS_WHEN_SETTINGS_DISABLED;
|
||||
let allow_command_line_settings =
|
||||
config::option2bool(option, &crate::get_builtin_option(option));
|
||||
config::is_disable_settings() && !allow_command_line_settings
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn args(values: &[&str]) -> Vec<String> {
|
||||
values.iter().map(|value| value.to_string()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_main_ipc_scope_cli_command_matches_management_commands_only() {
|
||||
for command in [
|
||||
"--password",
|
||||
"--set-unlock-pin",
|
||||
"--get-id",
|
||||
"--set-id",
|
||||
"--config",
|
||||
"--option",
|
||||
"--assign",
|
||||
"--deploy",
|
||||
] {
|
||||
assert!(is_user_main_ipc_scope_cli_command(&args(&[command])));
|
||||
}
|
||||
|
||||
for command in [
|
||||
"--service",
|
||||
"--server",
|
||||
"--tray",
|
||||
"--cm",
|
||||
"--check-hwcodec-config",
|
||||
"--connect",
|
||||
] {
|
||||
assert!(!is_user_main_ipc_scope_cli_command(&args(&[command])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the executable is a Quick Support version.
|
||||
/// Note: This function must be kept in sync with `libs/portable/src/main.rs`.
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -1135,6 +1135,10 @@ impl InvokeUiSession for FlutterHandler {
|
||||
("message", json!(&opened.message)),
|
||||
("pid", json!(opened.pid)),
|
||||
("service_id", json!(&opened.service_id)),
|
||||
(
|
||||
"replay_terminal_output",
|
||||
json!(opened.replay_terminal_output),
|
||||
),
|
||||
];
|
||||
if !opened.persistent_sessions.is_empty() {
|
||||
event_data.push(("persistent_sessions", json!(opened.persistent_sessions)));
|
||||
|
||||
@@ -972,6 +972,27 @@ pub fn main_show_option(_key: String) -> SyncReturn<bool> {
|
||||
}
|
||||
|
||||
pub fn main_set_option(key: String, value: String) {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let is_permission_option = key.eq(config::keys::OPTION_ENABLE_CLIPBOARD)
|
||||
|| key.eq(config::keys::OPTION_ENABLE_FILE_TRANSFER)
|
||||
|| key.eq(config::keys::OPTION_ENABLE_AUDIO);
|
||||
let allow_perm_change_in_accept_window = config::option2bool(
|
||||
config::keys::OPTION_ENABLE_PERM_CHANGE_IN_ACCEPT_WINDOW,
|
||||
&crate::get_builtin_option(config::keys::OPTION_ENABLE_PERM_CHANGE_IN_ACCEPT_WINDOW),
|
||||
);
|
||||
if is_permission_option
|
||||
&& !allow_perm_change_in_accept_window
|
||||
&& crate::ui_cm_interface::has_active_clients()
|
||||
{
|
||||
log::info!(
|
||||
"blocked main_set_option by policy, key={}, value={}",
|
||||
key,
|
||||
value
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
if key.eq(config::keys::OPTION_ENABLE_KEYBOARD) {
|
||||
crate::ui_cm_interface::switch_permission_all(
|
||||
@@ -1019,7 +1040,29 @@ pub fn main_get_options_sync() -> SyncReturn<String> {
|
||||
}
|
||||
|
||||
pub fn main_set_options(json: String) {
|
||||
let map: HashMap<String, String> = serde_json::from_str(&json).unwrap_or(HashMap::new());
|
||||
let mut map: HashMap<String, String> = serde_json::from_str(&json).unwrap_or(HashMap::new());
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let allow_perm_change_in_accept_window = config::option2bool(
|
||||
config::keys::OPTION_ENABLE_PERM_CHANGE_IN_ACCEPT_WINDOW,
|
||||
&crate::get_builtin_option(config::keys::OPTION_ENABLE_PERM_CHANGE_IN_ACCEPT_WINDOW),
|
||||
);
|
||||
if !allow_perm_change_in_accept_window && crate::ui_cm_interface::has_active_clients() {
|
||||
for key in [
|
||||
config::keys::OPTION_ENABLE_CLIPBOARD,
|
||||
config::keys::OPTION_ENABLE_FILE_TRANSFER,
|
||||
config::keys::OPTION_ENABLE_AUDIO,
|
||||
] {
|
||||
if let Some(value) = map.remove(key) {
|
||||
log::info!(
|
||||
"blocked main_set_options item by policy, key={}, value={}",
|
||||
key,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !map.is_empty() {
|
||||
set_options(map)
|
||||
}
|
||||
@@ -1110,6 +1153,22 @@ pub fn main_get_api_server() -> String {
|
||||
get_api_server()
|
||||
}
|
||||
|
||||
pub fn main_deploy_device(token: String, id: String) -> String {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let new_id = match id.trim() {
|
||||
"" => None,
|
||||
id => Some(id.to_owned()),
|
||||
};
|
||||
ui_interface::deploy_device(token, new_id).message()
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = (token, id);
|
||||
"Deployment is not supported on this platform.".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main_resolve_avatar_url(avatar: String) -> SyncReturn<String> {
|
||||
SyncReturn(resolve_avatar_url(avatar))
|
||||
}
|
||||
@@ -2073,6 +2132,7 @@ pub fn main_start_service() {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
config::Config::set_option("stop-service".into(), "".into());
|
||||
crate::rendezvous_mediator::reset_needs_deploy_notification();
|
||||
crate::rendezvous_mediator::RendezvousMediator::restart();
|
||||
}
|
||||
}
|
||||
@@ -2170,7 +2230,7 @@ pub fn cm_elevate_portable(conn_id: i32) {
|
||||
}
|
||||
|
||||
pub fn cm_switch_back(conn_id: i32) {
|
||||
#[cfg(not(any(target_os = "ios")))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
crate::ui_cm_interface::switch_back(conn_id);
|
||||
}
|
||||
|
||||
@@ -2428,23 +2488,13 @@ pub fn is_disable_installation() -> SyncReturn<bool> {
|
||||
}
|
||||
|
||||
pub fn is_preset_password() -> bool {
|
||||
let hard = config::HARD_SETTINGS
|
||||
.read()
|
||||
.unwrap()
|
||||
.get("password")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
if hard.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On desktop, service owns the authoritative config; query it via IPC and return only a boolean.
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
return crate::ipc::is_permanent_password_preset();
|
||||
|
||||
// On mobile, we have no service IPC; verify against local storage.
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
return config::Config::matches_permanent_password_plain(&hard);
|
||||
return config::Config::is_using_preset_password();
|
||||
}
|
||||
|
||||
// Don't call this function for desktop version.
|
||||
@@ -3022,6 +3072,7 @@ pub mod server_side {
|
||||
pub unsafe extern "system" fn Java_ffi_FFI_startService(_env: JNIEnv, _class: JClass) {
|
||||
log::debug!("startService from jvm");
|
||||
config::Config::set_option("stop-service".into(), "".into());
|
||||
crate::rendezvous_mediator::reset_needs_deploy_notification();
|
||||
crate::rendezvous_mediator::RendezvousMediator::restart();
|
||||
}
|
||||
|
||||
|
||||
705
src/ipc.rs
705
src/ipc.rs
@@ -1,33 +1,28 @@
|
||||
use crate::{
|
||||
common::CheckTestNatType,
|
||||
privacy_mode::PrivacyModeState,
|
||||
ui_interface::{get_local_option, set_local_option},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use parity_tokio_ipc::{
|
||||
Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
#[cfg(not(windows))]
|
||||
use std::{fs::File, io::prelude::*};
|
||||
#[path = "ipc/auth.rs"]
|
||||
mod ipc_auth;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[path = "ipc/fs.rs"]
|
||||
mod ipc_fs;
|
||||
|
||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::plugin::ipc::Plugin;
|
||||
use crate::{
|
||||
common::{is_server, CheckTestNatType},
|
||||
privacy_mode,
|
||||
privacy_mode::PrivacyModeState,
|
||||
rendezvous_mediator::RendezvousMediator,
|
||||
ui_interface::{get_local_option, set_local_option},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub use clipboard::ClipboardFile;
|
||||
#[cfg(target_os = "linux")]
|
||||
use hbb_common::anyhow;
|
||||
use hbb_common::{
|
||||
allow_err, bail, bytes,
|
||||
bytes_codec::BytesCodec,
|
||||
config::{
|
||||
self,
|
||||
keys::{self, OPTION_ALLOW_WEBSOCKET},
|
||||
Config, Config2,
|
||||
},
|
||||
config::{self, keys::OPTION_ALLOW_WEBSOCKET, Config, Config2},
|
||||
futures::StreamExt as _,
|
||||
futures_util::sink::SinkExt,
|
||||
log, password_security as password, timeout,
|
||||
@@ -38,13 +33,92 @@ use hbb_common::{
|
||||
tokio_util::codec::Framed,
|
||||
ResultType,
|
||||
};
|
||||
|
||||
use crate::{common::is_server, privacy_mode, rendezvous_mediator::RendezvousMediator};
|
||||
#[cfg(windows)]
|
||||
pub(crate) use ipc_auth::authorize_windows_portable_service_ipc_connection;
|
||||
#[cfg(windows)]
|
||||
pub(crate) use ipc_auth::ensure_peer_executable_matches_current_by_pid_opt;
|
||||
#[cfg(windows)]
|
||||
pub(crate) use ipc_auth::log_rejected_windows_ipc_connection;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use ipc_auth::{active_uid, authorize_service_scoped_ipc_connection};
|
||||
#[cfg(windows)]
|
||||
use ipc_auth::{
|
||||
authorize_windows_main_ipc_connection, portable_service_listener_security_attributes,
|
||||
should_allow_everyone_create_on_windows,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) use ipc_auth::{
|
||||
ensure_peer_executable_matches_current_by_fd, is_allowed_service_peer_uid,
|
||||
log_rejected_uinput_connection, peer_uid_from_fd,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
use ipc_fs::terminal_count_candidate_uids;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use ipc_fs::{
|
||||
check_pid, ensure_secure_ipc_parent_dir, scrub_secure_ipc_parent_dir,
|
||||
should_scrub_parent_entries_after_check_pid, write_pid,
|
||||
};
|
||||
use parity_tokio_ipc::{
|
||||
Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use std::cell::Cell;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
// IPC actions here.
|
||||
pub const IPC_ACTION_CLOSE: &str = "close";
|
||||
#[cfg(target_os = "windows")]
|
||||
const PORTABLE_SERVICE_IPC_HANDSHAKE_TIMEOUT_MS: u64 = 3_000;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) const IPC_TOKEN_LEN: usize = 64;
|
||||
#[cfg(target_os = "windows")]
|
||||
const IPC_TOKEN_RANDOM_BYTES: usize = IPC_TOKEN_LEN / 2;
|
||||
#[cfg(target_os = "windows")]
|
||||
const _: () = assert!(IPC_TOKEN_LEN % 2 == 0);
|
||||
pub static EXIT_RECV_CLOSE: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
thread_local! {
|
||||
static USE_USER_MAIN_IPC: Cell<bool> = Cell::new(false);
|
||||
}
|
||||
|
||||
#[must_use = "bind this guard to a local variable to keep the IPC scope active"]
|
||||
/// Thread-local guard for routing root main IPC to the active user on Linux/macOS.
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub(crate) struct UserMainIpcScope {
|
||||
previous: bool,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
impl UserMainIpcScope {
|
||||
pub(crate) fn new() -> Self {
|
||||
let previous = USE_USER_MAIN_IPC.with(|use_user_main| {
|
||||
let previous = use_user_main.get();
|
||||
use_user_main.set(true);
|
||||
previous
|
||||
});
|
||||
Self { previous }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
impl Drop for UserMainIpcScope {
|
||||
fn drop(&mut self) {
|
||||
USE_USER_MAIN_IPC.with(|use_user_main| use_user_main.set(self.previous));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn connect_service(ms_timeout: u64) -> ResultType<ConnectionTmpl<ConnClient>> {
|
||||
connect(ms_timeout, crate::POSTFIX_SERVICE).await
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
pub enum FS {
|
||||
@@ -207,6 +281,8 @@ pub enum DataControl {
|
||||
pub enum DataPortableService {
|
||||
Ping,
|
||||
Pong,
|
||||
AuthToken(String),
|
||||
AuthResult(bool),
|
||||
ConnCount(Option<usize>),
|
||||
Mouse((Vec<u8>, i32, String, u32, bool, bool)),
|
||||
Pointer((Vec<u8>, i32)),
|
||||
@@ -237,6 +313,7 @@ pub enum Data {
|
||||
restart: bool,
|
||||
recording: bool,
|
||||
block_input: bool,
|
||||
privacy_mode: bool,
|
||||
from_switch: bool,
|
||||
},
|
||||
ChatMessage {
|
||||
@@ -272,6 +349,7 @@ pub enum Data {
|
||||
ClipboardNonFile(Option<(String, Vec<ClipboardNonFile>)>),
|
||||
PrivacyModeState((i32, PrivacyModeState, String)),
|
||||
TestRendezvousServer,
|
||||
Deployed,
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Keyboard(DataKeyboard),
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
@@ -284,7 +362,14 @@ pub enum Data {
|
||||
Empty,
|
||||
Disconnected,
|
||||
DataPortableService(DataPortableService),
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
SwitchSidesRequest(String),
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
SwitchSidesUuid(String, String, Option<bool>),
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
SwitchSidesBack,
|
||||
UrlLink(String),
|
||||
VoiceCallIncoming,
|
||||
@@ -403,6 +488,22 @@ pub async fn start(postfix: &str) -> ResultType<()> {
|
||||
Ok(stream) => {
|
||||
let mut stream = Connection::new(stream);
|
||||
let postfix = postfix.to_owned();
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
if config::is_service_ipc_postfix(&postfix) {
|
||||
if !authorize_service_scoped_ipc_connection(&stream, &postfix) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
if postfix.is_empty() {
|
||||
// Windows main IPC (`postfix == ""`) is authorized here.
|
||||
// Other security-sensitive channels use dedicated authorization paths:
|
||||
// - `_portable_service`: portable-service listener + handshake policy
|
||||
// - service-scoped postfixes: service-specific listener/authorization
|
||||
if !authorize_windows_main_ipc_connection(&stream, &postfix) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
match stream.next().await {
|
||||
@@ -411,9 +512,48 @@ pub async fn start(postfix: &str) -> ResultType<()> {
|
||||
break;
|
||||
}
|
||||
Ok(Some(data)) => {
|
||||
// On Linux/macOS, the protected `_service` channel is used only for
|
||||
// syncing config between root service and the active user process.
|
||||
//
|
||||
// NOTE: `is_service_ipc_postfix()` also includes `_uinput_*`, but those
|
||||
// channels are handled by the dedicated uinput listener/protocol in
|
||||
// `src/server/uinput.rs` and therefore do not share this Data enum
|
||||
// allowlist. The SyncConfig allowlist here is intentionally scoped to the
|
||||
// `_service` channel only.
|
||||
//
|
||||
// Keep this explicit branch to avoid policy drift between `_service` and
|
||||
// uinput IPC paths while still minimizing exposed message surface here.
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
if postfix == crate::POSTFIX_SERVICE {
|
||||
if matches!(&data, Data::SyncConfig(_)) {
|
||||
handle(data, &mut stream).await;
|
||||
} else {
|
||||
log::warn!(
|
||||
"Rejected non-sync data on protected _service IPC channel: postfix={}, data_kind={:?}, peer_uid={:?}",
|
||||
postfix,
|
||||
std::mem::discriminant(&data),
|
||||
stream.peer_uid()
|
||||
);
|
||||
// Close the connection to avoid keeping a protected channel
|
||||
// alive while repeatedly receiving invalid traffic.
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
handle(data, &mut stream).await;
|
||||
}
|
||||
_ => {}
|
||||
Ok(None) => {
|
||||
// `Ok(None)` means a complete frame arrived but did not
|
||||
// deserialize into `Data`. Peer close/reset is returned as
|
||||
// `Err` by `ConnectionTmpl::next()`. Keep the historical
|
||||
// ignore behavior except on the protected `_service` channel.
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
if postfix == crate::POSTFIX_SERVICE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -428,20 +568,77 @@ pub async fn start(postfix: &str) -> ResultType<()> {
|
||||
|
||||
pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
|
||||
let path = Config::ipc_path(postfix);
|
||||
#[cfg(not(any(windows, target_os = "android", target_os = "ios")))]
|
||||
check_pid(postfix).await;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
let should_scrub_parent_entries = ensure_secure_ipc_parent_dir(&path, postfix)?;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
let existing_listener_alive = check_pid(postfix).await;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
if should_scrub_parent_entries_after_check_pid(
|
||||
should_scrub_parent_entries,
|
||||
existing_listener_alive,
|
||||
) {
|
||||
scrub_secure_ipc_parent_dir(&path, postfix)?;
|
||||
}
|
||||
let mut endpoint = Endpoint::new(path.clone());
|
||||
match SecurityAttributes::allow_everyone_create() {
|
||||
let security_attrs = {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if postfix == "_portable_service" {
|
||||
portable_service_listener_security_attributes()
|
||||
} else if should_allow_everyone_create_on_windows(postfix) {
|
||||
SecurityAttributes::allow_everyone_create()
|
||||
} else {
|
||||
Ok(SecurityAttributes::empty())
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
SecurityAttributes::allow_everyone_create()
|
||||
}
|
||||
};
|
||||
match security_attrs {
|
||||
Ok(attr) => endpoint.set_security_attributes(attr),
|
||||
Err(err) => log::error!("Failed to set ipc{} security: {}", postfix, err),
|
||||
Err(err) => {
|
||||
log::error!("Failed to set ipc{} security: {}", postfix, err);
|
||||
#[cfg(windows)]
|
||||
if postfix == "_portable_service" {
|
||||
// Fail closed for `_portable_service` when SDDL construction fails.
|
||||
// This endpoint is security-critical and must not start with default ACLs.
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
match endpoint.incoming() {
|
||||
Ok(incoming) => {
|
||||
log::info!("Started ipc{} server at path: {}", postfix, &path);
|
||||
#[cfg(not(windows))]
|
||||
if postfix == crate::POSTFIX_SERVICE {
|
||||
log::info!("Started protected ipc service server: postfix={}", postfix);
|
||||
} else {
|
||||
log::info!("Started ipc{} server at path: {}", postfix, &path);
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok();
|
||||
// NOTE: On Linux/macOS, some IPC sockets are intentionally world-connectable
|
||||
// (0666) so the active (non-root) user process can connect. Authorization is
|
||||
// enforced at accept-time for these channels, and the protected `_service`
|
||||
// channel is further restricted by an explicit message allowlist (SyncConfig
|
||||
// only).
|
||||
let socket_mode = if config::is_service_ipc_postfix(postfix) {
|
||||
0o0666
|
||||
} else {
|
||||
0o0600
|
||||
};
|
||||
if let Err(err) =
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(socket_mode))
|
||||
{
|
||||
log::error!(
|
||||
"Failed to set permissions on ipc{} socket at path {}: {}",
|
||||
postfix,
|
||||
&path,
|
||||
err
|
||||
);
|
||||
std::fs::remove_file(&path).ok();
|
||||
return Err(err.into());
|
||||
}
|
||||
write_pid(postfix);
|
||||
}
|
||||
Ok(incoming)
|
||||
@@ -642,15 +839,7 @@ async fn handle(data: Data, stream: &mut Connection) {
|
||||
"N".to_owned()
|
||||
});
|
||||
} else if name == "permanent-password-is-preset" {
|
||||
let hard = config::HARD_SETTINGS
|
||||
.read()
|
||||
.unwrap()
|
||||
.get("password")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let is_preset =
|
||||
!hard.is_empty() && Config::matches_permanent_password_plain(&hard);
|
||||
value = Some(if is_preset {
|
||||
value = Some(if Config::is_using_preset_password() {
|
||||
"Y".to_owned()
|
||||
} else {
|
||||
"N".to_owned()
|
||||
@@ -701,7 +890,7 @@ async fn handle(data: Data, stream: &mut Connection) {
|
||||
log::warn!("Changing permanent password is disabled");
|
||||
updated = false;
|
||||
} else {
|
||||
Config::set_permanent_password(&value);
|
||||
updated = Config::set_permanent_password(&value);
|
||||
}
|
||||
// Explicitly ACK/NACK permanent-password writes. This allows UIs/FFI to
|
||||
// distinguish "accepted by daemon" vs "IPC send succeeded" without
|
||||
@@ -770,6 +959,12 @@ async fn handle(data: Data, stream: &mut Connection) {
|
||||
Data::TestRendezvousServer => {
|
||||
crate::test_rendezvous_server();
|
||||
}
|
||||
Data::Deployed => {
|
||||
crate::rendezvous_mediator::NEEDS_DEPLOY.store(false, Ordering::SeqCst);
|
||||
crate::rendezvous_mediator::RendezvousMediator::restart();
|
||||
}
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Data::SwitchSidesRequest(id) => {
|
||||
let uuid = uuid::Uuid::new_v4();
|
||||
crate::server::insert_switch_sides_uuid(id, uuid.clone());
|
||||
@@ -779,6 +974,19 @@ async fn handle(data: Data, stream: &mut Connection) {
|
||||
.await
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "flutter")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Data::SwitchSidesUuid(uuid, id, None) => {
|
||||
let allowed = uuid
|
||||
.parse::<uuid::Uuid>()
|
||||
.map(|uuid| crate::server::remove_pending_switch_sides_uuid(&id, &uuid))
|
||||
.unwrap_or(false);
|
||||
allow_err!(
|
||||
stream
|
||||
.send(&Data::SwitchSidesUuid(uuid, id, Some(allowed)))
|
||||
.await
|
||||
);
|
||||
}
|
||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Data::Plugin(plugin) => crate::plugin::ipc::handle_plugin(plugin, stream).await,
|
||||
@@ -930,15 +1138,212 @@ async fn handle(data: Data, stream: &mut Connection) {
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) fn generate_one_time_ipc_token() -> ResultType<String> {
|
||||
use hbb_common::rand::{rngs::OsRng, RngCore as _};
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let mut random_bytes = [0u8; IPC_TOKEN_RANDOM_BYTES];
|
||||
let mut rng = OsRng;
|
||||
rng.try_fill_bytes(&mut random_bytes).map_err(|err| {
|
||||
hbb_common::anyhow::anyhow!(
|
||||
"failed to generate portable service ipc token from OsRng: {}",
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut token = String::with_capacity(IPC_TOKEN_LEN);
|
||||
for byte in random_bytes {
|
||||
let _ = write!(token, "{:02x}", byte);
|
||||
}
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) fn constant_time_ipc_token_eq(expected: &str, candidate: &str) -> bool {
|
||||
if expected.len() != IPC_TOKEN_LEN || candidate.len() != IPC_TOKEN_LEN {
|
||||
return false;
|
||||
}
|
||||
expected
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.zip(candidate.as_bytes().iter())
|
||||
.fold(0u8, |diff, (left, right)| diff | (*left ^ *right))
|
||||
== 0
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) async fn portable_service_ipc_handshake_as_client<T>(
|
||||
stream: &mut ConnectionTmpl<T>,
|
||||
token: &str,
|
||||
) -> ResultType<()>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + std::marker::Unpin,
|
||||
{
|
||||
stream
|
||||
.send(&Data::DataPortableService(DataPortableService::AuthToken(
|
||||
token.to_owned(),
|
||||
)))
|
||||
.await?;
|
||||
match stream
|
||||
.next_timeout(PORTABLE_SERVICE_IPC_HANDSHAKE_TIMEOUT_MS)
|
||||
.await?
|
||||
{
|
||||
Some(Data::DataPortableService(DataPortableService::AuthResult(true))) => Ok(()),
|
||||
Some(Data::DataPortableService(DataPortableService::AuthResult(false))) => {
|
||||
bail!("portable service ipc handshake was rejected by server")
|
||||
}
|
||||
Some(_) | None => bail!("portable service ipc handshake returned an unexpected response"),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect(ms_timeout: u64, postfix: &str) -> ResultType<ConnectionTmpl<ConnClient>> {
|
||||
let path = Config::ipc_path(postfix);
|
||||
let client = timeout(ms_timeout, Endpoint::connect(&path)).await??;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) async fn portable_service_ipc_handshake_as_server<T, F>(
|
||||
stream: &mut ConnectionTmpl<T>,
|
||||
mut validate_token: F,
|
||||
) -> ResultType<()>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + std::marker::Unpin,
|
||||
// Token validators must use `constant_time_ipc_token_eq` or an equivalent
|
||||
// fixed-length comparison; this handshake is part of the privilege boundary.
|
||||
F: FnMut(&str) -> bool,
|
||||
{
|
||||
let authorized = match stream
|
||||
.next_timeout(PORTABLE_SERVICE_IPC_HANDSHAKE_TIMEOUT_MS)
|
||||
.await?
|
||||
{
|
||||
Some(Data::DataPortableService(DataPortableService::AuthToken(token))) => {
|
||||
validate_token(&token)
|
||||
}
|
||||
Some(_) | None => false,
|
||||
};
|
||||
stream
|
||||
.send(&Data::DataPortableService(DataPortableService::AuthResult(
|
||||
authorized,
|
||||
)))
|
||||
.await?;
|
||||
if !authorized {
|
||||
bail!("portable service ipc handshake failed")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn connect_with_path(ms_timeout: u64, path: &str) -> ResultType<ConnectionTmpl<ConnClient>> {
|
||||
let client = timeout(ms_timeout, Endpoint::connect(path)).await??;
|
||||
Ok(ConnectionTmpl::new(client))
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[inline]
|
||||
fn select_server_uid_for_user_main_ipc(
|
||||
server_uids: &[u32],
|
||||
active_uid: Option<u32>,
|
||||
prefer_root: bool,
|
||||
) -> ResultType<u32> {
|
||||
let mut server_uids = server_uids.to_vec();
|
||||
server_uids.sort_unstable();
|
||||
server_uids.dedup();
|
||||
|
||||
match server_uids.as_slice() {
|
||||
[] => {
|
||||
if let Some(uid) = active_uid {
|
||||
// If no `--server` processes are found but the active user is identifiable,
|
||||
// try the active user anyway because the main process may also listen on "" IPC.
|
||||
return Ok(uid);
|
||||
} else {
|
||||
bail!("No --server process found for user main IPC")
|
||||
}
|
||||
}
|
||||
[uid] => return Ok(*uid),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if prefer_root && server_uids.contains(&0) {
|
||||
return Ok(0);
|
||||
}
|
||||
if let Some(active_uid) = active_uid.filter(|uid| server_uids.contains(uid)) {
|
||||
return Ok(active_uid);
|
||||
}
|
||||
bail!("Multiple --server processes found for user main IPC");
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn running_server_uids_for_current_exe() -> ResultType<Vec<u32>> {
|
||||
let current_exe = std::env::current_exe()?;
|
||||
let current_exe_path = std::fs::canonicalize(¤t_exe)?;
|
||||
let current_pid = hbb_common::sysinfo::Pid::from_u32(std::process::id());
|
||||
let mut sys = hbb_common::sysinfo::System::new();
|
||||
sys.refresh_processes();
|
||||
let mut server_uids = Vec::new();
|
||||
for process in sys.processes().values() {
|
||||
if process.pid() == current_pid {
|
||||
continue;
|
||||
}
|
||||
if process.cmd().get(1).map_or(true, |arg| arg != "--server") {
|
||||
continue;
|
||||
}
|
||||
let Ok(process_path) = std::fs::canonicalize(process.exe()) else {
|
||||
continue;
|
||||
};
|
||||
if process_path != current_exe_path {
|
||||
continue;
|
||||
}
|
||||
let Some(uid) = process.user_id().map(|uid| **uid as u32) else {
|
||||
// Root CLI management commands need a stable matching `--server` target.
|
||||
// If this key process races during enumeration, failing the command is clearer
|
||||
// than silently skipping it; `--server` is not expected to exit frequently.
|
||||
bail!("Failed to read --server process uid");
|
||||
};
|
||||
server_uids.push(uid);
|
||||
}
|
||||
Ok(server_uids)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn user_main_ipc_server_uid() -> ResultType<u32> {
|
||||
let server_uids = running_server_uids_for_current_exe()?;
|
||||
#[cfg(target_os = "linux")]
|
||||
let prefer_root = crate::platform::linux::is_login_screen_wayland();
|
||||
#[cfg(target_os = "macos")]
|
||||
let prefer_root = false;
|
||||
select_server_uid_for_user_main_ipc(&server_uids, active_uid(), prefer_root)
|
||||
}
|
||||
|
||||
pub async fn connect(ms_timeout: u64, postfix: &str) -> ResultType<ConnectionTmpl<ConnClient>> {
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
let use_user_main_ipc = USE_USER_MAIN_IPC.with(|use_user_main| use_user_main.get());
|
||||
let is_root_main_ipc =
|
||||
unsafe { hbb_common::libc::geteuid() == 0 } && postfix.is_empty() && use_user_main_ipc;
|
||||
if is_root_main_ipc {
|
||||
let uid = user_main_ipc_server_uid()?;
|
||||
let path = Config::ipc_path_for_uid(uid, postfix);
|
||||
return connect_with_path(ms_timeout, &path).await;
|
||||
}
|
||||
let path = Config::ipc_path(postfix);
|
||||
return connect_with_path(ms_timeout, &path).await;
|
||||
}
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
{
|
||||
let path = Config::ipc_path(postfix);
|
||||
connect_with_path(ms_timeout, &path).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn connect_for_uid(
|
||||
ms_timeout: u64,
|
||||
uid: u32,
|
||||
postfix: &str,
|
||||
) -> ResultType<ConnectionTmpl<ConnClient>> {
|
||||
let path = Config::ipc_path_for_uid(uid, postfix);
|
||||
connect_with_path(ms_timeout, &path).await
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn start_pa() {
|
||||
@@ -1016,54 +1421,6 @@ pub async fn start_pa() {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(windows))]
|
||||
fn get_pid_file(postfix: &str) -> String {
|
||||
let path = Config::ipc_path(postfix);
|
||||
format!("{}.pid", path)
|
||||
}
|
||||
|
||||
#[cfg(not(any(windows, target_os = "android", target_os = "ios")))]
|
||||
async fn check_pid(postfix: &str) {
|
||||
let pid_file = get_pid_file(postfix);
|
||||
if let Ok(mut file) = File::open(&pid_file) {
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).ok();
|
||||
let pid = content.parse::<usize>().unwrap_or(0);
|
||||
if pid > 0 {
|
||||
use hbb_common::sysinfo::System;
|
||||
let mut sys = System::new();
|
||||
sys.refresh_processes();
|
||||
if let Some(p) = sys.process(pid.into()) {
|
||||
if let Some(current) = sys.process((std::process::id() as usize).into()) {
|
||||
if current.name() == p.name() {
|
||||
// double check with connect
|
||||
if connect(1000, postfix).await.is_ok() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if not remove old ipc file, the new ipc creation will fail
|
||||
// if we remove a ipc file, but the old ipc process is still running,
|
||||
// new connection to the ipc will connect to new ipc, old connection to old ipc still keep alive
|
||||
std::fs::remove_file(&Config::ipc_path(postfix)).ok();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(windows))]
|
||||
fn write_pid(postfix: &str) {
|
||||
let path = get_pid_file(postfix);
|
||||
if let Ok(mut file) = File::create(&path) {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok();
|
||||
file.write_all(&std::process::id().to_string().into_bytes())
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectionTmpl<T> {
|
||||
inner: Framed<T, BytesCodec>,
|
||||
}
|
||||
@@ -1185,11 +1542,6 @@ fn apply_permanent_password_storage_and_salt_payload(payload: Option<&str>) -> R
|
||||
bail!("Invalid permanent-password-storage-and-salt payload");
|
||||
};
|
||||
|
||||
if storage.is_empty() {
|
||||
Config::set_permanent_password_storage_for_sync("", "")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Config::set_permanent_password_storage_for_sync(storage, salt)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1510,6 +1862,13 @@ pub async fn test_rendezvous_server() -> ResultType<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn notify_deployed() -> ResultType<()> {
|
||||
let mut c = connect(1000, "").await?;
|
||||
c.send(&Data::Deployed).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn send_url_scheme(url: String) -> ResultType<()> {
|
||||
connect(1_000, "_url")
|
||||
@@ -1527,9 +1886,10 @@ pub fn close_all_instances() -> ResultType<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn connect_to_user_session(usid: Option<u32>) -> ResultType<()> {
|
||||
let mut stream = crate::ipc::connect(1000, crate::POSTFIX_SERVICE).await?;
|
||||
let mut stream = crate::ipc::connect_service(1000).await?;
|
||||
timeout(1000, stream.send(&crate::ipc::Data::UserSid(usid))).await??;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1655,13 +2015,76 @@ pub async fn update_controlling_session_count(count: usize) -> ResultType<()> {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn get_terminal_session_count() -> ResultType<usize> {
|
||||
let ms_timeout = 1_000;
|
||||
let mut c = connect(ms_timeout, "").await?;
|
||||
c.send(&Data::TerminalSessionCount(0)).await?;
|
||||
if let Some(Data::TerminalSessionCount(c)) = c.next_timeout(ms_timeout).await? {
|
||||
return Ok(c);
|
||||
let timeout_ms = 1_000;
|
||||
let effective_uid = unsafe { hbb_common::libc::geteuid() as u32 };
|
||||
let candidate_uids = terminal_count_candidate_uids(effective_uid);
|
||||
let mut last_err: Option<anyhow::Error> = None;
|
||||
for candidate_uid in candidate_uids {
|
||||
let socket_path = Config::ipc_path_for_uid(candidate_uid, "");
|
||||
let connect_result = timeout(timeout_ms, Endpoint::connect(&socket_path))
|
||||
.await
|
||||
.map_err(|err| {
|
||||
anyhow::anyhow!(
|
||||
"Timeout connecting to terminal ipc at {}: {}",
|
||||
socket_path,
|
||||
err
|
||||
)
|
||||
});
|
||||
let connection = match connect_result {
|
||||
Ok(Ok(connection)) => connection,
|
||||
Ok(Err(err)) => {
|
||||
last_err = Some(anyhow::anyhow!(
|
||||
"Failed to connect to terminal ipc at {}: {}",
|
||||
socket_path,
|
||||
err
|
||||
));
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
last_err = Some(err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let mut ipc_conn = ConnectionTmpl::new(connection);
|
||||
if let Err(err) = ipc_conn.send(&Data::TerminalSessionCount(0)).await {
|
||||
last_err = Some(anyhow::anyhow!(
|
||||
"Failed to request terminal session count via ipc at {}: {}",
|
||||
socket_path,
|
||||
err
|
||||
));
|
||||
continue;
|
||||
}
|
||||
match ipc_conn.next_timeout(timeout_ms).await {
|
||||
Ok(Some(Data::TerminalSessionCount(session_count))) => {
|
||||
return Ok(session_count);
|
||||
}
|
||||
Ok(None) => {
|
||||
last_err = Some(anyhow::anyhow!(
|
||||
"Invalid response when requesting terminal session count via ipc at {}",
|
||||
socket_path
|
||||
));
|
||||
}
|
||||
Ok(other) => {
|
||||
last_err = Some(anyhow::anyhow!(
|
||||
"Unexpected response when requesting terminal session count via ipc at {}: {:?}",
|
||||
socket_path,
|
||||
other.map(|v| std::mem::discriminant(&v))
|
||||
));
|
||||
}
|
||||
Err(err) => {
|
||||
last_err = Some(anyhow::anyhow!(
|
||||
"Failed to read terminal session count via ipc at {}: {}",
|
||||
socket_path,
|
||||
err
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(err) = last_err {
|
||||
Err(err.into())
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
async fn handle_wayland_screencast_restore_token(
|
||||
@@ -1692,9 +2115,81 @@ pub async fn set_install_option(k: String, v: String) -> ResultType<()> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn verify_ffi_enum_data_size() {
|
||||
println!("{}", std::mem::size_of::<Data>());
|
||||
assert!(std::mem::size_of::<Data>() <= 120);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_service_ipc_path_is_shared_across_uids() {
|
||||
assert_eq!(
|
||||
Config::ipc_path_for_uid(0, crate::POSTFIX_SERVICE),
|
||||
Config::ipc_path_for_uid(501, crate::POSTFIX_SERVICE)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_ipc_path_differs_by_uid_for_cm() {
|
||||
let effective_uid = unsafe { hbb_common::libc::geteuid() as u32 };
|
||||
let other_uid = effective_uid.saturating_add(1);
|
||||
let postfix = "_cm";
|
||||
|
||||
// Default connect path targets the current effective uid.
|
||||
assert_eq!(
|
||||
Config::ipc_path(postfix),
|
||||
Config::ipc_path_for_uid(effective_uid, postfix)
|
||||
);
|
||||
// A different uid yields a different socket path - this is the root cause of the
|
||||
// cross-user regression when root spawns a user process but still connects as uid 0.
|
||||
assert_ne!(
|
||||
Config::ipc_path(postfix),
|
||||
Config::ipc_path_for_uid(other_uid, postfix)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_select_server_uid_uses_active_uid_when_no_server_found() {
|
||||
assert_eq!(
|
||||
select_server_uid_for_user_main_ipc(&[], Some(501), false).unwrap(),
|
||||
501
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_select_server_uid_uses_single_server_uid() {
|
||||
assert_eq!(
|
||||
select_server_uid_for_user_main_ipc(&[501], None, false).unwrap(),
|
||||
501
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_select_server_uid_prefers_active_uid_with_multiple_servers() {
|
||||
assert_eq!(
|
||||
select_server_uid_for_user_main_ipc(&[0, 501], Some(501), false).unwrap(),
|
||||
501
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_select_server_uid_prefers_root_on_wayland_login_screen() {
|
||||
assert_eq!(
|
||||
select_server_uid_for_user_main_ipc(&[0, 501], Some(501), true).unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_select_server_uid_fails_when_multiple_servers_are_ambiguous() {
|
||||
assert!(select_server_uid_for_user_main_ipc(&[501, 502], None, false).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
1075
src/ipc/auth.rs
Normal file
1075
src/ipc/auth.rs
Normal file
File diff suppressed because it is too large
Load Diff
951
src/ipc/fs.rs
Normal file
951
src/ipc/fs.rs
Normal file
@@ -0,0 +1,951 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
use super::ipc_auth::active_uid;
|
||||
use crate::ipc::{connect, Data};
|
||||
use hbb_common::{config, log, ResultType};
|
||||
use std::{
|
||||
ffi::CString,
|
||||
io::{Error, ErrorKind},
|
||||
os::unix::ffi::OsStrExt,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
struct FdGuard(i32);
|
||||
impl Drop for FdGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
hbb_common::libc::close(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
pub(crate) fn terminal_count_candidate_uids(effective_uid: u32) -> Vec<u32> {
|
||||
if effective_uid != 0 {
|
||||
return vec![effective_uid];
|
||||
}
|
||||
let mut candidates = Vec::with_capacity(2);
|
||||
if let Some(uid) = active_uid().filter(|uid| *uid != 0) {
|
||||
candidates.push(uid);
|
||||
}
|
||||
candidates.push(0);
|
||||
candidates
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn expected_ipc_parent_mode(postfix: &str) -> u32 {
|
||||
if config::is_service_ipc_postfix(postfix) {
|
||||
0o0711
|
||||
} else {
|
||||
0o0700
|
||||
}
|
||||
}
|
||||
|
||||
fn open_ipc_parent_dir_fd(parent_c: &CString) -> std::io::Result<i32> {
|
||||
let fd = unsafe {
|
||||
hbb_common::libc::open(
|
||||
parent_c.as_ptr(),
|
||||
hbb_common::libc::O_RDONLY
|
||||
| hbb_common::libc::O_DIRECTORY
|
||||
| hbb_common::libc::O_CLOEXEC
|
||||
| hbb_common::libc::O_NOFOLLOW,
|
||||
)
|
||||
};
|
||||
if fd < 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(fd)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove one preexisting IPC artifact via an already-opened parent directory FD.
|
||||
//
|
||||
// Security intent:
|
||||
// - Bind cleanup to the exact parent inode that passed O_NOFOLLOW + fstat checks.
|
||||
// - Avoid path-based TOCTOU during scrub (e.g., parent path rename/swap race).
|
||||
//
|
||||
// Flow:
|
||||
// 1) fstatat(..., AT_SYMLINK_NOFOLLOW) to inspect the target entry under parent_fd.
|
||||
// 2) Decide file vs directory from st_mode.
|
||||
// 3) unlinkat relative to parent_fd (AT_REMOVEDIR for directories).
|
||||
//
|
||||
// Error policy:
|
||||
// - NotFound is treated as benign (already removed / raced away).
|
||||
// - Other errors are surfaced explicitly.
|
||||
fn remove_parent_entry_via_fd(
|
||||
parent_fd: i32,
|
||||
parent_dir: &Path,
|
||||
entry_name: &str,
|
||||
) -> ResultType<()> {
|
||||
if entry_name.contains('/') {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!(
|
||||
"invalid ipc parent entry name (contains '/'): parent={}, entry={}",
|
||||
parent_dir.display(),
|
||||
entry_name
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let entry_c = CString::new(entry_name.as_bytes().to_vec()).map_err(|err| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!(
|
||||
"invalid ipc parent entry name: parent={}, entry={}, err={}",
|
||||
parent_dir.display(),
|
||||
entry_name,
|
||||
err
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let mut stat: hbb_common::libc::stat = unsafe { std::mem::zeroed() };
|
||||
let stat_rc = unsafe {
|
||||
hbb_common::libc::fstatat(
|
||||
parent_fd,
|
||||
entry_c.as_ptr(),
|
||||
&mut stat,
|
||||
hbb_common::libc::AT_SYMLINK_NOFOLLOW,
|
||||
)
|
||||
};
|
||||
if stat_rc != 0 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
if err.kind() == ErrorKind::NotFound {
|
||||
return Ok(());
|
||||
}
|
||||
return Err(Error::new(
|
||||
err.kind(),
|
||||
format!(
|
||||
"failed to stat preexisting ipc parent dir entry by fd: parent={}, entry={}, err={}",
|
||||
parent_dir.display(),
|
||||
entry_name,
|
||||
err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let is_dir = (stat.st_mode & (hbb_common::libc::S_IFMT as hbb_common::libc::mode_t))
|
||||
== hbb_common::libc::S_IFDIR;
|
||||
let unlink_flags = if is_dir {
|
||||
hbb_common::libc::AT_REMOVEDIR
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let unlink_rc =
|
||||
unsafe { hbb_common::libc::unlinkat(parent_fd, entry_c.as_ptr(), unlink_flags) };
|
||||
if unlink_rc != 0 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
if err.kind() == ErrorKind::NotFound {
|
||||
return Ok(());
|
||||
}
|
||||
return Err(Error::new(
|
||||
err.kind(),
|
||||
format!(
|
||||
"failed to remove preexisting ipc parent dir entry by fd: parent={}, entry={}, err={}",
|
||||
parent_dir.display(),
|
||||
entry_name,
|
||||
err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn scrub_preexisting_ipc_parent_entries(
|
||||
parent_fd: i32,
|
||||
parent_dir: &Path,
|
||||
postfix: &str,
|
||||
) -> ResultType<()> {
|
||||
let ipc_basename = format!("ipc{}", postfix);
|
||||
remove_parent_entry_via_fd(parent_fd, parent_dir, &ipc_basename)?;
|
||||
remove_parent_entry_via_fd(parent_fd, parent_dir, &format!("{}.pid", ipc_basename))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_ipc_socket_via_secure_parent_fd(postfix: &str) -> ResultType<()> {
|
||||
let path = config::Config::ipc_path(postfix);
|
||||
let parent_dir = Path::new(&path)
|
||||
.parent()
|
||||
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("invalid ipc path: {path}")))?;
|
||||
let parent_c = CString::new(parent_dir.as_os_str().as_bytes().to_vec())?;
|
||||
let fd = match open_ipc_parent_dir_fd(&parent_c) {
|
||||
Ok(fd) => fd,
|
||||
Err(open_err) => {
|
||||
if open_err.kind() == ErrorKind::NotFound {
|
||||
return Ok(());
|
||||
}
|
||||
return Err(Error::new(
|
||||
open_err.kind(),
|
||||
format!(
|
||||
"failed to open ipc parent dir for stale socket cleanup (no-follow): postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
open_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
let _fd_guard = FdGuard(fd);
|
||||
remove_parent_entry_via_fd(fd, parent_dir, &format!("ipc{}", postfix))
|
||||
}
|
||||
|
||||
// Purpose:
|
||||
// - Harden the IPC parent directory before creating/listening socket files.
|
||||
// - Prevent symlink/path-race abuse and reject unsafe owner/mode.
|
||||
//
|
||||
// Approach:
|
||||
// - Open parent dir with O_NOFOLLOW/O_DIRECTORY and operate on that fd.
|
||||
// - Validate inode type/owner/mode via fstat.
|
||||
// - For protected service postfix, optionally adopt owner (root only), then scrub stale
|
||||
// rustdesk IPC artifacts when directory trust boundary changed.
|
||||
//
|
||||
// Main steps:
|
||||
// 1) Resolve parent path and open/create directory securely.
|
||||
// 2) Verify directory inode type and owner uid.
|
||||
// 3) Enforce expected mode via fchmod on opened fd.
|
||||
// 4) Scrub stale IPC artifacts when owner/mode was unsafe before hardening.
|
||||
//
|
||||
// References:
|
||||
// - open(2): O_NOFOLLOW/O_DIRECTORY/O_CLOEXEC
|
||||
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||
// - fstat(2): verify file type/metadata on opened fd
|
||||
// https://man7.org/linux/man-pages/man2/fstat.2.html
|
||||
// - fchown(2): adopt ownership when running as root
|
||||
// https://man7.org/linux/man-pages/man2/chown.2.html
|
||||
// - fchmod(2): enforce exact mode on opened fd
|
||||
// https://man7.org/linux/man-pages/man2/fchmod.2.html
|
||||
pub(crate) fn ensure_secure_ipc_parent_dir(path: &str, postfix: &str) -> ResultType<bool> {
|
||||
let parent_dir = Path::new(path)
|
||||
.parent()
|
||||
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("invalid ipc path: {path}")))?;
|
||||
// Harden against common TOCTOU by opening the parent directory with O_NOFOLLOW (so the parent
|
||||
// itself cannot be a symlink) and then operating on its FD (fstat/fchown/fchmod). This ensures
|
||||
// we mutate the inode we opened, though it does not protect against symlinks in ancestor path
|
||||
// components.
|
||||
let parent_c = CString::new(parent_dir.as_os_str().as_bytes().to_vec())?;
|
||||
let fd = match open_ipc_parent_dir_fd(&parent_c) {
|
||||
Ok(fd) => fd,
|
||||
Err(open_err) => {
|
||||
// If the directory doesn't exist yet, create it with the expected mode. The parent
|
||||
// dir is intended to be a single-level /tmp path, so mkdir is sufficient here.
|
||||
if open_err.raw_os_error() == Some(hbb_common::libc::ENOENT) {
|
||||
let expected_mode = expected_ipc_parent_mode(postfix);
|
||||
let rc = unsafe {
|
||||
hbb_common::libc::mkdir(
|
||||
parent_c.as_ptr(),
|
||||
expected_mode as hbb_common::libc::mode_t,
|
||||
)
|
||||
};
|
||||
if rc != 0 {
|
||||
let mkdir_err = std::io::Error::last_os_error();
|
||||
// Handle a race where another process created the directory first.
|
||||
if mkdir_err.raw_os_error() != Some(hbb_common::libc::EEXIST) {
|
||||
return Err(Error::new(
|
||||
mkdir_err.kind(),
|
||||
format!(
|
||||
"failed to mkdir ipc parent dir: postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
mkdir_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
match open_ipc_parent_dir_fd(&parent_c) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
return Err(Error::new(
|
||||
err.kind(),
|
||||
format!(
|
||||
"failed to open ipc parent dir (no-follow): postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
open_err.kind(),
|
||||
format!(
|
||||
"failed to open ipc parent dir (no-follow): postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
open_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
let _fd_guard = FdGuard(fd);
|
||||
|
||||
let mut st: hbb_common::libc::stat = unsafe { std::mem::zeroed() };
|
||||
if unsafe { hbb_common::libc::fstat(fd, &mut st as *mut _) } != 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!(
|
||||
"failed to stat ipc parent dir: postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
os_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let mode = st.st_mode as u32;
|
||||
let is_dir = (mode & (hbb_common::libc::S_IFMT as u32)) == (hbb_common::libc::S_IFDIR as u32);
|
||||
if !is_dir {
|
||||
return Err(Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
format!(
|
||||
"ipc parent is not directory: postfix={}, parent={}",
|
||||
postfix,
|
||||
parent_dir.display()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let expected_uid = unsafe { hbb_common::libc::geteuid() as u32 };
|
||||
let mut owner_uid = st.st_uid as u32;
|
||||
let mut adopted_foreign_service_parent = false;
|
||||
// Service-scoped IPC may be created by different privilege contexts historically.
|
||||
// If running as root on protected service postfix, try adopting ownership first.
|
||||
if owner_uid != expected_uid && expected_uid == 0 && config::is_service_ipc_postfix(postfix) {
|
||||
let rc = unsafe {
|
||||
hbb_common::libc::fchown(
|
||||
fd,
|
||||
expected_uid as hbb_common::libc::uid_t,
|
||||
hbb_common::libc::gid_t::MAX,
|
||||
)
|
||||
};
|
||||
if rc == 0 {
|
||||
let mut st2: hbb_common::libc::stat = unsafe { std::mem::zeroed() };
|
||||
if unsafe { hbb_common::libc::fstat(fd, &mut st2 as *mut _) } == 0 {
|
||||
owner_uid = st2.st_uid as u32;
|
||||
st = st2;
|
||||
adopted_foreign_service_parent = true;
|
||||
}
|
||||
} else {
|
||||
// Keep behavior unchanged; capture errno to ease diagnosing why chown failed.
|
||||
let err = std::io::Error::last_os_error();
|
||||
log::warn!(
|
||||
"Failed to chown ipc parent dir, parent={}, postfix={}, expected_uid={}, rc={}, err={:?}",
|
||||
parent_dir.display(),
|
||||
postfix,
|
||||
expected_uid,
|
||||
rc,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
if owner_uid != expected_uid {
|
||||
return Err(Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
format!(
|
||||
"unsafe ipc parent owner, postfix={}, expected uid {expected_uid}, got {owner_uid}: {}",
|
||||
postfix,
|
||||
parent_dir.display()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let expected_mode = expected_ipc_parent_mode(postfix);
|
||||
// Include special bits (setuid/setgid/sticky) to ensure the directory is hardened to the exact
|
||||
// expected mode.
|
||||
let current_mode = (st.st_mode as u32) & 0o7777;
|
||||
let repaired_parent_mode = current_mode != expected_mode;
|
||||
let had_untrusted_parent_mode = (current_mode & 0o022) != 0;
|
||||
if repaired_parent_mode {
|
||||
// Use fchmod on the opened fd to avoid path-race between check and chmod.
|
||||
if unsafe { hbb_common::libc::fchmod(fd, expected_mode as hbb_common::libc::mode_t) } != 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!(
|
||||
"failed to chmod ipc parent dir: postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
os_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
let should_scrub =
|
||||
repaired_parent_mode || adopted_foreign_service_parent || had_untrusted_parent_mode;
|
||||
Ok(should_scrub)
|
||||
}
|
||||
|
||||
pub(crate) fn scrub_secure_ipc_parent_dir(path: &str, postfix: &str) -> ResultType<()> {
|
||||
let parent_dir = Path::new(path)
|
||||
.parent()
|
||||
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("invalid ipc path: {path}")))?;
|
||||
let parent_c = CString::new(parent_dir.as_os_str().as_bytes().to_vec())?;
|
||||
let fd = open_ipc_parent_dir_fd(&parent_c).map_err(|err| {
|
||||
Error::new(
|
||||
err.kind(),
|
||||
format!(
|
||||
"failed to open ipc parent dir for scrub (no-follow): postfix={}, parent={}, err={}",
|
||||
postfix,
|
||||
parent_dir.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let _fd_guard = FdGuard(fd);
|
||||
scrub_preexisting_ipc_parent_entries(fd, parent_dir, postfix)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_pid_file(postfix: &str) -> String {
|
||||
let path = config::Config::ipc_path(postfix);
|
||||
format!("{}.pid", path)
|
||||
}
|
||||
|
||||
// Purpose:
|
||||
// - Write current process pid to pid file without following attacker-controlled symlinks.
|
||||
// - Ensure the pid file is a regular file owned by the opened inode path.
|
||||
//
|
||||
// Approach:
|
||||
// - Use libc open/fstat/write syscalls (FFI) so flags and inode validation are explicit.
|
||||
// - Open file with O_NOFOLLOW/O_CLOEXEC and verify S_IFREG with fstat before write.
|
||||
// - Keep unsafe scopes minimal and check syscall return values immediately.
|
||||
//
|
||||
// Main steps:
|
||||
// 1) Secure-open pid file (without truncation).
|
||||
// 2) Validate opened inode is a regular file owned by current euid.
|
||||
// 3) Enforce pid file mode to 0600 and truncate via ftruncate after validation.
|
||||
// 4) Write process id bytes through fd.
|
||||
//
|
||||
// Why not plain std::fs::write?
|
||||
// - std::fs helpers cannot enforce this exact open-time hardening sequence
|
||||
// (especially "open with O_NOFOLLOW, then fstat the same opened inode").
|
||||
//
|
||||
// References:
|
||||
// - open(2): O_NOFOLLOW/O_CLOEXEC/O_NONBLOCK
|
||||
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||
// - fstat(2): verify file type on opened fd
|
||||
// https://man7.org/linux/man-pages/man2/fstat.2.html
|
||||
// - fchmod(2): enforce secure mode on reused pid file
|
||||
// https://man7.org/linux/man-pages/man2/fchmod.2.html
|
||||
// - ftruncate(2): truncate after validation
|
||||
// https://man7.org/linux/man-pages/man2/ftruncate.2.html
|
||||
// - write(2): write bytes via fd
|
||||
// https://man7.org/linux/man-pages/man2/write.2.html
|
||||
fn write_pid_file(path: &Path) -> ResultType<()> {
|
||||
let path_c = CString::new(path.as_os_str().as_bytes().to_vec()).map_err(|err| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("invalid pid file path '{}': {}", path.display(), err),
|
||||
)
|
||||
})?;
|
||||
let flags = hbb_common::libc::O_WRONLY
|
||||
| hbb_common::libc::O_CREAT
|
||||
| hbb_common::libc::O_CLOEXEC
|
||||
| hbb_common::libc::O_NOFOLLOW
|
||||
| hbb_common::libc::O_NONBLOCK;
|
||||
let fd = unsafe { hbb_common::libc::open(path_c.as_ptr(), flags, 0o0600) };
|
||||
if fd < 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!(
|
||||
"failed to open pid file with no-follow '{}': {}",
|
||||
path.display(),
|
||||
os_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let _fd_guard = FdGuard(fd);
|
||||
let mut stat: hbb_common::libc::stat = unsafe { std::mem::zeroed() };
|
||||
if unsafe { hbb_common::libc::fstat(fd, &mut stat) } != 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!("failed to stat pid file '{}': {}", path.display(), os_err),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
if (stat.st_mode & (hbb_common::libc::S_IFMT as hbb_common::libc::mode_t))
|
||||
!= (hbb_common::libc::S_IFREG as hbb_common::libc::mode_t)
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
format!("pid file path is not a regular file: '{}'", path.display()),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let expected_uid = unsafe { hbb_common::libc::geteuid() as u32 };
|
||||
if stat.st_uid as u32 != expected_uid {
|
||||
return Err(Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
format!(
|
||||
"pid file owner mismatch: expected uid {}, got {} for '{}'",
|
||||
expected_uid,
|
||||
stat.st_uid,
|
||||
path.display()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
if unsafe { hbb_common::libc::fchmod(fd, 0o600) } != 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!("failed to chmod pid file '{}': {}", path.display(), os_err),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
if unsafe { hbb_common::libc::ftruncate(fd, 0) } != 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!(
|
||||
"failed to truncate pid file '{}': {}",
|
||||
path.display(),
|
||||
os_err
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let bytes = std::process::id().to_string();
|
||||
let buf = bytes.as_bytes();
|
||||
// `write(2)` is allowed to return a short write even for regular files.
|
||||
// PID content is tiny and usually written in one shot, but we still loop
|
||||
// until all bytes are persisted so this path is semantically correct.
|
||||
let mut written = 0usize;
|
||||
while written < buf.len() {
|
||||
let rc = unsafe {
|
||||
hbb_common::libc::write(
|
||||
fd,
|
||||
buf[written..].as_ptr() as *const hbb_common::libc::c_void,
|
||||
buf.len() - written,
|
||||
)
|
||||
};
|
||||
if rc < 0 {
|
||||
let os_err = std::io::Error::last_os_error();
|
||||
return Err(Error::new(
|
||||
os_err.kind(),
|
||||
format!("failed to write pid file '{}': {}", path.display(), os_err),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
if rc == 0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::WriteZero,
|
||||
format!(
|
||||
"failed to write pid file '{}': write returned 0 bytes",
|
||||
path.display()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
written += rc as usize;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn write_pid(postfix: &str) {
|
||||
let path = std::path::PathBuf::from(get_pid_file(postfix));
|
||||
if let Err(err) = write_pid_file(&path) {
|
||||
log::warn!(
|
||||
"Failed to write pid file for postfix '{}', path='{}', err={}",
|
||||
postfix,
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Purpose:
|
||||
// - Read pid file safely and avoid trusting symlink/non-regular files.
|
||||
//
|
||||
// Approach:
|
||||
// - Use libc open/fstat/read syscalls (FFI) to control flags and inode checks.
|
||||
// - Open path with O_NOFOLLOW, validate opened fd via fstat, then read and parse.
|
||||
// - Keep unsafe scopes minimal and check syscall return values immediately.
|
||||
//
|
||||
// Main steps:
|
||||
// 1) Secure-open pid file read-only.
|
||||
// 2) Ensure fd points to regular file.
|
||||
// 3) Read bytes and parse usize pid.
|
||||
//
|
||||
// References:
|
||||
// - open(2): O_NOFOLLOW/O_CLOEXEC/O_NONBLOCK
|
||||
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||
// - fstat(2): validate S_IFREG on opened fd
|
||||
// https://man7.org/linux/man-pages/man2/fstat.2.html
|
||||
// - read(2): read bytes via fd
|
||||
// https://man7.org/linux/man-pages/man2/read.2.html
|
||||
#[inline]
|
||||
fn read_pid_file_secure(path: &Path) -> Option<usize> {
|
||||
let path_c = CString::new(path.as_os_str().as_bytes().to_vec()).ok()?;
|
||||
let flags = hbb_common::libc::O_RDONLY
|
||||
| hbb_common::libc::O_CLOEXEC
|
||||
| hbb_common::libc::O_NOFOLLOW
|
||||
| hbb_common::libc::O_NONBLOCK;
|
||||
let fd = unsafe { hbb_common::libc::open(path_c.as_ptr(), flags) };
|
||||
if fd < 0 {
|
||||
return None;
|
||||
}
|
||||
let _fd_guard = FdGuard(fd);
|
||||
|
||||
let mut stat: hbb_common::libc::stat = unsafe { std::mem::zeroed() };
|
||||
if unsafe { hbb_common::libc::fstat(fd, &mut stat) } != 0 {
|
||||
return None;
|
||||
}
|
||||
if (stat.st_mode & (hbb_common::libc::S_IFMT as hbb_common::libc::mode_t))
|
||||
!= (hbb_common::libc::S_IFREG as hbb_common::libc::mode_t)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut buffer = [0u8; 64];
|
||||
let read_len = unsafe {
|
||||
hbb_common::libc::read(
|
||||
fd,
|
||||
buffer.as_mut_ptr() as *mut hbb_common::libc::c_void,
|
||||
buffer.len(),
|
||||
)
|
||||
};
|
||||
if read_len <= 0 {
|
||||
return None;
|
||||
}
|
||||
let content = String::from_utf8_lossy(&buffer[..read_len as usize]).to_string();
|
||||
content.trim().parse::<usize>().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn probe_existing_listener(postfix: &str) -> bool {
|
||||
let Ok(mut stream) = connect(1000, postfix).await else {
|
||||
return false;
|
||||
};
|
||||
if postfix != crate::POSTFIX_SERVICE {
|
||||
return true;
|
||||
}
|
||||
if stream.send(&Data::SyncConfig(None)).await.is_err() {
|
||||
return false;
|
||||
}
|
||||
matches!(
|
||||
stream.next_timeout(1000).await,
|
||||
Ok(Some(Data::SyncConfig(Some(_))))
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn check_pid(postfix: &str) -> bool {
|
||||
let pid_file = std::path::PathBuf::from(get_pid_file(postfix));
|
||||
if let Some(pid) = read_pid_file_secure(&pid_file) {
|
||||
if pid > 0 {
|
||||
let mut sys = hbb_common::sysinfo::System::new();
|
||||
sys.refresh_processes();
|
||||
if let Some(p) = sys.process(pid.into()) {
|
||||
if let Some(current) = sys.process((std::process::id() as usize).into()) {
|
||||
if current.name() == p.name() && probe_existing_listener(postfix).await {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if probe_existing_listener(postfix).await {
|
||||
return true;
|
||||
}
|
||||
// if not remove old ipc file, the new ipc creation will fail
|
||||
// if we remove a ipc file, but the old ipc process is still running,
|
||||
// new connection to the ipc will connect to new ipc, old connection to old ipc still keep alive
|
||||
if let Err(err) = remove_ipc_socket_via_secure_parent_fd(postfix) {
|
||||
log::debug!(
|
||||
"Failed to remove stale ipc socket via secure parent fd: postfix={}, err={}",
|
||||
postfix,
|
||||
err
|
||||
);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn should_scrub_parent_entries_after_check_pid(
|
||||
should_scrub_parent_entries: bool,
|
||||
existing_listener_alive: bool,
|
||||
) -> bool {
|
||||
should_scrub_parent_entries && !existing_listener_alive
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_write_pid_file_rejects_symlink() {
|
||||
use std::os::unix::fs::symlink;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-pid-file-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
let target = base.join("target_pid");
|
||||
std::fs::write(&target, b"origin").unwrap();
|
||||
let link = base.join("pid_link");
|
||||
symlink(&target, &link).unwrap();
|
||||
|
||||
let res = super::write_pid_file(&link);
|
||||
assert!(res.is_err());
|
||||
assert_eq!(std::fs::read_to_string(&target).unwrap(), "origin");
|
||||
|
||||
std::fs::remove_file(&link).ok();
|
||||
std::fs::remove_file(&target).ok();
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ensure_secure_ipc_parent_dir_rejects_symlink_parent() {
|
||||
use std::os::unix::fs::symlink;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-secure-dir-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
let real_dir = base.join("real");
|
||||
let link_dir = base.join("link");
|
||||
std::fs::create_dir_all(&real_dir).unwrap();
|
||||
symlink(&real_dir, &link_dir).unwrap();
|
||||
let ipc_path = link_dir.join("ipc_service");
|
||||
let res =
|
||||
super::ensure_secure_ipc_parent_dir(ipc_path.to_string_lossy().as_ref(), "_service");
|
||||
assert!(res.is_err());
|
||||
std::fs::remove_file(&link_dir).ok();
|
||||
std::fs::remove_dir_all(&real_dir).ok();
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ensure_secure_ipc_parent_dir_creates_parent_with_expected_mode() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-secure-dir-create-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
// Intentionally choose a parent that does not exist to exercise the ENOENT -> mkdir branch.
|
||||
let parent_dir = base.join("parent");
|
||||
assert!(!parent_dir.exists());
|
||||
let ipc_path = parent_dir.join("ipc");
|
||||
|
||||
let res = super::ensure_secure_ipc_parent_dir(ipc_path.to_string_lossy().as_ref(), "");
|
||||
// Restrictive umask can make mkdir create a stricter initial mode. In that case
|
||||
// ensure_secure_ipc_parent_dir repairs it with fchmod and may request a scrub.
|
||||
res.unwrap();
|
||||
|
||||
let md = std::fs::metadata(&parent_dir).unwrap();
|
||||
assert!(md.is_dir());
|
||||
let mode = md.permissions().mode() & 0o777;
|
||||
assert_eq!(mode, 0o0700);
|
||||
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scrub_preexisting_ipc_parent_entries_only_removes_target_postfix_artifacts() {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-scrub-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
let ipc_file = base.join("ipc_service");
|
||||
let ipc_pid_file = base.join("ipc_service.pid");
|
||||
let ipc_other_postfix_file = base.join("ipc_uinput_1");
|
||||
let keep_file = base.join("keep.txt");
|
||||
let keep_dir = base.join("keep_dir");
|
||||
|
||||
std::fs::write(&ipc_file, b"socket-placeholder").unwrap();
|
||||
std::fs::write(&ipc_pid_file, b"1234").unwrap();
|
||||
std::fs::write(&ipc_other_postfix_file, b"other-postfix").unwrap();
|
||||
std::fs::write(&keep_file, b"keep").unwrap();
|
||||
std::fs::create_dir_all(&keep_dir).unwrap();
|
||||
|
||||
let base_c = std::ffi::CString::new(base.as_os_str().as_bytes().to_vec()).unwrap();
|
||||
let base_fd = super::open_ipc_parent_dir_fd(&base_c).unwrap();
|
||||
let _base_guard = super::FdGuard(base_fd);
|
||||
super::scrub_preexisting_ipc_parent_entries(base_fd, &base, "_service").unwrap();
|
||||
|
||||
assert!(!ipc_file.exists());
|
||||
assert!(!ipc_pid_file.exists());
|
||||
assert!(ipc_other_postfix_file.exists());
|
||||
assert!(keep_file.exists());
|
||||
assert!(keep_dir.exists());
|
||||
|
||||
std::fs::remove_file(&ipc_other_postfix_file).ok();
|
||||
std::fs::remove_file(&keep_file).ok();
|
||||
std::fs::remove_dir_all(&keep_dir).ok();
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scrub_preexisting_ipc_parent_entries_should_bind_to_opened_inode_not_path() {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-scrub-fd-bind-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
let trusted_parent = base.join("trusted_parent");
|
||||
let trusted_parent_moved = base.join("trusted_parent_moved");
|
||||
let attacker_parent = base.join("attacker_parent");
|
||||
std::fs::create_dir_all(&trusted_parent).unwrap();
|
||||
std::fs::create_dir_all(&attacker_parent).unwrap();
|
||||
|
||||
let trusted_ipc_file = trusted_parent.join("ipc_service");
|
||||
let attacker_ipc_file = attacker_parent.join("ipc_service");
|
||||
std::fs::write(&trusted_ipc_file, b"trusted").unwrap();
|
||||
std::fs::write(&attacker_ipc_file, b"attacker").unwrap();
|
||||
|
||||
let trusted_parent_c =
|
||||
std::ffi::CString::new(trusted_parent.as_os_str().as_bytes().to_vec()).unwrap();
|
||||
let trusted_parent_fd = super::open_ipc_parent_dir_fd(&trusted_parent_c).unwrap();
|
||||
let _trusted_parent_guard = super::FdGuard(trusted_parent_fd);
|
||||
|
||||
// Swap the path after the trusted inode has been opened.
|
||||
std::fs::rename(&trusted_parent, &trusted_parent_moved).unwrap();
|
||||
std::fs::rename(&attacker_parent, &trusted_parent).unwrap();
|
||||
|
||||
super::scrub_preexisting_ipc_parent_entries(trusted_parent_fd, &trusted_parent, "_service")
|
||||
.unwrap();
|
||||
|
||||
// Expected secure behavior: scrub should target the inode that was opened before path swap.
|
||||
assert!(
|
||||
!trusted_parent_moved.join("ipc_service").exists(),
|
||||
"trusted inode artifact should be removed even after path swap"
|
||||
);
|
||||
assert!(
|
||||
trusted_parent.join("ipc_service").exists(),
|
||||
"path-swapped attacker directory should not be scrubbed"
|
||||
);
|
||||
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ensure_secure_ipc_parent_dir_keeps_service_artifacts_before_liveness_probe() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-secure-dir-order-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
let parent_dir = base.join("service_parent");
|
||||
std::fs::create_dir_all(&parent_dir).unwrap();
|
||||
// Trigger "had_untrusted_service_parent_mode".
|
||||
std::fs::set_permissions(&parent_dir, std::fs::Permissions::from_mode(0o777)).unwrap();
|
||||
|
||||
let ipc_file = parent_dir.join("ipc_service");
|
||||
let ipc_pid_file = parent_dir.join("ipc_service.pid");
|
||||
std::fs::write(&ipc_file, b"socket-placeholder").unwrap();
|
||||
std::fs::write(&ipc_pid_file, b"1234").unwrap();
|
||||
|
||||
let res =
|
||||
super::ensure_secure_ipc_parent_dir(ipc_file.to_string_lossy().as_ref(), "_service");
|
||||
assert_eq!(res.unwrap(), true);
|
||||
|
||||
// Parent hardening should run first; artifacts should stay until liveness probe completes.
|
||||
assert!(ipc_file.exists(), "ipc socket marker should be preserved");
|
||||
assert!(ipc_pid_file.exists(), "pid marker should be preserved");
|
||||
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ensure_secure_ipc_parent_dir_marks_non_service_mode_repair_for_scrub() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let unique = format!(
|
||||
"rustdesk-ipc-nonservice-mode-repair-test-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
);
|
||||
let base = std::env::temp_dir().join(unique);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
|
||||
let parent_dir = base.join("non_service_parent");
|
||||
std::fs::create_dir_all(&parent_dir).unwrap();
|
||||
std::fs::set_permissions(&parent_dir, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
|
||||
let ipc_file = parent_dir.join("ipc");
|
||||
std::fs::write(&ipc_file, b"socket-placeholder").unwrap();
|
||||
|
||||
let res = super::ensure_secure_ipc_parent_dir(ipc_file.to_string_lossy().as_ref(), "");
|
||||
assert_eq!(res.unwrap(), true);
|
||||
|
||||
std::fs::remove_dir_all(&base).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_scrub_parent_entries_after_check_pid_only_when_requested_and_not_alive() {
|
||||
assert!(!super::should_scrub_parent_entries_after_check_pid(
|
||||
false, false
|
||||
));
|
||||
assert!(!super::should_scrub_parent_entries_after_check_pid(
|
||||
false, true
|
||||
));
|
||||
assert!(super::should_scrub_parent_entries_after_check_pid(
|
||||
true, false
|
||||
));
|
||||
assert!(!super::should_scrub_parent_entries_after_check_pid(
|
||||
true, true
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "اسم العرض"),
|
||||
("password-hidden-tip", "كلمة المرور مخفية"),
|
||||
("preset-password-in-use-tip", "كلمة المرور المحددة مسبقًا قيد الاستخدام"),
|
||||
("Enable privacy mode", "تفعيل وضع الخصوصية"),
|
||||
("allow-remote-toolbar-docking-any-edge", "السماح بإرساء شريط الأدوات البعيد إلى أي حافة من حواف النافذة"),
|
||||
("API Token", "رمز واجهة برمجة التطبيقات API"),
|
||||
("Deploy", "نشر"),
|
||||
("Custom ID (optional)", "معرّف مخصص (اختياري)"),
|
||||
("server_requires_deployment_tip", "يتطلب الخادم نشر هذا الجهاز بشكل صريح. هل تريد النشر الآن؟"),
|
||||
("The server does not require explicit deployment.", "لا يتطلب الخادم نشرًا صريحًا."),
|
||||
("Unknown response.", "استجابة غير معروفة."),
|
||||
("wayland-keyboard-input-disabled-tip", "هل تريد السماح بإدخال لوحة المفاتيح؟"),
|
||||
("wayland-keyboard-input-consent-tip", "ما تكتبه على هذا الكمبيوتر البعيد (بما في ذلك كلمات المرور) قد تتمكن التطبيقات الأخرى الموجودة عليه من قراءته."),
|
||||
("wayland-keyboard-input-applies-to-tip", "ينطبق هذا الاختيار على:"),
|
||||
("wayland-soft-keyboard-input-label", "إدخال لوحة المفاتيح الافتراضية"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "إعادة تعيين اختيار إدخال لوحة المفاتيح"),
|
||||
("remember-wayland-keyboard-choice-tip", "لا تسأل مرة أخرى لهذا الكمبيوتر البعيد"),
|
||||
("Why this happens", "سبب حدوث ذلك"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Запіс"),
|
||||
("Directory", "Каталог"),
|
||||
("Automatically record incoming sessions", "Аўтаматычна запісваць уваходныя сесіі"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Аўтаматычна запісваць выходныя сесіі"),
|
||||
("Change", "Змяніць"),
|
||||
("Start session recording", "Пачаць запіс сесіі"),
|
||||
("Stop session recording", "Спыніць запіс сесіі"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Дэманстрацыя экрана"),
|
||||
("ubuntu-21-04-required", "Wayland патрабуе Ubuntu версіі 21.04 або навейшай."),
|
||||
("wayland-requires-higher-linux-version", "Для Wayland патрабуецца вышэйшая версія дыстрыбутыва Linux. Карыстайцеся працоўным сталом X11 або зменіце сваю АС."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Не ўдалося захапіць экран Wayland. Магчыма, XDG Desktop Portal завяршыўся аварыйна або недаступны. Паспрабуйце перазапусціць яго камандай `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Прагляд"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Выберыце экран для дэманстрацыі (кіруецца на баку абанента)."),
|
||||
("Show RustDesk", "Паказаць RustDesk"),
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "Імя для адлюстравання"),
|
||||
("password-hidden-tip", "Зададзены пастаянны пароль (скрыты)."),
|
||||
("preset-password-in-use-tip", "Пададзены пароль цяпер выкарыстоўваецца"),
|
||||
("Enable privacy mode", "Уключыць рэжым канфідэнцыйнасці"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Дазволіць замацоўванне аддаленай панэлі інструментаў да любога краю акна"),
|
||||
("API Token", "Токен API"),
|
||||
("Deploy", "Разгарнуць"),
|
||||
("Custom ID (optional)", "Карыстальніцкі ID (неабавязкова)"),
|
||||
("server_requires_deployment_tip", "Сервер патрабуе яўнага разгортвання гэтай прылады. Разгарнуць зараз?"),
|
||||
("The server does not require explicit deployment.", "Сервер не патрабуе яўнага разгортвання."),
|
||||
("Unknown response.", "Невядомы адказ."),
|
||||
("wayland-keyboard-input-disabled-tip", "Дазволіць увод з клавіятуры?"),
|
||||
("wayland-keyboard-input-consent-tip", "Тое, што вы набіраеце на гэтым аддаленым кампутары (у тым ліку паролі), могуць прачытаць іншыя праграмы на ім."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Гэты выбар прымяняецца да:"),
|
||||
("wayland-soft-keyboard-input-label", "Увод з экраннай клавіятуры"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Скінуць выбар уводу з клавіятуры"),
|
||||
("remember-wayland-keyboard-choice-tip", "Не пытацца зноў для гэтага аддаленага кампутара"),
|
||||
("Why this happens", "Чаму гэта адбываецца"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
269
src/lang/bg.rs
269
src/lang/bg.rs
@@ -303,7 +303,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Ignore Battery Optimizations", "Игнорирай оптимизациите на батерията"),
|
||||
("android_open_battery_optimizations_tip", "Ако искате да деактивирате тази функция, моля, отидете на следващата страница с настройки на приложението RustDesk, намерете и въведете [Battery], премахнете отметката от [Unrestricted]"),
|
||||
("Start on boot", "Стартирайте при зареждане"),
|
||||
("Start the screen sharing service on boot, requires special permissions", ""),
|
||||
("Start the screen sharing service on boot, requires special permissions", "Стартиране на услугата за споделяне на екрана при зареждане, изисква специални разрешения"),
|
||||
("Connection not allowed", "Връзката непозволена"),
|
||||
("Legacy mode", "По остарял начин"),
|
||||
("Map mode", "По начин със съответствие (map)"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Споделяне на екрана"),
|
||||
("ubuntu-21-04-required", "Wayland изисква Ubuntu 21.04 или по-нов"),
|
||||
("wayland-requires-higher-linux-version", "Wayland изисква по-нов Linux. Моля, опитайте с X11 или сменете операционната система."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Заснемането на екрана под Wayland е неуспешно. XDG Desktop Portal може да е блокирал или да е недостъпен. Опитайте да го рестартирате с `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Препратка"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Моля, изберете екрана, който да бъде споделен (спрямо отдалечената страна)."),
|
||||
("Show RustDesk", "Покажи RustDesk"),
|
||||
@@ -557,7 +557,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Списък"),
|
||||
("Virtual display", "Виртуален екран"),
|
||||
("Plug out all", "Разкачане на всички"),
|
||||
("True color (4:4:4)", ""),
|
||||
("True color (4:4:4)", "Истински цвят (4:4:4)"),
|
||||
("Enable blocking user input", "Разрешаване на блокиране на потребителско въвеждане"),
|
||||
("id_input_tip", "Можете да въведете ID, директен IP адрес или домейн с порт (<domain>:<port>).\nАко искате да получите достъп до устройство на друг сървър, моля, добавете адреса на сървъра (<id>@<server_address >?key=<key_value>), например\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nАко искате да получите достъп до устройство на обществен сървър, моля, въведете \"<id>@public\" , ключът не е необходим за публичен сървър"),
|
||||
("privacy_mode_impl_mag_tip", "Режим 1"),
|
||||
@@ -567,7 +567,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("idd_not_support_under_win10_2004_tip", "Индиректен драйвер за дисплей не се поддържа. Изисква се Windows 10, версия 2004 или по-нова."),
|
||||
("input_source_1_tip", "Входен източник 1"),
|
||||
("input_source_2_tip", "Входен източник 2"),
|
||||
("Swap control-command key", ""),
|
||||
("Swap control-command key", "Размяна на клавишите control и command"),
|
||||
("swap-left-right-mouse", "Размяна на копчетата на мишката"),
|
||||
("2FA code", "Код за Двуфакторно удостоверяване"),
|
||||
("More", "Повече"),
|
||||
@@ -579,9 +579,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("2FA code must be 6 digits.", "Кодът за 2FA (двуфакторно удостоверяване) трябва да е 6-цифрен"),
|
||||
("Multiple Windows sessions found", "Установени са няколко Windwos сесии"),
|
||||
("Please select the session you want to connect to", "Моля определете сесия към която искате да се свърженете"),
|
||||
("powered_by_me", ""),
|
||||
("outgoing_only_desk_tip", ""),
|
||||
("preset_password_warning", ""),
|
||||
("powered_by_me", "Работи с RustDesk"),
|
||||
("outgoing_only_desk_tip", "Това е персонализирано издание.\nМожете да се свързвате с други устройства, но други устройства не могат да се свързват с вашето устройство."),
|
||||
("preset_password_warning", "Това персонализирано издание идва с предварително зададена парола. Всеки, който знае тази парола, може да получи пълен контрол върху вашето устройство. Ако не сте очаквали това, незабавно деинсталирайте софтуера."),
|
||||
("Security Alert", "Предупреждение за сигурност"),
|
||||
("My address book", "Моята адресна книга"),
|
||||
("Personal", "Личен"),
|
||||
@@ -591,25 +591,25 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Read-only", "Само четене"),
|
||||
("Read/Write", "Писане/четене"),
|
||||
("Full Control", "Пълен контрол"),
|
||||
("share_warning_tip", ""),
|
||||
("share_warning_tip", "Полетата по-горе са споделени и видими за други хора."),
|
||||
("Everyone", "Всички"),
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("ab_web_console_tip", "Повече в уеб конзолата"),
|
||||
("allow-only-conn-window-open-tip", "Разрешаване на връзка само ако прозорецът на RustDesk е отворен"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Няма физически екрани, не е необходимо да се използва режимът на поверителност."),
|
||||
("Follow remote cursor", "Следвай отдалечения курсор"),
|
||||
("Follow remote window focus", "Следвай фокуса на отдалечените прозорци"),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("default_proxy_tip", "Протоколът и портът по подразбиране са Socks5 и 1080"),
|
||||
("no_audio_input_device_tip", "Не е намерено устройство за аудио вход."),
|
||||
("Incoming", "Входящ"),
|
||||
("Outgoing", "Изходящ"),
|
||||
("Clear Wayland screen selection", "Изчистване избор на Wayland екран"),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("clear_Wayland_screen_selection_tip", "След изчистване на избора на екран можете да изберете отново екрана за споделяне."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Сигурни ли сте, че искате да изчистите избора на екран за Wayland?"),
|
||||
("android_new_voice_call_tip", "Получена е нова заявка за гласово обаждане. Ако приемете, звукът ще премине към гласова комуникация."),
|
||||
("texture_render_tip", "Използвайте рендер на текстури, за да направите картината по-плавна. Можете да опитате да изключите тази опция, ако срещнете проблеми с изобразяването."),
|
||||
("Use texture rendering", "Използвай рендер на текстури"),
|
||||
("Floating window", "Плаващ прозорец"),
|
||||
("floating_window_tip", ""),
|
||||
("floating_window_tip", "Помага за поддържане на фоновата услуга на RustDesk"),
|
||||
("Keep screen on", "Запази екранът включен"),
|
||||
("Never", "Никога"),
|
||||
("During controlled", "Докато е обект на управление"),
|
||||
@@ -621,127 +621,142 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Volume down", "Намаляване звук"),
|
||||
("Power", "Мощност"),
|
||||
("Telegram bot", "Телеграм бот"),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("enable-bot-tip", "Ако активирате тази функция, можете да получавате 2FA кода от вашия бот. Той може да функционира и като известие за връзка."),
|
||||
("enable-bot-desc", "1. Отворете чат с @BotFather.\n2. Изпратете командата \"/newbot\". След като завършите тази стъпка, ще получите токен.\n3. Започнете чат с новосъздадения си бот. Изпратете съобщение, започващо с наклонена черта (\"/\"), например \"/hello\", за да го активирате.\n"),
|
||||
("cancel-2fa-confirm-tip", "Сигурни ли сте, че искате да отмените 2FA?"),
|
||||
("cancel-bot-confirm-tip", "Сигурни ли сте, че искате да отмените бота на Telegram?"),
|
||||
("About RustDesk", "За RustDesk"),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Send clipboard keystrokes", "Изпращане на клавишни натискания от клипборда"),
|
||||
("network_error_tip", "Моля, проверете мрежовата си връзка, след което натиснете повторен опит."),
|
||||
("Unlock with PIN", "Отключване с PIN"),
|
||||
("Requires at least {} characters", ""),
|
||||
("Requires at least {} characters", "Изисква поне {} знака"),
|
||||
("Wrong PIN", "Грешен PIN"),
|
||||
("Set PIN", "Избор PIN"),
|
||||
("Enable trusted devices", "Позволяване доверени устройства"),
|
||||
("Manage trusted devices", "Управление доверени устройства"),
|
||||
("Platform", "Платформа"),
|
||||
("Days remaining", "Оставащи дни"),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("enable-trusted-devices-tip", "Пропускане на 2FA проверката на доверени устройства"),
|
||||
("Parent directory", "Родителска папка"),
|
||||
("Resume", "Възобновяване"),
|
||||
("Invalid file name", "Невалидно име за файл"),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("one-way-file-transfer-tip", "Еднопосочното прехвърляне на файлове е активирано от управляваната страна."),
|
||||
("Authentication Required", "Изисква се удостоверяване"),
|
||||
("Authenticate", "Удостоверяване"),
|
||||
("web_id_input_tip", "Можете да въведете ID на същия сървър, директният достъп по IP не се поддържа в уеб клиента.\nАко искате да получите достъп до устройство на друг сървър, моля, добавете адреса на сървъра (<id>@<server_address>?key=<key_value>), например,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nАко искате да получите достъп до устройство на публичен сървър, моля, въведете \"<id>@public\", за публичен сървър не е необходим ключ."),
|
||||
("Download", "Изтегляне"),
|
||||
("Upload folder", "Качване на папка"),
|
||||
("Upload files", "Качване на файлове"),
|
||||
("Clipboard is synchronized", "Клипбордът е синхронизиран"),
|
||||
("Update client clipboard", "Обновяване на клипборда на клиента"),
|
||||
("Untagged", "Без етикет"),
|
||||
("new-version-of-{}-tip", "Налична е нова версия на {}"),
|
||||
("Accessible devices", "Достъпни устройства"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Моля, надстройте клиента RustDesk до версия {} или по-нова от отдалечената страна!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Когато е активиран D3D рендерът, екранът за отдалечено управление може да е черен на някои машини."),
|
||||
("Use D3D rendering", "Използвай D3D рендер"),
|
||||
("Printer", "Принтер"),
|
||||
("printer-os-requirement-tip", "Функцията за изходящ печат изисква Windows 10 или по-нова версия."),
|
||||
("printer-requires-installed-{}-client-tip", "За да използвате отдалечен печат, на това устройство трябва да е инсталиран {}."),
|
||||
("printer-{}-not-installed-tip", "Принтерът {} не е инсталиран."),
|
||||
("printer-{}-ready-tip", "Принтерът {} е инсталиран и готов за употреба."),
|
||||
("Install {} Printer", "Инсталиране на принтер {}"),
|
||||
("Outgoing Print Jobs", "Изходящи задачи за печат"),
|
||||
("Incoming Print Jobs", "Входящи задачи за печат"),
|
||||
("Incoming Print Job", "Входяща задача за печат"),
|
||||
("use-the-default-printer-tip", "Използване на принтера по подразбиране"),
|
||||
("use-the-selected-printer-tip", "Използване на избрания принтер"),
|
||||
("auto-print-tip", "Автоматичен печат с избрания принтер."),
|
||||
("print-incoming-job-confirm-tip", "Получихте задача за печат от отдалечено устройство. Искате ли да я изпълните от вашата страна?"),
|
||||
("remote-printing-disallowed-tile-tip", "Отдалеченият печат не е разрешен"),
|
||||
("remote-printing-disallowed-text-tip", "Настройките за разрешения на управляваната страна забраняват отдалечен печат."),
|
||||
("save-settings-tip", "Запазване на настройките"),
|
||||
("dont-show-again-tip", "Не показвай това отново"),
|
||||
("Take screenshot", "Снимка на екрана"),
|
||||
("Taking screenshot", "Правене на снимка на екрана"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Обединяването на снимки от няколко екрана в момента не се поддържа. Моля, превключете към един екран и опитайте отново."),
|
||||
("screenshot-action-tip", "Моля, изберете как да продължите със снимката на екрана."),
|
||||
("Save as", "Запазване като"),
|
||||
("Copy to clipboard", "Копиране в клипборда"),
|
||||
("Enable remote printer", "Позволяване на отдалечен принтер"),
|
||||
("Downloading {}", "Изтегляне на {}"),
|
||||
("{} Update", "Обновяване на {}"),
|
||||
("{}-to-update-tip", "{} ще се затвори сега и ще инсталира новата версия."),
|
||||
("download-new-version-failed-tip", "Изтеглянето е неуспешно. Можете да опитате отново или да натиснете бутона \"Изтегляне\", за да изтеглите от страницата за издания и да обновите ръчно."),
|
||||
("Auto update", "Автоматично обновяване"),
|
||||
("update-failed-check-msi-tip", "Проверката на метода на инсталиране е неуспешна. Моля, натиснете бутона \"Изтегляне\", за да изтеглите от страницата за издания и да обновите ръчно."),
|
||||
("websocket_tip", "При използване на WebSocket се поддържат само препредаващи връзки."),
|
||||
("Use WebSocket", "Използване на WebSocket"),
|
||||
("Trackpad speed", "Скорост на тъчпада"),
|
||||
("Default trackpad speed", "Скорост на тъчпада по подразбиране"),
|
||||
("Numeric one-time password", "Цифрова еднократна парола"),
|
||||
("Enable IPv6 P2P connection", "Позволяване на IPv6 P2P връзка"),
|
||||
("Enable UDP hole punching", "Позволяване на UDP hole punching"),
|
||||
("View camera", "Преглед на камерата"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Позволяване на камерата"),
|
||||
("No cameras", "Няма камери"),
|
||||
("view_camera_unsupported_tip", "Отдалеченото устройство не поддържа преглед на камерата."),
|
||||
("Terminal", "Терминал"),
|
||||
("Enable terminal", "Позволяване на терминал"),
|
||||
("New tab", "Нов раздел"),
|
||||
("Keep terminal sessions on disconnect", "Запазване на терминалните сесии при прекъсване на връзката"),
|
||||
("Terminal (Run as administrator)", "Терминал (изпълнение като администратор)"),
|
||||
("terminal-admin-login-tip", "Моля, въведете потребителското име и паролата на администратора на управляваната страна."),
|
||||
("Failed to get user token.", "Неуспешно получаване на потребителски токен."),
|
||||
("Incorrect username or password.", "Неправилно потребителско име или парола."),
|
||||
("The user is not an administrator.", "Потребителят не е администратор."),
|
||||
("Failed to check if the user is an administrator.", "Неуспешна проверка дали потребителят е администратор."),
|
||||
("Supported only in the installed version.", "Поддържа се само в инсталираната версия."),
|
||||
("elevation_username_tip", "Въведете username или domain\\username"),
|
||||
("Preparing for installation ...", "Подготовка за инсталиране ..."),
|
||||
("Show my cursor", "Показвай моя курсор"),
|
||||
("Scale custom", "Персонализиран мащаб"),
|
||||
("Custom scale slider", "Плъзгач за персонализиран мащаб"),
|
||||
("Decrease", "Намаляване"),
|
||||
("Increase", "Увеличаване"),
|
||||
("Show virtual mouse", "Показвай виртуална мишка"),
|
||||
("Virtual mouse size", "Размер на виртуалната мишка"),
|
||||
("Small", "Малък"),
|
||||
("Large", "Голям"),
|
||||
("Show virtual joystick", "Показвай виртуален джойстик"),
|
||||
("Edit note", "Редактиране на бележка"),
|
||||
("Alias", "Псевдоним"),
|
||||
("ScrollEdge", "Превъртане при ръба"),
|
||||
("Allow insecure TLS fallback", "Позволяване на несигурно връщане към TLS"),
|
||||
("allow-insecure-tls-fallback-tip", "По подразбиране RustDesk проверява сертификата на сървъра за протоколи, използващи TLS.\nКогато тази опция е активирана, RustDesk ще пропусне стъпката на проверка и ще продължи в случай на неуспешна проверка."),
|
||||
("Disable UDP", "Забрана на UDP"),
|
||||
("disable-udp-tip", "Управлява дали да се използва само TCP.\nКогато тази опция е активирана, RustDesk вече няма да използва UDP 21116, а вместо това ще се използва TCP 21116."),
|
||||
("server-oss-not-support-tip", "ЗАБЕЛЕЖКА: RustDesk server OSS не включва тази функция."),
|
||||
("input note here", "въведете бележка тук"),
|
||||
("note-at-conn-end-tip", "Питане за бележка в края на връзката"),
|
||||
("Show terminal extra keys", "Показвай допълнителните клавиши на терминала"),
|
||||
("Relative mouse mode", "Относителен режим на мишката"),
|
||||
("rel-mouse-not-supported-peer-tip", "Относителният режим на мишката не се поддържа от свързания партньор."),
|
||||
("rel-mouse-not-ready-tip", "Относителният режим на мишката все още не е готов. Моля, опитайте отново."),
|
||||
("rel-mouse-lock-failed-tip", "Неуспешно заключване на курсора. Относителният режим на мишката е изключен."),
|
||||
("rel-mouse-exit-{}-tip", "Натиснете {} за изход."),
|
||||
("rel-mouse-permission-lost-tip", "Разрешението за клавиатура беше отнето. Относителният режим на мишката е изключен."),
|
||||
("Changelog", "Списък с промени"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Поддържай екрана активен по време на изходящи сесии"),
|
||||
("keep-awake-during-incoming-sessions-label", "Поддържай екрана активен по време на входящи сесии"),
|
||||
("Continue with {}", "Продължи с {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Показвано име"),
|
||||
("password-hidden-tip", "Зададена е постоянна парола (скрита)."),
|
||||
("preset-password-in-use-tip", "В момента се използва предварително зададена парола."),
|
||||
("Enable privacy mode", "Позволяване на режим на поверителност"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Позволяване на закачане на отдалечената лента с инструменти към всеки ръб на прозореца"),
|
||||
("API Token", "API токен"),
|
||||
("Deploy", "Внедряване"),
|
||||
("Custom ID (optional)", "Персонализиран ID (по избор)"),
|
||||
("server_requires_deployment_tip", "Сървърът изисква това устройство да бъде внедрено изрично. Да се внедри ли сега?"),
|
||||
("The server does not require explicit deployment.", "Сървърът не изисква изрично внедряване."),
|
||||
("Unknown response.", "Неизвестен отговор."),
|
||||
("wayland-keyboard-input-disabled-tip", "Да се позволи ли въвеждане от клавиатура?"),
|
||||
("wayland-keyboard-input-consent-tip", "Това, което въвеждате на този отдалечен компютър (включително пароли), може да бъде прочетено от други приложения на него."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Този избор се отнася за:"),
|
||||
("wayland-soft-keyboard-input-label", "Въвеждане от софтуерна клавиатура"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Нулиране на избора за въвеждане от клавиатура"),
|
||||
("remember-wayland-keyboard-choice-tip", "Не питай отново за този отдалечен компютър"),
|
||||
("Why this happens", "Защо се случва това"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
111
src/lang/ca.rs
111
src/lang/ca.rs
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Gravació"),
|
||||
("Directory", "Contactes"),
|
||||
("Automatically record incoming sessions", "Enregistrament automàtic de sessions entrants"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Enregistrament automàtic de sessions sortints"),
|
||||
("Change", "Canvia"),
|
||||
("Start session recording", "Inicia la gravació de la sessió"),
|
||||
("Stop session recording", "Atura la gravació de la sessió"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Compartició de pantalla"),
|
||||
("ubuntu-21-04-required", "Wayland requereix Ubuntu 21.04 o superior"),
|
||||
("wayland-requires-higher-linux-version", "Wayland requereix una versió superior de sistema Linux per a funcionar. Proveu iniciant un entorn d'escriptori amb x11 o actualitzeu el vostre sistema operatiu."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Ha fallat la captura de pantalla del Wayland. És possible que el XDG Desktop Portal hagi fallat o no estigui disponible. Proveu de reiniciar-lo amb `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Marcador"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seleccioneu la pantalla que compartireu (quina serà visible al client)"),
|
||||
("Show RustDesk", "Mostra el RustDesk"),
|
||||
@@ -650,43 +650,43 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Clipboard is synchronized", "El porta-retalls està sincronitzat"),
|
||||
("Update client clipboard", "Actualitza el porta-retalls del client"),
|
||||
("Untagged", "Sense etiquetar"),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("new-version-of-{}-tip", "Hi ha disponible una versió nova de {}"),
|
||||
("Accessible devices", "Dispositius accessibles"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
|
||||
("d3d_render_tip", ""),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Actualitzeu el client RustDesk a la versió {} o superior a la part remota!"),
|
||||
("d3d_render_tip", "Quan la renderització D3D està habilitada, en alguns equips la pantalla del control remot pot quedar en negre."),
|
||||
("Use D3D rendering", "Utilitza renderització D3D"),
|
||||
("Printer", "Impressora"),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("printer-os-requirement-tip", "La funció d'impressió sortint requereix Windows 10 o superior."),
|
||||
("printer-requires-installed-{}-client-tip", "Per a utilitzar la impressió remota, cal instal·lar {} en aquest dispositiu."),
|
||||
("printer-{}-not-installed-tip", "La impressora {} no està instal·lada."),
|
||||
("printer-{}-ready-tip", "La impressora {} està instal·lada i a punt per a utilitzar-se."),
|
||||
("Install {} Printer", "Instal·la {} impressora"),
|
||||
("Outgoing Print Jobs", "Treballs d'impressió sortints"),
|
||||
("Incoming Print Jobs", "Treballs d'impressió entrants"),
|
||||
("Incoming Print Job", "Treballs d'impressió entrant"),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("use-the-default-printer-tip", "Utilitza la impressora per defecte"),
|
||||
("use-the-selected-printer-tip", "Utilitza la impressora seleccionada"),
|
||||
("auto-print-tip", "Imprimeix automàticament utilitzant la impressora seleccionada."),
|
||||
("print-incoming-job-confirm-tip", "Heu rebut un treball d'impressió des de la part remota. Voleu executar-lo al vostre costat?"),
|
||||
("remote-printing-disallowed-tile-tip", "Impressió remota no permesa"),
|
||||
("remote-printing-disallowed-text-tip", "La configuració de permisos de la part controlada denega la impressió remota."),
|
||||
("save-settings-tip", "Desa la configuració"),
|
||||
("dont-show-again-tip", "No tornis a mostrar això"),
|
||||
("Take screenshot", "Fes una captura de pantalla"),
|
||||
("Taking screenshot", "Fent la captura de pantalla"),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", "Actualment no és possible combinar captures de pantalla de diverses pantalles. Canvieu a una sola pantalla i torneu a provar."),
|
||||
("screenshot-action-tip", "Seleccioneu com voleu continuar amb la captura de pantalla."),
|
||||
("Save as", "Anomena i desa"),
|
||||
("Copy to clipboard", "Copia al porta-retalls"),
|
||||
("Enable remote printer", "Habilita l'impressora remota"),
|
||||
("Downloading {}", "Descarregant {}"),
|
||||
("{} Update", "{} Actualitza"),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("{}-to-update-tip", "{} es tancarà ara i instal·larà la versió nova."),
|
||||
("download-new-version-failed-tip", "Ha fallat la descàrrega. Podeu tornar a provar o fer clic al botó \"Descarrega\" per descarregar-la des de la pàgina de publicacions i actualitzar-la manualment."),
|
||||
("Auto update", "Actualització automàtica"),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("update-failed-check-msi-tip", "Ha fallat la comprovació del mètode d'instal·lació. Feu clic al botó \"Descarrega\" per descarregar-la des de la pàgina de publicacions i actualitzar-la manualment."),
|
||||
("websocket_tip", "En utilitzar WebSocket, només s'admeten connexions per repetidor."),
|
||||
("Use WebSocket", "Utilitza WebSocket"),
|
||||
("Trackpad speed", "Velocitat del trackpad"),
|
||||
("Default trackpad speed", "Velocitat per defecte del trackpad"),
|
||||
("Numeric one-time password", "Contrasenya numèrica d'un sol ús"),
|
||||
@@ -695,19 +695,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("View camera", "Mostra la càmera"),
|
||||
("Enable camera", "Habilita la càmera"),
|
||||
("No cameras", "No hi ha càmeres"),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("view_camera_unsupported_tip", "El dispositiu remot no admet la visualització de la càmera."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Habilita el terminal"),
|
||||
("New tab", "Nova finestra"),
|
||||
("Keep terminal sessions on disconnect", "Mantingues les sessions de terminal desconnectades"),
|
||||
("Terminal (Run as administrator)", "Terminal (executa com a administrador"),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("terminal-admin-login-tip", "Inseriu el nom d'usuari i la contrasenya de l'administrador de la part controlada."),
|
||||
("Failed to get user token.", "No s'ha pogut obtenir el token d'usuari."),
|
||||
("Incorrect username or password.", "Nom d'usuari o contrasenya incorrecte"),
|
||||
("The user is not an administrator.", "Aquest usuari no és administrador"),
|
||||
("Failed to check if the user is an administrator.", "No s'ha pogut comprovar si l'usuari és administrador."),
|
||||
("Supported only in the installed version.", "Només compatible amb la versió instal·lada."),
|
||||
("elevation_username_tip", ""),
|
||||
("elevation_username_tip", "Inseriu el nom d'usuari o domini\\nomusuari"),
|
||||
("Preparing for installation ...", "Preparant per a l'instal·lació..."),
|
||||
("Show my cursor", "Mostra el meu punter"),
|
||||
("Scale custom", "Escala personalitzada"),
|
||||
@@ -721,27 +721,42 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Show virtual joystick", "Mostra el joystick virtual"),
|
||||
("Edit note", "Edita la nota"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("ScrollEdge", "Desplaçament a la vora"),
|
||||
("Allow insecure TLS fallback", "Permet l'ús alternatiu de TLS no segur"),
|
||||
("allow-insecure-tls-fallback-tip", "Per defecte, el RustDesk verifica el certificat del servidor per als protocols que utilitzen TLS.\nAmb aquesta opció habilitada, el RustDesk ometrà el pas de verificació i continuarà en cas que aquesta falli."),
|
||||
("Disable UDP", "Inhabilita l'UDP"),
|
||||
("disable-udp-tip", "Controla si s'utilitza només TCP.\nAmb aquesta opció habilitada, el RustDesk ja no utilitzarà l'UDP 21116, sinó que utilitzarà el TCP 21116 en el seu lloc."),
|
||||
("server-oss-not-support-tip", "NOTA: El RustDesk Server OSS no inclou aquesta característica."),
|
||||
("input note here", "inseriu la nota aquí"),
|
||||
("note-at-conn-end-tip", "Demana una nota en finalitzar la connexió"),
|
||||
("Show terminal extra keys", "Mostra les tecles addicionals del terminal"),
|
||||
("Relative mouse mode", "Mode de ratolí relatiu"),
|
||||
("rel-mouse-not-supported-peer-tip", "El client connectat no admet el mode de ratolí relatiu."),
|
||||
("rel-mouse-not-ready-tip", "El mode de ratolí relatiu encara no està a punt. Torneu a provar."),
|
||||
("rel-mouse-lock-failed-tip", "Ha fallat el bloqueig del cursor. S'ha inhabilitat el mode de ratolí relatiu."),
|
||||
("rel-mouse-exit-{}-tip", "Premeu {} per a sortir."),
|
||||
("rel-mouse-permission-lost-tip", "S'ha revocat el permís del teclat. S'ha inhabilitat el mode de ratolí relatiu."),
|
||||
("Changelog", "Registre de canvis"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Mantén la pantalla activa durant les sessions sortints"),
|
||||
("keep-awake-during-incoming-sessions-label", "Mantén la pantalla activa durant les sessions entrants"),
|
||||
("Continue with {}", "Continua amb {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Nom visible"),
|
||||
("password-hidden-tip", "La contrasenya permanent està definida (oculta)."),
|
||||
("preset-password-in-use-tip", "Actualment s'està utilitzant una contrasenya preestablerta."),
|
||||
("Enable privacy mode", "Habilita el Mode privat"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Permet ancorar la barra d'eines remota a qualsevol vora de la finestra"),
|
||||
("API Token", "Testimoni de l'API"),
|
||||
("Deploy", "Desplega"),
|
||||
("Custom ID (optional)", "ID personalitzada (opcional)"),
|
||||
("server_requires_deployment_tip", "El servidor requereix que aquest dispositiu es desplegui explícitament. Voleu desplegar-lo ara?"),
|
||||
("The server does not require explicit deployment.", "El servidor no requereix un desplegament explícit."),
|
||||
("Unknown response.", "Resposta desconeguda."),
|
||||
("wayland-keyboard-input-disabled-tip", "Voleu permetre l'entrada de teclat?"),
|
||||
("wayland-keyboard-input-consent-tip", "Allò que escriviu en aquest equip remot (incloses les contrasenyes) podria ser llegit per altres aplicacions que hi hagi."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Aquesta opció s'aplica a:"),
|
||||
("wayland-soft-keyboard-input-label", "Entrada de teclat virtual"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Restableix l'opció d'entrada de teclat"),
|
||||
("remember-wayland-keyboard-choice-tip", "No tornis a preguntar-ho per a aquest equip remot"),
|
||||
("Why this happens", "Per què passa això"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "仅共享屏幕"),
|
||||
("ubuntu-21-04-required", "Wayland 需要 Ubuntu 21.04 或更高版本。"),
|
||||
("wayland-requires-higher-linux-version", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland 屏幕捕获失败。XDG Desktop Portal 可能已崩溃或不可用。请尝试使用 `systemctl --user restart xdg-desktop-portal` 重启它。"),
|
||||
("JumpLink", "查看"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "请选择要分享的画面(对端操作)。"),
|
||||
("Show RustDesk", "显示 RustDesk"),
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "显示名称"),
|
||||
("password-hidden-tip", "永久密码已设置(已隐藏)"),
|
||||
("preset-password-in-use-tip", "当前使用预设密码"),
|
||||
("Enable privacy mode", "允许隐私模式"),
|
||||
("allow-remote-toolbar-docking-any-edge", "允许将远程工具栏停靠到任意窗口边缘"),
|
||||
("API Token", "API 令牌"),
|
||||
("Deploy", "部署"),
|
||||
("Custom ID (optional)", "自定义 ID(可选)"),
|
||||
("server_requires_deployment_tip", "服务器要求显式部署此设备。是否立即部署?"),
|
||||
("The server does not require explicit deployment.", "服务器不需要显式部署。"),
|
||||
("Unknown response.", "未知响应。"),
|
||||
("wayland-keyboard-input-disabled-tip", "允许键盘输入?"),
|
||||
("wayland-keyboard-input-consent-tip", "你在这台远程电脑上输入的内容(包括密码)可能被远程电脑上的其他程序读取。"),
|
||||
("wayland-keyboard-input-applies-to-tip", "此选择适用于:"),
|
||||
("wayland-soft-keyboard-input-label", "软键盘输入"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "重置键盘输入选择"),
|
||||
("remember-wayland-keyboard-choice-tip", "以后对这台远程电脑不再询问"),
|
||||
("Why this happens", "了解原因"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
219
src/lang/cs.rs
219
src/lang/cs.rs
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Nahrávání"),
|
||||
("Directory", "Adresář"),
|
||||
("Automatically record incoming sessions", "Automaticky nahrávat příchozí relace"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Automaticky nahrávat odchozí relace"),
|
||||
("Change", "Změnit"),
|
||||
("Start session recording", "Spustit záznam relace"),
|
||||
("Stop session recording", "Zastavit záznam relace"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Sdílení obrazovky"),
|
||||
("ubuntu-21-04-required", "Wayland vyžaduje Ubuntu 21.04, nebo vyšší verzi."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vyžaduje vyšší verzi linuxové distribuce. Zkuste prosím X11 desktop, nebo změňte OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Záznam obrazovky ve Waylandu selhal. XDG Desktop Portal mohl spadnout nebo je nedostupný. Zkuste jej restartovat příkazem `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Vyberte prosím obrazovku, kterou chcete sdílet (Ovládejte na straně protistrany)."),
|
||||
("Show RustDesk", "Zobrazit RustDesk"),
|
||||
@@ -640,108 +640,123 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Parent directory", "Rodičovský adresář"),
|
||||
("Resume", "Pokračovat"),
|
||||
("Invalid file name", "Nesprávný název souboru"),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("one-way-file-transfer-tip", "Na ovládané straně je povolen jednosměrný přenos souborů."),
|
||||
("Authentication Required", "Vyžadováno ověření"),
|
||||
("Authenticate", "Ověřit"),
|
||||
("web_id_input_tip", "Můžete zadat ID na stejném serveru, přímý přístup přes IP není ve webovém klientovi podporován.\nPokud chcete přistupovat k zařízení na jiném serveru, připojte adresu serveru (<id>@<server_address>?key=<key_value>), například,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nPokud chcete přistupovat k zařízení na veřejném serveru, zadejte \"<id>@public\", pro veřejný server není klíč potřeba."),
|
||||
("Download", "Stáhnout"),
|
||||
("Upload folder", "Nahrát složku"),
|
||||
("Upload files", "Nahrát soubory"),
|
||||
("Clipboard is synchronized", "Schránka je synchronizována"),
|
||||
("Update client clipboard", "Aktualizovat schránku klienta"),
|
||||
("Untagged", "Bez štítku"),
|
||||
("new-version-of-{}-tip", "Je k dispozici nová verze {}"),
|
||||
("Accessible devices", "Přístupná zařízení"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Upgradujte prosím klienta RustDesk na verzi {} nebo novější na vzdálené straně!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Když je povoleno vykreslování D3D, může být obrazovka vzdáleného ovládání na některých počítačích černá."),
|
||||
("Use D3D rendering", "Použít vykreslování D3D"),
|
||||
("Printer", "Tiskárna"),
|
||||
("printer-os-requirement-tip", "Funkce odchozího tisku vyžaduje Windows 10 nebo novější."),
|
||||
("printer-requires-installed-{}-client-tip", "Aby bylo možné používat vzdálený tisk, musí být na tomto zařízení nainstalován {}."),
|
||||
("printer-{}-not-installed-tip", "Tiskárna {} není nainstalována."),
|
||||
("printer-{}-ready-tip", "Tiskárna {} je nainstalována a připravena k použití."),
|
||||
("Install {} Printer", "Nainstalovat tiskárnu {}"),
|
||||
("Outgoing Print Jobs", "Odchozí tiskové úlohy"),
|
||||
("Incoming Print Jobs", "Příchozí tiskové úlohy"),
|
||||
("Incoming Print Job", "Příchozí tisková úloha"),
|
||||
("use-the-default-printer-tip", "Použít výchozí tiskárnu"),
|
||||
("use-the-selected-printer-tip", "Použít vybranou tiskárnu"),
|
||||
("auto-print-tip", "Tisknout automaticky pomocí vybrané tiskárny."),
|
||||
("print-incoming-job-confirm-tip", "Obdrželi jste tiskovou úlohu ze vzdáleného počítače. Chcete ji provést na své straně?"),
|
||||
("remote-printing-disallowed-tile-tip", "Vzdálený tisk není povolen"),
|
||||
("remote-printing-disallowed-text-tip", "Nastavení oprávnění ovládané strany zakazuje vzdálený tisk."),
|
||||
("save-settings-tip", "Uložit nastavení"),
|
||||
("dont-show-again-tip", "Toto již nezobrazovat"),
|
||||
("Take screenshot", "Pořídit snímek obrazovky"),
|
||||
("Taking screenshot", "Pořizuje se snímek obrazovky"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Sloučení snímků obrazovky z více displejů aktuálně není podporováno. Přepněte na jeden displej a zkuste to znovu."),
|
||||
("screenshot-action-tip", "Vyberte, jak pokračovat se snímkem obrazovky."),
|
||||
("Save as", "Uložit jako"),
|
||||
("Copy to clipboard", "Kopírovat do schránky"),
|
||||
("Enable remote printer", "Povolit vzdálenou tiskárnu"),
|
||||
("Downloading {}", "Stahuje se {}"),
|
||||
("{} Update", "Aktualizace {}"),
|
||||
("{}-to-update-tip", "{} se nyní zavře a nainstaluje novou verzi."),
|
||||
("download-new-version-failed-tip", "Stahování se nezdařilo. Můžete to zkusit znovu nebo kliknout na tlačítko \"Stáhnout\" pro stažení ze stránky vydání a ruční aktualizaci."),
|
||||
("Auto update", "Automatická aktualizace"),
|
||||
("update-failed-check-msi-tip", "Kontrola metody instalace se nezdařila. Klikněte na tlačítko \"Stáhnout\" pro stažení ze stránky vydání a ruční aktualizaci."),
|
||||
("websocket_tip", "Při použití WebSocket jsou podporována pouze přenosová (relay) připojení."),
|
||||
("Use WebSocket", "Použít WebSocket"),
|
||||
("Trackpad speed", "Rychlost trackpadu"),
|
||||
("Default trackpad speed", "Výchozí rychlost trackpadu"),
|
||||
("Numeric one-time password", "Číselné jednorázové heslo"),
|
||||
("Enable IPv6 P2P connection", "Povolit připojení IPv6 P2P"),
|
||||
("Enable UDP hole punching", "Povolit UDP hole punching"),
|
||||
("View camera", "Zobrazit kameru"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Povolit kameru"),
|
||||
("No cameras", "Žádné kamery"),
|
||||
("view_camera_unsupported_tip", "Vzdálené zařízení nepodporuje zobrazení kamery."),
|
||||
("Terminal", "Terminál"),
|
||||
("Enable terminal", "Povolit terminál"),
|
||||
("New tab", "Nová karta"),
|
||||
("Keep terminal sessions on disconnect", "Zachovat relace terminálu při odpojení"),
|
||||
("Terminal (Run as administrator)", "Terminál (Spustit jako správce)"),
|
||||
("terminal-admin-login-tip", "Zadejte uživatelské jméno a heslo správce ovládané strany."),
|
||||
("Failed to get user token.", "Nepodařilo se získat uživatelský token."),
|
||||
("Incorrect username or password.", "Nesprávné uživatelské jméno nebo heslo."),
|
||||
("The user is not an administrator.", "Uživatel není správce."),
|
||||
("Failed to check if the user is an administrator.", "Nepodařilo se ověřit, zda je uživatel správce."),
|
||||
("Supported only in the installed version.", "Podporováno pouze v nainstalované verzi."),
|
||||
("elevation_username_tip", "Zadejte uživatelské jméno nebo doména\\uživatelské jméno"),
|
||||
("Preparing for installation ...", "Příprava instalace ..."),
|
||||
("Show my cursor", "Zobrazit můj kurzor"),
|
||||
("Scale custom", "Vlastní měřítko"),
|
||||
("Custom scale slider", "Posuvník vlastního měřítka"),
|
||||
("Decrease", "Zmenšit"),
|
||||
("Increase", "Zvětšit"),
|
||||
("Show virtual mouse", "Zobrazit virtuální myš"),
|
||||
("Virtual mouse size", "Velikost virtuální myši"),
|
||||
("Small", "Malá"),
|
||||
("Large", "Velká"),
|
||||
("Show virtual joystick", "Zobrazit virtuální joystick"),
|
||||
("Edit note", "Upravit poznámku"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Povolit nezabezpečené záložní řešení TLS"),
|
||||
("allow-insecure-tls-fallback-tip", "Ve výchozím nastavení RustDesk ověřuje certifikát serveru u protokolů používajících TLS.\nKdyž je tato možnost povolena, RustDesk v případě selhání ověření přejde k přeskočení kroku ověření a bude pokračovat."),
|
||||
("Disable UDP", "Zakázat UDP"),
|
||||
("disable-udp-tip", "Určuje, zda se má používat pouze TCP.\nKdyž je tato možnost povolena, RustDesk již nebude používat UDP 21116, místo toho se použije TCP 21116."),
|
||||
("server-oss-not-support-tip", "POZNÁMKA: RustDesk server OSS tuto funkci neobsahuje."),
|
||||
("input note here", "sem zadejte poznámku"),
|
||||
("note-at-conn-end-tip", "Požádat o poznámku na konci připojení"),
|
||||
("Show terminal extra keys", "Zobrazit další klávesy terminálu"),
|
||||
("Relative mouse mode", "Relativní režim myši"),
|
||||
("rel-mouse-not-supported-peer-tip", "Připojený protějšek nepodporuje relativní režim myši."),
|
||||
("rel-mouse-not-ready-tip", "Relativní režim myši ještě není připraven. Zkuste to znovu."),
|
||||
("rel-mouse-lock-failed-tip", "Nepodařilo se uzamknout kurzor. Relativní režim myši byl zakázán."),
|
||||
("rel-mouse-exit-{}-tip", "Stiskněte {} pro ukončení."),
|
||||
("rel-mouse-permission-lost-tip", "Oprávnění ke klávesnici bylo odebráno. Relativní režim myši byl zakázán."),
|
||||
("Changelog", "Seznam změn"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Udržovat obrazovku aktivní během odchozích relací"),
|
||||
("keep-awake-during-incoming-sessions-label", "Udržovat obrazovku aktivní během příchozích relací"),
|
||||
("Continue with {}", "Pokračovat s {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Zobrazované jméno"),
|
||||
("password-hidden-tip", "Trvalé heslo je nastaveno (skryto)."),
|
||||
("preset-password-in-use-tip", "Aktuálně se používá přednastavené heslo."),
|
||||
("Enable privacy mode", "Povolit režim ochrany soukromí"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Povolit ukotvení vzdáleného panelu nástrojů k libovolnému okraji okna"),
|
||||
("API Token", "API token"),
|
||||
("Deploy", "Nasadit"),
|
||||
("Custom ID (optional)", "Vlastní ID (volitelné)"),
|
||||
("server_requires_deployment_tip", "Server vyžaduje, aby bylo toto zařízení výslovně nasazeno. Nasadit nyní?"),
|
||||
("The server does not require explicit deployment.", "Server nevyžaduje výslovné nasazení."),
|
||||
("Unknown response.", "Neznámá odpověď."),
|
||||
("wayland-keyboard-input-disabled-tip", "Povolit vstup z klávesnice?"),
|
||||
("wayland-keyboard-input-consent-tip", "To, co píšete na tomto vzdáleném počítači (včetně hesel), mohou číst jiné aplikace na něm."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Tato volba platí pro:"),
|
||||
("wayland-soft-keyboard-input-label", "Vstup ze softwarové klávesnice"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Resetovat volbu vstupu z klávesnice"),
|
||||
("remember-wayland-keyboard-choice-tip", "Pro tento vzdálený počítač se již neptat"),
|
||||
("Why this happens", "Proč k tomu dochází"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
219
src/lang/da.rs
219
src/lang/da.rs
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Optager"),
|
||||
("Directory", "Mappe"),
|
||||
("Automatically record incoming sessions", "Optag automatisk indgående sessioner"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Optag automatisk udgående sessioner"),
|
||||
("Change", "Ændr"),
|
||||
("Start session recording", "Start sessionsoptagelse"),
|
||||
("Stop session recording", "Stop sessionsoptagelse"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Skærmdeling"),
|
||||
("ubuntu-21-04-required", "Wayland kræver Ubuntu version 21.04 eller nyere."),
|
||||
("wayland-requires-higher-linux-version", "Wayland kræver en højere version af Linux distro. Prøv venligst X11 desktop eller skift dit OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Skærmoptagelse via Wayland mislykkedes. XDG Desktop Portal kan være gået ned eller er utilgængelig. Prøv at genstarte den med `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Vælg venligst den skærm, der skal deles (Betjen på modtagersiden)."),
|
||||
("Show RustDesk", "Vis RustDesk"),
|
||||
@@ -640,108 +640,123 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Parent directory", "mappe"),
|
||||
("Resume", "Fortsæt"),
|
||||
("Invalid file name", "Ugyldigt filnavn"),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("one-way-file-transfer-tip", "Envejs-filoverførsel er aktiveret på den kontrollerede side."),
|
||||
("Authentication Required", "Godkendelse påkrævet"),
|
||||
("Authenticate", "Godkend"),
|
||||
("web_id_input_tip", "Du kan indtaste et ID på den samme server; direkte IP-adgang understøttes ikke i webklienten.\nHvis du ønsker at få adgang til en enhed på en anden server, tilføj da serveradressen (<id>@<server_address>?key=<key_value>), fx,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nHvis du ønsker at få adgang til en enhed på en offentlig server, indtast da \"<id>@public\"; nøglen er ikke nødvendig for offentlige servere."),
|
||||
("Download", "Download"),
|
||||
("Upload folder", "Upload mappe"),
|
||||
("Upload files", "Upload filer"),
|
||||
("Clipboard is synchronized", "Udklipsholderen er synkroniseret"),
|
||||
("Update client clipboard", "Opdatér klientens udklipsholder"),
|
||||
("Untagged", "Uden nøgleord"),
|
||||
("new-version-of-{}-tip", "Der findes en ny version af {}"),
|
||||
("Accessible devices", "Tilgængelige enheder"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Opgrader venligst RustDesk-klienten til version {} eller nyere på fjernsiden!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Når D3D-rendering er aktiveret, kan fjernstyringsskærmen være sort på nogle maskiner."),
|
||||
("Use D3D rendering", "Anvend D3D-rendering"),
|
||||
("Printer", "Printer"),
|
||||
("printer-os-requirement-tip", "Den udgående printerfunktion kræver Windows 10 eller nyere."),
|
||||
("printer-requires-installed-{}-client-tip", "For at kunne bruge fjernudskrivning skal {} være installeret på denne enhed."),
|
||||
("printer-{}-not-installed-tip", "{}-printeren er ikke installeret."),
|
||||
("printer-{}-ready-tip", "{}-printeren er installeret og klar til brug."),
|
||||
("Install {} Printer", "Installér {}-printer"),
|
||||
("Outgoing Print Jobs", "Udgående udskriftsjob"),
|
||||
("Incoming Print Jobs", "Indgående udskriftsjob"),
|
||||
("Incoming Print Job", "Indgående udskriftsjob"),
|
||||
("use-the-default-printer-tip", "Brug standardprinteren"),
|
||||
("use-the-selected-printer-tip", "Brug den valgte printer"),
|
||||
("auto-print-tip", "Udskriv automatisk med den valgte printer."),
|
||||
("print-incoming-job-confirm-tip", "Du har modtaget et udskriftsjob fra fjernenheden. Vil du udføre det på din side?"),
|
||||
("remote-printing-disallowed-tile-tip", "Fjernudskrivning ikke tilladt"),
|
||||
("remote-printing-disallowed-text-tip", "Tilladelsesindstillingerne på den kontrollerede side afviser fjernudskrivning."),
|
||||
("save-settings-tip", "Gem indstillinger"),
|
||||
("dont-show-again-tip", "Vis ikke dette igen"),
|
||||
("Take screenshot", "Tag skærmbillede"),
|
||||
("Taking screenshot", "Tager skærmbillede"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Sammenfletning af skærmbilleder fra flere skærme understøttes ikke i øjeblikket. Skift venligst til en enkelt skærm og prøv igen."),
|
||||
("screenshot-action-tip", "Vælg venligst, hvordan du vil fortsætte med skærmbilledet."),
|
||||
("Save as", "Gem som"),
|
||||
("Copy to clipboard", "Kopiér til udklipsholder"),
|
||||
("Enable remote printer", "Aktivér fjernprinter"),
|
||||
("Downloading {}", "Downloader {}"),
|
||||
("{} Update", "{}-opdatering"),
|
||||
("{}-to-update-tip", "{} lukker nu og installerer den nye version."),
|
||||
("download-new-version-failed-tip", "Download mislykkedes. Du kan prøve igen eller klikke på knappen \"Download\" for at hente fra udgivelsessiden og opgradere manuelt."),
|
||||
("Auto update", "Automatisk opdatering"),
|
||||
("update-failed-check-msi-tip", "Kontrol af installationsmetode mislykkedes. Klik venligst på knappen \"Download\" for at hente fra udgivelsessiden og opgradere manuelt."),
|
||||
("websocket_tip", "Ved brug af WebSocket understøttes kun relay-forbindelser."),
|
||||
("Use WebSocket", "Brug WebSocket"),
|
||||
("Trackpad speed", "Pegefeltshastighed"),
|
||||
("Default trackpad speed", "Standard pegefeltshastighed"),
|
||||
("Numeric one-time password", "Numerisk engangskode"),
|
||||
("Enable IPv6 P2P connection", "Aktivér IPv6 P2P-forbindelse"),
|
||||
("Enable UDP hole punching", "Aktivér UDP hole punching"),
|
||||
("View camera", "Se kamera"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Aktivér kamera"),
|
||||
("No cameras", "Ingen kameraer"),
|
||||
("view_camera_unsupported_tip", "Fjernenheden understøtter ikke visning af kameraet."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Aktivér terminal"),
|
||||
("New tab", "Ny fane"),
|
||||
("Keep terminal sessions on disconnect", "Behold terminalsessioner ved afbrydelse"),
|
||||
("Terminal (Run as administrator)", "Terminal (Kør som administrator)"),
|
||||
("terminal-admin-login-tip", "Indtast venligst administratorbrugernavnet og adgangskoden på den kontrollerede side."),
|
||||
("Failed to get user token.", "Kunne ikke hente brugertoken."),
|
||||
("Incorrect username or password.", "Forkert brugernavn eller adgangskode."),
|
||||
("The user is not an administrator.", "Brugeren er ikke administrator."),
|
||||
("Failed to check if the user is an administrator.", "Kunne ikke kontrollere, om brugeren er administrator."),
|
||||
("Supported only in the installed version.", "Understøttes kun i den installerede version."),
|
||||
("elevation_username_tip", "Indtast brugernavn eller domæne\\brugernavn"),
|
||||
("Preparing for installation ...", "Forbereder installation ..."),
|
||||
("Show my cursor", "Vis min markør"),
|
||||
("Scale custom", "Tilpasset skalering"),
|
||||
("Custom scale slider", "Skyder til tilpasset skalering"),
|
||||
("Decrease", "Formindsk"),
|
||||
("Increase", "Forøg"),
|
||||
("Show virtual mouse", "Vis virtuel mus"),
|
||||
("Virtual mouse size", "Størrelse på virtuel mus"),
|
||||
("Small", "Lille"),
|
||||
("Large", "Stor"),
|
||||
("Show virtual joystick", "Vis virtuel joystick"),
|
||||
("Edit note", "Redigér note"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Tillad usikker TLS-fallback"),
|
||||
("allow-insecure-tls-fallback-tip", "Som standard verificerer RustDesk servercertifikatet for protokoller, der bruger TLS.\nNår denne indstilling er aktiveret, vil RustDesk springe verificeringstrinnet over og fortsætte, hvis verificeringen mislykkes."),
|
||||
("Disable UDP", "Deaktivér UDP"),
|
||||
("disable-udp-tip", "Bestemmer, om der kun skal bruges TCP.\nNår denne indstilling er aktiveret, vil RustDesk ikke længere bruge UDP 21116; i stedet bruges TCP 21116."),
|
||||
("server-oss-not-support-tip", "BEMÆRK: RustDesk server OSS indeholder ikke denne funktion."),
|
||||
("input note here", "indtast note her"),
|
||||
("note-at-conn-end-tip", "Spørg om note ved afslutningen af forbindelsen"),
|
||||
("Show terminal extra keys", "Vis ekstra terminaltaster"),
|
||||
("Relative mouse mode", "Relativ musetilstand"),
|
||||
("rel-mouse-not-supported-peer-tip", "Relativ musetilstand understøttes ikke af den tilsluttede modpart."),
|
||||
("rel-mouse-not-ready-tip", "Relativ musetilstand er ikke klar endnu. Prøv venligst igen."),
|
||||
("rel-mouse-lock-failed-tip", "Kunne ikke låse markøren. Relativ musetilstand er blevet deaktiveret."),
|
||||
("rel-mouse-exit-{}-tip", "Tryk på {} for at afslutte."),
|
||||
("rel-mouse-permission-lost-tip", "Tastaturtilladelsen blev tilbagekaldt. Relativ musetilstand er blevet deaktiveret."),
|
||||
("Changelog", "Ændringslog"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Hold skærmen tændt under udgående sessioner"),
|
||||
("keep-awake-during-incoming-sessions-label", "Hold skærmen tændt under indgående sessioner"),
|
||||
("Continue with {}", "Fortsæt med {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Visningsnavn"),
|
||||
("password-hidden-tip", "Permanent adgangskode er indstillet (skjult)."),
|
||||
("preset-password-in-use-tip", "Forudindstillet adgangskode er i øjeblikket i brug."),
|
||||
("Enable privacy mode", "Aktivér privatlivstilstand"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Tillad fastgørelse af fjernværktøjslinjen til enhver vindueskant"),
|
||||
("API Token", "API-token"),
|
||||
("Deploy", "Udrul"),
|
||||
("Custom ID (optional)", "Tilpasset ID (valgfrit)"),
|
||||
("server_requires_deployment_tip", "Serveren kræver, at denne enhed udrulles eksplicit. Udrul nu?"),
|
||||
("The server does not require explicit deployment.", "Serveren kræver ikke eksplicit udrulning."),
|
||||
("Unknown response.", "Ukendt svar."),
|
||||
("wayland-keyboard-input-disabled-tip", "Tillad tastaturinput?"),
|
||||
("wayland-keyboard-input-consent-tip", "Det, du skriver på denne fjerncomputer (inklusive adgangskoder), kan blive læst af andre apps på den."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Dette valg gælder for:"),
|
||||
("wayland-soft-keyboard-input-label", "Softwaretastaturinput"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Nulstil valg for tastaturinput"),
|
||||
("remember-wayland-keyboard-choice-tip", "Spørg ikke igen for denne fjerncomputer"),
|
||||
("Why this happens", "Hvorfor dette sker"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "Anzeigename"),
|
||||
("password-hidden-tip", "Ein permanentes Passwort wurde festgelegt (ausgeblendet)."),
|
||||
("preset-password-in-use-tip", "Das voreingestellte Passwort wird derzeit verwendet."),
|
||||
("Enable privacy mode", "Datenschutzmodus aktivieren"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Andocken der Remote-Symbolleiste an jeden Fensterrand zulassen"),
|
||||
("API Token", "API-Token"),
|
||||
("Deploy", "Bereitstellen"),
|
||||
("Custom ID (optional)", "Benutzerdefinierte ID (optional)"),
|
||||
("server_requires_deployment_tip", "Der Server erfordert, dass dieses Gerät explizit bereitgestellt wird. Jetzt bereitstellen?"),
|
||||
("The server does not require explicit deployment.", "Der Server erfordert keine explizite Bereitstellung."),
|
||||
("Unknown response.", "Unbekannte Antwort."),
|
||||
("wayland-keyboard-input-disabled-tip", "Tastatureingabe zulassen?"),
|
||||
("wayland-keyboard-input-consent-tip", "Was Sie auf diesem entfernten Computer eingeben (einschließlich Passwörter), könnte von anderen Apps darauf gelesen werden."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Diese Auswahl gilt für:"),
|
||||
("wayland-soft-keyboard-input-label", "Bildschirmtastatureingabe"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Auswahl der Tastatureingabe zurücksetzen"),
|
||||
("remember-wayland-keyboard-choice-tip", "Für diesen entfernten Computer nicht erneut fragen"),
|
||||
("Why this happens", "Warum dies passiert"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Κοινή χρήση οθόνης"),
|
||||
("ubuntu-21-04-required", "Το Wayland απαιτεί Ubuntu 21.04 ή νεότερη έκδοση."),
|
||||
("wayland-requires-higher-linux-version", "Το Wayland απαιτεί υψηλότερη έκδοση διανομής του linux. Δοκιμάστε την επιφάνεια εργασίας X11 ή αλλάξτε το λειτουργικό σας σύστημα."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Η καταγραφή οθόνης μέσω Wayland απέτυχε. Το XDG Desktop Portal ενδέχεται να έχει καταρρεύσει ή να μην είναι διαθέσιμο. Δοκιμάστε να το επανεκκινήσετε με `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Σύνδεσμος μετάβασης"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Επιλέξτε την οθόνη που θέλετε να μοιραστείτε (Λειτουργία στην πλευρά του απομακρυσμένου σταθμού)."),
|
||||
("Show RustDesk", "Εμφάνιση του RustDesk"),
|
||||
@@ -741,7 +741,22 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("keep-awake-during-incoming-sessions-label", "Διατήρηση ενεργής οθόνης κατά τη διάρκεια των εισερχόμενων συνεδριών"),
|
||||
("Continue with {}", "Συνέχεια με {}"),
|
||||
("Display Name", "Εμφανιζόμενο όνομα"),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("password-hidden-tip", "Έχει οριστεί μόνιμος κωδικός πρόσβασης (κρυφός)."),
|
||||
("preset-password-in-use-tip", "Ο προκαθορισμένος κωδικός πρόσβασης χρησιμοποιείται αυτήν τη στιγμή."),
|
||||
("Enable privacy mode", "Ενεργοποίηση λειτουργίας απορρήτου"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Να επιτρέπεται η προσάρτηση της απομακρυσμένης γραμμής εργαλείων σε οποιαδήποτε άκρη του παραθύρου"),
|
||||
("API Token", "Διακριτικό API"),
|
||||
("Deploy", "Ανάπτυξη"),
|
||||
("Custom ID (optional)", "Προσαρμοσμένο ID (προαιρετικό)"),
|
||||
("server_requires_deployment_tip", "Ο διακομιστής απαιτεί να αναπτυχθεί ρητά αυτή η συσκευή. Ανάπτυξη τώρα;"),
|
||||
("The server does not require explicit deployment.", "Ο διακομιστής δεν απαιτεί ρητή ανάπτυξη."),
|
||||
("Unknown response.", "Άγνωστη απάντηση."),
|
||||
("wayland-keyboard-input-disabled-tip", "Να επιτρέπεται η εισαγωγή από το πληκτρολόγιο;"),
|
||||
("wayland-keyboard-input-consent-tip", "Ό,τι πληκτρολογείτε σε αυτόν τον απομακρυσμένο υπολογιστή (συμπεριλαμβανομένων των κωδικών πρόσβασης) θα μπορούσε να διαβαστεί από άλλες εφαρμογές σε αυτόν."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Αυτή η επιλογή ισχύει για:"),
|
||||
("wayland-soft-keyboard-input-label", "Εισαγωγή από εικονικό πληκτρολόγιο"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Επαναφορά επιλογής εισαγωγής από πληκτρολόγιο"),
|
||||
("remember-wayland-keyboard-choice-tip", "Να μην ερωτηθώ ξανά για αυτόν τον απομακρυσμένο υπολογιστή"),
|
||||
("Why this happens", "Γιατί συμβαίνει αυτό"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -218,8 +218,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "More on web console"),
|
||||
("allow-only-conn-window-open-tip", "Only allow connection if RustDesk window is open"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "No physical displays, no need to use the privacy mode."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", "Default protocol and port are Socks5 and 1080"),
|
||||
("no_audio_input_device_tip", "No audio input device found."),
|
||||
("clear_Wayland_screen_selection_tip", "After clearing the screen selection, you can reselect the screen to share."),
|
||||
@@ -231,7 +229,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("enable-bot-desc", "1. Open a chat with @BotFather.\n2. Send the command \"/newbot\". You will receive a token after completing this step.\n3. Start a chat with your newly created bot. Send a message beginning with a forward slash (\"/\") like \"/hello\" to activate it.\n"),
|
||||
("cancel-2fa-confirm-tip", "Are you sure you want to cancel 2FA?"),
|
||||
("cancel-bot-confirm-tip", "Are you sure you want to cancel Telegram bot?"),
|
||||
("About RustDesk", ""),
|
||||
("network_error_tip", "Please check your network connection, then click retry."),
|
||||
("enable-trusted-devices-tip", "Skip 2FA verification on trusted devices"),
|
||||
("one-way-file-transfer-tip", "One-way file transfer is enabled on the controlled side."),
|
||||
@@ -274,5 +271,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("keep-awake-during-incoming-sessions-label", "Keep screen awake during incoming sessions"),
|
||||
("password-hidden-tip", "Permanent password is set (hidden)."),
|
||||
("preset-password-in-use-tip", "Preset password is currently in use."),
|
||||
("allow-remote-toolbar-docking-any-edge", "Allow docking remote toolbar to any window edge"),
|
||||
("server_requires_deployment_tip", "The server requires this device to be deployed explicitly. Deploy now?"),
|
||||
("wayland-keyboard-input-disabled-tip", "Allow keyboard input?"),
|
||||
("wayland-keyboard-input-consent-tip", "What you type on this remote computer (including passwords) could be read by other apps on it."),
|
||||
("wayland-keyboard-input-applies-to-tip", "This choice applies to:"),
|
||||
("wayland-soft-keyboard-input-label", "Soft keyboard input"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Reset keyboard input choice"),
|
||||
("remember-wayland-keyboard-choice-tip", "Don't ask again for this remote computer"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
829
src/lang/eo.rs
829
src/lang/eo.rs
@@ -125,7 +125,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Good image quality", "Bona bilda kvalito"),
|
||||
("Balanced", "Normala bilda kvalito"),
|
||||
("Optimize reaction time", "Optimigi reakcia tempo"),
|
||||
("Custom", ""),
|
||||
("Custom", "Propra"),
|
||||
("Show remote cursor", "Montri foran kursoron"),
|
||||
("Show quality monitor", "Montri kvalito monitoron"),
|
||||
("Disable clipboard", "Malebligi poŝon"),
|
||||
@@ -228,7 +228,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Username missed", "Uzantnomo forgesita"),
|
||||
("Password missed", "Pasvorto forgesita"),
|
||||
("Wrong credentials", "Identigilo aŭ pasvorto erara"),
|
||||
("The verification code is incorrect or has expired", ""),
|
||||
("The verification code is incorrect or has expired", "La konfirmkodo estas malĝusta aŭ eksvalidiĝis"),
|
||||
("Edit Tag", "Redakti etikedo"),
|
||||
("Forget Password", "Forgesi pasvorton"),
|
||||
("Favorites", "Favorataj"),
|
||||
@@ -305,7 +305,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Start on boot", "Komencu ĉe ekfunkciigo"),
|
||||
("Start the screen sharing service on boot, requires special permissions", "Komencu la servon de kundivido de ekrano ĉe lanĉo, postulas specialajn permesojn"),
|
||||
("Connection not allowed", "Konekto ne rajtas"),
|
||||
("Legacy mode", ""),
|
||||
("Legacy mode", "Malnova reĝimo"),
|
||||
("Map mode", "Mapa modo"),
|
||||
("Translate mode", "Traduki modo"),
|
||||
("Use permanent password", "Uzu permanenta pasvorto"),
|
||||
@@ -334,414 +334,429 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Insecure Connection", "Nesekura Konekto"),
|
||||
("Scale original", "Skalo originalo"),
|
||||
("Scale adaptive", "Skalo adapta"),
|
||||
("General", ""),
|
||||
("Security", ""),
|
||||
("Theme", ""),
|
||||
("Dark Theme", ""),
|
||||
("Light Theme", ""),
|
||||
("Dark", ""),
|
||||
("Light", ""),
|
||||
("Follow System", ""),
|
||||
("Enable hardware codec", ""),
|
||||
("Unlock Security Settings", ""),
|
||||
("Enable audio", ""),
|
||||
("Unlock Network Settings", ""),
|
||||
("Server", ""),
|
||||
("Direct IP Access", ""),
|
||||
("Proxy", ""),
|
||||
("Apply", ""),
|
||||
("Disconnect all devices?", ""),
|
||||
("Clear", ""),
|
||||
("Audio Input Device", ""),
|
||||
("Use IP Whitelisting", ""),
|
||||
("Network", ""),
|
||||
("Pin Toolbar", ""),
|
||||
("Unpin Toolbar", ""),
|
||||
("Recording", ""),
|
||||
("Directory", ""),
|
||||
("Automatically record incoming sessions", ""),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Change", ""),
|
||||
("Start session recording", ""),
|
||||
("Stop session recording", ""),
|
||||
("Enable recording session", ""),
|
||||
("Enable LAN discovery", ""),
|
||||
("Deny LAN discovery", ""),
|
||||
("Write a message", ""),
|
||||
("Prompt", ""),
|
||||
("Please wait for confirmation of UAC...", ""),
|
||||
("elevated_foreground_window_tip", ""),
|
||||
("Disconnected", ""),
|
||||
("Other", ""),
|
||||
("Confirm before closing multiple tabs", ""),
|
||||
("Keyboard Settings", ""),
|
||||
("Full Access", ""),
|
||||
("Screen Share", ""),
|
||||
("General", "Ĝenerala"),
|
||||
("Security", "Sekureco"),
|
||||
("Theme", "Etoso"),
|
||||
("Dark Theme", "Malhela etoso"),
|
||||
("Light Theme", "Hela etoso"),
|
||||
("Dark", "Malhela"),
|
||||
("Light", "Hela"),
|
||||
("Follow System", "Sekvi la sistemon"),
|
||||
("Enable hardware codec", "Ebligi aparataran kodekon"),
|
||||
("Unlock Security Settings", "Malŝlosi sekurecajn agordojn"),
|
||||
("Enable audio", "Ebligi sonon"),
|
||||
("Unlock Network Settings", "Malŝlosi retajn agordojn"),
|
||||
("Server", "Servilo"),
|
||||
("Direct IP Access", "Rekta IP-aliro"),
|
||||
("Proxy", "Prokurilo"),
|
||||
("Apply", "Apliki"),
|
||||
("Disconnect all devices?", "Ĉu malkonekti ĉiujn aparatojn?"),
|
||||
("Clear", "Vakigi"),
|
||||
("Audio Input Device", "Aŭdia eniga aparato"),
|
||||
("Use IP Whitelisting", "Uzi liston de IP akceptataj"),
|
||||
("Network", "Reto"),
|
||||
("Pin Toolbar", "Alpingli ilobreton"),
|
||||
("Unpin Toolbar", "Malalpingli ilobreton"),
|
||||
("Recording", "Registrado"),
|
||||
("Directory", "Dosierujo"),
|
||||
("Automatically record incoming sessions", "Aŭtomate registri envenajn sesiojn"),
|
||||
("Automatically record outgoing sessions", "Aŭtomate registri elirajn sesiojn"),
|
||||
("Change", "Ŝanĝi"),
|
||||
("Start session recording", "Komenci sesian registradon"),
|
||||
("Stop session recording", "Halti sesian registradon"),
|
||||
("Enable recording session", "Ebligi sesian registradon"),
|
||||
("Enable LAN discovery", "Ebligi malkovron en LAN"),
|
||||
("Deny LAN discovery", "Malpermesi malkovron en LAN"),
|
||||
("Write a message", "Skribi mesaĝon"),
|
||||
("Prompt", "Demandi"),
|
||||
("Please wait for confirmation of UAC...", "Bonvolu atendi la konfirmon de UAC..."),
|
||||
("elevated_foreground_window_tip", "La aktuala fenestro de la fora labortablo bezonas pli altajn privilegiojn por funkcii, do provizore ne eblas uzi la muson kaj klavaron. Vi povas peti la foran uzanton minimumigi la aktualan fenestron, aŭ alklaki la altigan butonon en la fenestro de konekta administrado. Por eviti tiun problemon, oni rekomendas instali la programaron sur la fora aparato."),
|
||||
("Disconnected", "Malkonektita"),
|
||||
("Other", "Alia"),
|
||||
("Confirm before closing multiple tabs", "Konfirmi antaŭ fermi plurajn langetojn"),
|
||||
("Keyboard Settings", "Klavaraj agordoj"),
|
||||
("Full Access", "Plena aliro"),
|
||||
("Screen Share", "Kundivido de ekrano"),
|
||||
("ubuntu-21-04-required", "Wayland postulas Ubuntu 21.04 aŭ pli altan version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland postulas pli altan version de linuksa distro. Bonvolu provi X11-labortablon aŭ ŝanĝi vian OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "La ekrankapto de Wayland malsukcesis. La XDG Desktop Portal eble kraŝis aŭ estas nedisponebla. Provu restarti ĝin per `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Bonvolu Elekti la ekranon por esti dividita (Funkciu ĉe la sama flanko)."),
|
||||
("Show RustDesk", ""),
|
||||
("This PC", ""),
|
||||
("or", ""),
|
||||
("Elevate", ""),
|
||||
("Zoom cursor", ""),
|
||||
("Accept sessions via password", ""),
|
||||
("Accept sessions via click", ""),
|
||||
("Accept sessions via both", ""),
|
||||
("Please wait for the remote side to accept your session request...", ""),
|
||||
("One-time Password", ""),
|
||||
("Use one-time password", ""),
|
||||
("One-time password length", ""),
|
||||
("Request access to your device", ""),
|
||||
("Hide connection management window", ""),
|
||||
("hide_cm_tip", ""),
|
||||
("wayland_experiment_tip", ""),
|
||||
("Right click to select tabs", ""),
|
||||
("Skipped", ""),
|
||||
("Add to address book", ""),
|
||||
("Group", ""),
|
||||
("Search", ""),
|
||||
("Closed manually by web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
("config_microphone", ""),
|
||||
("request_elevation_tip", ""),
|
||||
("Wait", ""),
|
||||
("Elevation Error", ""),
|
||||
("Ask the remote user for authentication", ""),
|
||||
("Choose this if the remote account is administrator", ""),
|
||||
("Transmit the username and password of administrator", ""),
|
||||
("still_click_uac_tip", ""),
|
||||
("Request Elevation", ""),
|
||||
("wait_accept_uac_tip", ""),
|
||||
("Elevate successfully", ""),
|
||||
("uppercase", ""),
|
||||
("lowercase", ""),
|
||||
("digit", ""),
|
||||
("special character", ""),
|
||||
("length>=8", ""),
|
||||
("Weak", ""),
|
||||
("Medium", ""),
|
||||
("Strong", ""),
|
||||
("Switch Sides", ""),
|
||||
("Please confirm if you want to share your desktop?", ""),
|
||||
("Display", ""),
|
||||
("Default View Style", ""),
|
||||
("Default Scroll Style", ""),
|
||||
("Default Image Quality", ""),
|
||||
("Default Codec", ""),
|
||||
("Bitrate", ""),
|
||||
("FPS", ""),
|
||||
("Auto", ""),
|
||||
("Other Default Options", ""),
|
||||
("Voice call", ""),
|
||||
("Text chat", ""),
|
||||
("Stop voice call", ""),
|
||||
("relay_hint_tip", ""),
|
||||
("Reconnect", ""),
|
||||
("Codec", ""),
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
("New Connection", ""),
|
||||
("Restore", ""),
|
||||
("Minimize", ""),
|
||||
("Maximize", ""),
|
||||
("Your Device", ""),
|
||||
("empty_recent_tip", ""),
|
||||
("empty_favorite_tip", ""),
|
||||
("empty_lan_tip", ""),
|
||||
("empty_address_book_tip", ""),
|
||||
("Empty Username", ""),
|
||||
("Empty Password", ""),
|
||||
("Me", ""),
|
||||
("identical_file_tip", ""),
|
||||
("show_monitors_tip", ""),
|
||||
("View Mode", ""),
|
||||
("login_linux_tip", ""),
|
||||
("verify_rustdesk_password_tip", ""),
|
||||
("remember_account_tip", ""),
|
||||
("os_account_desk_tip", ""),
|
||||
("OS Account", ""),
|
||||
("another_user_login_title_tip", ""),
|
||||
("another_user_login_text_tip", ""),
|
||||
("xorg_not_found_title_tip", ""),
|
||||
("xorg_not_found_text_tip", ""),
|
||||
("no_desktop_title_tip", ""),
|
||||
("no_desktop_text_tip", ""),
|
||||
("No need to elevate", ""),
|
||||
("System Sound", ""),
|
||||
("Default", ""),
|
||||
("New RDP", ""),
|
||||
("Fingerprint", ""),
|
||||
("Copy Fingerprint", ""),
|
||||
("no fingerprints", ""),
|
||||
("Select a peer", ""),
|
||||
("Select peers", ""),
|
||||
("Plugins", ""),
|
||||
("Uninstall", ""),
|
||||
("Update", ""),
|
||||
("Enable", ""),
|
||||
("Disable", ""),
|
||||
("Options", ""),
|
||||
("resolution_original_tip", ""),
|
||||
("resolution_fit_local_tip", ""),
|
||||
("resolution_custom_tip", ""),
|
||||
("Collapse toolbar", ""),
|
||||
("Accept and Elevate", ""),
|
||||
("accept_and_elevate_btn_tooltip", ""),
|
||||
("clipboard_wait_response_timeout_tip", ""),
|
||||
("Incoming connection", ""),
|
||||
("Outgoing connection", ""),
|
||||
("Exit", ""),
|
||||
("Open", ""),
|
||||
("logout_tip", ""),
|
||||
("Service", ""),
|
||||
("Start", ""),
|
||||
("Stop", ""),
|
||||
("exceed_max_devices", ""),
|
||||
("Sync with recent sessions", ""),
|
||||
("Sort tags", ""),
|
||||
("Open connection in new tab", ""),
|
||||
("Move tab to new window", ""),
|
||||
("Can not be empty", ""),
|
||||
("Already exists", ""),
|
||||
("Change Password", ""),
|
||||
("Refresh Password", ""),
|
||||
("ID", ""),
|
||||
("Grid View", ""),
|
||||
("List View", ""),
|
||||
("Select", ""),
|
||||
("Toggle Tags", ""),
|
||||
("pull_ab_failed_tip", ""),
|
||||
("push_ab_failed_tip", ""),
|
||||
("synced_peer_readded_tip", ""),
|
||||
("Change Color", ""),
|
||||
("Primary Color", ""),
|
||||
("HSV Color", ""),
|
||||
("Installation Successful!", ""),
|
||||
("Installation failed!", ""),
|
||||
("Reverse mouse wheel", ""),
|
||||
("{} sessions", ""),
|
||||
("scam_title", ""),
|
||||
("scam_text1", ""),
|
||||
("scam_text2", ""),
|
||||
("Don't show again", ""),
|
||||
("I Agree", ""),
|
||||
("Decline", ""),
|
||||
("Timeout in minutes", ""),
|
||||
("auto_disconnect_option_tip", ""),
|
||||
("Connection failed due to inactivity", ""),
|
||||
("Check for software update on startup", ""),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", ""),
|
||||
("pull_group_failed_tip", ""),
|
||||
("Filter by intersection", ""),
|
||||
("Remove wallpaper during incoming sessions", ""),
|
||||
("Test", ""),
|
||||
("display_is_plugged_out_msg", ""),
|
||||
("No displays", ""),
|
||||
("Open in new window", ""),
|
||||
("Show displays as individual windows", ""),
|
||||
("Use all my displays for the remote session", ""),
|
||||
("selinux_tip", ""),
|
||||
("Change view", ""),
|
||||
("Big tiles", ""),
|
||||
("Small tiles", ""),
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color (4:4:4)", ""),
|
||||
("Enable blocking user input", ""),
|
||||
("id_input_tip", ""),
|
||||
("privacy_mode_impl_mag_tip", ""),
|
||||
("privacy_mode_impl_virtual_display_tip", ""),
|
||||
("Enter privacy mode", ""),
|
||||
("Exit privacy mode", ""),
|
||||
("idd_not_support_under_win10_2004_tip", ""),
|
||||
("input_source_1_tip", ""),
|
||||
("input_source_2_tip", ""),
|
||||
("Swap control-command key", ""),
|
||||
("swap-left-right-mouse", ""),
|
||||
("2FA code", ""),
|
||||
("More", ""),
|
||||
("enable-2fa-title", ""),
|
||||
("enable-2fa-desc", ""),
|
||||
("wrong-2fa-code", ""),
|
||||
("enter-2fa-title", ""),
|
||||
("Email verification code must be 6 characters.", ""),
|
||||
("2FA code must be 6 digits.", ""),
|
||||
("Multiple Windows sessions found", ""),
|
||||
("Please select the session you want to connect to", ""),
|
||||
("powered_by_me", ""),
|
||||
("outgoing_only_desk_tip", ""),
|
||||
("preset_password_warning", ""),
|
||||
("Security Alert", ""),
|
||||
("My address book", ""),
|
||||
("Personal", ""),
|
||||
("Owner", ""),
|
||||
("Set shared password", ""),
|
||||
("Exist in", ""),
|
||||
("Read-only", ""),
|
||||
("Read/Write", ""),
|
||||
("Full Control", ""),
|
||||
("share_warning_tip", ""),
|
||||
("Everyone", ""),
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Clear Wayland screen selection", ""),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("Use texture rendering", ""),
|
||||
("Floating window", ""),
|
||||
("floating_window_tip", ""),
|
||||
("Keep screen on", ""),
|
||||
("Never", ""),
|
||||
("During controlled", ""),
|
||||
("During service is on", ""),
|
||||
("Capture screen using DirectX", ""),
|
||||
("Back", ""),
|
||||
("Apps", ""),
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("Show RustDesk", "Montri RustDesk"),
|
||||
("This PC", "Ĉi tiu komputilo"),
|
||||
("or", "aŭ"),
|
||||
("Elevate", "Altigi"),
|
||||
("Zoom cursor", "Zomi kursoron"),
|
||||
("Accept sessions via password", "Akcepti sesiojn per pasvorto"),
|
||||
("Accept sessions via click", "Akcepti sesiojn per alklako"),
|
||||
("Accept sessions via both", "Akcepti sesiojn per ambaŭ"),
|
||||
("Please wait for the remote side to accept your session request...", "Bonvolu atendi ke la fora flanko akceptu vian sesian peton..."),
|
||||
("One-time Password", "Unufoja pasvorto"),
|
||||
("Use one-time password", "Uzi unufojan pasvorton"),
|
||||
("One-time password length", "Longeco de la unufoja pasvorto"),
|
||||
("Request access to your device", "Peti aliron al via aparato"),
|
||||
("Hide connection management window", "Kaŝi la fenestron de konekta administrado"),
|
||||
("hide_cm_tip", "Permesi kaŝadon nur se oni akceptas sesiojn per pasvorto kaj uzas permanentan pasvorton"),
|
||||
("wayland_experiment_tip", "La subteno de Wayland estas en eksperimenta stadio, bonvolu uzi X11 se vi bezonas senĉeestan aliron."),
|
||||
("Right click to select tabs", "Dekstre alklaku por elekti langetojn"),
|
||||
("Skipped", "Preterlasita"),
|
||||
("Add to address book", "Aldoni al adresaro"),
|
||||
("Group", "Grupo"),
|
||||
("Search", "Serĉi"),
|
||||
("Closed manually by web console", "Fermita permane de la reta konzolo"),
|
||||
("Local keyboard type", "Tipo de loka klavaro"),
|
||||
("Select local keyboard type", "Elekti tipon de loka klavaro"),
|
||||
("software_render_tip", "Se vi uzas Nvidia-grafikkarton sub Linukso kaj la fora fenestro fermiĝas tuj post konektado, ŝanĝo al la malfermkoda Nouveau-pelilo kaj elekto de programara bildigo eble helpos. Programara restarto estas necesa."),
|
||||
("Always use software rendering", "Ĉiam uzi programaran bildigon"),
|
||||
("config_input", "Por kontroli la foran labortablon per klavaro, vi devas doni al RustDesk permeson \"Eniga Monitorado\"."),
|
||||
("config_microphone", "Por paroli fore, vi devas doni al RustDesk permeson \"Registri Sonon\"."),
|
||||
("request_elevation_tip", "Vi ankaŭ povas peti altigon se iu ĉeestas ĉe la fora flanko."),
|
||||
("Wait", "Atendi"),
|
||||
("Elevation Error", "Eraro de altigo"),
|
||||
("Ask the remote user for authentication", "Peti aŭtentikigon de la fora uzanto"),
|
||||
("Choose this if the remote account is administrator", "Elektu ĉi tion se la fora konto estas administranto"),
|
||||
("Transmit the username and password of administrator", "Transsendi la uzantnomon kaj pasvorton de administranto"),
|
||||
("still_click_uac_tip", "Ankoraŭ postulas ke la fora uzanto alklaku Bone en la UAC-fenestro de la funkcianta RustDesk."),
|
||||
("Request Elevation", "Peti altigon"),
|
||||
("wait_accept_uac_tip", "Bonvolu atendi ke la fora uzanto akceptu la UAC-dialogon."),
|
||||
("Elevate successfully", "Altigo sukcesa"),
|
||||
("uppercase", "majusklo"),
|
||||
("lowercase", "minusklo"),
|
||||
("digit", "cifero"),
|
||||
("special character", "speciala signo"),
|
||||
("length>=8", "longeco>=8"),
|
||||
("Weak", "Malforta"),
|
||||
("Medium", "Meza"),
|
||||
("Strong", "Forta"),
|
||||
("Switch Sides", "Interŝanĝi flankojn"),
|
||||
("Please confirm if you want to share your desktop?", "Bonvolu konfirmi ĉu vi volas kundividi vian labortablon?"),
|
||||
("Display", "Ekrano"),
|
||||
("Default View Style", "Implicita rigarda stilo"),
|
||||
("Default Scroll Style", "Implicita ruluma stilo"),
|
||||
("Default Image Quality", "Implicita bilda kvalito"),
|
||||
("Default Codec", "Implicita kodeko"),
|
||||
("Bitrate", "Bitrapido"),
|
||||
("FPS", "FPS"),
|
||||
("Auto", "Aŭtomata"),
|
||||
("Other Default Options", "Aliaj implicitaj opcioj"),
|
||||
("Voice call", "Voĉvoko"),
|
||||
("Text chat", "Teksta babilo"),
|
||||
("Stop voice call", "Halti voĉvokon"),
|
||||
("relay_hint_tip", "Eble ne eblas konekti rekte; vi povas provi konekti per relajso. Krome, se vi volas uzi relajson dum via unua provo, vi povas aldoni la sufikson \"/r\" al la identigilo aŭ elekti la opcion \"Ĉiam konekti per relajso\" en la karto de lastaj sesioj, se ĝi ekzistas."),
|
||||
("Reconnect", "Rekonekti"),
|
||||
("Codec", "Kodeko"),
|
||||
("Resolution", "Distingivo"),
|
||||
("No transfers in progress", "Neniu transigo en progreso"),
|
||||
("Set one-time password length", "Agordi longecon de la unufoja pasvorto"),
|
||||
("RDP Settings", "RDP-agordoj"),
|
||||
("Sort by", "Ordigi laŭ"),
|
||||
("New Connection", "Nova konekto"),
|
||||
("Restore", "Restarigi"),
|
||||
("Minimize", "Minimumigi"),
|
||||
("Maximize", "Maksimumigi"),
|
||||
("Your Device", "Via aparato"),
|
||||
("empty_recent_tip", "Aĥ, neniuj lastaj sesioj!\nEstas tempo plani novan."),
|
||||
("empty_favorite_tip", "Ankoraŭ neniuj favorataj samuloj?\nNi trovu iun por konekti kaj aldonu ĝin al viaj favorataj!"),
|
||||
("empty_lan_tip", "Ho ve, ŝajnas ke ni ankoraŭ ne malkovris iujn samulojn."),
|
||||
("empty_address_book_tip", "Ho ve, ŝajnas ke aktuale neniuj samuloj estas listigitaj en via adresaro."),
|
||||
("Empty Username", "Malplena uzantnomo"),
|
||||
("Empty Password", "Malplena pasvorto"),
|
||||
("Me", "Mi"),
|
||||
("identical_file_tip", "Ĉi tiu dosiero estas identa kun tiu de la samulo."),
|
||||
("show_monitors_tip", "Montri monitorojn en la ilobreto"),
|
||||
("View Mode", "Rigarda reĝimo"),
|
||||
("login_linux_tip", "Vi devas ensaluti al la fora Linuksa konto por ebligi X-labortablan sesion"),
|
||||
("verify_rustdesk_password_tip", "Kontroli RustDesk-pasvorton"),
|
||||
("remember_account_tip", "Memori ĉi tiun konton"),
|
||||
("os_account_desk_tip", "Ĉi tiu konto estas uzata por ensaluti al la fora operaciumo kaj ebligi la labortablan sesion en senekrana reĝimo"),
|
||||
("OS Account", "Konto de operaciumo"),
|
||||
("another_user_login_title_tip", "Alia uzanto jam ensalutis"),
|
||||
("another_user_login_text_tip", "Malkonekti"),
|
||||
("xorg_not_found_title_tip", "Xorg ne trovita"),
|
||||
("xorg_not_found_text_tip", "Bonvolu instali Xorg"),
|
||||
("no_desktop_title_tip", "Neniu labortabla medio disponeblas"),
|
||||
("no_desktop_text_tip", "Bonvolu instali GNOME-labortablon"),
|
||||
("No need to elevate", "Ne necesas altigi"),
|
||||
("System Sound", "Sistema sono"),
|
||||
("Default", "Implicita"),
|
||||
("New RDP", "Nova RDP"),
|
||||
("Fingerprint", "Fingrospuro"),
|
||||
("Copy Fingerprint", "Kopii fingrospuron"),
|
||||
("no fingerprints", "Neniuj fingrospuroj"),
|
||||
("Select a peer", "Elekti samulon"),
|
||||
("Select peers", "Elekti samulojn"),
|
||||
("Plugins", "Kromprogramoj"),
|
||||
("Uninstall", "Malinstali"),
|
||||
("Update", "Ĝisdatigi"),
|
||||
("Enable", "Ebligi"),
|
||||
("Disable", "Malebligi"),
|
||||
("Options", "Opcioj"),
|
||||
("resolution_original_tip", "Originala distingivo"),
|
||||
("resolution_fit_local_tip", "Adapti al loka distingivo"),
|
||||
("resolution_custom_tip", "Propra distingivo"),
|
||||
("Collapse toolbar", "Faldi ilobreton"),
|
||||
("Accept and Elevate", "Akcepti kaj altigi"),
|
||||
("accept_and_elevate_btn_tooltip", "Akcepti la konekton kaj altigi UAC-privilegiojn."),
|
||||
("clipboard_wait_response_timeout_tip", "Tempolimo dum atendado de kopia respondo."),
|
||||
("Incoming connection", "Enveninta konekto"),
|
||||
("Outgoing connection", "Eliranta konekto"),
|
||||
("Exit", "Eliri"),
|
||||
("Open", "Malfermi"),
|
||||
("logout_tip", "Ĉu vi certas ke vi volas elsaluti?"),
|
||||
("Service", "Servo"),
|
||||
("Start", "Komenci"),
|
||||
("Stop", "Halti"),
|
||||
("exceed_max_devices", "Vi atingis la maksimuman nombron da administrataj aparatoj."),
|
||||
("Sync with recent sessions", "Sinkronigi kun lastaj sesioj"),
|
||||
("Sort tags", "Ordigi etikedojn"),
|
||||
("Open connection in new tab", "Malfermi konekton en nova langeto"),
|
||||
("Move tab to new window", "Movi langeton al nova fenestro"),
|
||||
("Can not be empty", "Ne povas esti malplena"),
|
||||
("Already exists", "Jam ekzistas"),
|
||||
("Change Password", "Ŝanĝi pasvorton"),
|
||||
("Refresh Password", "Refreŝigi pasvorton"),
|
||||
("ID", "Identigilo"),
|
||||
("Grid View", "Krada rigardo"),
|
||||
("List View", "Lista rigardo"),
|
||||
("Select", "Elekti"),
|
||||
("Toggle Tags", "Baskuligi etikedojn"),
|
||||
("pull_ab_failed_tip", "Malsukcesis refreŝigi la adresaron"),
|
||||
("push_ab_failed_tip", "Malsukcesis sinkronigi la adresaron al la servilo"),
|
||||
("synced_peer_readded_tip", "La aparatoj kiuj ĉeestis en la lastaj sesioj estos sinkronigitaj reen al la adresaro."),
|
||||
("Change Color", "Ŝanĝi koloron"),
|
||||
("Primary Color", "Ĉefa koloro"),
|
||||
("HSV Color", "HSV-koloro"),
|
||||
("Installation Successful!", "Instalado sukcesa!"),
|
||||
("Installation failed!", "Instalado malsukcesis!"),
|
||||
("Reverse mouse wheel", "Inversigi musan radon"),
|
||||
("{} sessions", "{} sesioj"),
|
||||
("scam_title", "Vi Eble Estas TRUMPATA!"),
|
||||
("scam_text1", "Se vi telefonas kun iu kiun vi NE konas KAJ FIDAS, kiu petis vin uzi RustDesk kaj komenci la servon, ne daŭrigu kaj tuj malŝaltu la telefonon."),
|
||||
("scam_text2", "Ili verŝajne estas trompisto kiu provas ŝteli vian monon aŭ aliajn privatajn informojn."),
|
||||
("Don't show again", "Ne montri denove"),
|
||||
("I Agree", "Mi konsentas"),
|
||||
("Decline", "Malakcepti"),
|
||||
("Timeout in minutes", "Tempolimo en minutoj"),
|
||||
("auto_disconnect_option_tip", "Aŭtomate fermi envenajn sesiojn ĉe uzanta neaktiveco"),
|
||||
("Connection failed due to inactivity", "Aŭtomate malkonektita pro neaktiveco"),
|
||||
("Check for software update on startup", "Kontroli pri programara ĝisdatigo ĉe ekfunkciigo"),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", "Bonvolu ĝisdatigi RustDesk Server Pro al versio {} aŭ pli nova!"),
|
||||
("pull_group_failed_tip", "Malsukcesis refreŝigi la grupon"),
|
||||
("Filter by intersection", "Filtri laŭ intersekco"),
|
||||
("Remove wallpaper during incoming sessions", "Forigi la ekranfonon dum envenaj sesioj"),
|
||||
("Test", "Testi"),
|
||||
("display_is_plugged_out_msg", "La ekrano estas malkonektita, ŝanĝu al la unua ekrano."),
|
||||
("No displays", "Neniuj ekranoj"),
|
||||
("Open in new window", "Malfermi en nova fenestro"),
|
||||
("Show displays as individual windows", "Montri ekranojn kiel apartajn fenestrojn"),
|
||||
("Use all my displays for the remote session", "Uzi ĉiujn miajn ekranojn por la fora sesio"),
|
||||
("selinux_tip", "SELinux estas ebligita sur via aparato, kio povas malhelpi RustDesk funkcii ĝuste kiel kontrolata flanko."),
|
||||
("Change view", "Ŝanĝi rigardon"),
|
||||
("Big tiles", "Grandaj kaheloj"),
|
||||
("Small tiles", "Malgrandaj kaheloj"),
|
||||
("List", "Listo"),
|
||||
("Virtual display", "Virtuala ekrano"),
|
||||
("Plug out all", "Malkonekti ĉiujn"),
|
||||
("True color (4:4:4)", "Vera koloro (4:4:4)"),
|
||||
("Enable blocking user input", "Ebligi blokadon de uzanta enigo"),
|
||||
("id_input_tip", "Vi povas enigi identigilon, rektan IP, aŭ domajnon kun pordo (<domain>:<port>).\nSe vi volas aliri aparaton sur alia servilo, bonvolu aldoni la servilan adreson (<id>@<server_address>?key=<key_value>), ekzemple,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vi volas aliri aparaton sur publika servilo, bonvolu enigi \"<id>@public\", la ŝlosilo ne estas necesa por publika servilo.\n\nSe vi volas devigi la uzon de relajsa konekto ĉe la unua konekto, aldonu \"/r\" ĉe la fino de la identigilo, ekzemple, \"9123456234/r\"."),
|
||||
("privacy_mode_impl_mag_tip", "Reĝimo 1"),
|
||||
("privacy_mode_impl_virtual_display_tip", "Reĝimo 2"),
|
||||
("Enter privacy mode", "Eniri privatan reĝimon"),
|
||||
("Exit privacy mode", "Eliri privatan reĝimon"),
|
||||
("idd_not_support_under_win10_2004_tip", "Nerekta ekrana pelilo ne estas subtenata. Windows 10, versio 2004 aŭ pli nova estas necesa."),
|
||||
("input_source_1_tip", "Eniga fonto 1"),
|
||||
("input_source_2_tip", "Eniga fonto 2"),
|
||||
("Swap control-command key", "Interŝanĝi klavojn control kaj command"),
|
||||
("swap-left-right-mouse", "Interŝanĝi maldekstran kaj dekstran musajn butonojn"),
|
||||
("2FA code", "2FA-kodo"),
|
||||
("More", "Pli"),
|
||||
("enable-2fa-title", "Ebligi dufaktoran aŭtentikigon"),
|
||||
("enable-2fa-desc", "Bonvolu agordi vian aŭtentikilon nun. Vi povas uzi aŭtentikilan aplikaĵon kiel Authy, Microsoft aŭ Google Authenticator sur via telefono aŭ komputilo.\n\nSkanu la QR-kodon per via aplikaĵo kaj enigu la kodon kiun via aplikaĵo montras por ebligi dufaktoran aŭtentikigon."),
|
||||
("wrong-2fa-code", "Ne eblas kontroli la kodon. Kontrolu ke la kodo kaj la loka tempa agordo estas ĝustaj"),
|
||||
("enter-2fa-title", "Dufaktora aŭtentikigo"),
|
||||
("Email verification code must be 6 characters.", "La retpoŝta konfirmkodo devas esti 6 signoj."),
|
||||
("2FA code must be 6 digits.", "La 2FA-kodo devas esti 6 ciferoj."),
|
||||
("Multiple Windows sessions found", "Pluraj Windows-sesioj trovitaj"),
|
||||
("Please select the session you want to connect to", "Bonvolu elekti la sesion al kiu vi volas konekti"),
|
||||
("powered_by_me", "Funkciigita de RustDesk"),
|
||||
("outgoing_only_desk_tip", "Ĉi tio estas personigita eldono.\nVi povas konekti al aliaj aparatoj, sed aliaj aparatoj ne povas konekti al via aparato."),
|
||||
("preset_password_warning", "Ĉi tiu personigita eldono venas kun antaŭdifinita pasvorto. Iu ajn konanta ĉi tiun pasvorton povus akiri plenan kontrolon de via aparato. Se vi ne atendis ĉi tion, malinstalu la programaron tuj."),
|
||||
("Security Alert", "Sekureca averto"),
|
||||
("My address book", "Mia adresaro"),
|
||||
("Personal", "Persona"),
|
||||
("Owner", "Posedanto"),
|
||||
("Set shared password", "Agordi kundividitan pasvorton"),
|
||||
("Exist in", "Ekzistas en"),
|
||||
("Read-only", "Nurlega"),
|
||||
("Read/Write", "Lega/Skriba"),
|
||||
("Full Control", "Plena kontrolo"),
|
||||
("share_warning_tip", "La supraj kampoj estas kundividitaj kaj videblaj al aliaj."),
|
||||
("Everyone", "Ĉiuj"),
|
||||
("ab_web_console_tip", "Pli en la reta konzolo"),
|
||||
("allow-only-conn-window-open-tip", "Permesi konekton nur se la fenestro de RustDesk estas malfermita"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Neniuj fizikaj ekranoj, ne necesas uzi la privatan reĝimon."),
|
||||
("Follow remote cursor", "Sekvi foran kursoron"),
|
||||
("Follow remote window focus", "Sekvi fokuson de la fora fenestro"),
|
||||
("default_proxy_tip", "La implicitaj protokolo kaj pordo estas Socks5 kaj 1080"),
|
||||
("no_audio_input_device_tip", "Neniu aŭdia eniga aparato trovita."),
|
||||
("Incoming", "Enveninta"),
|
||||
("Outgoing", "Eliranta"),
|
||||
("Clear Wayland screen selection", "Vakigi la ekranelekton de Wayland"),
|
||||
("clear_Wayland_screen_selection_tip", "Post vakigo de la ekranelekto, vi povas reelekti la ekranon por kundividi."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Ĉu vi certas ke vi volas vakigi la ekranelekton de Wayland?"),
|
||||
("android_new_voice_call_tip", "Nova voĉvoka peto estis ricevita. Se vi akceptas, la sono ŝanĝiĝos al voĉa komunikado."),
|
||||
("texture_render_tip", "Uzi teksturan bildigon por glatigi la bildojn. Vi povus provi malebligi ĉi tiun opcion se vi renkontas bildigajn problemojn."),
|
||||
("Use texture rendering", "Uzi teksturan bildigon"),
|
||||
("Floating window", "Ŝveba fenestro"),
|
||||
("floating_window_tip", "Ĝi helpas teni la fonan servon de RustDesk"),
|
||||
("Keep screen on", "Teni la ekranon ŝaltita"),
|
||||
("Never", "Neniam"),
|
||||
("During controlled", "Dum kontrolata"),
|
||||
("During service is on", "Dum la servo estas ŝaltita"),
|
||||
("Capture screen using DirectX", "Kapti ekranon per DirectX"),
|
||||
("Back", "Reen"),
|
||||
("Apps", "Aplikaĵoj"),
|
||||
("Volume up", "Plilaŭtigi"),
|
||||
("Volume down", "Mallaŭtigi"),
|
||||
("Power", "Ŝalto"),
|
||||
("Telegram bot", "Telegram-roboto"),
|
||||
("enable-bot-tip", "Se vi ebligas ĉi tiun funkcion, vi povas ricevi la 2FA-kodon de via roboto. Ĝi ankaŭ povas funkcii kiel konekta sciigo."),
|
||||
("enable-bot-desc", "1. Malfermu babilon kun @BotFather.\n2. Sendu la komandon \"/newbot\". Vi ricevos ĵetonon post plenumi ĉi tiun paŝon.\n3. Komencu babilon kun via nove kreita roboto. Sendu mesaĝon komenciĝantan per oblikva streko (\"/\") kiel \"/hello\" por aktivigi ĝin.\n"),
|
||||
("cancel-2fa-confirm-tip", "Ĉu vi certas ke vi volas nuligi 2FA?"),
|
||||
("cancel-bot-confirm-tip", "Ĉu vi certas ke vi volas nuligi la Telegram-roboton?"),
|
||||
("About RustDesk", "Pri RustDesk"),
|
||||
("Send clipboard keystrokes", "Sendi poŝajn klavpremojn"),
|
||||
("network_error_tip", "Bonvolu kontroli vian retkonekton, poste alklaku reprovi."),
|
||||
("Unlock with PIN", "Malŝlosi per PIN"),
|
||||
("Requires at least {} characters", "Bezonas almenaŭ {} signojn"),
|
||||
("Wrong PIN", "Malĝusta PIN"),
|
||||
("Set PIN", "Agordi PIN"),
|
||||
("Enable trusted devices", "Ebligi fidatajn aparatojn"),
|
||||
("Manage trusted devices", "Administri fidatajn aparatojn"),
|
||||
("Platform", "Platformo"),
|
||||
("Days remaining", "Restantaj tagoj"),
|
||||
("enable-trusted-devices-tip", "Preterlasi 2FA-kontrolon sur fidataj aparatoj"),
|
||||
("Parent directory", "Patra dosierujo"),
|
||||
("Resume", "Daŭrigi"),
|
||||
("Invalid file name", "Nevalida dosiernomo"),
|
||||
("one-way-file-transfer-tip", "Unudirekta dosiertransigo estas ebligita ĉe la kontrolata flanko."),
|
||||
("Authentication Required", "Aŭtentikigo necesa"),
|
||||
("Authenticate", "Aŭtentikigi"),
|
||||
("web_id_input_tip", "Vi povas enigi identigilon en la sama servilo, rekta IP-aliro ne estas subtenata en la reta kliento.\nSe vi volas aliri aparaton sur alia servilo, bonvolu aldoni la servilan adreson (<id>@<server_address>?key=<key_value>), ekzemple,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vi volas aliri aparaton sur publika servilo, bonvolu enigi \"<id>@public\", la ŝlosilo ne estas necesa por publika servilo."),
|
||||
("Download", "Elŝuti"),
|
||||
("Upload folder", "Alŝuti dosierujon"),
|
||||
("Upload files", "Alŝuti dosierojn"),
|
||||
("Clipboard is synchronized", "La poŝo estas sinkronigita"),
|
||||
("Update client clipboard", "Ĝisdatigi la poŝon de la kliento"),
|
||||
("Untagged", "Sen etikedo"),
|
||||
("new-version-of-{}-tip", "Nova versio de {} disponeblas"),
|
||||
("Accessible devices", "Alireblaj aparatoj"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Bonvolu ĝisdatigi la RustDesk-klienton al versio {} aŭ pli nova ĉe la fora flanko!"),
|
||||
("d3d_render_tip", "Kiam D3D-bildigo estas ebligita, la ekrano de fora kontrolo povas esti nigra sur kelkaj maŝinoj."),
|
||||
("Use D3D rendering", "Uzi D3D-bildigon"),
|
||||
("Printer", "Presilo"),
|
||||
("printer-os-requirement-tip", "La eliranta presa funkcio bezonas Windows 10 aŭ pli novan."),
|
||||
("printer-requires-installed-{}-client-tip", "Por uzi foran presadon, {} devas esti instalita sur ĉi tiu aparato."),
|
||||
("printer-{}-not-installed-tip", "La presilo {} ne estas instalita."),
|
||||
("printer-{}-ready-tip", "La presilo {} estas instalita kaj preta por uzo."),
|
||||
("Install {} Printer", "Instali presilon {}"),
|
||||
("Outgoing Print Jobs", "Elirantaj presaj taskoj"),
|
||||
("Incoming Print Jobs", "Envenantaj presaj taskoj"),
|
||||
("Incoming Print Job", "Enveninta presa tasko"),
|
||||
("use-the-default-printer-tip", "Uzi la implicitan presilon"),
|
||||
("use-the-selected-printer-tip", "Uzi la elektitan presilon"),
|
||||
("auto-print-tip", "Presi aŭtomate uzante la elektitan presilon."),
|
||||
("print-incoming-job-confirm-tip", "Vi ricevis presan taskon de fore. Ĉu vi volas plenumi ĝin ĉe via flanko?"),
|
||||
("remote-printing-disallowed-tile-tip", "Fora presado malpermesita"),
|
||||
("remote-printing-disallowed-text-tip", "La permesaj agordoj de la kontrolata flanko malpermesas foran presadon."),
|
||||
("save-settings-tip", "Konservi agordojn"),
|
||||
("dont-show-again-tip", "Ne montri ĉi tion denove"),
|
||||
("Take screenshot", "Fari ekrankopion"),
|
||||
("Taking screenshot", "Faras ekrankopion"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Kunfandi ekrankopiojn de pluraj ekranoj aktuale ne estas subtenata. Bonvolu ŝanĝi al unu ekrano kaj reprovi."),
|
||||
("screenshot-action-tip", "Bonvolu elekti kiel daŭrigi kun la ekrankopio."),
|
||||
("Save as", "Konservi kiel"),
|
||||
("Copy to clipboard", "Kopii al la poŝo"),
|
||||
("Enable remote printer", "Ebligi foran presilon"),
|
||||
("Downloading {}", "Elŝutas {}"),
|
||||
("{} Update", "Ĝisdatigo de {}"),
|
||||
("{}-to-update-tip", "{} fermiĝos nun kaj instalos la novan version."),
|
||||
("download-new-version-failed-tip", "Elŝuto malsukcesis. Vi povas reprovi aŭ alklaki la butonon \"Elŝuti\" por elŝuti de la eldona paĝo kaj ĝisdatigi permane."),
|
||||
("Auto update", "Aŭtomata ĝisdatigo"),
|
||||
("update-failed-check-msi-tip", "Kontrolo de instala metodo malsukcesis. Bonvolu alklaki la butonon \"Elŝuti\" por elŝuti de la eldona paĝo kaj ĝisdatigi permane."),
|
||||
("websocket_tip", "Kiam oni uzas WebSocket, nur relajsaj konektoj estas subtenataj."),
|
||||
("Use WebSocket", "Uzi WebSocket"),
|
||||
("Trackpad speed", "Rapideco de tuŝplato"),
|
||||
("Default trackpad speed", "Implicita rapideco de tuŝplato"),
|
||||
("Numeric one-time password", "Numera unufoja pasvorto"),
|
||||
("Enable IPv6 P2P connection", "Ebligi IPv6 P2P-konekton"),
|
||||
("Enable UDP hole punching", "Ebligi UDP-trapikadon"),
|
||||
("View camera", "Rigardi kameron"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Enable camera", "Ebligi kameron"),
|
||||
("No cameras", "Neniuj kameroj"),
|
||||
("view_camera_unsupported_tip", "La fora aparato ne subtenas rigardadon de la kamero."),
|
||||
("Terminal", "Terminalo"),
|
||||
("Enable terminal", "Ebligi terminalon"),
|
||||
("New tab", "Nova langeto"),
|
||||
("Keep terminal sessions on disconnect", "Teni terminalajn sesiojn ĉe malkonekto"),
|
||||
("Terminal (Run as administrator)", "Terminalo (Ruli kiel administranto)"),
|
||||
("terminal-admin-login-tip", "Bonvolu enigi la administran uzantnomon kaj pasvorton de la kontrolata flanko."),
|
||||
("Failed to get user token.", "Malsukcesis akiri uzantan ĵetonon."),
|
||||
("Incorrect username or password.", "Malĝusta uzantnomo aŭ pasvorto."),
|
||||
("The user is not an administrator.", "La uzanto ne estas administranto."),
|
||||
("Failed to check if the user is an administrator.", "Malsukcesis kontroli ĉu la uzanto estas administranto."),
|
||||
("Supported only in the installed version.", "Subtenata nur en la instalita versio."),
|
||||
("elevation_username_tip", "Enigu uzantnomon aŭ domajno\\uzantnomo"),
|
||||
("Preparing for installation ...", "Preparas por instalado ..."),
|
||||
("Show my cursor", "Montri mian kursoron"),
|
||||
("Scale custom", "Propra skalo"),
|
||||
("Custom scale slider", "Ŝovilo de propra skalo"),
|
||||
("Decrease", "Malpliigi"),
|
||||
("Increase", "Pliigi"),
|
||||
("Show virtual mouse", "Montri virtualan muson"),
|
||||
("Virtual mouse size", "Grandeco de virtuala muso"),
|
||||
("Small", "Malgranda"),
|
||||
("Large", "Granda"),
|
||||
("Show virtual joystick", "Montri virtualan stirstangon"),
|
||||
("Edit note", "Redakti noton"),
|
||||
("Alias", "Kromnomo"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Permesi nesekuran TLS-retrokadron"),
|
||||
("allow-insecure-tls-fallback-tip", "Implicite, RustDesk kontrolas la servilan atestilon por protokoloj uzantaj TLS.\nKun ĉi tiu opcio ebligita, RustDesk retrokadros al preterlaso de la kontrola paŝo kaj daŭrigos en kazo de kontrola malsukceso."),
|
||||
("Disable UDP", "Malebligi UDP"),
|
||||
("disable-udp-tip", "Regas ĉu uzi nur TCP.\nKiam ĉi tiu opcio estas ebligita, RustDesk ne plu uzos UDP 21116, TCP 21116 estos uzata anstataŭe."),
|
||||
("server-oss-not-support-tip", "NOTU: RustDesk-servilo OSS ne inkluzivas ĉi tiun funkcion."),
|
||||
("input note here", "enigu noton ĉi tie"),
|
||||
("note-at-conn-end-tip", "Peti noton ĉe la fino de la konekto"),
|
||||
("Show terminal extra keys", "Montri kromajn klavojn de terminalo"),
|
||||
("Relative mouse mode", "Relativa musa reĝimo"),
|
||||
("rel-mouse-not-supported-peer-tip", "Relativa musa reĝimo ne estas subtenata de la konektita samulo."),
|
||||
("rel-mouse-not-ready-tip", "Relativa musa reĝimo ankoraŭ ne estas preta. Bonvolu reprovi."),
|
||||
("rel-mouse-lock-failed-tip", "Malsukcesis ŝlosi la kursoron. Relativa musa reĝimo estis malebligita."),
|
||||
("rel-mouse-exit-{}-tip", "Premu {} por eliri."),
|
||||
("rel-mouse-permission-lost-tip", "Klavara permeso estis revokita. Relativa musa reĝimo estis malebligita."),
|
||||
("Changelog", "Ŝanĝoprotokolo"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Teni la ekranon veka dum elirantaj sesioj"),
|
||||
("keep-awake-during-incoming-sessions-label", "Teni la ekranon veka dum envenantaj sesioj"),
|
||||
("Continue with {}", "Daŭrigi per {}"),
|
||||
("Display Name", "Montrata nomo"),
|
||||
("password-hidden-tip", "Permanenta pasvorto estas agordita (kaŝita)."),
|
||||
("preset-password-in-use-tip", "Antaŭdifinita pasvorto estas aktuale uzata."),
|
||||
("Enable privacy mode", "Ebligi privatan reĝimon"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Permesi alfiksi la foran ilobreton al iu ajn rando de fenestro"),
|
||||
("API Token", "API-ĵetono"),
|
||||
("Deploy", "Disfaldi"),
|
||||
("Custom ID (optional)", "Propra identigilo (laŭvola)"),
|
||||
("server_requires_deployment_tip", "La servilo postulas ke ĉi tiu aparato estu eksplicite disfaldita. Ĉu disfaldi nun?"),
|
||||
("The server does not require explicit deployment.", "La servilo ne postulas eksplicitan disfaldon."),
|
||||
("Unknown response.", "Nekonata respondo."),
|
||||
("wayland-keyboard-input-disabled-tip", "Ĉu permesi klavaran enigon?"),
|
||||
("wayland-keyboard-input-consent-tip", "Tio kion vi tajpas sur ĉi tiu fora komputilo (inkluzive pasvortojn) povus esti legata de aliaj aplikaĵoj sur ĝi."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Ĉi tiu elekto validas por:"),
|
||||
("wayland-soft-keyboard-input-label", "Programa klavara enigo"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Restarigi la elekton de klavara enigo"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ne demandi denove por ĉi tiu fora komputilo"),
|
||||
("Why this happens", "Kial ĉi tio okazas"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
123
src/lang/es.rs
123
src/lang/es.rs
@@ -67,14 +67,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Skip", "Omitir"),
|
||||
("Close", "Cerrar"),
|
||||
("Retry", "Reintentar"),
|
||||
("OK", ""),
|
||||
("OK", "Aceptar"),
|
||||
("Password Required", "Se requiere contraseña"),
|
||||
("Please enter your password", "Por favor, introduzca su contraseña"),
|
||||
("Remember password", "Recordar contraseña"),
|
||||
("Wrong Password", "Contraseña incorrecta"),
|
||||
("Do you want to enter again?", "¿Quieres volver a entrar?"),
|
||||
("Connection Error", "Error de conexión"),
|
||||
("Error", ""),
|
||||
("Error", "Error"),
|
||||
("Reset by the peer", "Restablecido por el par"),
|
||||
("Connecting...", "Conectando..."),
|
||||
("Connection in progress. Please wait.", "Conexión en curso. Espere por favor."),
|
||||
@@ -90,7 +90,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Receive", "Recibir"),
|
||||
("Send", "Enviar"),
|
||||
("Refresh File", "Actualizar archivo"),
|
||||
("Local", ""),
|
||||
("Local", "Local"),
|
||||
("Remote", "Remoto"),
|
||||
("Remote Computer", "Computadora remota"),
|
||||
("Local Computer", "Computadora local"),
|
||||
@@ -208,7 +208,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the peer", "Cerrado manualmente por el par"),
|
||||
("Enable remote configuration modification", "Habilitar modificación remota de configuración"),
|
||||
("Run without install", "Ejecutar sin instalar"),
|
||||
("Connect via relay", ""),
|
||||
("Connect via relay", "Conectar a través de relay"),
|
||||
("Always connect via relay", "Conéctese siempre a través de relay"),
|
||||
("whitelist_tip", "Solo las direcciones IP autorizadas pueden conectarse a este escritorio"),
|
||||
("Login", "Iniciar sesión"),
|
||||
@@ -228,7 +228,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Username missed", "Olvidó su nombre de usuario"),
|
||||
("Password missed", "Olvidó su contraseña"),
|
||||
("Wrong credentials", "Credenciales incorrectas"),
|
||||
("The verification code is incorrect or has expired", ""),
|
||||
("The verification code is incorrect or has expired", "El código de verificación es incorrecto o ha caducado"),
|
||||
("Edit Tag", "Editar tag"),
|
||||
("Forget Password", "Olvidar contraseña"),
|
||||
("Favorites", "Favoritos"),
|
||||
@@ -282,8 +282,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("android_service_will_start_tip", "Habilitar la captura de pantalla iniciará automáticamente el servicio, lo que permitirá que otros dispositivos soliciten una conexión desde este dispositivo."),
|
||||
("android_stop_service_tip", "Cerrar el servicio cerrará automáticamente todas las conexiones establecidas."),
|
||||
("android_version_audio_tip", "La versión actual de Android no admite la captura de audio, actualice a Android 10 o posterior."),
|
||||
("android_start_service_tip", ""),
|
||||
("android_permission_may_not_change_tip", ""),
|
||||
("android_start_service_tip", "Toque [Iniciar servicio] o conceda el permiso [Captura de pantalla] para iniciar el servicio de pantalla compartida."),
|
||||
("android_permission_may_not_change_tip", "Es posible que los permisos de las conexiones ya establecidas no cambien de inmediato hasta que se vuelva a conectar."),
|
||||
("Account", "Cuenta"),
|
||||
("Overwrite", "Sobrescribir"),
|
||||
("This file exists, skip or overwrite this file?", "Este archivo existe, ¿omitir o sobrescribir este archivo?"),
|
||||
@@ -302,8 +302,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Keep RustDesk background service", "Dejar RustDesk como Servicio en 2do plano"),
|
||||
("Ignore Battery Optimizations", "Ignorar optimizacioens de bateria"),
|
||||
("android_open_battery_optimizations_tip", "Si deseas deshabilitar esta característica, por favor, ve a la página siguiente de ajustes, busca y entra en [Batería] y desmarca [Sin restricción]"),
|
||||
("Start on boot", ""),
|
||||
("Start the screen sharing service on boot, requires special permissions", ""),
|
||||
("Start on boot", "Iniciar al arrancar"),
|
||||
("Start the screen sharing service on boot, requires special permissions", "Iniciar el servicio de pantalla compartida al arrancar, requiere permisos especiales"),
|
||||
("Connection not allowed", "Conexión no disponible"),
|
||||
("Legacy mode", "Modo heredado"),
|
||||
("Map mode", "Modo mapa"),
|
||||
@@ -326,19 +326,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Ratio", "Relación"),
|
||||
("Image Quality", "Calidad de imagen"),
|
||||
("Scroll Style", "Estilo de desplazamiento"),
|
||||
("Show Toolbar", ""),
|
||||
("Hide Toolbar", ""),
|
||||
("Show Toolbar", "Mostrar herramientas"),
|
||||
("Hide Toolbar", "Ocultar herramientas"),
|
||||
("Direct Connection", "Conexión directa"),
|
||||
("Relay Connection", "Conexión Relay"),
|
||||
("Secure Connection", "Conexión segura"),
|
||||
("Insecure Connection", "Conexión insegura"),
|
||||
("Scale original", "Escala original"),
|
||||
("Scale adaptive", "Escala adaptativa"),
|
||||
("General", ""),
|
||||
("General", "General"),
|
||||
("Security", "Seguridad"),
|
||||
("Theme", "Tema"),
|
||||
("Dark Theme", "Tema Oscuro"),
|
||||
("Light Theme", ""),
|
||||
("Light Theme", "Tema claro"),
|
||||
("Dark", "Oscuro"),
|
||||
("Light", "Claro"),
|
||||
("Follow System", "Tema del sistema"),
|
||||
@@ -348,19 +348,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Unlock Network Settings", "Desbloquear Ajustes de Red"),
|
||||
("Server", "Servidor"),
|
||||
("Direct IP Access", "Acceso IP Directo"),
|
||||
("Proxy", ""),
|
||||
("Proxy", "Proxy"),
|
||||
("Apply", "Aplicar"),
|
||||
("Disconnect all devices?", "¿Desconectar todos los dispositivos?"),
|
||||
("Clear", "Borrar"),
|
||||
("Audio Input Device", "Dispositivo de entrada de audio"),
|
||||
("Use IP Whitelisting", "Usar lista de IPs admitidas"),
|
||||
("Network", "Red"),
|
||||
("Pin Toolbar", ""),
|
||||
("Unpin Toolbar", ""),
|
||||
("Pin Toolbar", "Anclar herramientas"),
|
||||
("Unpin Toolbar", "Desanclar herramientas"),
|
||||
("Recording", "Grabando"),
|
||||
("Directory", "Directorio"),
|
||||
("Automatically record incoming sessions", "Grabación automática de sesiones entrantes"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Grabación automática de sesiones salientes"),
|
||||
("Change", "Cambiar"),
|
||||
("Start session recording", "Comenzar grabación de sesión"),
|
||||
("Stop session recording", "Detener grabación de sesión"),
|
||||
@@ -368,7 +368,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Enable LAN discovery", "Habilitar descubrimiento de LAN"),
|
||||
("Deny LAN discovery", "Denegar descubrimiento de LAN"),
|
||||
("Write a message", "Escribir un mensaje"),
|
||||
("Prompt", ""),
|
||||
("Prompt", "Solicitud"),
|
||||
("Please wait for confirmation of UAC...", "Por favor, espera confirmación de UAC"),
|
||||
("elevated_foreground_window_tip", "La ventana actual del escritorio remoto necesita privilegios elevados para funcionar, así que no puedes usar ratón y teclado temporalmente. Puedes solicitar al usuario remoto que minimize la ventana actual o hacer clic en el botón de elevación de la ventana de gestión de conexión. Para evitar este problema, se recomienda instalar el programa en el dispositivo remto."),
|
||||
("Disconnected", "Desconectado"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Compartir pantalla"),
|
||||
("ubuntu-21-04-required", "Wayland requiere Ubuntu 21.04 o una versión superior."),
|
||||
("wayland-requires-higher-linux-version", "Wayland requiere una versión superior de la distribución de Linux. Pruebe el escritorio X11 o cambie su sistema operativo."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Error en la captura de pantalla de Wayland. Es posible que el XDG Desktop Portal se haya bloqueado o no esté disponible. Intente reiniciarlo con `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Ver"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seleccione la pantalla que se compartirá (Operar en el lado del par)."),
|
||||
("Show RustDesk", "Mostrar RustDesk"),
|
||||
@@ -436,8 +436,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Default Image Quality", "Calidad de imagen predeterminada"),
|
||||
("Default Codec", "Códec predeterminado"),
|
||||
("Bitrate", "Tasa de bits"),
|
||||
("FPS", ""),
|
||||
("Auto", ""),
|
||||
("FPS", "FPS"),
|
||||
("Auto", "Automático"),
|
||||
("Other Default Options", "Otras opciones predeterminadas"),
|
||||
("Voice call", "Llamada de voz"),
|
||||
("Text chat", "Chat de texto"),
|
||||
@@ -515,7 +515,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Already exists", "Ya existe"),
|
||||
("Change Password", "Cambiar contraseña"),
|
||||
("Refresh Password", "Refrescar contraseña"),
|
||||
("ID", ""),
|
||||
("ID", "ID"),
|
||||
("Grid View", "Vista Cuadrícula"),
|
||||
("List View", "Vista Lista"),
|
||||
("Select", "Seleccionar"),
|
||||
@@ -616,9 +616,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("During service is on", "Mientras el servicio está activo"),
|
||||
("Capture screen using DirectX", "Capturar pantalla con DirectX"),
|
||||
("Back", "Atrás"),
|
||||
("Apps", ""),
|
||||
("Volume up", "Bajar volumen"),
|
||||
("Volume down", "Subir volumen"),
|
||||
("Apps", "Aplicaciones"),
|
||||
("Volume up", "Subir volumen"),
|
||||
("Volume down", "Bajar volumen"),
|
||||
("Power", "Encendido"),
|
||||
("Telegram bot", "Bot de Telegram"),
|
||||
("enable-bot-tip", "Si activas esta característica puedes recibir código 2FA de tu bot. También puede funcionar como notificación de conexión."),
|
||||
@@ -651,7 +651,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Update client clipboard", "Actualizar portapapeles del cliente"),
|
||||
("Untagged", "Sin itiquetar"),
|
||||
("new-version-of-{}-tip", "Hay una nueva versión de {} disponible"),
|
||||
("Accessible devices", ""),
|
||||
("Accessible devices", "Dispositivos accesibles"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Por favor, actualiza el cliente RustDesk a la versión {} o superior en el lado remoto"),
|
||||
("d3d_render_tip", "Al activar el renderizado D3D, la pantalla de control remoto puede verse negra en algunos equipos."),
|
||||
("Use D3D rendering", "Usar renderizado D3D"),
|
||||
@@ -689,14 +689,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Use WebSocket", "Usar WebSocket"),
|
||||
("Trackpad speed", "Velocidad de trackpad"),
|
||||
("Default trackpad speed", "Velocidad predeterminada de trackpad"),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("Numeric one-time password", "Contraseña numérica de un solo uso"),
|
||||
("Enable IPv6 P2P connection", "Habilitar conexión IPv6 P2P"),
|
||||
("Enable UDP hole punching", "Habilitar perforación de agujero UDP"),
|
||||
("View camera", "Ver cámara"),
|
||||
("Enable camera", "Habilitar cámara"),
|
||||
("No cameras", "No hay cámaras"),
|
||||
("view_camera_unsupported_tip", "El dispositivo remoto no soporta la visualización de la cámara."),
|
||||
("Terminal", ""),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Habilitar terminal"),
|
||||
("New tab", "Nueva pestaña"),
|
||||
("Keep terminal sessions on disconnect", "Mantener sesiones de terminal al desconectar"),
|
||||
@@ -708,8 +708,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Failed to check if the user is an administrator.", "No se ha podido comprobar si el usuario es un administrador."),
|
||||
("Supported only in the installed version.", "Soportado solo en la versión instalada."),
|
||||
("elevation_username_tip", "Introduzca el nombre de usuario o dominio\\NombreDeUsuario"),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Preparing for installation ...", "Preparando instlación..."),
|
||||
("Show my cursor", "Mostrar mi cursor"),
|
||||
("Scale custom", "Escala personalizada"),
|
||||
("Custom scale slider", "Control deslizante de escala personalizada"),
|
||||
("Decrease", "Disminuir"),
|
||||
@@ -720,28 +720,43 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Large", "Grande"),
|
||||
("Show virtual joystick", "Mostrar joystick virtual"),
|
||||
("Edit note", "Editar nota"),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "Desplazamiento de pantalla"),
|
||||
("Allow insecure TLS fallback", "Permitir conexión TLS insegura de respaldo"),
|
||||
("allow-insecure-tls-fallback-tip", "De forma predeterminada, RustDesk verifica el certificado de servidor para protocolos que usen TLS.\nCon esta opción habilitada, Rustdesk volverá al paso de omisión de verificación y procederá en caso de fallo de verificación."),
|
||||
("Disable UDP", "Inhabilitar UDP"),
|
||||
("disable-udp-tip", "Controla si se usa TCP solamente.\nCuando esta opción está activa, RustDesk no usará más el puerto UDP 21116, en su lugar se usará el TCP 21116."),
|
||||
("server-oss-not-support-tip", "NOTA: El servidor RustDesk OSS no incluye esta característica."),
|
||||
("input note here", "Introducir nota aquí"),
|
||||
("note-at-conn-end-tip", "Pedir nota al finalizar la conexión"),
|
||||
("Show terminal extra keys", "Mostrar teclas extra del terminal"),
|
||||
("Relative mouse mode", "Modo de ratón relativo"),
|
||||
("rel-mouse-not-supported-peer-tip", "El modo relativo de ratón no está soportado por el par."),
|
||||
("rel-mouse-not-ready-tip", "El modo relativo de ratón aún no está preparado. Por favor, inténtalo de nuevo."),
|
||||
("rel-mouse-lock-failed-tip", "Ha fallado el bloqueo del cursor. El modo relativo del ratón ha sido inhabilitado."),
|
||||
("rel-mouse-exit-{}-tip", "Pulsa {} para salir."),
|
||||
("rel-mouse-permission-lost-tip", "Permiso de teclado revocado. El modo relativo del ratón ha sido inhabilitado."),
|
||||
("Changelog", "Registro de cambios"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Mantener la pantalla activa durante sesiones salientes"),
|
||||
("keep-awake-during-incoming-sessions-label", "Mantener la pantalla activa durante sesiones entrantes"),
|
||||
("Continue with {}", "Continuar con {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Nombre de pantalla"),
|
||||
("password-hidden-tip", "La contraseña permanente está ajustada a (oculta)."),
|
||||
("preset-password-in-use-tip", "Se está usando la contraseña predeterminada."),
|
||||
("Enable privacy mode", "Habilitar modo privado"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Permitir acoplar la barra de herramientas remota a cualquier borde de la ventana"),
|
||||
("API Token", "Token de API"),
|
||||
("Deploy", "Implementar"),
|
||||
("Custom ID (optional)", "ID personalizado (opcional)"),
|
||||
("server_requires_deployment_tip", "El servidor requiere que este dispositivo se implemente de forma explícita. ¿Implementar ahora?"),
|
||||
("The server does not require explicit deployment.", "El servidor no requiere una implementación explícita."),
|
||||
("Unknown response.", "Respuesta desconocida."),
|
||||
("wayland-keyboard-input-disabled-tip", "¿Permitir la entrada del teclado?"),
|
||||
("wayland-keyboard-input-consent-tip", "Lo que escriba en este equipo remoto (incluidas las contraseñas) podría ser leído por otras aplicaciones del mismo."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Esta opción se aplica a:"),
|
||||
("wayland-soft-keyboard-input-label", "Entrada del teclado virtual"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Restablecer la opción de entrada del teclado"),
|
||||
("remember-wayland-keyboard-choice-tip", "No volver a preguntar para este equipo remoto"),
|
||||
("Why this happens", "Por qué ocurre esto"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
193
src/lang/et.rs
193
src/lang/et.rs
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Ekraanijagamine"),
|
||||
("ubuntu-21-04-required", "Wayland nõuab Ubuntu 21.04 või uuemat versiooni."),
|
||||
("wayland-requires-higher-linux-version", "Wayland nõuab Linuxi distributsiooni uuemat versiooni. Palun proovi X11 töölaual või muuda oma operatsioonisüsteemi."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland ekraani jäädvustamine ebaõnnestus. XDG Desktop Portal võis kokku joosta või pole saadaval. Proovi see taaskäivitada käsuga `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Palun vali jagatav ekraan (tegutse partneri poolel)."),
|
||||
("Show RustDesk", "Kuva RustDesk"),
|
||||
@@ -653,95 +653,110 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("new-version-of-{}-tip", "Saadaval on {} uus versioon"),
|
||||
("Accessible devices", "Ligipääsetavad seadmed"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Täiendage RustDeski klient kaugküljel versioonile {} või uuemale!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Kui D3D renderdamine on lubatud, võib kaugjuhtimise ekraan mõnel masinal olla must."),
|
||||
("Use D3D rendering", "Kasuta D3D renderdamist"),
|
||||
("Printer", "Printer"),
|
||||
("printer-os-requirement-tip", "Printeri väljuva töö funktsioon nõuab Windows 10 või uuemat."),
|
||||
("printer-requires-installed-{}-client-tip", "Kaugprintimise kasutamiseks tuleb sellesse seadmesse installida {}."),
|
||||
("printer-{}-not-installed-tip", "Printerit {} pole installitud."),
|
||||
("printer-{}-ready-tip", "Printer {} on installitud ja kasutusvalmis."),
|
||||
("Install {} Printer", "Installi printer {}"),
|
||||
("Outgoing Print Jobs", "Väljuvad prinditööd"),
|
||||
("Incoming Print Jobs", "Sissetulevad prinditööd"),
|
||||
("Incoming Print Job", "Sissetulev prinditöö"),
|
||||
("use-the-default-printer-tip", "Kasuta vaikeprinterit"),
|
||||
("use-the-selected-printer-tip", "Kasuta valitud printerit"),
|
||||
("auto-print-tip", "Prindi automaatselt valitud printeriga."),
|
||||
("print-incoming-job-confirm-tip", "Sa said kaugarvutist prinditöö. Kas soovid selle oma poolel teostada?"),
|
||||
("remote-printing-disallowed-tile-tip", "Kaugprintimine pole lubatud"),
|
||||
("remote-printing-disallowed-text-tip", "Juhitava poole õiguste seaded keelavad kaugprintimise."),
|
||||
("save-settings-tip", "Salvesta seaded"),
|
||||
("dont-show-again-tip", "Ära kuva seda uuesti"),
|
||||
("Take screenshot", "Tee kuvatõmmis"),
|
||||
("Taking screenshot", "Kuvatõmmise tegemine"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Mitme kuva kuvatõmmiste ühendamine pole praegu toetatud. Palun lülitu ühele kuvale ja proovi uuesti."),
|
||||
("screenshot-action-tip", "Palun vali, kuidas kuvatõmmisega jätkata."),
|
||||
("Save as", "Salvesta kui"),
|
||||
("Copy to clipboard", "Kopeeri lõikelauale"),
|
||||
("Enable remote printer", "Luba kaugprinter"),
|
||||
("Downloading {}", "Allalaadimine: {}"),
|
||||
("{} Update", "{} uuendus"),
|
||||
("{}-to-update-tip", "{} sulgub nüüd ja installib uue versiooni."),
|
||||
("download-new-version-failed-tip", "Allalaadimine ebaõnnestus. Võid proovida uuesti või klõpsata nuppu \"Laadi alla\", et laadida fail alla väljalaskelehelt ja uuendada käsitsi."),
|
||||
("Auto update", "Automaatne uuendamine"),
|
||||
("update-failed-check-msi-tip", "Installimismeetodi kontroll ebaõnnestus. Palun klõpsa nuppu \"Laadi alla\", et laadida fail alla väljalaskelehelt ja uuendada käsitsi."),
|
||||
("websocket_tip", "WebSocketi kasutamisel on toetatud ainult releeühendused."),
|
||||
("Use WebSocket", "Kasuta WebSocketit"),
|
||||
("Trackpad speed", "Puuteplaadi kiirus"),
|
||||
("Default trackpad speed", "Vaikimisi puuteplaadi kiirus"),
|
||||
("Numeric one-time password", "Numbriline ühekordne parool"),
|
||||
("Enable IPv6 P2P connection", "Luba IPv6 P2P-ühendus"),
|
||||
("Enable UDP hole punching", "Luba UDP-augustamine"),
|
||||
("View camera", "Vaata kaamerat"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Luba kaamera"),
|
||||
("No cameras", "Kaameraid pole"),
|
||||
("view_camera_unsupported_tip", "Kaugseade ei toeta kaamera vaatamist."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Luba terminal"),
|
||||
("New tab", "Uus kaart"),
|
||||
("Keep terminal sessions on disconnect", "Säilita terminaliseansid ühenduse katkemisel"),
|
||||
("Terminal (Run as administrator)", "Terminal (käivita administraatorina)"),
|
||||
("terminal-admin-login-tip", "Palun sisesta juhitava poole administraatori kasutajanimi ja parool."),
|
||||
("Failed to get user token.", "Kasutaja loa hankimine ebaõnnestus."),
|
||||
("Incorrect username or password.", "Vale kasutajanimi või parool."),
|
||||
("The user is not an administrator.", "Kasutaja ei ole administraator."),
|
||||
("Failed to check if the user is an administrator.", "Kasutaja administraatoriõiguste kontrollimine ebaõnnestus."),
|
||||
("Supported only in the installed version.", "Toetatud ainult installitud versioonis."),
|
||||
("elevation_username_tip", "Sisesta kasutajanimi või domeen\\kasutajanimi"),
|
||||
("Preparing for installation ...", "Installimiseks valmistumine ..."),
|
||||
("Show my cursor", "Näita minu kursorit"),
|
||||
("Scale custom", "Kohandatud mastaap"),
|
||||
("Custom scale slider", "Kohandatud mastaabi liugur"),
|
||||
("Decrease", "Vähenda"),
|
||||
("Increase", "Suurenda"),
|
||||
("Show virtual mouse", "Näita virtuaalset hiirt"),
|
||||
("Virtual mouse size", "Virtuaalse hiire suurus"),
|
||||
("Small", "Väike"),
|
||||
("Large", "Suur"),
|
||||
("Show virtual joystick", "Näita virtuaalset juhtkangi"),
|
||||
("Edit note", "Muuda märkust"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Luba ebaturvaline TLS-i tagavaravariant"),
|
||||
("allow-insecure-tls-fallback-tip", "Vaikimisi kontrollib RustDesk TLS-i kasutavate protokollide puhul serveri sertifikaati.\nKui see valik on lubatud, jätab RustDesk kontrollimissammu vahele ja jätkab kontrolli ebaõnnestumise korral."),
|
||||
("Disable UDP", "Keela UDP"),
|
||||
("disable-udp-tip", "Määrab, kas kasutada ainult TCP-d.\nKui see valik on lubatud, ei kasuta RustDesk enam UDP 21116, vaid kasutatakse selle asemel TCP 21116."),
|
||||
("server-oss-not-support-tip", "MÄRKUS: RustDeski serveri OSS ei sisalda seda funktsiooni."),
|
||||
("input note here", "sisesta märkus siia"),
|
||||
("note-at-conn-end-tip", "Küsi märkust ühenduse lõpus"),
|
||||
("Show terminal extra keys", "Näita terminali lisaklahve"),
|
||||
("Relative mouse mode", "Suhteline hiirerežiim"),
|
||||
("rel-mouse-not-supported-peer-tip", "Ühendatud partner ei toeta suhtelist hiirerežiimi."),
|
||||
("rel-mouse-not-ready-tip", "Suhteline hiirerežiim ei ole veel valmis. Palun proovi uuesti."),
|
||||
("rel-mouse-lock-failed-tip", "Kursori lukustamine ebaõnnestus. Suhteline hiirerežiim on keelatud."),
|
||||
("rel-mouse-exit-{}-tip", "Väljumiseks vajuta {}."),
|
||||
("rel-mouse-permission-lost-tip", "Klaviatuuriõigus võeti tagasi. Suhteline hiirerežiim on keelatud."),
|
||||
("Changelog", "Muudatuste logi"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Hoia ekraan ärkvel väljuvate seansside ajal"),
|
||||
("keep-awake-during-incoming-sessions-label", "Hoia ekraan ärkvel sissetulevate seansside ajal"),
|
||||
("Continue with {}", "Jätka koos {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Kuvatav nimi"),
|
||||
("password-hidden-tip", "Püsiparool on seatud (peidetud)."),
|
||||
("preset-password-in-use-tip", "Praegu on kasutusel eelseadistatud parool."),
|
||||
("Enable privacy mode", "Luba privaatsusrežiim"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Luba kaugjuhtimise tööriistariba dokkimine mis tahes akna servale"),
|
||||
("API Token", "API luba"),
|
||||
("Deploy", "Juuruta"),
|
||||
("Custom ID (optional)", "Kohandatud ID (valikuline)"),
|
||||
("server_requires_deployment_tip", "Server nõuab selle seadme selgesõnalist juurutamist. Kas juurutada kohe?"),
|
||||
("The server does not require explicit deployment.", "Server ei nõua selgesõnalist juurutamist."),
|
||||
("Unknown response.", "Tundmatu vastus."),
|
||||
("wayland-keyboard-input-disabled-tip", "Kas lubada klaviatuurisisestus?"),
|
||||
("wayland-keyboard-input-consent-tip", "Seda, mida sa sellesse kaugarvutisse sisestad (sealhulgas paroolid), võivad lugeda seal olevad teised rakendused."),
|
||||
("wayland-keyboard-input-applies-to-tip", "See valik kehtib järgmisele:"),
|
||||
("wayland-soft-keyboard-input-label", "Tarkvaralise klaviatuuri sisestus"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Lähtesta klaviatuurisisestuse valik"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ära küsi selle kaugarvuti puhul uuesti"),
|
||||
("Why this happens", "Miks see juhtub"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
253
src/lang/eu.rs
253
src/lang/eu.rs
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Grabatzen"),
|
||||
("Directory", "Direktorioa"),
|
||||
("Automatically record incoming sessions", "Automatikoki grabatu sarrerako saioak"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Grabatu automatikoki irteerako saioak"),
|
||||
("Change", "Aldatu"),
|
||||
("Start session recording", "Hasi saioaren grabaketa"),
|
||||
("Stop session recording", "Gelditu saioaren grabaketa"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Pantailaren partekatzea"),
|
||||
("ubuntu-21-04-required", "Wayland Ubuntu 21.04 edo bertsio berriagoa behar du."),
|
||||
("wayland-requires-higher-linux-version", "Wayland-ek linux banaketa berriago bat behar du. Saiatu X11 mahaigainarekin edo aldatu zure sistema eragilea."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland-eko pantaila-kapturak huts egin du. Baliteke XDG Desktop Portal kraskatu izana edo erabilgarri ez egotea. Saiatu berrabiarazten `systemctl --user restart xdg-desktop-portal` erabiliz."),
|
||||
("JumpLink", "Ikusi"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Mesedez, hautatu partekatuko den pantaila (Kudeatu parekidearen aldean)"),
|
||||
("Show RustDesk", "Erakutsi RustDesk"),
|
||||
@@ -623,125 +623,140 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Telegram bot", "Telegrameko bot-a"),
|
||||
("enable-bot-tip", "Ezaugarri hau gaitzen baduzu, zure bot-etik 2FA kodea jaso dezakezu. Konexio jakinarazpenetarako ere balio dezake."),
|
||||
("enable-bot-desc", "1, Ireki txat bat @BotFather bot-arekin.\n2, Bidali \"/newbot\" agindua. Token bat jasoko duzu urrats honen ostean.\n3, Hasi txat bat zure bot berriarekin. Bidali mezu bat aurreko barra batekin (\"/\") \"/kaixo\" bezala gaitzeko.\n"),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("cancel-2fa-confirm-tip", "Ziur 2FA bertan behera utzi nahi duzula?"),
|
||||
("cancel-bot-confirm-tip", "Ziur Telegram bota bertan behera utzi nahi duzula?"),
|
||||
("About RustDesk", "RustDesk-i buruz"),
|
||||
("Send clipboard keystrokes", "Bidali arbelaren tekla-sakatzeak"),
|
||||
("network_error_tip", "Egiaztatu zure sareko konexioa eta egin klik berriz saiatzeko."),
|
||||
("Unlock with PIN", "Desblokeatu PINarekin"),
|
||||
("Requires at least {} characters", "Gutxienez {} karaktere behar ditu"),
|
||||
("Wrong PIN", "PIN okerra"),
|
||||
("Set PIN", "Ezarri PINa"),
|
||||
("Enable trusted devices", "Gaitu gailu fidagarriak"),
|
||||
("Manage trusted devices", "Kudeatu gailu fidagarriak"),
|
||||
("Platform", "Plataforma"),
|
||||
("Days remaining", "Geratzen diren egunak"),
|
||||
("enable-trusted-devices-tip", "Saltatu 2FA egiaztapena gailu fidagarrietan"),
|
||||
("Parent directory", "Direktorio gurasoa"),
|
||||
("Resume", "Berrekin"),
|
||||
("Invalid file name", "Fitxategi-izen baliogabea"),
|
||||
("one-way-file-transfer-tip", "Norabide bakarreko fitxategi-transferentzia gaituta dago kontrolatutako aldean."),
|
||||
("Authentication Required", "Autentifikazioa beharrezkoa da"),
|
||||
("Authenticate", "Autentifikatu"),
|
||||
("web_id_input_tip", "Zerbitzari berean dagoen ID bat sar dezakezu; IP bidezko sarbide zuzena ez da onartzen web-bezeroan.\nBeste zerbitzari batean dagoen gailu batera sartu nahi baduzu, erantsi zerbitzariaren helbidea (<id>@<server_address>?key=<key_value>), adibidez,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nZerbitzari publiko batean dagoen gailu batera sartu nahi baduzu, sartu \"<id>@public\"; gakoa ez da beharrezkoa zerbitzari publikoarentzat."),
|
||||
("Download", "Deskargatu"),
|
||||
("Upload folder", "Igo karpeta"),
|
||||
("Upload files", "Igo fitxategiak"),
|
||||
("Clipboard is synchronized", "Arbela sinkronizatuta dago"),
|
||||
("Update client clipboard", "Eguneratu bezeroaren arbela"),
|
||||
("Untagged", "Etiketarik gabe"),
|
||||
("new-version-of-{}-tip", "{}(r)en bertsio berri bat dago eskuragarri"),
|
||||
("Accessible devices", "Gailu eskuragarriak"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Mesedez, eguneratu RustDesk bezeroa {} bertsiora edo berriagoa urruneko aldean!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "D3D errendatzea gaituta dagoenean, baliteke urruneko kontroleko pantaila beltza agertzea makina batzuetan."),
|
||||
("Use D3D rendering", "Erabili D3D errendatzea"),
|
||||
("Printer", "Inprimagailua"),
|
||||
("printer-os-requirement-tip", "Inprimagailuaren irteerako funtzioak Windows 10 edo berriagoa behar du."),
|
||||
("printer-requires-installed-{}-client-tip", "Urruneko inprimatzea erabiltzeko, {} gailu honetan instalatu behar da."),
|
||||
("printer-{}-not-installed-tip", "{} inprimagailua ez dago instalatuta."),
|
||||
("printer-{}-ready-tip", "{} inprimagailua instalatuta eta erabiltzeko prest dago."),
|
||||
("Install {} Printer", "Instalatu {} inprimagailua"),
|
||||
("Outgoing Print Jobs", "Irteerako inprimatze-lanak"),
|
||||
("Incoming Print Jobs", "Sarrerako inprimatze-lanak"),
|
||||
("Incoming Print Job", "Sarrerako inprimatze-lana"),
|
||||
("use-the-default-printer-tip", "Erabili inprimagailu lehenetsia"),
|
||||
("use-the-selected-printer-tip", "Erabili hautatutako inprimagailua"),
|
||||
("auto-print-tip", "Inprimatu automatikoki hautatutako inprimagailua erabiliz."),
|
||||
("print-incoming-job-confirm-tip", "Urrunetik inprimatze-lan bat jaso duzu. Zure aldean exekutatu nahi duzu?"),
|
||||
("remote-printing-disallowed-tile-tip", "Urruneko inprimatzea debekatuta"),
|
||||
("remote-printing-disallowed-text-tip", "Kontrolatutako aldearen baimen-ezarpenek urruneko inprimatzea ukatzen dute."),
|
||||
("save-settings-tip", "Gorde ezarpenak"),
|
||||
("dont-show-again-tip", "Ez erakutsi hau berriro"),
|
||||
("Take screenshot", "Atera pantaila-argazkia"),
|
||||
("Taking screenshot", "Pantaila-argazkia ateratzen"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Pantaila anitzen pantaila-argazkiak bateratzea ez da onartzen une honetan. Aldatu pantaila bakarrera eta saiatu berriro."),
|
||||
("screenshot-action-tip", "Hautatu pantaila-argazkiarekin nola jarraitu."),
|
||||
("Save as", "Gorde honela"),
|
||||
("Copy to clipboard", "Kopiatu arbelera"),
|
||||
("Enable remote printer", "Gaitu urruneko inprimagailua"),
|
||||
("Downloading {}", "{} deskargatzen"),
|
||||
("{} Update", "{} eguneratzea"),
|
||||
("{}-to-update-tip", "{} orain itxiko da eta bertsio berria instalatuko du."),
|
||||
("download-new-version-failed-tip", "Deskargak huts egin du. Berriro saia zaitezke edo egin klik \"Deskargatu\" botoian argitalpen-orritik deskargatu eta eskuz eguneratzeko."),
|
||||
("Auto update", "Eguneratze automatikoa"),
|
||||
("update-failed-check-msi-tip", "Instalazio-metodoaren egiaztapenak huts egin du. Egin klik \"Deskargatu\" botoian argitalpen-orritik deskargatu eta eskuz eguneratzeko."),
|
||||
("websocket_tip", "WebSocket erabiltzean, errele-konexioak soilik onartzen dira."),
|
||||
("Use WebSocket", "Erabili WebSocket"),
|
||||
("Trackpad speed", "Trackpad-aren abiadura"),
|
||||
("Default trackpad speed", "Trackpad-aren abiadura lehenetsia"),
|
||||
("Numeric one-time password", "Behin-behineko pasahitz numerikoa"),
|
||||
("Enable IPv6 P2P connection", "Gaitu IPv6 P2P konexioa"),
|
||||
("Enable UDP hole punching", "Gaitu UDP zulo-egitea"),
|
||||
("View camera", "Ikusi kamera"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Gaitu kamera"),
|
||||
("No cameras", "Kamerarik ez"),
|
||||
("view_camera_unsupported_tip", "Urruneko gailuak ez du kamera ikustea onartzen."),
|
||||
("Terminal", "Terminala"),
|
||||
("Enable terminal", "Gaitu terminala"),
|
||||
("New tab", "Fitxa berria"),
|
||||
("Keep terminal sessions on disconnect", "Mantendu terminaleko saioak deskonektatzean"),
|
||||
("Terminal (Run as administrator)", "Terminala (Exekutatu administratzaile gisa)"),
|
||||
("terminal-admin-login-tip", "Sartu kontrolatutako aldearen administratzailearen erabiltzaile-izena eta pasahitza."),
|
||||
("Failed to get user token.", "Ezin izan da erabiltzailearen tokena lortu."),
|
||||
("Incorrect username or password.", "Erabiltzaile-izen edo pasahitz okerra."),
|
||||
("The user is not an administrator.", "Erabiltzailea ez da administratzailea."),
|
||||
("Failed to check if the user is an administrator.", "Ezin izan da egiaztatu erabiltzailea administratzailea den."),
|
||||
("Supported only in the installed version.", "Instalatutako bertsioan soilik onartzen da."),
|
||||
("elevation_username_tip", "Sartu erabiltzaile-izena edo domeinua\\erabiltzaile-izena"),
|
||||
("Preparing for installation ...", "Instalaziorako prestatzen ..."),
|
||||
("Show my cursor", "Erakutsi nire kurtsorea"),
|
||||
("Scale custom", "Eskala pertsonalizatua"),
|
||||
("Custom scale slider", "Eskala pertsonalizatuaren graduatzailea"),
|
||||
("Decrease", "Txikiagotu"),
|
||||
("Increase", "Handiagotu"),
|
||||
("Show virtual mouse", "Erakutsi sagu birtuala"),
|
||||
("Virtual mouse size", "Sagu birtualaren tamaina"),
|
||||
("Small", "Txikia"),
|
||||
("Large", "Handia"),
|
||||
("Show virtual joystick", "Erakutsi joystick birtuala"),
|
||||
("Edit note", "Editatu nota"),
|
||||
("Alias", "Aliasa"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Onartu TLS ordezko ez-segurua"),
|
||||
("allow-insecure-tls-fallback-tip", "Modu lehenetsian, RustDesk-ek zerbitzariaren ziurtagiria egiaztatzen du TLS erabiltzen duten protokoloetarako.\nAukera hau gaituta dagoela, RustDesk-ek egiaztapen-urratsa saltatzera joko du eta aurrera egingo du egiaztapenak huts eginez gero."),
|
||||
("Disable UDP", "Desgaitu UDP"),
|
||||
("disable-udp-tip", "TCP soilik erabiliko den kontrolatzen du.\nAukera hau gaituta dagoenean, RustDesk-ek ez du gehiago UDP 21116 erabiliko; horren ordez, TCP 21116 erabiliko da."),
|
||||
("server-oss-not-support-tip", "OHARRA: RustDesk zerbitzariaren OSS bertsioak ez du ezaugarri hau barne hartzen."),
|
||||
("input note here", "sartu nota hemen"),
|
||||
("note-at-conn-end-tip", "Eskatu nota konexioaren amaieran"),
|
||||
("Show terminal extra keys", "Erakutsi terminaleko tekla gehigarriak"),
|
||||
("Relative mouse mode", "Sagu erlatiboaren modua"),
|
||||
("rel-mouse-not-supported-peer-tip", "Konektatutako parekideak ez du sagu erlatiboaren modua onartzen."),
|
||||
("rel-mouse-not-ready-tip", "Sagu erlatiboaren modua ez dago oraindik prest. Saiatu berriro."),
|
||||
("rel-mouse-lock-failed-tip", "Ezin izan da kurtsorea blokeatu. Sagu erlatiboaren modua desgaitu egin da."),
|
||||
("rel-mouse-exit-{}-tip", "Sakatu {} irteteko."),
|
||||
("rel-mouse-permission-lost-tip", "Teklatuaren baimena baliogabetu da. Sagu erlatiboaren modua desgaitu egin da."),
|
||||
("Changelog", "Aldaketen erregistroa"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Mantendu pantaila piztuta irteerako saioetan"),
|
||||
("keep-awake-during-incoming-sessions-label", "Mantendu pantaila piztuta sarrerako saioetan"),
|
||||
("Continue with {}", "{} honekin jarraitu"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Bistaratze-izena"),
|
||||
("password-hidden-tip", "Betiko pasahitza ezarrita dago (ezkutua)."),
|
||||
("preset-password-in-use-tip", "Aurrez ezarritako pasahitza erabiltzen ari da une honetan."),
|
||||
("Enable privacy mode", "Gaitu pribatutasun modua"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Onartu urruneko tresna-barra leihoaren edozein ertzetan atrakatzea"),
|
||||
("API Token", "API tokena"),
|
||||
("Deploy", "Hedatu"),
|
||||
("Custom ID (optional)", "ID pertsonalizatua (aukerakoa)"),
|
||||
("server_requires_deployment_tip", "Zerbitzariak gailu hau esplizituki hedatzea eskatzen du. Hedatu orain?"),
|
||||
("The server does not require explicit deployment.", "Zerbitzariak ez du hedapen esplizitua eskatzen."),
|
||||
("Unknown response.", "Erantzun ezezaguna."),
|
||||
("wayland-keyboard-input-disabled-tip", "Onartu teklatuko sarrera?"),
|
||||
("wayland-keyboard-input-consent-tip", "Urruneko ordenagailu honetan idazten duzuna (pasahitzak barne) bertako beste aplikazio batzuek irakur dezakete."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Aukera hau honi aplikatzen zaio:"),
|
||||
("wayland-soft-keyboard-input-label", "Teklatu birtualaren sarrera"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Berrezarri teklatuko sarreraren aukera"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ez galdetu berriro urruneko ordenagailu honetarako"),
|
||||
("Why this happens", "Zergatik gertatzen den hau"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "اشتراک گذاری صفحه"),
|
||||
("ubuntu-21-04-required", "نیازمند اوبونتو نسخه 21.04 یا بالاتر است Wayland"),
|
||||
("wayland-requires-higher-linux-version", "استفاده کنید و یا سیستم عامل خود را تغییر دهید X11 نیازمند نسخه بالاتری از توزیع لینوکس است. لطفا از دسکتاپ با سیستم"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "ضبط صفحه Wayland ناموفق بود. ممکن است XDG Desktop Portal از کار افتاده یا در دسترس نباشد. با اجرای دستور `systemctl --user restart xdg-desktop-portal` آن را مجدداً راهاندازی کنید."),
|
||||
("JumpLink", "چشم انداز"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "لطفاً صفحهای را برای اشتراکگذاری انتخاب کنید (در سمت همتا به همتا کار کنید)."),
|
||||
("Show RustDesk", "RustDesk نمایش"),
|
||||
@@ -721,7 +721,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Show virtual joystick", "نمایش جویاستیک مجازی"),
|
||||
("Edit note", "ویرایش یادداشت"),
|
||||
("Alias", "نام مستعار"),
|
||||
("ScrollEdge", ""),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "استفاده از TLS غیر امن در ارتباط"),
|
||||
("allow-insecure-tls-fallback-tip", "بهطور پیشفرض، RustDesk گواهی سرور را برای پروتکلها با استفاده از TLS تأیید میکند.\nبا فعال بودن این گزینه، RustDesk دوباره مرحله تأیید را رد میکند و در صورت عدم موفقیت تأیید ادامه میدهد."),
|
||||
("Disable UDP", "UDP غیر فعال کردن"),
|
||||
@@ -729,19 +729,34 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server-oss-not-support-tip", "توجه: سرور RustDesk OSS این ویژگی را ندارد."),
|
||||
("input note here", "یادداشت را اینجا وارد کنید"),
|
||||
("note-at-conn-end-tip", "در پایان اتصال، یادداشت بخواهید"),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Show terminal extra keys", "نمایش کلیدهای اضافی ترمینال"),
|
||||
("Relative mouse mode", "حالت ماوس نسبی"),
|
||||
("rel-mouse-not-supported-peer-tip", "حالت ماوس نسبی توسط همتای متصلشده پشتیبانی نمیشود."),
|
||||
("rel-mouse-not-ready-tip", "حالت ماوس نسبی هنوز آماده نیست. لطفاً دوباره تلاش کنید."),
|
||||
("rel-mouse-lock-failed-tip", "قفل کردن نشانگر ناموفق بود. حالت ماوس نسبی غیرفعال شد."),
|
||||
("rel-mouse-exit-{}-tip", "برای خروج {} را فشار دهید."),
|
||||
("rel-mouse-permission-lost-tip", "مجوز صفحه کلید لغو شد. حالت ماوس نسبی غیرفعال شد."),
|
||||
("Changelog", "تغییرات نسخه"),
|
||||
("keep-awake-during-outgoing-sessions-label", "نگه داشتن صفحه در حالت بیدار در طول جلسات خروجی"),
|
||||
("keep-awake-during-incoming-sessions-label", "نگه داشتن صفحه در حالت بیدار در طول جلسات ورودی"),
|
||||
("Continue with {}", "ادامه با {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "نام نمایشی"),
|
||||
("password-hidden-tip", "رمز عبور دائمی تنظیم شده است (پنهان)."),
|
||||
("preset-password-in-use-tip", "رمز عبور از پیش تعیینشده در حال حاضر در حال استفاده است."),
|
||||
("Enable privacy mode", "فعالسازی حالت حریم خصوصی"),
|
||||
("allow-remote-toolbar-docking-any-edge", "اجازه اتصال نوار ابزار از راه دور به هر لبه پنجره"),
|
||||
("API Token", "توکن API"),
|
||||
("Deploy", "استقرار"),
|
||||
("Custom ID (optional)", "شناسه سفارشی (اختیاری)"),
|
||||
("server_requires_deployment_tip", "سرور نیاز دارد که این دستگاه بهطور صریح مستقر شود. اکنون مستقر شود؟"),
|
||||
("The server does not require explicit deployment.", "سرور به استقرار صریح نیاز ندارد."),
|
||||
("Unknown response.", "پاسخ ناشناخته."),
|
||||
("wayland-keyboard-input-disabled-tip", "اجازه ورودی صفحه کلید داده شود؟"),
|
||||
("wayland-keyboard-input-consent-tip", "آنچه روی این رایانه از راه دور تایپ میکنید (از جمله رمزهای عبور) ممکن است توسط سایر برنامههای روی آن خوانده شود."),
|
||||
("wayland-keyboard-input-applies-to-tip", "این انتخاب برای موارد زیر اعمال میشود:"),
|
||||
("wayland-soft-keyboard-input-label", "ورودی صفحه کلید نرمافزاری"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "بازنشانی انتخاب ورودی صفحه کلید"),
|
||||
("remember-wayland-keyboard-choice-tip", "برای این رایانه از راه دور دوباره نپرس"),
|
||||
("Why this happens", "چرا این اتفاق میافتد"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Näytönjako"),
|
||||
("ubuntu-21-04-required", "Wayland vaatii Ubuntu 21.04:n tai uudemman version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vaatii uudemman Linux jakelun version. Kokeile X11 työpöytää tai vaihda käyttöjärjestelmää."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Waylandin näytön kaappaus epäonnistui. XDG Desktop Portal on saattanut kaatua tai ei ole käytettävissä. Yritä käynnistää se uudelleen komennolla `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Pikalinkki"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Valitse jaettava näyttö (toiminto etäpäässä)."),
|
||||
("Show RustDesk", "Näytä RustDesk"),
|
||||
@@ -721,27 +721,42 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Show virtual joystick", "Näytä virtuaalinen ohjain"),
|
||||
("Edit note", "Muokkaa muistiinpanoa"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Salli turvaton TLS-varajärjestely"),
|
||||
("allow-insecure-tls-fallback-tip", "Oletuksena RustDesk vahvistaa palvelimen varmenteen TLS:ää käyttävissä protokollissa.\nKun tämä asetus on käytössä, RustDesk ohittaa vahvistusvaiheen ja jatkaa toimintaa, jos vahvistus epäonnistuu."),
|
||||
("Disable UDP", "Poista UDP käytöstä"),
|
||||
("disable-udp-tip", "Määrittää, käytetäänkö vain TCP:tä.\nKun tämä asetus on käytössä, RustDesk ei enää käytä UDP-porttia 21116, vaan sen sijaan käytetään TCP-porttia 21116."),
|
||||
("server-oss-not-support-tip", "HUOMAUTUS: RustDesk-palvelimen OSS ei sisällä tätä ominaisuutta."),
|
||||
("input note here", "syötä muistiinpano tähän"),
|
||||
("note-at-conn-end-tip", "Kysy muistiinpanoa yhteyden päättyessä"),
|
||||
("Show terminal extra keys", "Näytä päätteen lisänäppäimet"),
|
||||
("Relative mouse mode", "Suhteellinen hiiritila"),
|
||||
("rel-mouse-not-supported-peer-tip", "Yhdistetty etäpää ei tue suhteellista hiiritilaa."),
|
||||
("rel-mouse-not-ready-tip", "Suhteellinen hiiritila ei ole vielä valmis. Yritä uudelleen."),
|
||||
("rel-mouse-lock-failed-tip", "Kursorin lukitseminen epäonnistui. Suhteellinen hiiritila on poistettu käytöstä."),
|
||||
("rel-mouse-exit-{}-tip", "Poistu painamalla {}."),
|
||||
("rel-mouse-permission-lost-tip", "Näppäimistöoikeus peruutettiin. Suhteellinen hiiritila on poistettu käytöstä."),
|
||||
("Changelog", "Muutosloki"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Pidä näyttö hereillä lähtevien istuntojen aikana"),
|
||||
("keep-awake-during-incoming-sessions-label", "Pidä näyttö hereillä saapuvien istuntojen aikana"),
|
||||
("Continue with {}", "Jatka käyttäen {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Näyttönimi"),
|
||||
("password-hidden-tip", "Pysyvä salasana on asetettu (piilotettu)."),
|
||||
("preset-password-in-use-tip", "Esiasetettu salasana on parhaillaan käytössä."),
|
||||
("Enable privacy mode", "Ota yksityisyystila käyttöön"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Salli etätyökalupalkin kiinnittäminen mihin tahansa ikkunan reunaan"),
|
||||
("API Token", "API-tunnus"),
|
||||
("Deploy", "Ota käyttöön"),
|
||||
("Custom ID (optional)", "Mukautettu tunnus (valinnainen)"),
|
||||
("server_requires_deployment_tip", "Palvelin edellyttää, että tämä laite otetaan käyttöön nimenomaisesti. Otetaanko käyttöön nyt?"),
|
||||
("The server does not require explicit deployment.", "Palvelin ei edellytä nimenomaista käyttöönottoa."),
|
||||
("Unknown response.", "Tuntematon vastaus."),
|
||||
("wayland-keyboard-input-disabled-tip", "Sallitaanko näppäimistösyöte?"),
|
||||
("wayland-keyboard-input-consent-tip", "Muut tämän etätietokoneen sovellukset voivat lukea sen, mitä kirjoitat (myös salasanat)."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Tämä valinta koskee:"),
|
||||
("wayland-soft-keyboard-input-label", "Virtuaalinäppäimistön syöte"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Nollaa näppäimistösyötteen valinta"),
|
||||
("remember-wayland-keyboard-choice-tip", "Älä kysy uudelleen tältä etätietokoneelta"),
|
||||
("Why this happens", "Miksi näin tapahtuu"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "Nom d’affichage"),
|
||||
("password-hidden-tip", "Le mot de passe permanent est défini (masqué)."),
|
||||
("preset-password-in-use-tip", "Le mot de passe prédéfini est actuellement utilisé."),
|
||||
("Enable privacy mode", "Activer le mode de confidentialité"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Autoriser l’ancrage de la barre d’outils à distance sur n’importe quel bord de la fenêtre"),
|
||||
("API Token", "Jeton API"),
|
||||
("Deploy", "Déployer"),
|
||||
("Custom ID (optional)", "ID personnalisé (facultatif)"),
|
||||
("server_requires_deployment_tip", "Le serveur requiert que cet appareil soit déployé explicitement. Déployer maintenant ?"),
|
||||
("The server does not require explicit deployment.", "Le serveur ne requiert pas de déploiement explicite."),
|
||||
("Unknown response.", "Réponse inconnue."),
|
||||
("wayland-keyboard-input-disabled-tip", "Autoriser la saisie au clavier ?"),
|
||||
("wayland-keyboard-input-consent-tip", "Les saisies sur cet appareil distant (mots de passe y compris) pourraient être lues par d’autres applications."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Ce choix s’applique à :"),
|
||||
("wayland-soft-keyboard-input-label", "Saisie au clavier virtuel"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Réinitialiser le choix de la saisie au clavier"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ne plus demander pour cet appareil distant"),
|
||||
("Why this happens", "Pourquoi cela se produit"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
151
src/lang/ge.rs
151
src/lang/ge.rs
@@ -237,7 +237,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Empty", "ცარიელი"),
|
||||
("Invalid folder name", "არასწორი საქაღალდის სახელი"),
|
||||
("Socks5 Proxy", "SOCKS5-პროქსი"),
|
||||
("Socks5/Http(s) Proxy", ""),
|
||||
("Socks5/Http(s) Proxy", "Socks5/Http(s) პროქსი"),
|
||||
("Discovered", "ნაპოვნია"),
|
||||
("install_daemon_tip", "ჩატვირთვისას გასაშვებად საჭიროა სისტემური სერვისის დაყენება"),
|
||||
("Remote ID", "დაშორებული ID"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "ეკრანის გაზიარება"),
|
||||
("ubuntu-21-04-required", "Wayland საჭიროებს Ubuntu 21.04 ან უფრო ახალ ვერსიას."),
|
||||
("wayland-requires-higher-linux-version", "Wayland-ს სჭირდება Linux-ის დისტრიბუტივის უფრო ახალი ვერსია. გამოიყენეთ X11 სამუშაო მაგიდა ან შეცვალეთ ოპერაციული სისტემა."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland-ის ეკრანის ჩაწერა ვერ მოხერხდა. XDG Desktop Portal შესაძლოა ავარიულად დასრულდა ან მიუწვდომელია. სცადეთ მისი გადატვირთვა ბრძანებით `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "ნახვა"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "აირჩიეთ ეკრანი გასაზიარებლად (იმუშავეთ პარტნიორის მხარეს)."),
|
||||
("Show RustDesk", "RustDesk-ის ჩვენება"),
|
||||
@@ -672,76 +672,91 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("remote-printing-disallowed-text-tip", "მართულ მხარეზე უფლებების პარამეტრები კრძალავს დისტანციურ ბეჭდვას."),
|
||||
("save-settings-tip", "პარამეტრების შენახვა"),
|
||||
("dont-show-again-tip", "აღარ აჩვენოთ"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("Take screenshot", "ეკრანის სურათის გადაღება"),
|
||||
("Taking screenshot", "მიმდინარეობს ეკრანის სურათის გადაღება"),
|
||||
("screenshot-merged-screen-not-supported-tip", "რამდენიმე ეკრანის სურათის გაერთიანება ამჟამად მხარდაჭერილი არ არის. გადართეთ ერთ ეკრანზე და სცადეთ ხელახლა."),
|
||||
("screenshot-action-tip", "აირჩიეთ, როგორ გავაგრძელოთ ეკრანის სურათთან მუშაობა."),
|
||||
("Save as", "შენახვა როგორც"),
|
||||
("Copy to clipboard", "ბუფერში კოპირება"),
|
||||
("Enable remote printer", "დისტანციური პრინტერის ჩართვა"),
|
||||
("Downloading {}", "მიმდინარეობს {}-ის ჩამოტვირთვა"),
|
||||
("{} Update", "{}-ის განახლება"),
|
||||
("{}-to-update-tip", "{} ახლა დაიხურება და დააინსტალირებს ახალ ვერსიას."),
|
||||
("download-new-version-failed-tip", "ჩამოტვირთვა ვერ მოხერხდა. შეგიძლიათ სცადოთ ხელახლა ან დააწკაპუნოთ ღილაკზე \"ჩამოტვირთვა\", რათა ჩამოტვირთოთ გამოშვების გვერდიდან და განაახლოთ ხელით."),
|
||||
("Auto update", "ავტომატური განახლება"),
|
||||
("update-failed-check-msi-tip", "ინსტალაციის მეთოდის შემოწმება ვერ მოხერხდა. დააწკაპუნეთ ღილაკზე \"ჩამოტვირთვა\", რათა ჩამოტვირთოთ გამოშვების გვერდიდან და განაახლოთ ხელით."),
|
||||
("websocket_tip", "WebSocket-ის გამოყენებისას მხარდაჭერილია მხოლოდ რელეური კავშირები."),
|
||||
("Use WebSocket", "WebSocket-ის გამოყენება"),
|
||||
("Trackpad speed", "ტაჩპადის სიჩქარე"),
|
||||
("Default trackpad speed", "ტაჩპადის ნაგულისხმევი სიჩქარე"),
|
||||
("Numeric one-time password", "ციფრული ერთჯერადი პაროლი"),
|
||||
("Enable IPv6 P2P connection", "IPv6 P2P კავშირის ჩართვა"),
|
||||
("Enable UDP hole punching", "UDP hole punching-ის ჩართვა"),
|
||||
("View camera", "კამერის ნახვა"),
|
||||
("Enable camera", "კამერის ჩართვა"),
|
||||
("No cameras", "კამერა არ არის"),
|
||||
("view_camera_unsupported_tip", "დისტანციური მოწყობილობა არ უჭერს მხარს კამერის ნახვას."),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Terminal", "ტერმინალი"),
|
||||
("Enable terminal", "ტერმინალის ჩართვა"),
|
||||
("New tab", "ახალი ჩანართი"),
|
||||
("Keep terminal sessions on disconnect", "ტერმინალის სესიების შენარჩუნება კავშირის გაწყვეტისას"),
|
||||
("Terminal (Run as administrator)", "ტერმინალი (ადმინისტრატორის სახელით გაშვება)"),
|
||||
("terminal-admin-login-tip", "შეიყვანეთ მართვადი მხარის ადმინისტრატორის მომხმარებლის სახელი და პაროლი."),
|
||||
("Failed to get user token.", "მომხმარებლის ტოკენის მიღება ვერ მოხერხდა."),
|
||||
("Incorrect username or password.", "არასწორი მომხმარებლის სახელი ან პაროლი."),
|
||||
("The user is not an administrator.", "მომხმარებელი არ არის ადმინისტრატორი."),
|
||||
("Failed to check if the user is an administrator.", "მომხმარებლის ადმინისტრატორობის შემოწმება ვერ მოხერხდა."),
|
||||
("Supported only in the installed version.", "მხარდაჭერილია მხოლოდ დაინსტალირებულ ვერსიაში."),
|
||||
("elevation_username_tip", "შეიყვანეთ მომხმარებლის სახელი ან domain\\username"),
|
||||
("Preparing for installation ...", "მიმდინარეობს ინსტალაციისთვის მომზადება ..."),
|
||||
("Show my cursor", "ჩემი კურსორის ჩვენება"),
|
||||
("Scale custom", "მორგებული მასშტაბი"),
|
||||
("Custom scale slider", "მორგებული მასშტაბის სლაიდერი"),
|
||||
("Decrease", "შემცირება"),
|
||||
("Increase", "გაზრდა"),
|
||||
("Show virtual mouse", "ვირტუალური მაუსის ჩვენება"),
|
||||
("Virtual mouse size", "ვირტუალური მაუსის ზომა"),
|
||||
("Small", "პატარა"),
|
||||
("Large", "დიდი"),
|
||||
("Show virtual joystick", "ვირტუალური ჯოისტიკის ჩვენება"),
|
||||
("Edit note", "შენიშვნის რედაქტირება"),
|
||||
("Alias", "ფსევდონიმი"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "დაუცველ TLS-ზე გადასვლის დაშვება"),
|
||||
("allow-insecure-tls-fallback-tip", "ნაგულისხმევად RustDesk ამოწმებს სერვერის სერტიფიკატს TLS-ის გამოყენებისას პროტოკოლებისთვის.\nამ პარამეტრის ჩართვისას RustDesk გადავა შემოწმების ეტაპის გამოტოვებაზე და გააგრძელებს მუშაობას შემოწმების წარუმატებლობის შემთხვევაში."),
|
||||
("Disable UDP", "UDP-ის გამორთვა"),
|
||||
("disable-udp-tip", "აკონტროლებს, გამოვიყენოთ თუ არა მხოლოდ TCP.\nამ პარამეტრის ჩართვისას RustDesk აღარ გამოიყენებს UDP 21116-ს, სანაცვლოდ გამოყენებული იქნება TCP 21116."),
|
||||
("server-oss-not-support-tip", "შენიშვნა: RustDesk server OSS არ მოიცავს ამ ფუნქციას."),
|
||||
("input note here", "შეიყვანეთ შენიშვნა აქ"),
|
||||
("note-at-conn-end-tip", "შენიშვნის მოთხოვნა კავშირის დასასრულს"),
|
||||
("Show terminal extra keys", "ტერმინალის დამატებითი ღილაკების ჩვენება"),
|
||||
("Relative mouse mode", "ფარდობითი მაუსის რეჟიმი"),
|
||||
("rel-mouse-not-supported-peer-tip", "ფარდობითი მაუსის რეჟიმი მხარდაჭერილი არ არის დაკავშირებული მხარის მიერ."),
|
||||
("rel-mouse-not-ready-tip", "ფარდობითი მაუსის რეჟიმი ჯერ მზად არ არის. სცადეთ ხელახლა."),
|
||||
("rel-mouse-lock-failed-tip", "კურსორის ჩაკეტვა ვერ მოხერხდა. ფარდობითი მაუსის რეჟიმი გამორთულია."),
|
||||
("rel-mouse-exit-{}-tip", "გასასვლელად დააჭირეთ {}."),
|
||||
("rel-mouse-permission-lost-tip", "კლავიატურის ნებართვა გაუქმდა. ფარდობითი მაუსის რეჟიმი გამორთულია."),
|
||||
("Changelog", "ცვლილებების ჟურნალი"),
|
||||
("keep-awake-during-outgoing-sessions-label", "ეკრანის ღვიძილის რეჟიმში შენარჩუნება გამავალი სესიების დროს"),
|
||||
("keep-awake-during-incoming-sessions-label", "ეკრანის ღვიძილის რეჟიმში შენარჩუნება შემომავალი სესიების დროს"),
|
||||
("Continue with {}", "{}-ით გაგრძელება"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "საჩვენებელი სახელი"),
|
||||
("password-hidden-tip", "მუდმივი პაროლი დაყენებულია (დამალული)."),
|
||||
("preset-password-in-use-tip", "ამჟამად გამოიყენება წინასწარ დაყენებული პაროლი."),
|
||||
("Enable privacy mode", "კონფიდენციალურობის რეჟიმის ჩართვა"),
|
||||
("allow-remote-toolbar-docking-any-edge", "დისტანციური ხელსაწყოთა პანელის მიმაგრების დაშვება ფანჯრის ნებისმიერ კიდეზე"),
|
||||
("API Token", "API ტოკენი"),
|
||||
("Deploy", "გაშლა"),
|
||||
("Custom ID (optional)", "მორგებული ID (არასავალდებულო)"),
|
||||
("server_requires_deployment_tip", "სერვერი მოითხოვს ამ მოწყობილობის ცალსახად გაშლას. გავშალოთ ახლა?"),
|
||||
("The server does not require explicit deployment.", "სერვერი არ მოითხოვს ცალსახა გაშლას."),
|
||||
("Unknown response.", "უცნობი პასუხი."),
|
||||
("wayland-keyboard-input-disabled-tip", "დავუშვათ კლავიატურის შეყვანა?"),
|
||||
("wayland-keyboard-input-consent-tip", "ის, რასაც ამ დისტანციურ კომპიუტერზე აკრებთ (პაროლების ჩათვლით), შესაძლოა წაიკითხონ მასზე არსებულმა სხვა აპლიკაციებმა."),
|
||||
("wayland-keyboard-input-applies-to-tip", "ეს არჩევანი ვრცელდება:"),
|
||||
("wayland-soft-keyboard-input-label", "პროგრამული კლავიატურის შეყვანა"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "კლავიატურის შეყვანის არჩევანის ჩამოყრა"),
|
||||
("remember-wayland-keyboard-choice-tip", "აღარ მკითხო ამ დისტანციური კომპიუტერისთვის"),
|
||||
("Why this happens", "რატომ ხდება ეს"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -654,6 +654,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Accessible devices", "એક્સેસિબલ ઉપકરણો"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "રિમોટ ક્લાયન્ટને {} માં અપગ્રેડ કરો"),
|
||||
("d3d_render_tip", "D3D રેન્ડરિંગ વાપરો"),
|
||||
("Use D3D rendering", "D3D રેન્ડરિંગનો ઉપયોગ કરો"),
|
||||
("Printer", "પ્રિન્ટર"),
|
||||
("printer-os-requirement-tip", "પ્રિન્ટિંગ માટે Windows જરૂરી છે."),
|
||||
("printer-requires-installed-{}-client-tip", "આ માટે {} ક્લાયન્ટ ઇન્સ્ટોલ હોવું જોઈએ."),
|
||||
@@ -742,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "ડિસ્પ્લે નામ"),
|
||||
("password-hidden-tip", "સુરક્ષા માટે પાસવર્ડ છુપાવેલ છે."),
|
||||
("preset-password-in-use-tip", "પ્રીસેટ પાસવર્ડ વપરાશમાં છે."),
|
||||
("Enable privacy mode", "પ્રાઇવસી મોડ સક્ષમ કરો"),
|
||||
("allow-remote-toolbar-docking-any-edge", "રિમોટ ટૂલબારને કોઈપણ વિન્ડો કિનારી પર ડોક કરવાની મંજૂરી આપો"),
|
||||
("API Token", "API ટોકન"),
|
||||
("Deploy", "ડિપ્લોય કરો"),
|
||||
("Custom ID (optional)", "કસ્ટમ ID (વૈકલ્પિક)"),
|
||||
("server_requires_deployment_tip", "સર્વરને આ ઉપકરણ સ્પષ્ટપણે ડિપ્લોય કરવાની જરૂર છે. હવે ડિપ્લોય કરવું છે?"),
|
||||
("The server does not require explicit deployment.", "સર્વરને સ્પષ્ટ ડિપ્લોયમેન્ટની જરૂર નથી."),
|
||||
("Unknown response.", "અજાણ્યો પ્રતિસાદ."),
|
||||
("wayland-keyboard-input-disabled-tip", "કીબોર્ડ ઇનપુટની મંજૂરી આપવી છે?"),
|
||||
("wayland-keyboard-input-consent-tip", "આ રિમોટ કમ્પ્યુટર પર તમે જે ટાઇપ કરો છો (પાસવર્ડ સહિત) તે તેના પરની અન્ય એપ્સ વાંચી શકે છે."),
|
||||
("wayland-keyboard-input-applies-to-tip", "આ પસંદગી આના પર લાગુ થાય છે:"),
|
||||
("wayland-soft-keyboard-input-label", "સોફ્ટ કીબોર્ડ ઇનપુટ"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "કીબોર્ડ ઇનપુટ પસંદગી રિસેટ કરો"),
|
||||
("remember-wayland-keyboard-choice-tip", "આ રિમોટ કમ્પ્યુટર માટે ફરીથી પૂછશો નહીં"),
|
||||
("Why this happens", "આવું શા માટે થાય છે"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "שיתוף מסך"),
|
||||
("ubuntu-21-04-required", "Wayland דורש Ubuntu 21.04 או גרסה גבוהה יותר"),
|
||||
("wayland-requires-higher-linux-version", "Wayland דורש גרסת הפצת לינוקס גבוהה יותר. אנא נסה שולחן עבודה מסוג X11 או החלף מערכת הפעלה"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "לכידת מסך ב-Wayland נכשלה. ייתכן ש-XDG Desktop Portal קרס או אינו זמין. נסה להפעיל אותו מחדש באמצעות `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "קישור מהיר"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "אנא בחר את המסך לשיתוף (פעולה בצד העמית)."),
|
||||
("Show RustDesk", "הצג את RustDesk"),
|
||||
@@ -689,9 +689,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Use WebSocket", "השתמש ב־WebSocket"),
|
||||
("Trackpad speed", "מהירות משטח מגע"),
|
||||
("Default trackpad speed", "מהירות ברירת מחדל של משטח מגע"),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("Numeric one-time password", "סיסמה חד-פעמית מספרית"),
|
||||
("Enable IPv6 P2P connection", "אפשר חיבור IPv6 P2P"),
|
||||
("Enable UDP hole punching", "אפשר UDP hole punching"),
|
||||
("View camera", "הצג מצלמה"),
|
||||
("Enable camera", "הפעל מצלמה"),
|
||||
("No cameras", "אין מצלמות"),
|
||||
@@ -709,39 +709,54 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Supported only in the installed version.", "נתמך רק בגרסה המותקנת"),
|
||||
("elevation_username_tip", "רמז_ליוזר_להעלאת_הרשאה"),
|
||||
("Preparing for installation ...", "הכנה להתקנה..."),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Show my cursor", "הצג את הסמן שלי"),
|
||||
("Scale custom", "קנה מידה מותאם אישית"),
|
||||
("Custom scale slider", "מחוון קנה מידה מותאם אישית"),
|
||||
("Decrease", "הקטן"),
|
||||
("Increase", "הגדל"),
|
||||
("Show virtual mouse", "הצג עכבר וירטואלי"),
|
||||
("Virtual mouse size", "גודל עכבר וירטואלי"),
|
||||
("Small", "קטן"),
|
||||
("Large", "גדול"),
|
||||
("Show virtual joystick", "הצג ג'ויסטיק וירטואלי"),
|
||||
("Edit note", "ערוך הערה"),
|
||||
("Alias", "כינוי"),
|
||||
("ScrollEdge", "גלילה בקצה"),
|
||||
("Allow insecure TLS fallback", "אפשר חזרה ל-TLS לא מאובטח"),
|
||||
("allow-insecure-tls-fallback-tip", "כברירת מחדל, RustDesk מאמת את אישור השרת עבור פרוטוקולים המשתמשים ב-TLS.\nכאשר אפשרות זו מופעלת, RustDesk יחזור לדילוג על שלב האימות וימשיך במקרה של כשל באימות."),
|
||||
("Disable UDP", "השבת UDP"),
|
||||
("disable-udp-tip", "קובע אם להשתמש ב-TCP בלבד.\nכאשר אפשרות זו מופעלת, RustDesk לא ישתמש יותר ב-UDP 21116, ובמקום זאת ייעשה שימוש ב-TCP 21116."),
|
||||
("server-oss-not-support-tip", "הערה: גרסת ה-OSS של שרת RustDesk אינה כוללת תכונה זו."),
|
||||
("input note here", "הזן הערה כאן"),
|
||||
("note-at-conn-end-tip", "בקש הערה בסיום החיבור"),
|
||||
("Show terminal extra keys", "הצג מקשים נוספים במסוף"),
|
||||
("Relative mouse mode", "מצב עכבר יחסי"),
|
||||
("rel-mouse-not-supported-peer-tip", "מצב עכבר יחסי אינו נתמך על-ידי העמית המחובר."),
|
||||
("rel-mouse-not-ready-tip", "מצב עכבר יחסי אינו מוכן עדיין. אנא נסה שוב."),
|
||||
("rel-mouse-lock-failed-tip", "נעילת הסמן נכשלה. מצב עכבר יחסי הושבת."),
|
||||
("rel-mouse-exit-{}-tip", "לחץ {} כדי לצאת."),
|
||||
("rel-mouse-permission-lost-tip", "הרשאת המקלדת בוטלה. מצב עכבר יחסי הושבת."),
|
||||
("Changelog", "יומן שינויים"),
|
||||
("keep-awake-during-outgoing-sessions-label", "השאר את המסך פעיל במהלך הפעלות יוצאות"),
|
||||
("keep-awake-during-incoming-sessions-label", "השאר את המסך פעיל במהלך הפעלות נכנסות"),
|
||||
("Continue with {}", "המשך עם {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "שם תצוגה"),
|
||||
("password-hidden-tip", "סיסמה קבועה הוגדרה (מוסתרת)."),
|
||||
("preset-password-in-use-tip", "סיסמה מוגדרת מראש נמצאת כעת בשימוש."),
|
||||
("Enable privacy mode", "אפשר מצב פרטיות"),
|
||||
("allow-remote-toolbar-docking-any-edge", "אפשר עיגון סרגל הכלים המרוחק לכל קצה של החלון"),
|
||||
("API Token", "אסימון API"),
|
||||
("Deploy", "פרוס"),
|
||||
("Custom ID (optional)", "מזהה מותאם אישית (אופציונלי)"),
|
||||
("server_requires_deployment_tip", "השרת דורש שמכשיר זה ייפרס במפורש. לפרוס כעת?"),
|
||||
("The server does not require explicit deployment.", "השרת אינו דורש פריסה מפורשת."),
|
||||
("Unknown response.", "תגובה לא ידועה."),
|
||||
("wayland-keyboard-input-disabled-tip", "לאפשר קלט מקלדת?"),
|
||||
("wayland-keyboard-input-consent-tip", "מה שאתה מקליד במחשב המרוחק הזה (כולל סיסמאות) עלול להיקרא על-ידי אפליקציות אחרות בו."),
|
||||
("wayland-keyboard-input-applies-to-tip", "בחירה זו חלה על:"),
|
||||
("wayland-soft-keyboard-input-label", "קלט מקלדת רכה"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "אפס את בחירת קלט המקלדת"),
|
||||
("remember-wayland-keyboard-choice-tip", "אל תשאל שוב עבור מחשב מרוחק זה"),
|
||||
("Why this happens", "מדוע זה קורה"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -654,6 +654,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Accessible devices", "सुलभ डिवाइस"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "रिमोट RustDesk क्लाइंट को संस्करण {} में अपग्रेड करें"),
|
||||
("d3d_render_tip", "D3D रेंडरिंग का उपयोग करें"),
|
||||
("Use D3D rendering", "D3D रेंडरिंग का उपयोग करें"),
|
||||
("Printer", "प्रिंटर"),
|
||||
("printer-os-requirement-tip", "प्रिंटिंग के लिए Windows आवश्यक है।"),
|
||||
("printer-requires-installed-{}-client-tip", "इसके लिए क्लाइंट साइड पर {} इंस्टॉल होना चाहिए।"),
|
||||
@@ -742,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "प्रदर्शित नाम"),
|
||||
("password-hidden-tip", "पासवर्ड सुरक्षा के लिए छिपा हुआ है।"),
|
||||
("preset-password-in-use-tip", "पूर्व-निर्धारित पासवर्ड उपयोग में है।"),
|
||||
("Enable privacy mode", "गोपनीयता मोड सक्षम करें"),
|
||||
("allow-remote-toolbar-docking-any-edge", "रिमोट टूलबार को विंडो के किसी भी किनारे पर डॉक करने की अनुमति दें"),
|
||||
("API Token", "API टोकन"),
|
||||
("Deploy", "तैनात करें"),
|
||||
("Custom ID (optional)", "कस्टम ID (वैकल्पिक)"),
|
||||
("server_requires_deployment_tip", "सर्वर के लिए इस डिवाइस को स्पष्ट रूप से तैनात करना आवश्यक है। अभी तैनात करें?"),
|
||||
("The server does not require explicit deployment.", "सर्वर के लिए स्पष्ट तैनाती आवश्यक नहीं है।"),
|
||||
("Unknown response.", "अज्ञात प्रतिक्रिया।"),
|
||||
("wayland-keyboard-input-disabled-tip", "कीबोर्ड इनपुट की अनुमति दें?"),
|
||||
("wayland-keyboard-input-consent-tip", "आप इस रिमोट कंप्यूटर पर जो टाइप करते हैं (पासवर्ड सहित) उसे उस पर मौजूद अन्य ऐप्स पढ़ सकते हैं।"),
|
||||
("wayland-keyboard-input-applies-to-tip", "यह चयन इस पर लागू होता है:"),
|
||||
("wayland-soft-keyboard-input-label", "सॉफ्ट कीबोर्ड इनपुट"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "कीबोर्ड इनपुट चयन रीसेट करें"),
|
||||
("remember-wayland-keyboard-choice-tip", "इस रिमोट कंप्यूटर के लिए दोबारा न पूछें"),
|
||||
("Why this happens", "ऐसा क्यों होता है"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
313
src/lang/hr.rs
313
src/lang/hr.rs
@@ -237,7 +237,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Empty", "Prazno"),
|
||||
("Invalid folder name", "Nevažeći naziv mape"),
|
||||
("Socks5 Proxy", "Socks5 Proxy"),
|
||||
("Socks5/Http(s) Proxy", ""),
|
||||
("Socks5/Http(s) Proxy", "Socks5/Http(s) proxy"),
|
||||
("Discovered", "Otkriveno"),
|
||||
("install_daemon_tip", "Servis sustava mora biti instaliran ako se želi pokrenuti pri pokretanju sustava."),
|
||||
("Remote ID", "Udaljeni ID"),
|
||||
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Snimanje"),
|
||||
("Directory", "Mapa"),
|
||||
("Automatically record incoming sessions", "Automatski snimi dolazne sesije"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Automatski snimi odlazne sesije"),
|
||||
("Change", "Promijeni"),
|
||||
("Start session recording", "Započni snimanje sesije"),
|
||||
("Stop session recording", "Zaustavi snimanje sesije"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Dijeljenje zaslona"),
|
||||
("ubuntu-21-04-required", "Wayland zahtijeva Ubuntu verziju 21.04 ili višu"),
|
||||
("wayland-requires-higher-linux-version", "Wayland zahtijeva višu verziju Linux distribucije. Molimo isprobjate X11 ili promijenite OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Snimanje zaslona za Wayland nije uspjelo. XDG Desktop Portal se možda srušio ili je nedostupan. Pokušajte ga ponovno pokrenuti naredbom `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Vidi"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Molimo odaberite zaslon koji će biti podijeljen (Za rad na strani klijenta)"),
|
||||
("Show RustDesk", "Prikaži RustDesk"),
|
||||
@@ -594,154 +594,169 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("share_warning_tip", "Gornja polja su podijeljena i vidljiva drugima."),
|
||||
("Everyone", "Svatko"),
|
||||
("ab_web_console_tip", "Više na web konzoli"),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Clear Wayland screen selection", ""),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("Use texture rendering", ""),
|
||||
("Floating window", ""),
|
||||
("floating_window_tip", ""),
|
||||
("Keep screen on", ""),
|
||||
("Never", ""),
|
||||
("During controlled", ""),
|
||||
("During service is on", ""),
|
||||
("Capture screen using DirectX", ""),
|
||||
("Back", ""),
|
||||
("Apps", ""),
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("allow-only-conn-window-open-tip", "Dopusti vezu samo ako je prozor RustDeska otvoren"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Nema fizičkih zaslona, nema potrebe za korištenjem načina privatnosti."),
|
||||
("Follow remote cursor", "Prati udaljeni kursor"),
|
||||
("Follow remote window focus", "Prati fokus udaljenog prozora"),
|
||||
("default_proxy_tip", "Zadani protokol i priključak su Socks5 i 1080"),
|
||||
("no_audio_input_device_tip", "Nije pronađen ulazni audio uređaj."),
|
||||
("Incoming", "Dolazno"),
|
||||
("Outgoing", "Odlazno"),
|
||||
("Clear Wayland screen selection", "Očisti odabir zaslona za Wayland"),
|
||||
("clear_Wayland_screen_selection_tip", "Nakon brisanja odabira zaslona možete ponovno odabrati zaslon za dijeljenje."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Jeste li sigurni da želite obrisati odabir zaslona za Wayland?"),
|
||||
("android_new_voice_call_tip", "Primljen je novi zahtjev za glasovni poziv. Ako ga prihvatite, zvuk će se prebaciti na glasovnu komunikaciju."),
|
||||
("texture_render_tip", "Koristite renderiranje tekstura kako bi slike bile glađe. Možete pokušati onemogućiti ovu opciju ako naiđete na probleme s renderiranjem."),
|
||||
("Use texture rendering", "Koristi renderiranje tekstura"),
|
||||
("Floating window", "Plutajući prozor"),
|
||||
("floating_window_tip", "Pomaže u održavanju pozadinskog servisa RustDeska"),
|
||||
("Keep screen on", "Zadrži zaslon uključenim"),
|
||||
("Never", "Nikad"),
|
||||
("During controlled", "Tijekom upravljanja"),
|
||||
("During service is on", "Dok je servis uključen"),
|
||||
("Capture screen using DirectX", "Snimaj zaslon pomoću DirectX-a"),
|
||||
("Back", "Natrag"),
|
||||
("Apps", "Aplikacije"),
|
||||
("Volume up", "Pojačaj glasnoću"),
|
||||
("Volume down", "Smanji glasnoću"),
|
||||
("Power", "Napajanje"),
|
||||
("Telegram bot", "Telegram bot"),
|
||||
("enable-bot-tip", "Ako omogućite ovu značajku, možete primati 2FA kôd od svog bota. Može poslužiti i kao obavijest o vezi."),
|
||||
("enable-bot-desc", "1. Otvorite razgovor s @BotFather.\n2. Pošaljite naredbu \"/newbot\". Nakon dovršetka ovog koraka primit ćete token.\n3. Započnite razgovor s novostvorenim botom. Pošaljite poruku koja počinje kosom crtom (\"/\"), poput \"/hello\", kako biste ga aktivirali.\n"),
|
||||
("cancel-2fa-confirm-tip", "Jeste li sigurni da želite otkazati 2FA?"),
|
||||
("cancel-bot-confirm-tip", "Jeste li sigurni da želite otkazati Telegram bota?"),
|
||||
("About RustDesk", "O RustDesku"),
|
||||
("Send clipboard keystrokes", "Pošalji pritiske tipki iz međuspremnika"),
|
||||
("network_error_tip", "Provjerite svoju mrežnu vezu, a zatim kliknite Pokušaj ponovno."),
|
||||
("Unlock with PIN", "Otključaj PIN-om"),
|
||||
("Requires at least {} characters", "Potrebno je najmanje {} znakova"),
|
||||
("Wrong PIN", "Pogrešan PIN"),
|
||||
("Set PIN", "Postavi PIN"),
|
||||
("Enable trusted devices", "Omogući pouzdane uređaje"),
|
||||
("Manage trusted devices", "Upravljaj pouzdanim uređajima"),
|
||||
("Platform", "Platforma"),
|
||||
("Days remaining", "Preostalo dana"),
|
||||
("enable-trusted-devices-tip", "Preskoči 2FA provjeru na pouzdanim uređajima"),
|
||||
("Parent directory", "Nadređeni direktorij"),
|
||||
("Resume", "Nastavi"),
|
||||
("Invalid file name", "Nevažeći naziv datoteke"),
|
||||
("one-way-file-transfer-tip", "Jednosmjerni prijenos datoteka omogućen je na upravljanoj strani."),
|
||||
("Authentication Required", "Potrebna autentifikacija"),
|
||||
("Authenticate", "Autentificiraj"),
|
||||
("web_id_input_tip", "Možete unijeti ID na istom poslužitelju, izravan pristup preko IP adrese nije podržan u web klijentu.\nAko želite pristupiti uređaju na drugom poslužitelju, dodajte adresu poslužitelja (<id>@<server_address>?key=<key_value>), na primjer,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nAko želite pristupiti uređaju na javnom poslužitelju, unesite \"<id>@public\", ključ nije potreban za javni poslužitelj."),
|
||||
("Download", "Preuzmi"),
|
||||
("Upload folder", "Prenesi mapu"),
|
||||
("Upload files", "Prenesi datoteke"),
|
||||
("Clipboard is synchronized", "Međuspremnik je sinkroniziran"),
|
||||
("Update client clipboard", "Ažuriraj međuspremnik klijenta"),
|
||||
("Untagged", "Bez oznake"),
|
||||
("new-version-of-{}-tip", "Dostupna je nova verzija {}"),
|
||||
("Accessible devices", "Dostupni uređaji"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Molimo ažurirajte RustDesk klijent na verziju {} ili noviju na udaljenoj strani!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Kada je omogućeno D3D renderiranje, na nekim računalima zaslon daljinskog upravljanja može biti crn."),
|
||||
("Use D3D rendering", "Koristi D3D renderiranje"),
|
||||
("Printer", "Pisač"),
|
||||
("printer-os-requirement-tip", "Funkcija odlaznog ispisa zahtijeva Windows 10 ili noviju verziju."),
|
||||
("printer-requires-installed-{}-client-tip", "Za korištenje udaljenog ispisa, na ovom uređaju mora biti instaliran {}."),
|
||||
("printer-{}-not-installed-tip", "Pisač {} nije instaliran."),
|
||||
("printer-{}-ready-tip", "Pisač {} je instaliran i spreman za korištenje."),
|
||||
("Install {} Printer", "Instaliraj pisač {}"),
|
||||
("Outgoing Print Jobs", "Odlazni zadaci ispisa"),
|
||||
("Incoming Print Jobs", "Dolazni zadaci ispisa"),
|
||||
("Incoming Print Job", "Dolazni zadatak ispisa"),
|
||||
("use-the-default-printer-tip", "Koristi zadani pisač"),
|
||||
("use-the-selected-printer-tip", "Koristi odabrani pisač"),
|
||||
("auto-print-tip", "Automatski ispisuj pomoću odabranog pisača."),
|
||||
("print-incoming-job-confirm-tip", "Primili ste zadatak ispisa s udaljenog uređaja. Želite li ga izvršiti na svojoj strani?"),
|
||||
("remote-printing-disallowed-tile-tip", "Udaljeni ispis nije dopušten"),
|
||||
("remote-printing-disallowed-text-tip", "Postavke dozvola upravljane strane onemogućuju udaljeni ispis."),
|
||||
("save-settings-tip", "Spremi postavke"),
|
||||
("dont-show-again-tip", "Ne prikazuj ovo ponovno"),
|
||||
("Take screenshot", "Snimi zaslon"),
|
||||
("Taking screenshot", "Snimanje zaslona"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Spajanje snimaka zaslona s više zaslona trenutačno nije podržano. Prebacite se na jedan zaslon i pokušajte ponovno."),
|
||||
("screenshot-action-tip", "Odaberite kako nastaviti sa snimkom zaslona."),
|
||||
("Save as", "Spremi kao"),
|
||||
("Copy to clipboard", "Kopiraj u međuspremnik"),
|
||||
("Enable remote printer", "Omogući udaljeni pisač"),
|
||||
("Downloading {}", "Preuzimanje {}"),
|
||||
("{} Update", "Ažuriranje {}"),
|
||||
("{}-to-update-tip", "{} će se sada zatvoriti i instalirati novu verziju."),
|
||||
("download-new-version-failed-tip", "Preuzimanje nije uspjelo. Možete pokušati ponovno ili kliknuti gumb \"Preuzmi\" za preuzimanje sa stranice izdanja i ručnu nadogradnju."),
|
||||
("Auto update", "Automatsko ažuriranje"),
|
||||
("update-failed-check-msi-tip", "Provjera načina instalacije nije uspjela. Kliknite gumb \"Preuzmi\" za preuzimanje sa stranice izdanja i ručnu nadogradnju."),
|
||||
("websocket_tip", "Kada koristite WebSocket, podržane su samo relejne veze."),
|
||||
("Use WebSocket", "Koristi WebSocket"),
|
||||
("Trackpad speed", "Brzina dodirne ploče"),
|
||||
("Default trackpad speed", "Zadana brzina dodirne ploče"),
|
||||
("Numeric one-time password", "Numerička jednokratna lozinka"),
|
||||
("Enable IPv6 P2P connection", "Omogući IPv6 P2P vezu"),
|
||||
("Enable UDP hole punching", "Omogući UDP hole punching"),
|
||||
("View camera", "Pregled kamere"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Omogući kameru"),
|
||||
("No cameras", "Nema kamera"),
|
||||
("view_camera_unsupported_tip", "Udaljeni uređaj ne podržava pregled kamere."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Omogući terminal"),
|
||||
("New tab", "Nova kartica"),
|
||||
("Keep terminal sessions on disconnect", "Zadrži sesije terminala pri prekidu veze"),
|
||||
("Terminal (Run as administrator)", "Terminal (Pokreni kao administrator)"),
|
||||
("terminal-admin-login-tip", "Unesite administratorsko korisničko ime i lozinku upravljane strane."),
|
||||
("Failed to get user token.", "Nije uspjelo dohvaćanje korisničkog tokena."),
|
||||
("Incorrect username or password.", "Netočno korisničko ime ili lozinka."),
|
||||
("The user is not an administrator.", "Korisnik nije administrator."),
|
||||
("Failed to check if the user is an administrator.", "Nije uspjela provjera je li korisnik administrator."),
|
||||
("Supported only in the installed version.", "Podržano samo u instaliranoj verziji."),
|
||||
("elevation_username_tip", "Unesite korisničko ime ili domena\\korisničko ime"),
|
||||
("Preparing for installation ...", "Priprema za instalaciju ..."),
|
||||
("Show my cursor", "Prikaži moj kursor"),
|
||||
("Scale custom", "Prilagođeno skaliranje"),
|
||||
("Custom scale slider", "Klizač prilagođenog skaliranja"),
|
||||
("Decrease", "Smanji"),
|
||||
("Increase", "Povećaj"),
|
||||
("Show virtual mouse", "Prikaži virtualnog miša"),
|
||||
("Virtual mouse size", "Veličina virtualnog miša"),
|
||||
("Small", "Malo"),
|
||||
("Large", "Veliko"),
|
||||
("Show virtual joystick", "Prikaži virtualni joystick"),
|
||||
("Edit note", "Uredi bilješku"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Dopusti nesigurni TLS pričuvni način"),
|
||||
("allow-insecure-tls-fallback-tip", "Prema zadanim postavkama, RustDesk provjerava certifikat poslužitelja za protokole koji koriste TLS.\nKada je ova opcija omogućena, RustDesk će u slučaju neuspjele provjere preskočiti korak provjere i nastaviti."),
|
||||
("Disable UDP", "Onemogući UDP"),
|
||||
("disable-udp-tip", "Određuje hoće li se koristiti samo TCP.\nKada je ova opcija omogućena, RustDesk više neće koristiti UDP 21116, već će umjesto toga koristiti TCP 21116."),
|
||||
("server-oss-not-support-tip", "NAPOMENA: RustDesk poslužitelj OSS ne uključuje ovu značajku."),
|
||||
("input note here", "ovdje unesite bilješku"),
|
||||
("note-at-conn-end-tip", "Zatraži bilješku na kraju veze"),
|
||||
("Show terminal extra keys", "Prikaži dodatne tipke terminala"),
|
||||
("Relative mouse mode", "Relativni način miša"),
|
||||
("rel-mouse-not-supported-peer-tip", "Povezani uređaj ne podržava relativni način miša."),
|
||||
("rel-mouse-not-ready-tip", "Relativni način miša još nije spreman. Pokušajte ponovno."),
|
||||
("rel-mouse-lock-failed-tip", "Zaključavanje kursora nije uspjelo. Relativni način miša je onemogućen."),
|
||||
("rel-mouse-exit-{}-tip", "Pritisnite {} za izlaz."),
|
||||
("rel-mouse-permission-lost-tip", "Dozvola za tipkovnicu je opozvana. Relativni način miša je onemogućen."),
|
||||
("Changelog", "Popis promjena"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Zadrži zaslon aktivnim tijekom odlaznih sesija"),
|
||||
("keep-awake-during-incoming-sessions-label", "Zadrži zaslon aktivnim tijekom dolaznih sesija"),
|
||||
("Continue with {}", "Nastavi sa {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Prikazani naziv"),
|
||||
("password-hidden-tip", "Trajna lozinka je postavljena (skrivena)."),
|
||||
("preset-password-in-use-tip", "Unaprijed postavljena lozinka trenutačno je u upotrebi."),
|
||||
("Enable privacy mode", "Omogući način privatnosti"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Dopusti usidrenje udaljene alatne trake na bilo koji rub prozora"),
|
||||
("API Token", "API token"),
|
||||
("Deploy", "Postavi"),
|
||||
("Custom ID (optional)", "Prilagođeni ID (neobavezno)"),
|
||||
("server_requires_deployment_tip", "Poslužitelj zahtijeva da se ovaj uređaj eksplicitno postavi. Postaviti sada?"),
|
||||
("The server does not require explicit deployment.", "Poslužitelj ne zahtijeva eksplicitno postavljanje."),
|
||||
("Unknown response.", "Nepoznat odgovor."),
|
||||
("wayland-keyboard-input-disabled-tip", "Dopustiti unos tipkovnicom?"),
|
||||
("wayland-keyboard-input-consent-tip", "Ono što tipkate na ovom udaljenom računalu (uključujući lozinke) mogle bi pročitati druge aplikacije na njemu."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Ovaj izbor odnosi se na:"),
|
||||
("wayland-soft-keyboard-input-label", "Unos softverskom tipkovnicom"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Poništi izbor unosa tipkovnicom"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ne pitaj ponovno za ovo udaljeno računalo"),
|
||||
("Why this happens", "Zašto se ovo događa"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Képernyőmegosztás"),
|
||||
("ubuntu-21-04-required", "A Waylandhez Ubuntu 21.04 vagy újabb verzió szükséges."),
|
||||
("wayland-requires-higher-linux-version", "A Wayland a Linux disztribúció magasabb verzióját igényli. Próbálja ki az X11 asztali környezetet, vagy változtassa meg az operációs rendszert."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "A Wayland képernyőrögzítés sikertelen. Lehet, hogy az XDG Desktop Portal összeomlott, vagy nem érhető el. Próbálja meg újraindítani a következővel: `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Hiperhivatkozás"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Válassza ki a megosztani kívánt képernyőt."),
|
||||
("Show RustDesk", "A RustDesk megjelenítése"),
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "Kijelző név"),
|
||||
("password-hidden-tip", "Állandó jelszó lett beállítva (rejtett)."),
|
||||
("preset-password-in-use-tip", "Jelenleg az alapértelmezett jelszót használja."),
|
||||
("Enable privacy mode", "Adatvédelmi mód aktiválása"),
|
||||
("allow-remote-toolbar-docking-any-edge", "A távoli eszköztár dokkolásának engedélyezése az ablak bármely széléhez"),
|
||||
("API Token", "API-token"),
|
||||
("Deploy", "Telepítés"),
|
||||
("Custom ID (optional)", "Egyéni azonosító (nem kötelező)"),
|
||||
("server_requires_deployment_tip", "A kiszolgáló megköveteli, hogy ez az eszköz kifejezetten telepítve legyen. Telepíti most?"),
|
||||
("The server does not require explicit deployment.", "A kiszolgáló nem igényel kifejezett telepítést."),
|
||||
("Unknown response.", "Ismeretlen válasz."),
|
||||
("wayland-keyboard-input-disabled-tip", "Engedélyezi a billentyűzetbevitelt?"),
|
||||
("wayland-keyboard-input-consent-tip", "Amit ezen a távoli számítógépen begépel (beleértve a jelszavakat is), azt a rajta futó más alkalmazások is olvashatják."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Ez a választás a következőre vonatkozik:"),
|
||||
("wayland-soft-keyboard-input-label", "Szoftveres billentyűzetbevitel"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Billentyűzetbevitel választásának visszaállítása"),
|
||||
("remember-wayland-keyboard-choice-tip", "Ne kérdezze meg újra ennél a távoli számítógépnél"),
|
||||
("Why this happens", "Miért történik ez"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
153
src/lang/id.rs
153
src/lang/id.rs
@@ -49,7 +49,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Mute", "Bisukan"),
|
||||
("Build Date", "Tanggal Build"),
|
||||
("Version", "Versi"),
|
||||
("Home", ""),
|
||||
("Home", "Beranda"),
|
||||
("Audio Input", "Input Audio"),
|
||||
("Enhancements", "Peningkatan"),
|
||||
("Hardware Codec", "Kodek Perangkat Keras"),
|
||||
@@ -360,7 +360,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Recording", "Perekaman"),
|
||||
("Directory", "Direktori"),
|
||||
("Automatically record incoming sessions", "Otomatis merekam sesi masuk"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Rekam sesi keluar secara otomatis"),
|
||||
("Change", "Ubah"),
|
||||
("Start session recording", "Mulai sesi perekaman"),
|
||||
("Stop session recording", "Hentikan sesi perekaman"),
|
||||
@@ -368,7 +368,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Enable LAN discovery", "Aktifkan Pencarian Jaringan Lokal (LAN)"),
|
||||
("Deny LAN discovery", "Tolak Pencarian Jaringan Lokal (LAN)"),
|
||||
("Write a message", "Tulis pesan"),
|
||||
("Prompt", ""),
|
||||
("Prompt", "Permintaan"),
|
||||
("Please wait for confirmation of UAC...", "Harap tunggu konfirmasi UAC"),
|
||||
("elevated_foreground_window_tip", "Jendela yang sedang aktif di remote desktop memerlukan hak istimewa yang lebih tinggi untuk beroperasi, sehingga mouse dan keyboard tidak dapat digunakan sementara waktu. Kamu bisa meminta pengguna jarak jauh untuk meminimalkan jendela saat ini, atau klik tombol elevasi di jendela manajemen koneksi. Untuk menghindari masalah ini, disarankan untuk menginstal software di perangkat remote secara permanen."),
|
||||
("Disconnected", "Terputus"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Berbagi Layar"),
|
||||
("ubuntu-21-04-required", "Wayland membutuhkan Ubuntu 21.04 atau versi yang lebih tinggi."),
|
||||
("wayland-requires-higher-linux-version", "Wayland membutuhkan versi distro linux yang lebih tinggi. Silakan coba desktop X11 atau ubah OS Anda."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Pengambilan layar Wayland gagal. XDG Desktop Portal mungkin telah crash atau tidak tersedia. Coba mulai ulang dengan `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Tautan Cepat"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Silakan Pilih layar yang akan dibagikan kepada rekan anda."),
|
||||
("Show RustDesk", "Tampilkan RustDesk"),
|
||||
@@ -480,9 +480,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("System Sound", "Suara Sistem"),
|
||||
("Default", "Default"),
|
||||
("New RDP", "RDP Baru"),
|
||||
("Fingerprint", ""),
|
||||
("Copy Fingerprint", ""),
|
||||
("no fingerprints", ""),
|
||||
("Fingerprint", "Sidik jari"),
|
||||
("Copy Fingerprint", "Salin sidik jari"),
|
||||
("no fingerprints", "Tidak ada sidik jari"),
|
||||
("Select a peer", "Pilih rekan"),
|
||||
("Select peers", "Pilih rekan-rekan"),
|
||||
("Plugins", "Plugin"),
|
||||
@@ -494,7 +494,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("resolution_original_tip", "Resolusi original"),
|
||||
("resolution_fit_local_tip", "Sesuaikan resolusi lokal"),
|
||||
("resolution_custom_tip", "Resolusi kustom"),
|
||||
("Collapse toolbar", ""),
|
||||
("Collapse toolbar", "Ciutkan bilah alat"),
|
||||
("Accept and Elevate", "Terima dan Elevasi"),
|
||||
("accept_and_elevate_btn_tooltip", "Terima koneksi dan elevasi izin UAC"),
|
||||
("clipboard_wait_response_timeout_tip", "Batas waktu habis saat menunggu respons salinan"),
|
||||
@@ -557,7 +557,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Daftar"),
|
||||
("Virtual display", "Tampilan virtual"),
|
||||
("Plug out all", "Lepaskan semua"),
|
||||
("True color (4:4:4)", ""),
|
||||
("True color (4:4:4)", "Warna penuh (4:4:4)"),
|
||||
("Enable blocking user input", "Aktifkan pemblokiran input pengguna"),
|
||||
("id_input_tip", "Anda bisa memasukkan ID, IP langsung, atau domain dengan port kostum yang sudah ditentukan (<domain>:<port>).\nJika anda ingin mengakses perangkat lain yang berbeda server, tambahkan alamat server setelah penulisan ID(<id>@<server_address>?key=<key_value>), sebagai contoh,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJika anda ingin mengakses perangkat yang menggunakan server publik, masukkan \"<id>@public\", server public tidak memerlukan key khusus"),
|
||||
("privacy_mode_impl_mag_tip", "Mode 1"),
|
||||
@@ -588,11 +588,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Owner", "Pemilik"),
|
||||
("Set shared password", "Atus kata sandi kolaboratif"),
|
||||
("Exist in", "Ada di"),
|
||||
("Read-only", ""),
|
||||
("Read/Write", ""),
|
||||
("Full Control", ""),
|
||||
("Read-only", "Hanya baca"),
|
||||
("Read/Write", "Baca/Tulis"),
|
||||
("Full Control", "Kontrol penuh"),
|
||||
("share_warning_tip", "Informasi di atas bersifat publik dan dapat dilihat oleh orang lain."),
|
||||
("Everyone", ""),
|
||||
("Everyone", "Semua orang"),
|
||||
("ab_web_console_tip", "Detail Lain di Konsol Web"),
|
||||
("allow-only-conn-window-open-tip", "Koneksi hanya diperbolehkan jika jendela RustDesk sedang terbuka."),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Karena tidak ada layar fisik, mode privasi tidak perlu diaktifkan."),
|
||||
@@ -600,26 +600,26 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Follow remote window focus", "Ikuti jendela remote yang sedang aktif"),
|
||||
("default_proxy_tip", "Pengaturan standar untuk protokol dan port adalah Socks5 dan 1080."),
|
||||
("no_audio_input_device_tip", "Perangkat input audio tidak terdeteksi."),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Incoming", "Masuk"),
|
||||
("Outgoing", "Keluar"),
|
||||
("Clear Wayland screen selection", "Kosongkan pilihan layar Wayland"),
|
||||
("clear_Wayland_screen_selection_tip", "Setelah mengosongkan pilihan layar, Kamu bisa memilih kembali layar untuk dibagi"),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Kamu yakin ingin membersihkan pemilihan layar Wayland?"),
|
||||
("android_new_voice_call_tip", "Kamu mendapatkan permintaan panggilan suara baru. Jika diterima, audio akan berubah menjadi komunikasi suara."),
|
||||
("texture_render_tip", "Aktifkan rendering tekstur untuk membuat tampilan gambar lebih mulus. Kamu dapat menonaktifkan opsi ini jika terjadi masalah saat merender."),
|
||||
("Use texture rendering", "Aktifkan rendering tekstur"),
|
||||
("Floating window", ""),
|
||||
("Floating window", "Jendela mengambang"),
|
||||
("floating_window_tip", "Untuk menjaga layanan/service RustDesk agar tetap aktif"),
|
||||
("Keep screen on", "Biarkan layar tetap menyala"),
|
||||
("Never", "Tidak pernah"),
|
||||
("During controlled", "Dalam proses pengendalian"),
|
||||
("During service is on", ""),
|
||||
("During service is on", "Saat layanan aktif"),
|
||||
("Capture screen using DirectX", "Rekam layar dengan DirectX"),
|
||||
("Back", "Kembali"),
|
||||
("Apps", "App"),
|
||||
("Volume up", "Naikkan volume"),
|
||||
("Volume down", "Turunkan volume"),
|
||||
("Power", ""),
|
||||
("Power", "Daya"),
|
||||
("Telegram bot", "Bot Telegram"),
|
||||
("enable-bot-tip", "Jika fitur ini diaktifkan, Kamu dapat menerima kode 2FA dari bot, serta mendapatkan notifikasi tentang koneksi."),
|
||||
("enable-bot-desc", "1. Buka chat dengan @BotFather.\n2. Kirim perintah \"/newbot\". Setelah menyelesaikan langkah ini, Kamu akan mendapatkan token\n3. Mulai percakapan dengan bot yang baru dibuat. Kirim pesan yang dimulai dengan garis miring (\"/\") seperti \"/hello\" untuk mengaktifkannya."),
|
||||
@@ -648,34 +648,34 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Upload folder", "Upload folder"),
|
||||
("Upload files", "Upload file"),
|
||||
("Clipboard is synchronized", "Clipboard disinkronisasi"),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("Update client clipboard", "Perbarui papan klip klien"),
|
||||
("Untagged", "Tanpa tag"),
|
||||
("new-version-of-{}-tip", "Versi {} sudah tersedia."),
|
||||
("Accessible devices", "Perangkat yang tersedia"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Silahkan perbarui aplikasi RustDesk ke versi {} atau yang lebih baru pada komputer yang akan terhubung!"),
|
||||
("d3d_render_tip", "Ketika rendering D3D diaktifkan, layar kontrol jarak jauh bisa tampak hitam di beberapa komputer"),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("Use D3D rendering", "Gunakan rendering D3D"),
|
||||
("Printer", "Printer"),
|
||||
("printer-os-requirement-tip", "Fungsi pencetakan keluar memerlukan Windows 10 atau yang lebih baru."),
|
||||
("printer-requires-installed-{}-client-tip", "Untuk menggunakan pencetakan jarak jauh, {} perlu dipasang di perangkat ini."),
|
||||
("printer-{}-not-installed-tip", "Printer {} tidak terinstal"),
|
||||
("printer-{}-ready-tip", "Printer {} sudah terinstal dan siap digunakan."),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("Install {} Printer", "Pasang Printer {}"),
|
||||
("Outgoing Print Jobs", "Tugas Cetak Keluar"),
|
||||
("Incoming Print Jobs", "Tugas Cetak Masuk"),
|
||||
("Incoming Print Job", "Tugas Cetak Masuk"),
|
||||
("use-the-default-printer-tip", "Gunakan printer default"),
|
||||
("use-the-selected-printer-tip", "Gunakan printer yang dipilih"),
|
||||
("auto-print-tip", "Cetak otomatis menggunakan printer yang dipilih."),
|
||||
("print-incoming-job-confirm-tip", "Anda menerima tugas cetak dari jarak jauh. Apakah Anda ingin menjalankannya di sisi Anda?"),
|
||||
("remote-printing-disallowed-tile-tip", "Remote Printing tidak diizinkan"),
|
||||
("remote-printing-disallowed-text-tip", "Komputer yang diakses tidak mengizinkan Remote Printing."),
|
||||
("save-settings-tip", "Simpan pengaturan"),
|
||||
("dont-show-again-tip", "Jangan tampilkan lagi"),
|
||||
("Take screenshot", "Ambil tangkapan layar"),
|
||||
("Taking screenshot", "Mengambil tangkapan layar"),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", "Menggabungkan tangkapan layar dari beberapa tampilan saat ini tidak didukung. Silakan beralih ke satu tampilan dan coba lagi."),
|
||||
("screenshot-action-tip", "Silakan pilih cara melanjutkan dengan tangkapan layar."),
|
||||
("Save as", "Simpan sebagai"),
|
||||
("Copy to clipboard", "Salin ke papan klip"),
|
||||
("Enable remote printer", "Aktifkan printer jarak jauh"),
|
||||
@@ -684,8 +684,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("{}-to-update-tip", "{} akan ditutup dan menginstal versi baru"),
|
||||
("download-new-version-failed-tip", "Gagal mendownload. Kamu bisa mencoba lagi nanti atau klik tombol \"Download\" melakukan download dari halaman rilis dan meningkatkan versi secara manual."),
|
||||
("Auto update", "Pembaruan otomatis"),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("update-failed-check-msi-tip", "Pemeriksaan metode pemasangan gagal. Silakan klik tombol \"Download\" untuk mengunduh dari halaman rilis dan tingkatkan secara manual."),
|
||||
("websocket_tip", "Saat menggunakan WebSocket, hanya koneksi relay yang didukung."),
|
||||
("Use WebSocket", "Gunakan WebSocket"),
|
||||
("Trackpad speed", "Kecepatan trackpad"),
|
||||
("Default trackpad speed", "Kecepatan default trackpad"),
|
||||
@@ -701,7 +701,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("New tab", "Tab baru"),
|
||||
("Keep terminal sessions on disconnect", "Pertahankan sesi terminal saat terputus"),
|
||||
("Terminal (Run as administrator)", "Terminal (Jalankan sebagai administrator)"),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("terminal-admin-login-tip", "Silakan masukkan nama pengguna dan kata sandi administrator dari sisi yang dikendalikan."),
|
||||
("Failed to get user token.", "Gagal mendapatkan token pengguna."),
|
||||
("Incorrect username or password.", "Nama pengguna atau kata sandi salah."),
|
||||
("The user is not an administrator.", "Pengguna bukanlah administrator."),
|
||||
@@ -710,38 +710,53 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("elevation_username_tip", "panduan_elevasi_nama_pengguna"),
|
||||
("Preparing for installation ...", "Mempersiapkan instalasi ..."),
|
||||
("Show my cursor", "Tampilkan kursor saya"),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Scale custom", "Skala kustom"),
|
||||
("Custom scale slider", "Penggeser skala kustom"),
|
||||
("Decrease", "Kurangi"),
|
||||
("Increase", "Tambah"),
|
||||
("Show virtual mouse", "Tampilkan mouse virtual"),
|
||||
("Virtual mouse size", "Ukuran mouse virtual"),
|
||||
("Small", "Kecil"),
|
||||
("Large", "Besar"),
|
||||
("Show virtual joystick", "Tampilkan joystick virtual"),
|
||||
("Edit note", "Edit catatan"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "Gulir Tepi"),
|
||||
("Allow insecure TLS fallback", "Izinkan fallback TLS tidak aman"),
|
||||
("allow-insecure-tls-fallback-tip", "Secara default, RustDesk memverifikasi sertifikat server untuk protokol yang menggunakan TLS.\nDengan opsi ini diaktifkan, RustDesk akan kembali melewati langkah verifikasi dan melanjutkan jika verifikasi gagal."),
|
||||
("Disable UDP", "Nonaktifkan UDP"),
|
||||
("disable-udp-tip", "Mengontrol apakah hanya menggunakan TCP.\nSaat opsi ini diaktifkan, RustDesk tidak akan menggunakan UDP 21116 lagi, TCP 21116 akan digunakan sebagai gantinya."),
|
||||
("server-oss-not-support-tip", "CATATAN: RustDesk server OSS tidak menyertakan fitur ini."),
|
||||
("input note here", "masukkan catatan di sini"),
|
||||
("note-at-conn-end-tip", "Minta catatan di akhir koneksi"),
|
||||
("Show terminal extra keys", "Tampilkan tombol tambahan terminal"),
|
||||
("Relative mouse mode", "Mode mouse relatif"),
|
||||
("rel-mouse-not-supported-peer-tip", "Mode Mouse Relatif tidak didukung oleh peer yang terhubung."),
|
||||
("rel-mouse-not-ready-tip", "Mode Mouse Relatif belum siap. Silakan coba lagi."),
|
||||
("rel-mouse-lock-failed-tip", "Gagal mengunci kursor. Mode Mouse Relatif telah dinonaktifkan."),
|
||||
("rel-mouse-exit-{}-tip", "Tekan {} untuk keluar."),
|
||||
("rel-mouse-permission-lost-tip", "Izin keyboard dicabut. Mode Mouse Relatif telah dinonaktifkan."),
|
||||
("Changelog", "Catatan perubahan"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Jaga layar tetap menyala selama sesi keluar"),
|
||||
("keep-awake-during-incoming-sessions-label", "Jaga layar tetap menyala selama sesi masuk"),
|
||||
("Continue with {}", "Lanjutkan dengan {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Nama Tampilan"),
|
||||
("password-hidden-tip", "Kata sandi permanen telah disetel (tersembunyi)."),
|
||||
("preset-password-in-use-tip", "Kata sandi pra-setel sedang digunakan."),
|
||||
("Enable privacy mode", "Aktifkan mode privasi"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Izinkan penambatan bilah alat jarak jauh ke tepi jendela mana pun"),
|
||||
("API Token", "Token API"),
|
||||
("Deploy", "Terapkan"),
|
||||
("Custom ID (optional)", "ID Kustom (opsional)"),
|
||||
("server_requires_deployment_tip", "Server memerlukan perangkat ini diterapkan secara eksplisit. Terapkan sekarang?"),
|
||||
("The server does not require explicit deployment.", "Server tidak memerlukan penerapan eksplisit."),
|
||||
("Unknown response.", "Respons tidak dikenal."),
|
||||
("wayland-keyboard-input-disabled-tip", "Izinkan masukan keyboard?"),
|
||||
("wayland-keyboard-input-consent-tip", "Apa yang Anda ketik di komputer jarak jauh ini (termasuk kata sandi) dapat dibaca oleh aplikasi lain di dalamnya."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Pilihan ini berlaku untuk:"),
|
||||
("wayland-soft-keyboard-input-label", "Masukan keyboard lunak"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Setel ulang pilihan masukan keyboard"),
|
||||
("remember-wayland-keyboard-choice-tip", "Jangan tanya lagi untuk komputer jarak jauh ini"),
|
||||
("Why this happens", "Mengapa ini terjadi"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "Visualizza nome"),
|
||||
("password-hidden-tip", "È impostata una password permanente (nascosta)."),
|
||||
("preset-password-in-use-tip", "È attualmente in uso la password preimpostata."),
|
||||
("Enable privacy mode", "Abilita modalità privacy"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Consenti ancoraggio barra strumenti remota a qualsiasi bordo della finestra"),
|
||||
("API Token", "Token API"),
|
||||
("Deploy", "Distribuisci"),
|
||||
("Custom ID (optional)", "ID personale (opzionale)"),
|
||||
("server_requires_deployment_tip", "Il server richiede che questo dispositivo venga distribuito in modo esplicito.\nVuoi distribuirlo?"),
|
||||
("The server does not require explicit deployment.", "Il server non richiede una distribuzione esplicita."),
|
||||
("Unknown response.", "Risposta sconosciuta"),
|
||||
("wayland-keyboard-input-disabled-tip", "Vuoi consentire l'input da tastiera?"),
|
||||
("wayland-keyboard-input-consent-tip", "Ciò che digiti in questo computer remoto (comprese le password) potrebbe essere letto da altre app presenti nel computer remoto."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Questa scelta si applica a:"),
|
||||
("wayland-soft-keyboard-input-label", "Inserimento tramite tastiera soft"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Ripristina scelta input da tastiera"),
|
||||
("remember-wayland-keyboard-choice-tip", "Non chiedere più per questo computer remoto"),
|
||||
("Why this happens", "Perché accade questo"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "画面共有"),
|
||||
("ubuntu-21-04-required", "Wayland を使用するには、Ubuntu 21.04 以降のバージョンが必要です。"),
|
||||
("wayland-requires-higher-linux-version", "Wayland を使用するには、より新しい Linux ディストリビューションが必要です。 X11 デスクトップを試すか、OS を変更してください。"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland の画面キャプチャに失敗しました。XDG Desktop Portal がクラッシュしたか、利用できない可能性があります。`systemctl --user restart xdg-desktop-portal` で再起動してみてください。"),
|
||||
("JumpLink", "表示"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "共有する画面を選択してください(リモートコンピューターが操作します)"),
|
||||
("Show RustDesk", "RustDesk を表示"),
|
||||
@@ -739,9 +739,24 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Changelog", "更新履歴"),
|
||||
("keep-awake-during-outgoing-sessions-label", "送信セッション中は、画面のスリープを無効化する"),
|
||||
("keep-awake-during-incoming-sessions-label", "受信セッション中は、画面のスリープを無効化する"),
|
||||
("Continue with {}", "{}で続行する"),
|
||||
("Continue with {}", "{} で続行する"),
|
||||
("Display Name", "表示名"),
|
||||
("password-hidden-tip", "永続的なパスワードが設定されています (非表示)"),
|
||||
("preset-password-in-use-tip", "プリセットパスワードが現在使用されています"),
|
||||
("Enable privacy mode", "プライバシーモードを有効化する"),
|
||||
("allow-remote-toolbar-docking-any-edge", "リモートツールバーをウィンドウの任意の端にドッキングすることを許可する"),
|
||||
("API Token", "API トークン"),
|
||||
("Deploy", "デプロイ"),
|
||||
("Custom ID (optional)", "カスタム ID(任意)"),
|
||||
("server_requires_deployment_tip", "このデバイスをサーバーに明示的にデプロイする必要があります。今すぐデプロイしますか?"),
|
||||
("The server does not require explicit deployment.", "このサーバーは明示的なデプロイを必要としません。"),
|
||||
("Unknown response.", "不明な応答です。"),
|
||||
("wayland-keyboard-input-disabled-tip", "キーボード入力を許可しますか?"),
|
||||
("wayland-keyboard-input-consent-tip", "このリモートコンピューターで入力した内容(パスワードを含む)は、そのコンピューター上の他のアプリに読み取られる可能性があります。"),
|
||||
("wayland-keyboard-input-applies-to-tip", "この選択が適用される対象:"),
|
||||
("wayland-soft-keyboard-input-label", "ソフトウェアキーボード入力"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "キーボード入力の選択をリセット"),
|
||||
("remember-wayland-keyboard-choice-tip", "このリモートコンピューターでは今後確認しない"),
|
||||
("Why this happens", "この問題が起こる理由"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "화면 공유"),
|
||||
("ubuntu-21-04-required", "Wayland는 Ubuntu 21.04 이상 버전이 필요합니다."),
|
||||
("wayland-requires-higher-linux-version", "Wayland는 상위 버전의 Linux 배포판이 필요합니다. X11 데스크탑을 사용하거나 OS를 변경하세요."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland 화면 캡처에 실패했습니다. XDG Desktop Portal이 충돌했거나 사용할 수 없는 상태일 수 있습니다. `systemctl --user restart xdg-desktop-portal` 명령으로 다시 시작해 보세요."),
|
||||
("JumpLink", "점프 링크"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "공유할 화면을 선택하세요 (피어 측에서 작동)"),
|
||||
("Show RustDesk", "RustDesk 표시"),
|
||||
@@ -743,5 +743,20 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Display Name", "표시 이름"),
|
||||
("password-hidden-tip", "영구 비밀번호가 설정되었습니다 (숨김)."),
|
||||
("preset-password-in-use-tip", "현재 사전 설정된 비밀번호가 사용 중입니다."),
|
||||
("Enable privacy mode", "개인정보 보호 모드 사용함"),
|
||||
("allow-remote-toolbar-docking-any-edge", "원격 도구 모음을 창 가장자리에 도킹 허용"),
|
||||
("API Token", "API 토큰"),
|
||||
("Deploy", "배포"),
|
||||
("Custom ID (optional)", "사용자 지정 ID (선택 사항)"),
|
||||
("server_requires_deployment_tip", "서버에서 이 장치를 명시적으로 배포하도록 요구합니다. 지금 배포하시겠습니까?"),
|
||||
("The server does not require explicit deployment.", "서버에서 명시적인 배포를 요구하지 않습니다."),
|
||||
("Unknown response.", "알 수 없는 응답입니다."),
|
||||
("wayland-keyboard-input-disabled-tip", "키보드 입력을 허용하시겠습니까?"),
|
||||
("wayland-keyboard-input-consent-tip", "이 원격 컴퓨터에서 입력하는 내용(비밀번호 포함)은 해당 컴퓨터의 다른 앱이 읽을 수 있습니다."),
|
||||
("wayland-keyboard-input-applies-to-tip", "이 선택이 적용되는 대상:"),
|
||||
("wayland-soft-keyboard-input-label", "소프트 키보드 입력"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "키보드 입력 선택 초기화"),
|
||||
("remember-wayland-keyboard-choice-tip", "이 원격 컴퓨터에 대해 다시 묻지 않기"),
|
||||
("Why this happens", "이런 현상이 발생하는 이유"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
885
src/lang/kz.rs
885
src/lang/kz.rs
@@ -30,26 +30,26 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("IP Whitelisting", "IP Ақ-тізімі"),
|
||||
("ID/Relay Server", "ID/Relay сербері"),
|
||||
("Import server config", "Серверді импорттау"),
|
||||
("Export Server Config", ""),
|
||||
("Export Server Config", "Сербер конфигурациясын экспорттау"),
|
||||
("Import server configuration successfully", "Сервердің конфигурациясы сәтті импортталды"),
|
||||
("Export server configuration successfully", ""),
|
||||
("Export server configuration successfully", "Сербердің конфигурациясы сәтті экспортталды"),
|
||||
("Invalid server configuration", "Жарамсыз сервердің конфигурациясы"),
|
||||
("Clipboard is empty", "Көшіру-тақта бос"),
|
||||
("Stop service", "Сербесті тоқтату"),
|
||||
("Change ID", "ID ауыстыру"),
|
||||
("Your new ID", ""),
|
||||
("length %min% to %max%", ""),
|
||||
("starts with a letter", ""),
|
||||
("allowed characters", ""),
|
||||
("Your new ID", "Сіздің жаңа ID"),
|
||||
("length %min% to %max%", "ұзындығы %min% мен %max% арасы"),
|
||||
("starts with a letter", "әріптен басталады"),
|
||||
("allowed characters", "рұқсат етілген таңбалар"),
|
||||
("id_change_tip", "Тек a-z, A-Z, 0-9, - (dash) және _ (астынғы-сызық) таңбалары рұқсат етілген. Бірінші таңба a-z, A-Z болуы қажет. Ұзындығы 6 мен 16 арасы."),
|
||||
("Website", "Web-сайт"),
|
||||
("About", "Туралы"),
|
||||
("Slogan_tip", ""),
|
||||
("Privacy Statement", ""),
|
||||
("Slogan_tip", "Осы бей-берекет әлемде жүрекпен жасалған!"),
|
||||
("Privacy Statement", "Құпиялылық туралы мәлімдеме"),
|
||||
("Mute", "Дыбыссыздандыру"),
|
||||
("Build Date", ""),
|
||||
("Version", ""),
|
||||
("Home", ""),
|
||||
("Build Date", "Құрастырылған күні"),
|
||||
("Version", "Нұсқа"),
|
||||
("Home", "Басты бет"),
|
||||
("Audio Input", "Аудио Еңгізу"),
|
||||
("Enhancements", "Жақсартулар"),
|
||||
("Hardware Codec", "Hardware Codec"),
|
||||
@@ -98,8 +98,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Delete", "Жою"),
|
||||
("Properties", "Қасиеттер"),
|
||||
("Multi Select", "Көптік таңдау"),
|
||||
("Select All", ""),
|
||||
("Unselect All", ""),
|
||||
("Select All", "Барлығын таңдау"),
|
||||
("Unselect All", "Барлық таңдауды алып тастау"),
|
||||
("Empty Directory", "Бос Бума"),
|
||||
("Not an empty directory", "Бос бума емес"),
|
||||
("Are you sure you want to delete this file?", "Бұл файылды жоюға сенімдісіз бе?"),
|
||||
@@ -125,7 +125,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Good image quality", "Жақсы сурет сапасы"),
|
||||
("Balanced", "Теңдестірілген"),
|
||||
("Optimize reaction time", "Реакция уақытын оңтайландыру"),
|
||||
("Custom", ""),
|
||||
("Custom", "Теңшеулі"),
|
||||
("Show remote cursor", "Қашықтағы курсорды көрсету"),
|
||||
("Show quality monitor", "Сапа мониторын көрсету"),
|
||||
("Disable clipboard", "Көшіру-тақтасын өшіру"),
|
||||
@@ -168,8 +168,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Action", "Әрекет"),
|
||||
("Add", "Қосу"),
|
||||
("Local Port", "Лақал Порт"),
|
||||
("Local Address", ""),
|
||||
("Change Local Port", ""),
|
||||
("Local Address", "Лақал мекенжай"),
|
||||
("Change Local Port", "Лақал портты өзгерту"),
|
||||
("setup_server_tip", "Тез қосылым үшін өз серберіңізді орнатуды өтінеміз"),
|
||||
("Too short, at least 6 characters.", "Тым қысқа, кемінде 6 таңба."),
|
||||
("The confirmation is not identical.", "Растау сәйкес келмейді."),
|
||||
@@ -208,15 +208,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the peer", "Пир қолымен жабылған"),
|
||||
("Enable remote configuration modification", "Қашықтан қалыптарды өзгертуді іске қосу"),
|
||||
("Run without install", "Орнатпай-ақ Іске қосу"),
|
||||
("Connect via relay", ""),
|
||||
("Connect via relay", "Релай арқылы қосылу"),
|
||||
("Always connect via relay", "Әрқашан да релай сербері арқылы қосылу"),
|
||||
("whitelist_tip", "Маған тек ақ-тізімделген IP қол жеткізе алады"),
|
||||
("Login", "Кіру"),
|
||||
("Verify", ""),
|
||||
("Remember me", ""),
|
||||
("Trust this device", ""),
|
||||
("Verification code", ""),
|
||||
("verification_tip", ""),
|
||||
("Verify", "Тексеру"),
|
||||
("Remember me", "Мені есте сақтау"),
|
||||
("Trust this device", "Бұл құрылғыға сену"),
|
||||
("Verification code", "Тексеру коды"),
|
||||
("verification_tip", "Тіркелген эл. пошта мекенжайына тексеру коды жіберілді, кіруді жалғастыру үшін тексеру кодын еңгізіңіз."),
|
||||
("Logout", "Шығу"),
|
||||
("Tags", "Тақтар"),
|
||||
("Search ID", "ID Іздеу"),
|
||||
@@ -228,7 +228,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Username missed", "Қолданушы аты бос"),
|
||||
("Password missed", "Құпия сөз бос"),
|
||||
("Wrong credentials", "Бұрыс тіркелгі деректер"),
|
||||
("The verification code is incorrect or has expired", ""),
|
||||
("The verification code is incorrect or has expired", "Тексеру коды бұрыс немесе мерзімі өтіп кеткен"),
|
||||
("Edit Tag", "Тақты Өндеу"),
|
||||
("Forget Password", "Құпия сөзді Ұмыту"),
|
||||
("Favorites", "Таңдаулылар"),
|
||||
@@ -282,8 +282,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("android_service_will_start_tip", "\"Екіренді Тұсіру\" қосылған кезде сербес аутыматты іске қосылып, басқа құрылғыларға сіздің құрылғыға қосылым сұраныстауға мүмкіндің береді."),
|
||||
("android_stop_service_tip", "Сербесті жабу аутыматты түрде барлық орнатылған қосылымдарды жабады."),
|
||||
("android_version_audio_tip", "Ағымдағы Android нұсқасы аудионы түсіруді қолдамайды, Android 10 не жоғарғысына жаңғыртуды өтінеміз."),
|
||||
("android_start_service_tip", ""),
|
||||
("android_permission_may_not_change_tip", ""),
|
||||
("android_start_service_tip", "Экранды бөлісу сербесін іске қосу үшін [Сербесті іске қосу]'ды түртіңіз немесе [Екіренді Түсіру] рұқсатын қосыңыз."),
|
||||
("android_permission_may_not_change_tip", "Орнатылған қосылымдар үшін рұқсаттар қайта қосылғанша бірден өзгермеуі мүмкін."),
|
||||
("Account", "Есепкі"),
|
||||
("Overwrite", "Үстінен қайта жазу"),
|
||||
("This file exists, skip or overwrite this file?", "Бұл файыл бар, өткізіп жіберу әлде үстінен қайта жазу керек пе?"),
|
||||
@@ -302,12 +302,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Keep RustDesk background service", "Артжақтағы RustDesk сербесін сақтап тұру"),
|
||||
("Ignore Battery Optimizations", "Бәтері Оңтайландыруларын Елемеу"),
|
||||
("android_open_battery_optimizations_tip", "Егер де бұл ерекшелікті өшіруді қаласаңыз, келесі RustDesk апылқат орнатпалары бетіне барып, [Бәтері]'ні тауып кіріңіз де [Шектеусіз]'ден құсбелгіні алып тастауды өтінеміз"),
|
||||
("Start on boot", ""),
|
||||
("Start the screen sharing service on boot, requires special permissions", ""),
|
||||
("Start on boot", "Бут кезінде іске қосу"),
|
||||
("Start the screen sharing service on boot, requires special permissions", "Экранды бөлісу сербесін бут кезінде іске қосу, арнайы рұқсаттарды қажет етеді"),
|
||||
("Connection not allowed", "Қосылу рұқсат етілмеген"),
|
||||
("Legacy mode", ""),
|
||||
("Map mode", ""),
|
||||
("Translate mode", ""),
|
||||
("Legacy mode", "Ескі мода"),
|
||||
("Map mode", "Карта модасы"),
|
||||
("Translate mode", "Аудару модасы"),
|
||||
("Use permanent password", "Тұрақты құпия сөзді қолдану"),
|
||||
("Use both passwords", "Қос құпия сөзді қолдану"),
|
||||
("Set permanent password", "Тұрақты құпия сөзді орнату"),
|
||||
@@ -326,422 +326,437 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Ratio", "Арақатынас"),
|
||||
("Image Quality", "Сурет Сапасы"),
|
||||
("Scroll Style", "Scroll Теңшетұрі"),
|
||||
("Show Toolbar", ""),
|
||||
("Hide Toolbar", ""),
|
||||
("Show Toolbar", "Құралдар тақтасын көрсету"),
|
||||
("Hide Toolbar", "Құралдар тақтасын жасыру"),
|
||||
("Direct Connection", "Тікелей Қосылым"),
|
||||
("Relay Connection", "Релай Қосылым"),
|
||||
("Secure Connection", "Қауіпсіз Қосылым"),
|
||||
("Insecure Connection", "Қатерлі Қосылым"),
|
||||
("Scale original", "Scale original"),
|
||||
("Scale adaptive", "Scale adaptive"),
|
||||
("General", ""),
|
||||
("Security", ""),
|
||||
("Theme", ""),
|
||||
("Dark Theme", ""),
|
||||
("Light Theme", ""),
|
||||
("Dark", ""),
|
||||
("Light", ""),
|
||||
("Follow System", ""),
|
||||
("Enable hardware codec", ""),
|
||||
("Unlock Security Settings", ""),
|
||||
("Enable audio", ""),
|
||||
("Unlock Network Settings", ""),
|
||||
("Server", ""),
|
||||
("Direct IP Access", ""),
|
||||
("Proxy", ""),
|
||||
("Apply", ""),
|
||||
("Disconnect all devices?", ""),
|
||||
("Clear", ""),
|
||||
("Audio Input Device", ""),
|
||||
("Use IP Whitelisting", ""),
|
||||
("Network", ""),
|
||||
("Pin Toolbar", ""),
|
||||
("Unpin Toolbar", ""),
|
||||
("Recording", ""),
|
||||
("Directory", ""),
|
||||
("Automatically record incoming sessions", ""),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Change", ""),
|
||||
("Start session recording", ""),
|
||||
("Stop session recording", ""),
|
||||
("Enable recording session", ""),
|
||||
("Enable LAN discovery", ""),
|
||||
("Deny LAN discovery", ""),
|
||||
("Write a message", ""),
|
||||
("Prompt", ""),
|
||||
("Please wait for confirmation of UAC...", ""),
|
||||
("elevated_foreground_window_tip", ""),
|
||||
("Disconnected", ""),
|
||||
("Other", ""),
|
||||
("Confirm before closing multiple tabs", ""),
|
||||
("Keyboard Settings", ""),
|
||||
("Full Access", ""),
|
||||
("Screen Share", ""),
|
||||
("General", "Жалпы"),
|
||||
("Security", "Қауіпсіздік"),
|
||||
("Theme", "Тақырып"),
|
||||
("Dark Theme", "Қараңғы тақырып"),
|
||||
("Light Theme", "Ашық тақырып"),
|
||||
("Dark", "Қараңғы"),
|
||||
("Light", "Ашық"),
|
||||
("Follow System", "Жүйеге еру"),
|
||||
("Enable hardware codec", "Hardware codec'ті қосу"),
|
||||
("Unlock Security Settings", "Қауіпсіздік орнатпаларын құлыптан шығару"),
|
||||
("Enable audio", "Аудионы қосу"),
|
||||
("Unlock Network Settings", "Желі орнатпаларын құлыптан шығару"),
|
||||
("Server", "Сербер"),
|
||||
("Direct IP Access", "Тікелей IP қолжетімділік"),
|
||||
("Proxy", "Proxy"),
|
||||
("Apply", "Қолдану"),
|
||||
("Disconnect all devices?", "Барлық құрылғыларды ажырату керек пе?"),
|
||||
("Clear", "Тазалау"),
|
||||
("Audio Input Device", "Аудио еңгізу құрылғысы"),
|
||||
("Use IP Whitelisting", "IP ақ-тізімін қолдану"),
|
||||
("Network", "Желі"),
|
||||
("Pin Toolbar", "Құралдар тақтасын бекіту"),
|
||||
("Unpin Toolbar", "Құралдар тақтасын бекітуден шығару"),
|
||||
("Recording", "Жазу"),
|
||||
("Directory", "Бума"),
|
||||
("Automatically record incoming sessions", "Кіріс сештерді аутыматты түрде жазу"),
|
||||
("Automatically record outgoing sessions", "Шығыс сештерді аутыматты түрде жазу"),
|
||||
("Change", "Өзгерту"),
|
||||
("Start session recording", "Сешті жазуды бастау"),
|
||||
("Stop session recording", "Сешті жазуды тоқтату"),
|
||||
("Enable recording session", "Сешті жазуды іске қосу"),
|
||||
("Enable LAN discovery", "LAN табуды іске қосу"),
|
||||
("Deny LAN discovery", "LAN табуға тыйым салу"),
|
||||
("Write a message", "Хабарлама жазу"),
|
||||
("Prompt", "Сұрау"),
|
||||
("Please wait for confirmation of UAC...", "UAC растауын күтуді өтінеміз..."),
|
||||
("elevated_foreground_window_tip", "Қашықтағы жұмыс үстелінің ағымдағы терезесі жұмыс істеу үшін жоғарырақ артықшылықты қажет етеді, сондықтан тінтуір мен пернетақтаны уақытша қолдану мүмкін емес. Қашықтағы қолданушыдан ағымдағы терезені кішірейтуді сұрауыңызға немесе қосылымды басқару терезесіндегі артықшылықты көтеру батырмасын басуыңызға болады. Бұл мәселені болдырмау үшін, апылқатты қашықтағы құрылғыға орнату ұсынылады."),
|
||||
("Disconnected", "Ажыратылды"),
|
||||
("Other", "Басқа"),
|
||||
("Confirm before closing multiple tabs", "Бірнеше бөлімшені жабудан бұрын растау"),
|
||||
("Keyboard Settings", "Пернетақта орнатпалары"),
|
||||
("Full Access", "Толық қолжетімділік"),
|
||||
("Screen Share", "Екіренді бөлісу"),
|
||||
("ubuntu-21-04-required", "Wayland Ubuntu 21.04 немесе одан жоғары нұсқасын қажет етеді."),
|
||||
("wayland-requires-higher-linux-version", "Wayland linux дистрибутивінің жоғарырақ нұсқасын қажет етеді. X11 жұмыс үстелін қолданып көріңіз немесе операциялық жүйеңізді өзгертіңіз."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Wayland экранды түсіру сәтсіз болды. XDG Desktop Portal құлаған немесе қолжетімсіз болуы мүмкін. Оны `systemctl --user restart xdg-desktop-portal` арқылы қайта қосып көріңіз."),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Бөлісетін экранды таңдаңыз (бірдей жағынан жұмыс жасаңыз)."),
|
||||
("Show RustDesk", ""),
|
||||
("This PC", ""),
|
||||
("or", ""),
|
||||
("Elevate", ""),
|
||||
("Zoom cursor", ""),
|
||||
("Accept sessions via password", ""),
|
||||
("Accept sessions via click", ""),
|
||||
("Accept sessions via both", ""),
|
||||
("Please wait for the remote side to accept your session request...", ""),
|
||||
("One-time Password", ""),
|
||||
("Use one-time password", ""),
|
||||
("One-time password length", ""),
|
||||
("Request access to your device", ""),
|
||||
("Hide connection management window", ""),
|
||||
("hide_cm_tip", ""),
|
||||
("wayland_experiment_tip", ""),
|
||||
("Right click to select tabs", ""),
|
||||
("Skipped", ""),
|
||||
("Add to address book", ""),
|
||||
("Group", ""),
|
||||
("Search", ""),
|
||||
("Closed manually by web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
("config_microphone", ""),
|
||||
("request_elevation_tip", ""),
|
||||
("Wait", ""),
|
||||
("Elevation Error", ""),
|
||||
("Ask the remote user for authentication", ""),
|
||||
("Choose this if the remote account is administrator", ""),
|
||||
("Transmit the username and password of administrator", ""),
|
||||
("still_click_uac_tip", ""),
|
||||
("Request Elevation", ""),
|
||||
("wait_accept_uac_tip", ""),
|
||||
("Elevate successfully", ""),
|
||||
("uppercase", ""),
|
||||
("lowercase", ""),
|
||||
("digit", ""),
|
||||
("special character", ""),
|
||||
("length>=8", ""),
|
||||
("Weak", ""),
|
||||
("Medium", ""),
|
||||
("Strong", ""),
|
||||
("Switch Sides", ""),
|
||||
("Please confirm if you want to share your desktop?", ""),
|
||||
("Display", ""),
|
||||
("Default View Style", ""),
|
||||
("Default Scroll Style", ""),
|
||||
("Default Image Quality", ""),
|
||||
("Default Codec", ""),
|
||||
("Bitrate", ""),
|
||||
("FPS", ""),
|
||||
("Auto", ""),
|
||||
("Other Default Options", ""),
|
||||
("Voice call", ""),
|
||||
("Text chat", ""),
|
||||
("Stop voice call", ""),
|
||||
("relay_hint_tip", ""),
|
||||
("Reconnect", ""),
|
||||
("Codec", ""),
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
("New Connection", ""),
|
||||
("Restore", ""),
|
||||
("Minimize", ""),
|
||||
("Maximize", ""),
|
||||
("Your Device", ""),
|
||||
("empty_recent_tip", ""),
|
||||
("empty_favorite_tip", ""),
|
||||
("empty_lan_tip", ""),
|
||||
("empty_address_book_tip", ""),
|
||||
("Empty Username", ""),
|
||||
("Empty Password", ""),
|
||||
("Me", ""),
|
||||
("identical_file_tip", ""),
|
||||
("show_monitors_tip", ""),
|
||||
("View Mode", ""),
|
||||
("login_linux_tip", ""),
|
||||
("verify_rustdesk_password_tip", ""),
|
||||
("remember_account_tip", ""),
|
||||
("os_account_desk_tip", ""),
|
||||
("OS Account", ""),
|
||||
("another_user_login_title_tip", ""),
|
||||
("another_user_login_text_tip", ""),
|
||||
("xorg_not_found_title_tip", ""),
|
||||
("xorg_not_found_text_tip", ""),
|
||||
("no_desktop_title_tip", ""),
|
||||
("no_desktop_text_tip", ""),
|
||||
("No need to elevate", ""),
|
||||
("System Sound", ""),
|
||||
("Default", ""),
|
||||
("New RDP", ""),
|
||||
("Fingerprint", ""),
|
||||
("Copy Fingerprint", ""),
|
||||
("no fingerprints", ""),
|
||||
("Select a peer", ""),
|
||||
("Select peers", ""),
|
||||
("Plugins", ""),
|
||||
("Uninstall", ""),
|
||||
("Update", ""),
|
||||
("Enable", ""),
|
||||
("Disable", ""),
|
||||
("Options", ""),
|
||||
("resolution_original_tip", ""),
|
||||
("resolution_fit_local_tip", ""),
|
||||
("resolution_custom_tip", ""),
|
||||
("Collapse toolbar", ""),
|
||||
("Accept and Elevate", ""),
|
||||
("accept_and_elevate_btn_tooltip", ""),
|
||||
("clipboard_wait_response_timeout_tip", ""),
|
||||
("Incoming connection", ""),
|
||||
("Outgoing connection", ""),
|
||||
("Exit", ""),
|
||||
("Open", ""),
|
||||
("logout_tip", ""),
|
||||
("Service", ""),
|
||||
("Start", ""),
|
||||
("Stop", ""),
|
||||
("exceed_max_devices", ""),
|
||||
("Sync with recent sessions", ""),
|
||||
("Sort tags", ""),
|
||||
("Open connection in new tab", ""),
|
||||
("Move tab to new window", ""),
|
||||
("Can not be empty", ""),
|
||||
("Already exists", ""),
|
||||
("Change Password", ""),
|
||||
("Refresh Password", ""),
|
||||
("ID", ""),
|
||||
("Grid View", ""),
|
||||
("List View", ""),
|
||||
("Select", ""),
|
||||
("Toggle Tags", ""),
|
||||
("pull_ab_failed_tip", ""),
|
||||
("push_ab_failed_tip", ""),
|
||||
("synced_peer_readded_tip", ""),
|
||||
("Change Color", ""),
|
||||
("Primary Color", ""),
|
||||
("HSV Color", ""),
|
||||
("Installation Successful!", ""),
|
||||
("Installation failed!", ""),
|
||||
("Reverse mouse wheel", ""),
|
||||
("{} sessions", ""),
|
||||
("scam_title", ""),
|
||||
("scam_text1", ""),
|
||||
("scam_text2", ""),
|
||||
("Don't show again", ""),
|
||||
("I Agree", ""),
|
||||
("Decline", ""),
|
||||
("Timeout in minutes", ""),
|
||||
("auto_disconnect_option_tip", ""),
|
||||
("Connection failed due to inactivity", ""),
|
||||
("Check for software update on startup", ""),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", ""),
|
||||
("pull_group_failed_tip", ""),
|
||||
("Filter by intersection", ""),
|
||||
("Remove wallpaper during incoming sessions", ""),
|
||||
("Test", ""),
|
||||
("display_is_plugged_out_msg", ""),
|
||||
("No displays", ""),
|
||||
("Open in new window", ""),
|
||||
("Show displays as individual windows", ""),
|
||||
("Use all my displays for the remote session", ""),
|
||||
("selinux_tip", ""),
|
||||
("Change view", ""),
|
||||
("Big tiles", ""),
|
||||
("Small tiles", ""),
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color (4:4:4)", ""),
|
||||
("Enable blocking user input", ""),
|
||||
("id_input_tip", ""),
|
||||
("privacy_mode_impl_mag_tip", ""),
|
||||
("privacy_mode_impl_virtual_display_tip", ""),
|
||||
("Enter privacy mode", ""),
|
||||
("Exit privacy mode", ""),
|
||||
("idd_not_support_under_win10_2004_tip", ""),
|
||||
("input_source_1_tip", ""),
|
||||
("input_source_2_tip", ""),
|
||||
("Swap control-command key", ""),
|
||||
("swap-left-right-mouse", ""),
|
||||
("2FA code", ""),
|
||||
("More", ""),
|
||||
("enable-2fa-title", ""),
|
||||
("enable-2fa-desc", ""),
|
||||
("wrong-2fa-code", ""),
|
||||
("enter-2fa-title", ""),
|
||||
("Email verification code must be 6 characters.", ""),
|
||||
("2FA code must be 6 digits.", ""),
|
||||
("Multiple Windows sessions found", ""),
|
||||
("Please select the session you want to connect to", ""),
|
||||
("powered_by_me", ""),
|
||||
("outgoing_only_desk_tip", ""),
|
||||
("preset_password_warning", ""),
|
||||
("Security Alert", ""),
|
||||
("My address book", ""),
|
||||
("Personal", ""),
|
||||
("Owner", ""),
|
||||
("Set shared password", ""),
|
||||
("Exist in", ""),
|
||||
("Read-only", ""),
|
||||
("Read/Write", ""),
|
||||
("Full Control", ""),
|
||||
("share_warning_tip", ""),
|
||||
("Everyone", ""),
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Clear Wayland screen selection", ""),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("Use texture rendering", ""),
|
||||
("Floating window", ""),
|
||||
("floating_window_tip", ""),
|
||||
("Keep screen on", ""),
|
||||
("Never", ""),
|
||||
("During controlled", ""),
|
||||
("During service is on", ""),
|
||||
("Capture screen using DirectX", ""),
|
||||
("Back", ""),
|
||||
("Apps", ""),
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("Show RustDesk", "RustDesk'ті көрсету"),
|
||||
("This PC", "Бұл ДК"),
|
||||
("or", "немесе"),
|
||||
("Elevate", "Артықшылықты көтеру"),
|
||||
("Zoom cursor", "Курсорды зумдау"),
|
||||
("Accept sessions via password", "Сештерді құпия сөз арқылы қабылдау"),
|
||||
("Accept sessions via click", "Сештерді шерту арқылы қабылдау"),
|
||||
("Accept sessions via both", "Сештерді екеуі арқылы да қабылдау"),
|
||||
("Please wait for the remote side to accept your session request...", "Қашықтағы жақтың сіздің сеш сұранысыңызды қабылдауын күтуді өтінеміз..."),
|
||||
("One-time Password", "Бір-реттік құпия сөз"),
|
||||
("Use one-time password", "Бір-реттік құпия сөзді қолдану"),
|
||||
("One-time password length", "Бір-реттік құпия сөздің ұзындығы"),
|
||||
("Request access to your device", "Құрылғыңызға қолжетімділік сұрау"),
|
||||
("Hide connection management window", "Қосылымды басқару терезесін жасыру"),
|
||||
("hide_cm_tip", "Тек сештерді құпия сөз арқылы қабылдағанда және тұрақты құпия сөзді қолданғанда ғана жасыруға рұқсат ету"),
|
||||
("wayland_experiment_tip", "Wayland қолдауы эксперименттік сатыда, қадағалаусыз қолжетімділік қажет болса X11 қолданыңыз."),
|
||||
("Right click to select tabs", "Бөлімшелерді таңдау үшін оң жақ батырмамен шертіңіз"),
|
||||
("Skipped", "Өткізіп жіберілді"),
|
||||
("Add to address book", "Мекенжай кітабына қосу"),
|
||||
("Group", "Топ"),
|
||||
("Search", "Іздеу"),
|
||||
("Closed manually by web console", "Web консоль арқылы қолмен жабылды"),
|
||||
("Local keyboard type", "Лақал пернетақта түрі"),
|
||||
("Select local keyboard type", "Лақал пернетақта түрін таңдау"),
|
||||
("software_render_tip", "Егер Linux астында Nvidia видеокартасын қолдансаңыз және қосылғаннан кейін қашықтағы терезе бірден жабылса, ашық бастапқы кодты Nouveau драйверіне ауысып, программалық рендерингті қолдануды таңдау көмектесуі мүмкін. Программаны қайта қосу қажет."),
|
||||
("Always use software rendering", "Әрқашан программалық рендерингті қолдану"),
|
||||
("config_input", "Қашықтағы жұмыс үстелін пернетақтамен басқару үшін, RustDesk'ке \"Еңгізуді Қадағалау\" рұқсаттарын беруіңіз керек."),
|
||||
("config_microphone", "Қашықтан сөйлесу үшін, RustDesk'ке \"Аудио Жазу\" рұқсаттарын беруіңіз керек."),
|
||||
("request_elevation_tip", "Қашықтағы жақта біреу болса, артықшылықты көтеруді де сұрауыңызға болады."),
|
||||
("Wait", "Күту"),
|
||||
("Elevation Error", "Артықшылықты көтеру қатесі"),
|
||||
("Ask the remote user for authentication", "Қашықтағы қолданушыдан аутентификация сұрау"),
|
||||
("Choose this if the remote account is administrator", "Қашықтағы есепкі әкімші болса, мұны таңдаңыз"),
|
||||
("Transmit the username and password of administrator", "Әкімшінің қолданушы аты мен құпия сөзін жіберу"),
|
||||
("still_click_uac_tip", "Қашықтағы қолданушыдан RustDesk іске қосылған UAC терезесінде OK басуды әлі де талап етеді."),
|
||||
("Request Elevation", "Артықшылықты көтеруді сұрау"),
|
||||
("wait_accept_uac_tip", "Қашықтағы қолданушының UAC диалогын қабылдауын күтуді өтінеміз."),
|
||||
("Elevate successfully", "Артықшылық сәтті көтерілді"),
|
||||
("uppercase", "бас әріп"),
|
||||
("lowercase", "кіші әріп"),
|
||||
("digit", "сан"),
|
||||
("special character", "арнайы таңба"),
|
||||
("length>=8", "ұзындығы>=8"),
|
||||
("Weak", "Әлсіз"),
|
||||
("Medium", "Орташа"),
|
||||
("Strong", "Күшті"),
|
||||
("Switch Sides", "Жақтарды ауыстыру"),
|
||||
("Please confirm if you want to share your desktop?", "Жұмыс үстеліңізді бөліскіңіз келетінін растауды өтінеміз?"),
|
||||
("Display", "Дисплей"),
|
||||
("Default View Style", "Әдепкі көрініс теңшетұрі"),
|
||||
("Default Scroll Style", "Әдепкі scroll теңшетұрі"),
|
||||
("Default Image Quality", "Әдепкі сурет сапасы"),
|
||||
("Default Codec", "Әдепкі codec"),
|
||||
("Bitrate", "Bitrate"),
|
||||
("FPS", "FPS"),
|
||||
("Auto", "Ауты"),
|
||||
("Other Default Options", "Басқа әдепкі опциялар"),
|
||||
("Voice call", "Дауыстық қоңырау"),
|
||||
("Text chat", "Мәтіндік чат"),
|
||||
("Stop voice call", "Дауыстық қоңырауды тоқтату"),
|
||||
("relay_hint_tip", "Тікелей қосылу мүмкін болмауы мүмкін; релай арқылы қосылып көруіңізге болады. Сонымен қатар, бірінші әрекетте релайды қолданғыңыз келсе, ID-ге \"/r\" жұрнағын қосуыңызға немесе соңғы сештер картасында бар болса \"Әрқашан да релай арқылы қосылу\" опциясын таңдауыңызға болады."),
|
||||
("Reconnect", "Қайта қосылу"),
|
||||
("Codec", "Codec"),
|
||||
("Resolution", "Ажыратымдылық"),
|
||||
("No transfers in progress", "Барысында тасымалдау жоқ"),
|
||||
("Set one-time password length", "Бір-реттік құпия сөздің ұзындығын орнату"),
|
||||
("RDP Settings", "RDP орнатпалары"),
|
||||
("Sort by", "Бойынша сұрыптау"),
|
||||
("New Connection", "Жаңа қосылым"),
|
||||
("Restore", "Қалпына келтіру"),
|
||||
("Minimize", "Кішірейту"),
|
||||
("Maximize", "Үлкейту"),
|
||||
("Your Device", "Сіздің құрылғыңыз"),
|
||||
("empty_recent_tip", "Ой, соңғы сештер жоқ!\nЖаңасын жоспарлайтын кез."),
|
||||
("empty_favorite_tip", "Әлі таңдаулы пирлер жоқ па?\nҚосылатын біреуді тауып, оны таңдаулыларыңызға қосайық!"),
|
||||
("empty_lan_tip", "О, біз әлі ешқандай пир таппаған сияқтымыз."),
|
||||
("empty_address_book_tip", "Қап, мекенжай кітабыңызда қазір тізімделген пирлер жоқ сияқты."),
|
||||
("Empty Username", "Бос қолданушы аты"),
|
||||
("Empty Password", "Бос құпия сөз"),
|
||||
("Me", "Мен"),
|
||||
("identical_file_tip", "Бұл файыл пирдікімен бірдей."),
|
||||
("show_monitors_tip", "Мониторларды құралдар тақтасында көрсету"),
|
||||
("View Mode", "Көру модасы"),
|
||||
("login_linux_tip", "X жұмыс үстелі сешін іске қосу үшін қашықтағы Linux есепкісіне кіруіңіз керек"),
|
||||
("verify_rustdesk_password_tip", "RustDesk құпия сөзін тексеру"),
|
||||
("remember_account_tip", "Бұл есепкіні есте сақтау"),
|
||||
("os_account_desk_tip", "Бұл есепкі қашықтағы OS-қа кіру және headless режимде жұмыс үстелі сешін іске қосу үшін қолданылады"),
|
||||
("OS Account", "OS есепкісі"),
|
||||
("another_user_login_title_tip", "Басқа қолданушы әлдеқашан кіріп қойған"),
|
||||
("another_user_login_text_tip", "Ажырату"),
|
||||
("xorg_not_found_title_tip", "Xorg табылмады"),
|
||||
("xorg_not_found_text_tip", "Xorg орнатуды өтінеміз"),
|
||||
("no_desktop_title_tip", "Жұмыс үстелі ортасы қолжетімсіз"),
|
||||
("no_desktop_text_tip", "GNOME жұмыс үстелін орнатуды өтінеміз"),
|
||||
("No need to elevate", "Артықшылықты көтерудің қажеті жоқ"),
|
||||
("System Sound", "Жүйе дыбысы"),
|
||||
("Default", "Әдепкі"),
|
||||
("New RDP", "Жаңа RDP"),
|
||||
("Fingerprint", "Саусақ ізі"),
|
||||
("Copy Fingerprint", "Саусақ ізін көшіру"),
|
||||
("no fingerprints", "Саусақ іздері жоқ"),
|
||||
("Select a peer", "Пир таңдау"),
|
||||
("Select peers", "Пирлерді таңдау"),
|
||||
("Plugins", "Плагиндер"),
|
||||
("Uninstall", "Жою"),
|
||||
("Update", "Жаңарту"),
|
||||
("Enable", "Қосу"),
|
||||
("Disable", "Өшіру"),
|
||||
("Options", "Опциялар"),
|
||||
("resolution_original_tip", "Түпнұсқа ажыратымдылық"),
|
||||
("resolution_fit_local_tip", "Лақал ажыратымдылыққа сыйғызу"),
|
||||
("resolution_custom_tip", "Теңшеулі ажыратымдылық"),
|
||||
("Collapse toolbar", "Құралдар тақтасын жию"),
|
||||
("Accept and Elevate", "Қабылдау және Артықшылықты көтеру"),
|
||||
("accept_and_elevate_btn_tooltip", "Қосылымды қабылдап, UAC артықшылықтарын көтеру."),
|
||||
("clipboard_wait_response_timeout_tip", "Көшіру жауабын күту мерзімі өтіп кетті."),
|
||||
("Incoming connection", "Кіріс қосылым"),
|
||||
("Outgoing connection", "Шығыс қосылым"),
|
||||
("Exit", "Шығу"),
|
||||
("Open", "Ашу"),
|
||||
("logout_tip", "Шынымен шыққыңыз келе ме?"),
|
||||
("Service", "Сербес"),
|
||||
("Start", "Іске қосу"),
|
||||
("Stop", "Тоқтату"),
|
||||
("exceed_max_devices", "Сіз басқарылатын құрылғылардың ең көп санына жеттіңіз."),
|
||||
("Sync with recent sessions", "Соңғы сештермен синхрондау"),
|
||||
("Sort tags", "Тақтарды сұрыптау"),
|
||||
("Open connection in new tab", "Қосылымды жаңа бөлімшеде ашу"),
|
||||
("Move tab to new window", "Бөлімшені жаңа терезеге жылжыту"),
|
||||
("Can not be empty", "Бос бола алмайды"),
|
||||
("Already exists", "Әлдеқашан бар"),
|
||||
("Change Password", "Құпия сөзді өзгерту"),
|
||||
("Refresh Password", "Құпия сөзді жаңарту"),
|
||||
("ID", "ID"),
|
||||
("Grid View", "Тор көрінісі"),
|
||||
("List View", "Тізім көрінісі"),
|
||||
("Select", "Таңдау"),
|
||||
("Toggle Tags", "Тақтарды ауыстырып қосу"),
|
||||
("pull_ab_failed_tip", "Мекенжай кітабын жаңарту сәтсіз болды"),
|
||||
("push_ab_failed_tip", "Мекенжай кітабын серберге синхрондау сәтсіз болды"),
|
||||
("synced_peer_readded_tip", "Соңғы сештерде болған құрылғылар мекенжай кітабына қайта синхрондалады."),
|
||||
("Change Color", "Түсті өзгерту"),
|
||||
("Primary Color", "Негізгі түс"),
|
||||
("HSV Color", "HSV түсі"),
|
||||
("Installation Successful!", "Орнату сәтті болды!"),
|
||||
("Installation failed!", "Орнату сәтсіз болды!"),
|
||||
("Reverse mouse wheel", "Тінтуір дөңгелегін кері бұру"),
|
||||
("{} sessions", "{} сеш"),
|
||||
("scam_title", "Сіз АЛДАНУ ҮСТІНДЕ болуыңыз мүмкін!"),
|
||||
("scam_text1", "Егер сіз танымайтын ЖӘНЕ СЕНБЕЙТІН біреумен телефонмен сөйлесіп жатсаңыз және ол сізден RustDesk қолданып, сербесті іске қосуды сұраса, жалғастырмаңыз да дереу телефонды қойыңыз."),
|
||||
("scam_text2", "Олар сіздің ақшаңызды немесе басқа жеке ақпаратыңызды ұрлауға тырысатын алаяқ болуы ықтимал."),
|
||||
("Don't show again", "Қайта көрсетпеу"),
|
||||
("I Agree", "Келісемін"),
|
||||
("Decline", "Бас тарту"),
|
||||
("Timeout in minutes", "Минуттардағы үзіліс"),
|
||||
("auto_disconnect_option_tip", "Қолданушы әрекетсіз болғанда кіріс сештерді аутыматты түрде жабу"),
|
||||
("Connection failed due to inactivity", "Әрекетсіздіктен аутыматты түрде ажыратылды"),
|
||||
("Check for software update on startup", "Іске қосылғанда программа жаңартуын тексеру"),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", "RustDesk Server Pro'ны {} немесе одан жаңа нұсқаға жаңартуды өтінеміз!"),
|
||||
("pull_group_failed_tip", "Топты жаңарту сәтсіз болды"),
|
||||
("Filter by intersection", "Қиылысу бойынша сүзу"),
|
||||
("Remove wallpaper during incoming sessions", "Кіріс сештер кезінде тұсқағазды алып тастау"),
|
||||
("Test", "Сынау"),
|
||||
("display_is_plugged_out_msg", "Дисплей ажыратылды, бірінші дисплейге ауысу."),
|
||||
("No displays", "Дисплейлер жоқ"),
|
||||
("Open in new window", "Жаңа терезеде ашу"),
|
||||
("Show displays as individual windows", "Дисплейлерді жеке терезелер ретінде көрсету"),
|
||||
("Use all my displays for the remote session", "Қашықтағы сеш үшін барлық дисплейлерімді қолдану"),
|
||||
("selinux_tip", "Сіздің құрылғыңызда SELinux қосылған, бұл RustDesk'тің басқарылатын жақ ретінде дұрыс жұмыс істеуіне кедергі келтіруі мүмкін."),
|
||||
("Change view", "Көріністі өзгерту"),
|
||||
("Big tiles", "Үлкен тақтайшалар"),
|
||||
("Small tiles", "Кіші тақтайшалар"),
|
||||
("List", "Тізім"),
|
||||
("Virtual display", "Виртуалды дисплей"),
|
||||
("Plug out all", "Барлығын ажырату"),
|
||||
("True color (4:4:4)", "Шынайы түс (4:4:4)"),
|
||||
("Enable blocking user input", "Қолданушы еңгізуін бұғаттауды іске қосу"),
|
||||
("id_input_tip", "Сіз ID, тікелей IP немесе портпен домен (<domain>:<port>) еңгізуіңізге болады.\nБасқа сербердегі құрылғыға қол жеткізгіңіз келсе, сербер мекенжайын қосыңыз (<id>@<server_address>?key=<key_value>), мысалы,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЖария сербердегі құрылғыға қол жеткізгіңіз келсе, \"<id>@public\" еңгізіңіз, жария сербер үшін кілт қажет емес.\n\nБірінші қосылымда релай қосылымын мәжбүрлеп қолданғыңыз келсе, ID соңына \"/r\" қосыңыз, мысалы, \"9123456234/r\"."),
|
||||
("privacy_mode_impl_mag_tip", "1-мода"),
|
||||
("privacy_mode_impl_virtual_display_tip", "2-мода"),
|
||||
("Enter privacy mode", "Құпиялылық модасына кіру"),
|
||||
("Exit privacy mode", "Құпиялылық модасынан шығу"),
|
||||
("idd_not_support_under_win10_2004_tip", "Жанама дисплей драйверіне қолдау көрсетілмейді. Windows 10, нұсқа 2004 немесе одан жаңасы қажет."),
|
||||
("input_source_1_tip", "1-еңгізу көзі"),
|
||||
("input_source_2_tip", "2-еңгізу көзі"),
|
||||
("Swap control-command key", "control-command пернесін ауыстыру"),
|
||||
("swap-left-right-mouse", "Тінтуірдің сол-оң батырмасын ауыстыру"),
|
||||
("2FA code", "2FA коды"),
|
||||
("More", "Көбірек"),
|
||||
("enable-2fa-title", "Екі-факторлы аутентификацияны іске қосу"),
|
||||
("enable-2fa-desc", "Аутентификаторды қазір орнатуды өтінеміз. Телефоныңызда немесе жұмыс үстеліңізде Authy, Microsoft немесе Google Authenticator сияқты аутентификатор апылқатын қолдануыңызға болады.\n\nQR кодты апылқатыңызбен сканерлеп, екі-факторлы аутентификацияны іске қосу үшін апылқат көрсететін кодты еңгізіңіз."),
|
||||
("wrong-2fa-code", "Кодты тексеру мүмкін болмады. Код пен жергілікті уақыт орнатпаларының дұрыстығын тексеріңіз"),
|
||||
("enter-2fa-title", "Екі-факторлы аутентификация"),
|
||||
("Email verification code must be 6 characters.", "Эл. пошта тексеру коды 6 таңба болуы керек."),
|
||||
("2FA code must be 6 digits.", "2FA коды 6 сан болуы керек."),
|
||||
("Multiple Windows sessions found", "Бірнеше Windows сеші табылды"),
|
||||
("Please select the session you want to connect to", "Қосылғыңыз келетін сешті таңдауды өтінеміз"),
|
||||
("powered_by_me", "RustDesk негізінде"),
|
||||
("outgoing_only_desk_tip", "Бұл теңшелген басылым.\nСіз басқа құрылғыларға қосыла аласыз, бірақ басқа құрылғылар сіздің құрылғыңызға қосыла алмайды."),
|
||||
("preset_password_warning", "Бұл теңшелген басылым алдын ала орнатылған құпия сөзбен келеді. Бұл құпия сөзді білетін кез келген адам сіздің құрылғыңызды толық басқара алады. Егер мұны күтпеген болсаңыз, программаны дереу жойыңыз."),
|
||||
("Security Alert", "Қауіпсіздік ескертуі"),
|
||||
("My address book", "Менің мекенжай кітабым"),
|
||||
("Personal", "Жеке"),
|
||||
("Owner", "Иесі"),
|
||||
("Set shared password", "Ортақ құпия сөзді орнату"),
|
||||
("Exist in", "Мынада бар"),
|
||||
("Read-only", "Тек оқуға"),
|
||||
("Read/Write", "Оқу/Жазу"),
|
||||
("Full Control", "Толық басқару"),
|
||||
("share_warning_tip", "Жоғарыдағы өрістер ортақ және басқаларға көрінеді."),
|
||||
("Everyone", "Барлығы"),
|
||||
("ab_web_console_tip", "Web консольде көбірек"),
|
||||
("allow-only-conn-window-open-tip", "Тек RustDesk терезесі ашық болғанда ғана қосылымға рұқсат ету"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Физикалық дисплейлер жоқ, құпиялылық модасын қолданудың қажеті жоқ."),
|
||||
("Follow remote cursor", "Қашықтағы курсорға еру"),
|
||||
("Follow remote window focus", "Қашықтағы терезе фокусына еру"),
|
||||
("default_proxy_tip", "Әдепкі протокол мен порт Socks5 және 1080"),
|
||||
("no_audio_input_device_tip", "Аудио еңгізу құрылғысы табылмады."),
|
||||
("Incoming", "Кіріс"),
|
||||
("Outgoing", "Шығыс"),
|
||||
("Clear Wayland screen selection", "Wayland экран таңдауын тазалау"),
|
||||
("clear_Wayland_screen_selection_tip", "Экран таңдауын тазалағаннан кейін, бөлісетін экранды қайта таңдай аласыз."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Wayland экран таңдауын тазалауға сенімдісіз бе?"),
|
||||
("android_new_voice_call_tip", "Жаңа дауыстық қоңырау сұранысы келді. Қабылдасаңыз, аудио дауыстық байланысқа ауысады."),
|
||||
("texture_render_tip", "Суреттерді тегіс ету үшін текстуралық рендерингті қолданыңыз. Рендеринг мәселелеріне тап болсаңыз, бұл опцияны өшіріп көруіңізге болады."),
|
||||
("Use texture rendering", "Текстуралық рендерингті қолдану"),
|
||||
("Floating window", "Қалқымалы терезе"),
|
||||
("floating_window_tip", "Ол RustDesk артжақ сербесін сақтап тұруға көмектеседі"),
|
||||
("Keep screen on", "Экранды қосулы ұстау"),
|
||||
("Never", "Ешқашан"),
|
||||
("During controlled", "Басқарылу кезінде"),
|
||||
("During service is on", "Сербес қосулы кезінде"),
|
||||
("Capture screen using DirectX", "DirectX арқылы экранды түсіру"),
|
||||
("Back", "Артқа"),
|
||||
("Apps", "Апылқаттар"),
|
||||
("Volume up", "Дыбысты көтеру"),
|
||||
("Volume down", "Дыбысты төмендету"),
|
||||
("Power", "Қуат"),
|
||||
("Telegram bot", "Telegram bot"),
|
||||
("enable-bot-tip", "Бұл ерекшелікті іске қоссаңыз, 2FA кодын ботыңыздан ала аласыз. Ол сондай-ақ қосылым хабарландыруы ретінде жұмыс істей алады."),
|
||||
("enable-bot-desc", "1. @BotFather'мен чатты ашыңыз.\n2. \"/newbot\" командасын жіберіңіз. Бұл қадамды аяқтағаннан кейін токен аласыз.\n3. Жаңадан құрылған ботыңызбен чатты бастаңыз. Оны белсендіру үшін \"/hello\" сияқты алға қарай қиғаш сызықтан (\"/\") басталатын хабарлама жіберіңіз.\n"),
|
||||
("cancel-2fa-confirm-tip", "2FA-ны бас тартуға сенімдісіз бе?"),
|
||||
("cancel-bot-confirm-tip", "Telegram bot-ты бас тартуға сенімдісіз бе?"),
|
||||
("About RustDesk", "RustDesk туралы"),
|
||||
("Send clipboard keystrokes", "Көшіру-тақта пернетерістерін жіберу"),
|
||||
("network_error_tip", "Желі қосылымыңызды тексеруді өтінеміз, сосын қайталауды басыңыз."),
|
||||
("Unlock with PIN", "PIN арқылы құлыптан шығару"),
|
||||
("Requires at least {} characters", "Кемінде {} таңбаны қажет етеді"),
|
||||
("Wrong PIN", "Бұрыс PIN"),
|
||||
("Set PIN", "PIN орнату"),
|
||||
("Enable trusted devices", "Сенімді құрылғыларды іске қосу"),
|
||||
("Manage trusted devices", "Сенімді құрылғыларды басқару"),
|
||||
("Platform", "Платформа"),
|
||||
("Days remaining", "Қалған күндер"),
|
||||
("enable-trusted-devices-tip", "Сенімді құрылғыларда 2FA тексеруін өткізіп жіберу"),
|
||||
("Parent directory", "Аталық бума"),
|
||||
("Resume", "Жалғастыру"),
|
||||
("Invalid file name", "Бұрыс файыл атауы"),
|
||||
("one-way-file-transfer-tip", "Басқарылатын жақта бір-бағытты файыл тасымалдау іске қосылған."),
|
||||
("Authentication Required", "Аутентификация қажет"),
|
||||
("Authenticate", "Аутентификациялау"),
|
||||
("web_id_input_tip", "Сіз бір сербердегі ID еңгізуіңізге болады, web клиентінде тікелей IP қолжетімділікке қолдау көрсетілмейді.\nБасқа сербердегі құрылғыға қол жеткізгіңіз келсе, сербер мекенжайын қосыңыз (<id>@<server_address>?key=<key_value>), мысалы,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЖария сербердегі құрылғыға қол жеткізгіңіз келсе, \"<id>@public\" еңгізіңіз, жария сербер үшін кілт қажет емес."),
|
||||
("Download", "Жүктеу"),
|
||||
("Upload folder", "Буманы жүктеп салу"),
|
||||
("Upload files", "Файылдарды жүктеп салу"),
|
||||
("Clipboard is synchronized", "Көшіру-тақта синхрондалды"),
|
||||
("Update client clipboard", "Клиент көшіру-тақтасын жаңарту"),
|
||||
("Untagged", "Тақсыз"),
|
||||
("new-version-of-{}-tip", "{} жаңа нұсқасы қолжетімді"),
|
||||
("Accessible devices", "Қолжетімді құрылғылар"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Қашықтағы жақтағы RustDesk клиентін {} немесе одан жоғары нұсқаға жаңартуды өтінеміз!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "D3D рендеринг қосылғанда, кейбір машиналарда қашықтан басқару экраны қара болуы мүмкін."),
|
||||
("Use D3D rendering", "D3D рендерингті қолдану"),
|
||||
("Printer", "Принтер"),
|
||||
("printer-os-requirement-tip", "Принтердің шығыс функциясы Windows 10 немесе одан жоғарысын қажет етеді."),
|
||||
("printer-requires-installed-{}-client-tip", "Қашықтан басып шығаруды қолдану үшін, осы құрылғыға {} орнатылуы керек."),
|
||||
("printer-{}-not-installed-tip", "{} Принтері орнатылмаған."),
|
||||
("printer-{}-ready-tip", "{} Принтері орнатылған және қолдануға дайын."),
|
||||
("Install {} Printer", "{} Принтерін орнату"),
|
||||
("Outgoing Print Jobs", "Шығыс басып шығару тапсырмалары"),
|
||||
("Incoming Print Jobs", "Кіріс басып шығару тапсырмалары"),
|
||||
("Incoming Print Job", "Кіріс басып шығару тапсырмасы"),
|
||||
("use-the-default-printer-tip", "Әдепкі принтерді қолдану"),
|
||||
("use-the-selected-printer-tip", "Таңдалған принтерді қолдану"),
|
||||
("auto-print-tip", "Таңдалған принтерді қолданып аутыматты түрде басып шығару."),
|
||||
("print-incoming-job-confirm-tip", "Сіз қашықтан басып шығару тапсырмасын алдыңыз. Оны өз жағыңызда орындағыңыз келе ме?"),
|
||||
("remote-printing-disallowed-tile-tip", "Қашықтан басып шығаруға тыйым салынған"),
|
||||
("remote-printing-disallowed-text-tip", "Басқарылатын жақтың рұқсат орнатпалары қашықтан басып шығаруға тыйым салады."),
|
||||
("save-settings-tip", "Орнатпаларды сақтау"),
|
||||
("dont-show-again-tip", "Мұны қайта көрсетпеу"),
|
||||
("Take screenshot", "Скриншот түсіру"),
|
||||
("Taking screenshot", "Скриншот түсірілуде"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Бірнеше дисплейдің скриншоттарын біріктіруге қазір қолдау көрсетілмейді. Жеке дисплейге ауысып, қайталап көруді өтінеміз."),
|
||||
("screenshot-action-tip", "Скриншотпен қалай жалғастыру керектігін таңдауды өтінеміз."),
|
||||
("Save as", "Басқаша сақтау"),
|
||||
("Copy to clipboard", "Көшіру-тақтаға көшіру"),
|
||||
("Enable remote printer", "Қашықтағы принтерді іске қосу"),
|
||||
("Downloading {}", "{} жүктелуде"),
|
||||
("{} Update", "{} жаңартуы"),
|
||||
("{}-to-update-tip", "{} қазір жабылып, жаңа нұсқаны орнатады."),
|
||||
("download-new-version-failed-tip", "Жүктеу сәтсіз болды. Қайталап көруіңізге немесе \"Жүктеу\" батырмасын басып, шығарылым бетінен жүктеп, қолмен жаңартуыңызға болады."),
|
||||
("Auto update", "Аутыматты жаңарту"),
|
||||
("update-failed-check-msi-tip", "Орнату әдісін тексеру сәтсіз болды. \"Жүктеу\" батырмасын басып, шығарылым бетінен жүктеп, қолмен жаңартуды өтінеміз."),
|
||||
("websocket_tip", "WebSocket қолданғанда, тек релай қосылымдарына қолдау көрсетіледі."),
|
||||
("Use WebSocket", "WebSocket қолдану"),
|
||||
("Trackpad speed", "Трекпад жылдамдығы"),
|
||||
("Default trackpad speed", "Әдепкі трекпад жылдамдығы"),
|
||||
("Numeric one-time password", "Сандық бір-реттік құпия сөз"),
|
||||
("Enable IPv6 P2P connection", "IPv6 P2P қосылымын іске қосу"),
|
||||
("Enable UDP hole punching", "UDP hole punching'ті іске қосу"),
|
||||
("View camera", "Камераны Көру"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Enable camera", "Камераны қосу"),
|
||||
("No cameras", "Камералар жоқ"),
|
||||
("view_camera_unsupported_tip", "Қашықтағы құрылғы камераны көруге қолдау көрсетпейді."),
|
||||
("Terminal", "Терминал"),
|
||||
("Enable terminal", "Терминалды іске қосу"),
|
||||
("New tab", "Жаңа бөлімше"),
|
||||
("Keep terminal sessions on disconnect", "Ажыратылғанда терминал сештерін сақтап тұру"),
|
||||
("Terminal (Run as administrator)", "Терминал (Әкімші ретінде іске қосу)"),
|
||||
("terminal-admin-login-tip", "Басқарылатын жақтың әкімші қолданушы аты мен құпия сөзін еңгізуді өтінеміз."),
|
||||
("Failed to get user token.", "Қолданушы токенін алу сәтсіз болды."),
|
||||
("Incorrect username or password.", "Бұрыс қолданушы аты немесе құпия сөз."),
|
||||
("The user is not an administrator.", "Қолданушы әкімші емес."),
|
||||
("Failed to check if the user is an administrator.", "Қолданушының әкімші екенін тексеру сәтсіз болды."),
|
||||
("Supported only in the installed version.", "Тек орнатылған нұсқада ғана қолдау көрсетіледі."),
|
||||
("elevation_username_tip", "Қолданушы аты немесе domain\\username еңгізіңіз"),
|
||||
("Preparing for installation ...", "Орнатуға дайындалуда ..."),
|
||||
("Show my cursor", "Менің курсорымды көрсету"),
|
||||
("Scale custom", "Теңшеулі масштаб"),
|
||||
("Custom scale slider", "Теңшеулі масштаб жүгірткісі"),
|
||||
("Decrease", "Азайту"),
|
||||
("Increase", "Көбейту"),
|
||||
("Show virtual mouse", "Виртуалды тінтуірді көрсету"),
|
||||
("Virtual mouse size", "Виртуалды тінтуір өлшемі"),
|
||||
("Small", "Кіші"),
|
||||
("Large", "Үлкен"),
|
||||
("Show virtual joystick", "Виртуалды джойстикті көрсету"),
|
||||
("Edit note", "Нотаны өңдеу"),
|
||||
("Alias", "Бүркеншік ат"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Қатерлі TLS қайтуына рұқсат ету"),
|
||||
("allow-insecure-tls-fallback-tip", "Әдепкіде RustDesk TLS қолданатын протоколдар үшін сербер сертификатын тексереді.\nБұл опция қосылғанда, RustDesk тексеру сәтсіз болған жағдайда тексеру қадамын өткізіп жіберуге қайтып, жалғастырады."),
|
||||
("Disable UDP", "UDP-ні өшіру"),
|
||||
("disable-udp-tip", "Тек TCP қолданатынын-қолданбайтынын басқарады.\nБұл опция қосылғанда, RustDesk енді UDP 21116 қолданбайды, оның орнына TCP 21116 қолданылады."),
|
||||
("server-oss-not-support-tip", "ЕСКЕРТПЕ: RustDesk server OSS бұл ерекшелікті қамтымайды."),
|
||||
("input note here", "осында нота еңгізіңіз"),
|
||||
("note-at-conn-end-tip", "Қосылым соңында нота сұрау"),
|
||||
("Show terminal extra keys", "Терминалдың қосымша пернелерін көрсету"),
|
||||
("Relative mouse mode", "Салыстырмалы тінтуір модасы"),
|
||||
("rel-mouse-not-supported-peer-tip", "Қосылған пир Салыстырмалы тінтуір модасына қолдау көрсетпейді."),
|
||||
("rel-mouse-not-ready-tip", "Салыстырмалы тінтуір модасы әлі дайын емес. Қайталап көруді өтінеміз."),
|
||||
("rel-mouse-lock-failed-tip", "Курсорды құлыптау сәтсіз болды. Салыстырмалы тінтуір модасы өшірілді."),
|
||||
("rel-mouse-exit-{}-tip", "Шығу үшін {} басыңыз."),
|
||||
("rel-mouse-permission-lost-tip", "Пернетақта рұқсаты кері қайтарылды. Салыстырмалы тінтуір модасы өшірілді."),
|
||||
("Changelog", "Өзгерістер журналы"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Шығыс сештер кезінде экранды ұйқыға кетпейтіндей ұстау"),
|
||||
("keep-awake-during-incoming-sessions-label", "Кіріс сештер кезінде экранды ұйқыға кетпейтіндей ұстау"),
|
||||
("Continue with {}", "{} арқылы жалғастыру"),
|
||||
("Display Name", "Көрсетілетін ат"),
|
||||
("password-hidden-tip", "Тұрақты құпия сөз орнатылған (жасырын)."),
|
||||
("preset-password-in-use-tip", "Алдын ала орнатылған құпия сөз қазір қолданыста."),
|
||||
("Enable privacy mode", "Құпиялылық модасын іске қосу"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Қашықтағы құралдар тақтасын кез келген терезе жиегіне бекітуге рұқсат ету"),
|
||||
("API Token", "API Token"),
|
||||
("Deploy", "Орналастыру"),
|
||||
("Custom ID (optional)", "Теңшеулі ID (міндетті емес)"),
|
||||
("server_requires_deployment_tip", "Сербер бұл құрылғыны нақты орналастыруды талап етеді. Қазір орналастыру керек пе?"),
|
||||
("The server does not require explicit deployment.", "Сербер нақты орналастыруды талап етпейді."),
|
||||
("Unknown response.", "Белгісіз жауап."),
|
||||
("wayland-keyboard-input-disabled-tip", "Пернетақта еңгізуіне рұқсат ету керек пе?"),
|
||||
("wayland-keyboard-input-consent-tip", "Осы қашықтағы компьютерде тергеніңізді (соның ішінде құпия сөздерді) ондағы басқа апылқаттар оқи алады."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Бұл таңдау мынаған қолданылады:"),
|
||||
("wayland-soft-keyboard-input-label", "Программалық пернетақта еңгізуі"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Пернетақта еңгізу таңдауын қалпына келтіру"),
|
||||
("remember-wayland-keyboard-choice-tip", "Осы қашықтағы компьютер үшін қайта сұрамау"),
|
||||
("Why this happens", "Бұл неге болады"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
557
src/lang/lt.rs
557
src/lang/lt.rs
@@ -228,7 +228,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Username missed", "Prarastas vartotojo vardas"),
|
||||
("Password missed", "Slaptažodis praleistas"),
|
||||
("Wrong credentials", "Klaidingi kredencialai"),
|
||||
("The verification code is incorrect or has expired", ""),
|
||||
("The verification code is incorrect or has expired", "Patvirtinimo kodas neteisingas arba nebegalioja"),
|
||||
("Edit Tag", "Redaguoti žymą"),
|
||||
("Forget Password", "Nebeprisiminti slaptažodžio"),
|
||||
("Favorites", "Parankiniai"),
|
||||
@@ -326,8 +326,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Ratio", "Santykis"),
|
||||
("Image Quality", "Vaizdo kokybė"),
|
||||
("Scroll Style", "Slinkimo stilius"),
|
||||
("Show Toolbar", ""),
|
||||
("Hide Toolbar", ""),
|
||||
("Show Toolbar", "Rodyti įrankių juostą"),
|
||||
("Hide Toolbar", "Slėpti įrankių juostą"),
|
||||
("Direct Connection", "Tiesioginis ryšys"),
|
||||
("Relay Connection", "Tarpinė jungtis"),
|
||||
("Secure Connection", "Saugus ryšys"),
|
||||
@@ -355,12 +355,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Audio Input Device", "Garso įvestis"),
|
||||
("Use IP Whitelisting", "Naudoti patikimą IP sąrašą"),
|
||||
("Network", "Tinklas"),
|
||||
("Pin Toolbar", ""),
|
||||
("Unpin Toolbar", ""),
|
||||
("Pin Toolbar", "Prisegti įrankių juostą"),
|
||||
("Unpin Toolbar", "Atsegti įrankių juostą"),
|
||||
("Recording", "Įrašymas"),
|
||||
("Directory", "Katalogas"),
|
||||
("Automatically record incoming sessions", "Automatiškai įrašyti įeinančius seansus"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record outgoing sessions", "Automatiškai įrašyti išeinančius seansus"),
|
||||
("Change", "Keisti"),
|
||||
("Start session recording", "Pradėti seanso įrašinėjimą"),
|
||||
("Stop session recording", "Sustabdyti seanso įrašinėjimą"),
|
||||
@@ -379,7 +379,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Screen Share", "Ekrano bendrinimas"),
|
||||
("ubuntu-21-04-required", "Wayland reikalauja Ubuntu 21.04 arba naujesnės versijos."),
|
||||
("wayland-requires-higher-linux-version", "Wayland reikalinga naujesnės Linux Distro versijos. Išbandykite X11 darbalaukį arba pakeiskite OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("xdp-portal-unavailable", "Nepavyko užfiksuoti Wayland ekrano. Galbūt sutriko XDG Desktop Portal arba jis nepasiekiamas. Pabandykite jį paleisti iš naujo komanda `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Peržiūra"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Prašome pasirinkti ekraną, kurį norite bendrinti (veikiantį kitoje pusėje)."),
|
||||
("Show RustDesk", "Rodyti RustDesk"),
|
||||
@@ -476,272 +476,287 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("xorg_not_found_text_tip", "Prašom įdiegti Xorg"),
|
||||
("no_desktop_title_tip", "Nėra pasiekiamų nuotolinių darbalaukių"),
|
||||
("no_desktop_text_tip", "Prašom įdiegti GNOME Desktop"),
|
||||
("No need to elevate", ""),
|
||||
("System Sound", ""),
|
||||
("Default", ""),
|
||||
("New RDP", ""),
|
||||
("Fingerprint", ""),
|
||||
("Copy Fingerprint", ""),
|
||||
("no fingerprints", ""),
|
||||
("Select a peer", ""),
|
||||
("Select peers", ""),
|
||||
("Plugins", ""),
|
||||
("Uninstall", ""),
|
||||
("Update", ""),
|
||||
("Enable", ""),
|
||||
("Disable", ""),
|
||||
("Options", ""),
|
||||
("resolution_original_tip", ""),
|
||||
("resolution_fit_local_tip", ""),
|
||||
("resolution_custom_tip", ""),
|
||||
("Collapse toolbar", ""),
|
||||
("Accept and Elevate", ""),
|
||||
("accept_and_elevate_btn_tooltip", ""),
|
||||
("clipboard_wait_response_timeout_tip", ""),
|
||||
("Incoming connection", ""),
|
||||
("Outgoing connection", ""),
|
||||
("Exit", ""),
|
||||
("Open", ""),
|
||||
("logout_tip", ""),
|
||||
("Service", ""),
|
||||
("Start", ""),
|
||||
("Stop", ""),
|
||||
("exceed_max_devices", ""),
|
||||
("Sync with recent sessions", ""),
|
||||
("Sort tags", ""),
|
||||
("Open connection in new tab", ""),
|
||||
("Move tab to new window", ""),
|
||||
("Can not be empty", ""),
|
||||
("Already exists", ""),
|
||||
("Change Password", ""),
|
||||
("Refresh Password", ""),
|
||||
("ID", ""),
|
||||
("Grid View", ""),
|
||||
("List View", ""),
|
||||
("Select", ""),
|
||||
("Toggle Tags", ""),
|
||||
("pull_ab_failed_tip", ""),
|
||||
("push_ab_failed_tip", ""),
|
||||
("synced_peer_readded_tip", ""),
|
||||
("Change Color", ""),
|
||||
("Primary Color", ""),
|
||||
("HSV Color", ""),
|
||||
("Installation Successful!", ""),
|
||||
("Installation failed!", ""),
|
||||
("Reverse mouse wheel", ""),
|
||||
("{} sessions", ""),
|
||||
("scam_title", ""),
|
||||
("scam_text1", ""),
|
||||
("scam_text2", ""),
|
||||
("Don't show again", ""),
|
||||
("I Agree", ""),
|
||||
("Decline", ""),
|
||||
("Timeout in minutes", ""),
|
||||
("auto_disconnect_option_tip", ""),
|
||||
("Connection failed due to inactivity", ""),
|
||||
("Check for software update on startup", ""),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", ""),
|
||||
("pull_group_failed_tip", ""),
|
||||
("Filter by intersection", ""),
|
||||
("Remove wallpaper during incoming sessions", ""),
|
||||
("Test", ""),
|
||||
("display_is_plugged_out_msg", ""),
|
||||
("No displays", ""),
|
||||
("Open in new window", ""),
|
||||
("Show displays as individual windows", ""),
|
||||
("Use all my displays for the remote session", ""),
|
||||
("selinux_tip", ""),
|
||||
("Change view", ""),
|
||||
("Big tiles", ""),
|
||||
("Small tiles", ""),
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color (4:4:4)", ""),
|
||||
("Enable blocking user input", ""),
|
||||
("id_input_tip", ""),
|
||||
("privacy_mode_impl_mag_tip", ""),
|
||||
("privacy_mode_impl_virtual_display_tip", ""),
|
||||
("Enter privacy mode", ""),
|
||||
("Exit privacy mode", ""),
|
||||
("idd_not_support_under_win10_2004_tip", ""),
|
||||
("input_source_1_tip", ""),
|
||||
("input_source_2_tip", ""),
|
||||
("Swap control-command key", ""),
|
||||
("swap-left-right-mouse", ""),
|
||||
("2FA code", ""),
|
||||
("More", ""),
|
||||
("enable-2fa-title", ""),
|
||||
("enable-2fa-desc", ""),
|
||||
("wrong-2fa-code", ""),
|
||||
("enter-2fa-title", ""),
|
||||
("Email verification code must be 6 characters.", ""),
|
||||
("2FA code must be 6 digits.", ""),
|
||||
("Multiple Windows sessions found", ""),
|
||||
("Please select the session you want to connect to", ""),
|
||||
("powered_by_me", ""),
|
||||
("outgoing_only_desk_tip", ""),
|
||||
("preset_password_warning", ""),
|
||||
("Security Alert", ""),
|
||||
("My address book", ""),
|
||||
("Personal", ""),
|
||||
("Owner", ""),
|
||||
("Set shared password", ""),
|
||||
("Exist in", ""),
|
||||
("Read-only", ""),
|
||||
("Read/Write", ""),
|
||||
("Full Control", ""),
|
||||
("share_warning_tip", ""),
|
||||
("Everyone", ""),
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Clear Wayland screen selection", ""),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("Use texture rendering", ""),
|
||||
("Floating window", ""),
|
||||
("floating_window_tip", ""),
|
||||
("Keep screen on", ""),
|
||||
("Never", ""),
|
||||
("During controlled", ""),
|
||||
("During service is on", ""),
|
||||
("Capture screen using DirectX", ""),
|
||||
("Back", ""),
|
||||
("Apps", ""),
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("No need to elevate", "Teisių kelti nereikia"),
|
||||
("System Sound", "Sistemos garsas"),
|
||||
("Default", "Numatytasis"),
|
||||
("New RDP", "Naujas RDP"),
|
||||
("Fingerprint", "Kontrolinis kodas"),
|
||||
("Copy Fingerprint", "Kopijuoti kontrolinį kodą"),
|
||||
("no fingerprints", "Nėra kontrolinių kodų"),
|
||||
("Select a peer", "Pasirinkite įrenginį"),
|
||||
("Select peers", "Pasirinkite įrenginius"),
|
||||
("Plugins", "Papildiniai"),
|
||||
("Uninstall", "Pašalinti"),
|
||||
("Update", "Atnaujinti"),
|
||||
("Enable", "Įgalinti"),
|
||||
("Disable", "Išjungti"),
|
||||
("Options", "Parinktys"),
|
||||
("resolution_original_tip", "Originali skiriamoji geba"),
|
||||
("resolution_fit_local_tip", "Pritaikyti prie vietinės skiriamosios gebos"),
|
||||
("resolution_custom_tip", "Tinkinta skiriamoji geba"),
|
||||
("Collapse toolbar", "Sutraukti įrankių juostą"),
|
||||
("Accept and Elevate", "Priimti ir pakelti teises"),
|
||||
("accept_and_elevate_btn_tooltip", "Priimti ryšį ir pakelti UAC teises."),
|
||||
("clipboard_wait_response_timeout_tip", "Baigėsi laukimo, kol bus gautas kopijavimo atsakas, laikas."),
|
||||
("Incoming connection", "Įeinantis ryšys"),
|
||||
("Outgoing connection", "Išeinantis ryšys"),
|
||||
("Exit", "Išeiti"),
|
||||
("Open", "Atidaryti"),
|
||||
("logout_tip", "Ar tikrai norite atsijungti?"),
|
||||
("Service", "Paslauga"),
|
||||
("Start", "Pradėti"),
|
||||
("Stop", "Sustabdyti"),
|
||||
("exceed_max_devices", "Pasiekėte didžiausią valdomų įrenginių skaičių."),
|
||||
("Sync with recent sessions", "Sinchronizuoti su seansų istorija"),
|
||||
("Sort tags", "Rikiuoti žymas"),
|
||||
("Open connection in new tab", "Atidaryti ryšį naujoje kortelėje"),
|
||||
("Move tab to new window", "Perkelti kortelę į naują langą"),
|
||||
("Can not be empty", "Negali būti tuščia"),
|
||||
("Already exists", "Jau egzistuoja"),
|
||||
("Change Password", "Keisti slaptažodį"),
|
||||
("Refresh Password", "Atnaujinti slaptažodį"),
|
||||
("ID", "ID"),
|
||||
("Grid View", "Tinklelio rodinys"),
|
||||
("List View", "Sąrašo rodinys"),
|
||||
("Select", "Pasirinkti"),
|
||||
("Toggle Tags", "Perjungti žymas"),
|
||||
("pull_ab_failed_tip", "Nepavyko atnaujinti adresų knygos"),
|
||||
("push_ab_failed_tip", "Nepavyko sinchronizuoti adresų knygos su serveriu"),
|
||||
("synced_peer_readded_tip", "Seansų istorijoje buvę įrenginiai bus sinchronizuoti atgal į adresų knygą."),
|
||||
("Change Color", "Keisti spalvą"),
|
||||
("Primary Color", "Pagrindinė spalva"),
|
||||
("HSV Color", "HSV spalva"),
|
||||
("Installation Successful!", "Įdiegimas sėkmingas!"),
|
||||
("Installation failed!", "Įdiegti nepavyko!"),
|
||||
("Reverse mouse wheel", "Apgręžti pelės ratuką"),
|
||||
("{} sessions", "{} seansai"),
|
||||
("scam_title", "GALBŪT ESATE APGAUDINĖJAMI!"),
|
||||
("scam_text1", "Jei kalbatės telefonu su žmogumi, kurio NEPAŽĮSTATE ir kuriuo NEPASITIKITE, ir jis paprašė jūsų naudoti RustDesk bei paleisti paslaugą, netęskite ir nedelsdami padėkite ragelį."),
|
||||
("scam_text2", "Tikėtina, kad tai sukčius, bandantis pavogti jūsų pinigus ar kitą asmeninę informaciją."),
|
||||
("Don't show again", "Daugiau neberodyti"),
|
||||
("I Agree", "Sutinku"),
|
||||
("Decline", "Atmesti"),
|
||||
("Timeout in minutes", "Skirtasis laikas minutėmis"),
|
||||
("auto_disconnect_option_tip", "Automatiškai uždaryti įeinančius seansus, kai naudotojas neaktyvus"),
|
||||
("Connection failed due to inactivity", "Automatiškai atjungta dėl neaktyvumo"),
|
||||
("Check for software update on startup", "Paleidžiant tikrinti, ar yra programinės įrangos atnaujinimų"),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", "Prašome atnaujinti RustDesk Server Pro į versiją {} ar naujesnę!"),
|
||||
("pull_group_failed_tip", "Nepavyko atnaujinti grupės"),
|
||||
("Filter by intersection", "Filtruoti pagal sankirtą"),
|
||||
("Remove wallpaper during incoming sessions", "Pašalinti darbalaukio foną įeinančių seansų metu"),
|
||||
("Test", "Testas"),
|
||||
("display_is_plugged_out_msg", "Ekranas atjungtas, perjungiama į pirmąjį ekraną."),
|
||||
("No displays", "Nėra ekranų"),
|
||||
("Open in new window", "Atidaryti naujame lange"),
|
||||
("Show displays as individual windows", "Rodyti ekranus kaip atskirus langus"),
|
||||
("Use all my displays for the remote session", "Naudoti visus mano ekranus nuotoliniam seansui"),
|
||||
("selinux_tip", "Jūsų įrenginyje įjungtas SELinux, kuris gali trukdyti RustDesk tinkamai veikti kaip valdomajai pusei."),
|
||||
("Change view", "Keisti rodinį"),
|
||||
("Big tiles", "Dideli langeliai"),
|
||||
("Small tiles", "Maži langeliai"),
|
||||
("List", "Sąrašas"),
|
||||
("Virtual display", "Virtualus ekranas"),
|
||||
("Plug out all", "Atjungti visus"),
|
||||
("True color (4:4:4)", "Tikrosios spalvos (4:4:4)"),
|
||||
("Enable blocking user input", "Įgalinti naudotojo įvesties blokavimą"),
|
||||
("id_input_tip", "Galite įvesti ID, tiesioginį IP arba domeną su prievadu (<domain>:<port>).\nJei norite pasiekti įrenginį kitame serveryje, pridėkite serverio adresą (<id>@<server_address>?key=<key_value>), pavyzdžiui,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJei norite pasiekti įrenginį viešajame serveryje, įveskite \"<id>@public\", viešajam serveriui raktas nereikalingas.\n\nJei norite priversti pirmą kartą jungiantis naudoti perdavimo ryšį, ID gale pridėkite \"/r\", pavyzdžiui, \"9123456234/r\"."),
|
||||
("privacy_mode_impl_mag_tip", "1 režimas"),
|
||||
("privacy_mode_impl_virtual_display_tip", "2 režimas"),
|
||||
("Enter privacy mode", "Įjungti privatumo režimą"),
|
||||
("Exit privacy mode", "Išjungti privatumo režimą"),
|
||||
("idd_not_support_under_win10_2004_tip", "Netiesioginio ekrano tvarkyklė nepalaikoma. Reikalinga Windows 10 2004 ar naujesnė versija."),
|
||||
("input_source_1_tip", "1 įvesties šaltinis"),
|
||||
("input_source_2_tip", "2 įvesties šaltinis"),
|
||||
("Swap control-command key", "Sukeisti control-command klavišus"),
|
||||
("swap-left-right-mouse", "Sukeisti kairįjį ir dešinįjį pelės mygtukus"),
|
||||
("2FA code", "2FA kodas"),
|
||||
("More", "Daugiau"),
|
||||
("enable-2fa-title", "Įgalinti dviejų veiksnių autentifikavimą"),
|
||||
("enable-2fa-desc", "Dabar nustatykite autentifikatorių. Telefone ar kompiuteryje galite naudoti autentifikatoriaus programėlę, pvz., Authy, Microsoft arba Google Authenticator.\n\nNuskaitykite QR kodą savo programėle ir įveskite jos rodomą kodą, kad įgalintumėte dviejų veiksnių autentifikavimą."),
|
||||
("wrong-2fa-code", "Nepavyksta patikrinti kodo. Patikrinkite, ar kodas ir vietinio laiko nustatymai yra teisingi"),
|
||||
("enter-2fa-title", "Dviejų veiksnių autentifikavimas"),
|
||||
("Email verification code must be 6 characters.", "El. pašto patvirtinimo kodą turi sudaryti 6 simboliai."),
|
||||
("2FA code must be 6 digits.", "2FA kodą turi sudaryti 6 skaitmenys."),
|
||||
("Multiple Windows sessions found", "Rasta keletas Windows seansų"),
|
||||
("Please select the session you want to connect to", "Pasirinkite seansą, prie kurio norite prisijungti"),
|
||||
("powered_by_me", "Veikia su RustDesk"),
|
||||
("outgoing_only_desk_tip", "Tai tinkinta laida.\nGalite jungtis prie kitų įrenginių, tačiau kiti įrenginiai negali prisijungti prie jūsų įrenginio."),
|
||||
("preset_password_warning", "Šioje tinkintoje laidoje yra iš anksto nustatytas slaptažodis. Bet kas, žinantis šį slaptažodį, gali visiškai valdyti jūsų įrenginį. Jei to nesitikėjote, nedelsdami pašalinkite programinę įrangą."),
|
||||
("Security Alert", "Saugumo įspėjimas"),
|
||||
("My address book", "Mano adresų knyga"),
|
||||
("Personal", "Asmeninė"),
|
||||
("Owner", "Savininkas"),
|
||||
("Set shared password", "Nustatyti bendrinamą slaptažodį"),
|
||||
("Exist in", "Yra"),
|
||||
("Read-only", "Tik skaitymas"),
|
||||
("Read/Write", "Skaitymas / rašymas"),
|
||||
("Full Control", "Visiškas valdymas"),
|
||||
("share_warning_tip", "Aukščiau esantys laukai yra bendrinami ir matomi kitiems."),
|
||||
("Everyone", "Visi"),
|
||||
("ab_web_console_tip", "Daugiau žiniatinklio konsolėje"),
|
||||
("allow-only-conn-window-open-tip", "Leisti prisijungti tik tada, kai atidarytas RustDesk langas"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Nėra fizinių ekranų, privatumo režimo naudoti nereikia."),
|
||||
("Follow remote cursor", "Sekti nuotolinį žymeklį"),
|
||||
("Follow remote window focus", "Sekti nuotolinio lango fokusavimą"),
|
||||
("default_proxy_tip", "Numatytasis protokolas ir prievadas yra Socks5 ir 1080"),
|
||||
("no_audio_input_device_tip", "Garso įvesties įrenginys nerastas."),
|
||||
("Incoming", "Įeinantis"),
|
||||
("Outgoing", "Išeinantis"),
|
||||
("Clear Wayland screen selection", "Išvalyti Wayland ekrano pasirinkimą"),
|
||||
("clear_Wayland_screen_selection_tip", "Išvalę ekrano pasirinkimą, galite iš naujo pasirinkti bendrinamą ekraną."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Ar tikrai norite išvalyti Wayland ekrano pasirinkimą?"),
|
||||
("android_new_voice_call_tip", "Gauta nauja balso skambučio užklausa. Jei priimsite, garsas bus perjungtas į balso ryšį."),
|
||||
("texture_render_tip", "Naudokite tekstūrų atvaizdavimą, kad vaizdas būtų sklandesnis. Jei kyla atvaizdavimo problemų, galite pabandyti šią parinktį išjungti."),
|
||||
("Use texture rendering", "Naudoti tekstūrų atvaizdavimą"),
|
||||
("Floating window", "Slankusis langas"),
|
||||
("floating_window_tip", "Tai padeda išlaikyti RustDesk foninę paslaugą"),
|
||||
("Keep screen on", "Neleisti ekranui užgesti"),
|
||||
("Never", "Niekada"),
|
||||
("During controlled", "Valdymo metu"),
|
||||
("During service is on", "Kol veikia paslauga"),
|
||||
("Capture screen using DirectX", "Fiksuoti ekraną naudojant DirectX"),
|
||||
("Back", "Atgal"),
|
||||
("Apps", "Programos"),
|
||||
("Volume up", "Padidinti garsą"),
|
||||
("Volume down", "Sumažinti garsą"),
|
||||
("Power", "Maitinimas"),
|
||||
("Telegram bot", "Telegram botas"),
|
||||
("enable-bot-tip", "Įgalinę šią funkciją, galėsite gauti 2FA kodą iš savo boto. Jis taip pat gali veikti kaip pranešimas apie ryšį."),
|
||||
("enable-bot-desc", "1. Atidarykite pokalbį su @BotFather.\n2. Išsiųskite komandą \"/newbot\". Atlikę šį veiksmą gausite prieigos raktą (token).\n3. Pradėkite pokalbį su naujai sukurtu botu. Norėdami jį aktyvuoti, išsiųskite žinutę, prasidedančią pasviru brūkšniu (\"/\"), pavyzdžiui, \"/hello\".\n"),
|
||||
("cancel-2fa-confirm-tip", "Ar tikrai norite atšaukti 2FA?"),
|
||||
("cancel-bot-confirm-tip", "Ar tikrai norite atšaukti Telegram botą?"),
|
||||
("About RustDesk", "Apie RustDesk"),
|
||||
("Send clipboard keystrokes", "Siųsti iškarpinės klavišų paspaudimus"),
|
||||
("network_error_tip", "Patikrinkite tinklo ryšį ir spustelėkite „Bandyti dar kartą“."),
|
||||
("Unlock with PIN", "Atrakinti PIN kodu"),
|
||||
("Requires at least {} characters", "Reikalingi mažiausiai {} simboliai"),
|
||||
("Wrong PIN", "Neteisingas PIN kodas"),
|
||||
("Set PIN", "Nustatyti PIN kodą"),
|
||||
("Enable trusted devices", "Įgalinti patikimus įrenginius"),
|
||||
("Manage trusted devices", "Tvarkyti patikimus įrenginius"),
|
||||
("Platform", "Platforma"),
|
||||
("Days remaining", "Liko dienų"),
|
||||
("enable-trusted-devices-tip", "Praleisti 2FA patikrinimą patikimuose įrenginiuose"),
|
||||
("Parent directory", "Aukštesnysis katalogas"),
|
||||
("Resume", "Tęsti"),
|
||||
("Invalid file name", "Netinkamas failo pavadinimas"),
|
||||
("one-way-file-transfer-tip", "Valdomojoje pusėje įgalintas vienpusis failų perdavimas."),
|
||||
("Authentication Required", "Reikalingas autentifikavimas"),
|
||||
("Authenticate", "Autentifikuoti"),
|
||||
("web_id_input_tip", "Galite įvesti tame pačiame serveryje esantį ID; žiniatinklio kliente tiesioginė prieiga per IP nepalaikoma.\nJei norite pasiekti įrenginį kitame serveryje, pridėkite serverio adresą (<id>@<server_address>?key=<key_value>), pavyzdžiui,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJei norite pasiekti įrenginį viešajame serveryje, įveskite \"<id>@public\", viešajam serveriui raktas nereikalingas."),
|
||||
("Download", "Atsisiųsti"),
|
||||
("Upload folder", "Įkelti aplanką"),
|
||||
("Upload files", "Įkelti failus"),
|
||||
("Clipboard is synchronized", "Iškarpinė sinchronizuota"),
|
||||
("Update client clipboard", "Atnaujinti kliento iškarpinę"),
|
||||
("Untagged", "Be žymų"),
|
||||
("new-version-of-{}-tip", "Yra nauja {} versija"),
|
||||
("Accessible devices", "Pasiekiami įrenginiai"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Prašome atnaujinti nuotolinės pusės RustDesk klientą į {} ar naujesnę versiją!"),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("d3d_render_tip", "Kai įgalintas D3D atvaizdavimas, kai kuriuose įrenginiuose nuotolinio valdymo ekranas gali būti juodas."),
|
||||
("Use D3D rendering", "Naudoti D3D atvaizdavimą"),
|
||||
("Printer", "Spausdintuvas"),
|
||||
("printer-os-requirement-tip", "Spausdinimo siuntimo funkcijai reikalinga Windows 10 ar naujesnė versija."),
|
||||
("printer-requires-installed-{}-client-tip", "Kad galėtumėte naudoti nuotolinį spausdinimą, šiame įrenginyje turi būti įdiegta {}."),
|
||||
("printer-{}-not-installed-tip", "{} spausdintuvas neįdiegtas."),
|
||||
("printer-{}-ready-tip", "{} spausdintuvas įdiegtas ir paruoštas naudoti."),
|
||||
("Install {} Printer", "Įdiegti {} spausdintuvą"),
|
||||
("Outgoing Print Jobs", "Išeinančios spausdinimo užduotys"),
|
||||
("Incoming Print Jobs", "Įeinančios spausdinimo užduotys"),
|
||||
("Incoming Print Job", "Įeinanti spausdinimo užduotis"),
|
||||
("use-the-default-printer-tip", "Naudoti numatytąjį spausdintuvą"),
|
||||
("use-the-selected-printer-tip", "Naudoti pasirinktą spausdintuvą"),
|
||||
("auto-print-tip", "Spausdinti automatiškai naudojant pasirinktą spausdintuvą."),
|
||||
("print-incoming-job-confirm-tip", "Gavote spausdinimo užduotį iš nuotolinės pusės. Ar norite ją įvykdyti savo pusėje?"),
|
||||
("remote-printing-disallowed-tile-tip", "Nuotolinis spausdinimas neleidžiamas"),
|
||||
("remote-printing-disallowed-text-tip", "Valdomosios pusės leidimų nustatymai draudžia nuotolinį spausdinimą."),
|
||||
("save-settings-tip", "Įrašyti nustatymus"),
|
||||
("dont-show-again-tip", "Daugiau šito neberodyti"),
|
||||
("Take screenshot", "Padaryti ekrano nuotrauką"),
|
||||
("Taking screenshot", "Daroma ekrano nuotrauka"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Kelių ekranų nuotraukų sujungimas šiuo metu nepalaikomas. Perjunkite į vieną ekraną ir bandykite dar kartą."),
|
||||
("screenshot-action-tip", "Pasirinkite, ką daryti su ekrano nuotrauka."),
|
||||
("Save as", "Įrašyti kaip"),
|
||||
("Copy to clipboard", "Kopijuoti į iškarpinę"),
|
||||
("Enable remote printer", "Įgalinti nuotolinį spausdintuvą"),
|
||||
("Downloading {}", "Atsisiunčiama {}"),
|
||||
("{} Update", "{} atnaujinimas"),
|
||||
("{}-to-update-tip", "{} dabar bus uždaryta ir bus įdiegta nauja versija."),
|
||||
("download-new-version-failed-tip", "Atsisiųsti nepavyko. Galite bandyti dar kartą arba spustelėti mygtuką \"Atsisiųsti\", kad atsisiųstumėte iš leidimų puslapio ir atnaujintumėte rankiniu būdu."),
|
||||
("Auto update", "Automatinis atnaujinimas"),
|
||||
("update-failed-check-msi-tip", "Nepavyko patikrinti įdiegimo būdo. Spustelėkite mygtuką \"Atsisiųsti\", kad atsisiųstumėte iš leidimų puslapio ir atnaujintumėte rankiniu būdu."),
|
||||
("websocket_tip", "Naudojant WebSocket palaikomi tik perdavimo ryšiai."),
|
||||
("Use WebSocket", "Naudoti WebSocket"),
|
||||
("Trackpad speed", "Jutiklinės dalies greitis"),
|
||||
("Default trackpad speed", "Numatytasis jutiklinės dalies greitis"),
|
||||
("Numeric one-time password", "Skaitmeninis vienkartinis slaptažodis"),
|
||||
("Enable IPv6 P2P connection", "Įgalinti IPv6 P2P ryšį"),
|
||||
("Enable UDP hole punching", "Įgalinti UDP gręžimą (hole punching)"),
|
||||
("View camera", "Peržiūrėti kamerą"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Scale custom", ""),
|
||||
("Custom scale slider", ""),
|
||||
("Decrease", ""),
|
||||
("Increase", ""),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Enable camera", "Įgalinti kamerą"),
|
||||
("No cameras", "Nėra kamerų"),
|
||||
("view_camera_unsupported_tip", "Nuotolinis įrenginys nepalaiko kameros peržiūros."),
|
||||
("Terminal", "Terminalas"),
|
||||
("Enable terminal", "Įgalinti terminalą"),
|
||||
("New tab", "Nauja kortelė"),
|
||||
("Keep terminal sessions on disconnect", "Atsijungus išlaikyti terminalo seansus"),
|
||||
("Terminal (Run as administrator)", "Terminalas (paleisti kaip administratorius)"),
|
||||
("terminal-admin-login-tip", "Įveskite valdomosios pusės administratoriaus naudotojo vardą ir slaptažodį."),
|
||||
("Failed to get user token.", "Nepavyko gauti naudotojo prieigos rakto."),
|
||||
("Incorrect username or password.", "Neteisingas naudotojo vardas arba slaptažodis."),
|
||||
("The user is not an administrator.", "Naudotojas nėra administratorius."),
|
||||
("Failed to check if the user is an administrator.", "Nepavyko patikrinti, ar naudotojas yra administratorius."),
|
||||
("Supported only in the installed version.", "Palaikoma tik įdiegtoje versijoje."),
|
||||
("elevation_username_tip", "Įveskite naudotojo vardą arba domenas\\naudotojo vardas"),
|
||||
("Preparing for installation ...", "Ruošiamasi įdiegti ..."),
|
||||
("Show my cursor", "Rodyti mano žymeklį"),
|
||||
("Scale custom", "Tinkintas mastelis"),
|
||||
("Custom scale slider", "Tinkinto mastelio slankiklis"),
|
||||
("Decrease", "Sumažinti"),
|
||||
("Increase", "Padidinti"),
|
||||
("Show virtual mouse", "Rodyti virtualią pelę"),
|
||||
("Virtual mouse size", "Virtualios pelės dydis"),
|
||||
("Small", "Mažas"),
|
||||
("Large", "Didelis"),
|
||||
("Show virtual joystick", "Rodyti virtualų vairalazdę"),
|
||||
("Edit note", "Redaguoti pastabą"),
|
||||
("Alias", "Slapyvardis"),
|
||||
("ScrollEdge", "ScrollEdge"),
|
||||
("Allow insecure TLS fallback", "Leisti nesaugų atsarginį TLS variantą"),
|
||||
("allow-insecure-tls-fallback-tip", "Pagal numatytuosius nustatymus RustDesk tikrina serverio sertifikatą protokoluose, naudojančiuose TLS.\nĮgalinus šią parinktį, patikros nesėkmės atveju RustDesk praleis patikros veiksmą ir tęs darbą."),
|
||||
("Disable UDP", "Išjungti UDP"),
|
||||
("disable-udp-tip", "Nurodo, ar naudoti tik TCP.\nĮgalinus šią parinktį, RustDesk nebenaudos UDP 21116, vietoj jo bus naudojamas TCP 21116."),
|
||||
("server-oss-not-support-tip", "PASTABA: RustDesk serverio OSS šios funkcijos neturi."),
|
||||
("input note here", "čia įveskite pastabą"),
|
||||
("note-at-conn-end-tip", "Klausti pastabos ryšio pabaigoje"),
|
||||
("Show terminal extra keys", "Rodyti papildomus terminalo klavišus"),
|
||||
("Relative mouse mode", "Santykinis pelės režimas"),
|
||||
("rel-mouse-not-supported-peer-tip", "Prisijungęs įrenginys nepalaiko santykinio pelės režimo."),
|
||||
("rel-mouse-not-ready-tip", "Santykinis pelės režimas dar neparuoštas. Bandykite dar kartą."),
|
||||
("rel-mouse-lock-failed-tip", "Nepavyko užrakinti žymeklio. Santykinis pelės režimas išjungtas."),
|
||||
("rel-mouse-exit-{}-tip", "Norėdami išeiti, paspauskite {}."),
|
||||
("rel-mouse-permission-lost-tip", "Klaviatūros leidimas buvo atšauktas. Santykinis pelės režimas išjungtas."),
|
||||
("Changelog", "Pakeitimų žurnalas"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Neleisti ekranui užgesti išeinančių seansų metu"),
|
||||
("keep-awake-during-incoming-sessions-label", "Neleisti ekranui užgesti įeinančių seansų metu"),
|
||||
("Continue with {}", "Tęsti su {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
("Display Name", "Rodomas vardas"),
|
||||
("password-hidden-tip", "Nustatytas nuolatinis slaptažodis (paslėptas)."),
|
||||
("preset-password-in-use-tip", "Šiuo metu naudojamas iš anksto nustatytas slaptažodis."),
|
||||
("Enable privacy mode", "Įgalinti privatumo režimą"),
|
||||
("allow-remote-toolbar-docking-any-edge", "Leisti prisegti nuotolinę įrankių juostą prie bet kurio lango krašto"),
|
||||
("API Token", "API prieigos raktas"),
|
||||
("Deploy", "Įdiegti"),
|
||||
("Custom ID (optional)", "Tinkintas ID (nebūtina)"),
|
||||
("server_requires_deployment_tip", "Serveris reikalauja, kad šis įrenginys būtų aiškiai įdiegtas. Įdiegti dabar?"),
|
||||
("The server does not require explicit deployment.", "Serveris nereikalauja aiškaus įdiegimo."),
|
||||
("Unknown response.", "Nežinomas atsakas."),
|
||||
("wayland-keyboard-input-disabled-tip", "Leisti klaviatūros įvestį?"),
|
||||
("wayland-keyboard-input-consent-tip", "Tai, ką rašote šiame nuotoliniame kompiuteryje (įskaitant slaptažodžius), gali matyti kitos jame esančios programos."),
|
||||
("wayland-keyboard-input-applies-to-tip", "Šis pasirinkimas taikomas:"),
|
||||
("wayland-soft-keyboard-input-label", "Programinės klaviatūros įvestis"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Atstatyti klaviatūros įvesties pasirinkimą"),
|
||||
("remember-wayland-keyboard-choice-tip", "Daugiau neklausti dėl šio nuotolinio kompiuterio"),
|
||||
("Why this happens", "Kodėl taip nutinka"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user