Browse Source

Merge branch 'main' into add-ClientNotification

pull/771/head
philon- 11 months ago
parent
commit
d59cdaf518
  1. 45
      .github/workflows/ci.yml
  2. 2
      .github/workflows/crowdin-download.yml
  3. 4
      .github/workflows/crowdin-upload-sources.yml
  4. 2
      .github/workflows/crowdin-upload-translations.yml
  5. 27
      .github/workflows/nightly.yml
  6. 33
      .github/workflows/pr.yml
  7. 86
      .github/workflows/release-packages.yml
  8. 79
      .github/workflows/release-web.yml
  9. 182
      .github/workflows/release.yml
  10. 4
      .gitignore
  11. 38
      README.md
  12. 1761
      bun.lock
  13. 5472
      deno.lock
  14. 27
      package.json
  15. 7
      packages/core/jsr.json
  16. 2
      packages/core/mod.ts
  17. 22
      packages/core/package.json
  18. 25
      packages/core/src/meshDevice.ts
  19. 1
      packages/core/src/types.ts
  20. 4
      packages/core/src/utils/mod.ts
  21. 10
      packages/core/src/utils/queue.ts
  22. 18
      packages/core/tsconfig.json
  23. 5
      packages/transport-deno/deno.json
  24. 16
      packages/transport-deno/package.json
  25. 31
      packages/transport-deno/scripts/build_npm.ts
  26. 14
      packages/transport-deno/src/transport.ts
  27. 674
      packages/transport-http/LICENSE
  28. 5
      packages/transport-http/jsr.json
  29. 33
      packages/transport-http/package.json
  30. 1135
      packages/transport-http/pnpm-lock.yaml
  31. 26
      packages/transport-http/src/transport.ts
  32. 13
      packages/transport-http/tsconfig.json
  33. 29
      packages/transport-node/package.json
  34. 20
      packages/transport-node/src/transport.ts
  35. 18
      packages/transport-node/tsconfig.json
  36. 5
      packages/transport-web-bluetooth/jsr.json
  37. 29
      packages/transport-web-bluetooth/package.json
  38. 10
      packages/transport-web-bluetooth/src/transport.ts
  39. 19
      packages/transport-web-bluetooth/tsconfig.json
  40. 5
      packages/transport-web-serial/jsr.json
  41. 26
      packages/transport-web-serial/package.json
  42. 9
      packages/transport-web-serial/src/transport.ts
  43. 19
      packages/transport-web-serial/tsconfig.json
  44. 2
      packages/web/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md
  45. 31
      packages/web/README.md
  46. 4
      packages/web/crowdin.yml
  47. 5
      packages/web/index.html
  48. 8
      packages/web/package.json
  49. 66
      packages/web/public/i18n/locales/bg-BG/channels.json
  50. 97
      packages/web/public/i18n/locales/bg-BG/commandPalette.json
  51. 32
      packages/web/public/i18n/locales/bg-BG/common.json
  52. 38
      packages/web/public/i18n/locales/bg-BG/deviceConfig.json
  53. 59
      packages/web/public/i18n/locales/bg-BG/dialog.json
  54. 54
      packages/web/public/i18n/locales/bg-BG/moduleConfig.json
  55. 8
      packages/web/public/i18n/locales/bg-BG/nodes.json
  56. 40
      packages/web/public/i18n/locales/bg-BG/ui.json
  57. 97
      packages/web/public/i18n/locales/cs-CZ/commandPalette.json
  58. 2
      packages/web/public/i18n/locales/cs-CZ/dashboard.json
  59. 25
      packages/web/public/i18n/locales/cs-CZ/dialog.json
  60. 6
      packages/web/public/i18n/locales/cs-CZ/moduleConfig.json
  61. 97
      packages/web/public/i18n/locales/de-DE/commandPalette.json
  62. 4
      packages/web/public/i18n/locales/de-DE/deviceConfig.json
  63. 27
      packages/web/public/i18n/locales/de-DE/dialog.json
  64. 20
      packages/web/public/i18n/locales/es-ES/channels.json
  65. 97
      packages/web/public/i18n/locales/es-ES/commandPalette.json
  66. 4
      packages/web/public/i18n/locales/es-ES/common.json
  67. 4
      packages/web/public/i18n/locales/es-ES/dashboard.json
  68. 144
      packages/web/public/i18n/locales/es-ES/deviceConfig.json
  69. 27
      packages/web/public/i18n/locales/es-ES/dialog.json
  70. 2
      packages/web/public/i18n/locales/es-ES/messages.json
  71. 34
      packages/web/public/i18n/locales/es-ES/moduleConfig.json
  72. 8
      packages/web/public/i18n/locales/es-ES/ui.json
  73. 97
      packages/web/public/i18n/locales/fi-FI/commandPalette.json
  74. 23
      packages/web/public/i18n/locales/fi-FI/dialog.json
  75. 80
      packages/web/public/i18n/locales/fr-FR/channels.json
  76. 97
      packages/web/public/i18n/locales/fr-FR/commandPalette.json
  77. 126
      packages/web/public/i18n/locales/fr-FR/common.json
  78. 10
      packages/web/public/i18n/locales/fr-FR/dashboard.json
  79. 368
      packages/web/public/i18n/locales/fr-FR/deviceConfig.json
  80. 213
      packages/web/public/i18n/locales/fr-FR/dialog.json
  81. 28
      packages/web/public/i18n/locales/fr-FR/messages.json
  82. 416
      packages/web/public/i18n/locales/fr-FR/moduleConfig.json
  83. 44
      packages/web/public/i18n/locales/fr-FR/nodes.json
  84. 168
      packages/web/public/i18n/locales/fr-FR/ui.json
  85. 97
      packages/web/public/i18n/locales/it-IT/commandPalette.json
  86. 23
      packages/web/public/i18n/locales/it-IT/dialog.json
  87. 97
      packages/web/public/i18n/locales/ja-JP/commandPalette.json
  88. 23
      packages/web/public/i18n/locales/ja-JP/dialog.json
  89. 80
      packages/web/public/i18n/locales/ko-KR/channels.json
  90. 97
      packages/web/public/i18n/locales/ko-KR/commandPalette.json
  91. 116
      packages/web/public/i18n/locales/ko-KR/common.json
  92. 10
      packages/web/public/i18n/locales/ko-KR/dashboard.json
  93. 236
      packages/web/public/i18n/locales/ko-KR/deviceConfig.json
  94. 45
      packages/web/public/i18n/locales/ko-KR/dialog.json
  95. 32
      packages/web/public/i18n/locales/ko-KR/messages.json
  96. 30
      packages/web/public/i18n/locales/ko-KR/moduleConfig.json
  97. 50
      packages/web/public/i18n/locales/ko-KR/nodes.json
  98. 176
      packages/web/public/i18n/locales/ko-KR/ui.json
  99. 97
      packages/web/public/i18n/locales/nl-NL/commandPalette.json
  100. 23
      packages/web/public/i18n/locales/nl-NL/dialog.json

45
.github/workflows/ci.yml

@ -16,10 +16,15 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Bun - name: Setup Node.js
uses: oven-sh/setup-bun@v2 uses: actions/setup-node@v4
with: with:
bun-version: latest node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Setup Deno - name: Setup Deno
uses: denoland/setup-deno@v2 uses: denoland/setup-deno@v2
@ -34,40 +39,28 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-deno- ${{ runner.os }}-deno-
- name: Cache Bun dependencies - name: Cache pnpm dependencies
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
~/.bun/install/cache ~/.pnpm-store
packages/web/node_modules packages/web/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: | restore-keys: |
${{ runner.os }}-bun- ${{ runner.os }}-pnpm-
# --- Detect changed packages --- - name: Build All Packages
- name: Get Changed Package Directories
id: changed_packages
uses: tj-actions/changed-files@v46
with:
dir_names: true
files: packages/**
- name: Build Changed Packages
if: steps.changed_packages.outputs.all_changed_and_modified_files != ''
run: | run: |
set -euo pipefail set -euo pipefail
for pkg_dir in ${{ steps.changed_packages.outputs.all_changed_and_modified_files }}; do for pkg_dir in packages/*/; do
pkg_dir=${pkg_dir%/} # Remove trailing slash
echo "🔍 Inspecting $pkg_dir..." echo "🔍 Inspecting $pkg_dir..."
if [[ -f "$pkg_dir/deno.lock" ]]; then if [[ -f "$pkg_dir/package.json" ]] && [[ "$pkg_dir" != "packages/web" ]]; then
echo "🔧 Building with Bun: $pkg_dir" echo "🔧 Building with pnpm: $pkg_dir"
(cd "$pkg_dir" && bun install && bun run build) (cd "$pkg_dir" && pnpm install && pnpm run build:npm)
else else
echo "⚠️ No recognizable build config in $pkg_dir — skipping" echo "⚠️ Skipping $pkg_dir (web package or no package.json)"
fi fi
done done
- name: No Changed Packages
if: steps.changed_packages.outputs.all_changed_and_modified_files == ''
run: echo "📦 No changed packages detected. Nothing to build."

2
.github/workflows/crowdin-download.yml

@ -17,7 +17,7 @@ jobs:
uses: crowdin/github-action@v2 uses: crowdin/github-action@v2
with: with:
base_url: "https://meshtastic.crowdin.com/api/v2" base_url: "https://meshtastic.crowdin.com/api/v2"
config: "crowdin.yml" config: "./packages/web/crowdin.yml"
upload_sources: false upload_sources: false
upload_translations: false upload_translations: false
download_translations: true download_translations: true

4
.github/workflows/crowdin-upload-sources.yml

@ -5,7 +5,7 @@ on:
# Monitor all .json files within the /i18n/locales/en/ directory. # Monitor all .json files within the /i18n/locales/en/ directory.
# This ensures the workflow triggers if any the English namespace files are modified on the main branch. # This ensures the workflow triggers if any the English namespace files are modified on the main branch.
paths: paths:
- "/i18n/locales/en/*.json" - "/packages/web/public/i18n/locales/en/*.json"
branches: [main] branches: [main]
workflow_dispatch: # Allow manual triggering workflow_dispatch: # Allow manual triggering
@ -21,7 +21,7 @@ jobs:
uses: crowdin/github-action@v2 uses: crowdin/github-action@v2
with: with:
base_url: "https://meshtastic.crowdin.com/api/v2" base_url: "https://meshtastic.crowdin.com/api/v2"
config: "crowdin.yml" config: "./packages/web/crowdin.yml"
upload_sources: true upload_sources: true
upload_translations: false upload_translations: false
download_translations: false download_translations: false

2
.github/workflows/crowdin-upload-translations.yml

@ -15,7 +15,7 @@ jobs:
uses: crowdin/github-action@v2 uses: crowdin/github-action@v2
with: with:
base_url: "https://meshtastic.crowdin.com/api/v2" base_url: "https://meshtastic.crowdin.com/api/v2"
config: "crowdin.yml" config: "./packages/web/crowdin.yml"
upload_sources: false upload_sources: false
upload_translations: true upload_translations: true
download_translations: false download_translations: false

27
.github/workflows/nightly.yml

@ -15,20 +15,25 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Bun - name: Setup Node.js
uses: oven-sh/setup-bun@v2 uses: actions/setup-node@v4
with: with:
bun-version: latest node-version: 22
- name: Cache Bun dependencies - name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Cache pnpm dependencies
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
~/.bun/install/cache ~/.pnpm-store
packages/web/node_modules packages/web/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('packages/web/bun.lockb') }} key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
restore-keys: | restore-keys: |
${{ runner.os }}-bun- ${{ runner.os }}-pnpm-
# - name: Run tests # - name: Run tests
# working-directory: packages/web # working-directory: packages/web
@ -36,15 +41,15 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
working-directory: packages/web working-directory: packages/web
run: bun install run: pnpm install
- name: Build Package - name: Build Package
working-directory: packages/web working-directory: packages/web
run: bun run build run: pnpm run build
- name: Package Output - name: Package Output
working-directory: packages/web working-directory: packages/web
run: bun run package run: pnpm run package
- name: Archive compressed build - name: Archive compressed build
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -73,7 +78,7 @@ jobs:
uses: redhat-actions/buildah-build@v2 uses: redhat-actions/buildah-build@v2
with: with:
containerfiles: | containerfiles: |
./infra/Containerfile ./packages/web/infra/Containerfile
image: ${{ github.event.repository.full_name }} image: ${{ github.event.repository.full_name }}
tags: nightly-${{ steps.get_release.outputs.tag }}-${{ github.sha }} tags: nightly-${{ steps.get_release.outputs.tag }}-${{ github.sha }}

33
.github/workflows/pr.yml

@ -13,34 +13,37 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Bun - name: Setup Node.js
uses: oven-sh/setup-bun@v2 uses: actions/setup-node@v4
with: with:
bun-version: latest node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Install Dependencies - name: Install Dependencies
# Commands will run from 'packages/web' # Commands will run from 'packages/web'
working-directory: packages/web working-directory: packages/web
run: bun install run: pnpm install
- name: Cache Bun dependencies - name: Cache pnpm dependencies
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
~/.bun/install/cache ~/.pnpm-store
packages/web/node_modules packages/web/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('packages/web/bun.lockb') }} key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
restore-keys: | restore-keys: |
${{ runner.os }}-bun- ${{ runner.os }}-pnpm-
# - name: Run linter - name: Run linter
# working-directory: packages/web run: pnpm run lint
# run: bun run lint
# - name: Check formatter - name: Check formatter
# working-directory: packages/web run: pnpm run check
# run: bun run check
- name: Build Package - name: Build Package
working-directory: packages/web working-directory: packages/web
run: bun run build run: pnpm run build

86
.github/workflows/release-packages.yml

@ -0,0 +1,86 @@
name: Release Packages
on:
workflow_dispatch:
inputs:
packages:
description: 'Packages to release (comma-separated, or "all" for all packages)'
required: false
default: 'all'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# --- Setup Node.js and pnpm ---
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
# --- Setup Deno ---
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
# --- Cache pnpm Dependencies ---
- name: Cache pnpm Dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
packages/web/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
# --- Cache Deno Dependencies ---
- name: Cache Deno Dependencies
uses: actions/cache@v4
with:
path: ~/.cache/deno
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
restore-keys: |
${{ runner.os }}-deno-
- name: Configure pnpm registry
run: pnpm config set registry https://registry.npmjs.org/
- name: Configure pnpm auth
run: pnpm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
- name: Publish packages to npm and JSR
run: |
for dir in packages/*; do
echo "Processing $dir"
cd $dir
# Build and publish to npm if package.json exists
if [ -f "package.json" ]; then
echo "Building and publishing $dir to npm..."
pnpm run build:npm
pnpm run publish:npm || echo "npm publish failed for $dir"
fi
pnpm run prepare:jsr
# Publish to JSR if jsr.json exists
if [ -f "jsr.json" ]; then
echo "Publishing $dir to jsr..."
deno publish || echo "JSR publish failed for $dir"
fi
cd - > /dev/null
done

79
.github/workflows/release-web.yml

@ -0,0 +1,79 @@
name: Release Web
on:
release:
types: [released, prereleased]
permissions:
contents: write
jobs:
release-web:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache Bun Dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
packages/web/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Run Web App Tests
working-directory: packages/web
run: bun run test
- name: Create Web App Release Archive
working-directory: packages/web
run: bun run package
- name: Upload Web App Archive
uses: actions/upload-artifact@v4
with:
name: web-build
if-no-files-found: error
path: packages/web/dist/build.tar
- name: Attach Web Archive to GitHub Release
run: gh release upload ${{ github.event.release.tag_name }} packages/web/dist/build.tar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build Container Image
id: build-container
uses: redhat-actions/buildah-build@v2
with:
containerfiles: |
./infra/Containerfile
image: ghcr.io/${{ github.repository }}
tags: latest, ${{ github.event.release.tag_name }}
oci: true
platforms: linux/amd64, linux/arm64
- name: Push Container to GHCR
id: push-to-registry
uses: redhat-actions/push-to-registry@v2
with:
image: ${{ steps.build-container.outputs.image }}
tags: ${{ steps.build-container.outputs.tags }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Output Image URL
run: echo "🖼️ Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"

182
.github/workflows/release.yml

@ -1,182 +0,0 @@
name: Release
on:
release:
types: [released, prereleased]
permissions:
id-token: write
contents: write
packages: write
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
# --- Checkout Code ---
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
# --- Setup Bun ---
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# --- Setup Deno ---
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
# --- Cache Bun Dependencies ---
- name: Cache Bun Dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
packages/web/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-
# --- Cache Deno Dependencies ---
- name: Cache Deno Dependencies
uses: actions/cache@v4
with:
path: ~/.cache/deno
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
restore-keys: |
${{ runner.os }}-deno-
# --- Determine Changed Packages ---
- name: Get Changed Package Directories
id: changed_packages
uses: tj-actions/changed-files@v46
with:
dir_names: true
files: packages/**
files_ignore: "packages/web/**,packages/transport-deno/npm/**"
# --- Setup Node for NPM Publishing ---
- name: Setup Node.js
if: steps.changed_packages.outputs.all_changed_and_modified_files != ''
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org"
- name: Verify NPM Authentication
if: steps.changed_packages.outputs.all_changed_and_modified_files != ''
run: npm whoami
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# --- Build and Publish Changed Packages ---
- name: Build and Publish Changed Packages
if: steps.changed_packages.outputs.all_changed_and_modified_files != ''
run: |
set -euo pipefail
excluded=("packages/web" "packages/transport-deno" "packages/transport-node")
for pkg_dir in ${{ steps.changed_packages.outputs.all_changed_and_modified_files }}; do
echo "🔍 Inspecting $pkg_dir"
if printf '%s\n' "${excluded[@]}" | grep -q "^$pkg_dir$"; then
echo "⏭️ Skipping excluded package: $pkg_dir"
continue
fi
if [[ -f "$pkg_dir/jsr.json" ]]; then
echo "🦕 Publishing to NPM: $pkg_dir"
bun run build:npm $pkg_dir
echo "📦 Publishing to JSR"
(cd "$pkg_dir" && deno publish --allow-dirty)
elif [[ -f "$pkg_dir/bun.lock" ]]; then
echo "🥖 Building with Bun: $pkg_dir"
(cd "$pkg_dir" && bun install && bun run build)
else
echo "❓ No recognizable build config in $pkg_dir — skipping"
continue
fi
if [[ -d "$pkg_dir/npm" ]]; then
echo "📤 Publishing to NPM: $pkg_dir"
npm publish "$pkg_dir/npm" --access public
fi
done
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: No Packages Changed
if: steps.changed_packages.outputs.all_changed_and_modified_files == ''
run: echo "✅ No changed packages detected. Skipping publish."
# --- Web Package Specific Tasks ---
- name: Check for Web Package Changes
id: web_changes
run: |
if [[ "${{ steps.changed_packages.outputs.all_changed_and_modified_files }}" == *"packages/web"* ]]; then
echo "web_changed=true" >> $GITHUB_OUTPUT
else
echo "web_changed=false" >> $GITHUB_OUTPUT
fi
- name: Run Web App Tests
if: steps.web_changes.outputs.web_changed == 'true'
working-directory: packages/web
run: bun run test
- name: Create Web App Release Archive
if: steps.web_changes.outputs.web_changed == 'true'
working-directory: packages/web
run: bun run package
- name: Upload Web App Archive
if: steps.web_changes.outputs.web_changed == 'true'
uses: actions/upload-artifact@v4
with:
name: web-build
if-no-files-found: error
path: packages/web/dist/build.tar
- name: Attach Web Archive to GitHub Release
if: steps.web_changes.outputs.web_changed == 'true'
run: gh release upload ${{ github.event.release.tag_name }} packages/web/dist/build.tar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# --- Build & Push Container Image ---
- name: Set up QEMU
if: steps.web_changes.outputs.web_changed == 'true'
uses: docker/setup-qemu-action@v3
- name: Build Container Image
if: steps.web_changes.outputs.web_changed == 'true'
id: build-container
uses: redhat-actions/buildah-build@v2
with:
containerfiles: |
./infra/Containerfile
image: ghcr.io/${{ github.repository }}
tags: latest, ${{ github.event.release.tag_name }}
oci: true
platforms: linux/amd64, linux/arm64
- name: Push Container to GHCR
if: steps.web_changes.outputs.web_changed == 'true'
id: push-to-registry
uses: redhat-actions/push-to-registry@v2
with:
image: ${{ steps.build-container.outputs.image }}
tags: ${{ steps.build-container.outputs.tags }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Output Image URL
if: steps.web_changes.outputs.web_changed == 'true'
run: echo "🖼️ Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"

4
.gitignore

@ -1,5 +1,5 @@
dist
node_modules node_modules
dist
stats.html stats.html
.vercel .vercel
.vite .vite
@ -7,4 +7,4 @@ dev-dist
__screenshots__* __screenshots__*
*.diff *.diff
npm/ npm/
.idea

38
README.md

@ -43,7 +43,7 @@ All `Meshtastic JS` packages (core and transports) are published both to
This monorepo leverages the following technologies: This monorepo leverages the following technologies:
- **Runtime:** Bun - **Runtime:** pnpm / Deno
- **Web Client:** React.js - **Web Client:** React.js
- **Styling:** Tailwind CSS - **Styling:** Tailwind CSS
- **Bundling:** Vite - **Bundling:** Vite
@ -56,19 +56,19 @@ This monorepo leverages the following technologies:
### Prerequisites ### Prerequisites
You'll need to have [Bun](https://bun.sh/) installed to work with this monorepo. You'll need to have [pnpm](https://pnpm.io/) installed to work with this monorepo.
Follow the installation instructions on their home page. Follow the installation instructions on their home page.
### Development Setup ### Development Setup
1. **Clone the repository:** 1. **Clone the repository:**
```bash ```bash
git clone [https://github.com/meshtastic/meshtastic-web.git](https://github.com/meshtastic/meshtastic-web.git) git clone https://github.com/meshtastic/meshtastic-web.git
cd meshtastic-web cd meshtastic-web
``` ```
2. **Install dependencies for all packages:** 2. **Install dependencies for all packages:**
```bash ```bash
bun install pnpm install
``` ```
This command installs all necessary dependencies for all packages within the This command installs all necessary dependencies for all packages within the
monorepo. monorepo.
@ -77,40 +77,14 @@ Follow the installation instructions on their home page.
#### Meshtastic Web Client #### Meshtastic Web Client
To start the development server for the web client: Please refer to the [Meshtastic Web README](packages/web/README.md) for setup and usage.
```bash
cd ./packages/web && bun run dev
```
This will typically run the web client on http://localhost:3000 and requires a
Chromium browser
### Feedback ### Feedback
If you encounter any issues with nightly builds, please report them in our If you encounter any issues, please report them in our
[issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps [issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps
improve the stability of future releases improve the stability of future releases
### Why Bun?
Meshtastic Web uses Bun as its development platform for several compelling
reasons:
- **Fast Performance**: Bun is built from the ground up for speed, offering
significantly faster package installation and bundling compared to other
JavaScript runtimes.
- **TypeScript Support**: Native TypeScript support without additional
configuration, enhancing code quality and developer experience.
- **Modern JavaScript**: First-class support for ESM imports, top-level await,
and other modern JavaScript features.
- **All-in-One Tooling**: Built-in package manager, bundler, test runner, and
transpiler eliminate the need for multiple third-party tools.
- **Node.js Compatibility**: Drop-in replacement for Node.js with better
performance and built-in tooling.
- **Reproducible Builds**: Lockfile ensures consistent builds across all
environments.
### Contributing ### Contributing
We welcome contributions! Here’s how the deployment flow works for pull We welcome contributions! Here’s how the deployment flow works for pull

1761
bun.lock

File diff suppressed because it is too large

5472
deno.lock

File diff suppressed because it is too large

27
package.json

@ -12,28 +12,31 @@
"url": "https://github.com/meshtastic/web/issues" "url": "https://github.com/meshtastic/web/issues"
}, },
"homepage": "https://meshtastic.org", "homepage": "https://meshtastic.org",
"workspaces": ["packages/*"], "simple-git-hooks": {
"simple-git-hooks": { "pre-commit": "pnpm run check:fix"
"pre-commit": "bun run check:fix"
}, },
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm",
"lint": "biome lint", "lint": "biome lint",
"lint:fix": "biome lint --write", "lint:fix": "biome lint --write",
"format": "biome format", "format": "biome format",
"format:fix": "biome format . --write", "format:fix": "biome format . --write",
"check": "biome check", "check": "biome check",
"check:fix": "biome check --write", "check:fix": "biome check --write",
"build:npm": "deno run -A scripts/build_npm_package.ts" "build:all": "pnpm run --filter '*' build",
"clean:all": "pnpm run --filter '*' clean",
"publish:packages": "pnpm run --filter 'packages/transport-* packages/core' build"
}, },
"dependencies": { "dependencies": {
"@bufbuild/protobuf": "^2.6.1", "@bufbuild/protobuf": "^2.6.1",
"@meshtastic/protobufs": "npm:@jsr/meshtastic__protobufs", "@meshtastic/protobufs": "npm:@jsr/meshtastic__protobufs@^2.7.0",
"ste-simple-events": "^3.0.11", "ste-simple-events": "^3.0.11",
"tslog": "^4.9.3" "tslog": "^4.9.3"
}, },
"devDependencies": { "devDependencies": {
"bun": "^1.2.18", "@types/node": "^22.16.4",
"typescript": "^5.8.3", "biome": "^0.3.3",
"@types/node": "^22.16.4" "tsdown": "^0.13.4",
"typescript": "^5.8.3"
} }
} }

7
packages/core/jsr.json

@ -0,0 +1,7 @@
{
"name": "@meshtastic/core",
"version": "2.6.6",
"exports": {
".": "./mod.ts"
}
}

2
packages/core/mod.ts

@ -1,5 +1,5 @@
export * as Protobuf from "@meshtastic/protobufs";
export { Constants } from "./src/constants.ts"; export { Constants } from "./src/constants.ts";
export { MeshDevice } from "./src/meshDevice.ts"; export { MeshDevice } from "./src/meshDevice.ts";
export * as Protobuf from "@meshtastic/protobufs";
export * as Types from "./src/types.ts"; export * as Types from "./src/types.ts";
export * as Utils from "./src/utils/mod.ts"; export * as Utils from "./src/utils/mod.ts";

22
packages/core/package.json

@ -1,10 +1,30 @@
{ {
"name": "@meshtastic/core", "name": "@meshtastic/core",
"version": "2.6.5", "version": "2.6.6",
"description": "Core functionalities for Meshtastic web applications.", "description": "Core functionalities for Meshtastic web applications.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"license": "GPL-3.0-only",
"tsdown": {
"entry": ["mod.ts"],
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
},
"dependencies": { "dependencies": {
"crc": "npm:crc@^4.3.2" "crc": "npm:crc@^4.3.2"
} }

25
packages/core/src/meshDevice.ts

@ -1,7 +1,6 @@
import { Logger } from "tslog";
import { create, fromBinary, toBinary } from "@bufbuild/protobuf"; import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
import * as Protobuf from "@meshtastic/protobufs"; import * as Protobuf from "@meshtastic/protobufs";
import { Logger } from "tslog";
import { Constants } from "./constants.ts"; import { Constants } from "./constants.ts";
import type { Destination, PacketMetadata, Transport } from "./types.ts"; import type { Destination, PacketMetadata, Transport } from "./types.ts";
@ -40,6 +39,8 @@ export class MeshDevice {
public xModem: Xmodem; public xModem: Xmodem;
private _heartbeatIntervalId: ReturnType<typeof setInterval> | undefined;
constructor(transport: Transport, configId?: number) { constructor(transport: Transport, configId?: number) {
this.log = new Logger({ this.log = new Logger({
name: "iMeshDevice", name: "iMeshDevice",
@ -201,7 +202,7 @@ export class MeshDevice {
}); });
if (echoResponse) { if (echoResponse) {
meshPacket.rxTime = Math.trunc(new Date().getTime() / 1000); meshPacket.rxTime = Math.trunc(Date.now() / 1000);
this.handleMeshPacket(meshPacket); this.handleMeshPacket(meshPacket);
} }
return await this.sendRaw( return await this.sendRaw(
@ -741,6 +742,18 @@ export class MeshDevice {
return this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio)); return this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
} }
/**
* Initializes the heartbeat interval, which sends a heartbeat ping every interval milliseconds.
*/
public setHeartbeatInterval(interval: number): void {
if (this._heartbeatIntervalId !== undefined) {
clearInterval(this._heartbeatIntervalId);
}
this._heartbeatIntervalId = setInterval(() => {
this.heartbeat();
}, interval);
}
/** /**
* Sends a trace route packet to the designated node * Sends a trace route packet to the designated node
*/ */
@ -798,8 +811,14 @@ export class MeshDevice {
/** Disconnects from the device **/ /** Disconnects from the device **/
public async disconnect(): Promise<void> { public async disconnect(): Promise<void> {
this.log.debug(Emitter[Emitter.Disconnect], "🔌 Disconnecting from device"); this.log.debug(Emitter[Emitter.Disconnect], "🔌 Disconnecting from device");
if (this._heartbeatIntervalId !== undefined) {
clearInterval(this._heartbeatIntervalId);
}
this.complete(); this.complete();
await this.transport.toDevice.close(); await this.transport.toDevice.close();
await this.transport.disconnect();
} }
/** /**

1
packages/core/src/types.ts

@ -15,6 +15,7 @@ export type DeviceOutput = Packet | DebugLog;
export interface Transport { export interface Transport {
toDevice: WritableStream<Uint8Array>; toDevice: WritableStream<Uint8Array>;
fromDevice: ReadableStream<DeviceOutput>; fromDevice: ReadableStream<DeviceOutput>;
disconnect(): Promise<void>;
} }
export interface QueueItem { export interface QueueItem {

4
packages/core/src/utils/mod.ts

@ -1,5 +1,5 @@
export { EventSystem } from "./eventSystem.ts"; export { EventSystem } from "./eventSystem.ts";
export { Queue } from "./queue.ts"; export { Queue } from "./queue.ts";
export { Xmodem } from "./xmodem.ts";
export { toDeviceStream } from "./transform/toDevice.ts";
export { fromDeviceStream } from "./transform/fromDevice.ts"; export { fromDeviceStream } from "./transform/fromDevice.ts";
export { toDeviceStream } from "./transform/toDevice.ts";
export { Xmodem } from "./xmodem.ts";

10
packages/core/src/utils/queue.ts

@ -44,6 +44,16 @@ export class Queue {
if (this.queue.findIndex((qi) => qi.id === item.id) !== -1) { if (this.queue.findIndex((qi) => qi.id === item.id) !== -1) {
this.remove(item.id); this.remove(item.id);
const decoded = fromBinary(Protobuf.Mesh.ToRadioSchema, item.data); const decoded = fromBinary(Protobuf.Mesh.ToRadioSchema, item.data);
if (
decoded.payloadVariant.case === "heartbeat" ||
decoded.payloadVariant.case === "wantConfigId"
) {
// heartbeat and wantConfigId packets are not acknowledged by the device, assume success after timeout
resolve(item.id);
return;
}
console.warn( console.warn(
`Packet ${item.id} of type ${decoded.payloadVariant.case} timed out`, `Packet ${item.id} of type ${decoded.payloadVariant.case} timed out`,
); );

18
packages/core/tsconfig.json

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
},
"include": ["src"]
}

5
packages/transport-deno/deno.json

@ -0,0 +1,5 @@
{
"imports": {
"@deno/dnt": "jsr:@deno/dnt@^0.42.3"
}
}

16
packages/transport-deno/package.json

@ -4,5 +4,19 @@
"description": "Deno-specific transport layer for Meshtastic web applications.", "description": "Deno-specific transport layer for Meshtastic web applications.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
} },
"main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
"license": "GPL-3.0-only",
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}
} }

31
packages/transport-deno/scripts/build_npm.ts

@ -0,0 +1,31 @@
import { build, emptyDir } from "@deno/dnt";
await emptyDir("./npm");
await build({
entryPoints: ["./mod.ts"],
outDir: "./npm",
shims: {
// see JS docs for overview and more options
deno: true,
},
package: {
// package.json properties
name: "@meshtastic/transport-deno",
version: Deno.args[0],
description: "A Deno transport layer for your project, enabling seamless integration with npm.",
license: "GPL-3.0-only",
repository: {
type: "git",
url: "git+https://github.com/username/repo.git",
},
bugs: {
url: "https://github.com/meshtastic/web/issues",
},
},
postBuild() {
// steps to run after building and before running the tests
Deno.copyFileSync("../../LICENSE", "npm/LICENSE");
Deno.copyFileSync("README.md", "npm/README.md");
},
});

14
packages/transport-deno/src/transport.ts

@ -1,9 +1,10 @@
import { Utils } from "@meshtastic/core";
import type { Types } from "@meshtastic/core"; import type { Types } from "@meshtastic/core";
import { Utils } from "@meshtastic/core";
export class TransportDeno implements Types.Transport { export class TransportDeno implements Types.Transport {
private _toDevice: WritableStream<Uint8Array>; private _toDevice: WritableStream<Uint8Array>;
private _fromDevice: ReadableStream<Types.DeviceOutput>; private _fromDevice: ReadableStream<Types.DeviceOutput>;
private connection: Deno.Conn | undefined;
public static async create(hostname: string): Promise<TransportDeno> { public static async create(hostname: string): Promise<TransportDeno> {
const connection = await Deno.connect({ const connection = await Deno.connect({
@ -14,10 +15,11 @@ export class TransportDeno implements Types.Transport {
} }
constructor(connection: Deno.Conn) { constructor(connection: Deno.Conn) {
Utils.toDeviceStream.readable.pipeTo(connection.writable); this.connection = connection;
Utils.toDeviceStream.readable.pipeTo(this.connection.writable);
this._toDevice = Utils.toDeviceStream.writable; this._toDevice = Utils.toDeviceStream.writable;
this._fromDevice = connection.readable.pipeThrough( this._fromDevice = this.connection.readable.pipeThrough(
Utils.fromDeviceStream(), Utils.fromDeviceStream(),
); );
} }
@ -29,4 +31,10 @@ export class TransportDeno implements Types.Transport {
get fromDevice(): ReadableStream<Types.DeviceOutput> { get fromDevice(): ReadableStream<Types.DeviceOutput> {
return this._fromDevice; return this._fromDevice;
} }
disconnect(): Promise<void> {
this.connection.close();
this.connection = undefined;
return Promise.resolve();
}
} }

674
packages/transport-http/LICENSE

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

5
packages/transport-http/jsr.json

@ -1,5 +0,0 @@
{
"name": "@meshtastic/transport-http",
"version": "0.2.2",
"exports": "./mod.ts"
}

33
packages/transport-http/package.json

@ -1,9 +1,32 @@
{ {
"name": "@meshtastic/transport-http", "name": "@meshtastic/transport-http",
"version": "0.2.2", "version": "0.2.3",
"description": "A transport layer for Meshtastic applications using HTTP.", "description": "A transport layer for Meshtastic applications using HTTP.",
"exports": {".": "./mod.ts"}, "exports": {".": "./mod.ts"},
"tasks": { "main": "./dist/mod.mjs",
"build": "deno build" "module": "./dist/mod.mjs",
} "types": "./dist/mod.d.mts",
} "license": "GPL-3.0-only",
"tsdown": {
"entry": ["mod.ts"],
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}
}

1135
packages/transport-http/pnpm-lock.yaml

File diff suppressed because it is too large

26
packages/transport-http/src/transport.ts

@ -6,6 +6,8 @@ export class TransportHTTP implements Types.Transport {
private url: string; private url: string;
private receiveBatchRequests: boolean; private receiveBatchRequests: boolean;
private fetchInterval: number; private fetchInterval: number;
private fetching: boolean;
private interval: ReturnType<typeof setInterval> | undefined;
public static async create( public static async create(
address: string, address: string,
@ -23,6 +25,7 @@ export class TransportHTTP implements Types.Transport {
this.url = url; this.url = url;
this.receiveBatchRequests = false; this.receiveBatchRequests = false;
this.fetchInterval = 3000; this.fetchInterval = 3000;
this.fetching = false;
this._toDevice = new WritableStream<Uint8Array>({ this._toDevice = new WritableStream<Uint8Array>({
write: async (chunk) => { write: async (chunk) => {
@ -38,8 +41,18 @@ export class TransportHTTP implements Types.Transport {
}, },
}); });
setInterval(async () => { this.interval = setInterval(async () => {
await this.readFromRadio(controller); if (this.fetching) {
// We still have the previous request open
return;
}
this.fetching = true;
try {
await this.readFromRadio(controller);
} catch {
// TODO: Emit disconnection events for certain types of errors
}
this.fetching = false;
}, this.fetchInterval); }, this.fetchInterval);
} }
@ -88,4 +101,13 @@ export class TransportHTTP implements Types.Transport {
get fromDevice(): ReadableStream<Types.DeviceOutput> { get fromDevice(): ReadableStream<Types.DeviceOutput> {
return this._fromDevice; return this._fromDevice;
} }
disconnect(): Promise<void> {
this.fetching = false;
if (this.interval) {
clearInterval(this.interval);
}
this.interval = undefined;
return Promise.resolve();
}
} }

13
packages/transport-http/tsconfig.json

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
},
"include": ["src"]
}

29
packages/transport-node/package.json

@ -4,5 +4,32 @@
"description": "NodeJS-specific transport layer for Meshtastic web applications.", "description": "NodeJS-specific transport layer for Meshtastic web applications.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
} },
"main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"license": "GPL-3.0-only",
"tsdown": {
"entry": ["mod.ts"],
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}
} }

20
packages/transport-node/src/transport.ts

@ -1,11 +1,12 @@
import { Socket } from "node:net"; import { Socket } from "node:net";
import { Readable, Writable } from "node:stream"; import { Readable, Writable } from "node:stream";
import { Utils } from "@meshtastic/core";
import type { Types } from "@meshtastic/core"; import type { Types } from "@meshtastic/core";
import { Utils } from "@meshtastic/core";
export class TransportNode implements Types.Transport { export class TransportNode implements Types.Transport {
private readonly _toDevice: WritableStream<Uint8Array>; private readonly _toDevice: WritableStream<Uint8Array>;
private readonly _fromDevice: ReadableStream<Types.DeviceOutput>; private readonly _fromDevice: ReadableStream<Types.DeviceOutput>;
private socket: Socket | undefined;
/** /**
* Creates and connects a new TransportNode instance. * Creates and connects a new TransportNode instance.
@ -36,7 +37,8 @@ export class TransportNode implements Types.Transport {
* @param connection - An active Node.js net.Socket connection. * @param connection - An active Node.js net.Socket connection.
*/ */
constructor(connection: Socket) { constructor(connection: Socket) {
connection.on("error", (err) => { this.socket = connection;
this.socket.on("error", (err) => {
console.error("Socket connection error:", err); console.error("Socket connection error:", err);
}); });
@ -45,9 +47,9 @@ export class TransportNode implements Types.Transport {
) as ReadableStream<Uint8Array>; ) as ReadableStream<Uint8Array>;
this._fromDevice = fromDeviceSource.pipeThrough(Utils.fromDeviceStream()); this._fromDevice = fromDeviceSource.pipeThrough(Utils.fromDeviceStream());
// Stream for data going FROM the application TO the Meshtastic device. // Stream for data going FROM the application TO the Meshtastic device.
const toDeviceTransform = Utils.toDeviceStream; const toDeviceTransform = Utils.toDeviceStream;
this._toDevice = toDeviceTransform.writable; this._toDevice = toDeviceTransform.writable;
// The readable end of the transform is then piped to the Node.js socket. // The readable end of the transform is then piped to the Node.js socket.
// A similar assertion is needed here because `Writable.toWeb` also returns // A similar assertion is needed here because `Writable.toWeb` also returns
@ -56,7 +58,7 @@ export class TransportNode implements Types.Transport {
.pipeTo(Writable.toWeb(connection) as WritableStream<Uint8Array>) .pipeTo(Writable.toWeb(connection) as WritableStream<Uint8Array>)
.catch((err) => { .catch((err) => {
console.error("Error piping data to socket:", err); console.error("Error piping data to socket:", err);
connection.destroy(err as Error); this.socket.destroy(err as Error);
}); });
} }
@ -73,4 +75,10 @@ export class TransportNode implements Types.Transport {
public get fromDevice(): ReadableStream<Types.DeviceOutput> { public get fromDevice(): ReadableStream<Types.DeviceOutput> {
return this._fromDevice; return this._fromDevice;
} }
disconnect() {
this.socket.destroy();
this.socket = undefined;
return Promise.resolve();
}
} }

18
packages/transport-node/tsconfig.json

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
},
"include": ["src"]
}

5
packages/transport-web-bluetooth/jsr.json

@ -1,5 +0,0 @@
{
"name": "@meshtastic/transport-web-bluetooth",
"version": "0.1.3",
"exports": "./mod.ts"
}

29
packages/transport-web-bluetooth/package.json

@ -1,14 +1,33 @@
{ {
"name": "@meshtastic/transport-web-bluetooth", "name": "@meshtastic/transport-web-bluetooth",
"version": "0.1.3", "version": "0.1.4",
"description": "A transport layer for Meshtastic applications using Web Bluetooth.", "description": "A transport layer for Meshtastic applications using Web Bluetooth.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"devDependencies": { "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
"license": "GPL-3.0-only",
"tsdown": {
"entry": ["mod.ts"],
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
},
"dependencies": {
"@types/web-bluetooth": "npm:@types/web-bluetooth@^0.0.20" "@types/web-bluetooth": "npm:@types/web-bluetooth@^0.0.20"
},
"compilerOptions": {
"types": ["@types/web-bluetooth"]
} }
} }

10
packages/transport-web-bluetooth/src/transport.ts

@ -9,6 +9,7 @@ export class TransportWebBluetooth implements Types.Transport {
private toRadioCharacteristic: BluetoothRemoteGATTCharacteristic; private toRadioCharacteristic: BluetoothRemoteGATTCharacteristic;
private fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic; private fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic;
private fromNumCharacteristic: BluetoothRemoteGATTCharacteristic; private fromNumCharacteristic: BluetoothRemoteGATTCharacteristic;
private gattServer: BluetoothRemoteGATTServer;
static ToRadioUuid = "f75c76d2-129e-4dad-a1dd-7866124401e7"; static ToRadioUuid = "f75c76d2-129e-4dad-a1dd-7866124401e7";
static FromRadioUuid = "2c55e69e-4993-11ed-b878-0242ac120002"; static FromRadioUuid = "2c55e69e-4993-11ed-b878-0242ac120002";
@ -65,6 +66,7 @@ export class TransportWebBluetooth implements Types.Transport {
toRadioCharacteristic, toRadioCharacteristic,
fromRadioCharacteristic, fromRadioCharacteristic,
fromNumCharacteristic, fromNumCharacteristic,
gattServer,
); );
} }
@ -72,10 +74,12 @@ export class TransportWebBluetooth implements Types.Transport {
toRadioCharacteristic: BluetoothRemoteGATTCharacteristic, toRadioCharacteristic: BluetoothRemoteGATTCharacteristic,
fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic, fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic,
fromNumCharacteristic: BluetoothRemoteGATTCharacteristic, fromNumCharacteristic: BluetoothRemoteGATTCharacteristic,
gattServer: BluetoothRemoteGATTServer,
) { ) {
this.toRadioCharacteristic = toRadioCharacteristic; this.toRadioCharacteristic = toRadioCharacteristic;
this.fromRadioCharacteristic = fromRadioCharacteristic; this.fromRadioCharacteristic = fromRadioCharacteristic;
this.fromNumCharacteristic = fromNumCharacteristic; this.fromNumCharacteristic = fromNumCharacteristic;
this.gattServer = gattServer;
this._fromDevice = new ReadableStream({ this._fromDevice = new ReadableStream({
start: (ctrl) => { start: (ctrl) => {
@ -89,6 +93,7 @@ export class TransportWebBluetooth implements Types.Transport {
if (this._isFirstWrite && this._fromDeviceController) { if (this._isFirstWrite && this._fromDeviceController) {
this._isFirstWrite = false; this._isFirstWrite = false;
setTimeout(() => { setTimeout(() => {
this.readFromRadio(this._fromDeviceController!); this.readFromRadio(this._fromDeviceController!);
}, 50); }, 50);
@ -132,4 +137,9 @@ export class TransportWebBluetooth implements Types.Transport {
}); });
} }
} }
disconnect(): Promise<void> {
this.gattServer.disconnect();
return Promise.resolve();
}
} }

19
packages/transport-web-bluetooth/tsconfig.json

@ -0,0 +1,19 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
"types": ["@types/web-bluetooth"],
},
"include": ["src"]
}

5
packages/transport-web-serial/jsr.json

@ -1,5 +0,0 @@
{
"name": "@meshtastic/transport-web-serial",
"version": "0.2.2",
"exports": "./mod.ts"
}

26
packages/transport-web-serial/package.json

@ -1,14 +1,32 @@
{ {
"name": "@meshtastic/transport-web-serial", "name": "@meshtastic/transport-web-serial",
"version": "0.2.2", "version": "0.2.3",
"description": "A transport layer for Meshtastic applications using Web Serial API.", "description": "A transport layer for Meshtastic applications using Web Serial API.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
"license": "GPL-3.0-only",
"tsdown": {
"entry": ["mod.ts"],
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
},
"dependencies": { "dependencies": {
"@types/w3c-web-serial": "npm:@types/w3c-web-serial@^1.0.7" "@types/w3c-web-serial": "npm:@types/w3c-web-serial@^1.0.7"
},
"compilerOptions": {
"types": ["@types/w3c-web-serial"]
} }
} }

9
packages/transport-web-serial/src/transport.ts

@ -1,9 +1,10 @@
import { Utils } from "@meshtastic/core";
import type { Types } from "@meshtastic/core"; import type { Types } from "@meshtastic/core";
import { Utils } from "@meshtastic/core";
export class TransportWebSerial implements Types.Transport { export class TransportWebSerial implements Types.Transport {
private _toDevice: WritableStream<Uint8Array>; private _toDevice: WritableStream<Uint8Array>;
private _fromDevice: ReadableStream<Types.DeviceOutput>; private _fromDevice: ReadableStream<Types.DeviceOutput>;
private connection: SerialPort;
public static async create(baudRate?: number): Promise<TransportWebSerial> { public static async create(baudRate?: number): Promise<TransportWebSerial> {
const port = await navigator.serial.requestPort(); const port = await navigator.serial.requestPort();
@ -24,6 +25,8 @@ export class TransportWebSerial implements Types.Transport {
throw new Error("Stream not accessible"); throw new Error("Stream not accessible");
} }
this.connection = connection;
Utils.toDeviceStream.readable.pipeTo(connection.writable); Utils.toDeviceStream.readable.pipeTo(connection.writable);
this._toDevice = Utils.toDeviceStream.writable; this._toDevice = Utils.toDeviceStream.writable;
@ -39,4 +42,8 @@ export class TransportWebSerial implements Types.Transport {
get fromDevice(): ReadableStream<Types.DeviceOutput> { get fromDevice(): ReadableStream<Types.DeviceOutput> {
return this._fromDevice; return this._fromDevice;
} }
disconnect() {
return this.connection.close();
}
} }

19
packages/transport-web-serial/tsconfig.json

@ -0,0 +1,19 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
"types": ["@types/w3c-web-serial"],
},
"include": ["src"]
}

2
packages/web/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md

@ -57,7 +57,7 @@ when creating new keys in the JSON files.
### Namespace Rules ### Namespace Rules
We use namespaces to organize keys. All source keys are added to the English We use namespaces to organize keys. All source keys are added to the English
(`en`) files located at `/i18n/locales/en/`. Place your new keys in the (`en`) files located at `/packages/web/public/i18n/locales/en/`. Place your new keys in the
appropriate file based on these rules: appropriate file based on these rules:
- `common.json`: - `common.json`:

31
packages/web/README.md

@ -81,7 +81,7 @@ improve the stability of future releases
## Development & Building ## Development & Building
You'll need to download the package manager used with this repo. You can install You'll need to download the package manager used with this repo. You can install
it by visiting [bun.sh](https://bun.sh/) and following the installation it by visiting [pnpm.io](https://pnpm.io/) and following the installation
instructions listed on the home page. instructions listed on the home page.
### Development ### Development
@ -90,13 +90,13 @@ Install the dependencies.
```bash ```bash
cd packages/web && cd packages/web &&
bun install pnpm install
``` ```
Start the development server: Start the development server:
```bash ```bash
bun run dev pnpm run dev
``` ```
### Building and Packaging ### Building and Packaging
@ -104,29 +104,28 @@ bun run dev
Build the project: Build the project:
```bash ```bash
bun run build pnpm run build
``` ```
GZip the output: GZip the output:
```bash ```bash
bun run package pnpm run package
``` ```
### Why Bun? ### Why pnpm?
Meshtastic Web uses Bun as its development platform for several compelling Meshtastic Web uses pnpm as its package manager for several compelling
reasons: reasons:
- **Fast Performance**: Bun is built from the ground up for speed, offering - **Efficient Storage**: pnpm uses content-addressable storage, avoiding duplication
significantly faster package installation and bundling compared to other of packages across projects and saving significant disk space.
JavaScript runtimes. - **Fast Performance**: Faster package installation compared to other package
- **TypeScript Support**: Native TypeScript support without additional managers through symlinks and efficient dependency resolution.
configuration, enhancing code quality and developer experience. - **Strict Dependency Management**: Prevents access to unlisted dependencies,
- **Modern JavaScript**: First-class support for ESM imports, top-level await, ensuring better project reliability and security.
and other modern JavaScript features. - **Workspace Support**: Excellent monorepo support with workspaces for managing
- **Node.js Compatibility**: Drop-in replacement for Node.js with better multiple packages efficiently.
performance and built-in tooling.
- **Reproducible Builds**: Lockfile ensures consistent builds across all - **Reproducible Builds**: Lockfile ensures consistent builds across all
environments. environments.

4
packages/web/crowdin.yml

@ -6,5 +6,5 @@ base_url: "https://meshtastic.crowdin.com/api/v2"
preserve_hierarchy: true preserve_hierarchy: true
files: files:
- source: "/i18n/locales/en/*.json" - source: "/public/i18n/locales/en/*.json"
translation: "/i18n/locales/%locale%/%original_file_name%" translation: "/public/i18n/locales/%locale%/%original_file_name%"

5
packages/web/index.html

@ -1,6 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" data-theme="system"> <html lang="en" data-theme="system">
<head> <head>
<!-- CookieYes banner -->
<%- cookieYesScript %>
<!-- End of CookieYes banner -->
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
@ -26,7 +29,7 @@
<meta name="theme-color" content="#67ea94" /> <meta name="theme-color" content="#67ea94" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Meshtastic Web Client" /> <meta name="description" content="Meshtastic Web Client" />
<title>Meshtastic Web</title> <title><%- title %></title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

8
packages/web/package.json

@ -11,9 +11,9 @@
"bugs": { "bugs": {
"url": "https://github.com/meshtastic/web/issues" "url": "https://github.com/meshtastic/web/issues"
}, },
"homepage": "https://meshtastic.org", "homepage": "https://meshtastic.org",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm",
"build": "vite build", "build": "vite build",
"build:analyze": "BUNDLE_ANALYZE=true bun run build", "build:analyze": "BUNDLE_ANALYZE=true bun run build",
"check": "biome check src/", "check": "biome check src/",
@ -28,7 +28,7 @@
"dependencies": { "dependencies": {
"@bufbuild/protobuf": "^2.6.0", "@bufbuild/protobuf": "^2.6.0",
"@hookform/resolvers": "^5.1.1", "@hookform/resolvers": "^5.1.1",
"@meshtastic/core": "npm:@jsr/[email protected]", "@meshtastic/core": "workspace:*",
"@meshtastic/transport-http": "npm:@jsr/meshtastic__transport-http", "@meshtastic/transport-http": "npm:@jsr/meshtastic__transport-http",
"@meshtastic/transport-web-bluetooth": "npm:@jsr/meshtastic__transport-web-bluetooth", "@meshtastic/transport-web-bluetooth": "npm:@jsr/meshtastic__transport-web-bluetooth",
"@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial", "@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial",
@ -49,6 +49,7 @@
"@radix-ui/react-toast": "^1.2.14", "@radix-ui/react-toast": "^1.2.14",
"@radix-ui/react-toggle-group": "^1.1.10", "@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7", "@radix-ui/react-tooltip": "^1.2.7",
"@radix-ui/react-visually-hidden": "^1.2.3",
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"@tanstack/react-router": "^1.127.9", "@tanstack/react-router": "^1.127.9",
"@tanstack/react-router-devtools": "^1.127.9", "@tanstack/react-router-devtools": "^1.127.9",
@ -78,6 +79,8 @@
"react-map-gl": "8.0.4", "react-map-gl": "8.0.4",
"react-qrcode-logo": "^3.0.0", "react-qrcode-logo": "^3.0.0",
"rfc4648": "^1.5.4", "rfc4648": "^1.5.4",
"vite-plugin-html": "^3.2.2",
"vite": "^7.0.4",
"zod": "^4.0.5", "zod": "^4.0.5",
"zustand": "5.0.6" "zustand": "5.0.6"
}, },
@ -104,7 +107,6 @@
"tar": "^7.4.3", "tar": "^7.4.3",
"testing-library": "^0.0.2", "testing-library": "^0.0.2",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vite": "^7.0.4",
"vitest": "^3.2.4" "vitest": "^3.2.4"
} }
} }

66
packages/web/public/i18n/locales/bg-BG/channels.json

@ -2,68 +2,68 @@
"page": { "page": {
"sectionLabel": "Канали", "sectionLabel": "Канали",
"channelName": "Канал: {{channelName}}", "channelName": "Канал: {{channelName}}",
"broadcastLabel": "Primary", "broadcastLabel": "Първичен",
"channelIndex": "Ch {{index}}" "channelIndex": "Ch {{index}}"
}, },
"validation": { "validation": {
"pskInvalid": "Please enter a valid {{bits}} bit PSK." "pskInvalid": "Моля, въведете валиден {{bits}} bit PSK."
}, },
"settings": { "settings": {
"label": "Настройки на канала", "label": "Настройки на канала",
"description": "Crypto, MQTT & misc settings" "description": "Крипто, MQTT и други настройки"
}, },
"role": { "role": {
"label": "Роля", "label": "Роля",
"description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", "description": "Телеметрията на устройството се изпраща през ПЪРВИЧЕН. Разрешен е само един ПЪРВИЧЕН.",
"options": { "options": {
"primary": "PRIMARY", "primary": "ПЪРВИЧЕН",
"disabled": "DISABLED", "disabled": "ДЕЗАКТИВИРАН",
"secondary": "SECONDARY" "secondary": "ВТОРИЧЕН"
} }
}, },
"psk": { "psk": {
"label": "Pre-Shared Key", "label": "Предварително споделен ключ",
"description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", "description": "Поддържани дължини на PSK: 256-битова, 128-битова, 8-битова, празна (0-битова)",
"generate": "Генериране" "generate": "Генериране"
}, },
"name": { "name": {
"label": "Име", "label": "Име",
"description": "A unique name for the channel <12 bytes, leave blank for default" "description": "Уникално име за канала <12 байта, оставете празно за подразбиране"
}, },
"uplinkEnabled": { "uplinkEnabled": {
"label": "Uplink Enabled", "label": "Uplink Enabled",
"description": "Send messages from the local mesh to MQTT" "description": "Изпращане на съобщения от локалната mesh към MQTT"
}, },
"downlinkEnabled": { "downlinkEnabled": {
"label": "Downlink Enabled", "label": "Downlink Enabled",
"description": "Send messages from MQTT to the local mesh" "description": "Изпращане на съобщения от MQTT към локалната mesh"
}, },
"positionPrecision": { "positionPrecision": {
"label": "Местоположение", "label": "Местоположение",
"description": "The precision of the location to share with the channel. Can be disabled.", "description": "Точността на местоположението, което да се споделя с канала. Може да бъде дезактивирано.",
"options": { "options": {
"none": "Да не се споделя местоположението", "none": "Да не се споделя местоположението",
"precise": "Точно местоположение", "precise": "Точно местоположение",
"metric_km23": "Within 23 kilometers", "metric_km23": "В рамките на 23 километра",
"metric_km12": "Within 12 kilometers", "metric_km12": "В рамките на 12 километра",
"metric_km5_8": "Within 5.8 kilometers", "metric_km5_8": "В рамките на 5.8 километра",
"metric_km2_9": "Within 2.9 kilometers", "metric_km2_9": "В рамките на 2.9 километра",
"metric_km1_5": "Within 1.5 kilometers", "metric_km1_5": "В рамките на 1.5 километра",
"metric_m700": "Within 700 meters", "metric_m700": "В рамките на 700 метра",
"metric_m350": "Within 350 meters", "metric_m350": "В рамките на 350 метра",
"metric_m200": "Within 200 meters", "metric_m200": "В рамките на 200 метра",
"metric_m90": "Within 90 meters", "metric_m90": "В рамките на 90 метра",
"metric_m50": "Within 50 meters", "metric_m50": "В рамките на 50 метра",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "В рамките на 15 мили",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "В рамките на 7.3 мили",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "В рамките на 3.6 мили",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "В рамките на 1.8 мили",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "В рамките на 0.9 мили",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "В рамките на 0.5 мили",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "В рамките на 0.2 мили",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "В рамките на 600 фута",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "В рамките на 300 фута",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "В рамките на 150 фута"
} }
} }
} }

97
packages/web/public/i18n/locales/bg-BG/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "Няма намерени резултати.", "emptyState": "Няма намерени резултати.",
"page": { "page": {
"title": "Command Menu" "title": "Command Menu"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Pin command group"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Unpin command group"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Goto",
"command": { "command": {
"messages": "Съобщения", "messages": "Съобщения",
"map": "Карта", "map": "Карта",
"config": "Конфигурация", "config": "Конфигурация",
"channels": "Канали", "channels": "Канали",
"nodes": "Възли" "nodes": "Възли"
} }
}, },
"manage": { "manage": {
"label": "Управление", "label": "Управление",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Switch Node",
"connectNewNode": "Свързване на нов възел" "connectNewNode": "Свързване на нов възел"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextual",
"command": { "command": {
"qrCode": "QR код", "qrCode": "QR код",
"qrGenerator": "Генератор", "qrGenerator": "Генератор",
"qrImport": "Импортиране", "qrImport": "Импортиране",
"scheduleShutdown": "Планирано изключване", "scheduleShutdown": "Планирано изключване",
"scheduleReboot": "Планирано рестартиране", "scheduleReboot": "Планирано рестартиране",
"rebootToOtaMode": "Рестартиране в режим OTA", "rebootToOtaMode": "Рестартиране в режим OTA",
"resetNodeDb": "Нулиране на базата данни с възли", "resetNodeDb": "Нулиране на базата данни с възли",
"factoryResetDevice": "Фабрично нулиране на устройството", "factoryResetDevice": "Фабрично нулиране на устройството",
"factoryResetConfig": "Фабрично нулиране на конфигурацията" "factoryResetConfig": "Фабрично нулиране на конфигурацията",
} "disconnect": "Прекъсване"
}, }
"debug": { },
"label": "Отстраняване на грешки", "debug": {
"command": { "label": "Отстраняване на грешки",
"reconfigure": "Преконфигуриране", "command": {
"clearAllStoredMessages": "Изчистване на всички съхранени съобщения" "reconfigure": "Преконфигуриране",
} "clearAllStoredMessages": "Изчистване на всички съхранени съобщения"
} }
}
} }

32
packages/web/public/i18n/locales/bg-BG/common.json

@ -1,7 +1,7 @@
{ {
"button": { "button": {
"apply": "Приложи", "apply": "Приложи",
"backupKey": "Backup Key", "backupKey": "Резервно копие на ключа",
"cancel": "Отказ", "cancel": "Отказ",
"clearMessages": "Изчистване на съобщенията", "clearMessages": "Изчистване на съобщенията",
"close": "Затвори", "close": "Затвори",
@ -19,7 +19,7 @@
"print": "Отпечатване", "print": "Отпечатване",
"rebootOtaNow": "Reboot to OTA Mode Now", "rebootOtaNow": "Reboot to OTA Mode Now",
"remove": "Изтрий", "remove": "Изтрий",
"requestNewKeys": "Request New Keys", "requestNewKeys": "Заявка за нови ключове",
"requestPosition": "Request Position", "requestPosition": "Request Position",
"reset": "Нулиране", "reset": "Нулиране",
"save": "Запис", "save": "Запис",
@ -37,8 +37,8 @@
"dbm": "dBm", "dbm": "dBm",
"hertz": "Hz", "hertz": "Hz",
"hop": { "hop": {
"one": "Hop", "one": "Хоп",
"plural": "Hops" "plural": "Хопа"
}, },
"hopsAway": { "hopsAway": {
"one": "{{count}} hop away", "one": "{{count}} hop away",
@ -93,7 +93,7 @@
} }
}, },
"security": { "security": {
"0bit": "Empty", "0bit": "Празен",
"8bit": "8 bit", "8bit": "8 bit",
"128bit": "128 bit", "128bit": "128 bit",
"256bit": "256 bit" "256bit": "256 bit"
@ -109,32 +109,32 @@
"fallbackName": "Meshtastic {{last4}}", "fallbackName": "Meshtastic {{last4}}",
"node": "Възел", "node": "Възел",
"formValidation": { "formValidation": {
"unsavedChanges": "Unsaved changes", "unsavedChanges": "Незапазени промени",
"tooBig": { "tooBig": {
"string": "Too long, expected less than or equal to {{maximum}} characters.", "string": "Твърде дълъг, очаква се по-малко или равно на {{maximum}} знака.",
"number": "Too big, expected a number smaller than or equal to {{maximum}}.", "number": "Твърде голям, очаква се число по-малко или равно на {{maximum}}.",
"bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." "bytes": "Твърде голям, очаква се по-малък или равен на {{params.maximum}} байта."
}, },
"tooSmall": { "tooSmall": {
"string": "Too short, expected more than or equal to {{minimum}} characters.", "string": "Твърде кратък, очаква се повече или равно на {{minimum}} знака.",
"number": "Too small, expected a number larger than or equal to {{minimum}}." "number": "Твърде малък, очаква се число, по-голямо или равно на {{minimum}}."
}, },
"invalidFormat": { "invalidFormat": {
"ipv4": "Невалиден формат, очаква се IPv4 адрес.", "ipv4": "Невалиден формат, очаква се IPv4 адрес.",
"key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." "key": "Невалиден формат, очаква се предварително споделен ключ (PSK), кодиран с Base64."
}, },
"invalidType": { "invalidType": {
"number": "Невалиден тип, очаква се число." "number": "Невалиден тип, очаква се число."
}, },
"pskLength": { "pskLength": {
"0bit": "Ключът трябва да е празен.", "0bit": "Ключът трябва да е празен.",
"8bit": "Key is required to be an 8 bit pre-shared key (PSK).", "8bit": "Ключът трябва да бъде 8-битов предварително споделен ключ (PSK).",
"128bit": "Key is required to be a 128 bit pre-shared key (PSK).", "128bit": "Ключът трябва да бъде 128-битов предварително споделен ключ (PSK).",
"256bit": "Key is required to be a 256 bit pre-shared key (PSK)." "256bit": "Ключът трябва да бъде 256-битов предварително споделен ключ (PSK)."
}, },
"required": { "required": {
"generic": "Това поле е задължително.", "generic": "Това поле е задължително.",
"managed": "At least one admin key is requred if the node is managed.", "managed": "Изисква се поне един администраторски ключ, ако възелът е управляван.",
"key": "Ключът е задължителен." "key": "Ключът е задължителен."
} }
} }

38
packages/web/public/i18n/locales/bg-BG/deviceConfig.json

@ -83,7 +83,7 @@
}, },
"compassNorthTop": { "compassNorthTop": {
"description": "Fix north to the top of compass", "description": "Fix north to the top of compass",
"label": "Compass North Top" "label": "Север на компаса отгоре"
}, },
"displayMode": { "displayMode": {
"description": "Screen layout variant", "description": "Screen layout variant",
@ -102,8 +102,8 @@
"label": "GPS Display Units" "label": "GPS Display Units"
}, },
"oledType": { "oledType": {
"description": "Type of OLED screen attached to the device", "description": "Тип на OLED екрана, прикрепен към устройството",
"label": "OLED Type" "label": "Тип OLED"
}, },
"screenTimeout": { "screenTimeout": {
"description": "Turn off the display after this long", "description": "Turn off the display after this long",
@ -120,7 +120,7 @@
}, },
"lora": { "lora": {
"title": "Настройки на Mesh", "title": "Настройки на Mesh",
"description": "Settings for the LoRa mesh", "description": "Настройки за LoRa mesh",
"bandwidth": { "bandwidth": {
"description": "Широчина на канала в MHz", "description": "Широчина на канала в MHz",
"label": "Широчина на честотната лента" "label": "Широчина на честотната лента"
@ -142,12 +142,12 @@
"label": "Честотен слот" "label": "Честотен слот"
}, },
"hopLimit": { "hopLimit": {
"description": "Maximum number of hops", "description": "Максимален брой хопове",
"label": "Hop Limit" "label": "Лимит на хопове"
}, },
"ignoreMqtt": { "ignoreMqtt": {
"description": "Don't forward MQTT messages over the mesh", "description": "Да не се препращат MQTT съобщения през mesh",
"label": "Ignore MQTT" "label": "Игнориране на MQTT"
}, },
"modemPreset": { "modemPreset": {
"description": "Използване на предварително настроен модем", "description": "Използване на предварително настроен модем",
@ -166,7 +166,7 @@
"label": "Override Frequency" "label": "Override Frequency"
}, },
"region": { "region": {
"description": "Sets the region for your node", "description": "Задаване на региона за вашия възел",
"label": "Регион" "label": "Регион"
}, },
"spreadingFactor": { "spreadingFactor": {
@ -186,7 +186,7 @@
"label": "Използване на предварително зададени настройки" "label": "Използване на предварително зададени настройки"
}, },
"meshSettings": { "meshSettings": {
"description": "Settings for the LoRa mesh", "description": "Настройки за LoRa mesh",
"label": "Настройки на Mesh" "label": "Настройки на Mesh"
}, },
"waveformSettings": { "waveformSettings": {
@ -239,16 +239,16 @@
"label": "Активиран" "label": "Активиран"
}, },
"meshViaUdp": { "meshViaUdp": {
"label": "Mesh via UDP" "label": "Mesh чрез UDP"
}, },
"ntpServer": { "ntpServer": {
"label": "NTP сървър" "label": "NTP сървър"
}, },
"rsyslogServer": { "rsyslogServer": {
"label": "Rsyslog Server" "label": "Сървър Rsyslog"
}, },
"ethernetConfigSettings": { "ethernetConfigSettings": {
"description": "Ethernet port configuration", "description": "Конфигурация на Ethernet порта",
"label": "Конфигурация на Ethernet " "label": "Конфигурация на Ethernet "
}, },
"ipConfigSettings": { "ipConfigSettings": {
@ -260,11 +260,11 @@
"label": "Конфигурация на NTP" "label": "Конфигурация на NTP"
}, },
"rsyslogConfigSettings": { "rsyslogConfigSettings": {
"description": "Rsyslog configuration", "description": "Конфигурация на Rsyslog",
"label": "Rsyslog Config" "label": "Конфиг. на Rsyslog"
}, },
"udpConfigSettings": { "udpConfigSettings": {
"description": "UDP over Mesh configuration", "description": "Конфигурация на UDP през Mesh",
"label": "Конфигурация на UDP" "label": "Конфигурация на UDP"
} }
}, },
@ -326,10 +326,10 @@
"altitudeMsl": "Altitude is Mean Sea Level", "altitudeMsl": "Altitude is Mean Sea Level",
"dop": "Dilution of precision (DOP) PDOP used by default", "dop": "Dilution of precision (DOP) PDOP used by default",
"hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP",
"numSatellites": "Number of satellites", "numSatellites": "Брой сателити",
"sequenceNumber": "Sequence number", "sequenceNumber": "Sequence number",
"timestamp": "Времево клеймо", "timestamp": "Времево клеймо",
"unset": "Отказ", "unset": "Не е зададен",
"vehicleHeading": "Vehicle heading", "vehicleHeading": "Vehicle heading",
"vehicleSpeed": "Скорост на превозното средство" "vehicleSpeed": "Скорост на превозното средство"
} }
@ -379,7 +379,7 @@
"security": { "security": {
"description": "Settings for the Security configuration", "description": "Settings for the Security configuration",
"title": "Насртойки на сигурността", "title": "Насртойки на сигурността",
"button_backupKey": "Backup Key", "button_backupKey": "Резервно копие на ключа",
"adminChannelEnabled": { "adminChannelEnabled": {
"description": "Allow incoming device control over the insecure legacy admin channel", "description": "Allow incoming device control over the insecure legacy admin channel",
"label": "Allow Legacy Admin" "label": "Allow Legacy Admin"

59
packages/web/public/i18n/locales/bg-BG/dialog.json

@ -7,10 +7,16 @@
"description": "Устройството ще се рестартира, след като конфигурацията бъде запазена.", "description": "Устройството ще се рестартира, след като конфигурацията бъде запазена.",
"longName": "Дълго име", "longName": "Дълго име",
"shortName": "Кратко име", "shortName": "Кратко име",
"title": "Промяна на името на устройството" "title": "Промяна на името на устройството",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "Текущата конфигурация на LoRa ще бъде презаписана.",
"error": { "error": {
"invalidUrl": "Невалиден Meshtastic URL" "invalidUrl": "Невалиден Meshtastic URL"
}, },
@ -21,13 +27,14 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Местоположение: {{identifier}}",
"altitude": "Надморска височина: ", "altitude": "Надморска височина: ",
"coordinates": "Координати:", "coordinates": "Координати:",
"title": "Местоположение: {{identifier}}" "noCoordinates": "Няма координати"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Регенериране на предварително споделения ключ?",
"description": "Are you sure you want to regenerate the pre-shared key?", "description": "Сигурни ли сте, че искате да регенерирате предварително споделения ключ?",
"regenerate": "Регенериране" "regenerate": "Регенериране"
}, },
"newDeviceDialog": { "newDeviceDialog": {
@ -36,7 +43,7 @@
"http": "http", "http": "http",
"tabHttp": "HTTP", "tabHttp": "HTTP",
"tabBluetooth": "Bluetooth", "tabBluetooth": "Bluetooth",
"tabSerial": "Serial", "tabSerial": "Серийна",
"useHttps": "Използване на HTTPS", "useHttps": "Използване на HTTPS",
"connecting": "Свързване...", "connecting": "Свързване...",
"connect": "Свързване", "connect": "Свързване",
@ -46,7 +53,7 @@
"httpsHint": "Ако използвате HTTPS, може да се наложи първо да приемете самоподписан сертификат. ", "httpsHint": "Ако използвате HTTPS, може да се наложи първо да приемете самоподписан сертификат. ",
"openLinkPrefix": "Моля, отворете", "openLinkPrefix": "Моля, отворете",
"openLinkSuffix": "в нов раздел", "openLinkSuffix": "в нов раздел",
"acceptTlsWarningSuffix": "", "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again",
"learnMoreLink": "Научете повече" "learnMoreLink": "Научете повече"
}, },
"httpConnection": { "httpConnection": {
@ -60,13 +67,17 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "Все още няма сдвоени устройства.", "noDevicesPaired": "Все още няма сдвоени устройства.",
"newDeviceButton": "Ново устройство" "newDeviceButton": "Ново устройство",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Неизвестно устройство",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "Този тип връзка изисква <0></0>. Моля, използвайте поддържан браузър, като Chrome или Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.", "requiresSecureContext": "Това приложение изисква <0>secure context</0>. Моля, свържете се чрез HTTPS или localhost.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "additionallyRequiresSecureContext": "Освен това, изисква <0>secure context</0>. Моля, свържете се чрез HTTPS или localhost."
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
}, },
"nodeDetails": { "nodeDetails": {
@ -88,9 +99,9 @@
"uptime": "Време на работа: ", "uptime": "Време на работа: ",
"voltage": "Напрежение", "voltage": "Напрежение",
"title": "Node Details for {{identifier}}", "title": "Node Details for {{identifier}}",
"ignoreNode": "Ignore node", "ignoreNode": "Игнориране на възела",
"removeNode": "Remove node", "removeNode": "Премахване на възела",
"unignoreNode": "Unignore node" "unignoreNode": "Премахване на игнорирането на възела"
}, },
"pkiBackup": { "pkiBackup": {
"loseKeysWarning": "Ако загубите ключовете си, ще трябва да нулирате устройството си.", "loseKeysWarning": "Ако загубите ключовете си, ще трябва да нулирате устройството си.",
@ -103,11 +114,11 @@
"title": "Backup Keys" "title": "Backup Keys"
}, },
"pkiBackupReminder": { "pkiBackupReminder": {
"description": "We recommend backing up your key data regularly. Would you like to back up now?", "description": "Препоръчваме редовно да правите резервни копия на данните с вашите ключове. Искате ли да направите резервно копие сега?",
"title": "Backup Reminder", "title": "Напомняне за резервно копие",
"remindLaterPrefix": "Remind me in", "remindLaterPrefix": "Remind me in",
"remindNever": "Never remind me", "remindNever": "Никога не ми напомняй",
"backupNow": "Back up now" "backupNow": "Създаване на резервно копие сега"
}, },
"pkiRegenerate": { "pkiRegenerate": {
"description": "Сигурни ли сте, че искате да регенерирате двойката ключове?", "description": "Сигурни ли сте, че искате да регенерирате двойката ключове?",
@ -136,7 +147,7 @@
"keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.",
"unableToSendDmPrefix": "Your node is unable to send a direct message to node: " "unableToSendDmPrefix": "Your node is unable to send a direct message to node: "
}, },
"acceptNewKeys": "Accept New Keys", "acceptNewKeys": "риемане на нови ключове",
"title": "Keys Mismatch - {{identifier}}" "title": "Keys Mismatch - {{identifier}}"
}, },
"removeNode": { "removeNode": {
@ -158,14 +169,14 @@
"confirmUnderstanding": "Да, знам какво правя", "confirmUnderstanding": "Да, знам какво правя",
"conjunction": " and the blog post about ", "conjunction": " and the blog post about ",
"postamble": " and understand the implications of changing the role.", "postamble": " and understand the implications of changing the role.",
"preamble": "I have read the ", "preamble": "Аз прочетох ",
"choosingRightDeviceRole": "Choosing The Right Device Role", "choosingRightDeviceRole": "Избор на правилната роля на устройството",
"deviceRoleDocumentation": "Device Role Documentation", "deviceRoleDocumentation": "Документация за ролите на устройството",
"title": "Сигурни ли сте?" "title": "Сигурни ли сте?"
}, },
"managedMode": { "managedMode": {
"confirmUnderstanding": "Да, знам какво правя", "confirmUnderstanding": "Да, знам какво правя",
"title": "Сигурни ли сте?", "title": "Сигурни ли сте?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

54
packages/web/public/i18n/locales/bg-BG/moduleConfig.json

@ -8,8 +8,8 @@
"tabMqtt": "MQTT", "tabMqtt": "MQTT",
"tabNeighborInfo": "Neighbor Info", "tabNeighborInfo": "Neighbor Info",
"tabPaxcounter": "Paxcounter", "tabPaxcounter": "Paxcounter",
"tabRangeTest": "Range Test", "tabRangeTest": "Тест на обхвата",
"tabSerial": "Serial", "tabSerial": "Серийна",
"tabStoreAndForward": "S&F", "tabStoreAndForward": "S&F",
"tabTelemetry": "Телеметрия" "tabTelemetry": "Телеметрия"
}, },
@ -21,7 +21,7 @@
"description": "Sets LED to on or off" "description": "Sets LED to on or off"
}, },
"current": { "current": {
"label": "Current", "label": "Текущ",
"description": "Sets the current for the LED output. Default is 10" "description": "Sets the current for the LED output. Default is 10"
}, },
"red": { "red": {
@ -269,26 +269,26 @@
"label": "Приблизително местоположение", "label": "Приблизително местоположение",
"description": "Position shared will be accurate within this distance", "description": "Position shared will be accurate within this distance",
"options": { "options": {
"metric_km23": "Within 23 km", "metric_km23": "В рамките на 23 км",
"metric_km12": "Within 12 km", "metric_km12": "В рамките на 12 км",
"metric_km5_8": "Within 5.8 km", "metric_km5_8": "Within 5.8 km",
"metric_km2_9": "Within 2.9 km", "metric_km2_9": "Within 2.9 km",
"metric_km1_5": "Within 1.5 km", "metric_km1_5": "Within 1.5 km",
"metric_m700": "Within 700 m", "metric_m700": "В рамките на 700 м",
"metric_m350": "Within 350 m", "metric_m350": "В рамките на 350 м",
"metric_m200": "Within 200 m", "metric_m200": "В рамките на 200 м",
"metric_m90": "Within 90 m", "metric_m90": "В рамките на 90 м",
"metric_m50": "Within 50 m", "metric_m50": "В рамките на 50 м",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "В рамките на 15 мили",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "В рамките на 7.3 мили",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "В рамките на 3.6 мили",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "В рамките на 1.8 мили",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "В рамките на 0.9 мили",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "В рамките на 0.5 мили",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "В рамките на 0.2 мили",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "В рамките на 600 фута",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "В рамките на 300 фута",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "В рамките на 150 фута"
} }
} }
} }
@ -301,7 +301,7 @@
"description": "Enable or disable Neighbor Info Module" "description": "Enable or disable Neighbor Info Module"
}, },
"updateInterval": { "updateInterval": {
"label": "Update Interval", "label": "Интервал на актуализиране",
"description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh"
} }
}, },
@ -313,7 +313,7 @@
"description": "Активиране на Paxcounter" "description": "Активиране на Paxcounter"
}, },
"paxcounterUpdateInterval": { "paxcounterUpdateInterval": {
"label": "Update Interval (seconds)", "label": "Интервал на актуализиране (секунди)",
"description": "How long to wait between sending paxcounter packets" "description": "How long to wait between sending paxcounter packets"
}, },
"wifiThreshold": { "wifiThreshold": {
@ -329,7 +329,7 @@
"title": "Range Test Settings", "title": "Range Test Settings",
"description": "Settings for the Range Test module", "description": "Settings for the Range Test module",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Модулът е активиран",
"description": "Enable Range Test" "description": "Enable Range Test"
}, },
"sender": { "sender": {
@ -405,11 +405,11 @@
"title": "Настройки на телеметрията", "title": "Настройки на телеметрията",
"description": "Настройки за модула за телеметрия", "description": "Настройки за модула за телеметрия",
"deviceUpdateInterval": { "deviceUpdateInterval": {
"label": "Device Metrics", "label": "Метрики на устройството",
"description": "Device metrics update interval (seconds)" "description": "Интервал на актуализиране на показателите на устройството (секунди)"
}, },
"environmentUpdateInterval": { "environmentUpdateInterval": {
"label": "Environment metrics update interval (seconds)", "label": "Интервал на актуализиране на показателите на околната среда (секунди)",
"description": "" "description": ""
}, },
"environmentMeasurementEnabled": { "environmentMeasurementEnabled": {
@ -417,7 +417,7 @@
"description": "Enable the Environment Telemetry" "description": "Enable the Environment Telemetry"
}, },
"environmentScreenEnabled": { "environmentScreenEnabled": {
"label": "Displayed on Screen", "label": "Показва се на екрана",
"description": "Show the Telemetry Module on the OLED" "description": "Show the Telemetry Module on the OLED"
}, },
"environmentDisplayFahrenheit": { "environmentDisplayFahrenheit": {

8
packages/web/public/i18n/locales/bg-BG/nodes.json

@ -25,7 +25,7 @@
"mqtt": "MQTT" "mqtt": "MQTT"
}, },
"elevation": { "elevation": {
"label": "Elevation" "label": "Височина"
}, },
"channelUtil": { "channelUtil": {
"label": "Channel Util" "label": "Channel Util"
@ -44,7 +44,7 @@
"macAddress": "MAC адрес" "macAddress": "MAC адрес"
}, },
"connectionStatus": { "connectionStatus": {
"direct": "Direct", "direct": "Директно",
"away": "away", "away": "away",
"unknown": "-", "unknown": "-",
"viaMqtt": ", чрез MQTT" "viaMqtt": ", чрез MQTT"
@ -56,8 +56,8 @@
"actions": { "actions": {
"added": "Добавен", "added": "Добавен",
"removed": "Премахнат", "removed": "Премахнат",
"ignoreNode": "Ignore Node", "ignoreNode": "Игнориране на възела",
"unignoreNode": "Unignore Node", "unignoreNode": "Премахване на игнорирането на възела",
"requestPosition": "Request Position" "requestPosition": "Request Position"
} }
} }

40
packages/web/public/i18n/locales/bg-BG/ui.json

@ -82,21 +82,21 @@
"description": "Промяната в конфигурацията {{case}} е запазена." "description": "Промяната в конфигурацията {{case}} е запазена."
}, },
"favoriteNode": { "favoriteNode": {
"title": "{{action}} {{nodeName}} {{direction}} favorites.", "title": "{{action}} {{nodeName}} {{direction}} любими.",
"action": { "action": {
"added": "Added", "added": "Добавен",
"removed": "Removed", "removed": "Премахнат",
"to": "to", "to": "в",
"from": "from" "from": "от"
} }
}, },
"ignoreNode": { "ignoreNode": {
"title": "{{action}} {{nodeName}} {{direction}} ignore list", "title": "{{action}} {{nodeName}} {{direction}} списък с игнорирани",
"action": { "action": {
"added": "Added", "added": "Добавен",
"removed": "Removed", "removed": "Премахнат",
"to": "to", "to": "в",
"from": "from" "from": "от"
} }
} }
}, },
@ -114,10 +114,10 @@
"label": "Показване на паролата" "label": "Показване на паролата"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": "Delivered", "delivered": "Доставено",
"failed": "Delivery Failed", "failed": "Неуспешна доставка",
"waiting": "Изчакване", "waiting": "Изчакване",
"unknown": "Unknown" "unknown": "Неизвестно"
} }
}, },
"general": { "general": {
@ -163,13 +163,13 @@
"label": "Използване на канала (%)" "label": "Използване на канала (%)"
}, },
"hops": { "hops": {
"direct": "Direct", "direct": "Директно",
"label": "Number of hops", "label": "Брой хопове",
"text": "Number of hops: {{value}}" "text": "Брой хопове: {{value}}"
}, },
"lastHeard": { "lastHeard": {
"label": "Последно чут", "label": "Последно чут",
"labelText": "Last heard: {{value}}", "labelText": "Последно чут: {{value}}",
"nowLabel": "Сега" "nowLabel": "Сега"
}, },
"snr": { "snr": {
@ -204,9 +204,9 @@
"changeTheme": "Промяна на цветовата схема" "changeTheme": "Промяна на цветовата схема"
}, },
"errorPage": { "errorPage": {
"title": "This is a little embarrassing...", "title": "Това е малко смущаващо...",
"description1": "We are really sorry but an error occurred in the web client that caused it to crash. <br /> This is not supposed to happen, and we are working hard to fix it.", "description1": "Наистина съжаляваме, но възникна грешка в web клиента, която доведе до срив. <br /> Това не би трябвало да се случва и работим усилено, за да го поправим.",
"description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", "description2": "Най-добрият начин да предотвратите това да се случи отново с вас или с някой друг е да ни съобщите за проблема.",
"reportInstructions": "Моля, включете следната информация в доклада си:", "reportInstructions": "Моля, включете следната информация в доклада си:",
"reportSteps": { "reportSteps": {
"step1": "Какво правехте, когато възникна грешката", "step1": "Какво правехте, когато възникна грешката",

97
packages/web/public/i18n/locales/cs-CZ/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "No results found.",
"page": { "page": {
"title": "Command Menu" "title": "Command Menu"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Pin command group"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Unpin command group"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Goto",
"command": { "command": {
"messages": "Zprávy", "messages": "Zprávy",
"map": "Mapa", "map": "Mapa",
"config": "Config", "config": "Config",
"channels": "Kanály", "channels": "Kanály",
"nodes": "Uzly" "nodes": "Uzly"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "Manage",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Switch Node",
"connectNewNode": "Connect New Node" "connectNewNode": "Connect New Node"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextual",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR Code",
"qrGenerator": "Generator", "qrGenerator": "Generator",
"qrImport": "Import", "qrImport": "Import",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Schedule Shutdown",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "Schedule Reboot",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "Reboot To OTA Mode",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Reset Node DB",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Factory Reset Device",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "Factory Reset Config",
} "disconnect": "Disconnect"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "Reconfigure",
} "clearAllStoredMessages": "Clear All Stored Message"
} }
}
} }

2
packages/web/public/i18n/locales/cs-CZ/dashboard.json

@ -3,7 +3,7 @@
"title": "Connected Devices", "title": "Connected Devices",
"description": "Manage your connected Meshtastic devices.", "description": "Manage your connected Meshtastic devices.",
"connectionType_ble": "BLE", "connectionType_ble": "BLE",
"connectionType_serial": "Sériová komunikace", "connectionType_serial": "Sériový",
"connectionType_network": "Síť", "connectionType_network": "Síť",
"noDevicesTitle": "No devices connected", "noDevicesTitle": "No devices connected",
"noDevicesDescription": "Connect a new device to get started.", "noDevicesDescription": "Connect a new device to get started.",

25
packages/web/public/i18n/locales/cs-CZ/dialog.json

@ -7,7 +7,13 @@
"description": "The Device will restart once the config is saved.", "description": "The Device will restart once the config is saved.",
"longName": "Long Name", "longName": "Long Name",
"shortName": "Short Name", "shortName": "Short Name",
"title": "Change Device Name" "title": "Change Device Name",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "The current LoRa configuration will be overridden.",
@ -21,9 +27,10 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Location: {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordinates: ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Regenerate Pre-Shared Key?",
@ -36,7 +43,7 @@
"http": "http", "http": "http",
"tabHttp": "HTTP", "tabHttp": "HTTP",
"tabBluetooth": "Bluetooth", "tabBluetooth": "Bluetooth",
"tabSerial": "Sériová komunikace", "tabSerial": "Sériový",
"useHttps": "Use HTTPS", "useHttps": "Use HTTPS",
"connecting": "Connecting...", "connecting": "Connecting...",
"connect": "Connect", "connect": "Connect",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "No devices paired yet.",
"newDeviceButton": "New device" "newDeviceButton": "New device",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Yes, I know what I'm doing",
"title": "Jste si jistý?", "title": "Jste si jistý?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

6
packages/web/public/i18n/locales/cs-CZ/moduleConfig.json

@ -9,7 +9,7 @@
"tabNeighborInfo": "Informace o sousedech", "tabNeighborInfo": "Informace o sousedech",
"tabPaxcounter": "Paxcounter", "tabPaxcounter": "Paxcounter",
"tabRangeTest": "Zkouška dosahu", "tabRangeTest": "Zkouška dosahu",
"tabSerial": "Sériová komunikace", "tabSerial": "Sériový",
"tabStoreAndForward": "S&F", "tabStoreAndForward": "S&F",
"tabTelemetry": "Telemetrie" "tabTelemetry": "Telemetrie"
}, },
@ -406,10 +406,10 @@
"description": "Settings for the Telemetry module", "description": "Settings for the Telemetry module",
"deviceUpdateInterval": { "deviceUpdateInterval": {
"label": "Device Metrics", "label": "Device Metrics",
"description": "Interval aktualizace měření spotřeby (v sekundách)" "description": "Interval aktualizace metrik zařízení (v sekundách)"
}, },
"environmentUpdateInterval": { "environmentUpdateInterval": {
"label": "Interval aktualizace měření životního prostředí (v sekundách)", "label": "Interval aktualizace metrik životního prostředí (v sekundách)",
"description": "" "description": ""
}, },
"environmentMeasurementEnabled": { "environmentMeasurementEnabled": {

97
packages/web/public/i18n/locales/de-DE/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "Keine Ergebnisse gefunden.", "emptyState": "Keine Ergebnisse gefunden.",
"page": { "page": {
"title": "Befehlsmenü" "title": "Befehlsmenü"
}, },
"pinGroup": { "pinGroup": {
"label": "Befehlsgruppe anheften" "label": "Befehlsgruppe anheften"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Befehlsgruppe lösen" "label": "Befehlsgruppe lösen"
}, },
"goto": { "goto": {
"label": "Gehe zu", "label": "Gehe zu",
"command": { "command": {
"messages": "Nachrichten", "messages": "Nachrichten",
"map": "Karte", "map": "Karte",
"config": "Einstellungen", "config": "Einstellungen",
"channels": "Kanäle", "channels": "Kanäle",
"nodes": "Knoten" "nodes": "Knoten"
} }
}, },
"manage": { "manage": {
"label": "Verwalten", "label": "Verwalten",
"command": { "command": {
"switchNode": "Knoten wechseln", "switchNode": "Knoten wechseln",
"connectNewNode": "Neuen Knoten verbinden" "connectNewNode": "Neuen Knoten verbinden"
} }
}, },
"contextual": { "contextual": {
"label": "Kontextabhängig", "label": "Kontextabhängig",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR Code",
"qrGenerator": "Generator", "qrGenerator": "Generator",
"qrImport": "Importieren", "qrImport": "Importieren",
"scheduleShutdown": "Herunterfahren planen", "scheduleShutdown": "Herunterfahren planen",
"scheduleReboot": "Neustarten planen", "scheduleReboot": "Neustarten planen",
"rebootToOtaMode": "Neustart in den OTA Modus", "rebootToOtaMode": "Neustart in den OTA Modus",
"resetNodeDb": "Knotendatenbank zurücksetzen", "resetNodeDb": "Knotendatenbank zurücksetzen",
"factoryResetDevice": "Gerät auf Werkseinstellungen zurücksetzen", "factoryResetDevice": "Gerät auf Werkseinstellungen zurücksetzen",
"factoryResetConfig": "Auf Werkseinstellungen zurücksetzen" "factoryResetConfig": "Auf Werkseinstellungen zurücksetzen",
} "disconnect": "Verbindung trennen"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Neu einrichten", "command": {
"clearAllStoredMessages": "Alle gespeicherten Nachrichten löschen" "reconfigure": "Neu einrichten",
} "clearAllStoredMessages": "Alle gespeicherten Nachrichten löschen"
} }
}
} }

4
packages/web/public/i18n/locales/de-DE/deviceConfig.json

@ -7,7 +7,7 @@
"tabLora": "LoRa", "tabLora": "LoRa",
"tabNetwork": "Netzwerk", "tabNetwork": "Netzwerk",
"tabPosition": "Standort", "tabPosition": "Standort",
"tabPower": "Leistung", "tabPower": "Energie",
"tabSecurity": "Sicherheit" "tabSecurity": "Sicherheit"
}, },
"sidebar": { "sidebar": {
@ -369,7 +369,7 @@
}, },
"powerConfigSettings": { "powerConfigSettings": {
"description": "Einstellungen für das Energiemodul", "description": "Einstellungen für das Energiemodul",
"label": "Power Konfiguration" "label": "Energie Einstellungen"
}, },
"sleepSettings": { "sleepSettings": {
"description": "Einstellungen Ruhezustand für das Energiemodul", "description": "Einstellungen Ruhezustand für das Energiemodul",

27
packages/web/public/i18n/locales/de-DE/dialog.json

@ -7,7 +7,13 @@
"description": "Das Gerät wird neu gestartet, sobald die Einstellung gespeichert ist.", "description": "Das Gerät wird neu gestartet, sobald die Einstellung gespeichert ist.",
"longName": "Langer Name", "longName": "Langer Name",
"shortName": "Kurzname", "shortName": "Kurzname",
"title": "Gerätename ändern" "title": "Gerätename ändern",
"validation": {
"longNameMax": "Lange Name darf nicht mehr als 40 Zeichen lang sein",
"shortNameMax": "Kurzname darf nicht mehr als 4 Zeichen lang sein",
"longNameMin": "Langer Name muss mindestens 1 Zeichen lang sein",
"shortNameMin": "Kurzname muss mindestens 1 Zeichen lang sein"
}
}, },
"import": { "import": {
"description": "Die aktuelle LoRa Einstellung wird überschrieben.", "description": "Die aktuelle LoRa Einstellung wird überschrieben.",
@ -21,9 +27,10 @@
"title": "Kanalsammlung importieren" "title": "Kanalsammlung importieren"
}, },
"locationResponse": { "locationResponse": {
"title": "Standort: {{identifier}}",
"altitude": "Höhe: ", "altitude": "Höhe: ",
"coordinates": "Koordinaten: ", "coordinates": "Koordinaten: ",
"title": "Standort: {{identifier}}" "noCoordinates": "Keine Koordinaten"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Vorab verteilten Schlüssel (PSK) neu erstellen?", "title": "Vorab verteilten Schlüssel (PSK) neu erstellen?",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "Noch keine Geräte gekoppelt.", "noDevicesPaired": "Noch keine Geräte gekoppelt.",
"newDeviceButton": "Neues Gerät" "newDeviceButton": "Neues Gerät",
"connectionFailed": "Verbindung fehlgeschlagen",
"deviceDisconnected": "Verbindung getrennt",
"unknownDevice": "Unbekanntes Gerät",
"errorLoadingDevices": "Fehler beim Laden der Geräte",
"unknownErrorLoadingDevices": "Unbekannter Fehler beim Laden der Geräte"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "Dieser Verbindungstyp erfordert <0>Bluetooth</0> im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.", "requiresFeatures": "Dieser Verbindungstyp erfordert <0></0>. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.",
"requiresWebSerial": "Dieser Verbindungstyp erfordert <0>Serielle Schnittstelle</0> im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.",
"requiresSecureContext": "Diese Anwendung erfordert einen <0>sicheren Kontext</0>. Bitte verbinden Sie sich über HTTPS oder localhost.", "requiresSecureContext": "Diese Anwendung erfordert einen <0>sicheren Kontext</0>. Bitte verbinden Sie sich über HTTPS oder localhost.",
"additionallyRequiresSecureContext": "Zusätzlich erfordert es einen <0>sicheren Kontext</0>. Bitte verbinden Sie sich über HTTPS oder localhost." "additionallyRequiresSecureContext": "Zusätzlich erfordert es einen <0>sicheren Kontext</0>. Bitte verbinden Sie sich über HTTPS oder localhost."
} }
@ -161,11 +172,11 @@
"preamble": "Ich habe die", "preamble": "Ich habe die",
"choosingRightDeviceRole": "Wahl der richtigen Geräterolle", "choosingRightDeviceRole": "Wahl der richtigen Geräterolle",
"deviceRoleDocumentation": "Dokumentation der Geräterolle", "deviceRoleDocumentation": "Dokumentation der Geräterolle",
"title": "Bist Du sicher?" "title": "Sind Sie sicher?"
}, },
"managedMode": { "managedMode": {
"confirmUnderstanding": "Ja, ich weiß, was ich tue!", "confirmUnderstanding": "Ja, ich weiß, was ich tue!",
"title": "Bist Du sicher?", "title": "Sind Sie sicher?",
"description": "Das Aktivieren des verwalteten Modus blockiert das Schreiben der Einstellungen in das Funkgerät durch alle Anwendungen (einschließlich der Webanwendung). Einmal aktiviert, können die Einstellungen <bold>nur</bold> durch administrative Nachrichten geändert werden. Diese Einstellung ist für die Fernverwaltung von abgesetzten Knoten nicht erforderlich." "description": "Das Aktivieren des verwalteten Modus blockiert das Schreiben der Einstellungen in das Funkgerät durch alle Anwendungen (einschließlich der Webanwendung). Einmal aktiviert, können die Einstellungen nur durch administrative Nachrichten geändert werden. Diese Einstellung ist für die Fernverwaltung von abgesetzten Knoten nicht erforderlich."
} }
} }

20
packages/web/public/i18n/locales/es-ES/channels.json

@ -1,24 +1,24 @@
{ {
"page": { "page": {
"sectionLabel": "Canales", "sectionLabel": "Canales",
"channelName": "Channel: {{channelName}}", "channelName": "Canal: {{channelName}}",
"broadcastLabel": "Primary", "broadcastLabel": "Primario",
"channelIndex": "Ch {{index}}" "channelIndex": "Cnl {{index}}"
}, },
"validation": { "validation": {
"pskInvalid": "Please enter a valid {{bits}} bit PSK." "pskInvalid": "Por favor, introduzca un PSK de {{bits}} bit válido."
}, },
"settings": { "settings": {
"label": "Ajustes del canal", "label": "Ajustes del canal",
"description": "Crypto, MQTT & misc settings" "description": "Criptografía, MQTT y otros ajustes"
}, },
"role": { "role": {
"label": "Role", "label": "Rol",
"description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", "description": "La telemetría del dispositivo se envía sobre PRIMARY. Solo se permite un PRIMARIO",
"options": { "options": {
"primary": "PRIMARY", "primary": "PRIMARIO",
"disabled": "DISABLED", "disabled": "DESHABILITADO",
"secondary": "SECONDARY" "secondary": "SECUNDARIO"
} }
}, },
"psk": { "psk": {

97
packages/web/public/i18n/locales/es-ES/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "No results found.",
"page": { "page": {
"title": "Command Menu" "title": "Command Menu"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Pin command group"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Unpin command group"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Goto",
"command": { "command": {
"messages": "Mensajes", "messages": "Mensajes",
"map": "Mapa", "map": "Mapa",
"config": "Config", "config": "Config",
"channels": "Canales", "channels": "Canales",
"nodes": "Nodes" "nodes": "Nodos"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "Manage",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Switch Node",
"connectNewNode": "Connect New Node" "connectNewNode": "Connect New Node"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextual",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR Code",
"qrGenerator": "Generator", "qrGenerator": "Generator",
"qrImport": "Import", "qrImport": "Importar",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Schedule Shutdown",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "Schedule Reboot",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "Reboot To OTA Mode",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Reset Node DB",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Factory Reset Device",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "Factory Reset Config",
} "disconnect": "Desconectar"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Depuración",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "Reconfigure",
} "clearAllStoredMessages": "Clear All Stored Message"
} }
}
} }

4
packages/web/public/i18n/locales/es-ES/common.json

@ -12,7 +12,7 @@
"export": "Export", "export": "Export",
"generate": "Generate", "generate": "Generate",
"regenerate": "Regenerate", "regenerate": "Regenerate",
"import": "Import", "import": "Importar",
"message": "Mensaje", "message": "Mensaje",
"now": "Now", "now": "Now",
"ok": "Vale", "ok": "Vale",
@ -23,7 +23,7 @@
"requestPosition": "Request Position", "requestPosition": "Request Position",
"reset": "Reiniciar", "reset": "Reiniciar",
"save": "Guardar", "save": "Guardar",
"scanQr": "Scan QR Code", "scanQr": "Escanear el código QR",
"traceRoute": "Trace Route", "traceRoute": "Trace Route",
"submit": "Submit" "submit": "Submit"
}, },

4
packages/web/public/i18n/locales/es-ES/dashboard.json

@ -3,8 +3,8 @@
"title": "Connected Devices", "title": "Connected Devices",
"description": "Manage your connected Meshtastic devices.", "description": "Manage your connected Meshtastic devices.",
"connectionType_ble": "BLE", "connectionType_ble": "BLE",
"connectionType_serial": "Serial", "connectionType_serial": "Conexión Serial",
"connectionType_network": "Red", "connectionType_network": "Conexión Red",
"noDevicesTitle": "No devices connected", "noDevicesTitle": "No devices connected",
"noDevicesDescription": "Connect a new device to get started.", "noDevicesDescription": "Connect a new device to get started.",
"button_newConnection": "New Connection" "button_newConnection": "New Connection"

144
packages/web/public/i18n/locales/es-ES/deviceConfig.json

@ -1,129 +1,129 @@
{ {
"page": { "page": {
"title": "Configuration", "title": "Configuración",
"tabBluetooth": "Bluetooth", "tabBluetooth": "Bluetooth",
"tabDevice": "Dispositivo", "tabDevice": "Dispositivo",
"tabDisplay": "Pantalla", "tabDisplay": "Pantalla",
"tabLora": "LoRa", "tabLora": "LoRa",
"tabNetwork": "Red", "tabNetwork": "Conexión Red",
"tabPosition": "Posición", "tabPosition": "Posición",
"tabPower": "Energía", "tabPower": "Consumo",
"tabSecurity": "Seguridad" "tabSecurity": "Seguridad"
}, },
"sidebar": { "sidebar": {
"label": "Modules" "label": "Módulos"
}, },
"device": { "device": {
"title": "Device Settings", "title": "Ajustes del dispositivo",
"description": "Settings for the device", "description": "Ajustes del dispositivo",
"buttonPin": { "buttonPin": {
"description": "Button pin override", "description": "Sobrescribir pin de botón",
"label": "Button Pin" "label": "Pin del botón"
}, },
"buzzerPin": { "buzzerPin": {
"description": "Buzzer pin override", "description": "Sobrescribir pin del zumbador",
"label": "Buzzer Pin" "label": "Pin del zumbador"
}, },
"disableTripleClick": { "disableTripleClick": {
"description": "Disable triple click", "description": "Deshabilitar clic triple",
"label": "Disable Triple Click" "label": "Deshabilitar clic triple"
}, },
"doubleTapAsButtonPress": { "doubleTapAsButtonPress": {
"description": "Treat double tap as button press", "description": "Tratar doble toque como botón presionado",
"label": "Double Tap as Button Press" "label": "Doble toque como botón presionado"
}, },
"ledHeartbeatDisabled": { "ledHeartbeatDisabled": {
"description": "Disable default blinking LED", "description": "Deshabilitar parpadeo del LED predeterminado",
"label": "LED Heartbeat Disabled" "label": "Deshabilitar LED de estado"
}, },
"nodeInfoBroadcastInterval": { "nodeInfoBroadcastInterval": {
"description": "How often to broadcast node info", "description": "Cada cuanto se transmite la información del nodo",
"label": "Node Info Broadcast Interval" "label": "Intervalo de transmisión de información del nodo"
}, },
"posixTimezone": { "posixTimezone": {
"description": "The POSIX timezone string for the device", "description": "La zona horaria para el dispositivo en formato de cadena POSIX",
"label": "POSIX Timezone" "label": "Zona horaria POSIX"
}, },
"rebroadcastMode": { "rebroadcastMode": {
"description": "How to handle rebroadcasting", "description": "Cómo manejar la retransmisión",
"label": "Rebroadcast Mode" "label": "Modo de retransmisión"
}, },
"role": { "role": {
"description": "What role the device performs on the mesh", "description": "Qué role realiza el dispositivo en la malla",
"label": "Role" "label": "Rol"
} }
}, },
"bluetooth": { "bluetooth": {
"title": "Bluetooth Settings", "title": "Ajustes de Bluetooth",
"description": "Settings for the Bluetooth module", "description": "Ajustes del módulo de Bluetooth",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "Nota: Algunos dispositivos (ESP32) no pueden usar Bluetooth y Wifi al mismo tiempo.",
"enabled": { "enabled": {
"description": "Enable or disable Bluetooth", "description": "Habilitar o deshabilitar Bluetooth",
"label": "Enabled" "label": "Habilitado"
}, },
"pairingMode": { "pairingMode": {
"description": "Pin selection behaviour.", "description": "Selección del comportamiento del Pin.",
"label": "Modo de emparejamiento" "label": "Modo de emparejamiento"
}, },
"pin": { "pin": {
"description": "Pin to use when pairing", "description": "Pin a usar al emparejar",
"label": "Pin" "label": "Pin"
} }
}, },
"display": { "display": {
"description": "Settings for the device display", "description": "Ajustes de la pantalla del dispositivo",
"title": "Display Settings", "title": "Ajustes de pantalla",
"headingBold": { "headingBold": {
"description": "Bolden the heading text", "description": "Negrita en el texto del encabezado",
"label": "Bold Heading" "label": "Encabezado en negrita"
}, },
"carouselDelay": { "carouselDelay": {
"description": "How fast to cycle through windows", "description": "Que tan rápido cambiar entre pantallas",
"label": "Carousel Delay" "label": "Retraso del carrusel"
}, },
"compassNorthTop": { "compassNorthTop": {
"description": "Fix north to the top of compass", "description": "Fijar el norte en la parte superior de la brújula",
"label": "Compass North Top" "label": "Norte arriba de la brújula"
}, },
"displayMode": { "displayMode": {
"description": "Screen layout variant", "description": "Variante del diseño de la pantalla",
"label": "Display Mode" "label": "Modo de visualización"
}, },
"displayUnits": { "displayUnits": {
"description": "Display metric or imperial units", "description": "Mostrar unidades de medidas métricas o imperiales",
"label": "Display Units" "label": "Unidades de medidas"
}, },
"flipScreen": { "flipScreen": {
"description": "Flip display 180 degrees", "description": "Rotar pantalla 180 grados",
"label": "Flip Screen" "label": "Rotar pantalla"
}, },
"gpsDisplayUnits": { "gpsDisplayUnits": {
"description": "Coordinate display format", "description": "Formato de visualización de las coordenadas",
"label": "GPS Display Units" "label": "Unidades de visualización del GPS"
}, },
"oledType": { "oledType": {
"description": "Type of OLED screen attached to the device", "description": "Tipo de pantalla OLED conectada al dispositivo",
"label": "OLED Type" "label": "Tipo de OLED"
}, },
"screenTimeout": { "screenTimeout": {
"description": "Turn off the display after this long", "description": "Apagar la pantalla después de este tiempo",
"label": "Screen Timeout" "label": "Tiempo de espera de la pantalla"
}, },
"twelveHourClock": { "twelveHourClock": {
"description": "Use 12-hour clock format", "description": "Usar reloj con formato de 12 horas",
"label": "12-Hour Clock" "label": "Reloj de 12 horas"
}, },
"wakeOnTapOrMotion": { "wakeOnTapOrMotion": {
"description": "Wake the device on tap or motion", "description": "Despertar dispositivo al tocar o mover",
"label": "Wake on Tap or Motion" "label": "Despertar al mover o tocar"
} }
}, },
"lora": { "lora": {
"title": "Mesh Settings", "title": "Ajustes de la Red",
"description": "Settings for the LoRa mesh", "description": "Settings for the LoRa mesh",
"bandwidth": { "bandwidth": {
"description": "Channel bandwidth in MHz", "description": "Channel bandwidth in MHz",
"label": "Bandwidth" "label": "Ancho de Banda"
}, },
"boostedRxGain": { "boostedRxGain": {
"description": "Boosted RX gain", "description": "Boosted RX gain",
@ -147,7 +147,7 @@
}, },
"ignoreMqtt": { "ignoreMqtt": {
"description": "Don't forward MQTT messages over the mesh", "description": "Don't forward MQTT messages over the mesh",
"label": "Ignore MQTT" "label": "Ignorar Paquetes MQTT"
}, },
"modemPreset": { "modemPreset": {
"description": "Modem preset to use", "description": "Modem preset to use",
@ -155,11 +155,11 @@
}, },
"okToMqtt": { "okToMqtt": {
"description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT",
"label": "OK to MQTT" "label": "Permitir Subir Paquetes al MQTT"
}, },
"overrideDutyCycle": { "overrideDutyCycle": {
"description": "Override Duty Cycle", "description": "Sobreescribir el Tiempo de Trabajo",
"label": "Override Duty Cycle" "label": "Sobreescribir el Tiempo de Trabajo"
}, },
"overrideFrequency": { "overrideFrequency": {
"description": "Override frequency", "description": "Override frequency",
@ -187,7 +187,7 @@
}, },
"meshSettings": { "meshSettings": {
"description": "Settings for the LoRa mesh", "description": "Settings for the LoRa mesh",
"label": "Mesh Settings" "label": "Ajustes de la Red"
}, },
"waveformSettings": { "waveformSettings": {
"description": "Settings for the LoRa waveform", "description": "Settings for the LoRa waveform",
@ -201,7 +201,7 @@
"network": { "network": {
"title": "WiFi Config", "title": "WiFi Config",
"description": "WiFi radio configuration", "description": "WiFi radio configuration",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "Nota: Algunos dispositivos (ESP32) no pueden usar Bluetooth y Wifi al mismo tiempo.",
"addressMode": { "addressMode": {
"description": "Address assignment selection", "description": "Address assignment selection",
"label": "Address Mode" "label": "Address Mode"
@ -212,11 +212,11 @@
}, },
"ethernetEnabled": { "ethernetEnabled": {
"description": "Enable or disable the Ethernet port", "description": "Enable or disable the Ethernet port",
"label": "Enabled" "label": "Habilitado"
}, },
"gateway": { "gateway": {
"description": "Default Gateway", "description": "Default Gateway",
"label": "Gateway" "label": "Puerta enlace"
}, },
"ip": { "ip": {
"description": "IP Address", "description": "IP Address",
@ -224,19 +224,19 @@
}, },
"psk": { "psk": {
"description": "Network password", "description": "Network password",
"label": "PSK" "label": "PSK (Contraseña)"
}, },
"ssid": { "ssid": {
"description": "Network name", "description": "Network name",
"label": "SSID" "label": "SSID (Nombre la Red)"
}, },
"subnet": { "subnet": {
"description": "Subnet Mask", "description": "Subnet Mask",
"label": "Subnet" "label": "Subred"
}, },
"wifiEnabled": { "wifiEnabled": {
"description": "Enable or disable the WiFi radio", "description": "Enable or disable the WiFi radio",
"label": "Enabled" "label": "Habilitado"
}, },
"meshViaUdp": { "meshViaUdp": {
"label": "Mesh via UDP" "label": "Mesh via UDP"
@ -328,7 +328,7 @@
"hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP",
"numSatellites": "Number of satellites", "numSatellites": "Number of satellites",
"sequenceNumber": "Sequence number", "sequenceNumber": "Sequence number",
"timestamp": "Timestamp", "timestamp": "Fecha",
"unset": "Sin configurar", "unset": "Sin configurar",
"vehicleHeading": "Vehicle heading", "vehicleHeading": "Vehicle heading",
"vehicleSpeed": "Vehicle speed" "vehicleSpeed": "Vehicle speed"
@ -357,7 +357,7 @@
}, },
"powerSavingEnabled": { "powerSavingEnabled": {
"description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.",
"label": "Enable power saving mode" "label": "Activar el modo ahorro de energía"
}, },
"shutdownOnBatteryDelay": { "shutdownOnBatteryDelay": {
"description": "Automatically shutdown node after this long when on battery, 0 for indefinite", "description": "Automatically shutdown node after this long when on battery, 0 for indefinite",
@ -369,7 +369,7 @@
}, },
"powerConfigSettings": { "powerConfigSettings": {
"description": "Settings for the power module", "description": "Settings for the power module",
"label": "Power Config" "label": "Configuración de elecenergía "
}, },
"sleepSettings": { "sleepSettings": {
"description": "Sleep settings for the power module", "description": "Sleep settings for the power module",

27
packages/web/public/i18n/locales/es-ES/dialog.json

@ -7,7 +7,13 @@
"description": "The Device will restart once the config is saved.", "description": "The Device will restart once the config is saved.",
"longName": "Long Name", "longName": "Long Name",
"shortName": "Short Name", "shortName": "Short Name",
"title": "Change Device Name" "title": "Change Device Name",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "The current LoRa configuration will be overridden.",
@ -21,9 +27,10 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Location: {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordinates: ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Regenerate Pre-Shared Key?",
@ -36,10 +43,10 @@
"http": "http", "http": "http",
"tabHttp": "HTTP", "tabHttp": "HTTP",
"tabBluetooth": "Bluetooth", "tabBluetooth": "Bluetooth",
"tabSerial": "Serial", "tabSerial": "Conexión Serial",
"useHttps": "Use HTTPS", "useHttps": "Use HTTPS",
"connecting": "Connecting...", "connecting": "Connecting...",
"connect": "Connect", "connect": "Conectar",
"connectionFailedAlert": { "connectionFailedAlert": {
"title": "Connection Failed", "title": "Connection Failed",
"descriptionPrefix": "Could not connect to the device. ", "descriptionPrefix": "Could not connect to the device. ",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "No devices paired yet.",
"newDeviceButton": "New device" "newDeviceButton": "New device",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Yes, I know what I'm doing",
"title": "¿Estás seguro?", "title": "¿Estás seguro?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

2
packages/web/public/i18n/locales/es-ES/messages.json

@ -16,7 +16,7 @@
}, },
"actionsMenu": { "actionsMenu": {
"addReactionLabel": "Add Reaction", "addReactionLabel": "Add Reaction",
"replyLabel": "Reply" "replyLabel": "Respuesta"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": { "delivered": {

34
packages/web/public/i18n/locales/es-ES/moduleConfig.json

@ -1,17 +1,17 @@
{ {
"page": { "page": {
"tabAmbientLighting": "Ambient Lighting", "tabAmbientLighting": "Luz Ambiental",
"tabAudio": "Audio", "tabAudio": "Audio",
"tabCannedMessage": "Canned", "tabCannedMessage": "Canned",
"tabDetectionSensor": "Detection Sensor", "tabDetectionSensor": "Sensor de Presencia",
"tabExternalNotification": "Ext Notif", "tabExternalNotification": "Ext Notif",
"tabMqtt": "MQTT", "tabMqtt": "MQTT",
"tabNeighborInfo": "Neighbor Info", "tabNeighborInfo": "Información de Vecinos",
"tabPaxcounter": "Paxcounter", "tabPaxcounter": "Contador de Paquetes",
"tabRangeTest": "Range Test", "tabRangeTest": "Test de Alcance",
"tabSerial": "Serial", "tabSerial": "Conexión Serial",
"tabStoreAndForward": "S&F", "tabStoreAndForward": "S&F",
"tabTelemetry": "Telemetry" "tabTelemetry": "Telemetría"
}, },
"ambientLighting": { "ambientLighting": {
"title": "Ambient Lighting Settings", "title": "Ambient Lighting Settings",
@ -25,15 +25,15 @@
"description": "Sets the current for the LED output. Default is 10" "description": "Sets the current for the LED output. Default is 10"
}, },
"red": { "red": {
"label": "Red", "label": "Rojo",
"description": "Sets the red LED level. Values are 0-255" "description": "Sets the red LED level. Values are 0-255"
}, },
"green": { "green": {
"label": "Green", "label": "Verde",
"description": "Sets the green LED level. Values are 0-255" "description": "Sets the green LED level. Values are 0-255"
}, },
"blue": { "blue": {
"label": "Blue", "label": "Azul",
"description": "Sets the blue LED level. Values are 0-255" "description": "Sets the blue LED level. Values are 0-255"
} }
}, },
@ -121,7 +121,7 @@
"title": "Detection Sensor Settings", "title": "Detection Sensor Settings",
"description": "Settings for the Detection Sensor module", "description": "Settings for the Detection Sensor module",
"enabled": { "enabled": {
"label": "Enabled", "label": "Habilitado",
"description": "Enable or disable Detection Sensor Module" "description": "Enable or disable Detection Sensor Module"
}, },
"minimumBroadcastSecs": { "minimumBroadcastSecs": {
@ -221,7 +221,7 @@
"title": "MQTT Settings", "title": "MQTT Settings",
"description": "Settings for the MQTT module", "description": "Settings for the MQTT module",
"enabled": { "enabled": {
"label": "Enabled", "label": "Habilitado",
"description": "Enable or disable MQTT" "description": "Enable or disable MQTT"
}, },
"address": { "address": {
@ -297,7 +297,7 @@
"title": "Neighbor Info Settings", "title": "Neighbor Info Settings",
"description": "Settings for the Neighbor Info module", "description": "Settings for the Neighbor Info module",
"enabled": { "enabled": {
"label": "Enabled", "label": "Habilitado",
"description": "Enable or disable Neighbor Info Module" "description": "Enable or disable Neighbor Info Module"
}, },
"updateInterval": { "updateInterval": {
@ -389,11 +389,11 @@
"description": "Enable Store & Forward heartbeat" "description": "Enable Store & Forward heartbeat"
}, },
"records": { "records": {
"label": "Number of records", "label": "Número de registros",
"description": "Number of records to store" "description": "Number of records to store"
}, },
"historyReturnMax": { "historyReturnMax": {
"label": "History return max", "label": "Historial máximo devuelto",
"description": "Max number of records to return" "description": "Max number of records to return"
}, },
"historyReturnWindow": { "historyReturnWindow": {
@ -406,10 +406,10 @@
"description": "Settings for the Telemetry module", "description": "Settings for the Telemetry module",
"deviceUpdateInterval": { "deviceUpdateInterval": {
"label": "Device Metrics", "label": "Device Metrics",
"description": "Device metrics update interval (seconds)" "description": "Periodo entre las actualizaciones de las medidas del dispositivo (segundos) "
}, },
"environmentUpdateInterval": { "environmentUpdateInterval": {
"label": "Environment metrics update interval (seconds)", "label": "Periodo de refresco para las medidas del entorno",
"description": "" "description": ""
}, },
"environmentMeasurementEnabled": { "environmentMeasurementEnabled": {

8
packages/web/public/i18n/locales/es-ES/ui.json

@ -7,7 +7,7 @@
"radioConfig": "Radio Config", "radioConfig": "Radio Config",
"moduleConfig": "Module Config", "moduleConfig": "Module Config",
"channels": "Canales", "channels": "Canales",
"nodes": "Nodes" "nodes": "Nodos"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",
@ -23,7 +23,7 @@
"deviceInfo": { "deviceInfo": {
"volts": "{{voltage}} volts", "volts": "{{voltage}} volts",
"firmware": { "firmware": {
"title": "Firmware", "title": "Software",
"version": "v{{version}}", "version": "v{{version}}",
"buildDate": "Build date: {{date}}" "buildDate": "Build date: {{date}}"
}, },
@ -108,7 +108,7 @@
"label": "Copy to clipboard" "label": "Copy to clipboard"
}, },
"hidePassword": { "hidePassword": {
"label": "Hide password" "label": "Ocultar contraseña"
}, },
"showPassword": { "showPassword": {
"label": "Mostrar contraseña" "label": "Mostrar contraseña"
@ -130,7 +130,7 @@
"label": "Metrics" "label": "Metrics"
}, },
"role": { "role": {
"label": "Role" "label": "Rol"
}, },
"filter": { "filter": {
"label": "Filtro" "label": "Filtro"

97
packages/web/public/i18n/locales/fi-FI/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "Tuloksia ei löytynyt.", "emptyState": "Tuloksia ei löytynyt.",
"page": { "page": {
"title": "Komentovalikko" "title": "Komentovalikko"
}, },
"pinGroup": { "pinGroup": {
"label": "Kiinnitä komentoryhmä" "label": "Kiinnitä komentoryhmä"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Irroita komentoryhmä" "label": "Irroita komentoryhmä"
}, },
"goto": { "goto": {
"label": "Siirry", "label": "Siirry",
"command": { "command": {
"messages": "Viestit", "messages": "Viestit",
"map": "Kartta", "map": "Kartta",
"config": "Asetukset", "config": "Asetukset",
"channels": "Kanavat", "channels": "Kanavat",
"nodes": "Laitteet" "nodes": "Laitteet"
} }
}, },
"manage": { "manage": {
"label": "Hallinnoi", "label": "Hallinnoi",
"command": { "command": {
"switchNode": "Vaihda laitetta", "switchNode": "Vaihda laitetta",
"connectNewNode": "Yhdistä uusi laite" "connectNewNode": "Yhdistä uusi laite"
} }
}, },
"contextual": { "contextual": {
"label": "Kontekstin mukainen", "label": "Kontekstin mukainen",
"command": { "command": {
"qrCode": "QR-koodi", "qrCode": "QR-koodi",
"qrGenerator": "QR-koodigeneraattori", "qrGenerator": "QR-koodigeneraattori",
"qrImport": "Tuo", "qrImport": "Tuo",
"scheduleShutdown": "Ajasta sammutus", "scheduleShutdown": "Ajasta sammutus",
"scheduleReboot": "Ajasta uudelleenkäynnistys", "scheduleReboot": "Ajasta uudelleenkäynnistys",
"rebootToOtaMode": "Uudelleenkäynnistä OTA-tilaan", "rebootToOtaMode": "Uudelleenkäynnistä OTA-tilaan",
"resetNodeDb": "Nollaa laitteen DB-tietokanta", "resetNodeDb": "Nollaa laitteen DB-tietokanta",
"factoryResetDevice": "Palauta tehdasasetukset", "factoryResetDevice": "Palauta tehdasasetukset",
"factoryResetConfig": "Tehdasasetusten palautusasetukset" "factoryResetConfig": "Tehdasasetusten palautusasetukset",
} "disconnect": "Katkaise yhteys"
}, }
"debug": { },
"label": "Vianetsintä", "debug": {
"command": { "label": "Vianetsintä",
"reconfigure": "Määritä uudelleen", "command": {
"clearAllStoredMessages": "Tyhjennä kaikki tallennetut viesti" "reconfigure": "Määritä uudelleen",
} "clearAllStoredMessages": "Tyhjennä kaikki tallennetut viesti"
} }
}
} }

23
packages/web/public/i18n/locales/fi-FI/dialog.json

@ -7,7 +7,13 @@
"description": "Laite käynnistyy uudelleen, kun asetus on tallennettu.", "description": "Laite käynnistyy uudelleen, kun asetus on tallennettu.",
"longName": "Pitkä nimi", "longName": "Pitkä nimi",
"shortName": "Lyhytnimi", "shortName": "Lyhytnimi",
"title": "Vaihda laitteen nimi" "title": "Vaihda laitteen nimi",
"validation": {
"longNameMax": "Pitkässä nimessä saa olla enintään 40 merkkiä",
"shortNameMax": "Lyhytnimessä ei saa olla enempää kuin 4 merkkiä",
"longNameMin": "Pitkässä nimessä täytyy olla vähintään yksi merkki",
"shortNameMin": "Lyhytnimessä täytyy olla vähintään ykis merkki"
}
}, },
"import": { "import": {
"description": "Nykyinen LoRa-asetus ylikirjoitetaan.", "description": "Nykyinen LoRa-asetus ylikirjoitetaan.",
@ -21,9 +27,10 @@
"title": "Tuo kanava-asetukset" "title": "Tuo kanava-asetukset"
}, },
"locationResponse": { "locationResponse": {
"title": "Sijainti: {{identifier}}",
"altitude": "Korkeus: ", "altitude": "Korkeus: ",
"coordinates": "Koordinaatit: ", "coordinates": "Koordinaatit: ",
"title": "Sijainti: {{identifier}}" "noCoordinates": "Ei koordinaatteja"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Luodaanko ennalta jaettu avain uudelleen?", "title": "Luodaanko ennalta jaettu avain uudelleen?",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "Yhtään laitetta ei ole vielä yhdistetty.", "noDevicesPaired": "Yhtään laitetta ei ole vielä yhdistetty.",
"newDeviceButton": "Uusi laite" "newDeviceButton": "Uusi laite",
"connectionFailed": "Yhdistäminen epäonnistui",
"deviceDisconnected": "Yhteys laitteeseen katkaistu",
"unknownDevice": "Tuntematon laite",
"errorLoadingDevices": "Virhe ladattaessa laitteita",
"unknownErrorLoadingDevices": "Tuntematon virhe laitteita ladattaessa"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti bluetooth</0> -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.", "requiresFeatures": "Tämä yhteystyyppi vaatii <0></0>. Käytä tuettua selainta, kuten Chromea tai Edgeä.",
"requiresWebSerial": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti</0> -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.",
"requiresSecureContext": "Tämä sovellus vaatii <0>suojatun yhteyden</0>. Yhdistä käyttämällä HTTPS:ää tai localhostia.", "requiresSecureContext": "Tämä sovellus vaatii <0>suojatun yhteyden</0>. Yhdistä käyttämällä HTTPS:ää tai localhostia.",
"additionallyRequiresSecureContext": "Lisäksi se vaatii <0>suojatun yhteyden</0>. Yhdistä käyttämällä HTTPS:ää tai localhostia." "additionallyRequiresSecureContext": "Lisäksi se vaatii <0>suojatun yhteyden</0>. Yhdistä käyttämällä HTTPS:ää tai localhostia."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Kyllä, tiedän mitä teen", "confirmUnderstanding": "Kyllä, tiedän mitä teen",
"title": "Oletko varma?", "title": "Oletko varma?",
"description": "Hallintatilan käyttöönotto estää asiakassovelluksia (mukaan lukien verkkosovellus) kirjoittamasta asetuksia radioon. Kun tila on otettu käyttöön, radion asetuksia voidaan muuttaa <bold>vain</bold> etähallintaviestien kautta. Tämä asetus ei ole pakollinen etähallittavien laitteiden hallintaan." "description": "Hallintatilan käyttöönotto estää asiakassovelluksia (mukaan lukien verkkoselain) tekemästä muutoksia laitteen asetuksiin. Kun hallintatila on käytössä, laitteen asetuksia voidaan muuttaa ainoastaan etähallintaviesteillä (Remote Admin). Tämä asetus ei ole pakollinen etähallintaan."
} }
} }

80
packages/web/public/i18n/locales/fr-FR/channels.json

@ -1,69 +1,69 @@
{ {
"page": { "page": {
"sectionLabel": "Canaux", "sectionLabel": "Canaux",
"channelName": "Channel: {{channelName}}", "channelName": "Canal {{channelName}}",
"broadcastLabel": "Principal", "broadcastLabel": "Principal",
"channelIndex": "Ch {{index}}" "channelIndex": "Ca {{index}}"
}, },
"validation": { "validation": {
"pskInvalid": "Please enter a valid {{bits}} bit PSK." "pskInvalid": "Veuillez entrer une clé PSK valide de {{bits}} bits."
}, },
"settings": { "settings": {
"label": "Paramètres du canal", "label": "Paramètres du canal",
"description": "Crypto, MQTT & misc settings" "description": "Paramètres Crypto, MQTT et divers"
}, },
"role": { "role": {
"label": "Rôle", "label": "Rôle",
"description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", "description": "La télémétrie de l’appareil est envoyée via le canal PRINCIPAL. Un seul canal PRINCIPAL est autorisé.",
"options": { "options": {
"primary": "PRIMARY", "primary": "PRINCIPAL",
"disabled": "DISABLED", "disabled": "DÉSACTIVÉ",
"secondary": "SECONDARY" "secondary": "SECONDAIRE"
} }
}, },
"psk": { "psk": {
"label": "Pre-Shared Key", "label": "Clé partagée",
"description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", "description": "Longueurs de clé PSK prises en charge : 256 bits, 128 bits, 8 bits, vide (0 bit)",
"generate": "Generate" "generate": "Générer"
}, },
"name": { "name": {
"label": "Nom", "label": "Nom",
"description": "A unique name for the channel <12 bytes, leave blank for default" "description": "Un nom unique pour le canal (<12 octets), laisser vide pour utiliser la valeur par défaut"
}, },
"uplinkEnabled": { "uplinkEnabled": {
"label": "Uplink Enabled", "label": "Liaison montante activée",
"description": "Send messages from the local mesh to MQTT" "description": "Envoyer les messages du maillage local vers MQTT"
}, },
"downlinkEnabled": { "downlinkEnabled": {
"label": "Downlink Enabled", "label": "Liaison descendante activée",
"description": "Send messages from MQTT to the local mesh" "description": "Envoyer les messages de MQTT vers le maillage local"
}, },
"positionPrecision": { "positionPrecision": {
"label": "Location", "label": "Position",
"description": "The precision of the location to share with the channel. Can be disabled.", "description": "La précision de la position à partager avec le canal. Peut être désactivée.",
"options": { "options": {
"none": "Do not share location", "none": "Ne pas partager la position",
"precise": "Precise Location", "precise": "Position précise",
"metric_km23": "Within 23 kilometers", "metric_km23": "À moins de 23 kilomètres",
"metric_km12": "Within 12 kilometers", "metric_km12": "À moins de 12 kilomètres",
"metric_km5_8": "Within 5.8 kilometers", "metric_km5_8": "À moins de 5,8 kilomètres",
"metric_km2_9": "Within 2.9 kilometers", "metric_km2_9": "À moins de 2,9 kilomètres",
"metric_km1_5": "Within 1.5 kilometers", "metric_km1_5": "À moins de 1,5 kilomètres",
"metric_m700": "Within 700 meters", "metric_m700": "À moins de 700 mètres",
"metric_m350": "Within 350 meters", "metric_m350": "À moins de 350 mètres",
"metric_m200": "Within 200 meters", "metric_m200": "À moins de 200 mètres",
"metric_m90": "Within 90 meters", "metric_m90": "À moins de 90 mètres",
"metric_m50": "Within 50 meters", "metric_m50": "À moins de 50 mètres",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "À moins de 15 miles",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "À moins de 7,3 miles",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "À moins de 3,6 miles",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "À moins de 1,8 miles",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "À moins de 0,9 miles",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "À moins de 0,5 miles",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "À moins de 0,2 miles",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "À moins de 600 pieds",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "À moins de 300 pieds",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "À moins de 150 pieds"
} }
} }
} }

97
packages/web/public/i18n/locales/fr-FR/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "Aucun résultat trouvé.",
"page": { "page": {
"title": "Command Menu" "title": "Menu des commandes"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Attacher le groupe de commandes"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Détacher le groupe de commandes"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Aller à",
"command": { "command": {
"messages": "Messages", "messages": "Messages",
"map": "Carte", "map": "Carte",
"config": "Config", "config": "Config",
"channels": "Canaux", "channels": "Canaux",
"nodes": "Noeuds" "nodes": "Noeuds"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "Gérer",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Changer de nœud ",
"connectNewNode": "Connect New Node" "connectNewNode": "Connecter un nouveau noeud"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextuel",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "Code QR",
"qrGenerator": "Generator", "qrGenerator": "Générateur",
"qrImport": "Import", "qrImport": "Importer",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Planifier l'arrêt",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "Effacer tous les messages stockés",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "Redémarrer en mode OTA",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Réinitialiser la DB des nœuds",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Réinitialisation d'usine de l'appareil",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "Réinitialisation d'usine de la config",
} "disconnect": "Déconnecter"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "Reconfigurer",
} "clearAllStoredMessages": "Effacer tous les messages stockés"
} }
}
} }

126
packages/web/public/i18n/locales/fr-FR/common.json

@ -1,55 +1,55 @@
{ {
"button": { "button": {
"apply": "Appliquer", "apply": "Appliquer",
"backupKey": "Backup Key", "backupKey": "Clé de sauvegarde",
"cancel": "Annuler", "cancel": "Annuler",
"clearMessages": "Clear Messages", "clearMessages": "Effacer les messages",
"close": "Fermer", "close": "Fermer",
"confirm": "Confirm", "confirm": "Confirmer",
"delete": "Effacer", "delete": "Effacer",
"dismiss": "Annuler", "dismiss": "Annuler",
"download": "Download", "download": "Télécharger",
"export": "Export", "export": "Exporter",
"generate": "Generate", "generate": "Générer",
"regenerate": "Regenerate", "regenerate": "Regénérer",
"import": "Import", "import": "Importer",
"message": "Message", "message": "Message",
"now": "Now", "now": "Maintenant",
"ok": "D'accord", "ok": "D'accord",
"print": "Print", "print": "Imprimer",
"rebootOtaNow": "Reboot to OTA Mode Now", "rebootOtaNow": "Redémarrer en mode OTA",
"remove": "Supprimer", "remove": "Supprimer",
"requestNewKeys": "Request New Keys", "requestNewKeys": "Demander de nouvelles clés",
"requestPosition": "Request Position", "requestPosition": "Demander la position",
"reset": "Réinitialiser", "reset": "Réinitialiser",
"save": "Sauvegarder", "save": "Sauvegarder",
"scanQr": "Scan QR Code", "scanQr": "Scanner le code QR",
"traceRoute": "Trace Route", "traceRoute": "Analyse du trajet réseau",
"submit": "Submit" "submit": "Envoyer"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",
"fullTitle": "Meshtastic Web Client" "fullTitle": "Client Web Meshtastic"
}, },
"loading": "Loading...", "loading": "Chargement...",
"unit": { "unit": {
"cps": "CPS", "cps": "CPS",
"dbm": "dBm", "dbm": "dBm",
"hertz": "Hz", "hertz": "Hz",
"hop": { "hop": {
"one": "Hop", "one": "Saut",
"plural": "Hops" "plural": "Sauts"
}, },
"hopsAway": { "hopsAway": {
"one": "{{count}} hop away", "one": "À {{count}} saut",
"plural": "{{count}} hops away", "plural": "À {{count}} sauts",
"unknown": "Unknown hops away" "unknown": "Nombre de sauts inconnu"
}, },
"megahertz": "MHz", "megahertz": "MHz",
"raw": "raw", "raw": "brute",
"meter": { "meter": {
"one": "Meter", "one": "Mètre",
"plural": "Meters", "plural": "Mètres",
"suffix": "m" "suffix": "m"
}, },
"minute": { "minute": {
@ -57,29 +57,29 @@
"plural": "Minutes" "plural": "Minutes"
}, },
"hour": { "hour": {
"one": "Hour", "one": "Heure",
"plural": "Hours" "plural": "Heures"
}, },
"millisecond": { "millisecond": {
"one": "Millisecond", "one": "Milliseconde",
"plural": "Milliseconds", "plural": "Millisecondes",
"suffix": "ms" "suffix": "ms"
}, },
"second": { "second": {
"one": "Second", "one": "Seconde",
"plural": "Seconds" "plural": "Secondes"
}, },
"day": { "day": {
"one": "Day", "one": "Jour",
"plural": "Days" "plural": "Jours"
}, },
"month": { "month": {
"one": "Month", "one": "Mois",
"plural": "Months" "plural": "Mois"
}, },
"year": { "year": {
"one": "Year", "one": "Année",
"plural": "Years" "plural": "Années"
}, },
"snr": "SNR", "snr": "SNR",
"volt": { "volt": {
@ -88,54 +88,54 @@
"suffix": "V" "suffix": "V"
}, },
"record": { "record": {
"one": "Records", "one": "Enregistrement",
"plural": "Records" "plural": "Enregistrements"
} }
}, },
"security": { "security": {
"0bit": "Empty", "0bit": "Vide",
"8bit": "8 bit", "8bit": "8 bits",
"128bit": "128 bit", "128bit": "128 bits",
"256bit": "256 bit" "256bit": "256 bits"
}, },
"unknown": { "unknown": {
"longName": "Inconnu", "longName": "Inconnu",
"shortName": "UNK", "shortName": "UNK",
"notAvailable": "N/A", "notAvailable": "Indisponible",
"num": "??" "num": "??"
}, },
"nodeUnknownPrefix": "!", "nodeUnknownPrefix": "!",
"unset": "UNSET", "unset": "DÉSACTIVER",
"fallbackName": "Meshtastic {{last4}}", "fallbackName": "Meshtastic {{last4}}",
"node": "Node", "node": "Noeud",
"formValidation": { "formValidation": {
"unsavedChanges": "Unsaved changes", "unsavedChanges": "Modifications non enregistrées",
"tooBig": { "tooBig": {
"string": "Too long, expected less than or equal to {{maximum}} characters.", "string": "Trop long : {{maximum}} caractères maximum autorisés.",
"number": "Too big, expected a number smaller than or equal to {{maximum}}.", "number": "Trop grand, un nombre inférieur ou égal à {{maximum}} est attendu.",
"bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." "bytes": "Taille trop grand : maximum {{params.maximum}} octets autorisés."
}, },
"tooSmall": { "tooSmall": {
"string": "Too short, expected more than or equal to {{minimum}} characters.", "string": "Trop court : au moins {{minimum}} caractères requis.",
"number": "Too small, expected a number larger than or equal to {{minimum}}." "number": "Valeur trop basse : minimum {{minimum}} requis."
}, },
"invalidFormat": { "invalidFormat": {
"ipv4": "Invalid format, expected an IPv4 address.", "ipv4": "Format invalide, adresse IPv4 attendue.",
"key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." "key": "Format incorrect, la clé PSK doit être encodée en Base64."
}, },
"invalidType": { "invalidType": {
"number": "Invalid type, expected a number." "number": "Type incorrect, nombre attendu."
}, },
"pskLength": { "pskLength": {
"0bit": "Key is required to be empty.", "0bit": "La clé doit être vide.",
"8bit": "Key is required to be an 8 bit pre-shared key (PSK).", "8bit": "La clé doit être une clé pré-partagée (PSK) de 8 bits.",
"128bit": "Key is required to be a 128 bit pre-shared key (PSK).", "128bit": "La clé doit être une clé pré-partagée (PSK) de 128 bits.",
"256bit": "Key is required to be a 256 bit pre-shared key (PSK)." "256bit": "La clé doit être une clé pré-partagée (PSK) de 256 bits."
}, },
"required": { "required": {
"generic": "This field is required.", "generic": "Ce champ est obligatoire.",
"managed": "At least one admin key is requred if the node is managed.", "managed": "Au moins une clé d’administration est requise si le nœud est géré.",
"key": "Key is required." "key": "Clé requise."
} }
} }
} }

10
packages/web/public/i18n/locales/fr-FR/dashboard.json

@ -1,12 +1,12 @@
{ {
"dashboard": { "dashboard": {
"title": "Connected Devices", "title": "Appareils connectés",
"description": "Manage your connected Meshtastic devices.", "description": "Gérez vos périphériques Meshtastic connectés.",
"connectionType_ble": "BLE", "connectionType_ble": "BLE",
"connectionType_serial": "Série", "connectionType_serial": "Série",
"connectionType_network": "Réseau", "connectionType_network": "Réseau",
"noDevicesTitle": "No devices connected", "noDevicesTitle": "Aucun appareil connecté",
"noDevicesDescription": "Connect a new device to get started.", "noDevicesDescription": "Connectez un nouvel appareil pour commencer.",
"button_newConnection": "New Connection" "button_newConnection": "Nouvelle connexion"
} }
} }

368
packages/web/public/i18n/locales/fr-FR/deviceConfig.json

@ -14,147 +14,147 @@
"label": "Modules" "label": "Modules"
}, },
"device": { "device": {
"title": "Device Settings", "title": "Paramètres de l'appareil",
"description": "Settings for the device", "description": "Paramètres de l'appareil",
"buttonPin": { "buttonPin": {
"description": "Button pin override", "description": "Redéfinition de la broche du bouton",
"label": "Button Pin" "label": "Broche du bouton"
}, },
"buzzerPin": { "buzzerPin": {
"description": "Buzzer pin override", "description": "Redéfinition de la broche du buzzer",
"label": "Buzzer Pin" "label": "Broche du buzzer"
}, },
"disableTripleClick": { "disableTripleClick": {
"description": "Disable triple click", "description": "Désactiver le triple clic",
"label": "Disable Triple Click" "label": "Désactiver le triple clic"
}, },
"doubleTapAsButtonPress": { "doubleTapAsButtonPress": {
"description": "Treat double tap as button press", "description": "Considérer le double tapotement comme un appui sur le bouton",
"label": "Double Tap as Button Press" "label": "Double tapotement comme appui bouton"
}, },
"ledHeartbeatDisabled": { "ledHeartbeatDisabled": {
"description": "Disable default blinking LED", "description": "Désactiver le clignotement LED par défaut",
"label": "LED Heartbeat Disabled" "label": "Clignotement LED désactivé"
}, },
"nodeInfoBroadcastInterval": { "nodeInfoBroadcastInterval": {
"description": "How often to broadcast node info", "description": "Fréquence de diffusion des informations du nœud",
"label": "Node Info Broadcast Interval" "label": "Intervalle de diffusion des infos nœud"
}, },
"posixTimezone": { "posixTimezone": {
"description": "The POSIX timezone string for the device", "description": "Chaîne de fuseau horaire POSIX pour l'appareil",
"label": "Zone horaire POSIX" "label": "Zone horaire POSIX"
}, },
"rebroadcastMode": { "rebroadcastMode": {
"description": "How to handle rebroadcasting", "description": "Mode de réémission des messages",
"label": "Rebroadcast Mode" "label": "Mode de réémission"
}, },
"role": { "role": {
"description": "What role the device performs on the mesh", "description": "Rôle de l'appareil dans le réseau mesh",
"label": "Rôle" "label": "Rôle"
} }
}, },
"bluetooth": { "bluetooth": {
"title": "Bluetooth Settings", "title": "Paramètres Bluetooth",
"description": "Settings for the Bluetooth module", "description": "Paramètres du module Bluetooth",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "Note: Certains appareils (ESP32) ne peuvent pas utiliser à la fois Bluetooth et WiFi en même temps.",
"enabled": { "enabled": {
"description": "Enable or disable Bluetooth", "description": "Activer ou désactiver le Bluetooth",
"label": "Activé" "label": "Activé"
}, },
"pairingMode": { "pairingMode": {
"description": "Pin selection behaviour.", "description": "Titre en gras",
"label": "Mode d'appariement" "label": "Mode d'appariement"
}, },
"pin": { "pin": {
"description": "Pin to use when pairing", "description": "Broche utilisée pour l'appairage",
"label": "Pin" "label": "Broche"
} }
}, },
"display": { "display": {
"description": "Settings for the device display", "description": "Paramètres d'affichage de l'appareil",
"title": "Display Settings", "title": "Paramètres d'affichage",
"headingBold": { "headingBold": {
"description": "Bolden the heading text", "description": "Mettre le titre en gras",
"label": "Bold Heading" "label": "Titre en gras"
}, },
"carouselDelay": { "carouselDelay": {
"description": "How fast to cycle through windows", "description": "Vitesse de défilement des fenêtres",
"label": "Carousel Delay" "label": "Délai du carrousel"
}, },
"compassNorthTop": { "compassNorthTop": {
"description": "Fix north to the top of compass", "description": "Fixer le nord en haut de la boussole",
"label": "Compass North Top" "label": "Nord en haut de la boussole"
}, },
"displayMode": { "displayMode": {
"description": "Screen layout variant", "description": "Variante de disposition d'affichage",
"label": "Display Mode" "label": "Mode d'affichage"
}, },
"displayUnits": { "displayUnits": {
"description": "Display metric or imperial units", "description": "Afficher en unités métriques ou impériales",
"label": "Display Units" "label": "Unités affichées"
}, },
"flipScreen": { "flipScreen": {
"description": "Flip display 180 degrees", "description": "Faire pivoter l'affichage de 180 degrés",
"label": "Flip Screen" "label": "Faire pivoter l'écran"
}, },
"gpsDisplayUnits": { "gpsDisplayUnits": {
"description": "Coordinate display format", "description": "Format d'affichage des coordonnées",
"label": "GPS Display Units" "label": "Unités GPS"
}, },
"oledType": { "oledType": {
"description": "Type of OLED screen attached to the device", "description": "Type d'écran OLED connecté à l'appareil",
"label": "OLED Type" "label": "Type d'OLED"
}, },
"screenTimeout": { "screenTimeout": {
"description": "Turn off the display after this long", "description": "Temps avant extinction de l'écran",
"label": "Screen Timeout" "label": "Délai d'extinction de l'écran"
}, },
"twelveHourClock": { "twelveHourClock": {
"description": "Use 12-hour clock format", "description": "Utiliser le format horaire 12 heures",
"label": "12-Hour Clock" "label": "Horloge 12 h"
}, },
"wakeOnTapOrMotion": { "wakeOnTapOrMotion": {
"description": "Wake the device on tap or motion", "description": "Réveiller l'appareil en cas de tapotement ou de mouvement",
"label": "Wake on Tap or Motion" "label": "Réveil par tapotement ou mouvement"
} }
}, },
"lora": { "lora": {
"title": "Mesh Settings", "title": "Paramètres maillage",
"description": "Settings for the LoRa mesh", "description": "Paramètres du réseau maillé LoRa",
"bandwidth": { "bandwidth": {
"description": "Channel bandwidth in MHz", "description": "Largeur de bande du canal en MHz",
"label": "Bande Passante" "label": "Bande Passante"
}, },
"boostedRxGain": { "boostedRxGain": {
"description": "Boosted RX gain", "description": "Gain de réception amplifié",
"label": "Boosted RX Gain" "label": "Gain RX amplifié"
}, },
"codingRate": { "codingRate": {
"description": "The denominator of the coding rate", "description": "Dénominateur du taux de codage",
"label": "Coding Rate" "label": "Taux de codage"
}, },
"frequencyOffset": { "frequencyOffset": {
"description": "Frequency offset to correct for crystal calibration errors", "description": "Décalage de fréquence pour corriger les erreurs d'étalonnage du cristal",
"label": "Frequency Offset" "label": "Décalage de fréquence"
}, },
"frequencySlot": { "frequencySlot": {
"description": "LoRa frequency channel number", "description": "Numéro du canal de fréquence LoRa",
"label": "Frequency Slot" "label": "Slot de fréquence"
}, },
"hopLimit": { "hopLimit": {
"description": "Maximum number of hops", "description": "Nombre maximum de sauts",
"label": "Hop Limit" "label": "Limite de sauts"
}, },
"ignoreMqtt": { "ignoreMqtt": {
"description": "Don't forward MQTT messages over the mesh", "description": "Ne pas transférer les messages MQTT sur le maillage",
"label": "Ignorer MQTT" "label": "Ignorer MQTT"
}, },
"modemPreset": { "modemPreset": {
"description": "Modem preset to use", "description": "Préréglage du modem à utiliser",
"label": "Modem Preset" "label": "Préréglage du modem"
}, },
"okToMqtt": { "okToMqtt": {
"description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", "description": "Si activé, permet la publication du paquet sur MQTT. Sinon, les nœuds distants ne doivent pas relayer les paquets vers MQTT.",
"label": "OK vers MQTT" "label": "OK vers MQTT"
}, },
"overrideDutyCycle": { "overrideDutyCycle": {
@ -162,267 +162,267 @@
"label": "Ne pas prendre en compte la limite d'utilisation" "label": "Ne pas prendre en compte la limite d'utilisation"
}, },
"overrideFrequency": { "overrideFrequency": {
"description": "Override frequency", "description": "Remplacement de la fréquence",
"label": "Override Frequency" "label": "Fréquence personnalisée"
}, },
"region": { "region": {
"description": "Sets the region for your node", "description": "Définit la région pour votre nœud",
"label": "Région" "label": "Région"
}, },
"spreadingFactor": { "spreadingFactor": {
"description": "Indicates the number of chirps per symbol", "description": "Nombre de chirps par symbole",
"label": "Spreading Factor" "label": "Facteur d'étalement"
}, },
"transmitEnabled": { "transmitEnabled": {
"description": "Enable/Disable transmit (TX) from the LoRa radio", "description": "Activer/désactiver l'émission (TX) depuis la radio LoRa",
"label": "Transmit Enabled" "label": "Transmission activée"
}, },
"transmitPower": { "transmitPower": {
"description": "Max transmit power", "description": "Puissance maximale d'émission",
"label": "Transmit Power" "label": "Puissance d'émission"
}, },
"usePreset": { "usePreset": {
"description": "Use one of the predefined modem presets", "description": "Utiliser un des préréglages prédéfinis du modem",
"label": "Use Preset" "label": "Utiliser un préréglage"
}, },
"meshSettings": { "meshSettings": {
"description": "Settings for the LoRa mesh", "description": "Paramètres du maillage LoRa",
"label": "Mesh Settings" "label": "Paramètres du maillage"
}, },
"waveformSettings": { "waveformSettings": {
"description": "Settings for the LoRa waveform", "description": "Paramètres de la forme d’onde LoRa",
"label": "Waveform Settings" "label": "Paramètres de l’onde"
}, },
"radioSettings": { "radioSettings": {
"label": "Radio Settings", "label": "Paramètres radio",
"description": "Settings for the LoRa radio" "description": "Paramètres de la radio LoRa"
} }
}, },
"network": { "network": {
"title": "WiFi Config", "title": "Configuration WiFi",
"description": "WiFi radio configuration", "description": "Configuration de la radio WiFi",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "Remarque : certains appareils (ESP32) ne peuvent pas utiliser simultanément Bluetooth et WiFi.",
"addressMode": { "addressMode": {
"description": "Address assignment selection", "description": "Sélection du mode d’attribution d’adresse",
"label": "Address Mode" "label": "Mode d’adressage"
}, },
"dns": { "dns": {
"description": "DNS Server", "description": "Serveur DNS",
"label": "DNS" "label": "DNS"
}, },
"ethernetEnabled": { "ethernetEnabled": {
"description": "Enable or disable the Ethernet port", "description": "Activer ou désactiver le port Ethernet",
"label": "Activé" "label": "Activé"
}, },
"gateway": { "gateway": {
"description": "Default Gateway", "description": "Passerelle par défaut",
"label": "Passerelle" "label": "Passerelle"
}, },
"ip": { "ip": {
"description": "IP Address", "description": "Adresse IP",
"label": "IP" "label": "IP"
}, },
"psk": { "psk": {
"description": "Network password", "description": "Mot de passe du réseau",
"label": "PSK" "label": "PSK"
}, },
"ssid": { "ssid": {
"description": "Network name", "description": "Nom du réseau",
"label": "SSID" "label": "SSID"
}, },
"subnet": { "subnet": {
"description": "Subnet Mask", "description": "Masque de sous-réseau",
"label": "Sous-réseau" "label": "Sous-réseau"
}, },
"wifiEnabled": { "wifiEnabled": {
"description": "Enable or disable the WiFi radio", "description": "Activer ou désactiver la radio WiFi",
"label": "Activé" "label": "Activé"
}, },
"meshViaUdp": { "meshViaUdp": {
"label": "Mesh via UDP" "label": "Réseau maillé via UDP"
}, },
"ntpServer": { "ntpServer": {
"label": "NTP Server" "label": "Serveur NTP"
}, },
"rsyslogServer": { "rsyslogServer": {
"label": "Rsyslog Server" "label": "Serveur Rsyslog"
}, },
"ethernetConfigSettings": { "ethernetConfigSettings": {
"description": "Ethernet port configuration", "description": "Paramètres du port Ethernet",
"label": "Ethernet Config" "label": "Configuration Ethernet"
}, },
"ipConfigSettings": { "ipConfigSettings": {
"description": "IP configuration", "description": "Paramètres IP",
"label": "IP Config" "label": "Configuration IP"
}, },
"ntpConfigSettings": { "ntpConfigSettings": {
"description": "NTP configuration", "description": "Configuration NTP",
"label": "NTP Config" "label": "Configuration NTP"
}, },
"rsyslogConfigSettings": { "rsyslogConfigSettings": {
"description": "Rsyslog configuration", "description": "Paramètres Rsyslog",
"label": "Rsyslog Config" "label": "Configuration Rsyslog"
}, },
"udpConfigSettings": { "udpConfigSettings": {
"description": "UDP over Mesh configuration", "description": "Configuration du réseau maillé via UDP",
"label": "Configuration UDP" "label": "Configuration UDP"
} }
}, },
"position": { "position": {
"title": "Position Settings", "title": "Paramètres de position",
"description": "Settings for the position module", "description": "Paramètres du module de position",
"broadcastInterval": { "broadcastInterval": {
"description": "How often your position is sent out over the mesh", "description": "Fréquence d’envoi de votre position sur le réseau maillé",
"label": "Broadcast Interval" "label": "Intervalle de diffusion"
}, },
"enablePin": { "enablePin": {
"description": "GPS module enable pin override", "description": "Redéfinition de la broche d’activation du module GPS",
"label": "Enable Pin" "label": "Broche d’activation"
}, },
"fixedPosition": { "fixedPosition": {
"description": "Don't report GPS position, but a manually-specified one", "description": "Ne pas envoyer la position GPS mais une position saisie manuellement",
"label": "Fixed Position" "label": "Position fixe"
}, },
"gpsMode": { "gpsMode": {
"description": "Configure whether device GPS is Enabled, Disabled, or Not Present", "description": "Configuration du GPS : activé, désactivé ou non présent",
"label": "GPS Mode" "label": "Mode GPS"
}, },
"gpsUpdateInterval": { "gpsUpdateInterval": {
"description": "How often a GPS fix should be acquired", "description": "Fréquence d’acquisition d’une position GPS",
"label": "GPS Update Interval" "label": "Intervalle de mise à jour GPS"
}, },
"positionFlags": { "positionFlags": {
"description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", "description": "Champs optionnels à inclure dans les messages de position. Plus il y en a, plus le message est grand, augmentant le risque de perte.",
"label": "Position Flags" "label": "Champs de position"
}, },
"receivePin": { "receivePin": {
"description": "GPS module RX pin override", "description": "Redéfinition de la broche RX du module GPS",
"label": "Receive Pin" "label": "Broche de réception"
}, },
"smartPositionEnabled": { "smartPositionEnabled": {
"description": "Only send position when there has been a meaningful change in location", "description": "N’envoyer la position qu’en cas de changement significatif",
"label": "Enable Smart Position" "label": "Activer la position intelligente"
}, },
"smartPositionMinDistance": { "smartPositionMinDistance": {
"description": "Minimum distance (in meters) that must be traveled before a position update is sent", "description": "Distance minimale (en mètres) à parcourir avant envoi de la nouvelle position",
"label": "Smart Position Minimum Distance" "label": "Distance minimale pour mise à jour"
}, },
"smartPositionMinInterval": { "smartPositionMinInterval": {
"description": "Minimum interval (in seconds) that must pass before a position update is sent", "description": "Délai minimal (en secondes) entre deux envois de position",
"label": "Smart Position Minimum Interval" "label": "Intervalle minimal de mise à jour"
}, },
"transmitPin": { "transmitPin": {
"description": "GPS module TX pin override", "description": "Redéfinition de la broche TX du module GPS",
"label": "Transmit Pin" "label": "Broche de transmission"
}, },
"intervalsSettings": { "intervalsSettings": {
"description": "How often to send position updates", "description": "Fréquence d’envoi des mises à jour de position",
"label": "Intervals" "label": "Intervalles"
}, },
"flags": { "flags": {
"placeholder": "Select position flags...", "placeholder": "Sélectionner les champs de position...",
"altitude": "Altitude", "altitude": "Altitude",
"altitudeGeoidalSeparation": "Altitude Geoidal Separation", "altitudeGeoidalSeparation": "Séparation géoïdale de l’altitude",
"altitudeMsl": "Altitude is Mean Sea Level", "altitudeMsl": "Altitude au-dessus du niveau moyen de la mer",
"dop": "Dilution of precision (DOP) PDOP used by default", "dop": "DOP (Dilution de la précision), PDOP utilisé par défaut",
"hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", "hdopVdop": "Si DOP est activé, utiliser HDOP / VDOP au lieu de PDOP",
"numSatellites": "Number of satellites", "numSatellites": "Nombre de satellites",
"sequenceNumber": "Sequence number", "sequenceNumber": "Numéro de séquence",
"timestamp": "Horodatage", "timestamp": "Horodatage",
"unset": "Désactivé", "unset": "Désactivé",
"vehicleHeading": "Vehicle heading", "vehicleHeading": "Cap du véhicule",
"vehicleSpeed": "Vehicle speed" "vehicleSpeed": "Vitesse du véhicule"
} }
}, },
"power": { "power": {
"adcMultiplierOverride": { "adcMultiplierOverride": {
"description": "Used for tweaking battery voltage reading", "description": "Utilisé pour ajuster la lecture de la tension batterie",
"label": "ADC Multiplier Override ratio" "label": "Coefficient de correction ADC"
}, },
"ina219Address": { "ina219Address": {
"description": "Address of the INA219 battery monitor", "description": "Adresse du moniteur de batterie INA219",
"label": "INA219 Address" "label": "Adresse INA219"
}, },
"lightSleepDuration": { "lightSleepDuration": {
"description": "How long the device will be in light sleep for", "description": "Durée pendant laquelle l'appareil reste en veille légère",
"label": "Light Sleep Duration" "label": "Durée de veille légère"
}, },
"minimumWakeTime": { "minimumWakeTime": {
"description": "Minimum amount of time the device will stay awake for after receiving a packet", "description": "Temps minimal pendant lequel l'appareil reste éveillé après réception d’un paquet",
"label": "Minimum Wake Time" "label": "Temps d’éveil minimal"
}, },
"noConnectionBluetoothDisabled": { "noConnectionBluetoothDisabled": {
"description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", "description": "Si aucune connexion Bluetooth n’est reçue, la radio BLE sera désactivée après ce délai",
"label": "No Connection Bluetooth Disabled" "label": "Bluetooth désactivé si non connecté"
}, },
"powerSavingEnabled": { "powerSavingEnabled": {
"description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", "description": "À activer si l’appareil est alimenté par une source à faible courant (ex. : panneau solaire)..",
"label": "Activer le mode économie d'énergie" "label": "Activer le mode économie d'énergie"
}, },
"shutdownOnBatteryDelay": { "shutdownOnBatteryDelay": {
"description": "Automatically shutdown node after this long when on battery, 0 for indefinite", "description": "Éteindre automatiquement le nœud après ce délai sur batterie, 0 pour indéfini",
"label": "Shutdown on battery delay" "label": "Délai d’extinction sur batterie"
}, },
"superDeepSleepDuration": { "superDeepSleepDuration": {
"description": "How long the device will be in super deep sleep for", "description": "Durée pendant laquelle l’appareil reste en super veille",
"label": "Super Deep Sleep Duration" "label": "Durée de veille profonde"
}, },
"powerConfigSettings": { "powerConfigSettings": {
"description": "Settings for the power module", "description": "Paramètres du module d’alimentation",
"label": "Configuration de l'alimentation" "label": "Configuration de l'alimentation"
}, },
"sleepSettings": { "sleepSettings": {
"description": "Sleep settings for the power module", "description": "Paramètres de veille du module d’alimentation",
"label": "Sleep Settings" "label": "Paramètres de veille"
} }
}, },
"security": { "security": {
"description": "Settings for the Security configuration", "description": "Paramètres de configuration de la sécurité",
"title": "Security Settings", "title": "Paramètres de sécurité",
"button_backupKey": "Backup Key", "button_backupKey": "Clé de sauvegarde",
"adminChannelEnabled": { "adminChannelEnabled": {
"description": "Allow incoming device control over the insecure legacy admin channel", "description": "Autoriser le contrôle distant via le canal d’administration hérité non sécurisé",
"label": "Allow Legacy Admin" "label": "Autoriser l’administration héritée"
}, },
"enableDebugLogApi": { "enableDebugLogApi": {
"description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", "description": "Afficher en direct les journaux de débogage via le port série, consulter/exporter les journaux sans position via Bluetooth",
"label": "Enable Debug Log API" "label": "Activer l’API des journaux de debug"
}, },
"managed": { "managed": {
"description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", "description": "Si cette option est activée, les options de configuration de l'appareil ne peuvent être modifiées à distance que par un nœud d'administration distante via des messages d'administration. N'activez cette option que si au moins un nœud d'administration distant approprié a été configuré et que la clé publique est stockée dans l'un des champs ci-dessus.",
"label": "Managed" "label": "Géré"
}, },
"privateKey": { "privateKey": {
"description": "Used to create a shared key with a remote device", "description": "Utilisée pour créer une clé partagée avec un appareil distant",
"label": "Clé privée" "label": "Clé privée"
}, },
"publicKey": { "publicKey": {
"description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", "description": "Envoyée aux autres nœuds pour générer une clé secrète partagée",
"label": "Clé publique" "label": "Clé publique"
}, },
"primaryAdminKey": { "primaryAdminKey": {
"description": "The primary public key authorized to send admin messages to this node", "description": "Clé publique principale autorisée à envoyer des messages d’administration",
"label": "Primary Admin Key" "label": "Clé Admin principale"
}, },
"secondaryAdminKey": { "secondaryAdminKey": {
"description": "The secondary public key authorized to send admin messages to this node", "description": "Clé publique secondaire autorisée à envoyer des messages d’administration",
"label": "Secondary Admin Key" "label": "Clé Admin secondaire"
}, },
"serialOutputEnabled": { "serialOutputEnabled": {
"description": "Serial Console over the Stream API", "description": "Console série via l’API de flux",
"label": "Serial Output Enabled" "label": "Sortie série activée"
}, },
"tertiaryAdminKey": { "tertiaryAdminKey": {
"description": "The tertiary public key authorized to send admin messages to this node", "description": "Clé publique tertiaire autorisée à envoyer des messages d’administration",
"label": "Tertiary Admin Key" "label": "Clé Admin tertiaire"
}, },
"adminSettings": { "adminSettings": {
"description": "Settings for Admin", "description": "Paramètres liés à l’administration",
"label": "Admin Settings" "label": "Paramètres administrateur"
}, },
"loggingSettings": { "loggingSettings": {
"description": "Settings for Logging", "description": "Paramètres liés aux journaux",
"label": "Logging Settings" "label": "Paramètres de journalisation"
} }
} }
} }

213
packages/web/public/i18n/locales/fr-FR/dialog.json

@ -1,171 +1,182 @@
{ {
"deleteMessages": { "deleteMessages": {
"description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", "description": "Cette action effacera tout l’historique des messages. Cette opération est irréversible. Voulez-vous vraiment continuer ?",
"title": "Clear All Messages" "title": "Supprimer tous les messages"
}, },
"deviceName": { "deviceName": {
"description": "The Device will restart once the config is saved.", "description": "L’appareil redémarrera une fois la configuration enregistrée.",
"longName": "Long Name", "longName": "Nom long",
"shortName": "Short Name", "shortName": "Nom court",
"title": "Change Device Name" "title": "Changer le nom de l’appareil",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "La configuration LoRa actuelle sera écrasée.",
"error": { "error": {
"invalidUrl": "Invalid Meshtastic URL" "invalidUrl": "URL Meshtastic invalide"
}, },
"channelPrefix": "Channel: ", "channelPrefix": "Canal: ",
"channelSetUrl": "Channel Set/QR Code URL", "channelSetUrl": "URL du set de canaux ou du QR code",
"channels": "Channels:", "channels": "Canaux:",
"usePreset": "Use Preset?", "usePreset": "Utiliser un préréglage?",
"title": "Import Channel Set" "title": "Importer un ensemble de canaux"
}, },
"locationResponse": { "locationResponse": {
"title": "Position : {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordonnées : ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Régénérer la clé pré-partagée ?",
"description": "Are you sure you want to regenerate the pre-shared key?", "description": "Êtes-vous sûr de vouloir régénérer la clé pré-partagée ?",
"regenerate": "Regenerate" "regenerate": "Régénérer"
}, },
"newDeviceDialog": { "newDeviceDialog": {
"title": "Connect New Device", "title": "Connecter un nouvel appareil",
"https": "https", "https": "https",
"http": "http", "http": "http",
"tabHttp": "HTTP", "tabHttp": "HTTP",
"tabBluetooth": "Bluetooth", "tabBluetooth": "Bluetooth",
"tabSerial": "Série", "tabSerial": "Série",
"useHttps": "Use HTTPS", "useHttps": "Utiliser HTTPS",
"connecting": "Connecting...", "connecting": "Connexion...",
"connect": "Connect", "connect": "Connecter",
"connectionFailedAlert": { "connectionFailedAlert": {
"title": "Connection Failed", "title": "Échec de la connexion",
"descriptionPrefix": "Could not connect to the device. ", "descriptionPrefix": "Vous ne pouvez pas connecter l'appareil. ",
"httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", "httpsHint": "Si vous utilisez HTTPS, vous devrez peut-être accepter un certificat auto-signé. ",
"openLinkPrefix": "Please open ", "openLinkPrefix": "Veuillez ouvrir ",
"openLinkSuffix": " in a new tab", "openLinkSuffix": " dans un nouvel onglet",
"acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", "acceptTlsWarningSuffix": ", acceptez les avertissements TLS si vous y êtes invité, puis réessayez",
"learnMoreLink": "Learn more" "learnMoreLink": "En savoir plus"
}, },
"httpConnection": { "httpConnection": {
"label": "IP Address/Hostname", "label": "Adresse IP / nom d'hôte",
"placeholder": "000.000.000.000 / meshtastic.local" "placeholder": "000.000.000.000 / meshtastic.local"
}, },
"serialConnection": { "serialConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "Aucun appareil appairé pour l’instant.",
"newDeviceButton": "New device", "newDeviceButton": "Nouvel appareil",
"deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}"
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "Aucun appareil appairé pour l’instant.",
"newDeviceButton": "New device" "newDeviceButton": "Nouvel appareil",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.", "requiresSecureContext": "Cette application nécessite un <0>contexte sécurisé</0>. Veuillez vous connecter via HTTPS ou localhost.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "additionallyRequiresSecureContext": "Elle nécessite également un <0>contexte sécurisé</0>. Veuillez vous connecter via HTTPS ou localhost."
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
}, },
"nodeDetails": { "nodeDetails": {
"message": "Message", "message": "Message",
"requestPosition": "Request Position", "requestPosition": "Demander la position",
"traceRoute": "Trace Route", "traceRoute": "Tracer la route",
"airTxUtilization": "Air TX utilization", "airTxUtilization": "Utilisation TX sur l’air",
"allRawMetrics": "All Raw Metrics:", "allRawMetrics": "Toutes les métriques brutes :",
"batteryLevel": "Battery level", "batteryLevel": "Niveau de batterie",
"channelUtilization": "Channel utilization", "channelUtilization": "Utilisation du canal",
"details": "Details:", "details": "Détails :",
"deviceMetrics": "Device Metrics:", "deviceMetrics": "Métriques de l’appareil :",
"hardware": "Hardware: ", "hardware": "Matériel : ",
"lastHeard": "Last Heard: ", "lastHeard": "Dernière écoute: ",
"nodeHexPrefix": "Node Hex: !", "nodeHexPrefix": "Hexa du nœud : !",
"nodeNumber": "Node Number: ", "nodeNumber": "Numéro de nœud: ",
"position": "Position:", "position": "Position:",
"role": "Role: ", "role": "Rôle: ",
"uptime": "Uptime: ", "uptime": "Temps de fonctionnement :",
"voltage": "Tension", "voltage": "Tension",
"title": "Node Details for {{identifier}}", "title": "Détails du nœud pour {{identifier}}",
"ignoreNode": "Ignore node", "ignoreNode": "Ignorer le nœud",
"removeNode": "Remove node", "removeNode": "Supprimer le nœud",
"unignoreNode": "Unignore node" "unignoreNode": "Ne plus ignorer le nœud"
}, },
"pkiBackup": { "pkiBackup": {
"loseKeysWarning": "If you lose your keys, you will need to reset your device.", "loseKeysWarning": "Si vous perdez vos clés, vous devrez réinitialiser votre appareil.",
"secureBackup": "Its important to backup your public and private keys and store your backup securely!", "secureBackup": "Il est important de sauvegarder vos clés publique et privée, et de stocker cette sauvegarde en lieu sûr !",
"footer": "=== END OF KEYS ===", "footer": "=== FIN DES CLÉS ===",
"header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", "header": "=== CLÉS MESHTASTIC POUR {{longName}} ({{shortName}}) ===",
"privateKey": "Private Key:", "privateKey": "Clé privée :",
"publicKey": "Public Key:", "publicKey": "Clé publique :",
"fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", "fileName": "meshtastic_cles_{{longName}}_{{shortName}}.txt",
"title": "Backup Keys" "title": "Sauvegarder les clés"
}, },
"pkiBackupReminder": { "pkiBackupReminder": {
"description": "We recommend backing up your key data regularly. Would you like to back up now?", "description": "Nous vous recommandons de sauvegarder régulièrement vos clés. Souhaitez-vous effectuer une sauvegarde maintenant ?",
"title": "Backup Reminder", "title": "Rappel de sauvegarde",
"remindLaterPrefix": "Remind me in", "remindLaterPrefix": "Me le rappeler dans",
"remindNever": "Never remind me", "remindNever": "Ne plus me le rappeler",
"backupNow": "Back up now" "backupNow": "Sauvegarder maintenant"
}, },
"pkiRegenerate": { "pkiRegenerate": {
"description": "Are you sure you want to regenerate key pair?", "description": "Êtes-vous sûr de vouloir régénérer la paire de clés ?",
"title": "Regenerate Key Pair" "title": "Régénérer la paire de clés"
}, },
"qr": { "qr": {
"addChannels": "Add Channels", "addChannels": "Ajouter des canaux",
"replaceChannels": "Replace Channels", "replaceChannels": "Remplacer les canaux",
"description": "The current LoRa configuration will also be shared.", "description": "La configuration LoRa actuelle sera également partagée.",
"sharableUrl": "Sharable URL", "sharableUrl": "URL partageable",
"title": "Générer un QR Code" "title": "Générer un QR Code"
}, },
"rebootOta": { "rebootOta": {
"title": "Schedule Reboot", "title": "Programmer un redémarrage",
"description": "Reboot the connected node after a delay into OTA (Over-the-Air) mode.", "description": "Redémarrer le nœud connecté après un délai en mode OTA (Over-the-Air).",
"enterDelay": "Enter delay (sec)", "enterDelay": "Entrer le délai (sec)",
"scheduled": "Reboot has been scheduled" "scheduled": "Le redémarrage a été programmé"
}, },
"reboot": { "reboot": {
"title": "Schedule Reboot", "title": "Programmer un redémarrage",
"description": "Reboot the connected node after x minutes." "description": "Redémarrer le nœud connecté après x minutes."
}, },
"refreshKeys": { "refreshKeys": {
"description": { "description": {
"acceptNewKeys": "This will remove the node from device and request new keys.", "acceptNewKeys": "Cela supprimera le nœud de l’appareil et demandera de nouvelles clés.",
"keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", "keyMismatchReasonSuffix": ". Cela est dû au fait que la clé publique actuelle du nœud distant ne correspond pas à celle précédemment enregistrée pour ce nœud.",
"unableToSendDmPrefix": "Your node is unable to send a direct message to node: " "unableToSendDmPrefix": "Accepter les nouvelles clés"
}, },
"acceptNewKeys": "Accept New Keys", "acceptNewKeys": "Accepter les nouvelles clés",
"title": "Keys Mismatch - {{identifier}}" "title": "Clés non concordantes – {{identifier}}"
}, },
"removeNode": { "removeNode": {
"description": "Are you sure you want to remove this Node?", "description": "Êtes-vous sûr de vouloir supprimer ce nœud ?",
"title": "Remove Node?" "title": "Supprimer le nœud ?"
}, },
"shutdown": { "shutdown": {
"title": "Schedule Shutdown", "title": "Programmer un arrêt",
"description": "Turn off the connected node after x minutes." "description": "Éteindre le nœud connecté après x minutes."
}, },
"traceRoute": { "traceRoute": {
"routeToDestination": "Route to destination:", "routeToDestination": "Route vers la destination :",
"routeBack": "Route back:" "routeBack": "Route de retour :"
}, },
"tracerouteResponse": { "tracerouteResponse": {
"title": "Traceroute: {{identifier}}" "title": "Traceroute : {{identifier}}"
}, },
"unsafeRoles": { "unsafeRoles": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Oui, je sais ce que je fais",
"conjunction": " and the blog post about ", "conjunction": " et l’article de blog sur le ",
"postamble": " and understand the implications of changing the role.", "postamble": " et je comprends les implications du changement de rôle.",
"preamble": "I have read the ", "preamble": "J'ai lu les",
"choosingRightDeviceRole": "Choosing The Right Device Role", "choosingRightDeviceRole": "Choisir le rôle d’appareil approprié",
"deviceRoleDocumentation": "Device Role Documentation", "deviceRoleDocumentation": "Documentation sur les rôles d’appareil",
"title": "Êtes-vous sûr ?" "title": "Êtes-vous sûr ?"
}, },
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Oui, je sais ce que je fais",
"title": "Êtes-vous sûr ?", "title": "Êtes-vous sûr ?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

28
packages/web/public/i18n/locales/fr-FR/messages.json

@ -1,39 +1,39 @@
{ {
"page": { "page": {
"title": "Messages: {{chatName}}", "title": "Messages: {{chatName}}",
"placeholder": "Enter Message" "placeholder": "Saisir message"
}, },
"emptyState": { "emptyState": {
"title": "Select a Chat", "title": "Sélectionnez un chat",
"text": "No messages yet." "text": "Aucun message pour le moment."
}, },
"selectChatPrompt": { "selectChatPrompt": {
"text": "Select a channel or node to start messaging." "text": "Sélectionnez un canal ou un nœud pour commencer à envoyer des messages."
}, },
"sendMessage": { "sendMessage": {
"placeholder": "Enter your message here...", "placeholder": "Entrez votre message ici...",
"sendButton": "Envoyer" "sendButton": "Envoyer"
}, },
"actionsMenu": { "actionsMenu": {
"addReactionLabel": "Add Reaction", "addReactionLabel": "Ajouter une réaction",
"replyLabel": "Répondre" "replyLabel": "Répondre"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": { "delivered": {
"label": "Message delivered", "label": "Message délivré",
"displayText": "Message delivered" "displayText": "Message délivré"
}, },
"failed": { "failed": {
"label": "Message delivery failed", "label": "La transmission du message a échoué",
"displayText": "Delivery failed" "displayText": "Échec de l'envoi"
}, },
"unknown": { "unknown": {
"label": "Message status unknown", "label": "Statut du message inconnu",
"displayText": "Unknown state" "displayText": "Statut inconnu"
}, },
"waiting": { "waiting": {
"label": "Sending message", "label": "Envoi du message",
"displayText": "Waiting for delivery" "displayText": "En attente de réception"
} }
} }
} }

416
packages/web/public/i18n/locales/fr-FR/moduleConfig.json

@ -2,410 +2,410 @@
"page": { "page": {
"tabAmbientLighting": "Lumière ambiante", "tabAmbientLighting": "Lumière ambiante",
"tabAudio": "Audio", "tabAudio": "Audio",
"tabCannedMessage": "Canned", "tabCannedMessage": "Message pré-enregistré",
"tabDetectionSensor": "Capteur de détection", "tabDetectionSensor": "Capteur de détection",
"tabExternalNotification": "Ext Notif", "tabExternalNotification": "Notification externe",
"tabMqtt": "MQTT", "tabMqtt": "MQTT",
"tabNeighborInfo": "Informations sur les voisins", "tabNeighborInfo": "Informations sur les voisins",
"tabPaxcounter": "Paxcounter", "tabPaxcounter": "Paxcounter",
"tabRangeTest": "Test de portée", "tabRangeTest": "Test de portée",
"tabSerial": "Série", "tabSerial": "Série",
"tabStoreAndForward": "S&F", "tabStoreAndForward": "Stocker & Relayer",
"tabTelemetry": "Télémetrie (Capteurs)" "tabTelemetry": "Télémetrie (Capteurs)"
}, },
"ambientLighting": { "ambientLighting": {
"title": "Ambient Lighting Settings", "title": "Paramètres de l’éclairage ambiant",
"description": "Settings for the Ambient Lighting module", "description": "Paramètres du module d’éclairage ambiant",
"ledState": { "ledState": {
"label": "LED State", "label": "État des LED",
"description": "Sets LED to on or off" "description": "Définit les LED sur allumées ou éteintes"
}, },
"current": { "current": {
"label": "Actif", "label": "Actif",
"description": "Sets the current for the LED output. Default is 10" "description": "Définit le courant de sortie des LED. Par défaut : 10"
}, },
"red": { "red": {
"label": "Rouge", "label": "Rouge",
"description": "Sets the red LED level. Values are 0-255" "description": "Définit le niveau de LED rouge (valeurs 0–255)"
}, },
"green": { "green": {
"label": "Vert", "label": "Vert",
"description": "Sets the green LED level. Values are 0-255" "description": "Définit le niveau de LED vert (valeurs 0–255)"
}, },
"blue": { "blue": {
"label": "Bleu", "label": "Bleu",
"description": "Sets the blue LED level. Values are 0-255" "description": "Définit le niveau de LED bleu (valeurs 0–255)"
} }
}, },
"audio": { "audio": {
"title": "Audio Settings", "title": "Paramètres audio",
"description": "Settings for the Audio module", "description": "Paramètres du module audio",
"codec2Enabled": { "codec2Enabled": {
"label": "Codec 2 Enabled", "label": "Codec 2 activé",
"description": "Enable Codec 2 audio encoding" "description": "Active l'encodage audio Codec 2"
}, },
"pttPin": { "pttPin": {
"label": "PTT Pin", "label": "Broche PTT",
"description": "GPIO pin to use for PTT" "description": "Broche GPIO utilisée pour le PTT"
}, },
"bitrate": { "bitrate": {
"label": "Bitrate", "label": "Débit",
"description": "Bitrate to use for audio encoding" "description": "Débit utilisé pour l’encodage audio"
}, },
"i2sWs": { "i2sWs": {
"label": "i2S WS", "label": "i2S WS",
"description": "GPIO pin to use for i2S WS" "description": "Broche GPIO utilisée pour i2S WS"
}, },
"i2sSd": { "i2sSd": {
"label": "i2S SD", "label": "i2S SD",
"description": "GPIO pin to use for i2S SD" "description": "Broche GPIO utilisée pour i2S SD"
}, },
"i2sDin": { "i2sDin": {
"label": "i2S DIN", "label": "i2S DIN",
"description": "GPIO pin to use for i2S DIN" "description": "Broche GPIO utilisée pour i2S DIN"
}, },
"i2sSck": { "i2sSck": {
"label": "i2S SCK", "label": "i2S SCK",
"description": "GPIO pin to use for i2S SCK" "description": "Broche GPIO utilisée pour i2S SCK"
} }
}, },
"cannedMessage": { "cannedMessage": {
"title": "Canned Message Settings", "title": "Paramètres des messages pré-enregistrés",
"description": "Settings for the Canned Message module", "description": "Paramètres du module de messages pré-enregistrés\n",
"moduleEnabled": { "moduleEnabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable Canned Message" "description": "Active les messages pré-enregistrés"
}, },
"rotary1Enabled": { "rotary1Enabled": {
"label": "Rotary Encoder #1 Enabled", "label": "Encodeur rotatif #1 activé",
"description": "Enable the rotary encoder" "description": "Active l’encodeur rotatif"
}, },
"inputbrokerPinA": { "inputbrokerPinA": {
"label": "Encoder Pin A", "label": "Broche A de l’encodeur",
"description": "GPIO Pin Value (1-39) For encoder port A" "description": "Valeur GPIO (1-39) pour le port A de l’encodeur"
}, },
"inputbrokerPinB": { "inputbrokerPinB": {
"label": "Encoder Pin B", "label": "Broche B de l’encodeur",
"description": "GPIO Pin Value (1-39) For encoder port B" "description": "Valeur GPIO (1-39) pour le port B de l’encodeur"
}, },
"inputbrokerPinPress": { "inputbrokerPinPress": {
"label": "Encoder Pin Press", "label": "Broche de pression de l’encodeur",
"description": "GPIO Pin Value (1-39) For encoder Press" "description": "Valeur GPIO (1-39) pour la pression sur l’encodeur"
}, },
"inputbrokerEventCw": { "inputbrokerEventCw": {
"label": "Clockwise event", "label": "Événement horaire",
"description": "Select input event." "description": "Sélectionner l’événement d’entrée"
}, },
"inputbrokerEventCcw": { "inputbrokerEventCcw": {
"label": "Counter Clockwise event", "label": "Événement antihoraire",
"description": "Select input event." "description": "Sélectionner l’événement d’entrée"
}, },
"inputbrokerEventPress": { "inputbrokerEventPress": {
"label": "Press event", "label": "Événement pression",
"description": "Select input event" "description": "Sélectionner l’événement d’entrée"
}, },
"updown1Enabled": { "updown1Enabled": {
"label": "Up Down enabled", "label": "Encodeur haut/bas activé",
"description": "Enable the up / down encoder" "description": "Active l’encodeur haut/bas"
}, },
"allowInputSource": { "allowInputSource": {
"label": "Allow Input Source", "label": "Autoriser la source d’entrée",
"description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" "description": "Sélectionner parmi : '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'"
}, },
"sendBell": { "sendBell": {
"label": "Send Bell", "label": "Envoyer un bip",
"description": "Sends a bell character with each message" "description": "Envoie un caractère de cloche avec chaque message"
} }
}, },
"detectionSensor": { "detectionSensor": {
"title": "Detection Sensor Settings", "title": "Paramètres du capteur de détection",
"description": "Settings for the Detection Sensor module", "description": "Paramètres du module de capteur de détection",
"enabled": { "enabled": {
"label": "Activé", "label": "Activé",
"description": "Enable or disable Detection Sensor Module" "description": "Activer ou désactiver le module de détection"
}, },
"minimumBroadcastSecs": { "minimumBroadcastSecs": {
"label": "Minimum Broadcast Seconds", "label": "Intervalle minimum d’émission (s)",
"description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" "description": "L'intervalle en secondes de la fréquence à laquelle nous pouvons envoyer un message au maillage quand un changement d'état est détecté"
}, },
"stateBroadcastSecs": { "stateBroadcastSecs": {
"label": "State Broadcast Seconds", "label": "Intervalle d’état (s)",
"description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" "description": "Temps entre deux messages d’état envoyés, même sans changement"
}, },
"sendBell": { "sendBell": {
"label": "Send Bell", "label": "Envoyer un bip",
"description": "Send ASCII bell with alert message" "description": "Envoyer un caractère ASCII 'bell' avec le message d’alerte"
}, },
"name": { "name": {
"label": "Friendly Name", "label": "Nom convivial",
"description": "Used to format the message sent to mesh, max 20 Characters" "description": "Utilisé pour formater le message envoyé au réseau, max. 20 caractères"
}, },
"monitorPin": { "monitorPin": {
"label": "Monitor Pin", "label": "Broche de monitoring",
"description": "The GPIO pin to monitor for state changes" "description": "Broche GPIO pour surveiller les changements d'état"
}, },
"detectionTriggerType": { "detectionTriggerType": {
"label": "Detection Triggered Type", "label": "Type du déclencheur de détection",
"description": "The type of trigger event to be used" "description": "Le type d'événement déclencheur à utiliser"
}, },
"usePullup": { "usePullup": {
"label": "Use Pullup", "label": "Utiliser Pullup",
"description": "Whether or not use INPUT_PULLUP mode for GPIO pin" "description": "Utiliser ou non le mode INPUT_PULLUP pour la broche GPIO"
} }
}, },
"externalNotification": { "externalNotification": {
"title": "External Notification Settings", "title": "Paramètres de la notification extérieure",
"description": "Configure the external notification module", "description": "Configurer le module de notification externe",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable External Notification" "description": "Activer les notifications externes"
}, },
"outputMs": { "outputMs": {
"label": "Output MS", "label": "Sortie MS",
"description": "Output MS" "description": "Sortie MS"
}, },
"output": { "output": {
"label": "Output", "label": "Sortie",
"description": "Output" "description": "Sortie"
}, },
"outputVibra": { "outputVibra": {
"label": "Output Vibrate", "label": "Sortie vibreur",
"description": "Output Vibrate" "description": "Sortie vibreur"
}, },
"outputBuzzer": { "outputBuzzer": {
"label": "Output Buzzer", "label": "Sortie buzzer",
"description": "Output Buzzer" "description": "Sortie buzzer"
}, },
"active": { "active": {
"label": "Active", "label": "Actif",
"description": "Active" "description": "Actif"
}, },
"alertMessage": { "alertMessage": {
"label": "Alert Message", "label": "Message d'alerte",
"description": "Alert Message" "description": "Message d'alerte"
}, },
"alertMessageVibra": { "alertMessageVibra": {
"label": "Alert Message Vibrate", "label": "Message d'alerte vibreur",
"description": "Alert Message Vibrate" "description": "Message d'alerte vibreur"
}, },
"alertMessageBuzzer": { "alertMessageBuzzer": {
"label": "Alert Message Buzzer", "label": "Message d'alerte buzzer",
"description": "Alert Message Buzzer" "description": "Message d'alerte buzzer"
}, },
"alertBell": { "alertBell": {
"label": "Alert Bell", "label": "Bip d'alerte",
"description": "Should an alert be triggered when receiving an incoming bell?" "description": "Une alerte doit-elle être déclenchée lors de la réception d'un bip entrant ?"
}, },
"alertBellVibra": { "alertBellVibra": {
"label": "Alert Bell Vibrate", "label": "Bip d'alerte vibreur",
"description": "Alert Bell Vibrate" "description": "Bip d'alerte vibreur"
}, },
"alertBellBuzzer": { "alertBellBuzzer": {
"label": "Alert Bell Buzzer", "label": "Bip d'alerte buzzer",
"description": "Alert Bell Buzzer" "description": "Bip d'alerte buzzer"
}, },
"usePwm": { "usePwm": {
"label": "Use PWM", "label": "Utiliser PWM",
"description": "Use PWM" "description": "Utiliser PWM"
}, },
"nagTimeout": { "nagTimeout": {
"label": "Nag Timeout", "label": "Délai d'expiration du message",
"description": "Nag Timeout" "description": "Délai d'expiration du message"
}, },
"useI2sAsBuzzer": { "useI2sAsBuzzer": {
"label": "Use I²S Pin as Buzzer", "label": "Utiliser la broche I2S comme Buzzer",
"description": "Designate I²S Pin as Buzzer Output" "description": "Désigner la broche I2S comme sortie Buzzer"
} }
}, },
"mqtt": { "mqtt": {
"title": "MQTT Settings", "title": "Paramètres MQTT",
"description": "Settings for the MQTT module", "description": "Paramètres du module MQTT",
"enabled": { "enabled": {
"label": "Activé", "label": "Activé",
"description": "Enable or disable MQTT" "description": "Activer ou désactiver MQTT"
}, },
"address": { "address": {
"label": "MQTT Server Address", "label": "Adresse du serveur MQTT",
"description": "MQTT server address to use for default/custom servers" "description": "Adresse du serveur MQTT à utiliser pour les serveurs par défaut/personnalisés"
}, },
"username": { "username": {
"label": "MQTT Username", "label": "Nom d'utilisateur MQTT",
"description": "MQTT username to use for default/custom servers" "description": "Nom d'utilisateur MQTT à utiliser pour les serveurs par défaut/personnalisés"
}, },
"password": { "password": {
"label": "MQTT Password", "label": "Mot de passe MQTT",
"description": "MQTT password to use for default/custom servers" "description": "Mot de passe MQTT à utiliser pour les serveurs par défaut/personnalisés"
}, },
"encryptionEnabled": { "encryptionEnabled": {
"label": "Encryption Enabled", "label": "Chiffrement activé",
"description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." "description": "Activer ou désactiver le chiffrement MQTT. Remarque : Tous les messages sont envoyés au broker MQTT non chiffré si cette option n'est pas activée, même si vos canaux uplink ont des clés de chiffrement. Cela inclut les données de position."
}, },
"jsonEnabled": { "jsonEnabled": {
"label": "JSON Enabled", "label": "JSON activé",
"description": "Whether to send/consume JSON packets on MQTT" "description": "S'il faut envoyer/consommer des paquets JSON sur MQTT"
}, },
"tlsEnabled": { "tlsEnabled": {
"label": "TLS Enabled", "label": "TLS activé",
"description": "Enable or disable TLS" "description": "Activer ou désactiver TLS"
}, },
"root": { "root": {
"label": "Sujet principal", "label": "Sujet principal",
"description": "MQTT root topic to use for default/custom servers" "description": "Sujet racine MQTT à utiliser pour les serveurs par défaut/personnalisés"
}, },
"proxyToClientEnabled": { "proxyToClientEnabled": {
"label": "MQTT Client Proxy Enabled", "label": "Proxy client MQTT activé",
"description": "Utilizes the network connection to proxy MQTT messages to the client." "description": "Utilise la connexion réseau pour transmettre les messages MQTT au client."
}, },
"mapReportingEnabled": { "mapReportingEnabled": {
"label": "Map Reporting Enabled", "label": "Rapport cartographique activé",
"description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." "description": "Votre nœud enverra périodiquement un paquet de rapport de position non chiffré au serveur MQTT configuré. Ce paquet inclut l'identifiant, les noms long et court, la position approximative, le modèle matériel, le rôle, la version du micrologiciel, la région LoRa, le préréglage du modem et le nom du canal principal."
}, },
"mapReportSettings": { "mapReportSettings": {
"publishIntervalSecs": { "publishIntervalSecs": {
"label": "Map Report Publish Interval (s)", "label": "Intervalles de publication du rapport de carte",
"description": "Interval in seconds to publish map reports" "description": "Intervalle en secondes pour publier les rapports de carte"
}, },
"positionPrecision": { "positionPrecision": {
"label": "Approximate Location", "label": "Position approximative",
"description": "Position shared will be accurate within this distance", "description": "La position partagée sera précise dans cette distance",
"options": { "options": {
"metric_km23": "Within 23 km", "metric_km23": "A moins de 23 km",
"metric_km12": "Within 12 km", "metric_km12": "A moins de 12 km",
"metric_km5_8": "Within 5.8 km", "metric_km5_8": "A moins de 5.8 km",
"metric_km2_9": "Within 2.9 km", "metric_km2_9": "A moins de 2.9 km",
"metric_km1_5": "Within 1.5 km", "metric_km1_5": "A moins de 1.5 km",
"metric_m700": "Within 700 m", "metric_m700": "A moins de 700 m",
"metric_m350": "Within 350 m", "metric_m350": "A moins de 350 m",
"metric_m200": "Within 200 m", "metric_m200": "À moins de 200 m",
"metric_m90": "Within 90 m", "metric_m90": "A moins de 90 m",
"metric_m50": "Within 50 m", "metric_m50": "A moins de 50 m",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "À moins de 15 miles",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "À moins de 7,3 miles",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "À moins de 3,6 miles",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "À moins de 1,8 miles",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "À moins de 0,9 miles",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "À moins de 0,5 miles",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "À moins de 0,2 miles",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "À moins de 600 pieds",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "À moins de 300 pieds",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "À moins de 150 pieds"
} }
} }
} }
}, },
"neighborInfo": { "neighborInfo": {
"title": "Neighbor Info Settings", "title": "Paramètres des informations du voisinage",
"description": "Settings for the Neighbor Info module", "description": "Paramètres pour le module informations du voisinage",
"enabled": { "enabled": {
"label": "Activé", "label": "Activé",
"description": "Enable or disable Neighbor Info Module" "description": "Activer ou désactiver le module informations du voisinage"
}, },
"updateInterval": { "updateInterval": {
"label": "Update Interval", "label": "Intervalle de mise à jour",
"description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" "description": "Intervalle en secondes de la fréquence à laquelle nous devrions essayer d'envoyer nos informations de Voisinage au maillage"
} }
}, },
"paxcounter": { "paxcounter": {
"title": "Paxcounter Settings", "title": "Paramètres Paxcounter",
"description": "Settings for the Paxcounter module", "description": "Paramètres du module Paxcounter",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable Paxcounter" "description": "Activer Paxcounter"
}, },
"paxcounterUpdateInterval": { "paxcounterUpdateInterval": {
"label": "Update Interval (seconds)", "label": "Intervalle de mise à jour (secondes)",
"description": "How long to wait between sending paxcounter packets" "description": "Durée d'attente entre l'envoi de paquets paxcounter"
}, },
"wifiThreshold": { "wifiThreshold": {
"label": "WiFi RSSI Threshold", "label": "Seuil RSSI WiFi",
"description": "At what WiFi RSSI level should the counter increase. Defaults to -80." "description": "A quel niveau de WiFi RSSI devrait augmenter le compteur. Par défaut, -80."
}, },
"bleThreshold": { "bleThreshold": {
"label": "BLE RSSI Threshold", "label": "Seuil RSSI BLE",
"description": "At what BLE RSSI level should the counter increase. Defaults to -80." "description": "A quel niveau de BLE RSSI devrait augmenter le compteur. Par défaut, -80."
} }
}, },
"rangeTest": { "rangeTest": {
"title": "Range Test Settings", "title": "Paramètres de test de portée",
"description": "Settings for the Range Test module", "description": "Paramètres du module de test de portée",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable Range Test" "description": "Activer le test de portée"
}, },
"sender": { "sender": {
"label": "Message Interval", "label": "Intervalle de message",
"description": "How long to wait between sending test packets" "description": "Durée d'attente entre l'envoi de paquets de test"
}, },
"save": { "save": {
"label": "Save CSV to storage", "label": "Enregistrer le CSV dans le stockage",
"description": "ESP32 Only" "description": "ESP32 seulement"
} }
}, },
"serial": { "serial": {
"title": "Serial Settings", "title": "Paramètres série",
"description": "Settings for the Serial module", "description": "Paramètres du module série",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable Serial output" "description": "Activer la sortie série"
}, },
"echo": { "echo": {
"label": "Écho", "label": "Écho",
"description": "Any packets you send will be echoed back to your device" "description": "Tous les paquets que vous envoyez seront renvoyés vers votre appareil"
}, },
"rxd": { "rxd": {
"label": "Receive Pin", "label": "Broche de réception",
"description": "Set the GPIO pin to the RXD pin you have set up." "description": "Réglez la broche GPIO sur la broche RXD que vous avez configurée."
}, },
"txd": { "txd": {
"label": "Transmit Pin", "label": "Broche de transmission",
"description": "Set the GPIO pin to the TXD pin you have set up." "description": "Réglez la broche GPIO sur la broche TXD que vous avez configurée."
}, },
"baud": { "baud": {
"label": "Baud Rate", "label": "Vitesse en bauds",
"description": "The serial baud rate" "description": "Vitesse de transmission série"
}, },
"timeout": { "timeout": {
"label": "Délai d'expiration", "label": "Délai d'expiration",
"description": "Seconds to wait before we consider your packet as 'done'" "description": "Secondes à attendre avant de considérer votre paquet comme \"fini\""
}, },
"mode": { "mode": {
"label": "Mode", "label": "Mode",
"description": "Select Mode" "description": "Sélection de mode"
}, },
"overrideConsoleSerialPort": { "overrideConsoleSerialPort": {
"label": "Override Console Serial Port", "label": "Outrepasser le port série de la console",
"description": "If you have a serial port connected to the console, this will override it." "description": "Si vous avez un port série connecté à la console, cela va le remplacer."
} }
}, },
"storeForward": { "storeForward": {
"title": "Store & Forward Settings", "title": "Paramètres de stockage et transfert",
"description": "Settings for the Store & Forward module", "description": "Paramètres du module stockage et transfert",
"enabled": { "enabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable Store & Forward" "description": "Activer stockage et transfert"
}, },
"heartbeat": { "heartbeat": {
"label": "Heartbeat Enabled", "label": "Pulsations activées",
"description": "Enable Store & Forward heartbeat" "description": "Activer les pulsations stockage et transfert"
}, },
"records": { "records": {
"label": "Nombre d'enregistrements", "label": "Nombre d'enregistrements",
"description": "Number of records to store" "description": "Nombre d'enregistrements à stocker"
}, },
"historyReturnMax": { "historyReturnMax": {
"label": "History return max", "label": "Limite d’historique renvoyé",
"description": "Max number of records to return" "description": "Nombre maximum d'enregistrements à retourner"
}, },
"historyReturnWindow": { "historyReturnWindow": {
"label": "History return window", "label": "Fenêtre de retour d’historique",
"description": "Max number of records to return" "description": "Nombre maximum d'enregistrements à retourner"
} }
}, },
"telemetry": { "telemetry": {
"title": "Telemetry Settings", "title": "Paramètres de télémétrie",
"description": "Settings for the Telemetry module", "description": "Paramètres du module télémétrie",
"deviceUpdateInterval": { "deviceUpdateInterval": {
"label": "Device Metrics", "label": "Métriques de l’appareil",
"description": "Intervalle de mise à jour des métriques de l'appareil (secondes)" "description": "Intervalle de mise à jour des métriques de l'appareil (secondes)"
}, },
"environmentUpdateInterval": { "environmentUpdateInterval": {
@ -413,36 +413,36 @@
"description": "" "description": ""
}, },
"environmentMeasurementEnabled": { "environmentMeasurementEnabled": {
"label": "Module Enabled", "label": "Module activé",
"description": "Enable the Environment Telemetry" "description": "Activer la télémétrie d'environnement"
}, },
"environmentScreenEnabled": { "environmentScreenEnabled": {
"label": "Displayed on Screen", "label": "Affiché à l'écran",
"description": "Show the Telemetry Module on the OLED" "description": "Afficher le module de télémétrie sur OLED"
}, },
"environmentDisplayFahrenheit": { "environmentDisplayFahrenheit": {
"label": "Display Fahrenheit", "label": "Afficher en Fahrenheit",
"description": "Display temp in Fahrenheit" "description": "Afficher la température en Fahrenheit"
}, },
"airQualityEnabled": { "airQualityEnabled": {
"label": "Air Quality Enabled", "label": "Qualité de l'air activée",
"description": "Enable the Air Quality Telemetry" "description": "Activer la télémétrie de qualité de l'air"
}, },
"airQualityInterval": { "airQualityInterval": {
"label": "Air Quality Update Interval", "label": "Intervalle de mise à jour de la qualité de l'air",
"description": "How often to send Air Quality data over the mesh" "description": "Fréquence d'envoi des données de qualité de l'air sur le maillage"
}, },
"powerMeasurementEnabled": { "powerMeasurementEnabled": {
"label": "Power Measurement Enabled", "label": "Mesure de puissance activée",
"description": "Enable the Power Measurement Telemetry" "description": "Activer la télémétrie de mesure d'énergie"
}, },
"powerUpdateInterval": { "powerUpdateInterval": {
"label": "Power Update Interval", "label": "Intervalle de mise à jour de l'alimentation",
"description": "How often to send Power data over the mesh" "description": "Fréquence d'envoi de données d'alimentation sur le maillage"
}, },
"powerScreenEnabled": { "powerScreenEnabled": {
"label": "Power Screen Enabled", "label": "Écran d'alimentation activé",
"description": "Enable the Power Telemetry Screen" "description": "Activer l'écran de télémétrie d'alimentation"
} }
} }
} }

44
packages/web/public/i18n/locales/fr-FR/nodes.json

@ -1,63 +1,63 @@
{ {
"nodeDetail": { "nodeDetail": {
"publicKeyEnabled": { "publicKeyEnabled": {
"label": "Public Key Enabled" "label": "Clé publique activée"
}, },
"noPublicKey": { "noPublicKey": {
"label": "No Public Key" "label": "Aucune clé publique"
}, },
"directMessage": { "directMessage": {
"label": "Direct Message {{shortName}}" "label": "Message direct à {{shortName}}"
}, },
"favorite": { "favorite": {
"label": "Favoris", "label": "Favoris",
"tooltip": "Add or remove this node from your favorites" "tooltip": "Ajouter ou retirer ce nœud de vos favoris"
}, },
"notFavorite": { "notFavorite": {
"label": "Not a Favorite" "label": "Non favori"
}, },
"error": { "error": {
"label": "Erreur", "label": "Erreur",
"text": "An error occurred while fetching node details. Please try again later." "text": "Une erreur est survenue lors du chargement des détails du nœud. Veuillez réessayer."
}, },
"status": { "status": {
"heard": "Capté", "heard": "Capté",
"mqtt": "MQTT" "mqtt": "MQTT"
}, },
"elevation": { "elevation": {
"label": "Elevation" "label": "Altitude"
}, },
"channelUtil": { "channelUtil": {
"label": "Channel Util" "label": "Utilisation du canal"
}, },
"airtimeUtil": { "airtimeUtil": {
"label": "Airtime Util" "label": "Utilisation du temps d’antenne"
} }
}, },
"nodesTable": { "nodesTable": {
"headings": { "headings": {
"longName": "Long Name", "longName": "Nom long",
"connection": "Connection", "connection": "Connexion",
"lastHeard": "Last Heard", "lastHeard": "Dernière écoute",
"encryption": "Encryption", "encryption": "Chiffrement",
"model": "Model", "model": "Modèle",
"macAddress": "MAC Address" "macAddress": "Adresse MAC"
}, },
"connectionStatus": { "connectionStatus": {
"direct": "Direk", "direct": "Direk",
"away": "away", "away": "distant",
"unknown": "-", "unknown": "-",
"viaMqtt": ", via MQTT" "viaMqtt": ", via MQTT"
}, },
"lastHeardStatus": { "lastHeardStatus": {
"never": "Never" "never": "Jamais"
} }
}, },
"actions": { "actions": {
"added": "Added", "added": "Ajouté",
"removed": "Removed", "removed": "Supprimé",
"ignoreNode": "Ignore Node", "ignoreNode": "Ignorer le nœud",
"unignoreNode": "Unignore Node", "unignoreNode": "Ne plus ignorer le nœud",
"requestPosition": "Request Position" "requestPosition": "Demander la position"
} }
} }

168
packages/web/public/i18n/locales/fr-FR/ui.json

@ -3,109 +3,109 @@
"title": "Navigation", "title": "Navigation",
"messages": "Messages", "messages": "Messages",
"map": "Carte", "map": "Carte",
"config": "Config", "config": "Configuration",
"radioConfig": "Radio Config", "radioConfig": "Configuration radio",
"moduleConfig": "Module Config", "moduleConfig": "Configuration du module",
"channels": "Canaux", "channels": "Canaux",
"nodes": "Noeuds" "nodes": "Noeuds"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",
"logo": "Meshtastic Logo" "logo": "Logo Meshtastic"
}, },
"sidebar": { "sidebar": {
"collapseToggle": { "collapseToggle": {
"button": { "button": {
"open": "Open sidebar", "open": "Ouvrir la barre latérale",
"close": "Close sidebar" "close": "Fermer la barre latérale"
} }
}, },
"deviceInfo": { "deviceInfo": {
"volts": "{{voltage}} volts", "volts": "{{voltage}} volts",
"firmware": { "firmware": {
"title": "Firmware", "title": "Micrologiciel",
"version": "v{{version}}", "version": "v{{version}}",
"buildDate": "Build date: {{date}}" "buildDate": "Date de compilation : {{date}}"
}, },
"deviceName": { "deviceName": {
"title": "Device Name", "title": "Nom de l'appareil",
"changeName": "Change Device Name", "changeName": "Changer le nom de l'appareil",
"placeholder": "Enter device name" "placeholder": "Saisissez le nom de l'appareil"
}, },
"editDeviceName": "Edit device name" "editDeviceName": "Éditer le nom de l'appareil"
} }
}, },
"batteryStatus": { "batteryStatus": {
"charging": "{{level}}% charging", "charging": "{{level}}% en charge",
"pluggedIn": "Plugged in", "pluggedIn": "Branché",
"title": "Batterie" "title": "Batterie"
}, },
"search": { "search": {
"nodes": "Search nodes...", "nodes": "Recherche de nœuds...",
"channels": "Search channels...", "channels": "Rechercher des canaux...",
"commandPalette": "Search commands..." "commandPalette": "Rechercher des commandes..."
}, },
"toast": { "toast": {
"positionRequestSent": { "positionRequestSent": {
"title": "Position request sent." "title": "Requête de position envoyée."
}, },
"requestingPosition": { "requestingPosition": {
"title": "Requesting position, please wait..." "title": "Requête de position en cours, veuillez patienter..."
}, },
"sendingTraceroute": { "sendingTraceroute": {
"title": "Sending Traceroute, please wait..." "title": "Envoi du traceroute en cours, veuillez patienter..."
}, },
"tracerouteSent": { "tracerouteSent": {
"title": "Traceroute sent." "title": "Traceroute envoyé."
}, },
"savedChannel": { "savedChannel": {
"title": "Saved Channel: {{channelName}}" "title": "Canal enregistré : {{channelName}}"
}, },
"messages": { "messages": {
"pkiEncryption": { "pkiEncryption": {
"title": "Chat is using PKI encryption." "title": "La discussion utilise un chiffrement PKI."
}, },
"pskEncryption": { "pskEncryption": {
"title": "Chat is using PSK encryption." "title": "La discussion utilise un chiffrement PSK."
} }
}, },
"configSaveError": { "configSaveError": {
"title": "Error Saving Config", "title": "Erreur lors de l’enregistrement",
"description": "An error occurred while saving the configuration." "description": "Une erreur est survenue lors de l’enregistrement de la configuration."
}, },
"validationError": { "validationError": {
"title": "Config Errors Exist", "title": "Des erreurs de configuration existent",
"description": "Please fix the configuration errors before saving." "description": "Veuillez corriger les erreurs de configuration avant d’enregistrer."
}, },
"saveSuccess": { "saveSuccess": {
"title": "Saving Config", "title": "Configuration enregistrée",
"description": "The configuration change {{case}} has been saved." "description": "Le changement de configuration {{case}} a été enregistré."
}, },
"favoriteNode": { "favoriteNode": {
"title": "{{action}} {{nodeName}} {{direction}} favorites.", "title": "{{action}} {{nodeName}} {{direction}} des favoris.",
"action": { "action": {
"added": "Added", "added": "Ajouté",
"removed": "Removed", "removed": "Supprimé",
"to": "to", "to": "à",
"from": "from" "from": "de"
} }
}, },
"ignoreNode": { "ignoreNode": {
"title": "{{action}} {{nodeName}} {{direction}} ignore list", "title": "{{action}} {{nodeName}} {{direction}} de la liste d’ignorés",
"action": { "action": {
"added": "Added", "added": "Ajouté",
"removed": "Removed", "removed": "Supprimé",
"to": "to", "to": "à",
"from": "from" "from": "de"
} }
} }
}, },
"notifications": { "notifications": {
"copied": { "copied": {
"label": "Copied!" "label": "Copié !"
}, },
"copyToClipboard": { "copyToClipboard": {
"label": "Copy to clipboard" "label": "Copier dans le presse-papiers"
}, },
"hidePassword": { "hidePassword": {
"label": "Masquer le mot de passe" "label": "Masquer le mot de passe"
@ -114,20 +114,20 @@
"label": "Afficher le mot de passe" "label": "Afficher le mot de passe"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": "Delivered", "delivered": "Distribué",
"failed": "Delivery Failed", "failed": "Échec de l'envoi",
"waiting": "En attente . . .", "waiting": "En attente . . .",
"unknown": "Inconnu" "unknown": "Inconnu"
} }
}, },
"general": { "general": {
"label": "General" "label": "Général"
}, },
"hardware": { "hardware": {
"label": "Matériel" "label": "Matériel"
}, },
"metrics": { "metrics": {
"label": "Metrics" "label": "Métriques"
}, },
"role": { "role": {
"label": "Rôle" "label": "Rôle"
@ -136,93 +136,93 @@
"label": "Filtre" "label": "Filtre"
}, },
"advanced": { "advanced": {
"label": "Advanced" "label": "Avancé"
}, },
"clearInput": { "clearInput": {
"label": "Clear input" "label": "Effacer la saisie"
}, },
"resetFilters": { "resetFilters": {
"label": "Reset Filters" "label": "Réinitialiser les filtres"
}, },
"nodeName": { "nodeName": {
"label": "Node name/number", "label": "Nom/numéro de nœud",
"placeholder": "Meshtastic 1234" "placeholder": "Meshtastic 1234"
}, },
"airtimeUtilization": { "airtimeUtilization": {
"label": "Airtime Utilization (%)" "label": "Utilisation du temps d’antenne (%)"
}, },
"batteryLevel": { "batteryLevel": {
"label": "Battery level (%)", "label": "Niveau de batterie (%)",
"labelText": "Battery level (%): {{value}}" "labelText": "Niveau de batterie (%) : {{value}}"
}, },
"batteryVoltage": { "batteryVoltage": {
"label": "Battery voltage (V)", "label": "Tension de batterie (V)",
"title": "Tension" "title": "Tension"
}, },
"channelUtilization": { "channelUtilization": {
"label": "Channel Utilization (%)" "label": "Utilisation du canal (%)"
}, },
"hops": { "hops": {
"direct": "Direk", "direct": "Direk",
"label": "Number of hops", "label": "Nombre de sauts",
"text": "Number of hops: {{value}}" "text": "Nombre de sauts : {{value}}"
}, },
"lastHeard": { "lastHeard": {
"label": "Dernière écoute", "label": "Dernière écoute",
"labelText": "Last heard: {{value}}", "labelText": "Dernier signal reçu : {{value}}",
"nowLabel": "Now" "nowLabel": "Maintenant"
}, },
"snr": { "snr": {
"label": "SNR (db)" "label": "SNR (db)"
}, },
"favorites": { "favorites": {
"label": "Favorites" "label": "Favoris"
}, },
"hide": { "hide": {
"label": "Hide" "label": "Masquer"
}, },
"showOnly": { "showOnly": {
"label": "Show Only" "label": "Montrer seulement"
}, },
"viaMqtt": { "viaMqtt": {
"label": "Connected via MQTT" "label": "Connecté via MQTT"
}, },
"hopsUnknown": { "hopsUnknown": {
"label": "Unknown number of hops" "label": "Nombre de sauts inconnu"
}, },
"showUnheard": { "showUnheard": {
"label": "Never heard" "label": "Jamais entendu"
}, },
"language": { "language": {
"label": "Langue", "label": "Langue",
"changeLanguage": "Change Language" "changeLanguage": "Changer la langue"
}, },
"theme": { "theme": {
"dark": "Sombre", "dark": "Sombre",
"light": "Clair", "light": "Clair",
"system": "Automatic", "system": "Automatique",
"changeTheme": "Change Color Scheme" "changeTheme": "Changer le schéma de couleurs"
}, },
"errorPage": { "errorPage": {
"title": "This is a little embarrassing...", "title": "C'est un peu embarrassant...",
"description1": "We are really sorry but an error occurred in the web client that caused it to crash. <br /> This is not supposed to happen, and we are working hard to fix it.", "description1": "Nous sommes vraiment désolés mais une erreur est survenue dans le client web qui l'a fait planter. <br /> Ce n'est pas censé se produire, et nous travaillons dur pour le corriger.",
"description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", "description2": "La meilleure façon d'éviter que cela ne se reproduise à vous ou à qui que ce soit d'autre consiste à nous signaler le problème.",
"reportInstructions": "Please include the following information in your report:", "reportInstructions": "Veuillez inclure les informations suivantes dans votre rapport :",
"reportSteps": { "reportSteps": {
"step1": "What you were doing when the error occurred", "step1": "Ce que vous faisiez lorsque l'erreur s'est produite",
"step2": "What you expected to happen", "step2": "Ce que vous vous attendiez à se produire",
"step3": "What actually happened", "step3": "Ce qui s'est réellement passé",
"step4": "Any other relevant information" "step4": "Toute autre information pertinente"
}, },
"reportLink": "You can report the issue to our <0>GitHub</0>", "reportLink": "Vous pouvez signaler le problème à notre <0>GitHub</0>",
"dashboardLink": "Return to the <0>dashboard</0>", "dashboardLink": "Retourner au <0>tableau de bord</0>",
"detailsSummary": "Error Details", "detailsSummary": "Détails de l'erreur",
"errorMessageLabel": "Error message:", "errorMessageLabel": "Message d'erreur :",
"stackTraceLabel": "Stack trace:", "stackTraceLabel": "État de la pile :",
"fallbackError": "{{error}}" "fallbackError": "{{error}}"
}, },
"footer": { "footer": {
"text": "Powered by <0>▲ Vercel</0> | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information</1>", "text": "Propulsé par <0>▲ Vercel</0> | Meshtastic® est une marque déposée de Meshtastic LLC. | <1>Informations légales</1>",
"commitSha": "Commit SHA: {{sha}}" "commitSha": "SHA : {{sha}}"
} }
} }

97
packages/web/public/i18n/locales/it-IT/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "Nessun risultato trovato.", "emptyState": "Nessun risultato trovato.",
"page": { "page": {
"title": "Menu Comandi" "title": "Menu Comandi"
}, },
"pinGroup": { "pinGroup": {
"label": "Fissa gruppo comandi" "label": "Fissa gruppo comandi"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Rimuovi gruppo comandi" "label": "Rimuovi gruppo comandi"
}, },
"goto": { "goto": {
"label": "Vai a", "label": "Vai a",
"command": { "command": {
"messages": "Messaggi", "messages": "Messaggi",
"map": "Mappa", "map": "Mappa",
"config": "Configurazione", "config": "Configurazione",
"channels": "Canali", "channels": "Canali",
"nodes": "Nodi" "nodes": "Nodi"
} }
}, },
"manage": { "manage": {
"label": "Gestisci", "label": "Gestisci",
"command": { "command": {
"switchNode": "Cambia Nodo", "switchNode": "Cambia Nodo",
"connectNewNode": "Connetti Nuovo Nodo" "connectNewNode": "Connetti Nuovo Nodo"
} }
}, },
"contextual": { "contextual": {
"label": "Contestuale", "label": "Contestuale",
"command": { "command": {
"qrCode": "Codice QR", "qrCode": "Codice QR",
"qrGenerator": "Generatore", "qrGenerator": "Generatore",
"qrImport": "Importa", "qrImport": "Importa",
"scheduleShutdown": "Pianifica Spegnimento", "scheduleShutdown": "Pianifica Spegnimento",
"scheduleReboot": "Pianifica Riavvio", "scheduleReboot": "Pianifica Riavvio",
"rebootToOtaMode": "Riavvia In Modalità OTA", "rebootToOtaMode": "Riavvia In Modalità OTA",
"resetNodeDb": "Resetta DB dei Nodi", "resetNodeDb": "Resetta DB dei Nodi",
"factoryResetDevice": "Factory reset dispositivo", "factoryResetDevice": "Factory reset dispositivo",
"factoryResetConfig": "Factory reset impostazioni" "factoryResetConfig": "Factory reset impostazioni",
} "disconnect": "Disconnetti"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Riconfigura", "command": {
"clearAllStoredMessages": "Cancella Tutti i Messaggi Memorizzati" "reconfigure": "Riconfigura",
} "clearAllStoredMessages": "Cancella Tutti i Messaggi Memorizzati"
} }
}
} }

23
packages/web/public/i18n/locales/it-IT/dialog.json

@ -7,7 +7,13 @@
"description": "Il dispositivo verrà riavviato una volta salvata la configurazione.", "description": "Il dispositivo verrà riavviato una volta salvata la configurazione.",
"longName": "Nome Lungo", "longName": "Nome Lungo",
"shortName": "Nome Breve", "shortName": "Nome Breve",
"title": "Cambia Nome Dispositivo" "title": "Cambia Nome Dispositivo",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "La configurazione attuale di LoRa sarà sovrascritta.", "description": "La configurazione attuale di LoRa sarà sovrascritta.",
@ -21,9 +27,10 @@
"title": "Importa Set Canale" "title": "Importa Set Canale"
}, },
"locationResponse": { "locationResponse": {
"title": "Posizione: {{identifier}}",
"altitude": "Altitudine: ", "altitude": "Altitudine: ",
"coordinates": "Coordinate: ", "coordinates": "Coordinate: ",
"title": "Posizione: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Rigenerare La Chiave Pre-Condivisa?", "title": "Rigenerare La Chiave Pre-Condivisa?",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "Nessun dispositivo ancora abbinato.", "noDevicesPaired": "Nessun dispositivo ancora abbinato.",
"newDeviceButton": "Nuovo dispositivo" "newDeviceButton": "Nuovo dispositivo",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "Questo tipo di connessione richiede <0></0>. Si prega di utilizzare un browser supportato, come Chrome o Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "Questa applicazione richiede un <0>contesto sicuro</0>. Si prega di connettersi utilizzando HTTPS o localhost.", "requiresSecureContext": "Questa applicazione richiede un <0>contesto sicuro</0>. Si prega di connettersi utilizzando HTTPS o localhost.",
"additionallyRequiresSecureContext": "Inoltre, richiede un <0>contesto sicuro</0>. Si prega di connettersi utilizzando HTTPS o localhost." "additionallyRequiresSecureContext": "Inoltre, richiede un <0>contesto sicuro</0>. Si prega di connettersi utilizzando HTTPS o localhost."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Sì, so cosa sto facendo", "confirmUnderstanding": "Sì, so cosa sto facendo",
"title": "Sei sicuro?", "title": "Sei sicuro?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

97
packages/web/public/i18n/locales/ja-JP/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "No results found.",
"page": { "page": {
"title": "Command Menu" "title": "Command Menu"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Pin command group"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Unpin command group"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Goto",
"command": { "command": {
"messages": "メッセージ", "messages": "メッセージ",
"map": "地図", "map": "地図",
"config": "Config", "config": "Config",
"channels": "チャンネル", "channels": "チャンネル",
"nodes": "ノード" "nodes": "ノード"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "Manage",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Switch Node",
"connectNewNode": "Connect New Node" "connectNewNode": "Connect New Node"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextual",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR Code",
"qrGenerator": "Generator", "qrGenerator": "Generator",
"qrImport": "インポート", "qrImport": "インポート",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Schedule Shutdown",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "Schedule Reboot",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "Reboot To OTA Mode",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Reset Node DB",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Factory Reset Device",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "Factory Reset Config",
} "disconnect": "Disconnect"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "Reconfigure",
} "clearAllStoredMessages": "Clear All Stored Message"
} }
}
} }

23
packages/web/public/i18n/locales/ja-JP/dialog.json

@ -7,7 +7,13 @@
"description": "The Device will restart once the config is saved.", "description": "The Device will restart once the config is saved.",
"longName": "Long Name", "longName": "Long Name",
"shortName": "Short Name", "shortName": "Short Name",
"title": "Change Device Name" "title": "Change Device Name",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "The current LoRa configuration will be overridden.",
@ -21,9 +27,10 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Location: {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordinates: ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Regenerate Pre-Shared Key?",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "No devices paired yet.",
"newDeviceButton": "New device" "newDeviceButton": "New device",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Yes, I know what I'm doing",
"title": "よろしいですか?", "title": "よろしいですか?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

80
packages/web/public/i18n/locales/ko-KR/channels.json

@ -1,69 +1,69 @@
{ {
"page": { "page": {
"sectionLabel": "채널", "sectionLabel": "채널",
"channelName": "Channel: {{channelName}}", "channelName": "채널 {{channelName}}",
"broadcastLabel": "Primary", "broadcastLabel": "주 채널",
"channelIndex": "Ch {{index}}" "channelIndex": "Ch {{index}}"
}, },
"validation": { "validation": {
"pskInvalid": "Please enter a valid {{bits}} bit PSK." "pskInvalid": "유효한 {{bits}} bit PSK를 입력해 주세요."
}, },
"settings": { "settings": {
"label": "채널 설정", "label": "채널 설정",
"description": "Crypto, MQTT & misc settings" "description": "암호화, MQTT 및 기타 설정"
}, },
"role": { "role": {
"label": "역할", "label": "역할",
"description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", "description": "장치 텔레메트리 데이터는 주 채널을 통해 전송됩니다. 주 채널은 하나만 허용됩니다",
"options": { "options": {
"primary": "PRIMARY", "primary": "주 채널",
"disabled": "DISABLED", "disabled": "비활성화",
"secondary": "SECONDARY" "secondary": "보조 채널"
} }
}, },
"psk": { "psk": {
"label": "Pre-Shared Key", "label": "사전 공유 키",
"description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", "description": "지원되는 PSK 길이: 256-bit, 128-bit, 8-bit, Empty (0-bit)",
"generate": "Generate" "generate": "생성"
}, },
"name": { "name": {
"label": "이름", "label": "이름",
"description": "A unique name for the channel <12 bytes, leave blank for default" "description": "채널의 고유 이름 12 바이트 미만, 기본 값을 사용하려면 빈칸으로 두세요"
}, },
"uplinkEnabled": { "uplinkEnabled": {
"label": "Uplink Enabled", "label": "업링크 활성화",
"description": "Send messages from the local mesh to MQTT" "description": "로컬 메쉬에서 MQTT로 메시지를 전송합니다"
}, },
"downlinkEnabled": { "downlinkEnabled": {
"label": "Downlink Enabled", "label": "다운링크 활성화",
"description": "Send messages from MQTT to the local mesh" "description": "MQTT를 통해 로컬 메쉬로 메시지를 전송합니다"
}, },
"positionPrecision": { "positionPrecision": {
"label": "Location", "label": "위치",
"description": "The precision of the location to share with the channel. Can be disabled.", "description": "채널에 공유할 위치 정확도. 비활성화 할 수 있습니다.",
"options": { "options": {
"none": "Do not share location", "none": "위치를 공유하지 않습니다",
"precise": "Precise Location", "precise": "정확한 위치",
"metric_km23": "Within 23 kilometers", "metric_km23": "23 km 이내",
"metric_km12": "Within 12 kilometers", "metric_km12": "12 km 이내",
"metric_km5_8": "Within 5.8 kilometers", "metric_km5_8": "5.8 km 이내",
"metric_km2_9": "Within 2.9 kilometers", "metric_km2_9": "2.9 km 이내",
"metric_km1_5": "Within 1.5 kilometers", "metric_km1_5": "1.5 km 이내",
"metric_m700": "Within 700 meters", "metric_m700": "700 m 이내",
"metric_m350": "Within 350 meters", "metric_m350": "350 m 이내",
"metric_m200": "Within 200 meters", "metric_m200": "200 m 이내",
"metric_m90": "Within 90 meters", "metric_m90": "90 m 이내",
"metric_m50": "Within 50 meters", "metric_m50": "50 m 이내",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "15 miles 이내",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "7.3 miles 이내",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "3.6 miles 이내",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "1.8 miles 이내",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "0.9 miles 이내",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "0.5 miles 이내",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "0.2 miles 이내",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "600 feet 이내",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "300 feet 이내",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "150 feet 이내"
} }
} }
} }

97
packages/web/public/i18n/locales/ko-KR/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "검색된 결과 없음.",
"page": { "page": {
"title": "Command Menu" "title": "명령 메뉴"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "명령 그룹 고정"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "명령 그룹 고정 해제"
}, },
"goto": { "goto": {
"label": "Goto", "label": "메뉴",
"command": { "command": {
"messages": "메시지", "messages": "메시지기기",
"map": "지도", "map": "지도",
"config": "Config", "config": "설정",
"channels": "채널", "channels": "채널",
"nodes": "Nodes" "nodes": "노드"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "관리",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "노드 변경",
"connectNewNode": "Connect New Node" "connectNewNode": "새로운 노드 연결"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "관련 기능",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR 코드",
"qrGenerator": "Generator", "qrGenerator": "생성",
"qrImport": "불러오기", "qrImport": "불러오기",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "종료 예약",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "재부팅 예약",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "OTA 모드로 재부팅",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "노드 목록 초기화",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "공장 초기화",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "설정 초기",
} "disconnect": "연결 끊기"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "디버그",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "재설정",
} "clearAllStoredMessages": "저장된 모든 메시지 삭제"
} }
}
} }

116
packages/web/public/i18n/locales/ko-KR/common.json

@ -1,37 +1,37 @@
{ {
"button": { "button": {
"apply": "적용", "apply": "적용",
"backupKey": "Backup Key", "backupKey": "백업 키",
"cancel": "취소", "cancel": "취소",
"clearMessages": "Clear Messages", "clearMessages": "메시지 삭제",
"close": "닫기", "close": "닫기",
"confirm": "Confirm", "confirm": "확인",
"delete": "삭제", "delete": "삭제",
"dismiss": "Dismiss", "dismiss": "취소",
"download": "Download", "download": "다운로드",
"export": "Export", "export": "내보내기",
"generate": "Generate", "generate": "생성",
"regenerate": "Regenerate", "regenerate": "재생성",
"import": "불러오기", "import": "불러오기",
"message": "메시지", "message": "메시지",
"now": "Now", "now": "지금",
"ok": "확인", "ok": "확인",
"print": "Print", "print": "인쇄",
"rebootOtaNow": "Reboot to OTA Mode Now", "rebootOtaNow": "지금 OTA 모드로 재부팅",
"remove": "지우기", "remove": "지우기",
"requestNewKeys": "Request New Keys", "requestNewKeys": "새로운 키 요청",
"requestPosition": "Request Position", "requestPosition": "위치 요청",
"reset": "초기화", "reset": "초기화",
"save": "저장", "save": "저장",
"scanQr": " QR코드 스캔", "scanQr": " QR코드 스캔",
"traceRoute": "Trace Route", "traceRoute": "추적 루트",
"submit": "Submit" "submit": "제출"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",
"fullTitle": "Meshtastic Web Client" "fullTitle": "Meshtastic 웹 클라이언트"
}, },
"loading": "Loading...", "loading": "로딩 중...",
"unit": { "unit": {
"cps": "CPS", "cps": "CPS",
"dbm": "dBm", "dbm": "dBm",
@ -41,55 +41,55 @@
"plural": "Hops" "plural": "Hops"
}, },
"hopsAway": { "hopsAway": {
"one": "{{count}} hop away", "one": "{{count}} hop 떨어짐",
"plural": "{{count}} hops away", "plural": "{{count}} hops 떨어짐",
"unknown": "Unknown hops away" "unknown": "알 수 없는 hops 떨어짐"
}, },
"megahertz": "MHz", "megahertz": "MHz",
"raw": "raw", "raw": "raw",
"meter": { "meter": {
"one": "Meter", "one": "미터",
"plural": "Meters", "plural": "미터",
"suffix": "m" "suffix": "m"
}, },
"minute": { "minute": {
"one": "Minute", "one": "",
"plural": "Minutes" "plural": ""
}, },
"hour": { "hour": {
"one": "Hour", "one": "",
"plural": "Hours" "plural": ""
}, },
"millisecond": { "millisecond": {
"one": "Millisecond", "one": "밀리초",
"plural": "Milliseconds", "plural": "밀리초",
"suffix": "ms" "suffix": "ms"
}, },
"second": { "second": {
"one": "Second", "one": "",
"plural": "Seconds" "plural": ""
}, },
"day": { "day": {
"one": "Day", "one": "",
"plural": "Days" "plural": ""
}, },
"month": { "month": {
"one": "Month", "one": "",
"plural": "Months" "plural": ""
}, },
"year": { "year": {
"one": "Year", "one": "",
"plural": "Years" "plural": ""
}, },
"snr": "SNR", "snr": "SNR",
"volt": { "volt": {
"one": "Volt", "one": "볼트",
"plural": "Volts", "plural": "볼트",
"suffix": "V" "suffix": "V"
}, },
"record": { "record": {
"one": "Records", "one": "레코드",
"plural": "Records" "plural": "레코드"
} }
}, },
"security": { "security": {
@ -99,7 +99,7 @@
"256bit": "256 bit" "256bit": "256 bit"
}, },
"unknown": { "unknown": {
"longName": "Unknown", "longName": "알 수 없는",
"shortName": "UNK", "shortName": "UNK",
"notAvailable": "N/A", "notAvailable": "N/A",
"num": "??" "num": "??"
@ -107,35 +107,35 @@
"nodeUnknownPrefix": "!", "nodeUnknownPrefix": "!",
"unset": "UNSET", "unset": "UNSET",
"fallbackName": "Meshtastic {{last4}}", "fallbackName": "Meshtastic {{last4}}",
"node": "Node", "node": "노드",
"formValidation": { "formValidation": {
"unsavedChanges": "Unsaved changes", "unsavedChanges": "변경 내용이 저장되지 않았습니다",
"tooBig": { "tooBig": {
"string": "Too long, expected less than or equal to {{maximum}} characters.", "string": "너무 깁니다. {{maximum}} 문자 이하",
"number": "Too big, expected a number smaller than or equal to {{maximum}}.", "number": "너무 큽니다. {{maximum}} 이하",
"bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." "bytes": "너무 큽니다. {{params.maximum}} 바이트 이하"
}, },
"tooSmall": { "tooSmall": {
"string": "Too short, expected more than or equal to {{minimum}} characters.", "string": "너무 짧습니다. {{minimum}} 이상",
"number": "Too small, expected a number larger than or equal to {{minimum}}." "number": "너무 작습니다. {{minimum}} 이상"
}, },
"invalidFormat": { "invalidFormat": {
"ipv4": "Invalid format, expected an IPv4 address.", "ipv4": "잘못된 형식입니다. IPv4 주소",
"key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." "key": "잘못된 형식입니다. Base64로 인코딩된 사전 공유키 (PSK)"
}, },
"invalidType": { "invalidType": {
"number": "Invalid type, expected a number." "number": "잘못된 타입입니다. 숫자"
}, },
"pskLength": { "pskLength": {
"0bit": "Key is required to be empty.", "0bit": "키는 비어있어야 합니다.",
"8bit": "Key is required to be an 8 bit pre-shared key (PSK).", "8bit": "8 bit 사전공유키 (PSK) 가 필요합니다.",
"128bit": "Key is required to be a 128 bit pre-shared key (PSK).", "128bit": "128 bit 사전공유키 (PSK) 가 필요합니다.",
"256bit": "Key is required to be a 256 bit pre-shared key (PSK)." "256bit": "256 bit 사전공유키 (PSK) 가 필요합니다."
}, },
"required": { "required": {
"generic": "This field is required.", "generic": "필수 입력 사항입니다.",
"managed": "At least one admin key is requred if the node is managed.", "managed": "노드 관리를 위해 최소 한 개의 관리자 키가 필요합니다.",
"key": "Key is required." "key": "키가 필요합니다."
} }
} }
} }

10
packages/web/public/i18n/locales/ko-KR/dashboard.json

@ -1,12 +1,12 @@
{ {
"dashboard": { "dashboard": {
"title": "Connected Devices", "title": "연결된 장치",
"description": "Manage your connected Meshtastic devices.", "description": "연결된 Meshtastic 장치를 관리하세요.",
"connectionType_ble": "BLE", "connectionType_ble": "BLE",
"connectionType_serial": "시리얼", "connectionType_serial": "시리얼",
"connectionType_network": "네트워크", "connectionType_network": "네트워크",
"noDevicesTitle": "No devices connected", "noDevicesTitle": "연결된 장치 없음",
"noDevicesDescription": "Connect a new device to get started.", "noDevicesDescription": "새로운 장치를 연결하여 시작하세요.",
"button_newConnection": "New Connection" "button_newConnection": "새 연결"
} }
} }

236
packages/web/public/i18n/locales/ko-KR/deviceConfig.json

@ -1,8 +1,8 @@
{ {
"page": { "page": {
"title": "Configuration", "title": "설정",
"tabBluetooth": "블루투스", "tabBluetooth": "블루투스",
"tabDevice": "기기", "tabDevice": "장치",
"tabDisplay": "화면", "tabDisplay": "화면",
"tabLora": "LoRa", "tabLora": "LoRa",
"tabNetwork": "네트워크", "tabNetwork": "네트워크",
@ -11,150 +11,150 @@
"tabSecurity": "보안" "tabSecurity": "보안"
}, },
"sidebar": { "sidebar": {
"label": "Modules" "label": "모듈"
}, },
"device": { "device": {
"title": "Device Settings", "title": "장치 설정",
"description": "Settings for the device", "description": "장치 설정",
"buttonPin": { "buttonPin": {
"description": "Button pin override", "description": "버튼 핀 오버라이드",
"label": "Button Pin" "label": "버튼 핀"
}, },
"buzzerPin": { "buzzerPin": {
"description": "Buzzer pin override", "description": "부저 핀 오버라이드",
"label": "Buzzer Pin" "label": "부저 핀"
}, },
"disableTripleClick": { "disableTripleClick": {
"description": "Disable triple click", "description": "세 번 클릭 끄기",
"label": "Disable Triple Click" "label": "세 번 클릭 끄기"
}, },
"doubleTapAsButtonPress": { "doubleTapAsButtonPress": {
"description": "Treat double tap as button press", "description": "더블 탭하여 버튼 누름",
"label": "Double Tap as Button Press" "label": "더블 탭하여 버튼 누름"
}, },
"ledHeartbeatDisabled": { "ledHeartbeatDisabled": {
"description": "Disable default blinking LED", "description": "기본 깜빡이는 LED를 비활성화",
"label": "LED Heartbeat Disabled" "label": "LED 깜빡임 비활성화"
}, },
"nodeInfoBroadcastInterval": { "nodeInfoBroadcastInterval": {
"description": "How often to broadcast node info", "description": "노드 정보의 발송 주기를 설정",
"label": "Node Info Broadcast Interval" "label": "노드 정보 발송 주기"
}, },
"posixTimezone": { "posixTimezone": {
"description": "The POSIX timezone string for the device", "description": "장치의 Posix Timezone String 입력",
"label": "POSIX 시간대" "label": "POSIX 시간대"
}, },
"rebroadcastMode": { "rebroadcastMode": {
"description": "How to handle rebroadcasting", "description": "중계를 처리하는 방법 설정",
"label": "Rebroadcast Mode" "label": "중계 모드"
}, },
"role": { "role": {
"description": "What role the device performs on the mesh", "description": "해당 장치가 메쉬에서 수행하는 역할을 설정",
"label": "역할" "label": "역할"
} }
}, },
"bluetooth": { "bluetooth": {
"title": "Bluetooth Settings", "title": "블루투스 설정",
"description": "Settings for the Bluetooth module", "description": "블루투스 설정",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "참고: 일부 장치(ESP32)는 블루투스와 와이파이를 동시에 사용할 수 없습니다.",
"enabled": { "enabled": {
"description": "Enable or disable Bluetooth", "description": "블루투스를 켜거나 끕니다.",
"label": "Enabled" "label": "활성화"
}, },
"pairingMode": { "pairingMode": {
"description": "Pin selection behaviour.", "description": "핀 선택",
"label": "페어링 모드" "label": "페어링 모드"
}, },
"pin": { "pin": {
"description": "Pin to use when pairing", "description": "페어링에 사용할 핀",
"label": "Pin" "label": ""
} }
}, },
"display": { "display": {
"description": "Settings for the device display", "description": "장치의 디스플레이 설정",
"title": "Display Settings", "title": "디스플레이 설정",
"headingBold": { "headingBold": {
"description": "Bolden the heading text", "description": "상태표시줄 볼드체 적용하기",
"label": "Bold Heading" "label": "상태표시줄 볼드체"
}, },
"carouselDelay": { "carouselDelay": {
"description": "How fast to cycle through windows", "description": "화면 전환 사이클 시간을 입력",
"label": "Carousel Delay" "label": "전환 시간"
}, },
"compassNorthTop": { "compassNorthTop": {
"description": "Fix north to the top of compass", "description": "나침반 상단을 북쪽으로 고정",
"label": "Compass North Top" "label": "나침반 북쪽 고정"
}, },
"displayMode": { "displayMode": {
"description": "Screen layout variant", "description": "스크린 레이아웃 변형",
"label": "Display Mode" "label": "디스플레이 모드"
}, },
"displayUnits": { "displayUnits": {
"description": "Display metric or imperial units", "description": "단위 표시 형식",
"label": "Display Units" "label": "단위 표시"
}, },
"flipScreen": { "flipScreen": {
"description": "Flip display 180 degrees", "description": "화면 180도 뒤집기",
"label": "Flip Screen" "label": "화면 뒤집기"
}, },
"gpsDisplayUnits": { "gpsDisplayUnits": {
"description": "Coordinate display format", "description": "좌표 표시 형식",
"label": "GPS Display Units" "label": "GPS 표시 단위"
}, },
"oledType": { "oledType": {
"description": "Type of OLED screen attached to the device", "description": "장치에 부착된 OLED 화면의 유형",
"label": "OLED Type" "label": "OLED 타입"
}, },
"screenTimeout": { "screenTimeout": {
"description": "Turn off the display after this long", "description": "디스플레이가 꺼지기까지 걸리는 시간",
"label": "Screen Timeout" "label": "화면 끄기 시간"
}, },
"twelveHourClock": { "twelveHourClock": {
"description": "Use 12-hour clock format", "description": "12시간제 보기",
"label": "12-Hour Clock" "label": "12시간제"
}, },
"wakeOnTapOrMotion": { "wakeOnTapOrMotion": {
"description": "Wake the device on tap or motion", "description": "탭하거나 모션으로 깨우기",
"label": "Wake on Tap or Motion" "label": "탭하거나 모션으로 깨우기"
} }
}, },
"lora": { "lora": {
"title": "Mesh Settings", "title": "Mesh 설정",
"description": "Settings for the LoRa mesh", "description": "LoRa mesh 설정",
"bandwidth": { "bandwidth": {
"description": "Channel bandwidth in MHz", "description": "채널 대역폭 MHz",
"label": "대역폭" "label": "대역폭"
}, },
"boostedRxGain": { "boostedRxGain": {
"description": "Boosted RX gain", "description": "수신 부스트 gain",
"label": "Boosted RX Gain" "label": "수신 부스트 Gain"
}, },
"codingRate": { "codingRate": {
"description": "The denominator of the coding rate", "description": "Coding rate의 분모",
"label": "Coding Rate" "label": "Coding rate"
}, },
"frequencyOffset": { "frequencyOffset": {
"description": "Frequency offset to correct for crystal calibration errors", "description": "크리스탈 교정 오차를 보정하기 위한 주파수 오프셋",
"label": "Frequency Offset" "label": "주파수 오프셋"
}, },
"frequencySlot": { "frequencySlot": {
"description": "LoRa frequency channel number", "description": "LoRa 주파수 채널 번호",
"label": "Frequency Slot" "label": "주파수 슬롯"
}, },
"hopLimit": { "hopLimit": {
"description": "Maximum number of hops", "description": "최고 hops 수",
"label": "Hop Limit" "label": "Hop 제한"
}, },
"ignoreMqtt": { "ignoreMqtt": {
"description": "Don't forward MQTT messages over the mesh", "description": "MQTT로 부터 mesh로 메시지를를 전달하지 않습니다",
"label": "MQTT로 부터 수신 무시" "label": "MQTT로 부터 수신 무시"
}, },
"modemPreset": { "modemPreset": {
"description": "Modem preset to use", "description": "모뎀 프리셋 사용",
"label": "모뎀 프리셋" "label": "모뎀 프리셋"
}, },
"okToMqtt": { "okToMqtt": {
"description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", "description": "이 설정을 true로 하면 사용자가 패킷을 MQTT에 업로드하는 것을 허용하고, false 이면 원격 노드들은 패킷을 MQTT로 전달하지 않도록 요청됩니다",
"label": "MQTT로 전송 허용" "label": "MQTT로 전송 허용"
}, },
"overrideDutyCycle": { "overrideDutyCycle": {
@ -162,118 +162,118 @@
"label": "Duty Cycle 무시" "label": "Duty Cycle 무시"
}, },
"overrideFrequency": { "overrideFrequency": {
"description": "Override frequency", "description": "해당 주파수 강제 설정",
"label": "Override Frequency" "label": "주파수 오버라이드"
}, },
"region": { "region": {
"description": "Sets the region for your node", "description": "당신의 노드의 지역을 설정하세요",
"label": "지역" "label": "지역"
}, },
"spreadingFactor": { "spreadingFactor": {
"description": "Indicates the number of chirps per symbol", "description": "Indicates the number of chirps per symbol",
"label": "Spreading Factor" "label": "Spread factor"
}, },
"transmitEnabled": { "transmitEnabled": {
"description": "Enable/Disable transmit (TX) from the LoRa radio", "description": "LoRa 전송(TX)을 활성화/비활성화합니다",
"label": "Transmit Enabled" "label": "전송 활성화"
}, },
"transmitPower": { "transmitPower": {
"description": "Max transmit power", "description": "최대 전송 출력",
"label": "Transmit Power" "label": "전송 출력"
}, },
"usePreset": { "usePreset": {
"description": "Use one of the predefined modem presets", "description": "사전 정의된 모뎀프리셋을 사용하세요",
"label": "Use Preset" "label": "프리셋 사용"
}, },
"meshSettings": { "meshSettings": {
"description": "Settings for the LoRa mesh", "description": "LoRa mesh 설정",
"label": "Mesh Settings" "label": "Mesh 설정"
}, },
"waveformSettings": { "waveformSettings": {
"description": "Settings for the LoRa waveform", "description": "LoRa 파형 설정",
"label": "Waveform Settings" "label": "파형 설정"
}, },
"radioSettings": { "radioSettings": {
"label": "Radio Settings", "label": "무선 설정",
"description": "Settings for the LoRa radio" "description": "LoRa 무선 설정"
} }
}, },
"network": { "network": {
"title": "WiFi Config", "title": "WiFi 설정",
"description": "WiFi radio configuration", "description": "WiFi 설정",
"note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "note": "참고: 일부 장치(ESP32)는 블루투스와 와이파이를 동시에 사용할 수 없습니다.",
"addressMode": { "addressMode": {
"description": "Address assignment selection", "description": "주소 할당 선택",
"label": "Address Mode" "label": "주소 모드"
}, },
"dns": { "dns": {
"description": "DNS Server", "description": "DNS 서버",
"label": "DNS" "label": "DNS"
}, },
"ethernetEnabled": { "ethernetEnabled": {
"description": "Enable or disable the Ethernet port", "description": "이더넷 포트 활성화하거나 비활성화",
"label": "Enabled" "label": "활성화"
}, },
"gateway": { "gateway": {
"description": "Default Gateway", "description": "기본 게이트웨이",
"label": "게이트웨이" "label": "게이트웨이"
}, },
"ip": { "ip": {
"description": "IP Address", "description": "IP 주소",
"label": "IP" "label": "IP"
}, },
"psk": { "psk": {
"description": "Network password", "description": "네트워크 암호",
"label": "PSK" "label": "PSK"
}, },
"ssid": { "ssid": {
"description": "Network name", "description": "네트워크 이름",
"label": "SSID" "label": "SSID"
}, },
"subnet": { "subnet": {
"description": "Subnet Mask", "description": "서브넷 마스크",
"label": "서브넷" "label": "서브넷"
}, },
"wifiEnabled": { "wifiEnabled": {
"description": "Enable or disable the WiFi radio", "description": "WiFi를 활성화하거나 비활성화",
"label": "Enabled" "label": "활성화"
}, },
"meshViaUdp": { "meshViaUdp": {
"label": "Mesh via UDP" "label": "UDP를 통한 Mesh"
}, },
"ntpServer": { "ntpServer": {
"label": "NTP Server" "label": "NTP 서버"
}, },
"rsyslogServer": { "rsyslogServer": {
"label": "Rsyslog Server" "label": "Rsyslog 서버"
}, },
"ethernetConfigSettings": { "ethernetConfigSettings": {
"description": "Ethernet port configuration", "description": "이더넷 포트 설정",
"label": "Ethernet Config" "label": "이더넷 설정"
}, },
"ipConfigSettings": { "ipConfigSettings": {
"description": "IP configuration", "description": "IP 설정",
"label": "IP Config" "label": "IP 설정"
}, },
"ntpConfigSettings": { "ntpConfigSettings": {
"description": "NTP configuration", "description": "NTP 설정",
"label": "NTP Config" "label": "NTP 설정"
}, },
"rsyslogConfigSettings": { "rsyslogConfigSettings": {
"description": "Rsyslog configuration", "description": "Rsyslog 설정",
"label": "Rsyslog Config" "label": "Rsyslog 설정"
}, },
"udpConfigSettings": { "udpConfigSettings": {
"description": "UDP over Mesh configuration", "description": "UDP over Mesh 설정",
"label": "UDP 설정" "label": "UDP 설정"
} }
}, },
"position": { "position": {
"title": "Position Settings", "title": "위치 설정",
"description": "Settings for the position module", "description": "위치 설정",
"broadcastInterval": { "broadcastInterval": {
"description": "How often your position is sent out over the mesh", "description": "메쉬를 통해 당신의 위치 정보가 전송되는 빈도",
"label": "Broadcast Interval" "label": "전송 간격"
}, },
"enablePin": { "enablePin": {
"description": "GPS module enable pin override", "description": "GPS module enable pin override",
@ -357,7 +357,7 @@
}, },
"powerSavingEnabled": { "powerSavingEnabled": {
"description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.",
"label": "저력 모드 설정" "label": "저력 모드 설정"
}, },
"shutdownOnBatteryDelay": { "shutdownOnBatteryDelay": {
"description": "Automatically shutdown node after this long when on battery, 0 for indefinite", "description": "Automatically shutdown node after this long when on battery, 0 for indefinite",
@ -379,7 +379,7 @@
"security": { "security": {
"description": "Settings for the Security configuration", "description": "Settings for the Security configuration",
"title": "Security Settings", "title": "Security Settings",
"button_backupKey": "Backup Key", "button_backupKey": "백업 키",
"adminChannelEnabled": { "adminChannelEnabled": {
"description": "Allow incoming device control over the insecure legacy admin channel", "description": "Allow incoming device control over the insecure legacy admin channel",
"label": "Allow Legacy Admin" "label": "Allow Legacy Admin"

45
packages/web/public/i18n/locales/ko-KR/dialog.json

@ -1,13 +1,19 @@
{ {
"deleteMessages": { "deleteMessages": {
"description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", "description": "이 작업은 모든 메시지 기록을 삭제합니다. 이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?",
"title": "Clear All Messages" "title": "모든 메시지 삭제"
}, },
"deviceName": { "deviceName": {
"description": "The Device will restart once the config is saved.", "description": "The Device will restart once the config is saved.",
"longName": "Long Name", "longName": "긴 이름",
"shortName": "Short Name", "shortName": "짧은 이름",
"title": "Change Device Name" "title": "장치 이름 변경",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "The current LoRa configuration will be overridden.",
@ -21,14 +27,15 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Location: {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordinates: ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Regenerate Pre-Shared Key?",
"description": "Are you sure you want to regenerate the pre-shared key?", "description": "Are you sure you want to regenerate the pre-shared key?",
"regenerate": "Regenerate" "regenerate": "재생성"
}, },
"newDeviceDialog": { "newDeviceDialog": {
"title": "Connect New Device", "title": "Connect New Device",
@ -39,7 +46,7 @@
"tabSerial": "시리얼", "tabSerial": "시리얼",
"useHttps": "Use HTTPS", "useHttps": "Use HTTPS",
"connecting": "Connecting...", "connecting": "Connecting...",
"connect": "Connect", "connect": "연결",
"connectionFailedAlert": { "connectionFailedAlert": {
"title": "Connection Failed", "title": "Connection Failed",
"descriptionPrefix": "Could not connect to the device. ", "descriptionPrefix": "Could not connect to the device. ",
@ -60,19 +67,23 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "No devices paired yet.",
"newDeviceButton": "New device" "newDeviceButton": "New device",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
}, },
"nodeDetails": { "nodeDetails": {
"message": "메시지", "message": "메시지",
"requestPosition": "Request Position", "requestPosition": "위치 요청",
"traceRoute": "Trace Route", "traceRoute": "추적 루트",
"airTxUtilization": "Air TX utilization", "airTxUtilization": "Air TX utilization",
"allRawMetrics": "All Raw Metrics:", "allRawMetrics": "All Raw Metrics:",
"batteryLevel": "Battery level", "batteryLevel": "Battery level",
@ -121,13 +132,13 @@
"title": "Generate QR Code" "title": "Generate QR Code"
}, },
"rebootOta": { "rebootOta": {
"title": "Schedule Reboot", "title": "재부팅 예약",
"description": "Reboot the connected node after a delay into OTA (Over-the-Air) mode.", "description": "Reboot the connected node after a delay into OTA (Over-the-Air) mode.",
"enterDelay": "Enter delay (sec)", "enterDelay": "Enter delay (sec)",
"scheduled": "Reboot has been scheduled" "scheduled": "Reboot has been scheduled"
}, },
"reboot": { "reboot": {
"title": "Schedule Reboot", "title": "재부팅 예약",
"description": "Reboot the connected node after x minutes." "description": "Reboot the connected node after x minutes."
}, },
"refreshKeys": { "refreshKeys": {
@ -144,7 +155,7 @@
"title": "Remove Node?" "title": "Remove Node?"
}, },
"shutdown": { "shutdown": {
"title": "Schedule Shutdown", "title": "종료 예약",
"description": "Turn off the connected node after x minutes." "description": "Turn off the connected node after x minutes."
}, },
"traceRoute": { "traceRoute": {
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Yes, I know what I'm doing",
"title": "확실합니까?", "title": "확실합니까?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

32
packages/web/public/i18n/locales/ko-KR/messages.json

@ -1,39 +1,39 @@
{ {
"page": { "page": {
"title": "Messages: {{chatName}}", "title": "메시지: {{chatName}}",
"placeholder": "Enter Message" "placeholder": "메시지 입력"
}, },
"emptyState": { "emptyState": {
"title": "Select a Chat", "title": "채팅 선택",
"text": "No messages yet." "text": "아직 메시지가 없습니다."
}, },
"selectChatPrompt": { "selectChatPrompt": {
"text": "Select a channel or node to start messaging." "text": "채널 또는 노드를 선택하여 메시지 전송을 시작하세요."
}, },
"sendMessage": { "sendMessage": {
"placeholder": "Enter your message here...", "placeholder": "여기에 메시지를 입력하세요...",
"sendButton": "보내기" "sendButton": "보내기"
}, },
"actionsMenu": { "actionsMenu": {
"addReactionLabel": "Add Reaction", "addReactionLabel": "반응 추가",
"replyLabel": "Reply" "replyLabel": "답장"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": { "delivered": {
"label": "Message delivered", "label": "메시지 전송",
"displayText": "Message delivered" "displayText": "메시지 전송됨"
}, },
"failed": { "failed": {
"label": "Message delivery failed", "label": "메시지 전송 실패",
"displayText": "Delivery failed" "displayText": "전송 실패"
}, },
"unknown": { "unknown": {
"label": "Message status unknown", "label": "메시지 상태 알 수 없음",
"displayText": "Unknown state" "displayText": "알 수 없는 상태"
}, },
"waiting": { "waiting": {
"label": "Sending message", "label": "메시지 전송 중",
"displayText": "Waiting for delivery" "displayText": "전송 대기 중"
} }
} }
} }

30
packages/web/public/i18n/locales/ko-KR/moduleConfig.json

@ -121,7 +121,7 @@
"title": "Detection Sensor Settings", "title": "Detection Sensor Settings",
"description": "Settings for the Detection Sensor module", "description": "Settings for the Detection Sensor module",
"enabled": { "enabled": {
"label": "Enabled", "label": "활성화",
"description": "Enable or disable Detection Sensor Module" "description": "Enable or disable Detection Sensor Module"
}, },
"minimumBroadcastSecs": { "minimumBroadcastSecs": {
@ -221,7 +221,7 @@
"title": "MQTT Settings", "title": "MQTT Settings",
"description": "Settings for the MQTT module", "description": "Settings for the MQTT module",
"enabled": { "enabled": {
"label": "Enabled", "label": "활성화",
"description": "Enable or disable MQTT" "description": "Enable or disable MQTT"
}, },
"address": { "address": {
@ -279,16 +279,16 @@
"metric_m200": "Within 200 m", "metric_m200": "Within 200 m",
"metric_m90": "Within 90 m", "metric_m90": "Within 90 m",
"metric_m50": "Within 50 m", "metric_m50": "Within 50 m",
"imperial_mi15": "Within 15 miles", "imperial_mi15": "15 miles 이내",
"imperial_mi7_3": "Within 7.3 miles", "imperial_mi7_3": "7.3 miles 이내",
"imperial_mi3_6": "Within 3.6 miles", "imperial_mi3_6": "3.6 miles 이내",
"imperial_mi1_8": "Within 1.8 miles", "imperial_mi1_8": "1.8 miles 이내",
"imperial_mi0_9": "Within 0.9 miles", "imperial_mi0_9": "0.9 miles 이내",
"imperial_mi0_5": "Within 0.5 miles", "imperial_mi0_5": "0.5 miles 이내",
"imperial_mi0_2": "Within 0.2 miles", "imperial_mi0_2": "0.2 miles 이내",
"imperial_ft600": "Within 600 feet", "imperial_ft600": "600 feet 이내",
"imperial_ft300": "Within 300 feet", "imperial_ft300": "300 feet 이내",
"imperial_ft150": "Within 150 feet" "imperial_ft150": "150 feet 이내"
} }
} }
} }
@ -297,7 +297,7 @@
"title": "Neighbor Info Settings", "title": "Neighbor Info Settings",
"description": "Settings for the Neighbor Info module", "description": "Settings for the Neighbor Info module",
"enabled": { "enabled": {
"label": "Enabled", "label": "활성화",
"description": "Enable or disable Neighbor Info Module" "description": "Enable or disable Neighbor Info Module"
}, },
"updateInterval": { "updateInterval": {
@ -365,7 +365,7 @@
"description": "The serial baud rate" "description": "The serial baud rate"
}, },
"timeout": { "timeout": {
"label": "시간 초과", "label": "시간 초과",
"description": "Seconds to wait before we consider your packet as 'done'" "description": "Seconds to wait before we consider your packet as 'done'"
}, },
"mode": { "mode": {
@ -406,7 +406,7 @@
"description": "Settings for the Telemetry module", "description": "Settings for the Telemetry module",
"deviceUpdateInterval": { "deviceUpdateInterval": {
"label": "Device Metrics", "label": "Device Metrics",
"description": "기기 메트릭 업데이트 간격 (초)" "description": "장치 메트릭 업데이트 간격 (초)"
}, },
"environmentUpdateInterval": { "environmentUpdateInterval": {
"label": "환경 메트릭 업데이트 간격 (초)", "label": "환경 메트릭 업데이트 간격 (초)",

50
packages/web/public/i18n/locales/ko-KR/nodes.json

@ -1,63 +1,63 @@
{ {
"nodeDetail": { "nodeDetail": {
"publicKeyEnabled": { "publicKeyEnabled": {
"label": "Public Key Enabled" "label": "공개 키 활성화"
}, },
"noPublicKey": { "noPublicKey": {
"label": "No Public Key" "label": "공개 키 없음"
}, },
"directMessage": { "directMessage": {
"label": "Direct Message {{shortName}}" "label": "DM {{shortName}}"
}, },
"favorite": { "favorite": {
"label": "즐겨찾기", "label": "즐겨찾기",
"tooltip": "Add or remove this node from your favorites" "tooltip": "이 노드를 즐겨찾기에 추가하거나 삭제"
}, },
"notFavorite": { "notFavorite": {
"label": "Not a Favorite" "label": "즐겨찾기 아님"
}, },
"error": { "error": {
"label": "오류", "label": "Error",
"text": "An error occurred while fetching node details. Please try again later." "text": "노드 정보를 가져오는 과정에서 오류가 발생했습니다. 나중에 다시 시도해 주세요."
}, },
"status": { "status": {
"heard": "Heard", "heard": "수신",
"mqtt": "MQTT" "mqtt": "MQTT"
}, },
"elevation": { "elevation": {
"label": "Elevation" "label": "고도"
}, },
"channelUtil": { "channelUtil": {
"label": "Channel Util" "label": "채널 사용률"
}, },
"airtimeUtil": { "airtimeUtil": {
"label": "Airtime Util" "label": "통신 사용률"
} }
}, },
"nodesTable": { "nodesTable": {
"headings": { "headings": {
"longName": "Long Name", "longName": "긴 이름",
"connection": "Connection", "connection": "연결",
"lastHeard": "Last Heard", "lastHeard": "최근 수신",
"encryption": "Encryption", "encryption": "암호화",
"model": "Model", "model": "하드웨어",
"macAddress": "MAC Address" "macAddress": "MAC 주소"
}, },
"connectionStatus": { "connectionStatus": {
"direct": "직접 연결", "direct": "직접 연결",
"away": "away", "away": "떨어짐",
"unknown": "-", "unknown": "-",
"viaMqtt": ", via MQTT" "viaMqtt": ", MQTT 경유"
}, },
"lastHeardStatus": { "lastHeardStatus": {
"never": "Never" "never": "수신 된 적 없음"
} }
}, },
"actions": { "actions": {
"added": "Added", "added": "추가됨",
"removed": "Removed", "removed": "삭제됨",
"ignoreNode": "Ignore Node", "ignoreNode": "노드 무시하기",
"unignoreNode": "Unignore Node", "unignoreNode": "노드 무시 해제",
"requestPosition": "Request Position" "requestPosition": "위치 요청"
} }
} }

176
packages/web/public/i18n/locales/ko-KR/ui.json

@ -1,111 +1,111 @@
{ {
"navigation": { "navigation": {
"title": "Navigation", "title": "메뉴",
"messages": "메시지", "messages": "메시지기기",
"map": "지도", "map": "지도",
"config": "Config", "config": "설정",
"radioConfig": "Radio Config", "radioConfig": "무선 설정",
"moduleConfig": "Module Config", "moduleConfig": "모듈 설정",
"channels": "채널", "channels": "채널",
"nodes": "Nodes" "nodes": "노드"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",
"logo": "Meshtastic Logo" "logo": "Meshtastic 로고"
}, },
"sidebar": { "sidebar": {
"collapseToggle": { "collapseToggle": {
"button": { "button": {
"open": "Open sidebar", "open": "사이드바 열기",
"close": "Close sidebar" "close": "사이드바 닫기"
} }
}, },
"deviceInfo": { "deviceInfo": {
"volts": "{{voltage}} volts", "volts": "{{voltage}} V",
"firmware": { "firmware": {
"title": "펌웨어", "title": "펌웨어",
"version": "v{{version}}", "version": "v{{version}}",
"buildDate": "Build date: {{date}}" "buildDate": "빌드 날짜: {{date}}"
}, },
"deviceName": { "deviceName": {
"title": "Device Name", "title": "장치 이름",
"changeName": "Change Device Name", "changeName": "장치 이름 변경",
"placeholder": "Enter device name" "placeholder": "장치 이름 입력"
}, },
"editDeviceName": "Edit device name" "editDeviceName": "장치 이름 수정"
} }
}, },
"batteryStatus": { "batteryStatus": {
"charging": "{{level}}% charging", "charging": "{{level}}% 충전중",
"pluggedIn": "Plugged in", "pluggedIn": "전원 연결됨",
"title": "배터리" "title": "배터리"
}, },
"search": { "search": {
"nodes": "Search nodes...", "nodes": "노드 검색...",
"channels": "Search channels...", "channels": "채널 검색...",
"commandPalette": "Search commands..." "commandPalette": "명령 검색..."
}, },
"toast": { "toast": {
"positionRequestSent": { "positionRequestSent": {
"title": "Position request sent." "title": "위치 요청 보냄."
}, },
"requestingPosition": { "requestingPosition": {
"title": "Requesting position, please wait..." "title": "위치 요청 중, 기다려주세요."
}, },
"sendingTraceroute": { "sendingTraceroute": {
"title": "Sending Traceroute, please wait..." "title": "추적 루트 요청, 기다려주세요."
}, },
"tracerouteSent": { "tracerouteSent": {
"title": "Traceroute sent." "title": "추적 루트 보냄."
}, },
"savedChannel": { "savedChannel": {
"title": "Saved Channel: {{channelName}}" "title": "저장된 채널: {{channelName}}"
}, },
"messages": { "messages": {
"pkiEncryption": { "pkiEncryption": {
"title": "Chat is using PKI encryption." "title": "채팅은 PKI 암호화를 사용하고 있습니다."
}, },
"pskEncryption": { "pskEncryption": {
"title": "Chat is using PSK encryption." "title": "채팅은 PSK 암호화를 사용하고 있습니다."
} }
}, },
"configSaveError": { "configSaveError": {
"title": "Error Saving Config", "title": "설정 저장 오류",
"description": "An error occurred while saving the configuration." "description": "설정을 저장하는 과정에서 오류가 발생했습니다."
}, },
"validationError": { "validationError": {
"title": "Config Errors Exist", "title": "설정 오류",
"description": "Please fix the configuration errors before saving." "description": "저장하기 전에 설정 오류를 수정해 주시기 바랍니다."
}, },
"saveSuccess": { "saveSuccess": {
"title": "Saving Config", "title": "설정 저장됨",
"description": "The configuration change {{case}} has been saved." "description": "설정 변경 사항 {{case}}가 저장되었습니다."
}, },
"favoriteNode": { "favoriteNode": {
"title": "{{action}} {{nodeName}} {{direction}} favorites.", "title": "{{nodeName}}이 즐겨찾기{{direction}} {{action}}",
"action": { "action": {
"added": "Added", "added": "추가됨",
"removed": "Removed", "removed": "삭제됨",
"to": "to", "to": "",
"from": "from" "from": "에서"
} }
}, },
"ignoreNode": { "ignoreNode": {
"title": "{{action}} {{nodeName}} {{direction}} ignore list", "title": "{{nodeName}}이 무시 목록{{direction}} {{action}}",
"action": { "action": {
"added": "Added", "added": "추가됨",
"removed": "Removed", "removed": "삭제됨",
"to": "to", "to": "",
"from": "from" "from": "에서"
} }
} }
}, },
"notifications": { "notifications": {
"copied": { "copied": {
"label": "Copied!" "label": "저장됨!"
}, },
"copyToClipboard": { "copyToClipboard": {
"label": "Copy to clipboard" "label": "클립보드에 복사"
}, },
"hidePassword": { "hidePassword": {
"label": "비밀번호 숨김" "label": "비밀번호 숨김"
@ -114,20 +114,20 @@
"label": "비밀번호 보기" "label": "비밀번호 보기"
}, },
"deliveryStatus": { "deliveryStatus": {
"delivered": "Delivered", "delivered": "전송됨",
"failed": "Delivery Failed", "failed": "전송 실패",
"waiting": "Waiting", "waiting": "대기 중",
"unknown": "Unknown" "unknown": "알 수 없는"
} }
}, },
"general": { "general": {
"label": "General" "label": "일반"
}, },
"hardware": { "hardware": {
"label": "하드웨어" "label": "하드웨어"
}, },
"metrics": { "metrics": {
"label": "Metrics" "label": "메트릭"
}, },
"role": { "role": {
"label": "역할" "label": "역할"
@ -136,93 +136,93 @@
"label": "필터" "label": "필터"
}, },
"advanced": { "advanced": {
"label": "Advanced" "label": "고급"
}, },
"clearInput": { "clearInput": {
"label": "Clear input" "label": "입력 지우기"
}, },
"resetFilters": { "resetFilters": {
"label": "Reset Filters" "label": "필터 초기화"
}, },
"nodeName": { "nodeName": {
"label": "Node name/number", "label": "노드 이름/숫자",
"placeholder": "Meshtastic 1234" "placeholder": "Meshtastic 1234"
}, },
"airtimeUtilization": { "airtimeUtilization": {
"label": "Airtime Utilization (%)" "label": "통신 사용률 (%)"
}, },
"batteryLevel": { "batteryLevel": {
"label": "Battery level (%)", "label": "배터리 잔량 (%)",
"labelText": "Battery level (%): {{value}}" "labelText": "배터리 잔량 (%): {{value}}"
}, },
"batteryVoltage": { "batteryVoltage": {
"label": "Battery voltage (V)", "label": "배터리 전압 (V)",
"title": "전압" "title": "전압"
}, },
"channelUtilization": { "channelUtilization": {
"label": "Channel Utilization (%)" "label": "채널 사용률 (%)"
}, },
"hops": { "hops": {
"direct": "직접 연결", "direct": "직접 연결",
"label": "Number of hops", "label": "Hops 수",
"text": "Number of hops: {{value}}" "text": "Hops 수: {{value}}"
}, },
"lastHeard": { "lastHeard": {
"label": "최근 수신", "label": "최근 수신",
"labelText": "Last heard: {{value}}", "labelText": "최근 수신: {{value}}",
"nowLabel": "Now" "nowLabel": "지금"
}, },
"snr": { "snr": {
"label": "SNR (db)" "label": "SNR (db)"
}, },
"favorites": { "favorites": {
"label": "Favorites" "label": "즐겨찾기"
}, },
"hide": { "hide": {
"label": "Hide" "label": "숨기기"
}, },
"showOnly": { "showOnly": {
"label": "Show Only" "label": "만 보이기"
}, },
"viaMqtt": { "viaMqtt": {
"label": "Connected via MQTT" "label": "MQTT로 연결된"
}, },
"hopsUnknown": { "hopsUnknown": {
"label": "Unknown number of hops" "label": "Hops 알 수 없음"
}, },
"showUnheard": { "showUnheard": {
"label": "Never heard" "label": "수신된 적 없음"
}, },
"language": { "language": {
"label": "언어", "label": "언어",
"changeLanguage": "Change Language" "changeLanguage": "언어 선택"
}, },
"theme": { "theme": {
"dark": "다크", "dark": "다크",
"light": "라이트", "light": "라이트",
"system": "Automatic", "system": "자동",
"changeTheme": "Change Color Scheme" "changeTheme": "컬러 선택"
}, },
"errorPage": { "errorPage": {
"title": "This is a little embarrassing...", "title": "이건 좀 부끄러운 일이에요...",
"description1": "We are really sorry but an error occurred in the web client that caused it to crash. <br /> This is not supposed to happen, and we are working hard to fix it.", "description1": "정말 죄송합니다. 웹 클라이언트에서 오류가 발생하여 강제 종료되었습니다. <br /> 이 문제는 발생하지 않아야 하는 것이며, 현재 이를 해결하기 위해 최선을 다하고 있습니다.",
"description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", "description2": "이 문제가 다시 발생하지 않도록 하는 가장 좋은 방법은 해당 문제를 저희에게 신고해 주시는 것입니다.",
"reportInstructions": "Please include the following information in your report:", "reportInstructions": "보고서에 다음 정보를 포함해 주시기 바랍니다:",
"reportSteps": { "reportSteps": {
"step1": "What you were doing when the error occurred", "step1": "오류가 발생했을 때 무엇을 하고 계셨나요?",
"step2": "What you expected to happen", "step2": "어떤 상황을 예상 하셨나요?",
"step3": "What actually happened", "step3": "실제로 무슨 일이 일어났나요?",
"step4": "Any other relevant information" "step4": "기타 관련 정보"
}, },
"reportLink": "You can report the issue to our <0>GitHub</0>", "reportLink": "이 문제를 저희 <0>GitHub</0>에 보고해주세요",
"dashboardLink": "Return to the <0>dashboard</0>", "dashboardLink": "<0>메인</0>으로 돌아가기",
"detailsSummary": "Error Details", "detailsSummary": "오류 세부 정보",
"errorMessageLabel": "Error message:", "errorMessageLabel": "오류 메시지:",
"stackTraceLabel": "Stack trace:", "stackTraceLabel": "스택 추적:",
"fallbackError": "{{error}}" "fallbackError": "{{error}}"
}, },
"footer": { "footer": {
"text": "Powered by <0>▲ Vercel</0> | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information</1>", "text": "Powered by <0>▲ Vercel</0> | Meshtastic®는 Meshtastic LLC의 등록 상표입니다. | <1>법적 정보</1>",
"commitSha": "Commit SHA: {{sha}}" "commitSha": "Commit SHA: {{sha}}"
} }
} }

97
packages/web/public/i18n/locales/nl-NL/commandPalette.json

@ -1,50 +1,51 @@
{ {
"emptyState": "No results found.", "emptyState": "No results found.",
"page": { "page": {
"title": "Command Menu" "title": "Command Menu"
}, },
"pinGroup": { "pinGroup": {
"label": "Pin command group" "label": "Pin command group"
}, },
"unpinGroup": { "unpinGroup": {
"label": "Unpin command group" "label": "Unpin command group"
}, },
"goto": { "goto": {
"label": "Goto", "label": "Goto",
"command": { "command": {
"messages": "Berichten", "messages": "Berichten",
"map": "Kaart", "map": "Kaart",
"config": "Config", "config": "Config",
"channels": "Kanalen", "channels": "Kanalen",
"nodes": "Nodes" "nodes": "Nodes"
} }
}, },
"manage": { "manage": {
"label": "Manage", "label": "Manage",
"command": { "command": {
"switchNode": "Switch Node", "switchNode": "Switch Node",
"connectNewNode": "Connect New Node" "connectNewNode": "Connect New Node"
} }
}, },
"contextual": { "contextual": {
"label": "Contextual", "label": "Contextual",
"command": { "command": {
"qrCode": "QR Code", "qrCode": "QR Code",
"qrGenerator": "Generator", "qrGenerator": "Generator",
"qrImport": "Importeer", "qrImport": "Importeer",
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Schedule Shutdown",
"scheduleReboot": "Schedule Reboot", "scheduleReboot": "Schedule Reboot",
"rebootToOtaMode": "Reboot To OTA Mode", "rebootToOtaMode": "Reboot To OTA Mode",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Reset Node DB",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Factory Reset Device",
"factoryResetConfig": "Factory Reset Config" "factoryResetConfig": "Factory Reset Config",
} "disconnect": "Verbinding verbreken"
}, }
"debug": { },
"label": "Debug", "debug": {
"command": { "label": "Debug",
"reconfigure": "Reconfigure", "command": {
"clearAllStoredMessages": "Clear All Stored Message" "reconfigure": "Reconfigure",
} "clearAllStoredMessages": "Clear All Stored Message"
} }
}
} }

23
packages/web/public/i18n/locales/nl-NL/dialog.json

@ -7,7 +7,13 @@
"description": "The Device will restart once the config is saved.", "description": "The Device will restart once the config is saved.",
"longName": "Long Name", "longName": "Long Name",
"shortName": "Short Name", "shortName": "Short Name",
"title": "Change Device Name" "title": "Change Device Name",
"validation": {
"longNameMax": "Long name must not be more than 40 characters",
"shortNameMax": "Short name must not be more than 4 characters",
"longNameMin": "Long name must have at least 1 character",
"shortNameMin": "Short name must have at least 1 character"
}
}, },
"import": { "import": {
"description": "The current LoRa configuration will be overridden.", "description": "The current LoRa configuration will be overridden.",
@ -21,9 +27,10 @@
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
"title": "Location: {{identifier}}",
"altitude": "Altitude: ", "altitude": "Altitude: ",
"coordinates": "Coordinates: ", "coordinates": "Coordinates: ",
"title": "Location: {{identifier}}" "noCoordinates": "No Coordinates"
}, },
"pkiRegenerateDialog": { "pkiRegenerateDialog": {
"title": "Regenerate Pre-Shared Key?", "title": "Regenerate Pre-Shared Key?",
@ -60,11 +67,15 @@
}, },
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "No devices paired yet.", "noDevicesPaired": "No devices paired yet.",
"newDeviceButton": "New device" "newDeviceButton": "New device",
"connectionFailed": "Connection failed",
"deviceDisconnected": "Device disconnected",
"unknownDevice": "Unknown Device",
"errorLoadingDevices": "Error loading devices",
"unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.", "requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.",
"requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
@ -166,6 +177,6 @@
"managedMode": { "managedMode": {
"confirmUnderstanding": "Yes, I know what I'm doing", "confirmUnderstanding": "Yes, I know what I'm doing",
"title": "Weet u het zeker?", "title": "Weet u het zeker?",
"description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can <bold>only</bold> be changed through Remote Admin messages. This setting is not required for remote node administration." "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration."
} }
} }

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

Loading…
Cancel
Save