mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-06-15 07:04:26 +10:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| becfbedc99 | |||
| 7da4e68384 | |||
| 5ea6b17b16 | |||
| 3707acb124 | |||
| 51d6210920 | |||
| 6a31d304d3 | |||
| 26fdf74d69 | |||
| b1de1b4bf0 | |||
| 3c26ce2d93 | |||
| cba1e5950c | |||
| 743ef7f124 | |||
| 13d3a107da | |||
| dfdcafb071 | |||
| 33b3b04294 | |||
| 6a7dd981a2 | |||
| d68f755677 | |||
| 264d2bcc9a | |||
| 8dd385beed | |||
| 2328848400 | |||
| 0287de1862 | |||
| 4dd472e3c3 | |||
| ed0e6b6554 | |||
| 6d258154a0 | |||
| bac82dc9e8 | |||
| 8682e6ea67 | |||
| 30a1a36ee4 | |||
| 3fe5cdf55d | |||
| 9ada4ea601 | |||
| 7a823654df | |||
| 425229fce8 | |||
| c4b3971bdd | |||
| a50c0d0b2d | |||
| 72448f67d0 | |||
| bc5f299350 | |||
| 6d97ad6855 | |||
| 1fbe1823cb | |||
| f941f0dbfa | |||
| 352a6c427e | |||
| 5f9259e41f | |||
| 75ae903b99 | |||
| 8892823337 | |||
| e738664f89 | |||
| e37616fa15 | |||
| 2763d83fe4 | |||
| 77018dc358 | |||
| 1f6b2dacf9 | |||
| 21c58d4e13 | |||
| 3af97ff6dd | |||
| 703d5a1ec4 | |||
| d2a6fbe182 | |||
| e801a497f8 | |||
| e92a66ff28 | |||
| 6900e5c3db | |||
| 966a8d0d2c | |||
| 3ec3b05fb8 | |||
| 14a93e9bf5 | |||
| c229b0369e | |||
| 9f332e93be | |||
| b472ea8c70 | |||
| a67c6d81c3 | |||
| 91ae4dab90 | |||
| 08ac60a408 | |||
| d4da34fcf7 | |||
| 74840d3baf | |||
| 4a72fbd1ad | |||
| dbe0a5411b | |||
| dc3325ec46 | |||
| a92e57bb64 | |||
| e21f3106d0 | |||
| 0dcb5f05f0 | |||
| f501d11ec6 | |||
| dfcf13a97b | |||
| ccd23c4b81 | |||
| 00636c9084 | |||
| accec1681b | |||
| 67238468ce | |||
| bc5b12f1ef | |||
| c09af98bef | |||
| ae32e76563 | |||
| 5572c9ee75 | |||
| f6cc000788 | |||
| 75b0d198bc | |||
| 1947cd9f3e | |||
| f1d93bd5e8 | |||
| f63d50f0da | |||
| eb597b6c68 | |||
| efe21c4e87 | |||
| 38fece3313 | |||
| 3af3cce606 | |||
| 026ec6f7de | |||
| eb50249b93 | |||
| ca6058eccd | |||
| 99c0ab7e22 | |||
| 2950a9a687 | |||
| 1b3de54873 | |||
| 20a9ef3c2b | |||
| a741e12ad1 | |||
| e54f30d6fb | |||
| e1d23ad2c7 | |||
| f07993b367 | |||
| 0e5f1a45c4 | |||
| f10aeaeba8 | |||
| 00e4f52d75 | |||
| 3ea2e4763e | |||
| 94d9afe8b1 | |||
| 7db3a12723 | |||
| fcf10b4a73 | |||
| 7f353490cf | |||
| 46683e0ec2 | |||
| 4e368d562d | |||
| 38f6e42796 | |||
| f56c28a27d | |||
| 92d3009eb4 | |||
| 7a4ac9ae9b | |||
| f8d00caae0 | |||
| e03d80b71f | |||
| b7d0db8d1c | |||
| 6ae3f612ae | |||
| 40d3941aab | |||
| 5e446207c6 | |||
| 609d0c8dbc | |||
| 820bac0db0 | |||
| d3c7d8e43a | |||
| 0c1e163b88 | |||
| d0d6a34fb5 | |||
| 16ce1359d7 | |||
| 9fe4a3710d | |||
| 8611adab1f | |||
| 7d457cb863 | |||
| 297516fc80 | |||
| 5cfe45b953 | |||
| 1c9c089a53 | |||
| cb3b5a84eb | |||
| 1b94442ab6 | |||
| 3ae14781f0 | |||
| ecc496f2af | |||
| 87b25655d0 | |||
| c47a4cb622 | |||
| a30fc439f3 | |||
| afcc4db405 | |||
| 87bcb6a6a3 | |||
| 68bb031bb6 | |||
| c4f5c7b171 | |||
| 2bce14224d | |||
| fd305fd55b | |||
| d0dd805244 | |||
| 8668564464 |
@@ -87,6 +87,10 @@ keystore.properties
|
||||
# IDE
|
||||
.vscode/launch.json
|
||||
.vscode/settings.json
|
||||
.contextstream/
|
||||
|
||||
# Cloudflare Wrangler
|
||||
.wrangler
|
||||
|
||||
# Claude Code local working dir (worktrees, jobs, settings)
|
||||
.claude/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# MeshCore Open - Flutter Client
|
||||
|
||||
Open-source Flutter client for MeshCore LoRa mesh networking devices.
|
||||
Open-source Flutter client for MeshCore LoRa mesh networking devices. Connects to MeshCore-compatible radios over **BLE, TCP, or USB serial** and provides direct/channel chat, contact and channel management, on-map node tracking, repeater administration, and on-device message translation.
|
||||
|
||||
## Build Commands
|
||||
|
||||
@@ -17,6 +17,9 @@ Open-source Flutter client for MeshCore LoRa mesh networking devices.
|
||||
# Build iOS
|
||||
~/flutter/bin/flutter build ios
|
||||
|
||||
# Build versioned web release (uses build_pipe)
|
||||
~/flutter/bin/dart run build_pipe
|
||||
|
||||
# Run static analysis
|
||||
~/flutter/bin/flutter analyze
|
||||
|
||||
@@ -28,43 +31,132 @@ Open-source Flutter client for MeshCore LoRa mesh networking devices.
|
||||
|
||||
```
|
||||
lib/
|
||||
├── main.dart # App entry point, MaterialApp setup with Provider
|
||||
├── connector/
|
||||
│ └── meshcore_connector.dart # BLE communication layer (MeshCoreConnector)
|
||||
├── screens/
|
||||
│ ├── scanner_screen.dart # BLE device scanning (home screen)
|
||||
│ ├── device_screen.dart # Connected device hub with navigation
|
||||
│ ├── chat_screen.dart # Chat interface (placeholder)
|
||||
│ ├── contacts_screen.dart # Contacts list (placeholder)
|
||||
│ └── settings_screen.dart # Device info and app settings
|
||||
└── widgets/
|
||||
└── device_tile.dart # Device list item with signal strength
|
||||
├── main.dart # Entry point: MultiProvider wiring, locale + theme, initial route
|
||||
├── connector/ # Unified BLE/TCP/USB transport layer
|
||||
│ ├── meshcore_connector.dart # Central state holder + ChangeNotifier (all transports)
|
||||
│ ├── meshcore_connector_tcp.dart # TCP transport helper
|
||||
│ ├── meshcore_connector_usb.dart # USB serial transport helper
|
||||
│ ├── meshcore_protocol.dart # Frame size + version constants
|
||||
│ └── meshcore_uuids.dart # Nordic UART UUIDs + scan name prefixes
|
||||
├── models/ # Plain data classes (Contact, Channel, Message, Community, …)
|
||||
├── services/ # ChangeNotifier services + IO services (retry, translation, ML, …)
|
||||
├── storage/ # SharedPreferences-backed stores, scoped per device key
|
||||
├── helpers/ # Pure utilities (Smaz compression, GIF parsing, scroll helpers)
|
||||
├── utils/ # Platform / IO / UX utilities (logger, GPX export, dialogs)
|
||||
├── theme/ # MeshPalette (defined, not yet wired in main.dart)
|
||||
├── l10n/ # ARB localization for 18 locales
|
||||
├── icons/ # Custom icon widgets
|
||||
├── widgets/ # Reusable widgets (AppBar, BatteryUi, QR, jump-to-bottom, …)
|
||||
└── screens/ # ~26 screens — see Screens section below
|
||||
```
|
||||
|
||||
## Screens
|
||||
|
||||
All screens are fully implemented (no remaining placeholders).
|
||||
|
||||
### Connection / Scanning
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `scanner_screen.dart` | BLE device scan and connect — main entry point |
|
||||
| `tcp_screen.dart` | Connect to a MeshCore device over TCP/IP |
|
||||
| `usb_screen.dart` | Connect to a MeshCore device over USB serial |
|
||||
| `discovery_screen.dart` | Browse all discovered (non-contact) mesh nodes |
|
||||
| `chrome_required_screen.dart` | Web gate for non-Chrome browsers (BLE unavailable) |
|
||||
|
||||
### Chat / Messaging
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `chat_screen.dart` | Direct (private) messaging with a contact |
|
||||
| `channel_chat_screen.dart` | Group messaging inside a named channel |
|
||||
| `channels_screen.dart` | List and manage channels (add/edit/delete) |
|
||||
| `channel_message_path_screen.dart` | Hop-by-hop route a channel message took, with map overlay |
|
||||
|
||||
### Contacts / Neighbors
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `contacts_screen.dart` | Full contacts list with previews and management |
|
||||
| `neighbors_screen.dart` | Nodes directly heard by the connected radio (one-hop) |
|
||||
|
||||
### Repeater Management
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `repeater_hub_screen.dart` | Top-level repeater hub; navigates to sub-screens |
|
||||
| `repeater_status_screen.dart` | Live status of a managed repeater node |
|
||||
| `repeater_cli_screen.dart` | Raw command-line interface to a repeater |
|
||||
| `repeater_settings_screen.dart` | Full radio/node settings editor for a repeater |
|
||||
|
||||
### Map / Location
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `map_screen.dart` | Main map view of contacts/nodes with live GPS positions |
|
||||
| `line_of_sight_map_screen.dart` | Terrain LOS analysis between configurable endpoints |
|
||||
| `path_trace_map.dart` | Animates the hop path a direct message traveled |
|
||||
| `map_cache_screen.dart` | Download/clear offline map tile cache |
|
||||
| `community_qr_scanner_screen.dart` | Scan QR to join a mesh community/channel |
|
||||
|
||||
### Settings / Debug / Diagnostics
|
||||
| Screen | Purpose |
|
||||
|---|---|
|
||||
| `settings_screen.dart` | Connected device settings: radio params, identity, GPS |
|
||||
| `app_settings_screen.dart` | App preferences: theme, units, map source, notifications |
|
||||
| `app_debug_log_screen.dart` | In-app log viewer (app-layer messages) |
|
||||
| `ble_debug_log_screen.dart` | In-app log viewer (raw BLE frame traffic) |
|
||||
| `companion_radio_stats_screen.dart` | RF stats (RSSI, SNR, packet counts) for paired radio |
|
||||
| `telemetry_screen.dart` | Battery / sensor / environmental telemetry for a contact |
|
||||
|
||||
## Architecture
|
||||
|
||||
### State Management
|
||||
- **Provider** with `ChangeNotifier` pattern
|
||||
- `MeshCoreConnector` is the central state holder for BLE connection
|
||||
- Screens use `Consumer<MeshCoreConnector>` for reactive UI updates
|
||||
|
||||
`Provider` with `ChangeNotifier`. `main.dart` wires a `MultiProvider` with the following:
|
||||
|
||||
| Provider | Role |
|
||||
|---|---|
|
||||
| `MeshCoreConnector` | Active transport (BLE/TCP/USB), connection state, frame I/O |
|
||||
| `MessageRetryService` | ACK tracking and retry scheduling with backoff |
|
||||
| `PathHistoryService` | Per-contact routing history (LRU cache, 50 contacts) |
|
||||
| `AppSettingsService` | App preferences (theme, units, locale, notifications) |
|
||||
| `BleDebugLogService` | Raw BLE frame log buffer |
|
||||
| `AppDebugLogService` | Structured app log buffer |
|
||||
| `ChatTextScaleService` | Pinch-to-zoom text scale for chat screens |
|
||||
| `TranslationService` | On-device LLM translation (llamadart) |
|
||||
| `UiViewStateService` | Contacts/channels sort/filter/search state |
|
||||
| `TimeoutPredictionService` | ML linear regression for ACK timeout prediction |
|
||||
| `StorageService` | Path history + delivery observation persistence |
|
||||
| `MapTileCacheService` | OSM tile pre-cache |
|
||||
|
||||
Screens consume these via `Consumer<T>` (or `context.watch<T>()` / `context.read<T>()`) for reactive UI.
|
||||
|
||||
### Storage / Persistence
|
||||
|
||||
All stores in `lib/storage/` use `PrefsManager` (a `SharedPreferences` singleton initialized in `main()`). Most stores **scope keys by the first 10 hex chars of the connected device's public key**, so per-radio data is isolated.
|
||||
|
||||
| Store | Persists |
|
||||
|---|---|
|
||||
| `message_store`, `channel_message_store` | Direct + channel messages |
|
||||
| `contact_store`, `contact_discovery_store` | Known + discovered contacts |
|
||||
| `channel_store`, `channel_order_store`, `channel_settings_store` | Channels, display order, per-channel Smaz toggle |
|
||||
| `community_store` | Communities (32-byte shared secrets) |
|
||||
| `contact_group_store`, `contact_settings_store` | Groups, per-contact Smaz toggle |
|
||||
| `unread_store` | Per-contact unread counts (debounced writes) |
|
||||
|
||||
GGUF translation models are stored as files (not SharedPreferences) via `translation_file_store`.
|
||||
|
||||
### Theming
|
||||
- Material 3 design (`useMaterial3: true`)
|
||||
- System-based dark/light mode (`ThemeMode.system`)
|
||||
- Blue color scheme seed
|
||||
- `lib/theme/mesh_theme.dart` defines a warm-dark `MeshPalette` (phosphor-green accents) but is **not currently wired** in `main.dart` — available for a future redesign
|
||||
|
||||
## BLE Protocol
|
||||
### Localization
|
||||
|
||||
### Nordic UART Service (NUS)
|
||||
- **Service UUID**: `6e400001-b5a3-f393-e0a9-e50e24dcca9e`
|
||||
- **RX Characteristic**: `6e400002-b5a3-f393-e0a9-e50e24dcca9e` (Write to device)
|
||||
- **TX Characteristic**: `6e400003-b5a3-f393-e0a9-e50e24dcca9e` (Notify from device)
|
||||
18 locales supported via Flutter's standard ARB pipeline (`lib/l10n/`): en, de, es, fr, it, pt, ru, uk, bg, hu, ja, ko, nl, pl, sk, sl, sv, zh. Language override comes from `AppSettingsService.settings.languageOverride`. Use the `context.l10n` extension (`lib/l10n/l10n.dart`) for translated strings; contact-type names live in `contact_localization.dart`.
|
||||
|
||||
### Device Discovery
|
||||
- Scans for devices with known name prefixes
|
||||
- Filters by `platformName` or `advertisementData.advName`
|
||||
## Transports
|
||||
|
||||
### Connection States
|
||||
`MeshCoreConnector` unifies all three transports under one `ChangeNotifier`. There is **no shared base class** — selection is via the `MeshCoreTransportType { bluetooth, usb, tcp }` enum, and BLE/TCP/USB share the same connection-state enum, send/receive API, and frame protocol.
|
||||
|
||||
### Connection State
|
||||
```dart
|
||||
enum MeshCoreConnectionState {
|
||||
disconnected,
|
||||
@@ -75,28 +167,136 @@ enum MeshCoreConnectionState {
|
||||
}
|
||||
```
|
||||
|
||||
### Frame I/O
|
||||
- **Send**: `MeshCoreConnector.sendFrame(Uint8List data)`
|
||||
- **Receive**: `MeshCoreConnector.receivedFrames` stream of `Uint8List`
|
||||
### Frame I/O (all transports)
|
||||
- **Send**: `MeshCoreConnector.sendFrame(Uint8List data, {String? channelSendQueueId, bool expectsGenericAck})`
|
||||
- **Receive**: `Stream<Uint8List> get receivedFrames`
|
||||
- **Protocol constants** (`meshcore_protocol.dart`): `maxFrameSize = 172`, `maxTextPayloadBytes = 160`, `appProtocolVersion = 4`
|
||||
|
||||
### BLE — Nordic UART Service (NUS)
|
||||
- **Service UUID**: `6e400001-b5a3-f393-e0a9-e50e24dcca9e`
|
||||
- **RX Characteristic** (write to device): `6e400002-b5a3-f393-e0a9-e50e24dcca9e`
|
||||
- **TX Characteristic** (notify from device): `6e400003-b5a3-f393-e0a9-e50e24dcca9e`
|
||||
- **Discovery**: scans for devices whose name starts with `MeshCore-`, `Whisper-`, `WisCore-`, `Seeed`, `Lilygo`, `HT-`, or `LowMesh_MC_` (filters on both `platformName` and `advertisementData.advName`)
|
||||
- **Linux**: `linux_ble_pairing_service.dart` falls back to `bluetoothctl` when BlueZ agent prompts fail
|
||||
|
||||
### TCP
|
||||
- Manual host/port entry, persisted via `AppSettingsService` (`tcpServerAddress`, `tcpServerPort`)
|
||||
- UI hint: `192.168.40.10` / port `5000`
|
||||
- Disabled on web (`PlatformInfo.isWeb`)
|
||||
- API: `MeshCoreConnector.connectTcp(host: ..., port: ...)`
|
||||
|
||||
### USB Serial (flserial)
|
||||
- Default baud rate: `115200`
|
||||
- Port enumeration: `MeshCoreConnector.listUsbPorts()`
|
||||
- COBS-framed packets via `usb_serial_frame_codec.dart`
|
||||
- macOS device-name resolution via `ioreg` (`utils/macos_usb_device_names.dart`)
|
||||
- API: `MeshCoreConnector.connectUsb(portName: ..., baudRate: 115200)`
|
||||
|
||||
## Dependencies
|
||||
|
||||
App version: `8.0.0+11` — Dart SDK constraint: `^3.9.2`
|
||||
|
||||
**Connectivity**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| flutter_blue_plus | ^2.1.0 | BLE communication |
|
||||
| provider | ^6.1.5+1 | State management |
|
||||
| cupertino_icons | ^1.0.8 | iOS-style icons |
|
||||
| flutter_blue_plus | ^2.1.0 | BLE scanning, connecting, and UART data transfer |
|
||||
| flutter_blue_plus_platform_interface | ^8.2.1 | Platform-interface layer required by flutter_blue_plus |
|
||||
| flserial | git (MeshEnvy fork) | USB serial transport for wired device connections (TODO: upstream pending) |
|
||||
|
||||
**State / Storage**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| provider | ^6.1.5+1 | ChangeNotifier-based state management across screens |
|
||||
| shared_preferences | ^2.2.2 | Persistent key-value storage for user settings |
|
||||
| path_provider | ^2.1.5 | Locates platform-appropriate directories for file I/O |
|
||||
|
||||
**Crypto**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| crypto | ^3.0.3 | SHA/HMAC hashing used in message authentication |
|
||||
| pointycastle | ^4.0.0 | AES encryption/decryption for channel and direct messages |
|
||||
| uuid | ^4.3.3 | Generates UUIDs for message and contact identity |
|
||||
|
||||
**Maps & Location**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| flutter_map | ^8.2.2 | Interactive tile map for node positions and path traces |
|
||||
| latlong2 | ^0.9.1 | LatLng coordinate type used throughout map and GPS code |
|
||||
| gpx | ^2.3.0 | Export node paths as GPX track files |
|
||||
|
||||
**UI**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| material_symbols_icons | ^4.2906.0 | Extended Material Symbols icon set (line-of-sight, etc.) |
|
||||
| flutter_svg | ^2.0.10+1 | Renders SVG assets (custom icons such as LoS indicator) |
|
||||
| cached_network_image | ^3.4.1 | Caches map tile images downloaded over the network |
|
||||
| flutter_cache_manager | ^3.4.1 | Underlying cache manager used by cached_network_image |
|
||||
| flutter_linkify | ^6.0.0 | Auto-detects and makes URLs tappable in chat messages |
|
||||
| mobile_scanner | ^7.1.4 | QR/barcode scanning for contact and channel import |
|
||||
| qr_flutter | ^4.1.0 | Generates QR codes for sharing contacts and channels |
|
||||
| cupertino_icons | ^1.0.8 | iOS-style icon font (bundled for completeness) |
|
||||
| characters | ^1.4.0 | Unicode-aware string operations for message text handling |
|
||||
|
||||
**Notifications / Background**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| flutter_local_notifications | ^20.1.0 | Shows local push notifications for incoming messages |
|
||||
| flutter_foreground_task | ^9.2.0 | Keeps the app alive in background to maintain BLE/USB connection |
|
||||
|
||||
**ML / AI**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| ml_algo | ^16.0.0 | OLS regression used in `timeout_prediction_service.dart` to predict message ACK timeouts |
|
||||
| ml_dataframe | ^1.0.0 | DataFrame input format required by ml_algo |
|
||||
| llamadart | >=0.6.8 <0.7.0 | On-device LLM inference used in `translation_service.dart` for message translation |
|
||||
|
||||
**Misc**
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| http | ^1.2.0 | Fetches tile URLs and any remote API calls |
|
||||
| url_launcher | ^6.3.0 | Opens URLs in the system browser from linkified chat text |
|
||||
| share_plus | ^12.0.1 | Shares files (e.g. exported GPX tracks) via the system share sheet |
|
||||
| package_info_plus | ^9.0.0 | Reads app version/build number displayed in settings |
|
||||
| web | ^1.1.1 | Web-platform APIs for USB serial and browser detection on Flutter Web |
|
||||
| intl | any | Internationalization and locale formatting (required by flutter_localizations) |
|
||||
| build_pipe | ^0.3.1 | CI/CD build pipeline configuration (web release builds with versioned assets) |
|
||||
|
||||
## Platform Configuration
|
||||
|
||||
### Android (`android/app/src/main/AndroidManifest.xml`)
|
||||
- `BLUETOOTH`, `BLUETOOTH_ADMIN` (API 30 and below)
|
||||
- `BLUETOOTH_SCAN`, `BLUETOOTH_CONNECT`, `BLUETOOTH_ADVERTISE` (API 31+)
|
||||
- `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION` (for BLE scanning)
|
||||
- `INTERNET` (map tiles, translation model downloads)
|
||||
- `BLUETOOTH`, `BLUETOOTH_ADMIN` (API ≤ 30)
|
||||
- `BLUETOOTH_SCAN` (with `neverForLocation`), `BLUETOOTH_CONNECT`, `BLUETOOTH_ADVERTISE` (API 31+)
|
||||
- `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION` (BLE scanning on API ≤ 30)
|
||||
- `POST_NOTIFICATIONS` (API 33+)
|
||||
- `FOREGROUND_SERVICE`, `FOREGROUND_SERVICE_CONNECTED_DEVICE` (background BLE/USB connection)
|
||||
- `WAKE_LOCK`
|
||||
- `CAMERA` (QR scanning, declared as optional feature)
|
||||
- USB host hardware feature (optional)
|
||||
|
||||
`flutter_foreground_task` registers a `ForegroundService` with `foregroundServiceType="connectedDevice"` and `stopWithTask="false"`.
|
||||
|
||||
**Build config (`android/app/build.gradle.kts`)**: `applicationId = com.meshcore.meshcore_open`, NDK `29.0.14206865`, Java 8 core-library desugaring (`desugar_jdk_libs:2.1.4`), release signing via `key.properties` (debug fallback).
|
||||
|
||||
### iOS (`ios/Runner/Info.plist`)
|
||||
- `NSBluetoothAlwaysUsageDescription`
|
||||
- `NSBluetoothPeripheralUsageDescription`
|
||||
- `NSBluetoothAlwaysUsageDescription`, `NSBluetoothPeripheralUsageDescription`
|
||||
- `NSCameraUsageDescription` (QR scanning to join communities)
|
||||
- Background modes: `bluetooth-central`
|
||||
- `LSApplicationQueriesSchemes`: `http`, `https`
|
||||
|
||||
### Web (`web/`)
|
||||
PWA scaffold present but boilerplate (`manifest.json` and `index.html` are unmodified Flutter defaults). BLE is unsupported in browsers; TCP and Web Serial USB may work in Chrome only. `ChromeRequiredScreen` gates non-Chrome web users. Versioned releases are produced via `build_pipe` (`?v=<pubspec version>` cache busting, no service worker).
|
||||
|
||||
### Desktop
|
||||
`linux/`, `windows/`, and `macos/` directories are present as Flutter scaffolds. No app-specific native config has been added; BLE on desktop has not been validated.
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
@@ -123,14 +323,14 @@ enum MeshCoreConnectionState {
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `lib/connector/meshcore_connector.dart` | All BLE logic - scanning, connecting, data transfer |
|
||||
| `lib/screens/scanner_screen.dart` | Entry point UI, device list |
|
||||
| `lib/main.dart` | App configuration, theme, Provider setup |
|
||||
| `pubspec.yaml` | Dependencies and project metadata |
|
||||
|
||||
## Placeholder Screens
|
||||
|
||||
The following screens are implemented as placeholders and need full implementation:
|
||||
- `chat_screen.dart` - Mesh chat functionality
|
||||
- `contacts_screen.dart` - Contact management
|
||||
- `settings_screen.dart` - Radio settings, node identity, location (partially implemented)
|
||||
| `lib/main.dart` | App configuration, MultiProvider setup, theme, locale, initial route |
|
||||
| `lib/connector/meshcore_connector.dart` | Unified BLE/TCP/USB transport state holder |
|
||||
| `lib/connector/meshcore_protocol.dart` | Frame size limits and protocol version |
|
||||
| `lib/connector/meshcore_uuids.dart` | NUS UUIDs and BLE scan name prefixes |
|
||||
| `lib/services/app_settings_service.dart` | App-wide settings (`AppSettings` JSON in SharedPreferences) |
|
||||
| `lib/services/storage_service.dart` | Path history + delivery observation persistence |
|
||||
| `lib/services/message_retry_service.dart` | ACK tracking + retry scheduling |
|
||||
| `lib/services/translation_service.dart` | On-device LLM translation (llamadart) |
|
||||
| `lib/storage/prefs_manager.dart` | SharedPreferences singleton initialized in `main()` |
|
||||
| `lib/screens/scanner_screen.dart` | Home screen — BLE scan and connect |
|
||||
| `pubspec.yaml` | Dependencies and project metadata (current version `8.0.0+11`) |
|
||||
|
||||
@@ -6,6 +6,8 @@ Open-source Flutter client for MeshCore LoRa mesh networking devices.
|
||||
|
||||
MeshCore Open is a cross-platform mobile application for communicating with MeshCore LoRa mesh network devices via Bluetooth Low Energy (BLE). The app enables long-range, off-grid communication through peer-to-peer messaging, public channels, and mesh networking capabilities.
|
||||
|
||||
**Website:** [meshcoreopen.org](https://meshcoreopen.org/)
|
||||
|
||||
<a href="http://apps.obtainium.imranr.dev/redirect.html?r=obtainium://add/https://github.com/zjs81/meshcore-open">
|
||||
<img src="assets/badges/badge_obtainium.png" height="80" align="center" alt="Get it on Obtainium"/>
|
||||
</a>
|
||||
@@ -191,6 +193,7 @@ Devices are discovered by scanning for BLE advertisements with known MeshCore de
|
||||
- `WisCore-`
|
||||
- `HT-`
|
||||
- `LowMesh_MC_`
|
||||
- `NRF52`
|
||||
|
||||
New device prefixes can be added in `lib/connector/meshcore_uuids.dart`.
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ A bottom sheet with a search field and a grid of GIF thumbnails.
|
||||
### How to Access
|
||||
App Settings → Appearance → Language
|
||||
|
||||
### Supported Languages (15)
|
||||
English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian
|
||||
### Supported Languages (18)
|
||||
English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian, Hungarian, Japanese, Korean
|
||||
|
||||
### How It Works
|
||||
- All UI strings go through Flutter's ARB localization system
|
||||
@@ -185,3 +185,77 @@ An ML-based service that predicts expected delivery timeouts:
|
||||
- Blends per-contact statistics with ML predictions
|
||||
- Falls back to `3000 + 3000 × pathLength` ms when insufficient data
|
||||
- Observations are persisted to storage via a 2-second debounced timer (observations within 2s of app termination may be lost)
|
||||
|
||||
---
|
||||
|
||||
## On-Device Message Translation
|
||||
|
||||
### What It Is
|
||||
An optional on-device translation service powered by an embedded LLM (llamadart, running GGUF models). Translation runs entirely on-device — no data leaves the app.
|
||||
|
||||
### How to Access
|
||||
Tap the translate button on any received message. On first use, the GGUF model file is downloaded and cached locally.
|
||||
|
||||
### How It Works
|
||||
- Model files are managed by `TranslationFileStore`; download progress is shown in-place
|
||||
- Translation runs via `TranslationService` using the llamadart CPU backend (arm64 and x64 on Android)
|
||||
- Translated text is shown in `TranslatedMessageContent` as an inline overlay on the original message bubble
|
||||
- Each translation is cached; re-tapping shows the cached result without re-running inference
|
||||
|
||||
---
|
||||
|
||||
## Emoji Reactions
|
||||
|
||||
### How to Access
|
||||
Long-press a message bubble in any direct or channel chat, then select a reaction emoji.
|
||||
|
||||
### What the User Sees
|
||||
An emoji picker inline with common reactions. Selected reactions appear below the message bubble with a count.
|
||||
|
||||
### How It Works
|
||||
- Implemented via `emoji_picker.dart` and `reaction_helper.dart`
|
||||
- Reactions are transmitted as a special message type visible to all participants with MeshCore Open
|
||||
|
||||
---
|
||||
|
||||
## Linkification
|
||||
|
||||
### What It Does
|
||||
URLs and `meshcore://` URIs in received messages are automatically detected and rendered as tappable links.
|
||||
|
||||
### How It Works
|
||||
- Powered by the `flutter_linkify` package via `link_handler.dart`
|
||||
- Tapping a URL opens the system browser; tapping a `meshcore://` URI imports the contact
|
||||
|
||||
---
|
||||
|
||||
## GPX Export
|
||||
|
||||
### How to Access
|
||||
Settings → Export section (three options: Export Repeaters, Export Contacts, Export All).
|
||||
|
||||
### What It Does
|
||||
Exports contacts with GPS coordinates to a `.gpx` file via the OS share sheet. Not available on web.
|
||||
|
||||
---
|
||||
|
||||
## Pinch-to-Zoom Chat Text
|
||||
|
||||
### What It Does
|
||||
Users can pinch to scale all chat text up or down within a session.
|
||||
|
||||
### How It Works
|
||||
- Implemented via `ChatTextScaleService` and `ChatZoomWrapper`
|
||||
- Scale range: 0.8× to 1.8×
|
||||
- The chosen scale persists across the session via the service
|
||||
|
||||
---
|
||||
|
||||
## Background Service (Android)
|
||||
|
||||
### What It Does
|
||||
On Android, a foreground service (`background_service.dart`) keeps the BLE connection and message handling alive when the app is in the background. On other platforms this is a no-op.
|
||||
|
||||
### User Impact
|
||||
- A persistent notification appears while the service is running
|
||||
- Messages are received and retry logic continues even when the app is not in the foreground
|
||||
|
||||
@@ -33,7 +33,6 @@ RX (device → host): [0x3E][len_lo][len_hi][payload...]
|
||||
- Length: 2-byte little-endian, payload only
|
||||
- Max payload: 172 bytes
|
||||
- TCP: `tcpNoDelay: true` (Nagle disabled), writes serialized to prevent interleaving
|
||||
- USB: 10ms post-write delay between frames
|
||||
|
||||
## Connection State Machine
|
||||
|
||||
@@ -53,9 +52,11 @@ enum MeshCoreConnectionState {
|
||||
- `MeshCore-`
|
||||
- `Whisper-`
|
||||
- `WisCore-`
|
||||
- `Seeed`
|
||||
- `Lilygo`
|
||||
- `HT-`
|
||||
- `LowMesh_MC_`
|
||||
2. **Connect** with 15-second timeout
|
||||
2. **Connect** with 15-second timeout (6 seconds on Linux)
|
||||
3. **Request MTU** 185 bytes (non-web only)
|
||||
4. **Discover services** and locate NUS
|
||||
5. **Enable TX notifications** (up to 3 attempts on native)
|
||||
@@ -79,7 +80,7 @@ On unexpected disconnection, auto-reconnect with exponential backoff:
|
||||
| Max path size | 64 bytes | Maximum path data |
|
||||
| Max name size | 32 bytes | Maximum node name |
|
||||
| Max text payload | 160 bytes | Firmware `MAX_TEXT_LEN` |
|
||||
| App protocol version | 3 | Sent in device query |
|
||||
| App protocol version | 4 | Sent in device query |
|
||||
| Contact frame size | 148 bytes | Fixed-size contact record |
|
||||
|
||||
## Command Codes (App → Device)
|
||||
|
||||
@@ -28,7 +28,6 @@ QuickSwitchBar tab 1 (middle) from any main screen.
|
||||
- **Scrollable list of channel cards**, each showing:
|
||||
- Type icon with color coding (purple badge overlay for community channels)
|
||||
- Channel name (or "Channel N" if unnamed)
|
||||
- Subtitle: "Public channel", "Hashtag channel", "Private channel", or "Community channel - {name}"
|
||||
- Unread badge (if messages are unread)
|
||||
- Drag handle (when manual sort is active)
|
||||
- **"+" FAB** to add a new channel
|
||||
@@ -70,9 +69,9 @@ Tap a channel card to open the channel chat screen.
|
||||
|
||||
### App Bar
|
||||
|
||||
- Type icon (public/private/hashtag)
|
||||
- Type icon: globe for public channels, tag (#) for all other channel types
|
||||
- Channel name
|
||||
- Subtitle: "{type} - {N} unread"
|
||||
- Subtitle: "{Public|Private} • {N} unread" (e.g., "Public • 3 unread")
|
||||
|
||||
### Message Display
|
||||
|
||||
@@ -113,17 +112,9 @@ Tap a channel card to open the channel chat screen.
|
||||
| Path | Desktop only | Opens message path view |
|
||||
| Add Reaction | Incoming messages only | Opens emoji picker (cannot react to your own messages) |
|
||||
| Copy | All messages | Copies text to clipboard |
|
||||
| Mark as Unread | Incoming messages only | Marks this message and all subsequent incoming messages as unread |
|
||||
| Delete | All messages | Removes locally (not from mesh) |
|
||||
|
||||
### Message Path Viewing
|
||||
|
||||
Tap a message bubble to open the Channel Message Path Screen, which shows:
|
||||
- Each hop in the path as a visual chain
|
||||
- Known contacts identified by name at each hop
|
||||
- Observed vs. declared hop counts
|
||||
- Alternative path variants (if received via multiple paths)
|
||||
- Map view buttons for geographic path visualization
|
||||
|
||||
## Communities
|
||||
|
||||
Communities are a layer above channels that provide a private namespace.
|
||||
|
||||
@@ -37,6 +37,7 @@ From the Contacts screen, tap any Chat-type contact to open the ChatScreen.
|
||||
### Input Bar
|
||||
|
||||
- **GIF button** (left): Opens GIF picker bottom sheet
|
||||
- **Translation button** (optional, between GIF and text field): Shown only when translation is enabled in App Settings. Tap to configure outgoing-message translation language and on/off toggle.
|
||||
- **Text field** (center): Auto-capitalization, enforces UTF-8 byte limit in real-time
|
||||
- **Send button** (right): Submits the message
|
||||
- On desktop: Enter/Numpad Enter also submits
|
||||
@@ -66,8 +67,8 @@ Outgoing messages display a status indicator:
|
||||
|
||||
When enabled in App Settings, additional metadata appears inside each bubble:
|
||||
- Timestamp (HH:MM)
|
||||
- Retry count (e.g., "Retry 2 of 4")
|
||||
- Status icon
|
||||
- Retry count (e.g., "Retry 2 of 4") — only shown for outgoing messages where at least one retry has occurred
|
||||
- Status icon (outgoing only)
|
||||
- Round-trip time in seconds (if delivered)
|
||||
|
||||
## Message Length Limits
|
||||
@@ -86,7 +87,7 @@ When a direct message is sent:
|
||||
|
||||
1. The app computes an expected ACK hash: `SHA256([timestamp][attempt][text][selfPubKey])[0:4]` — matching the firmware's hash calculation. If SMAZ compression is enabled, the compressed text (not the original) is hashed
|
||||
2. On device acknowledgment (`RESP_CODE_SENT`), the message transitions to "sent" and a timeout timer starts
|
||||
3. **Timeout duration**: Preferably from the ML timeout prediction service; otherwise `3000 + 3000 × path_length` milliseconds (15000ms for flood)
|
||||
3. **Timeout duration**: Preferably from the ML timeout prediction service; otherwise calculated from LoRa airtime physics: `500 + (airtime × 6 + 250) × (pathLength + 1)` ms for direct paths, `500 + 16 × airtime` ms for flood (airtime is estimated from the radio's current spreading factor, bandwidth, and coding rate)
|
||||
4. On timeout, the message is retried with **exponential backoff**: `1000 × 2^retryCount` ms (1s, 2s, 4s, 8s, 16s...)
|
||||
5. **Max retries**: Configurable (default 5, range 2–10)
|
||||
6. After max retries, the message is marked "failed" — but a **30-second grace window** remains during which a late ACK can still resolve the message to "delivered"
|
||||
@@ -115,6 +116,7 @@ Add emoji reactions to incoming messages (not your own):
|
||||
| Add reaction | Incoming messages only | Opens emoji picker |
|
||||
| View path | Mobile: tap bubble directly; Desktop: long-press/right-click menu | Shows message routing path |
|
||||
| Copy | All messages | Copies text to clipboard |
|
||||
| Mark as Unread | Incoming messages only | Marks this message and all subsequent incoming messages as unread |
|
||||
| Delete | All messages | Removes locally (not from mesh) |
|
||||
| Retry | Failed outgoing messages | Re-sends the message |
|
||||
| Open chat with sender | Room server chats | Opens 1:1 chat with the message sender |
|
||||
|
||||
@@ -73,7 +73,8 @@ Groups are stored per radio identity (scoped by public key).
|
||||
|
||||
| Action | Availability | Description |
|
||||
|---|---|---|
|
||||
| Path Trace / Ping | Repeaters, Rooms (always); Chat if `pathLength > 0` | Opens PathTraceMapScreen. Label shows "Ping" when no path bytes are known, "Path Trace" otherwise |
|
||||
| Ping | Repeaters (always) | Opens PathTraceMapScreen targeting the repeater |
|
||||
| Path Trace | Rooms (always); Chat/Sensor if `pathLength > 0` | Opens PathTraceMapScreen. For rooms, label shows "Ping" when no path bytes are known, "Path Trace" when path bytes are available |
|
||||
| Manage Repeater | Repeaters only | Login dialog → RepeaterHubScreen |
|
||||
| Room Login | Rooms only | Login dialog → ChatScreen |
|
||||
| Room Management | Rooms only | Login dialog → RepeaterHubScreen (management mode) |
|
||||
|
||||
@@ -25,7 +25,7 @@ All contacts with known GPS coordinates are plotted:
|
||||
| Room | Purple | Meeting room |
|
||||
| Sensor | Orange | Sensors |
|
||||
|
||||
Node name labels appear automatically at zoom level 12 and above.
|
||||
Node name labels appear automatically at zoom level 14 and above.
|
||||
|
||||
### Shared Map Pins (Flag Icons)
|
||||
Location pins shared in chat messages are displayed as flags:
|
||||
@@ -88,10 +88,10 @@ Shows a bottom sheet with:
|
||||
- **Set as my location**: Updates your device's advertised location
|
||||
|
||||
### Filter Dialog (FAB)
|
||||
Toggle visibility of: chat nodes, repeaters, other nodes, guessed locations, discovery contacts.
|
||||
Toggle visibility of: chat nodes, repeaters, other nodes, guessed locations, discovery contacts, overlapping markers (stacked markers at similar coordinates), and shared map pins (flag markers).
|
||||
Additional filters:
|
||||
- **Key prefix filter**: Show only contacts whose public key starts with a given prefix
|
||||
- **Last-seen time slider**: From 1 hour to "all time"
|
||||
- **Last-seen time slider**: Exponential scale from near-zero to 6 months, with "all time" at the top end
|
||||
|
||||
### Legend Card (Top-Right)
|
||||
Shows node count and pin count. Tappable to expand a legend of all marker types.
|
||||
|
||||
@@ -22,31 +22,16 @@ The QuickSwitchBar is a Material 3 `NavigationBar` with a frosted-glass visual t
|
||||
|
||||
Tapping a tab replaces the current screen with a subtle fade + slight horizontal nudge transition (220ms forward, 200ms reverse). The back button is suppressed on all three main screens — navigation between them is flat, not stacked. All icons use outline variants (`people_outline`, `tag`, `map_outlined`) following Material 3 conventions.
|
||||
|
||||
## Device Screen
|
||||
## Disconnection
|
||||
|
||||
The Device Screen is a transitional hub that shows after connection. In practice, the app navigates directly to Contacts after connecting, but the Device Screen is reachable via the QuickSwitchBar.
|
||||
|
||||
### What the User Sees
|
||||
|
||||
**App Bar**:
|
||||
- Left: Battery indicator chip (tappable — toggles between percentage and voltage display). Icon changes based on level: `battery_unknown` when data unavailable, `battery_alert` (orange) at 15% or below, `battery_full` otherwise
|
||||
- Left-aligned title (`centerTitle: false`): Two-line layout — small grey "MeshCore" label above the device name in bold
|
||||
- Right: Disconnect button (`bluetooth_disabled` crossed-out icon) and Settings button (tune icon)
|
||||
|
||||
**Body**:
|
||||
- **Connection Card**: Device avatar, device name, device ID, "Connected" chip, and battery chip
|
||||
- **Quick Switch** section: The QuickSwitchBar widget for navigating to Contacts/Channels/Map
|
||||
|
||||
### Disconnection
|
||||
|
||||
- The disconnect button shows a confirmation dialog before disconnecting
|
||||
- The disconnect button (available in the Settings screen and other main screens) shows a confirmation dialog before disconnecting
|
||||
- If the device disconnects unexpectedly, the app automatically navigates back to the Scanner screen (fires after the current frame completes via a post-frame callback)
|
||||
- This auto-navigation behavior (`DisconnectNavigationMixin`) is shared across all main screens
|
||||
|
||||
## Theme and Locale
|
||||
|
||||
- **Theme mode** is user-configurable in App Settings (System / Light / Dark) — not locked to system
|
||||
- **Language** can be overridden to one of 15 supported languages, or follow the system locale
|
||||
- **Language** can be overridden to one of 18 supported languages, or follow the system locale
|
||||
- On web, if a non-Chromium browser is detected, the app shows a `ChromeRequiredScreen` instead of the Scanner (Web Bluetooth requires Chromium)
|
||||
|
||||
## Full Navigation Graph
|
||||
|
||||
@@ -73,7 +73,7 @@ There is no per-contact muting.
|
||||
|
||||
The notification system prevents notification storms:
|
||||
- **Minimum interval**: 3 seconds between individual notifications
|
||||
- **Batch window**: If multiple notifications arrive within 5 seconds, they are combined into a single summary notification on a fourth Android channel (`batch_summary`): "MeshCore Activity — 2 messages, 1 channel message, 3 new nodes". Note: batch summaries are Android-only; on Apple platforms individual notifications are shown
|
||||
- **Batch window**: If multiple notifications arrive within 5 seconds, they are combined into a single summary notification on a fourth Android channel (`batch_summary`). The title is "MeshCore Activity" and the body lists the grouped counts (e.g., "2 messages, 1 channel message, 3 new nodes"). Batch summaries are Android-only; queued notifications that overflow the batch window are silently dropped on other platforms
|
||||
|
||||
## Notification Clearing
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ From the Contacts screen:
|
||||
- Password field with show/hide toggle
|
||||
- "Save password" checkbox (persists for future logins). If a saved password exists, it is pre-filled and the checkbox is pre-checked, making login one-tap
|
||||
- Routing mode selector and "Manage Paths" link are available directly in the dialog (configure routing before login)
|
||||
- Auto-retries up to 5 times on timeout, showing progress ("Attempt 2 of 5"). A wrong password stops immediately after the first attempt — only timeouts trigger retries
|
||||
- After 5 failed attempts, further login attempts are blocked
|
||||
- Auto-retries up to 5 times on timeout, showing progress ("Attempt 2 of 5"). A wrong password (explicit failure response) stops immediately — only timeouts trigger retries
|
||||
- If auto-clock-sync is enabled for this repeater (configured in Repeater Settings), a `clock sync` command is sent automatically on successful login
|
||||
|
||||
---
|
||||
|
||||
@@ -28,15 +28,17 @@ The central management screen showing:
|
||||
|
||||
- **Header card**: Repeater name, short public key, path label, GPS coordinates (if known)
|
||||
- **Battery chemistry selector**: NMC / LiFePO4 / LiPo (saved per repeater)
|
||||
- **Management tool cards** (full-width cards with chevron arrows, not a grid). Title dynamically shows "Repeater Management" or "Room Management" based on contact type:
|
||||
- **Management tool cards** (full-width cards with chevron arrows, not a grid). Title dynamically shows "Repeater Management" or "Room Management" (admin) or "Repeater Guest" / "Room Guest" (guest) based on contact type and login result:
|
||||
|
||||
| Card | Destination |
|
||||
|---|---|
|
||||
| Status | Repeater Status Screen |
|
||||
| Telemetry | Telemetry Screen |
|
||||
| CLI | Repeater CLI Screen |
|
||||
| Neighbors | Neighbors Screen |
|
||||
| Settings | Repeater Settings Screen |
|
||||
| Card | Destination | Visibility |
|
||||
|---|---|---|
|
||||
| Status | Repeater Status Screen | All users |
|
||||
| Telemetry | Telemetry Screen | All users |
|
||||
| CLI | Repeater CLI Screen | Admin only |
|
||||
| Neighbors | Neighbors Screen | All users |
|
||||
| Settings | Repeater Settings Screen | Admin only |
|
||||
|
||||
The battery chemistry selector and CLI/Settings cards are hidden from guest users.
|
||||
|
||||
---
|
||||
|
||||
@@ -47,26 +49,28 @@ The central management screen showing:
|
||||
Three information cards:
|
||||
|
||||
**System Information**:
|
||||
- Battery percentage
|
||||
- Uptime
|
||||
- Queue length
|
||||
- Error flags
|
||||
- Battery percentage and voltage (e.g. "85% / 3.95V"), using the battery chemistry set in the hub screen
|
||||
- Clock at login time
|
||||
- Uptime (days/hours/minutes/seconds)
|
||||
- Queue length
|
||||
- Debug flags (error event count)
|
||||
|
||||
**Radio Statistics**:
|
||||
- Last RSSI and SNR
|
||||
- Noise floor
|
||||
- TX and RX airtime
|
||||
- TX airtime and RX airtime
|
||||
|
||||
**Packet Statistics**:
|
||||
- Packets sent, received, and duplicates
|
||||
- Broken down by flood vs. direct
|
||||
- Packets sent and received, each broken down by flood vs. direct
|
||||
- Duplicates, broken down by flood vs. direct
|
||||
- Channel utilization (% of uptime used by TX + RX)
|
||||
|
||||
### Key Interactions
|
||||
- Auto-queries the repeater on open; shows a loading spinner until data arrives
|
||||
- On timeout: red snackbar error. On success: data appears with a green snackbar confirmation
|
||||
- Pull-to-refresh or refresh button to re-query
|
||||
- On timeout: red snackbar error. On success: data appears in-place (no extra snackbar)
|
||||
- Pull-to-refresh or refresh button in the app bar to re-query
|
||||
- Routing mode popup and path management dialog in app bar (these controls appear on **all** management sub-screens, not just Status)
|
||||
- Accepts both binary `RESP_CODE_STATUS_RESPONSE` frames and legacy JSON text responses
|
||||
|
||||
---
|
||||
|
||||
@@ -76,7 +80,7 @@ A terminal-style interface for sending commands directly to the repeater.
|
||||
|
||||
### What the User Sees
|
||||
|
||||
- **Quick-command bar** (horizontal scroll): Shortcut buttons for common commands (get name, get radio, get tx, neighbors, ver, advert, clock)
|
||||
- **Quick-command bar** (horizontal scroll): Shortcut buttons for 9 common commands (advert, get name, get radio, get tx, discover.neighbors, neighbors, ver, clock, clock sync)
|
||||
- **Command history list**: Sent commands in primary color, responses in secondary color
|
||||
- **Input bar**: Up/down history arrows, monospace text field with `> ` prefix, send button
|
||||
|
||||
@@ -92,9 +96,13 @@ A terminal-style interface for sending commands directly to the repeater.
|
||||
|
||||
### Available CLI Commands
|
||||
|
||||
**General**: `advert`, `reboot`, `clock`, `password`, `ver`, `clear stats`
|
||||
The in-app help reference (help icon) documents all known commands. Categories:
|
||||
|
||||
**Settings**: `set name`, `set af`, `set tx`, `set repeat`, `set allow.read.only`, `set flood.max`, `set int.thresh`, `set agc.reset.interval`, `set multi.acks`, `set advert.interval`, `set flood.advert.interval`, `set guest.password`, `set lat`, `set lon`, `set radio`, `set rxdelay`, `set txdelay`, `set direct.txdelay`, `set bridge.*`, `set adc.multiplier`, `tempradio`, `setperm`
|
||||
**General**: `advert`, `advert.zerohop`, `reboot`, `clock`, `clock sync`, `password`, `ver`, `clear stats`, `erase`, `poweroff`, `shutdown`, `clkreboot`, `start ota`, `time`, `board`, `discover.neighbors`, `powersaving`, `stats-packets`, `stats-radio`, `stats-core`
|
||||
|
||||
**Get**: `get name`, `get role`, `get public.key`, `get prv.key`, `get repeat`, `get tx`, `get freq`, `get radio`, `get radio.rxgain`, `get af`, `get dutycycle`, `get int.thresh`, `get agc.reset.interval`, `get multi.acks`, `get allow.read.only`, `get advert.interval`, `get flood.advert.interval`, `get guest.password`, `get lat`, `get lon`, `get rxdelay`, `get txdelay`, `get direct.txdelay`, `get flood.max`, `get owner.info`, `get path.hash.mode`, `get loop.detect`, `get acl`, `get bridge.*`, `get adc.multiplier`, `get bootloader.ver`
|
||||
|
||||
**Set**: `set name`, `set af`, `set tx`, `set repeat`, `set allow.read.only`, `set flood.max`, `set int.thresh`, `set agc.reset.interval`, `set multi.acks`, `set advert.interval`, `set flood.advert.interval`, `set guest.password`, `set lat`, `set lon`, `set freq`, `set radio`, `set rxdelay`, `set txdelay`, `set direct.txdelay`, `set radio.rxgain`, `set dutycycle`, `set loop.detect`, `set path.hash.mode`, `set owner.info`, `set prv.key`, `set bridge.*`, `set adc.multiplier`, `tempradio`, `setperm`
|
||||
|
||||
**Bridge**: `get bridge.type`
|
||||
|
||||
@@ -102,9 +110,11 @@ A terminal-style interface for sending commands directly to the repeater.
|
||||
|
||||
**Neighbors**: `neighbors`, `neighbor.remove`
|
||||
|
||||
**Region Management**: `region`, `region load/get/put/remove/allowf/denyf/home/save`
|
||||
**Power Management**: `get pwrmgt.support`, `get pwrmgt.source`, `get pwrmgt.bootreason`, `get pwrmgt.bootmv`
|
||||
|
||||
**GPS**: `gps`, `gps on/off/sync/setloc/advert`
|
||||
**Sensors**: `sensor get {key}`
|
||||
|
||||
**Region Management**: `region`, `region load`, `region get`, `region put`, `region remove`, `region allowf`, `region denyf`, `region home`, `region save`, `region default`, `region list allowed`, `region list denied`
|
||||
|
||||
---
|
||||
|
||||
@@ -147,40 +157,63 @@ A card titled "Repeater's Neighbors - N" listing each neighbor as:
|
||||
|
||||
### What the User Sees
|
||||
|
||||
Five configuration cards:
|
||||
Nine configuration cards, each with its own per-field refresh button(s):
|
||||
|
||||
**1. Basic Settings**
|
||||
- Name field
|
||||
- Admin password field
|
||||
- Guest password field
|
||||
- Admin password field (write-only; always sent when non-empty)
|
||||
- Guest password field (write-only; always sent when non-empty)
|
||||
|
||||
**2. Radio Settings**
|
||||
- Frequency (MHz)
|
||||
- TX Power (dBm)
|
||||
- TX Power (dBm) — has its own independent refresh button
|
||||
- Bandwidth dropdown (kHz)
|
||||
- Spreading Factor (SF5–SF12)
|
||||
- Coding Rate (4/5–4/8)
|
||||
- RX Gain boost toggle
|
||||
|
||||
**3. Location Settings**
|
||||
- Latitude and longitude fields
|
||||
- Latitude and longitude fields, each with an independent refresh button
|
||||
|
||||
**4. Features**
|
||||
- Packet forwarding toggle
|
||||
- Guest access toggle
|
||||
- Packet forwarding toggle (`set repeat`)
|
||||
- Guest access toggle (`set allow.read.only`)
|
||||
- Multi-ACKs toggle (`set multi.acks`)
|
||||
- Auto clock sync after login toggle (local app setting only, not sent to repeater)
|
||||
|
||||
**5. Advertisement Settings**
|
||||
**5. Network Health**
|
||||
- Loop detection dropdown (off / minimal / moderate / strict; `set loop.detect`)
|
||||
- Duty cycle slider (1–100%; `set dutycycle`)
|
||||
|
||||
**6. Advertisement Settings**
|
||||
- Local advert interval slider (60–240 minutes) with enable/disable toggle
|
||||
- Flood advert interval slider (3–168 hours) with enable/disable toggle
|
||||
- Flood max hops slider (0–64; `set flood.max`)
|
||||
|
||||
**6. Danger Zone** (red-styled card)
|
||||
- Reboot repeater
|
||||
- Erase filesystem (serial-only warning)
|
||||
**7. Owner Info**
|
||||
- Multi-line text field for operator contact info (`set owner.info`); newlines sent as `|`
|
||||
|
||||
**8. Actions** (one-tap, no save needed)
|
||||
- Send Advertisement (`advert`)
|
||||
- Send Zero-Hop Advertisement (`advert.zerohop`)
|
||||
- Clock Sync (`clock sync`)
|
||||
|
||||
**9. Advanced** (collapsed by default)
|
||||
- Path hash mode dropdown (0–2; `set path.hash.mode`)
|
||||
- TX delay field (`set txdelay`)
|
||||
- Direct TX delay field (`set direct.txdelay`)
|
||||
- Interference threshold field (`set int.thresh`)
|
||||
- AGC reset interval slider (0–240s in multiples of 4; `set agc.reset.interval`)
|
||||
|
||||
**Danger Zone** (red-styled card)
|
||||
- Reboot repeater (sends `reboot` with confirmation dialog)
|
||||
- Erase filesystem (serial-only; shows informational snackbar only — no command is sent over the air)
|
||||
|
||||
### Key Interactions
|
||||
- **Settings are NOT auto-fetched on open**. Only name and location are pre-filled from locally cached contact data. You must tap each section's refresh button to fetch live values from the repeater
|
||||
- TX Power has its own separate refresh button, independent from the main Radio Settings refresh
|
||||
- Save button appears when changes are detected
|
||||
- Settings are sent sequentially with 200ms delays between commands (fire-and-forget, no per-command acknowledgment wait)
|
||||
- Validation prevents invalid values (e.g., frequency range, LoRa parameter compatibility)
|
||||
- **Settings are NOT auto-fetched on open**. Name is pre-filled from cached contact data. Each section has its own refresh button to fetch live values from the repeater
|
||||
- TX Power, RX Gain, latitude, longitude, and advanced fields each have independent inline refresh buttons
|
||||
- Save button in app bar appears when any change is detected; failed commands keep those fields dirty for retry
|
||||
- Settings are sent sequentially with 200ms delays between commands; firmware responses are checked and partial failures are reported in a snackbar
|
||||
- Some changes (e.g. radio frequency) require a reboot; the firmware response triggers an orange "reboot needed" snackbar
|
||||
- Advertisement interval sliders reset to defaults when re-enabled (local: 60 min, flood: 3 hours)
|
||||
- **Erase Filesystem** does NOT send any command over the air — tapping it only shows a snackbar explaining the operation requires physical serial access. It is effectively non-functional when connected wirelessly
|
||||
- **Erase Filesystem** does NOT send any command over the air — tapping it only shows a snackbar explaining the operation requires physical serial access
|
||||
|
||||
@@ -51,7 +51,7 @@ Note: The weak (-80 to -90 dBm) and poor (< -90 dBm) tiers share the same icon s
|
||||
|
||||
### How Scanning Works
|
||||
|
||||
- Filters for devices with names starting with `MeshCore-` or `Whisper-`
|
||||
- Filters for devices with names starting with one of the known prefixes: `MeshCore-`, `Whisper-`, `WisCore-`, `Seeed`, `Lilygo`, `HT-`, `LowMesh_MC_`
|
||||
- Uses low-latency scan mode on Android
|
||||
- Scans for 10 seconds then auto-stops
|
||||
- On iOS/macOS, waits for BLE adapter initialization before starting
|
||||
@@ -61,7 +61,7 @@ Note: The weak (-80 to -90 dBm) and poor (< -90 dBm) tiers share the same icon s
|
||||
|
||||
Tap a device tile or its Connect button:
|
||||
1. The connector stops scanning and transitions to "connecting"
|
||||
2. Connects to the device with a 15-second timeout
|
||||
2. Connects to the device with a 15-second timeout (6 seconds on Linux)
|
||||
3. Requests MTU 185 bytes for optimal throughput
|
||||
4. Discovers BLE services and locates the Nordic UART Service
|
||||
5. Subscribes to TX notifications for receiving data
|
||||
|
||||
@@ -46,7 +46,7 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de
|
||||
|
||||
### Appearance
|
||||
- **Theme**: System / Light / Dark
|
||||
- **Language**: System default or one of 15 languages (English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian)
|
||||
- **Language**: System default or one of 18 languages (English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian, Hungarian, Japanese, Korean)
|
||||
- **Enable Message Tracing**: Shows path trace overlays and extra metadata on messages
|
||||
|
||||
### Notifications
|
||||
@@ -57,6 +57,7 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de
|
||||
|
||||
### Messaging
|
||||
- **Clear Path on Max Retry**: Erases the stored routing path after all retries fail
|
||||
- **Jump to Oldest Unread**: When opening a chat, scrolls to the oldest unread message instead of the newest
|
||||
- **Auto Route Rotation**: Enables weighted routing algorithm. When enabled, expands to show five slider sub-settings (hidden when off):
|
||||
- Max Route Weight (1–10, default 5, integer steps)
|
||||
- Initial Route Weight (0.5–5.0, default 3.0)
|
||||
@@ -67,6 +68,15 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de
|
||||
### Battery
|
||||
- **Battery Chemistry**: NMC / LiFePO4 / LiPo (per device, used to calibrate percentage from voltage)
|
||||
|
||||
### Translation
|
||||
Not shown on web. Controls on-device message translation powered by a locally-downloaded ML model:
|
||||
- **Enable Translation**: Translates incoming messages into the selected target language
|
||||
- **Translate Composer**: Translates outgoing messages from the target language back before sending
|
||||
- **Target Language**: Language to translate into (searchable list; defaults to the app language)
|
||||
- **Downloaded Model**: Dropdown to select among already-downloaded translation models
|
||||
- **Preset Model**: Download a curated preset model with one tap
|
||||
- **Custom Model URL**: Enter a URL to download a custom GGUF-format model; shows download progress and a cancel button
|
||||
|
||||
### Map Display
|
||||
- **Show Repeaters**: Toggle repeater markers on map
|
||||
- **Show Chat Nodes**: Toggle chat node markers
|
||||
@@ -91,7 +101,7 @@ These settings are sent directly to the connected device firmware.
|
||||
|
||||
### Radio Settings
|
||||
Opens a dialog pre-populated with the device's current radio settings. Contains:
|
||||
- **Preset dropdown**: 19 regional presets — selecting a preset immediately fills all fields below. Full list: Australia, Australia (Narrow), Australia SA/WA/QLD, Czech Republic, EU 433MHz, EU/UK (Long Range), EU/UK (Medium Range), EU/UK (Narrow), New Zealand, New Zealand (Narrow), Portugal 433, Portugal 869, Switzerland, USA Arizona, USA/Canada, Vietnam, Off-Grid 433, Off-Grid 869, Off-Grid 918
|
||||
- **Preset dropdown**: 19 regional presets — selecting a preset immediately fills all fields below. Full list: Australia, Australia (Narrow), Australia SA, WA, QLD, Czech Republic, EU 433MHz, EU/UK (Long Range), EU/UK (Medium Range), EU/UK (Narrow), New Zealand, New Zealand (Narrow), Portugal 433, Portugal 869, Switzerland, USA Arizona, USA/Canada, Vietnam, Off-Grid 433, Off-Grid 869, Off-Grid 918
|
||||
- **Frequency** (MHz): Free text, validated 300–2500 MHz
|
||||
- **Bandwidth**: Dropdown (7.8 / 10.4 / 15.6 / 20.8 / 31.25 / 41.7 / 62.5 / 125 / 250 / 500 kHz)
|
||||
- **Spreading Factor**: SF5–SF12
|
||||
|
||||
@@ -20,7 +20,5 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>13.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
platform :ios, '15.5'
|
||||
platform :ios, '16.4'
|
||||
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
@@ -32,5 +32,8 @@ end
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.4'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+13
-84
@@ -7,57 +7,13 @@ PODS:
|
||||
- Flutter
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- GoogleMLKit/BarcodeScanning (7.0.0):
|
||||
- GoogleMLKit/MLKitCore
|
||||
- MLKitBarcodeScanning (~> 6.0.0)
|
||||
- GoogleMLKit/MLKitCore (7.0.0):
|
||||
- MLKitCommon (~> 12.0.0)
|
||||
- GoogleToolboxForMac/Defines (4.2.1)
|
||||
- GoogleToolboxForMac/Logger (4.2.1):
|
||||
- GoogleToolboxForMac/Defines (= 4.2.1)
|
||||
- "GoogleToolboxForMac/NSData+zlib (4.2.1)":
|
||||
- GoogleToolboxForMac/Defines (= 4.2.1)
|
||||
- GoogleUtilities/Environment (8.1.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Logger (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (8.1.0)
|
||||
- GoogleUtilities/UserDefaults (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GTMSessionFetcher/Core (3.5.0)
|
||||
- MLImage (1.0.0-beta6)
|
||||
- MLKitBarcodeScanning (6.0.0):
|
||||
- MLKitCommon (~> 12.0)
|
||||
- MLKitVision (~> 8.0)
|
||||
- MLKitCommon (12.0.0):
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
|
||||
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
|
||||
- GoogleUtilities/Logger (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
|
||||
- MLKitVision (8.0.0):
|
||||
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
|
||||
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
|
||||
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
|
||||
- MLImage (= 1.0.0-beta6)
|
||||
- MLKitCommon (~> 12.0)
|
||||
- mobile_scanner (6.0.2):
|
||||
- mobile_scanner (7.0.0):
|
||||
- Flutter
|
||||
- GoogleMLKit/BarcodeScanning (~> 7.0.0)
|
||||
- nanopb (3.30910.0):
|
||||
- nanopb/decode (= 3.30910.0)
|
||||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- FlutterMacOS
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- PromisesObjC (2.4.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -66,34 +22,18 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`)
|
||||
- flutter_foreground_task (from `.symlinks/plugins/flutter_foreground_task/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
|
||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GoogleDataTransport
|
||||
- GoogleMLKit
|
||||
- GoogleToolboxForMac
|
||||
- GoogleUtilities
|
||||
- GTMSessionFetcher
|
||||
- MLImage
|
||||
- MLKitBarcodeScanning
|
||||
- MLKitCommon
|
||||
- MLKitVision
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
@@ -105,41 +45,30 @@ EXTERNAL SOURCES:
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
mobile_scanner:
|
||||
:path: ".symlinks/plugins/mobile_scanner/ios"
|
||||
:path: ".symlinks/plugins/mobile_scanner/darwin"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sqflite_darwin:
|
||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3
|
||||
flutter_foreground_task: a159d2c2173b33699ddb3e6c2a067045d7cebb89
|
||||
flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
|
||||
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
|
||||
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
|
||||
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
|
||||
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
|
||||
mobile_scanner: af8f71879eaba2bbcb4d86c6a462c3c0e7f23036
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
|
||||
PODFILE CHECKSUM: 570da2a631486c6bd6496bed1e605e63e2471be5
|
||||
PODFILE CHECKSUM: e42b502c78c33aa1ed9d42eaea8960ce2139504b
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
F0D7F2413C6E4B7A9B1C2D3E /* Fix Native Asset Minimum OS */,
|
||||
B788CEDB957A87EE8AC593BB /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -299,6 +300,22 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F0D7F2413C6E4B7A9B1C2D3E /* Fix Native Asset Minimum OS */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}",
|
||||
);
|
||||
name = "Fix Native Asset Minimum OS";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\nFRAMEWORKS_DIR=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nMIN_OS=\"${IPHONEOS_DEPLOYMENT_TARGET}\"\nif [ ! -d \"$FRAMEWORKS_DIR\" ] || [ -z \"$MIN_OS\" ]; then\n exit 0\nfi\nfind \"$FRAMEWORKS_DIR\" -maxdepth 2 -name Info.plist | while read -r plist; do\n bundle_id=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' \"$plist\" 2>/dev/null || true)\n case \"$bundle_id\" in\n io.flutter.flutter.native-assets.*)\n /usr/libexec/PlistBuddy -c \"Set :MinimumOSVersion $MIN_OS\" \"$plist\" 2>/dev/null || \\\n /usr/libexec/PlistBuddy -c \"Add :MinimumOSVersion string $MIN_OS\" \"$plist\"\n ;;\n esac\ndone\n";
|
||||
};
|
||||
DE3B2E091393835C0B38492E /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -414,7 +431,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -540,7 +557,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -591,7 +608,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
||||
@@ -2,12 +2,15 @@ import Flutter
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||
}
|
||||
}
|
||||
|
||||
+40
-19
@@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
@@ -22,8 +24,46 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>http</string>
|
||||
<string>https</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>This app uses Bluetooth to communicate with MeshCore devices.</string>
|
||||
<key>NSBluetoothPeripheralUsageDescription</key>
|
||||
<string>This app uses Bluetooth to communicate with MeshCore devices.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app uses the camera to scan QR codes for joining communities.</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneClassName</key>
|
||||
<string>UIWindowScene</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>flutter</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>FlutterSceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>bluetooth-central</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
@@ -41,24 +81,5 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>bluetooth-central</string>
|
||||
</array>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>This app uses Bluetooth to communicate with MeshCore devices.</string>
|
||||
<key>NSBluetoothPeripheralUsageDescription</key>
|
||||
<string>This app uses Bluetooth to communicate with MeshCore devices.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app uses the camera to scan QR codes for joining communities.</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>http</string>
|
||||
<string>https</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+1056
-348
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ class MeshCoreUsbManager {
|
||||
String? get activePortKey => _activePortKey;
|
||||
String? get activePortDisplayLabel => _activePortLabel ?? _activePortKey;
|
||||
bool get isConnected => _service.isConnected;
|
||||
Object? get lastError => _service.lastError;
|
||||
Stream<Uint8List> get frameStream => _service.frameStream;
|
||||
|
||||
// --- Configuration ---
|
||||
|
||||
@@ -224,6 +224,12 @@ const int reqTypeGetTelemetry = 0x03;
|
||||
const int reqTypeGetAccessList = 0x05;
|
||||
const int reqTypeGetNeighbors = 0x06;
|
||||
|
||||
Uint8List buildTelemetryBinaryPayload() {
|
||||
// Room servers/repeaters read byte 1 as an inverse telemetry permission mask.
|
||||
// Zero means "request every telemetry field allowed for this contact".
|
||||
return Uint8List.fromList([reqTypeGetTelemetry, 0x00, 0x00, 0x00, 0x00]);
|
||||
}
|
||||
|
||||
// Repeater response codes
|
||||
const int respServerLoginOk = 0;
|
||||
|
||||
@@ -320,7 +326,7 @@ const int maxPathSize = 64;
|
||||
const int pathHashSize = 1;
|
||||
const int maxNameSize = 32;
|
||||
const int maxFrameSize = 172;
|
||||
const int appProtocolVersion = 3;
|
||||
const int appProtocolVersion = 4;
|
||||
// Matches firmware MAX_TEXT_LEN (10 * CIPHER_BLOCK_SIZE).
|
||||
const int maxTextPayloadBytes = 160;
|
||||
const int _sendTextMsgOverheadBytes =
|
||||
@@ -451,8 +457,13 @@ String pubKeyToHex(Uint8List pubKey) {
|
||||
|
||||
// Helper to convert hex string to public key
|
||||
Uint8List hexToPubKey(String hex) {
|
||||
if (hex.length != pubKeySize * 2) {
|
||||
throw FormatException(
|
||||
'Public key hex must be ${pubKeySize * 2} chars, got ${hex.length}',
|
||||
);
|
||||
}
|
||||
final result = Uint8List(pubKeySize);
|
||||
for (int i = 0; i < pubKeySize && i * 2 + 1 < hex.length; i++) {
|
||||
for (int i = 0; i < pubKeySize; i++) {
|
||||
result[i] = int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16);
|
||||
}
|
||||
return result;
|
||||
@@ -720,25 +731,19 @@ Uint8List buildUpdateContactPathFrame(
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
writer.writeUInt32LE(timestamp);
|
||||
|
||||
if ((lat == null || lon == null) && lastModified != null) {
|
||||
// If lat/lon not provided, write zeros
|
||||
writer.writeInt32LE(0);
|
||||
writer.writeInt32LE(0);
|
||||
} else {
|
||||
// Latitude and Longitude are expected in degrees, convert to int by multiplying by 1e6
|
||||
// Latitude
|
||||
final latitude = lat ?? 0.0;
|
||||
writer.writeInt32LE((latitude * 1e6).round());
|
||||
|
||||
// Longitude
|
||||
final longitude = lon ?? 0.0;
|
||||
writer.writeInt32LE((longitude * 1e6).round());
|
||||
}
|
||||
|
||||
if (lastModified != null) {
|
||||
// Last modified
|
||||
final lastModifiedTimestamp = lastModified.millisecondsSinceEpoch ~/ 1000;
|
||||
writer.writeUInt32LE(lastModifiedTimestamp);
|
||||
// Optional [Lat x4, Lon x4][timestamp x4] tail per the doc comment above.
|
||||
// Emit 8 bytes of position (zero-filled when only lastModified is provided)
|
||||
// followed by an optional 4-byte timestamp. Earlier code emitted the
|
||||
// position block twice, which corrupted the tail and caused the firmware
|
||||
// to parse the second lat as the timestamp. See #427.
|
||||
final hasLocation = lat != null && lon != null;
|
||||
if (hasLocation || lastModified != null) {
|
||||
writer.writeInt32LE(hasLocation ? (lat * 1e6).round() : 0);
|
||||
writer.writeInt32LE(hasLocation ? (lon * 1e6).round() : 0);
|
||||
if (lastModified != null) {
|
||||
final lastModifiedTimestamp = lastModified.millisecondsSinceEpoch ~/ 1000;
|
||||
writer.writeUInt32LE(lastModifiedTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
return writer.toBytes();
|
||||
@@ -951,7 +956,7 @@ Uint8List buildSendTelemetryReq(Uint8List? pubKey) {
|
||||
writer.writeBytes(Uint8List(3)); // reserved bytes
|
||||
writer.writeBytes(pubKey);
|
||||
} else {
|
||||
writer.writeBytes(Uint8List(4)); // reserved bytes
|
||||
writer.writeBytes(Uint8List(3)); // reserved bytes
|
||||
}
|
||||
return writer.toBytes();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ class MeshCoreUuids {
|
||||
static const String rxCharacteristic = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
|
||||
static const String txCharacteristic = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
|
||||
|
||||
/// Known advertised-name prefixes used by stock MeshCore firmware builds.
|
||||
/// Discovery no longer filters on these (it filters on the [service] UUID so
|
||||
/// that community forks with custom names are still found); kept for
|
||||
/// reference and possible future display heuristics.
|
||||
static const List<String> deviceNamePrefixes = [
|
||||
"MeshCore-",
|
||||
"Whisper-",
|
||||
@@ -11,5 +15,6 @@ class MeshCoreUuids {
|
||||
"Lilygo",
|
||||
"HT-",
|
||||
"LowMesh_MC_",
|
||||
"NRF52",
|
||||
];
|
||||
}
|
||||
|
||||
@@ -96,6 +96,34 @@ class CayenneLpp {
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case lppDigitalInput:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt8(),
|
||||
});
|
||||
break;
|
||||
case lppDigitalOutput:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt8(),
|
||||
});
|
||||
break;
|
||||
case lppAnalogInput:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readInt16BE() / 100,
|
||||
});
|
||||
break;
|
||||
case lppAnalogOutput:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readInt16BE() / 100,
|
||||
});
|
||||
break;
|
||||
case lppGenericSensor:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
@@ -131,6 +159,17 @@ class CayenneLpp {
|
||||
'value': buffer.readUInt8() / 2,
|
||||
});
|
||||
break;
|
||||
case lppAccelerometer:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': {
|
||||
'x': buffer.readInt16BE() / 1000,
|
||||
'y': buffer.readInt16BE() / 1000,
|
||||
'z': buffer.readInt16BE() / 1000,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case lppBarometricPressure:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
@@ -138,6 +177,13 @@ class CayenneLpp {
|
||||
'value': buffer.readUInt16BE() / 10,
|
||||
});
|
||||
break;
|
||||
case lppAltitude:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readInt16BE(),
|
||||
});
|
||||
break;
|
||||
case lppVoltage:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
@@ -152,6 +198,13 @@ class CayenneLpp {
|
||||
'value': buffer.readInt16BE() / 1000,
|
||||
});
|
||||
break;
|
||||
case lppFrequency:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt32BE(),
|
||||
});
|
||||
break;
|
||||
case lppPercentage:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
@@ -173,6 +226,56 @@ class CayenneLpp {
|
||||
'value': buffer.readUInt16BE(),
|
||||
});
|
||||
break;
|
||||
case lppDistance:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt32BE() / 1000,
|
||||
});
|
||||
break;
|
||||
case lppEnergy:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt32BE() / 1000,
|
||||
});
|
||||
break;
|
||||
case lppDirection:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt16BE(),
|
||||
});
|
||||
break;
|
||||
case lppUnixTime:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt32BE(),
|
||||
});
|
||||
break;
|
||||
case lppGyrometer:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': {
|
||||
'x': buffer.readInt16BE() / 100,
|
||||
'y': buffer.readInt16BE() / 100,
|
||||
'z': buffer.readInt16BE() / 100,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case lppColour:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': {
|
||||
'red': buffer.readUInt8(),
|
||||
'green': buffer.readUInt8(),
|
||||
'blue': buffer.readUInt8(),
|
||||
},
|
||||
});
|
||||
break;
|
||||
case lppGps:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
@@ -184,6 +287,24 @@ class CayenneLpp {
|
||||
},
|
||||
});
|
||||
break;
|
||||
case lppSwitch:
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': buffer.readUInt8(),
|
||||
});
|
||||
break;
|
||||
case lppPolyline:
|
||||
final size = buffer.readUInt8();
|
||||
telemetry.add({
|
||||
'channel': channel,
|
||||
'type': type,
|
||||
'value': {
|
||||
'size': size,
|
||||
'data': _bytesToHex(_readPolylinePayload(buffer, size)),
|
||||
},
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return telemetry;
|
||||
}
|
||||
@@ -216,6 +337,19 @@ class CayenneLpp {
|
||||
);
|
||||
|
||||
switch (type) {
|
||||
case lppDigitalInput:
|
||||
channelData['values']['digitalInput'] = buffer.readUInt8();
|
||||
break;
|
||||
case lppDigitalOutput:
|
||||
channelData['values']['digitalOutput'] = buffer.readUInt8();
|
||||
break;
|
||||
case lppAnalogInput:
|
||||
channelData['values']['analogInput'] = buffer.readInt16BE() / 100.0;
|
||||
break;
|
||||
case lppAnalogOutput:
|
||||
channelData['values']['analogOutput'] =
|
||||
buffer.readInt16BE() / 100.0;
|
||||
break;
|
||||
case lppGenericSensor:
|
||||
channelData['values']['generic'] = buffer.readUInt32BE();
|
||||
break;
|
||||
@@ -231,15 +365,29 @@ class CayenneLpp {
|
||||
case lppRelativeHumidity:
|
||||
channelData['values']['humidity'] = buffer.readUInt8() / 2.0;
|
||||
break;
|
||||
case lppAccelerometer:
|
||||
channelData['values']['accelerometer'] = {
|
||||
'x': buffer.readInt16BE() / 1000.0,
|
||||
'y': buffer.readInt16BE() / 1000.0,
|
||||
'z': buffer.readInt16BE() / 1000.0,
|
||||
};
|
||||
break;
|
||||
case lppBarometricPressure:
|
||||
channelData['values']['pressure'] = buffer.readUInt16BE() / 10.0;
|
||||
break;
|
||||
case lppAltitude:
|
||||
// MeshCore encodes standalone barometric altitude as LPP type 121.
|
||||
channelData['values']['altitude'] = buffer.readInt16BE();
|
||||
break;
|
||||
case lppVoltage:
|
||||
channelData['values']['voltage'] = buffer.readInt16BE() / 100.0;
|
||||
break;
|
||||
case lppCurrent:
|
||||
channelData['values']['current'] = buffer.readInt16BE() / 1000.0;
|
||||
break;
|
||||
case lppFrequency:
|
||||
channelData['values']['frequency'] = buffer.readUInt32BE();
|
||||
break;
|
||||
case lppPercentage:
|
||||
channelData['values']['percentage'] = buffer.readUInt8();
|
||||
break;
|
||||
@@ -249,6 +397,32 @@ class CayenneLpp {
|
||||
case lppPower:
|
||||
channelData['values']['power'] = buffer.readUInt16BE();
|
||||
break;
|
||||
case lppDistance:
|
||||
channelData['values']['distance'] = buffer.readUInt32BE() / 1000.0;
|
||||
break;
|
||||
case lppEnergy:
|
||||
channelData['values']['energy'] = buffer.readUInt32BE() / 1000.0;
|
||||
break;
|
||||
case lppDirection:
|
||||
channelData['values']['direction'] = buffer.readUInt16BE();
|
||||
break;
|
||||
case lppUnixTime:
|
||||
channelData['values']['time'] = buffer.readUInt32BE();
|
||||
break;
|
||||
case lppGyrometer:
|
||||
channelData['values']['gyrometer'] = {
|
||||
'x': buffer.readInt16BE() / 100.0,
|
||||
'y': buffer.readInt16BE() / 100.0,
|
||||
'z': buffer.readInt16BE() / 100.0,
|
||||
};
|
||||
break;
|
||||
case lppColour:
|
||||
channelData['values']['colour'] = {
|
||||
'red': buffer.readUInt8(),
|
||||
'green': buffer.readUInt8(),
|
||||
'blue': buffer.readUInt8(),
|
||||
};
|
||||
break;
|
||||
case lppGps:
|
||||
channelData['values']['gps'] = {
|
||||
'latitude': buffer.readInt24BE() / 10000.0,
|
||||
@@ -256,22 +430,48 @@ class CayenneLpp {
|
||||
'altitude': buffer.readInt24BE() / 100.0,
|
||||
};
|
||||
break;
|
||||
// Add more types as needed...
|
||||
case lppSwitch:
|
||||
channelData['values']['switch'] = buffer.readUInt8() != 0;
|
||||
break;
|
||||
case lppPolyline:
|
||||
final size = buffer.readUInt8();
|
||||
channelData['values']['polyline'] = {
|
||||
'size': size,
|
||||
'data': _bytesToHex(_readPolylinePayload(buffer, size)),
|
||||
};
|
||||
break;
|
||||
default:
|
||||
//Stopped parsing to avoid misalignment
|
||||
return channels.values.toList();
|
||||
// Stop parsing to avoid losing alignment on an unknown LPP type.
|
||||
return _sortedChannelValues(channels);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Map<String, dynamic>> channelsOut = channels.values.toList();
|
||||
channelsOut.sort((a, b) => a['channel'].compareTo(b['channel']));
|
||||
return channelsOut;
|
||||
return _sortedChannelValues(channels);
|
||||
} catch (e) {
|
||||
// Handle parsing errors, possibly due to malformed data
|
||||
appLogger.error('Error parsing Cayenne LPP data: $e');
|
||||
return <
|
||||
Map<String, dynamic>
|
||||
>[]; // Return an empty list on error to avoid crashing the app
|
||||
// Preserve any fields parsed before the malformed value.
|
||||
return _sortedChannelValues(channels);
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8List _readPolylinePayload(BufferReader buffer, int size) {
|
||||
final declaredPayloadSize = size > 0 ? size - 1 : 0;
|
||||
final availablePayloadSize = declaredPayloadSize <= buffer.remaining
|
||||
? declaredPayloadSize
|
||||
: buffer.remaining;
|
||||
return buffer.readBytes(availablePayloadSize);
|
||||
}
|
||||
|
||||
static List<Map<String, dynamic>> _sortedChannelValues(
|
||||
Map<int, Map<String, dynamic>> channels,
|
||||
) {
|
||||
final channelsOut = channels.values.toList();
|
||||
channelsOut.sort((a, b) => a['channel'].compareTo(b['channel']));
|
||||
return channelsOut;
|
||||
}
|
||||
|
||||
static String _bytesToHex(Uint8List bytes) {
|
||||
return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,25 @@ class ChatScrollController extends ScrollController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Jumps toward an off-screen message so that lazy ListView.builder builds
|
||||
/// items near it. Only visible + cacheExtent items have real heights, so we
|
||||
/// use proportion of maxScrollExtent (itself an estimate from built items'
|
||||
/// avg height). Call [onJumped] on the next frame to ensureVisible/scroll
|
||||
/// to the exact target.
|
||||
void jumpToEstimatedOffset({
|
||||
required int unreadCount,
|
||||
required int totalMessages,
|
||||
required VoidCallback onJumped,
|
||||
}) {
|
||||
if (!hasClients || totalMessages == 0) return;
|
||||
final maxExtent = position.maxScrollExtent;
|
||||
final jumpOffset = maxExtent * (unreadCount / totalMessages);
|
||||
if (jumpOffset > 100) {
|
||||
jumpTo(jumpOffset);
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => onJumped());
|
||||
}
|
||||
|
||||
void scrollToBottomIfAtBottom() {
|
||||
// Only scroll if jump button is NOT showing (i.e., already at bottom)
|
||||
if (!showJumpToBottom.value && hasClients && position.maxScrollExtent > 0) {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../utils/emoji_utils.dart';
|
||||
|
||||
IconData contactTypeIcon(int type) {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return Icons.chat;
|
||||
case advTypeRepeater:
|
||||
return Icons.cell_tower;
|
||||
case advTypeRoom:
|
||||
return Icons.group;
|
||||
case advTypeSensor:
|
||||
return Icons.sensors;
|
||||
default:
|
||||
return Icons.device_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
Color contactTypeColor(int type) {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return Colors.blue;
|
||||
case advTypeRepeater:
|
||||
return Colors.orange;
|
||||
case advTypeRoom:
|
||||
return Colors.purple;
|
||||
case advTypeSensor:
|
||||
return Colors.green;
|
||||
default:
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
Color colorForName(String name) {
|
||||
const colors = [
|
||||
Colors.blue,
|
||||
Colors.green,
|
||||
Colors.orange,
|
||||
Colors.purple,
|
||||
Colors.pink,
|
||||
Colors.teal,
|
||||
Colors.indigo,
|
||||
Colors.cyan,
|
||||
Colors.amber,
|
||||
Colors.deepOrange,
|
||||
];
|
||||
return colors[name.hashCode.abs() % colors.length];
|
||||
}
|
||||
|
||||
String firstCharacterOrEmoji(String name) {
|
||||
if (name.isEmpty) return '?';
|
||||
final emoji = firstEmoji(name);
|
||||
if (emoji != null) return emoji;
|
||||
final runes = name.runes.toList();
|
||||
if (runes.isEmpty) return '?';
|
||||
return String.fromCharCode(runes[0]).toUpperCase();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
class Cyr2Lat {
|
||||
static Map<String, String> _charMap = {
|
||||
'А': 'A',
|
||||
'В': 'B',
|
||||
'Е': 'E',
|
||||
'Ё': 'E',
|
||||
'З': '3',
|
||||
'К': 'K',
|
||||
'М': 'M',
|
||||
'Н': 'H',
|
||||
'О': 'O',
|
||||
'Р': 'P',
|
||||
'С': 'C',
|
||||
'Т': 'T',
|
||||
'Х': 'X',
|
||||
'Ь': 'b',
|
||||
'а': 'a',
|
||||
'е': 'e',
|
||||
'ё': 'e',
|
||||
'о': 'o',
|
||||
'р': 'p',
|
||||
'с': 'c',
|
||||
'у': 'y',
|
||||
'х': 'x',
|
||||
};
|
||||
|
||||
static final RegExp _prefixRegExp = RegExp(r'\@\[[\S\s]+\] ');
|
||||
|
||||
static void setCharMap(Map<String, String> charMap) {
|
||||
_charMap = Map.from(charMap);
|
||||
}
|
||||
|
||||
static String encode(String text) {
|
||||
if (text.isEmpty) return text;
|
||||
final buffer = StringBuffer();
|
||||
|
||||
final senderName = extractSenderName(text);
|
||||
final msgText = removeSenderName(text);
|
||||
|
||||
for (final rune in msgText.runes) {
|
||||
final char = String.fromCharCode(rune);
|
||||
buffer.write(_charMap[char] ?? char);
|
||||
}
|
||||
|
||||
return senderName + buffer.toString();
|
||||
}
|
||||
|
||||
static String removeSenderName(String text) {
|
||||
final match = _prefixRegExp.matchAsPrefix(text);
|
||||
if (match != null) {
|
||||
return text.substring(match.end);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
static String extractSenderName(String text) {
|
||||
final match = _prefixRegExp.matchAsPrefix(text);
|
||||
if (match != null) {
|
||||
return match.group(0) ?? '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -8,24 +8,29 @@ class PathHelper {
|
||||
.join(',');
|
||||
}
|
||||
|
||||
static String hopHex(int byte) {
|
||||
return byte.toRadixString(16).padLeft(2, '0').toUpperCase();
|
||||
}
|
||||
|
||||
static String? hopName(int byte, List<Contact> allContacts) {
|
||||
final matches = allContacts
|
||||
.where(
|
||||
(c) =>
|
||||
c.publicKey.first == byte &&
|
||||
(c.type == advTypeRepeater || c.type == advTypeRoom),
|
||||
)
|
||||
.toList();
|
||||
if (matches.isEmpty) return null;
|
||||
if (matches.length == 1) return matches.first.name;
|
||||
return matches.map((c) => c.name).join(' | ');
|
||||
}
|
||||
|
||||
static String resolvePathNames(
|
||||
List<int> pathBytes,
|
||||
List<Contact> allContacts,
|
||||
) {
|
||||
return pathBytes
|
||||
.map((b) {
|
||||
final hex = b.toRadixString(16).padLeft(2, '0').toUpperCase();
|
||||
final matches = allContacts
|
||||
.where(
|
||||
(c) =>
|
||||
c.publicKey.first == b &&
|
||||
(c.type == advTypeRepeater || c.type == advTypeRoom),
|
||||
)
|
||||
.toList();
|
||||
if (matches.isEmpty) return hex;
|
||||
if (matches.length == 1) return matches.first.name;
|
||||
return matches.map((c) => c.name).join(' | ');
|
||||
})
|
||||
.map((b) => hopName(b, allContacts) ?? hopHex(b))
|
||||
.join(' \u2192 ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../models/contact.dart';
|
||||
|
||||
class PathHopResolver {
|
||||
const PathHopResolver._();
|
||||
|
||||
static List<Contact?> resolve({
|
||||
required List<int> pathBytes,
|
||||
required List<Contact> contacts,
|
||||
LatLng? endpoint,
|
||||
bool resolveFromEnd = false,
|
||||
}) {
|
||||
final candidatesByPrefix = <int, List<Contact>>{};
|
||||
for (final contact in contacts) {
|
||||
if (contact.publicKey.isEmpty) continue;
|
||||
if (contact.type != advTypeRepeater && contact.type != advTypeRoom) {
|
||||
continue;
|
||||
}
|
||||
candidatesByPrefix
|
||||
.putIfAbsent(contact.publicKey.first, () => <Contact>[])
|
||||
.add(contact);
|
||||
}
|
||||
for (final candidates in candidatesByPrefix.values) {
|
||||
candidates.sort((a, b) => b.lastSeen.compareTo(a.lastSeen));
|
||||
}
|
||||
|
||||
final resolved = List<Contact?>.filled(pathBytes.length, null);
|
||||
final indexes = resolveFromEnd
|
||||
? List<int>.generate(pathBytes.length, (i) => pathBytes.length - 1 - i)
|
||||
: List<int>.generate(pathBytes.length, (i) => i);
|
||||
final distance = Distance();
|
||||
var previousPosition = endpoint;
|
||||
|
||||
for (final index in indexes) {
|
||||
final candidates = candidatesByPrefix[pathBytes[index]];
|
||||
if (candidates == null || candidates.isEmpty) continue;
|
||||
|
||||
var bestIndex = 0;
|
||||
if (previousPosition != null && candidates.length > 1) {
|
||||
double? nearestDistance;
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
final position = _positionOf(candidates[i]);
|
||||
if (position == null) continue;
|
||||
final candidateDistance = distance(previousPosition, position);
|
||||
if (nearestDistance == null || candidateDistance < nearestDistance) {
|
||||
nearestDistance = candidateDistance;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final contact = candidates.removeAt(bestIndex);
|
||||
resolved[index] = contact;
|
||||
previousPosition = _positionOf(contact) ?? previousPosition;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
static LatLng? _positionOf(Contact contact) {
|
||||
if (!contact.hasLocation ||
|
||||
contact.latitude == null ||
|
||||
contact.longitude == null) {
|
||||
return null;
|
||||
}
|
||||
return LatLng(contact.latitude!, contact.longitude!);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,19 @@ void showDismissibleSnackBar(
|
||||
DismissDirection? dismissDirection,
|
||||
Clip? clipBehavior,
|
||||
}) {
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
// Callers often reach here after an async gap; the context may already be
|
||||
// unmounted, or deactivated (popped but not yet disposed) — ancestor
|
||||
// lookups on a deactivated element throw. Showing nothing is the right
|
||||
// outcome in both cases.
|
||||
if (!context.mounted) return;
|
||||
var isActive = true;
|
||||
assert(() {
|
||||
isActive = (context as Element).debugIsActive;
|
||||
return true;
|
||||
}());
|
||||
if (!isActive) return;
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
if (messenger == null) return;
|
||||
messenger.showSnackBar(
|
||||
SnackBar(
|
||||
key: key,
|
||||
|
||||
+408
-28
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Изтрий",
|
||||
"common_enable": "Активирай",
|
||||
"common_disable": "Деактивирай",
|
||||
"common_autoRefresh": "Автоматично обновяване",
|
||||
"common_interval": "Интервал",
|
||||
"common_reboot": "Рестартирай",
|
||||
"common_loading": "Зареждане...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – Отворена версия",
|
||||
"scanner_scanning": "Сканиране за устройства...",
|
||||
"scanner_connecting": "Свързвам се...",
|
||||
"scanner_disconnecting": "Изключване...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Режим на поверителност е активиран",
|
||||
"settings_privacyModeDisabled": "Режим на поверителност е деактивиран",
|
||||
"settings_actions": "Действия",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Изпрати Реклама",
|
||||
"settings_sendAdvertisementSubtitle": "Сега присъствие в ефир",
|
||||
"settings_advertisementSent": "Реклама изпратена",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Лог на отстраняване на грешки на приложението",
|
||||
"settings_appDebugLogSubtitle": "Съобщения за отстраняване на грешки на приложението",
|
||||
"settings_about": "За нас",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open, версия {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -140,7 +144,7 @@
|
||||
"settings_infoChannelCount": "Брой канали",
|
||||
"settings_presets": "Предварителни настройки",
|
||||
"settings_frequency": "Честота (MHz)",
|
||||
"settings_frequencyHelper": "300.0 - 2500.0",
|
||||
"settings_frequencyHelper": "300,0 – 2500,0",
|
||||
"settings_frequencyInvalid": "Невалидна честота (300-2500 MHz)",
|
||||
"settings_bandwidth": "Ширина на честотния спектър",
|
||||
"settings_spreadingFactor": "Фактор на разпространение",
|
||||
@@ -164,18 +168,18 @@
|
||||
"appSettings_themeDark": "Тъмно",
|
||||
"appSettings_language": "Език",
|
||||
"appSettings_languageSystem": "Система по подразбиране",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageEn": "Английски",
|
||||
"appSettings_languageFr": "Френски",
|
||||
"appSettings_languageEs": "Испански",
|
||||
"appSettings_languageDe": "Немски",
|
||||
"appSettings_languagePl": "Полски",
|
||||
"appSettings_languageSl": "Словенски език",
|
||||
"appSettings_languagePt": "Португалски",
|
||||
"appSettings_languageIt": "Италиански",
|
||||
"appSettings_languageZh": "Китайски",
|
||||
"appSettings_languageSv": "Шведски",
|
||||
"appSettings_languageNl": "Хололандски",
|
||||
"appSettings_languageSk": "Словенски",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_notifications": "Уведомления",
|
||||
"appSettings_enableNotifications": "Активирай Известия",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Канал с хаштаг",
|
||||
"channels_public": "Публично",
|
||||
"channels_private": "Личен",
|
||||
"channels_publicChannel": "Публичен канал",
|
||||
"channels_privateChannel": "Частен канал",
|
||||
"channels_editChannel": "Редактирай канал",
|
||||
"channels_muteChannel": "Заглуши канала",
|
||||
"channels_unmuteChannel": "Включи известията на канала",
|
||||
@@ -367,7 +368,7 @@
|
||||
"channels_channelName": "Име на канала",
|
||||
"channels_usePublicChannel": "Използвайте публичен канал",
|
||||
"channels_standardPublicPsk": "Стандартен публичен PSK",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (шестнадесетичен код)",
|
||||
"channels_generateRandomPsk": "Генерирай случайна PSK",
|
||||
"channels_enterChannelName": "Моля, въведете име на канал.",
|
||||
"channels_pskMustBe32Hex": "PSK трябва да бъде 32 шестнаредни знака.",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Компресия SMAZ",
|
||||
"channels_cyr2latCompression": "Компресия Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Заменя някои кирилични символи с латиница при изпращане.",
|
||||
"channels_cyr2latSettingsHeading": "Настройки на Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Списък със замествания",
|
||||
"channels_cyr2latSettingsDscr": "Редактиране на JSON конфигурацията за заместване на символи",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON карта за замествания",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Неправилен JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Добавяне на профил Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Име на профила",
|
||||
"settings_cyr2latProfileNameEmpty": "Името на профила не може да бъде празно",
|
||||
"settings_cyr2latProfileAdded": "Профилът е добавен успешно",
|
||||
"settings_cyr2latProfileUpdated": "Профилът е актуализиран успешно",
|
||||
"settings_cyr2latProfileEdit": "Редактиране на Cyr2Lat профил",
|
||||
"settings_cyr2latProfileDelete": "Изтриване на профил Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Профилът беше изтрит успешно",
|
||||
"settings_cyr2latProfileDeleteDscr": "Сигурен ли сте, че искате да изтриете профила \"{name}\"?",
|
||||
"channels_channelUpdated": "Каналът \"{name}\" е актуализиран",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Публичен канал добавен",
|
||||
"channels_sortBy": "Сортирай по",
|
||||
"channels_sortManual": "Ръчно",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "От A до Я",
|
||||
"channels_sortLatestMessages": "Последни съобщения",
|
||||
"channels_sortUnread": "Непрочетено",
|
||||
"chat_noMessages": "Няма съобщения.",
|
||||
@@ -477,7 +494,7 @@
|
||||
"debugLog_noEntries": "Все още няма дебъг логове.",
|
||||
"debugLog_enableInSettings": "Активирайте отстраняване на грешки в настройките на приложението",
|
||||
"debugLog_frames": "Рамки",
|
||||
"debugLog_rawLogRx": "Raw Log-RX",
|
||||
"debugLog_rawLogRx": "Необработен лог-RX",
|
||||
"debugLog_noBleActivity": "Няма BLE активност към момента.",
|
||||
"debugFrame_length": "Дължина на кадъра: {count} байта",
|
||||
"@debugFrame_length": {
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Команден ред (CLI)",
|
||||
"debugFrame_textTypePlain": "Просто",
|
||||
"debugFrame_text": "- Текст: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "Историята на пътя е пълна. Премахнете записи, за да добавите нови.",
|
||||
"chat_hopSingular": "скочи",
|
||||
"chat_hopPlural": "скоци",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{скача} other{скача}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -883,7 +900,7 @@
|
||||
"repeater_statusSubtitle": "Прегледайте статуса, статистиката и съседните устройства.",
|
||||
"repeater_telemetry": "Телеметрия",
|
||||
"repeater_telemetrySubtitle": "Прегледайте телеметрията на сензорите и системните статистики",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Команден ред (CLI)",
|
||||
"repeater_cliSubtitle": "Изпрати команди към ретранслатора",
|
||||
"repeater_settings": "Настройки",
|
||||
"repeater_settingsSubtitle": "Конфигурирайте параметрите на репитера",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "БеПотвърди",
|
||||
"repeater_settingsSaved": "Настройките са запазени успешно.",
|
||||
"repeater_rxGain": "Увеличен коефициент на възвръщаемост (RX)",
|
||||
"repeater_rxGainHelper": "По-висока чувствителност, по-голям ток (само за SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Възстановете повишената ефективност на RX",
|
||||
"repeater_multiAcks": "Множество потвърждения",
|
||||
"repeater_multiAcksSubtitle": "Признавайте съобщения по множество канали за по-добро доставяне.",
|
||||
"repeater_refreshMultiAcks": "Обновете множество потвърждения",
|
||||
"repeater_networkHealth": "Състояние на мрежата",
|
||||
"repeater_loopDetect": "Откриване на цикли",
|
||||
"repeater_loopDetectHelper": "Изпратете пакети, които изглеждат като цикли в маршрутизацията.",
|
||||
"repeater_loopDetectOff": "Изключено",
|
||||
"repeater_loopDetectMinimal": "Минимален",
|
||||
"repeater_loopDetectModerate": "Умерен",
|
||||
"repeater_loopDetectStrict": "Строг",
|
||||
"repeater_dutyCycle": "Цикъл на работа/почивка",
|
||||
"repeater_dutyCycleHelper": "Максимален процент на използване на времето на въздуха",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Информация за оператора",
|
||||
"repeater_ownerInfoHelper": "Публични метаданни за този репитер",
|
||||
"repeater_refreshOwnerInfo": "Обновете информацията за оператора",
|
||||
"repeater_floodMax": "Максимален брой скачания при наводнение",
|
||||
"repeater_floodMaxHelper": "Максималният брой пакети, които един поток може да пренесе (0-64)",
|
||||
"repeater_advancedSettings": "Напреднал",
|
||||
"repeater_advancedSettingsSubtitle": "Регулаторни копчета за опитни оператори",
|
||||
"repeater_pathHashMode": "Режим за хеширане на пътища",
|
||||
"repeater_pathHashModeHelper": "Байтовете, използвани за кодиране на идентификатора на този репитер в таговете за откриване на потоци/цикли, са: 0=1 байт (256 идентификатора, до 64 скача), 1=2 байта (65 000 идентификатора, до 32 скача), 2=3 байта (16 милиона идентификатора, до 21 скача). Версии 1.13 и по-стари версии на фърмуера използват многобайтови пътища – само след като мрежата е актуализирана до версия 1.14 или по-нова.",
|
||||
"repeater_txDelay": "Забавяне на проекта \"Flood TX\"",
|
||||
"repeater_txDelayHelper": "Предавайте разстоянието между пакетите за трафик при наводнения, като множител на времето за пренос на пакета (0-2, по подразбиране 0.5). По-висока стойност означава по-малко сблъсъци, но по-бавно предаване.",
|
||||
"repeater_directTxDelay": "Директно забавяне на сигнала",
|
||||
"repeater_directTxDelayHelper": "Предаване на интервали за директен (не-масивен) трафик, като множител на времето за пренос на пакета (0-2, по подразбиране 0.3).",
|
||||
"repeater_intThresh": "Праг на интерференция",
|
||||
"repeater_intThreshHelper": "Прагът е зададен на нивото на шума на радиото, така че да отхвърля смущения, които са над този праг. 0 – изключва; активирайте само, ако забележите грешки в шумна честотна лента.",
|
||||
"repeater_agcResetInterval": "Интервал за рестартиране на AGC",
|
||||
"repeater_agcResetIntervalHelper": "Колко често да се рестартира автоматичната настройка на усилването, за да се възстанови от състояние, в което усилването е блокирано. Времето за рестартиране е няколко секунди, като се определя като кратна на 4. 0 деактивира периодичното рестартиране.",
|
||||
"repeater_actionsTitle": "Действия",
|
||||
"repeater_sendAdvert": "Изпратете реклама за навод",
|
||||
"repeater_sendAdvertSubtitle": "Публикувайте реклама за навод в мрежата.",
|
||||
"repeater_sendAdvertZeroHop": "Изпратете реклама без преминаване през други системи",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Публикувайте реклама, която достига до целевата аудитория само чрез директно разпространение (без използване на посредници).",
|
||||
"repeater_clockSync": "Синхронизиране на часовника сега",
|
||||
"repeater_clockSyncSubtitle": "Настройте времето на телефона си да съвпада с времето на репитера.",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Настройки запаметени – рестартирайте ретранслатора, за да ги приложите.",
|
||||
"repeater_settingsPartialFailure": "Някои настройки не успяха: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Грешка при запазване на настройките: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Обнови Основни Настройки",
|
||||
"repeater_refreshRadioSettings": "Обнови настройките на радиопредавателите",
|
||||
"repeater_refreshTxPower": "Обнови TX захранване",
|
||||
"repeater_refreshLocationSettings": "Обнови настройките на местоположението",
|
||||
"repeater_refreshPacketForwarding": "Обнови пакетно пренасочване",
|
||||
"repeater_refreshGuestAccess": "Обнови достъп за гости",
|
||||
"repeater_refreshPrivacyMode": "Обнови Режим на поверителност",
|
||||
"repeater_refreshAdvertisementSettings": "Обнови Настройки на Рекламата",
|
||||
"repeater_refreshed": "{label} е обновено",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Цифров вход",
|
||||
"telemetry_digitalOutputLabel": "Цифров изход",
|
||||
"telemetry_analogInputLabel": "Аналогов вход",
|
||||
"telemetry_analogOutputLabel": "Аналогов изход",
|
||||
"telemetry_genericLabel": "Общ сензор",
|
||||
"telemetry_luminosityLabel": "Осветеност",
|
||||
"telemetry_presenceLabel": "Присъствие",
|
||||
"telemetry_humidityLabel": "Влажност",
|
||||
"telemetry_accelerometerLabel": "Акселерометър",
|
||||
"telemetry_pressureLabel": "Налягане",
|
||||
"telemetry_altitudeLabel": "Надморска височина",
|
||||
"telemetry_frequencyLabel": "Честота",
|
||||
"telemetry_percentageLabel": "Процент",
|
||||
"telemetry_concentrationLabel": "Концентрация",
|
||||
"telemetry_powerLabel": "Мощност",
|
||||
"telemetry_distanceLabel": "Разстояние",
|
||||
"telemetry_energyLabel": "Енергия",
|
||||
"telemetry_directionLabel": "Посока",
|
||||
"telemetry_timeLabel": "Време",
|
||||
"telemetry_gyrometerLabel": "Жироскоп",
|
||||
"telemetry_colourLabel": "Цвят",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Превключвател",
|
||||
"telemetry_polylineLabel": "Полилиния",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Брой заявки",
|
||||
"telemetry_error": "Неуспешно получаване на данни",
|
||||
"telemetry_noData": "Няма налични данни за телеметрията.",
|
||||
"telemetry_channelTitle": "Канал {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Сортирай по",
|
||||
"listFilter_latestMessages": "Последни съобщения",
|
||||
"listFilter_heardRecently": "Слушано е наскоро",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "А-Я",
|
||||
"listFilter_filters": "Филтри",
|
||||
"listFilter_all": "Всички",
|
||||
"listFilter_users": "Потребители",
|
||||
@@ -2011,6 +2138,9 @@
|
||||
"translation_composerTitle": "Преведете преди да изпратите",
|
||||
"translation_enableSubtitle": "Превеждайте входящите съобщения и позволявайте предварително превеждане преди изпращане.",
|
||||
"translation_composerSubtitle": "Контролира началния статус на иконата за превод, създадена от композитора.",
|
||||
"translation_autoIncomingTitle": "Автоматичен превод на съобщения",
|
||||
"translation_autoIncomingSubtitle": "Превежда автоматично съобщенията за известия, както и за чатове или канали.",
|
||||
"translation_translateMessage": "Преведи съобщението",
|
||||
"translation_targetLanguage": "Целеви език",
|
||||
"translation_useAppLanguage": "Използвайте езика на приложението",
|
||||
"translation_downloadedModelLabel": "Изтегнат модел",
|
||||
@@ -2066,5 +2196,255 @@
|
||||
"room_guest": "Информация за сървъра на стаята",
|
||||
"repeater_guest": "Информация за ретранслаторите",
|
||||
"repeater_guestTools": "Инструменти за гости",
|
||||
"settings_multiAck": "Множество потвърждения"
|
||||
"repeater_getCategory": "Получете стойности",
|
||||
"repeater_powerMgmt": "Управление на енергията",
|
||||
"repeater_sensors": "Датчици",
|
||||
"repeater_cliHelpPowerOff": "Изключва устройството. (не се очаква отговор)",
|
||||
"repeater_cliHelpClkReboot": "Възстановява часовника до известна историческа дата и рестартира устройството.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Изпраща реклама, която достига само до съседни устройства (само до съседни мрежи).",
|
||||
"repeater_cliHelpStartOta": "Стартира актуализация на фърмуера чрез въздушното, на всички поддържани платки.",
|
||||
"repeater_cliHelpTime": "Задава времето на устройството към зададените секунди от началото на Unix ерата. Времето не може да се върне назад.",
|
||||
"repeater_cliHelpBoard": "Показва производителя на платката / идентификатора на хардуера.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Изпраща заявка за откриване на съседни възли. (Само за устройства тип репитер)",
|
||||
"repeater_cliHelpPowersaving": "Показва дали режимът за пестене на енергия е активиран или деактивиран.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Активира или деактивира режима за пестене на енергия (ако е поддържан).",
|
||||
"repeater_cliHelpErase": "(Само за серийни устройства) Форматира файловата система на устройството. Изтрива всички настройки и контакти.",
|
||||
"repeater_cliHelpSetDutyCycle": "Задава максимално допустимия процент на използване на времето за предаване (от 1 до 100 процента). Вътрешно коригира фактора за времето на предаване.",
|
||||
"repeater_cliHelpSetPrvKey": "(Само за серийни номера) Заменя личната част от ключа за идентификация на устройството. Необходимо е да се рестартира устройството, за да се приложи. Генерира нов публичен ключ.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Само за SX126x) Превключва усиления на приемния сигнал (RX gain) за подобрена чувствителност при по-високо потребление на ток.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Задава низовете с информация за контакт на собственика, които са включени в рекламите. Използвайте '|' за нови редове.",
|
||||
"repeater_cliHelpSetPathHashMode": "Задава режима за хеширане на пътищата. 0 = за стари системи, 1 = за стандартни системи, 2 = за строги системи. Влияе върху начина, по който се съпоставят маршрутите.",
|
||||
"repeater_cliHelpSetLoopDetect": "Задава чувствителността за откриване на цикли в маршрутизацията: изключена, минимална, умерена или строга.",
|
||||
"repeater_cliHelpSetFreq": "(Само за серийно управление) Бързо задава само честотата. Необходимо е рестартиране. Препоръчително е да се използват настройките за \"радио\", за да се зададат всички параметри.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Само за моста ESPNow) Определя WiFi канала (от 1 до 14), използван от моста.",
|
||||
"repeater_cliHelpGetName": "Показва зададеното име на възела.",
|
||||
"repeater_cliHelpGetRole": "Показва ролята на фърмуера (например, репитер, сървър за стая и т.н.).",
|
||||
"repeater_cliHelpGetPublicKey": "Показва публичния ключ на устройството.",
|
||||
"repeater_cliHelpGetPrvKey": "(Само за серийния номер) Показва личната ключа на устройството. Трябва да се третира като тайна.",
|
||||
"repeater_cliHelpGetRepeat": "Показва дали функцията за пренасочване на пакети (ролята на репитер) е активирана или деактивирана.",
|
||||
"repeater_cliHelpGetTx": "Показва текущата мощност на TX в dBm.",
|
||||
"repeater_cliHelpGetFreq": "Показва зададената честота в MHz.",
|
||||
"repeater_cliHelpGetRadio": "Показва пълните радио параметри: честота, ширина на честотния обхват, фактор на разпространение, скорост на кодиране.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Само за SX126x) Показва състоянието на усиления сигнал на RX.",
|
||||
"repeater_cliHelpGetAf": "Показва текущия коефициент на въздействие върху въздуха.",
|
||||
"repeater_cliHelpGetDutyCycle": "Показва текущия допустим цикъл на работа като процент.",
|
||||
"repeater_cliHelpGetIntThresh": "Показва прага на интерференцията на канала в децибели (dB).",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Показва интервала за рестартиране на AGC в секунди.",
|
||||
"repeater_cliHelpGetMultiAcks": "Показва дали режимът \"двоен ACK\" е активиран (1) или деактивиран (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Показва дали е разрешено само четене за гостите.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Показва времето на рекламата в минути.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Показва интервала на рекламата за навод в часове.",
|
||||
"repeater_cliHelpGetGuestPassword": "Показва зададения парол за гост.",
|
||||
"repeater_cliHelpGetLat": "Показва зададената географска ширина.",
|
||||
"repeater_cliHelpGetLon": "Показва зададената дължина.",
|
||||
"repeater_cliHelpGetRxDelay": "Показва основната стойност на забавянето на сигнала.",
|
||||
"repeater_cliHelpGetTxDelay": "Показва коефициента за забавяне при режим на наводняване.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Показва коефициента за забавяне при директен режим.",
|
||||
"repeater_cliHelpGetFloodMax": "Показва максималния брой на повторни наводнения.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Показва информацията за контакт на собственика.",
|
||||
"repeater_cliHelpGetPathHashMode": "Показва режима на хеширане на пътя (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Показва чувствителността към откриване на цикли.",
|
||||
"repeater_cliHelpGetAcl": "(Само за серийни номера) Изброява настройките за контрол на достъпа в репитера.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Показва дали мостът е активиран.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Показва забавянето на моста в милисекунди.",
|
||||
"repeater_cliHelpGetBridgeSource": "Показва дали мостът изпраща или получава пакети RX или TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Само за мост RS232) Показва скоростта на предаване на данните на моста.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Само за моста ESPNow) Показва канала на WiFi на моста.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Само за моста ESPNow) Показва споделения секрет на моста.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Само за NRF52) Показва версията на зареждащия софтуер.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Показва множителя на аналоговия-цифров преобразувател (мащабиране на напрежението от батерията).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Описва дали борда на директорите има поддръжка за управление на захранването.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Показва текущия източник на захранване: външен или батерия.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Показва най-скорошните причини за рестартиране и изключване.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Показва напрежението на батерията при стартиране, измерено в миливолта (mV).",
|
||||
"repeater_cliHelpSensorGet": "Чете персонализирана настройка на сензор чрез клавиш.",
|
||||
"repeater_cliHelpSensorSet": "Създава персонализирана настройка за сензор.",
|
||||
"repeater_cliHelpSensorList": "Показва всички настройки на потребителските сензори, разделени на страници, започвайки от опционален индекс.",
|
||||
"repeater_cliHelpRegionDefault": "Показва текущия обхват на региона по подразбиране.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Задава обхвата на региона по подразбиране. Използвайте \"<null>\", за да го изчистите.",
|
||||
"repeater_cliHelpRegionListAllowed": "Списва регионите, които позволяват преминаване на превозни средства при наводнение.",
|
||||
"repeater_cliHelpRegionListDenied": "Списва региони, които забраняват движението по пътищата при наводнения.",
|
||||
"repeater_cliHelpStatsPackets": "(Само за серия) Показва статистически данни на ниво пакет.",
|
||||
"repeater_cliHelpStatsRadio": "(Само за конкретен сериал) Показва радиостатистика.",
|
||||
"repeater_cliHelpStatsCore": "(Само за серийния номер) Показва основните статистически данни за фърмуера.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Множество потвърждения",
|
||||
"map_sharedAt": "Споделено",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Избрано препятствие",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "Кликнете върху блокираната точка, за да я отбележите на картата.",
|
||||
"losBlockedSpotsTitle": "Ограничени места",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"chat_markAsUnread": "Отбелязване като непрочетено",
|
||||
"settings_companionDebugLogSubtitle": "Команди, отговори и сурови данни за протоколите BLE/TCP/USB",
|
||||
"chat_newMessages": "Нови съобщения",
|
||||
"settings_companionDebugLog": "Лог за отстраняване на грешки (за съпътстваща програма)",
|
||||
"repeater_chanUtil": "Използване на канала",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_pending": "Изпращане",
|
||||
"common_undo": "Отмяни",
|
||||
"messageStatus_delivered": "Доставен",
|
||||
"messageStatus_sent": "Изпратено",
|
||||
"messageStatus_failed": "Не успях да изпратя",
|
||||
"messageStatus_repeated": "Слушах го многократно",
|
||||
"contacts_moreOptions": "Повече възможности",
|
||||
"contacts_searchOpen": "Търсене на контакти",
|
||||
"contacts_searchClose": "Затвори търсене",
|
||||
"routing_title": "Маршрутизиране",
|
||||
"routing_modeAuto": "Автомобил",
|
||||
"routing_modeFlood": "Наводнение",
|
||||
"routing_modeManual": "Ръководство",
|
||||
"routing_modeAutoHint": "Автоматично избира най-известния път, като при липса на информация, използва стратегия за \"запълване\" на празните пространства.",
|
||||
"routing_modeFloodHint": "Излъчване през всички ретранслатори. Най-надежният начин, но изисква повече време на въздуха.",
|
||||
"routing_modeManualHint": "Винаги следва точно пътя, който сте определили.",
|
||||
"routing_currentRoute": "Текущ маршрут",
|
||||
"routing_directNoHops": "Директ – без превключватели",
|
||||
"routing_noPathYet": "Все още няма път. Съобщението продължава да се изпраща, докато не бъде открит маршрут.",
|
||||
"routing_floodBroadcast": "Предаване през всички ретранслатори",
|
||||
"routing_editPath": "Редактиране на пътя",
|
||||
"routing_forgetPath": "Забравете за пътя",
|
||||
"routing_knownPaths": "Известни маршрути",
|
||||
"routing_knownPathsHint": "Натиснете бутона, за да превключите към него.",
|
||||
"routing_inUse": "В експлоатация",
|
||||
"routing_qualityStrong": "Силен първи скок",
|
||||
"routing_qualityGood": "Добър първи опит",
|
||||
"routing_qualityFair": "Първият добър скок",
|
||||
"routing_qualityWorked": "Беше изпълнено/Доведено до край",
|
||||
"routing_qualityFlood": "Получено чрез информация, разпространена в резултат на навод.",
|
||||
"routing_qualityUntested": "Не тестван",
|
||||
"routing_neverWorked": "никога не е потвърдено",
|
||||
"routing_floodDelivery": "Доставка при навод",
|
||||
"pathEditor_title": "Създаване на път",
|
||||
"pathEditor_hopCounter": "{count} от 64 различни вида малц",
|
||||
"pathEditor_noHops": "Все още няма добавени хмел. Можете да използвате бутоните по-долу, за да ги добавите по ред, или да запазите рецептата без хмел, за да я изпратите директно.",
|
||||
"pathEditor_addHops": "Добавете хмела в реда, в който е посочено.",
|
||||
"pathEditor_searchRepeaters": "Търсене на повтори",
|
||||
"pathEditor_advancedHex": "Разширено: необработен шестничен път",
|
||||
"pathEditor_hexLabel": "Префикси на шестнадесетична система",
|
||||
"pathEditor_hexHelper": "Два шест-символни идентификатора на скок, разделени със запетаи",
|
||||
"pathEditor_invalidTokens": "Невалидно: {tokens}",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_tooManyHops": "Максимум 64 крачета",
|
||||
"pathEditor_usePath": "Използвайте този маршрут.",
|
||||
"pathEditor_removeHop": "Премахнете хмела",
|
||||
"pathEditor_unknownHop": "Неизвестен репитер",
|
||||
"map_zoomIn": "Увеличи",
|
||||
"map_zoomOut": "Приближете се по-малко",
|
||||
"map_centerMap": "Карта на центъра",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth изисква браузър, базиран на Chromium.",
|
||||
"channels_communityShortId": "Идентификационен номер: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS потвърдено",
|
||||
"pathTrace_legendInferred": "Извлечена позиция"
|
||||
}
|
||||
|
||||
+421
-41
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Löschen",
|
||||
"common_enable": "Aktivieren",
|
||||
"common_disable": "Deaktivieren",
|
||||
"common_autoRefresh": "Automatische Aktualisierung",
|
||||
"common_interval": "Intervall",
|
||||
"common_reboot": "Neustart",
|
||||
"common_loading": "Laden...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – Open-Version",
|
||||
"scanner_scanning": "Scannen nach Geräten...",
|
||||
"scanner_connecting": "Verbunden...",
|
||||
"scanner_disconnecting": "Trenne...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Datenschutzmodus aktiviert",
|
||||
"settings_privacyModeDisabled": "Datenschutzmodus deaktiviert",
|
||||
"settings_actions": "Aktionen",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Sende Ankündigung",
|
||||
"settings_sendAdvertisementSubtitle": "Sende eine Ankündigung",
|
||||
"settings_advertisementSent": "Ankündigung gesendet",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "App-Debug-Protokoll",
|
||||
"settings_appDebugLogSubtitle": "Anwendung Debug-Nachrichten",
|
||||
"settings_about": "Über",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open, Version {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -146,7 +150,7 @@
|
||||
"settings_spreadingFactor": "Verteilungsfaktor",
|
||||
"settings_codingRate": "Kodierungsrate",
|
||||
"settings_txPower": "TX-Leistung (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerHelper": "0 – 22",
|
||||
"settings_txPowerInvalid": "Ungültige TX-Leistung (0-22 dBm)",
|
||||
"settings_error": "Fehler: {message}",
|
||||
"@settings_error": {
|
||||
@@ -158,25 +162,25 @@
|
||||
},
|
||||
"appSettings_title": "App-Einstellungen",
|
||||
"appSettings_appearance": "Aussehen",
|
||||
"appSettings_theme": "Theme",
|
||||
"appSettings_theme": "Thema",
|
||||
"appSettings_themeSystem": "Systemstandard",
|
||||
"appSettings_themeLight": "Hell",
|
||||
"appSettings_themeDark": "Dunkel",
|
||||
"appSettings_language": "Sprache",
|
||||
"appSettings_languageSystem": "Systemstandard",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageEn": "Englisch",
|
||||
"appSettings_languageFr": "Französisch",
|
||||
"appSettings_languageEs": "Spanisch",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languagePl": "Polnisch",
|
||||
"appSettings_languageSl": "Slowenisch",
|
||||
"appSettings_languagePt": "Portugiesisch",
|
||||
"appSettings_languageIt": "Italienisch",
|
||||
"appSettings_languageZh": "Chinesisch",
|
||||
"appSettings_languageSv": "Schwedisch",
|
||||
"appSettings_languageNl": "Niederländisch",
|
||||
"appSettings_languageSk": "Slowenisch",
|
||||
"appSettings_languageBg": "Bulgarisch",
|
||||
"appSettings_notifications": "Benachrichtigungen",
|
||||
"appSettings_enableNotifications": "Benachrichtigungen aktivieren",
|
||||
"appSettings_enableNotificationsSubtitle": "Erhalte Benachrichtigungen für Nachrichten und Ankündigungen",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtag-Kanal",
|
||||
"channels_public": "Öffentlich",
|
||||
"channels_private": "Privat",
|
||||
"channels_publicChannel": "Öffentlicher Kanal",
|
||||
"channels_privateChannel": "Privater Kanal",
|
||||
"channels_editChannel": "Kanal bearbeiten",
|
||||
"channels_muteChannel": "Kanal stummschalten",
|
||||
"channels_unmuteChannel": "Kanal Stummschaltung aufheben",
|
||||
@@ -367,7 +368,7 @@
|
||||
"channels_channelName": "Kanalname",
|
||||
"channels_usePublicChannel": "Verwende öffentlichen Kanal",
|
||||
"channels_standardPublicPsk": "Öffentliche Standard PSK",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (Hexadezimal)",
|
||||
"channels_generateRandomPsk": "Zufällige PSK generieren",
|
||||
"channels_enterChannelName": "Bitte geben Sie einen Kanalnamen ein.",
|
||||
"channels_pskMustBe32Hex": "Die PSK muss 32 hexadezimale Zeichen haben.",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ-Komprimierung",
|
||||
"channels_cyr2latCompression": "Cyr2Lat-Komprimierung",
|
||||
"channels_cyr2latCompressionDscr": "Ersetzt einige kyrillische Zeichen durch lateinische Zeichen, wenn sie gesendet werden.",
|
||||
"channels_cyr2latSettingsHeading": "Cyr2Lat-Einstellungen",
|
||||
"channels_cyr2latSettingsSubheading": "Ersetzungsliste",
|
||||
"channels_cyr2latSettingsDscr": "JSON-Konfiguration für die Zeichenersetzung bearbeiten",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-Ersetzungstabelle",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Ungültiges JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Cyr2Lat-Profil hinzufügen",
|
||||
"settings_cyr2latProfileName": "Profilname",
|
||||
"settings_cyr2latProfileNameEmpty": "Der Profilname darf nicht leer sein",
|
||||
"settings_cyr2latProfileAdded": "Profil erfolgreich hinzugefügt",
|
||||
"settings_cyr2latProfileUpdated": "Profil erfolgreich aktualisiert",
|
||||
"settings_cyr2latProfileEdit": "Cyr2Lat-Profil bearbeiten",
|
||||
"settings_cyr2latProfileDelete": "Cyr2Lat-Profil löschen",
|
||||
"settings_cyr2latProfileDeleted": "Profil erfolgreich gelöscht",
|
||||
"settings_cyr2latProfileDeleteDscr": "Möchten Sie das Profil \"{name}\" wirklich löschen?",
|
||||
"channels_channelUpdated": "Kanal \"{name}\" aktualisiert",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -512,7 +529,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_flags": "- Flags: 0x{value}",
|
||||
"debugFrame_flags": "- Flaggen: 0x{value}",
|
||||
"@debugFrame_flags": {
|
||||
"placeholders": {
|
||||
"value": {
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Befehlszeilen-Schnittstelle",
|
||||
"debugFrame_textTypePlain": "Einfach",
|
||||
"debugFrame_text": "- Text: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -633,7 +650,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_pinsCount": "Pins: {count}",
|
||||
"map_pinsCount": "Nadeln: {count}",
|
||||
"@map_pinsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -642,20 +659,20 @@
|
||||
}
|
||||
},
|
||||
"map_chat": "Benutzer",
|
||||
"map_repeater": "Repeater",
|
||||
"map_repeater": "Wiederholungseinheit",
|
||||
"map_room": "Raum",
|
||||
"map_sensor": "Sensor",
|
||||
"map_pinDm": "Pin (Kontakt)",
|
||||
"map_pinPrivate": "Pin (Channel)",
|
||||
"map_pinPublic": "Pin (Public)",
|
||||
"map_pinPublic": "Kennzeichnung (Öffentlich)",
|
||||
"map_lastSeen": "Letzte Sichtung",
|
||||
"map_disconnectConfirm": "Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?",
|
||||
"map_from": "Von",
|
||||
"map_source": "Quelle",
|
||||
"map_flags": "Flags",
|
||||
"map_flags": "Flaggen",
|
||||
"map_shareMarkerHere": "Teilen Sie den Marker hier.",
|
||||
"map_pinLabel": "Pin Name",
|
||||
"map_label": "Label",
|
||||
"map_label": "Etikett",
|
||||
"map_pointOfInterest": "Punkt von Interesse",
|
||||
"map_sendToContact": "Senden an Kontakt",
|
||||
"map_sendToChannel": "Senden an Kanal",
|
||||
@@ -883,7 +900,7 @@
|
||||
"repeater_statusSubtitle": "Status, Statistiken und Nachbarn anzeigen",
|
||||
"repeater_telemetry": "Telemetrie",
|
||||
"repeater_telemetrySubtitle": "Sensordaten und Systemwerte anzeigen",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Befehlszeilen-Schnittstelle",
|
||||
"repeater_cliSubtitle": "Sende Befehle an den Repeater",
|
||||
"repeater_settings": "Einstellungen",
|
||||
"repeater_settingsSubtitle": "Repeater-parameter konfigurieren",
|
||||
@@ -984,7 +1001,7 @@
|
||||
},
|
||||
"repeater_settingsTitle": "Repeater Einstellungen",
|
||||
"repeater_basicSettings": "Grundlegende Einstellungen",
|
||||
"repeater_repeaterName": "Repeater Name",
|
||||
"repeater_repeaterName": "Name des Repeater",
|
||||
"repeater_repeaterNameHelper": "Anzeigename für diesen Repeater",
|
||||
"repeater_adminPassword": "Admin-Passwort",
|
||||
"repeater_adminPasswordHelper": "Vollzugriffspasswort",
|
||||
@@ -992,7 +1009,7 @@
|
||||
"repeater_guestPasswordHelper": "Schreibgeschütztes Zugriffspasswort",
|
||||
"repeater_radioSettings": "Funk Einstellungen",
|
||||
"repeater_frequencyMhz": "Frequenz (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300–2500 MHz",
|
||||
"repeater_txPower": "TX Power",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Bandbreite",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Bestätigen",
|
||||
"repeater_settingsSaved": "Einstellungen erfolgreich gespeichert",
|
||||
"repeater_rxGain": "Erhöhter RX-Gewinn",
|
||||
"repeater_rxGainHelper": "Höhere Empfindlichkeit, höherer Stromverbrauch (nur für SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Erneuerung des verstärkten RX-Effekts",
|
||||
"repeater_multiAcks": "Mehrere Bestätigungen",
|
||||
"repeater_multiAcksSubtitle": "Nachrichten über verschiedene Pfade senden, um die Zustellbarkeit zu verbessern.",
|
||||
"repeater_refreshMultiAcks": "Mehrere Bestätigungen neu senden/aktualisieren",
|
||||
"repeater_networkHealth": "Netzwerkgesundheit",
|
||||
"repeater_loopDetect": "Erkennung von Schleifen",
|
||||
"repeater_loopDetectHelper": "Erstellen Sie \"Flood\"-Pakete, die so aussehen, als ob sie Schleifen erzeugen.",
|
||||
"repeater_loopDetectOff": "Aus",
|
||||
"repeater_loopDetectMinimal": "Minimal",
|
||||
"repeater_loopDetectModerate": "mäßig",
|
||||
"repeater_loopDetectStrict": "streng",
|
||||
"repeater_dutyCycle": "Betriebsdauer",
|
||||
"repeater_dutyCycleHelper": "Höchster zulässiger Prozentsatz der Sendefläche",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Information zum Betreiber",
|
||||
"repeater_ownerInfoHelper": "Öffentliche Metadaten für dieses Gerät",
|
||||
"repeater_refreshOwnerInfo": "Aktualisieren Sie die Informationen zum Betreiber",
|
||||
"repeater_floodMax": "Max-Hops-Flut",
|
||||
"repeater_floodMaxHelper": "Maximale Anzahl an Hop-Paketen, die ein einzelnes Paket durchlaufen kann (0-64)",
|
||||
"repeater_advancedSettings": "Fortgeschritten",
|
||||
"repeater_advancedSettingsSubtitle": "Regler für erfahrene Bediener",
|
||||
"repeater_pathHashMode": "Hash-Modus für Pfade",
|
||||
"repeater_pathHashModeHelper": "Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware-Versionen 1.13 und älter verwenden mehrstellige Pfade – ab Version 1.14+ wird nur ein Pfad erstellt, sobald das Netzwerk aktiv ist.",
|
||||
"repeater_txDelay": "Verzögerung bei Flood TX",
|
||||
"repeater_txDelayHelper": "Wiederholung des Abstands für Hochwasser-Verkehr, als Multiplikator der Übertragungszeit des Pakets (0-2, Standardwert 0,5). Höherer Wert = weniger Kollisionen, aber langsamere Übertragung.",
|
||||
"repeater_directTxDelay": "Direkter TX-Verzögerung",
|
||||
"repeater_directTxDelayHelper": "Die Übertragungsrate für direkten (nicht-fluten) Datenverkehr wird als Vielfaches der Übertragungszeit des Pakets festgelegt (0-2, Standardwert 0,3).",
|
||||
"repeater_intThresh": "Grenzwert für Störungen",
|
||||
"repeater_intThreshHelper": "Der Schwellenwert wird an die Rauschpegel-Kalibrierung des Radios angepasst, sodass Störungen über diesem Wert abgefangen werden. 0 deaktiviert – erhöhen Sie diesen Wert nur, wenn Sie in einem verrauschten Frequenzbereich RX-Fehler feststellen.",
|
||||
"repeater_agcResetInterval": "Intervall für die Rücksetzung von AGC",
|
||||
"repeater_agcResetIntervalHelper": "Wie oft sollte die automatische Verstärkungskontrolle des Radios zurückgesetzt werden, um von einem Zustand mit zu hoher Verstärkung wieder in einen normalen Zustand zu gelangen? Die Einstellung „Sekunden“ ermöglicht eine Rücksetzung alle 4 Sekunden. Die Einstellung „0“ deaktiviert die periodische Rücksetzung.",
|
||||
"repeater_actionsTitle": "Aktionen",
|
||||
"repeater_sendAdvert": "Flood-Werbung versenden",
|
||||
"repeater_sendAdvertSubtitle": "Eine Werbekampagne für Überschwemmungen über das Netzwerk verbreiten.",
|
||||
"repeater_sendAdvertZeroHop": "Versenden Sie eine Anzeige ohne Zwischenvermittler.",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Eine Werbekampagne mit einem einzigen Sender (ohne Weiterleitung) senden.",
|
||||
"repeater_clockSync": "Uhr jetzt synchronisieren",
|
||||
"repeater_clockSyncSubtitle": "Übertragen Sie die Uhrzeit Ihres Telefons an den Repeater.",
|
||||
"repeater_actionSucceeded": "{action} war erfolgreich",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} fehlgeschlagen: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Einstellungen gespeichert – Repeater neu starten, um die Änderungen anzuwenden.",
|
||||
"repeater_settingsPartialFailure": "Einige Einstellungen sind fehlgeschlagen: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Fehler beim Speichern der Einstellungen: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Grundlegende Einstellungen aktualisieren",
|
||||
"repeater_refreshRadioSettings": "Radio-Einstellungen aktualisieren",
|
||||
"repeater_refreshTxPower": "Sendeleistung aktualisieren",
|
||||
"repeater_refreshLocationSettings": "Aktualisieren Sie die Standort Einstellungen",
|
||||
"repeater_refreshPacketForwarding": "Aktualisieren Paketweiterleitung",
|
||||
"repeater_refreshGuestAccess": "Aktualisieren Sie den Gastzugriff",
|
||||
"repeater_refreshPrivacyMode": "Wiederherstellen des Datenschutzzustands",
|
||||
"repeater_refreshAdvertisementSettings": "Aktualisieren Sie die Ankündigungseinstellungen",
|
||||
"repeater_refreshed": "{label} wurde aktualisiert",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1091,7 +1181,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_cliTitle": "Repeater CLI",
|
||||
"repeater_cliTitle": "Befehlszeilen-Schnittstelle (CLI) für Repeater",
|
||||
"repeater_debugNextCommand": "Fehlersuche des nächsten Befehls",
|
||||
"repeater_commandHelp": "Hilfe",
|
||||
"repeater_clearHistory": "Löschen der Historie",
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digitaleingang",
|
||||
"telemetry_digitalOutputLabel": "Digitalausgang",
|
||||
"telemetry_analogInputLabel": "Analogeingang",
|
||||
"telemetry_analogOutputLabel": "Analogausgang",
|
||||
"telemetry_genericLabel": "Allgemeiner Sensor",
|
||||
"telemetry_luminosityLabel": "Helligkeit",
|
||||
"telemetry_presenceLabel": "Anwesenheit",
|
||||
"telemetry_humidityLabel": "Luftfeuchtigkeit",
|
||||
"telemetry_accelerometerLabel": "Beschleunigungsmesser",
|
||||
"telemetry_pressureLabel": "Druck",
|
||||
"telemetry_altitudeLabel": "Höhe",
|
||||
"telemetry_frequencyLabel": "Frequenz",
|
||||
"telemetry_percentageLabel": "Prozentsatz",
|
||||
"telemetry_concentrationLabel": "Konzentration",
|
||||
"telemetry_powerLabel": "Leistung",
|
||||
"telemetry_distanceLabel": "Entfernung",
|
||||
"telemetry_energyLabel": "Energie",
|
||||
"telemetry_directionLabel": "Richtung",
|
||||
"telemetry_timeLabel": "Zeit",
|
||||
"telemetry_gyrometerLabel": "Gyroskop",
|
||||
"telemetry_colourLabel": "Farbe",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Schalter",
|
||||
"telemetry_polylineLabel": "Polylinie",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Anzahl der Anfragen",
|
||||
"telemetry_error": "Daten konnten nicht abgerufen werden",
|
||||
"telemetry_noData": "Keine Telemetriedaten verfügbar.",
|
||||
"telemetry_channelTitle": "Kanal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Sortiere nach",
|
||||
"listFilter_latestMessages": "Letzte Nachrichten",
|
||||
"listFilter_heardRecently": "Kürzlich gehört",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "Von A bis Z",
|
||||
"listFilter_filters": "Filtere",
|
||||
"listFilter_all": "Alle",
|
||||
"listFilter_favorites": "Favoriten",
|
||||
@@ -1462,7 +1589,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_ok": "OK",
|
||||
"common_ok": "Alles klar",
|
||||
"community_create": "Erstelle Community",
|
||||
"community_createDesc": "Erstelle eine neue Community und teile sie über den QR-Code.",
|
||||
"community_join": "Beitreten",
|
||||
@@ -1473,14 +1600,14 @@
|
||||
"community_showQr": "Zeige QR-Code",
|
||||
"community_publicChannel": "Community Öffentlich",
|
||||
"community_enterName": "Bitte Community-Name eingeben",
|
||||
"community_title": "Community",
|
||||
"community_title": "Gemeinschaft",
|
||||
"community_created": "Community \"{name}\" wurde erstellt",
|
||||
"community_joined": "Community \"{name}\" beigetreten",
|
||||
"community_qrTitle": "Teile Community",
|
||||
"community_qrInstructions": "Scannen Sie diesen QR-Code, um sich \"{name}\" anzuschließen.",
|
||||
"community_hashtagPrivacyHint": "Community-Hashtag-Kanäle können nur von Mitgliedern der Community betreten werden",
|
||||
"community_hashtagChannel": "Community Hashtag",
|
||||
"community_name": "Community Name",
|
||||
"community_hashtagChannel": "Gemeinschaftlicher Hashtag",
|
||||
"community_name": "Name der Gemeinde",
|
||||
"community_invalidQrCode": "Ungültiger Community-QR-Code",
|
||||
"community_alreadyMember": "Bereits registriert",
|
||||
"community_alreadyMemberMessage": "Sie sind bereits Mitglied von \"{name}\".",
|
||||
@@ -1507,7 +1634,7 @@
|
||||
"community_regularHashtagDesc": "Öffentlicher Hashtag (jeder kann teilnehmen)",
|
||||
"community_communityHashtagDesc": "Nur für Mitglieder der Community",
|
||||
"community_forCommunity": "Für {name}",
|
||||
"community_communityHashtag": "Community Hashtag",
|
||||
"community_communityHashtag": "Gemeinschaftlicher Hashtag",
|
||||
"@community_regenerateSecretConfirm": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
@@ -1907,7 +2034,7 @@
|
||||
"connectionChoiceTcpLabel": "TCP",
|
||||
"tcpHostHint": "192.168.40.10",
|
||||
"tcpScreenTitle": "Verbinden über TCP",
|
||||
"tcpPortLabel": "Port",
|
||||
"tcpPortLabel": "Hafen",
|
||||
"tcpPortHint": "5000",
|
||||
"tcpStatus_notConnected": "Geben Sie den Endpunkt ein und verbinden Sie sich.",
|
||||
"tcpStatus_connectingTo": "Verbindung zu {endpoint}...",
|
||||
@@ -2039,6 +2166,9 @@
|
||||
"translation_enableSubtitle": "Nachrichten empfangen und übersetzen sowie die Möglichkeit bieten, Nachrichten vor dem Versenden zu übersetzen.",
|
||||
"translation_enableTitle": "Aktivieren Sie die Übersetzung",
|
||||
"translation_composerSubtitle": "Steuert den Standardzustand des Icons für die Übersetzung des Komponisten.",
|
||||
"translation_autoIncomingTitle": "Nachrichten automatisch übersetzen",
|
||||
"translation_autoIncomingSubtitle": "Übersetzt Nachrichten für Benachrichtigungen sowie für Chats oder Kanäle automatisch.",
|
||||
"translation_translateMessage": "Nachricht übersetzen",
|
||||
"translation_targetLanguage": "Zielsprache",
|
||||
"translation_useAppLanguage": "Verwenden Sie die App-Sprache",
|
||||
"translation_downloadedModelLabel": "Heruntergeladenes Modell",
|
||||
@@ -2094,5 +2224,255 @@
|
||||
"repeater_guestTools": "Gastwerkzeuge",
|
||||
"chat_sendMessage": "Nachricht senden",
|
||||
"room_guest": "Informationen zum Room Server",
|
||||
"settings_multiAck": "Mehrere Bestätigungen"
|
||||
"repeater_getCategory": "Werte erhalten",
|
||||
"repeater_powerMgmt": "Energieverwaltung",
|
||||
"repeater_sensors": "Sensoren",
|
||||
"repeater_cliHelpPowerOff": "Schaltet das Gerät aus. (keine Antwort erwartet)",
|
||||
"repeater_cliHelpClkReboot": "Setzt die Uhr auf einen bekannten Zeitpunkt zurück und startet das Gerät neu.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Sendet eine Werbeanzeige, die nur an unmittelbare Nachbarn gesendet wird (ohne Zwischenstation).",
|
||||
"repeater_cliHelpStartOta": "Startet ein Firmware-Update über Funk, das auf unterstützten Boards durchgeführt wird.",
|
||||
"repeater_cliHelpTime": "Stellt die Gerätuhr auf die angegebene Unix-Epoche in Sekunden ein. Die Uhr kann nicht rückwärts laufen.",
|
||||
"repeater_cliHelpBoard": "Zeigt den Hersteller/die Hardware-Kennung an.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Sendet eine Anfrage zur Entdeckung von Nachbarn in der Nähe. (Nur bei Repeatern)",
|
||||
"repeater_cliHelpPowersaving": "Zeigt an, ob der Energiesparmodus aktiviert oder deaktiviert ist.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Aktiviert oder deaktiviert den Energiesparmodus (falls unterstützt).",
|
||||
"repeater_cliHelpErase": "(Nur für serielle Schnittstellen) Formatiert das Dateisystem des Geräts. Löscht alle Einstellungen und Kontakte.",
|
||||
"repeater_cliHelpSetDutyCycle": "Legt den maximal zulässigen Übertragungszyklus als Prozentsatz fest (1-100). Passt den Zeitfaktor intern an.",
|
||||
"repeater_cliHelpSetPrvKey": "(Nur für serielle Anwendungen) Ersetzt den privaten Schlüssel zur Geräteidentifizierung. Nach der Anwendung ist ein Neustart erforderlich. Generiert einen neuen öffentlichen Schlüssel.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Nur für SX126x) Schaltet die verstärkte RX-Verstärkung ein, um die Empfindlichkeit bei höherem Stromverbrauch zu verbessern.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Definiert den String mit den Kontaktinformationen des Eigentümers, der in den Anzeigen enthalten ist. Verwenden Sie '|' für Zeilenumbrüche.",
|
||||
"repeater_cliHelpSetPathHashMode": "Legt den Modus für die Pfad-Hashes fest. 0 = ältere Version, 1 = Standard, 2 = streng. Beeinflusst, wie Routing-Pfade abgeglichen werden.",
|
||||
"repeater_cliHelpSetLoopDetect": "Legt die Empfindlichkeit der Schleifenerkennung fest: aus, minimal, moderat oder streng.",
|
||||
"repeater_cliHelpSetFreq": "(Nur für die serielle Schnittstelle) Ermöglicht die schnelle Einstellung der Frequenz. Nach der Einstellung ist ein Neustart erforderlich. Für die vollständige Einstellung aller Radio-Parameter wird die Option \"Radio einstellen\" empfohlen.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Nur für ESPNow-Brücke) Legt den verwendeten WLAN-Kanal (1-14) für die Brücke fest.",
|
||||
"repeater_cliHelpGetName": "Zeigt den konfigurierten Knotenamen an.",
|
||||
"repeater_cliHelpGetRole": "Zeigt die Funktion der Firmware an (Repeater, Raumserver usw.).",
|
||||
"repeater_cliHelpGetPublicKey": "Zeigt den öffentlichen Schlüssel des Geräts an.",
|
||||
"repeater_cliHelpGetPrvKey": "(Nur für serielle Kommunikation) Zeigt den privaten Schlüssel des Geräts an. Behandeln Sie diesen als ein Geheimnis.",
|
||||
"repeater_cliHelpGetRepeat": "Zeigt an, ob die Weiterleitung von Paketen (als Repeater) aktiviert oder deaktiviert ist.",
|
||||
"repeater_cliHelpGetTx": "Zeigt die aktuelle Sendeleistung in dBm an.",
|
||||
"repeater_cliHelpGetFreq": "Zeigt die konfigurierte Funkfrequenz in MHz an.",
|
||||
"repeater_cliHelpGetRadio": "Zeigt alle Funkparameter an: Frequenz, Bandbreite, Spreading-Faktor, Codierungsrate.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Nur für SX126x) Zeigt den Zustand des verstärkten Empfangs (RX).",
|
||||
"repeater_cliHelpGetAf": "Zeigt den aktuellen Zeitfaktor an.",
|
||||
"repeater_cliHelpGetDutyCycle": "Zeigt den aktuellen zulässigen Schaltzyklus als Prozentsatz an.",
|
||||
"repeater_cliHelpGetIntThresh": "Zeigt den Grenzwert für Kanalüberlagerung in dB an.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Zeigt das Intervall für die Rücksetzung des AGC in Sekunden an.",
|
||||
"repeater_cliHelpGetMultiAcks": "Zeigt an, ob der Modus \"doppelte ACK\"-Funktion aktiviert (1) oder deaktiviert (0) ist.",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Zeigt an, ob der Zugriff für Gäste nur in Lesemodus erlaubt ist.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Zeigt die Dauer des lokalen Werbeintervalls in Minuten an.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Zeigt die Dauer der Werbeunterbrechung in Stunden an.",
|
||||
"repeater_cliHelpGetGuestPassword": "Zeigt das konfigurierte Gast-Passwort an.",
|
||||
"repeater_cliHelpGetLat": "Zeigt die konfigurierte Breitengrade.",
|
||||
"repeater_cliHelpGetLon": "Zeigt die konfigurierte Länge an.",
|
||||
"repeater_cliHelpGetRxDelay": "Zeigt den Basiswert für die Verzögerungszeit an.",
|
||||
"repeater_cliHelpGetTxDelay": "Zeigt den Faktor für die Übertragungsverzögerung im Notfallmodus an.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Zeigt den Faktor für die Verzögerung im Direktmodus an.",
|
||||
"repeater_cliHelpGetFloodMax": "Zeigt die maximale Anzahl von Überschwemmungsphasen an.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Zeigt die Zeichenkette mit den Kontaktinformationen des Eigentümers an.",
|
||||
"repeater_cliHelpGetPathHashMode": "Zeigt den Pfad-Hash-Modus (0/1/2) an.",
|
||||
"repeater_cliHelpGetLoopDetect": "Zeigt die Empfindlichkeit der Schleifenerkennung an.",
|
||||
"repeater_cliHelpGetAcl": "(Nur für serielle Kommunikation) Zeigt die Zugriffskontrolleinträge auf einem Repeater an.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Zeigt an, ob die Brücke aktiviert ist.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Zeigt die Verzögerung der Brücke in Millisekunden an.",
|
||||
"repeater_cliHelpGetBridgeSource": "Zeigt, ob die Brücke RX- oder TX-Pakete empfängt oder sendet.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Nur für RS232-Verbindungen) Zeigt die Baudrate der Verbindung an.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Nur für ESPNow-Brücke) Zeigt den WLAN-Kanal der Brücke an.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Nur für ESPNow-Brücke) Zeigt das gemeinsam genutzte Geheimnis der Brücke.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Nur für NRF52) Zeigt die Version des Bootloaders an.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Zeigt den ADC-Verstärker (Spannungs-Skalierung) an.",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Gibt an, ob der Verwaltungsrat die Funktion zur Energieverwaltung unterstützt.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Zeigt die aktuelle Stromquelle an: extern oder Batterie.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Zeigt die aktuellsten Gründe für einen Neustart und Herunterfahren an.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Zeigt die Batteriespannung beim Start in Millivolt (mV) an.",
|
||||
"repeater_cliHelpSensorGet": "Liest eine benutzerdefinierte Sensoreinstellung über eine Taste.",
|
||||
"repeater_cliHelpSensorSet": "Erstellt eine benutzerdefinierte Sensoreinstellung.",
|
||||
"repeater_cliHelpSensorList": "Zeigt alle benutzerdefinierten Sensoreinstellungen an, wobei die Seitennummerierung optional von einem Startindex abhängt.",
|
||||
"repeater_cliHelpRegionDefault": "Zeigt den aktuellen Standard-Region-Bereich an.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Definiert den Standard-Regionenbereich. Verwenden Sie \"<null>\", um diesen zu löschen.",
|
||||
"repeater_cliHelpRegionListAllowed": "Nennt die Regionen, die Überschwemmungsverkehr zulassen.",
|
||||
"repeater_cliHelpRegionListDenied": "Auflistung von Regionen, die den Verkehr aufgrund von Überschwemmungen verbieten.",
|
||||
"repeater_cliHelpStatsPackets": "(Nur für serielle Verbindungen) Zeigt Statistiken auf Paketebene.",
|
||||
"repeater_cliHelpStatsRadio": "(Nur für Serien) Zeigt Radiostatistiken an.",
|
||||
"repeater_cliHelpStatsCore": "(Nur für serielle Schnittstellen) Zeigt grundlegende Firmware-Statistiken.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Mehrere Bestätigungen",
|
||||
"map_sharedAt": "Geteilt",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Reservierte Plätze",
|
||||
"losSelectedObstructionTitle": "Ausgewählte Behinderung",
|
||||
"losBlockedSpotChip": "{distance} • {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "Klicken Sie auf einen blockierten Bereich, um ihn auf der Karte hervorzuheben.",
|
||||
"losSelectedObstructionDetails": "Blockiert durch {obstruction} in einer Höhe von {heightUnit}, {distanceFromA} von A und {distanceFromB} von B ({distanceUnit}).",
|
||||
"chat_markAsUnread": "Als nicht gelesen markieren",
|
||||
"chat_newMessages": "Neue Nachrichten",
|
||||
"settings_companionDebugLog": "Debug-Protokoll für die Begleitsoftware",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-Befehle, Antworten und Rohdaten",
|
||||
"repeater_chanUtil": "Nutzung des Kanals",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "Gesendet",
|
||||
"messageStatus_delivered": "Geliefert",
|
||||
"common_undo": "Rückgängig machen",
|
||||
"messageStatus_pending": "Versenden",
|
||||
"messageStatus_failed": "Nicht gesendet",
|
||||
"messageStatus_repeated": "Wiederholt gehört",
|
||||
"contacts_moreOptions": "Weitere Optionen",
|
||||
"contacts_searchOpen": "Kontakte suchen",
|
||||
"contacts_searchClose": "Erweiterte Suche",
|
||||
"routing_title": "Routenplanung",
|
||||
"routing_modeAuto": "Auto",
|
||||
"routing_modeFlood": "Überschwemmung",
|
||||
"routing_modeManual": "Handbuch",
|
||||
"routing_modeFloodHint": "Übertragung über alle Repeater. Die zuverlässigste Methode, jedoch mit höherem Datenverbrauch.",
|
||||
"routing_modeAutoHint": "Wählt automatisch den bekanntesten Pfad aus und verwendet eine Flutungsmethode, wenn kein Pfad bekannt ist.",
|
||||
"routing_modeManualHint": "Sendet immer genau den von Ihnen festgelegten Weg.",
|
||||
"routing_currentRoute": "Aktuelle Route",
|
||||
"routing_directNoHops": "Direkt – ohne Zwischenverstärkung",
|
||||
"routing_noPathYet": "Noch kein Pfad gefunden. Die Nachricht wird gesendet, bis ein Weg entdeckt wurde.",
|
||||
"routing_floodBroadcast": "Übertragung über jeden Repeater",
|
||||
"routing_editPath": "Pfad bearbeiten",
|
||||
"routing_forgetPath": "Vergiss den Weg",
|
||||
"routing_knownPaths": "Bekannte Routen",
|
||||
"routing_knownPathsHint": "Wählen Sie den Pfad, um zu diesem zu wechseln.",
|
||||
"routing_inUse": "Im Gebrauch",
|
||||
"routing_qualityStrong": "Ein starker erster Sprung",
|
||||
"routing_qualityGood": "Ein guter erster Schritt",
|
||||
"routing_qualityFair": "Erster erfolgreicher Schritt",
|
||||
"routing_qualityWorked": "Hat erfolgreich geliefert",
|
||||
"routing_qualityFlood": "Information erhalten durch Nachrichten über die Überschwemmung",
|
||||
"routing_qualityUntested": "Nicht getestet",
|
||||
"routing_lastWorked": "war beschäftigt {when}",
|
||||
"routing_neverWorked": "nie bestätigt",
|
||||
"routing_floodDelivery": "Lieferung bei Überschwemmung",
|
||||
"pathEditor_title": "Pfad erstellen",
|
||||
"pathEditor_hopCounter": "{count} von 64 Hopfengewächsen",
|
||||
"pathEditor_noHops": "Noch keine Hopfen hinzugefügt. Klicken Sie auf die Schaltflächen unten, um sie nacheinander hinzuzufügen, oder speichern Sie die Rezepter ohne Hopfen, um sie direkt zu versenden.",
|
||||
"pathEditor_addHops": "Fügen Sie die Hopfen in der richtigen Reihenfolge hinzu.",
|
||||
"pathEditor_searchRepeaters": "Suche nach wiederholten Nachrichten",
|
||||
"pathEditor_advancedHex": "Fortgeschritten: Roh-Hex-Pfad",
|
||||
"pathEditor_hexLabel": "Hex-Präfixe",
|
||||
"pathEditor_hexHelper": "Zwei Hexadezimalzeichen pro Sprung, getrennt durch Kommas",
|
||||
"pathEditor_invalidTokens": "Ungültig: {tokens}",
|
||||
"pathEditor_tooManyHops": "Maximal 64 Hopfengreifer",
|
||||
"pathEditor_usePath": "Verwenden Sie diesen Pfad.",
|
||||
"pathEditor_removeHop": "Hop entfernen",
|
||||
"pathEditor_unknownHop": "Unbekannter Repeater",
|
||||
"map_zoomIn": "Zoomen",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Auszoomen",
|
||||
"map_centerMap": "Zentralkarte",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth benötigt einen Chromium-Browser.",
|
||||
"channels_communityShortId": "ID: {id}…",
|
||||
"pathTrace_legendGpsConfirmed": "GPS-Bestätigung",
|
||||
"pathTrace_legendInferred": "Abgeleitete Position"
|
||||
}
|
||||
|
||||
+575
-94
@@ -12,6 +12,7 @@
|
||||
"common_delete": "Delete",
|
||||
"common_deleteAll": "Delete All",
|
||||
"common_close": "Close",
|
||||
"common_done": "Done",
|
||||
"common_edit": "Edit",
|
||||
"common_add": "Add",
|
||||
"common_settings": "Settings",
|
||||
@@ -27,6 +28,12 @@
|
||||
"common_remove": "Remove",
|
||||
"common_enable": "Enable",
|
||||
"common_disable": "Disable",
|
||||
"common_undo": "Undo",
|
||||
"messageStatus_sent": "Sent",
|
||||
"messageStatus_delivered": "Delivered",
|
||||
"messageStatus_pending": "Sending",
|
||||
"messageStatus_failed": "Failed to send",
|
||||
"messageStatus_repeated": "Heard repeated",
|
||||
"common_reboot": "Reboot",
|
||||
"common_loading": "Loading...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -46,13 +53,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_autoRefresh": "Autorefresh",
|
||||
"common_interval": "Interval",
|
||||
"scanner_title": "MeshCore Open",
|
||||
"connectionChoiceUsbLabel": "USB",
|
||||
"connectionChoiceBluetoothLabel": "Bluetooth",
|
||||
"connectionChoiceTcpLabel": "TCP",
|
||||
"tcpScreenTitle": "Connect over TCP",
|
||||
"tcpHostLabel": "IP Address",
|
||||
"tcpHostHint": "192.168.40.10",
|
||||
"tcpHostLabel": "Endpoint",
|
||||
"tcpHostHint": "192.168.40.10 / example.com",
|
||||
"tcpPortLabel": "Port",
|
||||
"tcpPortHint": "5000",
|
||||
"tcpStatus_notConnected": "Enter endpoint and connect",
|
||||
@@ -64,7 +73,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tcpErrorHostRequired": "IP address is required.",
|
||||
"tcpErrorHostRequired": "Host is required.",
|
||||
"tcpErrorPortInvalid": "Port must be between 1 and 65535.",
|
||||
"tcpErrorUnsupported": "TCP transport is not supported on this platform.",
|
||||
"tcpErrorTimedOut": "TCP connection timed out.",
|
||||
@@ -127,7 +136,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"scanner_stop": "Stop",
|
||||
"scanner_scan": "Scan",
|
||||
"scanner_bluetoothOff": "Bluetooth is off",
|
||||
@@ -135,6 +143,7 @@
|
||||
"scanner_chromeRequired": "Chrome Browser Required",
|
||||
"scanner_chromeRequiredMessage": "This web application requires Google Chrome or a Chromium-based browser for Bluetooth support.",
|
||||
"scanner_enableBluetooth": "Enable Bluetooth",
|
||||
"scanner_bluetoothWebUnsupported": "Bluetooth isn't available in the browser. Connect over USB instead.",
|
||||
"device_quickSwitch": "Quick switch",
|
||||
"device_meshcore": "MeshCore",
|
||||
"settings_title": "Settings",
|
||||
@@ -181,6 +190,8 @@
|
||||
"settings_multiAck": "Multi-ACKs",
|
||||
"settings_telemetryModeUpdated": "Telemetry mode updated",
|
||||
"settings_actions": "Actions",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Send Advertisement",
|
||||
"settings_sendAdvertisementSubtitle": "Broadcast presence now",
|
||||
"settings_advertisementSent": "Advertisement sent",
|
||||
@@ -193,8 +204,8 @@
|
||||
"settings_rebootDeviceSubtitle": "Restart the MeshCore device",
|
||||
"settings_rebootDeviceConfirm": "Are you sure you want to reboot the device? You will be disconnected.",
|
||||
"settings_debug": "Debug",
|
||||
"settings_bleDebugLog": "BLE Debug Log",
|
||||
"settings_bleDebugLogSubtitle": "BLE commands, responses, and raw data",
|
||||
"settings_companionDebugLog": "Companion Debug Log",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB commands, responses, and raw data",
|
||||
"settings_appDebugLog": "App Debug Log",
|
||||
"settings_appDebugLogSubtitle": "Application debug messages",
|
||||
"settings_about": "About",
|
||||
@@ -293,17 +304,6 @@
|
||||
"appSettings_routeWeightFailureDecrementSubtitle": "Weight removed from a path after failed delivery",
|
||||
"appSettings_maxMessageRetries": "Max Message Retries",
|
||||
"appSettings_maxMessageRetriesSubtitle": "Number of retry attempts before marking a message as failed",
|
||||
"path_routeWeight": "{weight}/{max}",
|
||||
"@path_routeWeight": {
|
||||
"placeholders": {
|
||||
"weight": {
|
||||
"type": "String"
|
||||
},
|
||||
"max": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_battery": "Battery",
|
||||
"appSettings_batteryChemistry": "Battery Chemistry",
|
||||
"appSettings_batteryChemistryPerDevice": "Set per device ({deviceName})",
|
||||
@@ -449,6 +449,9 @@
|
||||
}
|
||||
},
|
||||
"contacts_newGroup": "New Group",
|
||||
"contacts_moreOptions": "More options",
|
||||
"contacts_searchOpen": "Search contacts",
|
||||
"contacts_searchClose": "Close search",
|
||||
"contacts_groupName": "Group name",
|
||||
"contacts_groupNameRequired": "Group name is required",
|
||||
"contacts_groupNameReserved": "This group name is reserved",
|
||||
@@ -514,11 +517,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtag channel",
|
||||
"channels_public": "Public",
|
||||
"channels_via": "via {path}",
|
||||
"@channels_via": {
|
||||
"placeholders": {
|
||||
"path": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_private": "Private",
|
||||
"channels_publicChannel": "Public channel",
|
||||
"channels_privateChannel": "Private channel",
|
||||
"channels_editChannel": "Edit channel",
|
||||
"channels_muteChannel": "Mute channel",
|
||||
"channels_unmuteChannel": "Unmute channel",
|
||||
@@ -573,6 +581,18 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ compression",
|
||||
"channels_cyr2latCompression": "Cyr2Lat compression",
|
||||
"channels_cyr2latCompressionDscr": "Replaces some Cyrillic characters with Latin characters when sending.",
|
||||
"channels_cyr2latSettingsHeading": "Cyr2Lat Setup",
|
||||
"channels_cyr2latSettingsSubheading": "List of replacements",
|
||||
"channels_cyr2latSettingsDscr": "Edit the JSON configuration of character replacement",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON replacement map",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Invalid JSON: {error}",
|
||||
"@channels_cyr2latSettingsDialogWrongJSON": {
|
||||
"placeholders": {
|
||||
"error": {}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdated": "Channel \"{name}\" updated",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -581,6 +601,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_cyr2latProfileAdd": "Add Cyr2Lat Profile",
|
||||
"settings_cyr2latProfileName": "Profile Name",
|
||||
"settings_cyr2latProfileNameEmpty": "Profile name cannot be empty",
|
||||
"settings_cyr2latProfileAdded": "Profile added successfully",
|
||||
"settings_cyr2latProfileUpdated": "Profile updated successfully",
|
||||
"settings_cyr2latProfileEdit": "Edit Cyr2Lat Profile",
|
||||
"settings_cyr2latProfileDelete": "Delete Cyr2Lat Profile",
|
||||
"settings_cyr2latProfileDeleted": "Profile deleted successfully",
|
||||
"settings_cyr2latProfileDeleteDscr": "Are you sure you want to delete the profile \"{name}\"?",
|
||||
"@settings_cyr2latProfileDeleteDscr": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_publicChannelAdded": "Public channel added",
|
||||
"channels_sortBy": "Sort by",
|
||||
"channels_sortManual": "Manual",
|
||||
@@ -601,10 +637,10 @@
|
||||
"channels_hashtagHint": "e.g. #team",
|
||||
"chat_noMessages": "No messages yet",
|
||||
"chat_sendMessage": "Send message",
|
||||
"chat_sendMessageTo": "Send message to {name}",
|
||||
"chat_sendMessageTo": "Send a message to {contactName}",
|
||||
"@chat_sendMessageTo": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"contactName": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
@@ -628,14 +664,6 @@
|
||||
}
|
||||
},
|
||||
"chat_location": "Location",
|
||||
"chat_sendMessageTo": "Send a message to {contactName}",
|
||||
"@chat_sendMessageTo": {
|
||||
"placeholders": {
|
||||
"contactName": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat_typeMessage": "Type a message...",
|
||||
"chat_messageTooLong": "Message too long (max {maxBytes} bytes).",
|
||||
"@chat_messageTooLong": {
|
||||
@@ -748,15 +776,6 @@
|
||||
}
|
||||
},
|
||||
"debugFrame_hexDump": "Hex Dump:",
|
||||
"chat_pathManagement": "Path Management",
|
||||
"chat_ShowAllPaths": "Show all paths",
|
||||
"chat_routingMode": "Routing mode",
|
||||
"chat_autoUseSavedPath": "Auto (use saved path)",
|
||||
"chat_forceFloodMode": "Force Flood Mode",
|
||||
"chat_recentAckPaths": "Recent ACK Paths (tap to use):",
|
||||
"chat_pathHistoryFull": "Path history is full. Remove entries to add new ones.",
|
||||
"chat_hopSingular": "hop",
|
||||
"chat_hopPlural": "hops",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
@@ -765,30 +784,80 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat_successes": "successes",
|
||||
"chat_removePath": "Remove path",
|
||||
"chat_noPathHistoryYet": "No path history yet.\nSend a message to discover paths.",
|
||||
"chat_pathActions": "Path Actions:",
|
||||
"chat_setCustomPath": "Set Custom Path",
|
||||
"chat_setCustomPathSubtitle": "Manually specify routing path",
|
||||
"chat_clearPath": "Clear Path",
|
||||
"chat_clearPathSubtitle": "Force rediscovery on next send",
|
||||
"chat_pathCleared": "Path cleared. Next message will rediscover route.",
|
||||
"chat_floodModeSubtitle": "Use routing toggle in app bar",
|
||||
"chat_floodModeEnabled": "Flood mode enabled. Toggle back via routing icon in app bar.",
|
||||
"chat_fullPath": "Full Path",
|
||||
"chat_pathDetailsNotAvailable": "Path details not available yet. Try sending a message to refresh.",
|
||||
"chat_pathSetHops": "Path set: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
|
||||
"@chat_pathSetHops": {
|
||||
"routing_title": "Routing",
|
||||
"routing_modeAuto": "Auto",
|
||||
"routing_modeFlood": "Flood",
|
||||
"routing_modeManual": "Manual",
|
||||
"routing_modeAutoHint": "Picks the best known path automatically, flooding when none is known.",
|
||||
"routing_modeFloodHint": "Broadcasts through every repeater. Most reliable, but uses more airtime.",
|
||||
"routing_modeManualHint": "Always sends along the exact path you set.",
|
||||
"routing_currentRoute": "Current route",
|
||||
"routing_directNoHops": "Direct — no repeater hops",
|
||||
"routing_noPathYet": "No path yet. The next message floods until a route is discovered.",
|
||||
"routing_floodBroadcast": "Broadcast through every repeater",
|
||||
"routing_editPath": "Edit path",
|
||||
"routing_forgetPath": "Forget path",
|
||||
"routing_knownPaths": "Known paths",
|
||||
"routing_knownPathsHint": "Tap a path to switch to it.",
|
||||
"routing_inUse": "In use",
|
||||
"routing_qualityStrong": "Strong first hop",
|
||||
"routing_qualityGood": "Good first hop",
|
||||
"routing_qualityFair": "Fair first hop",
|
||||
"routing_qualityWorked": "Has delivered",
|
||||
"routing_qualityFlood": "Heard via flood",
|
||||
"routing_qualityUntested": "Untested",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"hopCount": {
|
||||
"type": "int"
|
||||
},
|
||||
"status": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"routing_neverWorked": "never confirmed",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"routing_floodDelivery": "Flood delivery",
|
||||
"pathEditor_title": "Build Path",
|
||||
"pathEditor_hopCounter": "{count} of 64 hops",
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathEditor_noHops": "No hops yet. Tap repeaters below to add them in order, or save with no hops to send direct.",
|
||||
"pathEditor_addHops": "Add hops in order",
|
||||
"pathEditor_searchRepeaters": "Search repeaters",
|
||||
"pathEditor_advancedHex": "Advanced: raw hex path",
|
||||
"pathEditor_hexLabel": "Hex prefixes",
|
||||
"pathEditor_hexHelper": "Two hex characters per hop, separated by commas",
|
||||
"pathEditor_invalidTokens": "Invalid: {tokens}",
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathEditor_tooManyHops": "Maximum 64 hops",
|
||||
"pathEditor_usePath": "Use this path",
|
||||
"pathEditor_removeHop": "Remove hop",
|
||||
"pathEditor_unknownHop": "Unknown repeater",
|
||||
"chat_pathSavedLocally": "Saved locally. Connect to sync.",
|
||||
"chat_pathDeviceConfirmed": "Device confirmed.",
|
||||
"chat_pathDeviceNotConfirmed": "Device not confirmed yet.",
|
||||
@@ -817,6 +886,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat_markAsUnread": "Mark as Unread",
|
||||
"chat_newMessages": "New messages",
|
||||
"chat_openLink": "Open Link?",
|
||||
"chat_openLinkConfirmation": "Do you want to open this link in your browser?",
|
||||
"chat_open": "Open",
|
||||
@@ -830,6 +901,17 @@
|
||||
},
|
||||
"chat_invalidLink": "Invalid link format",
|
||||
"map_title": "Node Map",
|
||||
"map_searchHint": "Search node name or ID",
|
||||
"map_activity": "Activity",
|
||||
"map_online": "Online",
|
||||
"map_recent": "Recent",
|
||||
"map_stale": "Stale",
|
||||
"map_visible": "Visible",
|
||||
"map_hidden": "Hidden",
|
||||
"map_centerOnNode": "Center on node",
|
||||
"map_details": "Details",
|
||||
"map_noGps": "No GPS",
|
||||
"map_noResults": "No matching nodes",
|
||||
"map_lineOfSight": "Line of Sight",
|
||||
"map_losScreenTitle": "Line of Sight",
|
||||
"map_noNodesWithLocation": "No nodes with location data",
|
||||
@@ -862,6 +944,12 @@
|
||||
"map_from": "From",
|
||||
"map_source": "Source",
|
||||
"map_flags": "Flags",
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"map_shareMarkerHere": "Share marker here",
|
||||
"map_setAsMyLocation": "Set as my location",
|
||||
"map_pinLabel": "Pin label",
|
||||
@@ -896,6 +984,7 @@
|
||||
"map_guessedLocation": "Guessed location",
|
||||
"map_lastSeenTime": "Last Seen Time",
|
||||
"map_sharedPin": "Shared pin",
|
||||
"map_sharedAt": "Shared",
|
||||
"map_joinRoom": "Join Room",
|
||||
"map_manageRepeater": "Manage Repeater",
|
||||
"map_tapToAdd": "Tap on nodes to add them to the path.",
|
||||
@@ -1061,41 +1150,8 @@
|
||||
"login_failedMessage": "Login failed. Either the password is incorrect or the repeater is unreachable.",
|
||||
"common_reload": "Reload",
|
||||
"common_clear": "Clear",
|
||||
"path_currentPath": "Current path: {path}",
|
||||
"@path_currentPath": {
|
||||
"placeholders": {
|
||||
"path": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path_usingHopsPath": "Using {count} {count, plural, =1{hop} other{hops}} path",
|
||||
"@path_usingHopsPath": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path_enterCustomPath": "Enter Custom Path",
|
||||
"path_currentPathLabel": "Current path",
|
||||
"path_hexPrefixInstructions": "Enter 2-character hex prefixes for each hop, separated by commas.",
|
||||
"path_hexPrefixExample": "Example: A1,F2,3C (each node uses first byte of its public key)",
|
||||
"path_labelHexPrefixes": "Path (hex prefixes)",
|
||||
"path_helperMaxHops": "Max 64 hops. Each prefix is 2 hex characters (1 byte)",
|
||||
"path_selectFromContacts": "Or select from contacts:",
|
||||
"path_noRepeatersFound": "No repeaters or room servers found.",
|
||||
"path_customPathsRequire": "Custom paths require intermediate hops that can relay messages.",
|
||||
"path_invalidHexPrefixes": "Invalid hex prefixes: {prefixes}",
|
||||
"@path_invalidHexPrefixes": {
|
||||
"placeholders": {
|
||||
"prefixes": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path_tooLong": "Path too long. Maximum 64 hops allowed.",
|
||||
"path_setPath": "Set Path",
|
||||
"repeater_management": "Repeater Management",
|
||||
"room_management": "Room Server Management",
|
||||
"repeater_guest": "Repeater Information",
|
||||
@@ -1122,9 +1178,6 @@
|
||||
},
|
||||
"repeater_statusTitle": "Repeater Status",
|
||||
"repeater_routingMode": "Routing mode",
|
||||
"repeater_autoUseSavedPath": "Auto (use saved path)",
|
||||
"repeater_forceFloodMode": "Force Flood Mode",
|
||||
"repeater_pathManagement": "Path management",
|
||||
"repeater_refresh": "Refresh",
|
||||
"repeater_statusRequestTimeout": "Status request timed out.",
|
||||
"repeater_errorLoadingStatus": "Error loading status: {error}",
|
||||
@@ -1147,6 +1200,7 @@
|
||||
"repeater_noiseFloor": "Noise Floor",
|
||||
"repeater_txAirtime": "TX Airtime",
|
||||
"repeater_rxAirtime": "RX Airtime",
|
||||
"repeater_chanUtil": "Channel Utilization",
|
||||
"repeater_packetStatistics": "Packet Statistics",
|
||||
"repeater_sent": "Sent",
|
||||
"repeater_received": "Received",
|
||||
@@ -1292,6 +1346,81 @@
|
||||
},
|
||||
"repeater_confirm": "Confirm",
|
||||
"repeater_settingsSaved": "Settings saved successfully",
|
||||
"repeater_rxGain": "Boosted RX gain",
|
||||
"repeater_rxGainHelper": "Higher sensitivity, more current draw (SX1262/SX1268 only)",
|
||||
"repeater_refreshRxGain": "Refresh boosted RX gain",
|
||||
"repeater_multiAcks": "Multi-ACKs",
|
||||
"repeater_multiAcksSubtitle": "Acknowledge messages over multiple paths for better delivery",
|
||||
"repeater_refreshMultiAcks": "Refresh multi-ACKs",
|
||||
"repeater_networkHealth": "Network health",
|
||||
"repeater_loopDetect": "Loop detection",
|
||||
"repeater_loopDetectHelper": "Drop flood packets that look like routing loops",
|
||||
"repeater_loopDetectOff": "Off",
|
||||
"repeater_loopDetectMinimal": "Minimal",
|
||||
"repeater_loopDetectModerate": "Moderate",
|
||||
"repeater_loopDetectStrict": "Strict",
|
||||
"repeater_dutyCycle": "Duty cycle",
|
||||
"repeater_dutyCycleHelper": "Maximum percentage of airtime",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Operator info",
|
||||
"repeater_ownerInfoHelper": "Public metadata for this repeater",
|
||||
"repeater_refreshOwnerInfo": "Refresh operator info",
|
||||
"repeater_floodMax": "Flood max hops",
|
||||
"repeater_floodMaxHelper": "Maximum hops a flood packet may travel (0-64)",
|
||||
"repeater_advancedSettings": "Advanced",
|
||||
"repeater_advancedSettingsSubtitle": "Tuning knobs for experienced operators",
|
||||
"repeater_pathHashMode": "Path hash mode",
|
||||
"repeater_pathHashModeHelper": "Bytes used to encode this repeater's ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.",
|
||||
"repeater_txDelay": "Flood TX delay",
|
||||
"repeater_txDelayHelper": "Retransmit spacing for flood traffic, as a multiplier of the packet's airtime (0-2, default 0.5). Higher = fewer collisions but slower delivery.",
|
||||
"repeater_directTxDelay": "Direct TX delay",
|
||||
"repeater_directTxDelayHelper": "Retransmit spacing for direct (non-flood) traffic, as a multiplier of the packet's airtime (0-2, default 0.3).",
|
||||
"repeater_intThresh": "Interference threshold",
|
||||
"repeater_intThreshHelper": "Threshold passed to the radio's noise-floor calibration so it rejects interference above this level. 0 disables — only raise if you see RX errors in a noisy band.",
|
||||
"repeater_agcResetInterval": "AGC reset interval",
|
||||
"repeater_agcResetIntervalHelper": "How often to reset the radio's automatic gain control to recover from a stuck gain state. Seconds, snapped down to a multiple of 4. 0 disables periodic resets.",
|
||||
"repeater_actionsTitle": "Actions",
|
||||
"repeater_sendAdvert": "Send flood advert",
|
||||
"repeater_sendAdvertSubtitle": "Broadcast a flood advert through the network",
|
||||
"repeater_sendAdvertZeroHop": "Send zero-hop advert",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Broadcast a one-hop advert (no relays)",
|
||||
"repeater_clockSync": "Sync clock now",
|
||||
"repeater_clockSyncSubtitle": "Push your phone's time to the repeater",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Settings saved — reboot the repeater to apply",
|
||||
"repeater_settingsPartialFailure": "Some settings failed: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Error saving settings: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1303,11 +1432,9 @@
|
||||
"repeater_refreshBasicSettings": "Refresh Basic Settings",
|
||||
"repeater_refreshRadioSettings": "Refresh Radio Settings",
|
||||
"repeater_refreshTxPower": "Refresh TX power",
|
||||
"repeater_refreshLocationSettings": "Refresh Location Settings",
|
||||
"repeater_refreshPacketForwarding": "Refresh Packet Forwarding",
|
||||
"repeater_refreshGuestAccess": "Refresh Guest Access",
|
||||
"repeater_refreshPrivacyMode": "Refresh Privacy Mode",
|
||||
"repeater_refreshAdvertisementSettings": "Refresh Advertisement Settings",
|
||||
"repeater_refreshed": "{label} refreshed",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1417,6 +1544,77 @@
|
||||
"repeater_regionNote": "Region commands have been introduced to manage region definitions and permissions.",
|
||||
"repeater_gpsManagement": "GPS Management",
|
||||
"repeater_gpsNote": "gps command has been introduced to manage location related topics.",
|
||||
"repeater_getCategory": "Get Values",
|
||||
"repeater_powerMgmt": "Power Management",
|
||||
"repeater_sensors": "Sensors",
|
||||
"repeater_cliHelpPowerOff": "Powers the device off. (no response expected)",
|
||||
"repeater_cliHelpClkReboot": "Resets the clock to a known epoch and reboots the device.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Sends a zero-hop advertisement (immediate neighbors only).",
|
||||
"repeater_cliHelpStartOta": "Starts an over-the-air firmware update on supported boards.",
|
||||
"repeater_cliHelpTime": "Sets the device clock to the given Unix epoch seconds. Clock cannot move backwards.",
|
||||
"repeater_cliHelpBoard": "Shows the board manufacturer / hardware identifier.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Sends a node-discovery request to nearby neighbors. (Repeater only)",
|
||||
"repeater_cliHelpPowersaving": "Shows whether powersaving mode is on or off.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Enables or disables powersaving mode (where supported).",
|
||||
"repeater_cliHelpErase": "(Serial only) Formats the device file system. Wipes all settings and contacts.",
|
||||
"repeater_cliHelpSetDutyCycle": "Sets the maximum allowed transmit duty cycle as a percentage (1-100). Internally adjusts the airtime factor.",
|
||||
"repeater_cliHelpSetPrvKey": "(Serial only) Replaces the device identity private key. Reboot required to apply. Generates a new public key.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(SX126x only) Toggles boosted RX gain for improved sensitivity at higher current draw.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Sets the owner contact info string included in adverts. Use '|' for newlines.",
|
||||
"repeater_cliHelpSetPathHashMode": "Sets the path-hash mode. 0 = legacy, 1 = standard, 2 = strict. Affects how routing paths are matched.",
|
||||
"repeater_cliHelpSetLoopDetect": "Sets the routing loop-detection sensitivity: off, minimal, moderate, or strict.",
|
||||
"repeater_cliHelpSetFreq": "(Serial only) Quickly sets just the frequency. Reboot required. Prefer \"set radio\" for full radio params.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(ESPNow bridge only) Sets the WiFi channel (1-14) used by the bridge.",
|
||||
"repeater_cliHelpGetName": "Shows the configured node name.",
|
||||
"repeater_cliHelpGetRole": "Shows the firmware role (Repeater, Room Server, etc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Shows the device public key.",
|
||||
"repeater_cliHelpGetPrvKey": "(Serial only) Shows the device private key. Treat as a secret.",
|
||||
"repeater_cliHelpGetRepeat": "Shows whether packet forwarding (repeater role) is on or off.",
|
||||
"repeater_cliHelpGetTx": "Shows the current TX power in dBm.",
|
||||
"repeater_cliHelpGetFreq": "Shows the configured radio frequency in MHz.",
|
||||
"repeater_cliHelpGetRadio": "Shows full radio params: freq, bandwidth, spreading factor, coding rate.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(SX126x only) Shows the RX boosted gain state.",
|
||||
"repeater_cliHelpGetAf": "Shows the current airtime factor.",
|
||||
"repeater_cliHelpGetDutyCycle": "Shows the current allowed duty cycle as a percentage.",
|
||||
"repeater_cliHelpGetIntThresh": "Shows the channel interference threshold in dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Shows the AGC reset interval in seconds.",
|
||||
"repeater_cliHelpGetMultiAcks": "Shows whether double-ACK mode is on (1) or off (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Shows whether guest read-only access is allowed.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Shows the local advertisement interval in minutes.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Shows the flood advertisement interval in hours.",
|
||||
"repeater_cliHelpGetGuestPassword": "Shows the configured guest password.",
|
||||
"repeater_cliHelpGetLat": "Shows the configured latitude.",
|
||||
"repeater_cliHelpGetLon": "Shows the configured longitude.",
|
||||
"repeater_cliHelpGetRxDelay": "Shows the rxdelay base value.",
|
||||
"repeater_cliHelpGetTxDelay": "Shows the flood-mode txdelay factor.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Shows the direct-mode txdelay factor.",
|
||||
"repeater_cliHelpGetFloodMax": "Shows the maximum flood hop count.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Shows the owner contact info string.",
|
||||
"repeater_cliHelpGetPathHashMode": "Shows the path-hash mode (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Shows the loop-detection sensitivity.",
|
||||
"repeater_cliHelpGetAcl": "(Serial only) Lists the access-control entries on a repeater.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Shows whether the bridge is enabled.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Shows the bridge delay in ms.",
|
||||
"repeater_cliHelpGetBridgeSource": "Shows whether the bridge logs RX or TX packets.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(RS232 bridge only) Shows the bridge baud rate.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(ESPNow bridge only) Shows the bridge WiFi channel.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(ESPNow bridge only) Shows the bridge shared secret.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(NRF52 only) Shows the bootloader version.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Shows the ADC multiplier (battery-voltage scaling).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Reports whether the board has power-management support.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Shows the current power source: external or battery.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Shows the most recent reset and shutdown reasons.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Shows the boot-time battery voltage in mV.",
|
||||
"repeater_cliHelpSensorGet": "Reads a custom sensor setting by key.",
|
||||
"repeater_cliHelpSensorSet": "Writes a custom sensor setting.",
|
||||
"repeater_cliHelpSensorList": "Lists all custom sensor settings, paginated from optional start index.",
|
||||
"repeater_cliHelpRegionDefault": "Shows the current default region scope.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Sets the default region scope. Use \"<null>\" to clear.",
|
||||
"repeater_cliHelpRegionListAllowed": "Lists regions that allow flood traffic.",
|
||||
"repeater_cliHelpRegionListDenied": "Lists regions that deny flood traffic.",
|
||||
"repeater_cliHelpStatsPackets": "(Serial only) Shows packet-level statistics.",
|
||||
"repeater_cliHelpStatsRadio": "(Serial only) Shows radio statistics.",
|
||||
"repeater_cliHelpStatsCore": "(Serial only) Shows core firmware statistics.",
|
||||
"telemetry_receivedData": "Received Telemetry Data",
|
||||
"telemetry_requestTimeout": "Telemetry request timed out.",
|
||||
"telemetry_errorLoading": "Error loading telemetry: {error}",
|
||||
@@ -1479,6 +1677,120 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digital Input",
|
||||
"telemetry_digitalOutputLabel": "Digital Output",
|
||||
"telemetry_analogInputLabel": "Analog Input",
|
||||
"telemetry_analogOutputLabel": "Analog Output",
|
||||
"telemetry_genericLabel": "Generic Sensor",
|
||||
"telemetry_luminosityLabel": "Luminosity",
|
||||
"telemetry_presenceLabel": "Presence",
|
||||
"telemetry_humidityLabel": "Humidity",
|
||||
"telemetry_accelerometerLabel": "Accelerometer",
|
||||
"telemetry_pressureLabel": "Pressure",
|
||||
"telemetry_altitudeLabel": "Altitude",
|
||||
"telemetry_frequencyLabel": "Frequency",
|
||||
"telemetry_percentageLabel": "Percentage",
|
||||
"telemetry_concentrationLabel": "Concentration",
|
||||
"telemetry_powerLabel": "Power",
|
||||
"telemetry_distanceLabel": "Distance",
|
||||
"telemetry_energyLabel": "Energy",
|
||||
"telemetry_directionLabel": "Direction",
|
||||
"telemetry_timeLabel": "Time",
|
||||
"telemetry_gyrometerLabel": "Gyrometer",
|
||||
"telemetry_colourLabel": "Colour",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Switch",
|
||||
"telemetry_polylineLabel": "Polyline",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"@telemetry_altitudeValue": {
|
||||
"placeholders": {
|
||||
"meters": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"@telemetry_frequencyValue": {
|
||||
"placeholders": {
|
||||
"hertz": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"@telemetry_pressureValue": {
|
||||
"placeholders": {
|
||||
"hpa": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"@telemetry_luminosityValue": {
|
||||
"placeholders": {
|
||||
"lux": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"@telemetry_powerValue": {
|
||||
"placeholders": {
|
||||
"watts": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"@telemetry_distanceValue": {
|
||||
"placeholders": {
|
||||
"meters": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"@telemetry_energyValue": {
|
||||
"placeholders": {
|
||||
"kilowattHours": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"@telemetry_directionValue": {
|
||||
"placeholders": {
|
||||
"degrees": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"@telemetry_concentrationValue": {
|
||||
"placeholders": {
|
||||
"ppm": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"@telemetry_percentageValue": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_analogValue": "{value}",
|
||||
"@telemetry_analogValue": {
|
||||
"placeholders": {
|
||||
"value": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_autoFetchQuantity": "Requests quantity",
|
||||
"telemetry_error": "Unable to retrieve data",
|
||||
"neighbors_receivedData": "Received Neighbors Data",
|
||||
"neighbors_requestTimedOut": "Neighbors request timed out.",
|
||||
"neighbors_errorLoading": "Error loading neighbors: {error}",
|
||||
@@ -1875,6 +2187,46 @@
|
||||
"losLegendRadioHorizon": "Radio horizon",
|
||||
"losLegendLosBeam": "LOS beam",
|
||||
"losLegendTerrain": "Terrain",
|
||||
"losBlockedSpotsTitle": "Blocked spots",
|
||||
"losBlockedSpotsHint": "Tap a blocked spot to highlight it on the map.",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Selected obstruction",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losFrequencyLabel": "Frequency",
|
||||
"losFrequencyInfoTooltip": "View calculation details",
|
||||
"losFrequencyDialogTitle": "Radio horizon calculation",
|
||||
@@ -2061,12 +2413,14 @@
|
||||
"radioStats_stripWaiting": "Fetching radio stats…",
|
||||
"radioStats_settingsTile": "Radio stats",
|
||||
"radioStats_settingsSubtitle": "Noise floor, RSSI, SNR, and airtime",
|
||||
|
||||
"translation_title": "Translation",
|
||||
"translation_enableTitle": "Enable translation",
|
||||
"translation_enableSubtitle": "Translate incoming messages and allow pre-send translation.",
|
||||
"translation_composerTitle": "Translate before sending",
|
||||
"translation_composerSubtitle": "Controls the default state of the composer translation icon.",
|
||||
"translation_autoIncomingTitle": "Auto-translate incoming messages",
|
||||
"translation_autoIncomingSubtitle": "Translates Messages for notification and for chat or channel automatically.",
|
||||
"translation_translateMessage": "Translate message",
|
||||
"translation_targetLanguage": "Target language",
|
||||
"translation_useAppLanguage": "Use app language",
|
||||
"translation_downloadedModelLabel": "Downloaded model",
|
||||
@@ -2114,5 +2468,132 @@
|
||||
}
|
||||
},
|
||||
"translation_translationOptions": "Translation options",
|
||||
"translation_systemLanguage": "System language"
|
||||
"translation_systemLanguage": "System language",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"map_zoomIn": "Zoom in",
|
||||
"map_zoomOut": "Zoom out",
|
||||
"map_centerMap": "Center map",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth requires a Chromium browser",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathTrace_legendGpsConfirmed": "GPS confirmed",
|
||||
"pathTrace_legendInferred": "Inferred position",
|
||||
"pathMap_viewSingle": "Single",
|
||||
"pathMap_viewCombined": "Combined",
|
||||
"pathMap_play": "Play",
|
||||
"pathMap_pause": "Pause",
|
||||
"pathMap_replay": "Replay",
|
||||
"pathMap_stepBack": "Previous hop",
|
||||
"pathMap_stepForward": "Next hop",
|
||||
"pathMap_animationOn": "Show packet animation",
|
||||
"pathMap_animationOff": "Hide packet animation",
|
||||
"pathMap_hopOf": "Hop {current} of {total}",
|
||||
"@pathMap_hopOf": {
|
||||
"placeholders": {
|
||||
"current": {
|
||||
"type": "int"
|
||||
},
|
||||
"total": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_observedPaths": "Observed paths: {count}",
|
||||
"@pathMap_observedPaths": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_primary": "Primary",
|
||||
"pathMap_alternate": "Alt {index}",
|
||||
"@pathMap_alternate": {
|
||||
"placeholders": {
|
||||
"index": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_hopCount": "{count, plural, =1{1 hop} other{{count} hops}}",
|
||||
"@pathMap_hopCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_gpsCount": "{confirmed}/{total} GPS",
|
||||
"@pathMap_gpsCount": {
|
||||
"placeholders": {
|
||||
"confirmed": {
|
||||
"type": "int"
|
||||
},
|
||||
"total": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_legendShared": "Shared segment",
|
||||
"pathMap_legendEstimated": "Estimated segment",
|
||||
"pathMap_sharedNodeCount": "Used by {count} paths",
|
||||
"@pathMap_sharedNodeCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_partialAnimation": "{count, plural, =1{1 hop has no location — the shown path is partial} other{{count} hops have no location — the shown path is partial}}",
|
||||
"@pathMap_partialAnimation": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pathMap_showAllPaths": "Show all",
|
||||
"pathMap_hidePath": "Hide path",
|
||||
"pathMap_showPath": "Show path",
|
||||
"pathMap_collapsePanel": "Collapse panel",
|
||||
"pathMap_expandPanel": "Expand panel",
|
||||
"pathMap_noLocation": "No location",
|
||||
"pathMap_followPacket": "Lock view to packet",
|
||||
"pathMap_unfollowPacket": "Unlock view from packet"
|
||||
}
|
||||
|
||||
+410
-30
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Eliminar",
|
||||
"common_enable": "Activar",
|
||||
"common_disable": "Desactivar",
|
||||
"common_autoRefresh": "Actualización automática",
|
||||
"common_interval": "Intervalo",
|
||||
"common_reboot": "Reiniciar",
|
||||
"common_loading": "Cargando...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore: Versión abierta",
|
||||
"scanner_scanning": "Escaneando dispositivos...",
|
||||
"scanner_connecting": "Conectando...",
|
||||
"scanner_disconnecting": "Desconectando...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Modo de privacidad activado",
|
||||
"settings_privacyModeDisabled": "Modo de privacidad desactivado",
|
||||
"settings_actions": "Acciones",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Enviar Anuncio",
|
||||
"settings_sendAdvertisementSubtitle": "Presencia de transmisión ahora",
|
||||
"settings_advertisementSent": "Anuncio enviado",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Registro de Depuración de la App",
|
||||
"settings_appDebugLogSubtitle": "Mensajes de depuración de la aplicación",
|
||||
"settings_about": "Acerca de",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open versión {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Oscuro",
|
||||
"appSettings_language": "Idioma",
|
||||
"appSettings_languageSystem": "Predeterminado del sistema",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEn": "Inglés",
|
||||
"appSettings_languageFr": "Francés",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageDe": "Alemán",
|
||||
"appSettings_languagePl": "Polaco",
|
||||
"appSettings_languageSl": "Esloveno",
|
||||
"appSettings_languagePt": "Portugués",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageZh": "Chino",
|
||||
"appSettings_languageSv": "Sueco",
|
||||
"appSettings_languageNl": "Neerlandés",
|
||||
"appSettings_languageSk": "Esloveno",
|
||||
"appSettings_languageBg": "Bulgaro",
|
||||
"appSettings_notifications": "Notificaciones",
|
||||
"appSettings_enableNotifications": "Habilitar Notificaciones",
|
||||
"appSettings_enableNotificationsSubtitle": "Recibir notificaciones para mensajes y anuncios",
|
||||
@@ -209,8 +213,8 @@
|
||||
}
|
||||
},
|
||||
"appSettings_batteryChemistryConnectFirst": "Conéctate a un dispositivo para elegir",
|
||||
"appSettings_batteryNmc": "18650 NMC (3.0-4.2V)",
|
||||
"appSettings_batteryLifepo4": "LiFePO4 (2.6-3.65V)",
|
||||
"appSettings_batteryNmc": "18650 NMC (3,0-4,2 V)",
|
||||
"appSettings_batteryLifepo4": "LiFePO4 (2.6-3.65 V)",
|
||||
"appSettings_batteryLipo": "LiPo (3.0-4.2V)",
|
||||
"appSettings_mapDisplay": "Visualización del Mapa",
|
||||
"appSettings_showRepeaters": "Mostrar Repetidores",
|
||||
@@ -298,7 +302,7 @@
|
||||
"contacts_noContactsMatchFilter": "No hay contactos que coincidan con tu filtro",
|
||||
"contacts_noMembers": "No miembros",
|
||||
"contacts_lastSeenNow": "Última vez que se vio ahora",
|
||||
"contacts_lastSeenMinsAgo": "~ {minutes} min.",
|
||||
"contacts_lastSeenMinsAgo": "~ {minutes} minutos",
|
||||
"@contacts_lastSeenMinsAgo": {
|
||||
"placeholders": {
|
||||
"minutes": {
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Canal con hashtag",
|
||||
"channels_public": "Público",
|
||||
"channels_private": "Privado",
|
||||
"channels_publicChannel": "Canal público",
|
||||
"channels_privateChannel": "Canal privado",
|
||||
"channels_editChannel": "Editar canal",
|
||||
"channels_muteChannel": "Silenciar canal",
|
||||
"channels_unmuteChannel": "Activar canal",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Compresión SMAZ",
|
||||
"channels_cyr2latCompression": "Compresión Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Reemplaza algunos caracteres cirílicos con caracteres latinos al enviar.",
|
||||
"channels_cyr2latSettingsHeading": "Configuración de Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Lista de sustituciones",
|
||||
"channels_cyr2latSettingsDscr": "Editar la configuración JSON de sustitución de caracteres",
|
||||
"channels_cyr2latSettingsDialogHint": "Mapa JSON de sustituciones",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "JSON incorrecto: {error}",
|
||||
"settings_cyr2latProfileAdd": "Añadir perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Nombre del perfil",
|
||||
"settings_cyr2latProfileNameEmpty": "El nombre del perfil no puede estar vacío",
|
||||
"settings_cyr2latProfileAdded": "Perfil añadido correctamente",
|
||||
"settings_cyr2latProfileUpdated": "Perfil actualizado correctamente",
|
||||
"settings_cyr2latProfileEdit": "Editar perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Eliminar perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Perfil eliminado correctamente",
|
||||
"settings_cyr2latProfileDeleteDscr": "¿Está seguro de que desea eliminar el perfil \"{name}\"?",
|
||||
"channels_channelUpdated": "Canal \"{name}\" actualizado",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Canal público añadido",
|
||||
"channels_sortBy": "Ordenar por",
|
||||
"channels_sortManual": "Manual",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "De la A a la Z",
|
||||
"channels_sortLatestMessages": "Últimos mensajes",
|
||||
"channels_sortUnread": "Sin leer",
|
||||
"chat_noMessages": "Aún no hay mensajes",
|
||||
@@ -463,7 +480,7 @@
|
||||
"emojiCategoryObjects": "Objetos",
|
||||
"gifPicker_title": "Elegir un GIF",
|
||||
"gifPicker_searchHint": "Buscar GIFs...",
|
||||
"gifPicker_poweredBy": "Powered by GIPHY",
|
||||
"gifPicker_poweredBy": "Con tecnología de GIPHY",
|
||||
"gifPicker_noGifsFound": "No se encontraron GIFs",
|
||||
"gifPicker_failedLoad": "No se pudo cargar los GIFs",
|
||||
"gifPicker_failedSearch": "No se encontraron GIFs",
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Interfaz de línea de comandos",
|
||||
"debugFrame_textTypePlain": "Sencillo",
|
||||
"debugFrame_text": "- Texto: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "El historial de rutas está completo. Eliminar entradas para añadir nuevas.",
|
||||
"chat_hopSingular": "salta",
|
||||
"chat_hopPlural": "salta",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{salto} other{saltos}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -645,7 +662,7 @@
|
||||
"map_repeater": "Repetidor",
|
||||
"map_room": "Habitación",
|
||||
"map_sensor": "Sensor",
|
||||
"map_pinDm": "Pin (DM)",
|
||||
"map_pinDm": "Etiqueta (DM)",
|
||||
"map_pinPrivate": "Bloqueo (Privado)",
|
||||
"map_pinPublic": "Clave (Pública)",
|
||||
"map_lastSeen": "Última vez que se vio",
|
||||
@@ -881,9 +898,9 @@
|
||||
"repeater_managementTools": "Herramientas de Gestión",
|
||||
"repeater_status": "Estado",
|
||||
"repeater_statusSubtitle": "Ver el estado, las estadísticas y los vecinos del repetidor",
|
||||
"repeater_telemetry": "Telemetry",
|
||||
"repeater_telemetry": "Telemetría",
|
||||
"repeater_telemetrySubtitle": "Ver la telemetría de los sensores y las estadísticas del sistema",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Interfaz de línea de comandos",
|
||||
"repeater_cliSubtitle": "Enviar comandos al repetidor",
|
||||
"repeater_settings": "Configuración",
|
||||
"repeater_settingsSubtitle": "Configurar parámetros del repetidor",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Confirmar",
|
||||
"repeater_settingsSaved": "Guardado de ajustes exitoso",
|
||||
"repeater_rxGain": "Aumento en la ganancia de RX",
|
||||
"repeater_rxGainHelper": "Mayor sensibilidad, mayor consumo de corriente (solo para SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Aumenta el rendimiento de RX con la nueva versión.",
|
||||
"repeater_multiAcks": "Múltiples respuestas de confirmación",
|
||||
"repeater_multiAcksSubtitle": "Reconocer mensajes a través de múltiples vías para una mejor entrega.",
|
||||
"repeater_refreshMultiAcks": "Reenviar múltiples confirmaciones",
|
||||
"repeater_networkHealth": "Salud de la red",
|
||||
"repeater_loopDetect": "Detección de bucles",
|
||||
"repeater_loopDetectHelper": "Crea paquetes de \"flujo\" que parezcan bucles de enrutamiento.",
|
||||
"repeater_loopDetectOff": "Fuera",
|
||||
"repeater_loopDetectMinimal": "Mínimo",
|
||||
"repeater_loopDetectModerate": "Moderado",
|
||||
"repeater_loopDetectStrict": "Estrictos",
|
||||
"repeater_dutyCycle": "Ciclo de trabajo",
|
||||
"repeater_dutyCycleHelper": "Porcentaje máximo de tiempo de antena",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Información del operador",
|
||||
"repeater_ownerInfoHelper": "Metadatos públicos para este repetidor",
|
||||
"repeater_refreshOwnerInfo": "Actualizar información del operador",
|
||||
"repeater_floodMax": "Máximo número de saltos en caso de inundación",
|
||||
"repeater_floodMaxHelper": "Número máximo de paquetes de flujo que un nodo puede enviar (0-64)",
|
||||
"repeater_advancedSettings": "Avanzado",
|
||||
"repeater_advancedSettingsSubtitle": "Perillas de ajuste para operadores experimentados",
|
||||
"repeater_pathHashMode": "Modo de hash de ruta",
|
||||
"repeater_pathHashModeHelper": "Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). Las versiones 1.13 y anteriores de firmware eliminan rutas de múltiples bytes; solo se detectan una vez que la red está activa en la versión 1.14 o posterior.",
|
||||
"repeater_txDelay": "Retraso en Flood, TX",
|
||||
"repeater_txDelayHelper": "Ajuste de retransmisión para el tráfico de inundación, como un multiplicador del tiempo de transmisión del paquete (0-2, valor predeterminado 0.5). Un valor más alto significa menos colisiones, pero una entrega más lenta.",
|
||||
"repeater_directTxDelay": "Retraso directo en TX",
|
||||
"repeater_directTxDelayHelper": "Reenvío de espacios para el tráfico directo (no masivo), como un multiplicador del tiempo de transmisión del paquete (0-2, valor predeterminado 0.3).",
|
||||
"repeater_intThresh": "Límite de interferencia",
|
||||
"repeater_intThreshHelper": "Se establece un umbral para la calibración del nivel de ruido de la radio, de modo que rechaza las interferencias que superen este nivel. 0 deshabilita — solo aumente este valor si observa errores en una banda de frecuencia con mucho ruido.",
|
||||
"repeater_agcResetInterval": "Intervalo de reinicio de AGC",
|
||||
"repeater_agcResetIntervalHelper": "¿Con qué frecuencia se debe restablecer el control automático de ganancia del radio para recuperarse de un estado de ganancia bloqueada? Se puede restablecer cada pocos segundos, o cada 4 segundos. Desactivar la función de restablecimiento periódico.",
|
||||
"repeater_actionsTitle": "Acciones",
|
||||
"repeater_sendAdvert": "Enviar anuncio sobre inundaciones",
|
||||
"repeater_sendAdvertSubtitle": "Transmite un anuncio sobre inundaciones a través de la red.",
|
||||
"repeater_sendAdvertZeroHop": "Enviar anuncio sin intermediarios",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Transmite un anuncio de un solo salto (sin retransmisiones).",
|
||||
"repeater_clockSync": "Sincronizar reloj ahora",
|
||||
"repeater_clockSyncSubtitle": "Envía la hora de tu teléfono al repetidor.",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Configuración guardada — reinicie el repetidor para aplicar los cambios.",
|
||||
"repeater_settingsPartialFailure": "Algunas configuraciones no se pudieron aplicar: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Error al guardar la configuración: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Actualizar Configuración Básica",
|
||||
"repeater_refreshRadioSettings": "Actualizar Ajustes de Radio",
|
||||
"repeater_refreshTxPower": "Actualizar TX de energía",
|
||||
"repeater_refreshLocationSettings": "Actualizar Configuración de Ubicación",
|
||||
"repeater_refreshPacketForwarding": "Actualizar Enrutamiento de Paquetes",
|
||||
"repeater_refreshGuestAccess": "Actualizar Acceso Invitados",
|
||||
"repeater_refreshPrivacyMode": "Actualizar Modo Privacidad",
|
||||
"repeater_refreshAdvertisementSettings": "Actualizar Configuración de Anuncios",
|
||||
"repeater_refreshed": "{label} actualizado",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Entrada digital",
|
||||
"telemetry_digitalOutputLabel": "Salida digital",
|
||||
"telemetry_analogInputLabel": "Entrada analógica",
|
||||
"telemetry_analogOutputLabel": "Salida analógica",
|
||||
"telemetry_genericLabel": "Sensor genérico",
|
||||
"telemetry_luminosityLabel": "Luminosidad",
|
||||
"telemetry_presenceLabel": "Presencia",
|
||||
"telemetry_humidityLabel": "Humedad",
|
||||
"telemetry_accelerometerLabel": "Acelerómetro",
|
||||
"telemetry_pressureLabel": "Presión",
|
||||
"telemetry_altitudeLabel": "Altitud",
|
||||
"telemetry_frequencyLabel": "Frecuencia",
|
||||
"telemetry_percentageLabel": "Porcentaje",
|
||||
"telemetry_concentrationLabel": "Concentración",
|
||||
"telemetry_powerLabel": "Potencia",
|
||||
"telemetry_distanceLabel": "Distancia",
|
||||
"telemetry_energyLabel": "Energía",
|
||||
"telemetry_directionLabel": "Dirección",
|
||||
"telemetry_timeLabel": "Hora",
|
||||
"telemetry_gyrometerLabel": "Girómetro",
|
||||
"telemetry_colourLabel": "Color",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Interruptor",
|
||||
"telemetry_polylineLabel": "Polilínea",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Número de solicitudes",
|
||||
"telemetry_error": "No se pudieron obtener los datos",
|
||||
"telemetry_noData": "No hay datos de telemetría disponibles.",
|
||||
"telemetry_channelTitle": "Canal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Ordenar por",
|
||||
"listFilter_latestMessages": "Últimos mensajes",
|
||||
"listFilter_heardRecently": "Escuchado recientemente",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "De la A a la Z",
|
||||
"listFilter_filters": "Filtros",
|
||||
"listFilter_all": "Todas",
|
||||
"listFilter_users": "Usuarios",
|
||||
@@ -1962,6 +2089,7 @@
|
||||
"appSettings_maxMessageRetriesSubtitle": "Número de intentos de reintento antes de marcar un mensaje como fallido.",
|
||||
"path_routeWeight": "{weight}/{max}",
|
||||
"settings_telemetryModeUpdated": "Modo de telemetría actualizado",
|
||||
"settings_multiAck": "Múltiples respuestas de confirmación",
|
||||
"map_showOverlaps": "Superposiciones de tecla repetidora",
|
||||
"map_runTraceWithReturnPath": "Volver atrás por el mismo camino.",
|
||||
"@radioStats_noiseFloor": {
|
||||
@@ -2039,6 +2167,9 @@
|
||||
"translation_enableTitle": "Habilitar la traducción",
|
||||
"translation_composerTitle": "Traducir antes de enviar",
|
||||
"translation_composerSubtitle": "Controla el estado predeterminado del icono de traducción del compositor.",
|
||||
"translation_autoIncomingTitle": "Traducir mensajes automáticamente",
|
||||
"translation_autoIncomingSubtitle": "Traduce mensajes para notificaciones y para chats o canales automáticamente.",
|
||||
"translation_translateMessage": "Traducir mensaje",
|
||||
"translation_targetLanguage": "Idioma de destino",
|
||||
"translation_useAppLanguage": "Utilizar el idioma de la aplicación",
|
||||
"translation_downloadedModelLabel": "Modelo descargado",
|
||||
@@ -2094,5 +2225,254 @@
|
||||
"chat_sendMessage": "Enviar mensaje",
|
||||
"repeater_guestTools": "Herramientas para invitados",
|
||||
"room_guest": "Información del servidor",
|
||||
"settings_multiAck": "Múltiples respuestas de confirmación"
|
||||
"repeater_getCategory": "Obtener valores",
|
||||
"repeater_powerMgmt": "Gestión de la energía",
|
||||
"repeater_sensors": "Sensores",
|
||||
"repeater_cliHelpPowerOff": "Apaga el dispositivo. (no se espera respuesta)",
|
||||
"repeater_cliHelpClkReboot": "Restablece el reloj a una fecha conocida y reinicia el dispositivo.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Envía un anuncio que no requiere saltos (solo para los vecinos inmediatos).",
|
||||
"repeater_cliHelpStartOta": "Inicia una actualización de firmware por aire en las placas compatibles.",
|
||||
"repeater_cliHelpTime": "Establece la hora del dispositivo en los segundos correspondientes a la época Unix. La hora no puede retroceder.",
|
||||
"repeater_cliHelpBoard": "Muestra el fabricante de la placa base / identificador de hardware.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Envía una solicitud de descubrimiento de nodos a los vecinos cercanos. (Solo para repetidores)",
|
||||
"repeater_cliHelpPowersaving": "Indica si el modo de ahorro de energía está activado o desactivado.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Activa o desactiva el modo de ahorro de energía (si está disponible).",
|
||||
"repeater_cliHelpErase": "(Solo para dispositivos) Formatea el sistema de archivos del dispositivo. Elimina todas las configuraciones y contactos.",
|
||||
"repeater_cliHelpSetDutyCycle": "Establece el ciclo de transmisión máximo permitido como un porcentaje (1-100). Ajusta internamente el factor de tiempo de aire.",
|
||||
"repeater_cliHelpSetPrvKey": "(Solo para series) Reemplaza la clave privada de identificación del dispositivo. Se requiere reiniciar para aplicar. Genera una nueva clave pública.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Solo para SX126x) Activa/desactiva el amplificador de la RX para mejorar la sensibilidad a corrientes más altas.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Define la cadena de información de contacto del propietario que se incluye en los anuncios. Utilice '|' para indicar nuevas líneas.",
|
||||
"repeater_cliHelpSetPathHashMode": "Establece el modo de hash de la ruta. 0 = antiguo, 1 = estándar, 2 = estricto. Afecta la forma en que se comparan las rutas.",
|
||||
"repeater_cliHelpSetLoopDetect": "Establece la sensibilidad para la detección de bucles de enrutamiento: apagado, mínimo, moderado o estricto.",
|
||||
"repeater_cliHelpSetFreq": "(Solo para la configuración de frecuencia) Establece rápidamente la frecuencia deseada. Se requiere reiniciar. Se recomienda utilizar la opción \"configurar radio\" para obtener todos los parámetros de la radio.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Solo para el puente ESPNow) Establece el canal de WiFi (1-14) que utiliza el puente.",
|
||||
"repeater_cliHelpGetName": "Muestra el nombre del nodo configurado.",
|
||||
"repeater_cliHelpGetRole": "Muestra el rol del firmware (Repetidor, Servidor de habitación, etc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Muestra la clave pública del dispositivo.",
|
||||
"repeater_cliHelpGetPrvKey": "(Solo para uso en serie) Muestra la clave privada del dispositivo. Trátala como una información confidencial.",
|
||||
"repeater_cliHelpGetRepeat": "Indica si el enrutamiento de paquetes (función de repetidor) está activado o desactivado.",
|
||||
"repeater_cliHelpGetTx": "Muestra la potencia actual en dBm.",
|
||||
"repeater_cliHelpGetFreq": "Muestra la frecuencia de radio configurada en MHz.",
|
||||
"repeater_cliHelpGetRadio": "Muestra todos los parámetros de radio: frecuencia, ancho de banda, factor de dispersión, tasa de codificación.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Solo para SX126x) Muestra el estado de ganancia amplificada del receptor.",
|
||||
"repeater_cliHelpGetAf": "Muestra el factor de tiempo actual.",
|
||||
"repeater_cliHelpGetDutyCycle": "Muestra el ciclo de trabajo actual permitido como un porcentaje.",
|
||||
"repeater_cliHelpGetIntThresh": "Muestra el umbral de interferencia del canal en dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Muestra el intervalo de reinicio del AGC en segundos.",
|
||||
"repeater_cliHelpGetMultiAcks": "Indica si el modo de confirmación doble está activado (1) o desactivado (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Indica si se permite el acceso de solo lectura para los usuarios invitados.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Muestra el intervalo de publicidad local en minutos.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Muestra el intervalo de publicidad para la emisión de la señal de inundación, expresado en horas.",
|
||||
"repeater_cliHelpGetGuestPassword": "Muestra la contraseña de invitado configurada.",
|
||||
"repeater_cliHelpGetLat": "Muestra la latitud configurada.",
|
||||
"repeater_cliHelpGetLon": "Muestra la longitud configurada.",
|
||||
"repeater_cliHelpGetRxDelay": "Muestra el valor base de rxdelay.",
|
||||
"repeater_cliHelpGetTxDelay": "Muestra el factor de retardo en modo de inundación.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Muestra el factor de retardo en modo directo.",
|
||||
"repeater_cliHelpGetFloodMax": "Muestra el número máximo de saltos por inundación.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Muestra la cadena de información de contacto del propietario.",
|
||||
"repeater_cliHelpGetPathHashMode": "Muestra el modo de hash de ruta (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Muestra la sensibilidad en la detección de bucles.",
|
||||
"repeater_cliHelpGetAcl": "(Solo para series) Enumera las entradas de control de acceso en un repetidor.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Indica si el puente está habilitado.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Muestra el retardo del puente en milisegundos.",
|
||||
"repeater_cliHelpGetBridgeSource": "Indica si el puente está enviando o recibiendo paquetes RX o TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Solo puente RS232) Muestra la velocidad de transmisión del puente.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Solo para el puente ESPNow) Muestra el canal WiFi del puente.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Solo para el puente ESPNow) Muestra el secreto compartido por el puente.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Solo NRF52) Muestra la versión del cargador.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Muestra el multiplicador del ADC (escalado de voltaje de la batería).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Indica si el sistema cuenta con funciones de gestión de energía.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Indica la fuente de energía actual: externa o batería.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Muestra las razones más recientes de reinicio y apagado.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Muestra el voltaje de la batería al encender el sistema en milivoltios (mV).",
|
||||
"repeater_cliHelpSensorGet": "Lee una configuración de sensor personalizada mediante una tecla.",
|
||||
"repeater_cliHelpSensorSet": "Crea una configuración personalizada para un sensor.",
|
||||
"repeater_cliHelpSensorList": "Muestra todas las configuraciones de sensores personalizadas, paginadas a partir de un índice de inicio opcional.",
|
||||
"repeater_cliHelpRegionDefault": "Muestra el ámbito predeterminado actual.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Establece el ámbito regional predeterminado. Utilice \"<null>\" para restablecer a la configuración predeterminada.",
|
||||
"repeater_cliHelpRegionListAllowed": "Enumera las regiones que permiten el paso de vehículos debido a inundaciones.",
|
||||
"repeater_cliHelpRegionListDenied": "Enumera las regiones que prohíben el tráfico debido a las inundaciones.",
|
||||
"repeater_cliHelpStatsPackets": "(Solo para series) Muestra estadísticas a nivel de paquetes.",
|
||||
"repeater_cliHelpStatsRadio": "(Solo para transmisiones en serie) Muestra estadísticas de radio.",
|
||||
"repeater_cliHelpStatsCore": "(Solo para series) Muestra estadísticas clave del firmware.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Compartido",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Espacios ocupados",
|
||||
"losBlockedSpotsHint": "Seleccione un punto bloqueado para resaltarlo en el mapa.",
|
||||
"losSelectedObstructionTitle": "Obstrucción seleccionada",
|
||||
"losSelectedObstructionDetails": "Bloqueado por {obstruction} a una altura de {heightUnit}, a {distanceFromA} metros de A y a {distanceFromB} metros de B ({distanceUnit}).",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"settings_companionDebugLog": "Registro de depuración asociado",
|
||||
"chat_newMessages": "Nuevos mensajes",
|
||||
"settings_companionDebugLogSubtitle": "Comandos, respuestas y datos brutos para protocolos BLE/TCP/USB",
|
||||
"chat_markAsUnread": "Marcar como no leído",
|
||||
"repeater_chanUtil": "Utilización del canal",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_pending": "Enviar",
|
||||
"common_undo": "Deshacer",
|
||||
"messageStatus_sent": "Sentido",
|
||||
"messageStatus_delivered": "Entregado",
|
||||
"messageStatus_failed": "No se pudo enviar",
|
||||
"messageStatus_repeated": "Escuché repetidamente",
|
||||
"contacts_moreOptions": "Más opciones",
|
||||
"contacts_searchOpen": "Buscar contactos",
|
||||
"contacts_searchClose": "Búsqueda avanzada",
|
||||
"routing_title": "Ruteo",
|
||||
"routing_modeAuto": "Coche",
|
||||
"routing_modeFlood": "Inundación",
|
||||
"routing_modeManual": "Manual",
|
||||
"routing_modeAutoHint": "Selecciona automáticamente la ruta más conocida, y si no hay ninguna ruta conocida, utiliza la ruta más directa.",
|
||||
"routing_modeFloodHint": "Transmisiones a través de todos los repetidores. Es la opción más fiable, pero utiliza más tiempo de transmisión.",
|
||||
"routing_modeManualHint": "Siempre sigue exactamente la ruta que usted ha definido.",
|
||||
"routing_currentRoute": "Ruta actual",
|
||||
"routing_directNoHops": "Directo — sin saltos de repetidor",
|
||||
"routing_noPathYet": "Aún no hay un camino definido. El mensaje se envía continuamente hasta que se encuentre una ruta.",
|
||||
"routing_floodBroadcast": "Transmisión a través de todos los repetidores.",
|
||||
"routing_editPath": "Editar ruta",
|
||||
"routing_forgetPath": "Olvídate del camino",
|
||||
"routing_knownPaths": "Rutas conocidas",
|
||||
"routing_knownPathsHint": "Seleccione una opción para cambiar a esa.",
|
||||
"routing_inUse": "En uso",
|
||||
"routing_qualityStrong": "Primer salto exitoso",
|
||||
"routing_qualityGood": "Primer paso exitoso",
|
||||
"routing_qualityWorked": "Ha cumplido",
|
||||
"routing_qualityFair": "Primer salto de calidad",
|
||||
"routing_qualityFlood": "Se ha escuchado a través de rumores.",
|
||||
"routing_qualityUntested": "Sin probar",
|
||||
"routing_lastWorked": "trabajó {when}",
|
||||
"routing_neverWorked": "nunca confirmado",
|
||||
"routing_floodDelivery": "Entrega por inundación",
|
||||
"pathEditor_title": "Crear ruta",
|
||||
"pathEditor_hopCounter": "{count} de 64 granos de lúpulo",
|
||||
"pathEditor_noHops": "Aún no se han añadido lúpulos. Haga clic en los repetidores para añadirlos en el orden deseado, o guarde la receta sin lúpulos para enviarla directamente.",
|
||||
"pathEditor_addHops": "Añadir los lúpulos en el orden adecuado.",
|
||||
"pathEditor_searchRepeaters": "Buscar repetidores",
|
||||
"pathEditor_advancedHex": "Avanzado: ruta hexadecimal sin procesar",
|
||||
"pathEditor_hexLabel": "Prefijos hexadecimales",
|
||||
"pathEditor_hexHelper": "Dos caracteres hexadecimales por salto, separados por comas.",
|
||||
"pathEditor_invalidTokens": "Inválido: {tokens}",
|
||||
"pathEditor_tooManyHops": "Máximo 64 saltos",
|
||||
"pathEditor_usePath": "Utilice esta ruta.",
|
||||
"pathEditor_removeHop": "Eliminar el lúpulo",
|
||||
"pathEditor_unknownHop": "Repetidor desconocido",
|
||||
"map_zoomIn": "Acercar",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Acercar",
|
||||
"map_centerMap": "Mapa del centro",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth requiere un navegador Chromium.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "Confirmado mediante GPS",
|
||||
"pathTrace_legendInferred": "Posición inferida"
|
||||
}
|
||||
|
||||
+416
-29
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"@@locale": "fr",
|
||||
"appTitle": "MeshCore Open",
|
||||
"nav_contacts": "Contacts",
|
||||
"nav_contacts": "Coordonnées",
|
||||
"nav_channels": "Canaux",
|
||||
"nav_map": "Carte",
|
||||
"common_cancel": "Annuler",
|
||||
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Supprimer",
|
||||
"common_enable": "Activer",
|
||||
"common_disable": "Désactiver",
|
||||
"common_autoRefresh": "Actualisation automatique",
|
||||
"common_interval": "Intervalle",
|
||||
"common_reboot": "Redémarrer",
|
||||
"common_loading": "Chargement...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Mode de confidentialité activé",
|
||||
"settings_privacyModeDisabled": "Mode de confidentialité désactivé",
|
||||
"settings_actions": "Actions",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "S'annoncer",
|
||||
"settings_sendAdvertisementSubtitle": "Présence diffusée maintenant",
|
||||
"settings_advertisementSent": "Annonce envoyée",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Journal de débogage de l'application",
|
||||
"settings_appDebugLogSubtitle": "Messages de débogage de l'application",
|
||||
"settings_about": "À propos",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -132,7 +136,7 @@
|
||||
"settings_aboutLegalese": "Projet MeshCore Open Source 2026",
|
||||
"settings_aboutDescription": "Un client Flutter open source pour les appareils de réseau mesh MeshCore LoRa.",
|
||||
"settings_infoName": "Nom",
|
||||
"settings_infoId": "ID",
|
||||
"settings_infoId": "Numéro d'identification",
|
||||
"settings_infoStatus": "État",
|
||||
"settings_infoBattery": "Batterie",
|
||||
"settings_infoPublicKey": "Clé Publique",
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Sombre",
|
||||
"appSettings_language": "Langue",
|
||||
"appSettings_languageSystem": "Par défaut du système",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageEn": "Anglais",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageEs": "Espagnol",
|
||||
"appSettings_languageDe": "Allemand",
|
||||
"appSettings_languagePl": "Polonais",
|
||||
"appSettings_languageSl": "Sloveno",
|
||||
"appSettings_languagePt": "Portugais",
|
||||
"appSettings_languageIt": "Italien",
|
||||
"appSettings_languageZh": "Chinois",
|
||||
"appSettings_languageSv": "Suédois",
|
||||
"appSettings_languageNl": "Néerlandais",
|
||||
"appSettings_languageSk": "Slovène",
|
||||
"appSettings_languageBg": "Bulgare",
|
||||
"appSettings_notifications": "Notifications",
|
||||
"appSettings_enableNotifications": "Activer les Notifications",
|
||||
"appSettings_enableNotificationsSubtitle": "Recevoir des notifications pour les messages et les annonces",
|
||||
@@ -254,7 +258,7 @@
|
||||
"appSettings_appDebugLoggingSubtitle": "Enregistrez les messages de débogage de l'application Log pour le dépannage.",
|
||||
"appSettings_appDebugLoggingEnabled": "Journalisation de débogage de l'application activée",
|
||||
"appSettings_appDebugLoggingDisabled": "Le débogage de l'application est désactivé.",
|
||||
"contacts_title": "Contacts",
|
||||
"contacts_title": "Coordonnées",
|
||||
"contacts_noContacts": "Aucun contact trouvé.",
|
||||
"contacts_contactsWillAppear": "Les contacts apparaîtront lorsque les appareils font leur annonce.",
|
||||
"contacts_searchContacts": "Rechercher des contacts...",
|
||||
@@ -298,7 +302,7 @@
|
||||
"contacts_noContactsMatchFilter": "Aucun contact ne correspond à votre filtre.",
|
||||
"contacts_noMembers": "Aucun membre",
|
||||
"contacts_lastSeenNow": "Vu maintenant",
|
||||
"contacts_lastSeenMinsAgo": "~ {minutes} min.",
|
||||
"contacts_lastSeenMinsAgo": "~ {minutes} minutes.",
|
||||
"@contacts_lastSeenMinsAgo": {
|
||||
"placeholders": {
|
||||
"minutes": {
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Canal avec hashtag",
|
||||
"channels_public": "Public",
|
||||
"channels_private": "Privé",
|
||||
"channels_publicChannel": "Canal public",
|
||||
"channels_privateChannel": "Canal privé",
|
||||
"channels_editChannel": "Modifier le canal",
|
||||
"channels_muteChannel": "Désactiver les notifications du canal",
|
||||
"channels_unmuteChannel": "Réactiver les notifications du canal",
|
||||
@@ -367,7 +368,7 @@
|
||||
"channels_channelName": "Nom du canal",
|
||||
"channels_usePublicChannel": "Utiliser le canal public",
|
||||
"channels_standardPublicPsk": "PSK public standard",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (Hexadécimal)",
|
||||
"channels_generateRandomPsk": "Générer une clé de modulation PSK aléatoire",
|
||||
"channels_enterChannelName": "Veuillez entrer un nom de canal",
|
||||
"channels_pskMustBe32Hex": "Le PKS doit être composé de 32 caractères hexadécimaux.",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Compression SMAZ",
|
||||
"channels_cyr2latCompression": "Compression Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Remplace certains caractères cyrilliques par des caractères latins lors de l'envoi.",
|
||||
"channels_cyr2latSettingsHeading": "Paramètres Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Liste des remplacements",
|
||||
"channels_cyr2latSettingsDscr": "Modifier la configuration JSON des remplacements de caractères",
|
||||
"channels_cyr2latSettingsDialogHint": "Tableau de remplacement JSON",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "JSON incorrect : {error}",
|
||||
"settings_cyr2latProfileAdd": "Ajouter un profil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Nom du profil",
|
||||
"settings_cyr2latProfileNameEmpty": "Le nom du profil ne peut pas être vide",
|
||||
"settings_cyr2latProfileAdded": "Profil ajouté avec succès",
|
||||
"settings_cyr2latProfileUpdated": "Profil mis à jour avec succès",
|
||||
"settings_cyr2latProfileEdit": "Modifier le profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Supprimer le profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Profil supprimé avec succès",
|
||||
"settings_cyr2latProfileDeleteDscr": "Êtes-vous sûr de vouloir supprimer le profil \"{name}\"?",
|
||||
"channels_channelUpdated": "Le canal \"{name}\" a été mis à jour",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -496,7 +513,7 @@
|
||||
}
|
||||
},
|
||||
"debugFrame_textMessageHeader": "Message :",
|
||||
"debugFrame_destinationPubKey": "- Destination PubKey: {pubKey}",
|
||||
"debugFrame_destinationPubKey": "- Clé publique de destination : {pubKey}",
|
||||
"@debugFrame_destinationPubKey": {
|
||||
"placeholders": {
|
||||
"pubKey": {
|
||||
@@ -641,7 +658,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_chat": "Chat",
|
||||
"map_chat": "Conversation",
|
||||
"map_repeater": "Répéteur",
|
||||
"map_room": "Room Server",
|
||||
"map_sensor": "Capteur",
|
||||
@@ -994,7 +1011,7 @@
|
||||
"repeater_frequencyMhz": "Fréquence (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_txPower": "TX Puissance",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_txPowerHelper": "1 à 30 dBm",
|
||||
"repeater_bandwidth": "Bande passante",
|
||||
"repeater_spreadingFactor": "Facteur de répartition (SF)",
|
||||
"repeater_codingRate": "Taux de codage (CR)",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Confirmer",
|
||||
"repeater_settingsSaved": "Les paramètres ont été enregistrés avec succès.",
|
||||
"repeater_rxGain": "Augmentation du rendement de RX",
|
||||
"repeater_rxGainHelper": "Meilleure sensibilité, consommation de courant plus élevée (uniquement pour les modèles SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Renforcer les gains de RX grâce à la mise à jour",
|
||||
"repeater_multiAcks": "Plusieurs accusés de réception",
|
||||
"repeater_multiAcksSubtitle": "Valider les messages via plusieurs chemins pour une meilleure livraison.",
|
||||
"repeater_refreshMultiAcks": "Renvoyer plusieurs accusés de réception",
|
||||
"repeater_networkHealth": "Santé du réseau",
|
||||
"repeater_loopDetect": "Détection de boucles",
|
||||
"repeater_loopDetectHelper": "Envoyer des paquets de données qui semblent former des boucles de routage.",
|
||||
"repeater_loopDetectOff": "Prix",
|
||||
"repeater_loopDetectMinimal": "Minimal",
|
||||
"repeater_loopDetectModerate": "Modéré",
|
||||
"repeater_loopDetectStrict": "Strict",
|
||||
"repeater_dutyCycle": "Cycle de fonctionnement",
|
||||
"repeater_dutyCycleHelper": "Pourcentage maximal de temps d'antenne",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informations sur l'opérateur",
|
||||
"repeater_ownerInfoHelper": "Métadonnées publiques pour cet émetteur",
|
||||
"repeater_refreshOwnerInfo": "Rafraîchir les informations sur l'opérateur",
|
||||
"repeater_floodMax": "Nombre maximal de sauts lors des inondations",
|
||||
"repeater_floodMaxHelper": "Nombre maximal de paquets de données qu'un flux peut transmettre (0-64)",
|
||||
"repeater_advancedSettings": "Avancé",
|
||||
"repeater_advancedSettingsSubtitle": "Molettes de réglage pour les opérateurs expérimentés",
|
||||
"repeater_pathHashMode": "Mode de hachage de chemin",
|
||||
"repeater_pathHashModeHelper": "Octets utilisés pour encoder l'ID de ce routeur dans les balises de détection de flux/boucles. 0 = 1 octet (256 ID, jusqu'à 64 sauts), 1 = 2 octets (65 000 ID, jusqu'à 32 sauts), 2 = 3 octets (16 millions d'ID, jusqu'à 21 sauts). Les versions 1.13 et antérieures utilisent des chemins multi-octets ; à partir de la version 1.14, cela n'est plus nécessaire.",
|
||||
"repeater_txDelay": "Retard dû aux inondations à Texas",
|
||||
"repeater_txDelayHelper": "Rétransmettre l'espacement pour le trafic de secours en cas de inondation, en multipliant le temps d'émission du paquet (0-2, valeur par défaut : 0,5). Une valeur plus élevée signifie moins de collisions, mais une vitesse de transmission plus lente.",
|
||||
"repeater_directTxDelay": "Retard de transmission direct",
|
||||
"repeater_directTxDelayHelper": "Rétransmettre l'espacement pour le trafic direct (non-inondation), en multipliant le temps de transmission des paquets (0-2, valeur par défaut : 0,3).",
|
||||
"repeater_intThresh": "Seuil de perturbation",
|
||||
"repeater_intThreshHelper": "Seuil dépassé pour la calibration du niveau de bruit de la radio, afin de rejeter les interférences supérieures à ce niveau. 0 désactive – ne mettez cette valeur que si vous constatez des erreurs RX dans une bande de fréquences bruyante.",
|
||||
"repeater_agcResetInterval": "Interval de réinitialisation de l'AGC",
|
||||
"repeater_agcResetIntervalHelper": "À quelle fréquence réinitialiser le contrôle automatique du gain de la radio pour revenir à un état normal ? Chaque seconde, ou à chaque multiple de 4. Désactiver la réinitialisation périodique avec 0.",
|
||||
"repeater_actionsTitle": "Actions",
|
||||
"repeater_sendAdvert": "Envoyer une publicité sur les inondations",
|
||||
"repeater_sendAdvertSubtitle": "Diffuser une publicité sur les inondations via le réseau.",
|
||||
"repeater_sendAdvertZeroHop": "Envoyer une publicité sans intermédiaire",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Diffuser une publicité d'un seul saut (sans relais)",
|
||||
"repeater_clockSync": "Synchroniser l'heure maintenant",
|
||||
"repeater_clockSyncSubtitle": "Envoyez l'heure de votre téléphone au répéteur.",
|
||||
"repeater_actionSucceeded": "{action} a réussi",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} a échoué : {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Paramètres sauvegardés — redémarrer le répéteur pour appliquer les modifications.",
|
||||
"repeater_settingsPartialFailure": "Certaines configurations ont échoué : {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Erreur lors de la sauvegarde des paramètres : {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Rafraîchir les paramètres de base",
|
||||
"repeater_refreshRadioSettings": "Rafraîchir les paramètres Radio",
|
||||
"repeater_refreshTxPower": "Rafraîchir la tension TX",
|
||||
"repeater_refreshLocationSettings": "Rafraîchir les paramètres de localisation",
|
||||
"repeater_refreshPacketForwarding": "Rafraîchir le routage des paquets",
|
||||
"repeater_refreshGuestAccess": "Rafraîchir l'accès invité",
|
||||
"repeater_refreshPrivacyMode": "Rafraîchir le Mode Confidentialité",
|
||||
"repeater_refreshAdvertisementSettings": "Rafraîchir les Paramètres des annonces",
|
||||
"repeater_refreshed": "{label} rafraîchi",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Entrée numérique",
|
||||
"telemetry_digitalOutputLabel": "Sortie numérique",
|
||||
"telemetry_analogInputLabel": "Entrée analogique",
|
||||
"telemetry_analogOutputLabel": "Sortie analogique",
|
||||
"telemetry_genericLabel": "Capteur générique",
|
||||
"telemetry_luminosityLabel": "Luminosité",
|
||||
"telemetry_presenceLabel": "Présence",
|
||||
"telemetry_humidityLabel": "Humidité",
|
||||
"telemetry_accelerometerLabel": "Accéléromètre",
|
||||
"telemetry_pressureLabel": "Pression",
|
||||
"telemetry_altitudeLabel": "Altitude",
|
||||
"telemetry_frequencyLabel": "Fréquence",
|
||||
"telemetry_percentageLabel": "Pourcentage",
|
||||
"telemetry_concentrationLabel": "Concentration",
|
||||
"telemetry_powerLabel": "Puissance",
|
||||
"telemetry_distanceLabel": "Distance",
|
||||
"telemetry_energyLabel": "Énergie",
|
||||
"telemetry_directionLabel": "Direction",
|
||||
"telemetry_timeLabel": "Heure",
|
||||
"telemetry_gyrometerLabel": "Gyromètre",
|
||||
"telemetry_colourLabel": "Couleur",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Interrupteur",
|
||||
"telemetry_polylineLabel": "Polyligne",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Nombre de requêtes",
|
||||
"telemetry_error": "Impossible de récupérer les données",
|
||||
"telemetry_noData": "Aucune donnée de télémétrie disponible.",
|
||||
"telemetry_channelTitle": "Canal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1352,7 +1479,7 @@
|
||||
"listFilter_all": "Tout",
|
||||
"listFilter_users": "Utilisateurs",
|
||||
"listFilter_repeaters": "Répéteurs",
|
||||
"listFilter_roomServers": "Room servers",
|
||||
"listFilter_roomServers": "Serveurs de salle",
|
||||
"listFilter_unreadOnly": "Messages non lus seulement",
|
||||
"listFilter_newGroup": "Nouveau groupe",
|
||||
"@neighbors_errorLoading": {
|
||||
@@ -1459,7 +1586,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_ok": "OK",
|
||||
"common_ok": "D'accord",
|
||||
"community_title": "Communauté",
|
||||
"community_create": "Créer une Communauté",
|
||||
"community_createDesc": "Créer une nouvelle communauté et la partager via QR code.",
|
||||
@@ -2011,6 +2138,9 @@
|
||||
"translation_title": "Traduction",
|
||||
"translation_enableSubtitle": "Traduire les messages entrants et permettre la traduction avant l'envoi.",
|
||||
"translation_composerSubtitle": "Contrôle l'état par défaut de l'icône de traduction du composant.",
|
||||
"translation_autoIncomingTitle": "Traduire automatiquement les messages",
|
||||
"translation_autoIncomingSubtitle": "Traduit automatiquement les messages pour les notifications et pour les discussions ou les canaux.",
|
||||
"translation_translateMessage": "Traduire le message",
|
||||
"translation_targetLanguage": "Langue cible",
|
||||
"translation_useAppLanguage": "Utiliser la langue de l'application",
|
||||
"translation_downloadedModelLabel": "Modèle téléchargé",
|
||||
@@ -2066,5 +2196,262 @@
|
||||
"chat_sendMessage": "Envoyer un message",
|
||||
"room_guest": "Informations sur le serveur",
|
||||
"repeater_guest": "Informations sur les répéteurs",
|
||||
"settings_multiAck": "Plusieurs accusés de réception"
|
||||
"@notification_messagesCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_getCategory": "Obtenir des valeurs",
|
||||
"repeater_powerMgmt": "Gestion de l'énergie",
|
||||
"repeater_sensors": "Capteurs",
|
||||
"repeater_cliHelpPowerOff": "Éteint l'appareil. (aucune réponse n'est attendue)",
|
||||
"repeater_cliHelpClkReboot": "Réinitialise l'horloge à une époque connue et redémarre l'appareil.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Envoie une publicité sans intermédiaire (uniquement aux voisins immédiats).",
|
||||
"repeater_cliHelpStartOta": "Démarre une mise à jour du firmware par voie radio sur les cartes prises en charge.",
|
||||
"repeater_cliHelpTime": "Définit l'heure de l'appareil sur les secondes de l'époque Unix spécifiée. L'heure ne peut pas reculer.",
|
||||
"repeater_cliHelpBoard": "Indique le fabricant du panneau / l'identifiant du matériel.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Envoie une requête de découverte de nœuds aux voisins proches. (Uniquement pour les répéteurs)",
|
||||
"repeater_cliHelpPowersaving": "Indique si le mode d'économie d'énergie est activé ou désactivé.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Active ou désactive le mode d'économie d'énergie (si pris en charge).",
|
||||
"repeater_cliHelpErase": "(Uniquement pour les appareils) Formate le système de fichiers de l'appareil. Efface tous les paramètres et les contacts.",
|
||||
"repeater_cliHelpSetDutyCycle": "Définit le cycle de transmission maximal autorisé en pourcentage (de 1 à 100). Ajuste automatiquement le facteur de temps d'émission.",
|
||||
"repeater_cliHelpSetPrvKey": "(Uniquement pour les séries) Remplace la clé privée d'identification de l'appareil. Un redémarrage est nécessaire pour appliquer. Génère une nouvelle clé publique.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Uniquement pour les SX126x) Active le gain RX amplifié pour une meilleure sensibilité à des courants plus élevés.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Définit la chaîne d'informations de contact du propriétaire, qui figure dans les annonces. Utilisez '|' pour les sauts de ligne.",
|
||||
"repeater_cliHelpSetPathHashMode": "Définit le mode de hachage de chemin. 0 = mode ancien, 1 = mode standard, 2 = mode strict. Influence la façon dont les chemins de routage sont correspondus.",
|
||||
"repeater_cliHelpSetLoopDetect": "Définit la sensibilité de la détection des boucles de routage : désactivée, minimale, modérée ou stricte.",
|
||||
"repeater_cliHelpSetFreq": "(Uniquement pour les modèles série) Permet de régler rapidement la fréquence. Redémarrage nécessaire. Il est préférable d'utiliser l'option \"réglage radio\" pour configurer tous les paramètres radio.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Uniquement pour le pont ESPNow) Définit le canal WiFi (de 1 à 14) utilisé par le pont.",
|
||||
"repeater_cliHelpGetName": "Affiche le nom du nœud configuré.",
|
||||
"repeater_cliHelpGetRole": "Indique le rôle du firmware (répéteur, serveur de pièce, etc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Affiche la clé publique du dispositif.",
|
||||
"repeater_cliHelpGetPrvKey": "(Uniquement pour les séries) Affiche la clé privée de l'appareil. Traitez-la comme une information confidentielle.",
|
||||
"repeater_cliHelpGetRepeat": "Indique si le transfert de paquets (en tant que routeur) est activé ou désactivé.",
|
||||
"repeater_cliHelpGetTx": "Indique la puissance actuelle en dBm.",
|
||||
"repeater_cliHelpGetFreq": "Affiche la fréquence radio configurée en MHz.",
|
||||
"repeater_cliHelpGetRadio": "Affiche tous les paramètres radio : fréquence, largeur de bande, facteur de dispersion, taux de codage.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Uniquement pour les SX126x) Affiche l'état du gain amplifié de la réception.",
|
||||
"repeater_cliHelpGetAf": "Indique le facteur de temps d'antenne actuel.",
|
||||
"repeater_cliHelpGetDutyCycle": "Affiche le cycle de fonctionnement actuel autorisé en pourcentage.",
|
||||
"repeater_cliHelpGetIntThresh": "Indique le seuil d'interférence du canal en dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Indique l'intervalle de réinitialisation de l'AGC en secondes.",
|
||||
"repeater_cliHelpGetMultiAcks": "Indique si le mode \"double ACK\" est activé (1) ou désactivé (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Indique si l'accès en lecture seule pour les invités est autorisé.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Indique l'intervalle publicitaire local en minutes.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Indique l'intervalle publicitaire pour la diffusion de l'annonce en heures.",
|
||||
"repeater_cliHelpGetGuestPassword": "Affiche le mot de passe invité configuré.",
|
||||
"repeater_cliHelpGetLat": "Affiche la latitude configurée.",
|
||||
"repeater_cliHelpGetLon": "Affiche la longitude configurée.",
|
||||
"repeater_cliHelpGetRxDelay": "Affiche la valeur de base de rxdelay.",
|
||||
"repeater_cliHelpGetTxDelay": "Indique le facteur de délai de transmission en mode inondation.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Indique le facteur de délai direct.",
|
||||
"repeater_cliHelpGetFloodMax": "Indique le nombre maximal de fois où le niveau de l'eau a atteint son point culminant.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Affiche la chaîne d'informations de contact du propriétaire.",
|
||||
"repeater_cliHelpGetPathHashMode": "Affiche le mode \"hash de chemin\" (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Illustre la sensibilité à la détection des boucles.",
|
||||
"repeater_cliHelpGetAcl": "(Uniquement pour les séries) Liste les entrées de contrôle d'accès sur un répéteur.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Indique si le pont est activé.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Indique le délai du pont en millisecondes.",
|
||||
"repeater_cliHelpGetBridgeSource": "Indique si le pont transmet des paquets RX ou TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Uniquement pour le pont RS232) Affiche la vitesse de communication du pont.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Uniquement pour le pont ESPNow) Affiche le canal WiFi du pont.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Uniquement pour le pont ESPNow) Affiche la clé partagée du pont.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Uniquement pour le NRF52) Affiche la version du chargeur initial.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Affiche le multiplicateur de l'ADC (mise à l'échelle de la tension de la batterie).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Indique si le système dispose de fonctionnalités de gestion de l'alimentation.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Indique la source d'alimentation actuelle : externe ou batterie.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Indique les raisons les plus récentes de réinitialisation et d'arrêt.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Affiche la tension de la batterie au démarrage, en millivolts (mV).",
|
||||
"repeater_cliHelpSensorGet": "Lit une valeur de configuration personnalisée pour un capteur en utilisant une touche.",
|
||||
"repeater_cliHelpSensorSet": "Crée une configuration personnalisée pour un capteur.",
|
||||
"repeater_cliHelpSensorList": "Affiche toutes les configurations de capteurs personnalisées, avec une pagination à partir d'un index de départ optionnel.",
|
||||
"repeater_cliHelpRegionDefault": "Affiche la portée régionale par défaut actuelle.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Définit la portée régionale par défaut. Utilisez \"<null>\" pour la réinitialiser.",
|
||||
"repeater_cliHelpRegionListAllowed": "Énumère les régions autorisant la circulation des véhicules en cas de inondation.",
|
||||
"repeater_cliHelpRegionListDenied": "Liste des régions qui interdisent la circulation en cas de inondation.",
|
||||
"repeater_cliHelpStatsPackets": "(Uniquement pour les séries) Affiche des statistiques au niveau des paquets.",
|
||||
"repeater_cliHelpStatsRadio": "(Uniquement pour les séries) Affiche les statistiques de la radio.",
|
||||
"repeater_cliHelpStatsCore": "(Uniquement pour les séries) Affiche les statistiques du micrologicem intégré.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Plusieurs accusés de réception",
|
||||
"map_sharedAt": "Partagé",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Obstruction sélectionnée",
|
||||
"losBlockedSpotsTitle": "Places occupés",
|
||||
"losBlockedSpotsHint": "Sélectionnez un emplacement bloqué pour le mettre en évidence sur la carte.",
|
||||
"losSelectedObstructionDetails": "Bloqué par {obstruction}, à une hauteur de {heightUnit}, à une distance de {distanceFromA} par rapport à A et à une distance de {distanceFromB} par rapport à B ({distanceUnit}).",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"settings_companionDebugLog": "Journal de débogage associé",
|
||||
"chat_markAsUnread": "Signaler comme non lu",
|
||||
"chat_newMessages": "Nouveaux messages",
|
||||
"settings_companionDebugLogSubtitle": "Commandes, réponses et données brutes pour les protocoles BLE/TCP/USB",
|
||||
"repeater_chanUtil": "Utilisation du canal",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_undo": "Annuler",
|
||||
"messageStatus_sent": "Envoyer",
|
||||
"messageStatus_delivered": "Livré",
|
||||
"messageStatus_pending": "Envoyer",
|
||||
"messageStatus_failed": "Échec de l'envoi",
|
||||
"messageStatus_repeated": "Répété plusieurs fois",
|
||||
"contacts_searchOpen": "Rechercher des contacts",
|
||||
"contacts_moreOptions": "Plus d'options",
|
||||
"contacts_searchClose": "Recherche avancée",
|
||||
"routing_title": "Planification des itinéraires",
|
||||
"routing_modeAuto": "Voiture",
|
||||
"routing_modeFlood": "Inondation",
|
||||
"routing_modeManual": "Manuel",
|
||||
"routing_modeFloodHint": "Diffusion via tous les répéteurs. La méthode la plus fiable, mais qui utilise plus de temps d'antenne.",
|
||||
"routing_modeAutoHint": "Sélectionne automatiquement le chemin le plus connu, et utilise la méthode de \"inondation\" si aucun chemin n'est connu.",
|
||||
"routing_modeManualHint": "Il suit toujours le chemin précis que vous avez défini.",
|
||||
"routing_currentRoute": "Itinéraire actuel",
|
||||
"routing_directNoHops": "Direct — sans relais",
|
||||
"routing_noPathYet": "Aucune voie encore trouvée. Le message suivant est envoyé jusqu'à ce qu'une route soit découverte.",
|
||||
"routing_floodBroadcast": "Diffusion via tous les répéteurs",
|
||||
"routing_editPath": "Modifier le chemin",
|
||||
"routing_forgetPath": "Oubliez le chemin",
|
||||
"routing_knownPaths": "Chemins connus",
|
||||
"routing_knownPathsHint": "Créez un raccourci pour y accéder.",
|
||||
"routing_inUse": "En cours d'utilisation",
|
||||
"routing_qualityStrong": "Première étape réussie",
|
||||
"routing_qualityGood": "Première étape réussie",
|
||||
"routing_qualityFair": "Première étape réussie",
|
||||
"routing_qualityWorked": "A livré",
|
||||
"routing_qualityFlood": "Rapporté par des informations provenant de plusieurs sources.",
|
||||
"routing_qualityUntested": "Non testé",
|
||||
"routing_lastWorked": "a travaillé {when}",
|
||||
"routing_neverWorked": "jamais confirmé",
|
||||
"routing_floodDelivery": "Livraison en cas de inondation",
|
||||
"pathEditor_hopCounter": "{count} parmi 64 houblons",
|
||||
"pathEditor_title": "Créer un chemin",
|
||||
"pathEditor_noHops": "Aucun houblon ajouté pour le moment. Cliquez sur les répétiteurs ci-dessous pour les ajouter dans l'ordre souhaité, ou enregistrez sans houblon pour envoyer directement.",
|
||||
"pathEditor_addHops": "Ajoutez les houblons dans l'ordre souhaité.",
|
||||
"pathEditor_searchRepeaters": "Rechercher des répétiteurs",
|
||||
"pathEditor_advancedHex": "Avancé : chemin hexadécimal brut",
|
||||
"pathEditor_hexLabel": "Préfixes hexadécimaux",
|
||||
"pathEditor_hexHelper": "Deux caractères hexadécimaux par saut, séparés par des virgules.",
|
||||
"pathEditor_invalidTokens": "Incorrect : {tokens}",
|
||||
"pathEditor_tooManyHops": "Maximum 64 sauts",
|
||||
"pathEditor_usePath": "Utilisez ce chemin.",
|
||||
"pathEditor_removeHop": "Éliminer le haricot",
|
||||
"pathEditor_unknownHop": "Répéteur non identifié",
|
||||
"map_zoomIn": "Zoomez",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Zoomez",
|
||||
"map_centerMap": "Carte du centre",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth nécessite un navigateur Chromium.",
|
||||
"channels_communityShortId": "ID : {id}…",
|
||||
"pathTrace_legendGpsConfirmed": "Le GPS a confirmé.",
|
||||
"pathTrace_legendInferred": "Position déduite"
|
||||
}
|
||||
|
||||
+386
-6
@@ -27,6 +27,8 @@
|
||||
"common_remove": "Eltávolít",
|
||||
"common_enable": "Engedélyezés",
|
||||
"common_disable": "Leteteszt",
|
||||
"common_autoRefresh": "Automatikus frissítés",
|
||||
"common_interval": "Intervallum",
|
||||
"common_reboot": "Újraindítás",
|
||||
"common_loading": "Betöltés...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -167,6 +169,8 @@
|
||||
"settings_privacyModeEnabled": "Adatvédelem mód beállítva",
|
||||
"settings_privacyModeDisabled": "Adatvédelem mód kikapcsolva",
|
||||
"settings_actions": "Tevékenységek",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Hirdetés küldése",
|
||||
"settings_sendAdvertisementSubtitle": "A nyilvános megjelenés",
|
||||
"settings_advertisementSent": "Hirdetés elküldve",
|
||||
@@ -489,11 +493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtag-ok közössége",
|
||||
"channels_public": "A nyilvánosság számára",
|
||||
"channels_private": "Személyes",
|
||||
"channels_publicChannel": "Össztávos csatorna",
|
||||
"channels_privateChannel": "Személyes csatorna",
|
||||
"channels_editChannel": "Csatorna szerkesztése",
|
||||
"channels_muteChannel": "Csendes csatorna",
|
||||
"channels_unmuteChannel": "Engedje be a hangot",
|
||||
@@ -548,6 +549,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ kompresszió",
|
||||
"channels_cyr2latCompression": "Cyr2Lat kompresszió",
|
||||
"channels_cyr2latCompressionDscr": "Néhány Cirill betűt Latin betűkkel helyettesít küldéskor.",
|
||||
"channels_cyr2latSettingsHeading": "Cyr2Lat beállítások",
|
||||
"channels_cyr2latSettingsSubheading": "Helyettesítési lista",
|
||||
"channels_cyr2latSettingsDscr": "A karakterhelyettesítési JSON-konfiguráció szerkesztése",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-csere táblázat",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Hibás JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Cyr2Lat-profil hozzáadása",
|
||||
"settings_cyr2latProfileName": "Profil neve",
|
||||
"settings_cyr2latProfileNameEmpty": "A profil neve nem lehet üres",
|
||||
"settings_cyr2latProfileAdded": "A profil hozzáadása sikeres",
|
||||
"settings_cyr2latProfileUpdated": "A profil frissítése sikeres",
|
||||
"settings_cyr2latProfileEdit": "Cyr2Lat profil szerkesztése",
|
||||
"settings_cyr2latProfileDelete": "Cyr2Lat profil törlése",
|
||||
"settings_cyr2latProfileDeleted": "A profil törlése sikeresen megtörtént",
|
||||
"settings_cyr2latProfileDeleteDscr": "Biztosan törölni szeretné a \"{name}\" profilt?",
|
||||
"channels_channelUpdated": "A {name} csatorna frissítve",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -1245,6 +1262,81 @@
|
||||
},
|
||||
"repeater_confirm": "Beküldve",
|
||||
"repeater_settingsSaved": "Beállítások sikeresen mentve",
|
||||
"repeater_rxGain": "Nagyobb RX-jel erősítés",
|
||||
"repeater_rxGainHelper": "Magasabb érzékenység, nagyobb áramfelvétel (csak SX1262/SX1268 esetén)",
|
||||
"repeater_refreshRxGain": "Újraindított, fokozott RX hatás",
|
||||
"repeater_multiAcks": "Többszörös visszaigazolások",
|
||||
"repeater_multiAcksSubtitle": "Ismerje el üzeneteket több úton is, hogy biztosítsa a jobb átadást.",
|
||||
"repeater_refreshMultiAcks": "Frissítse a többször is kapott visszaigazolásokat.",
|
||||
"repeater_networkHealth": "Hálózati állapot",
|
||||
"repeater_loopDetect": "Ciklusok azonosítása",
|
||||
"repeater_loopDetectHelper": "Készíts olyan \"vízfolyást\" megjelenítő csomagokat, amelyek úgy néznek ki, mint egy hibaút.",
|
||||
"repeater_loopDetectOff": "Le, kikap",
|
||||
"repeater_loopDetectMinimal": "Minimális",
|
||||
"repeater_loopDetectModerate": "Közepes",
|
||||
"repeater_loopDetectStrict": "Szigorú",
|
||||
"repeater_dutyCycle": "Munka- és pihenőidő aránya",
|
||||
"repeater_dutyCycleHelper": "A maximális időszámítás százalékos aránya",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Üzemeltető információ",
|
||||
"repeater_ownerInfoHelper": "A nyilvánosan elérhető metadatak a repeaterhez",
|
||||
"repeater_refreshOwnerInfo": "Frissítse az üzemeltető adatokat",
|
||||
"repeater_floodMax": "A vízmaximumos ugrások",
|
||||
"repeater_floodMaxHelper": "A legmagasabb szám, amely egy vízszint-csomagban szerepelhet (0-64)",
|
||||
"repeater_advancedSettings": "Haladó",
|
||||
"repeater_advancedSettingsSubtitle": "Erkélő kapcsolók tapasztalt kezelők számára",
|
||||
"repeater_pathHashMode": "Út-hash mód",
|
||||
"repeater_pathHashModeHelper": "A byte-ok, amelyek az alábbi repeater-ek azonosítójának kódolására szolgálnak a flood-útvonal/ciklus-észlelő címkékben. 0=1 byte (256 azonosító, akár 64 útvonal), 1=2 byte (65 000 azonosító, akár 32 útvonal), 2=3 byte (16 millió azonosító, akár 21 útvonal). A v1.13-as verziótól kezdődően és az azt követő verziókban a több byte-os útvonalak megszűntek – csak egyetlen útvonal létesül, miután a hálózat a v1.14-es verzióra vagy az azt követő verzióra frissült.",
|
||||
"repeater_txDelay": "Flood TX késés",
|
||||
"repeater_txDelayHelper": "Újraküldési intervallum árvíz esetén, amely a csomag átviteli idejének (0-2, alapérték 0,5) szorzata. Minél nagyobb az érték, annál kevesebb ütközés, de lassabb a továbbítás.",
|
||||
"repeater_directTxDelay": "Közvetlen TX késés",
|
||||
"repeater_directTxDelayHelper": "A közvetlen (nem tömeges) forgalomhoz tartozó adatcsomagok újrádiózására szolgáló intervallum, amely a csomag átviteli idejének (0-2, alapértelmezett érték 0,3) szorzata.",
|
||||
"repeater_intThresh": "Interferencia határ",
|
||||
"repeater_intThreshHelper": "A határt a rádió zajszintjének kalibrálására állították, így elutasítja a fenti szint feletti interferenciákat. 0 kikapcsol – csak akkor állítsa be, ha zajos frekvencián RX hibákat észlel.",
|
||||
"repeater_agcResetInterval": "AGC visszazárási intervallum",
|
||||
"repeater_agcResetIntervalHelper": "Mennyi időnként kell a rádió automatikus hangerőszabályozását visszaállítani, hogy kijavítsa a problémát? A visszaállítás időtartama: másoderek, amely 4-szeresével osztható. A 0 érték a periodikus visszaállítás kikapcsolását jelzi.",
|
||||
"repeater_actionsTitle": "Tevékenységek",
|
||||
"repeater_sendAdvert": "Eljuttass flood hirdetést",
|
||||
"repeater_sendAdvertSubtitle": "Terjesztse egy árvíz elleni reklámot a hálózaton keresztül.",
|
||||
"repeater_sendAdvertZeroHop": "Küldj egy közvetlen hirdetést",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Adja közzé egyetlen átjáró hirdetést (nincs átjátszás).",
|
||||
"repeater_clockSync": "Synchronizálja az órát",
|
||||
"repeater_clockSyncSubtitle": "Állítsa be a telefon időzítését a repeaterhez.",
|
||||
"repeater_actionSucceeded": "{action} sikert aratott",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} sikertelen: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Beállítások mentve – újraindítsa a repeatert, hogy alkalmazza",
|
||||
"repeater_settingsPartialFailure": "Bizonyos beállítások nem sikerültek: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Hibás beállítások mentése: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1256,11 +1348,9 @@
|
||||
"repeater_refreshBasicSettings": "Visszaállítás az alapértékekre",
|
||||
"repeater_refreshRadioSettings": "Frissítse a rádió beállításait",
|
||||
"repeater_refreshTxPower": "Újraindítás TX-támogatással",
|
||||
"repeater_refreshLocationSettings": "Újraindítás helyszín beállításokkal",
|
||||
"repeater_refreshPacketForwarding": "Csomagok továbbításának frissítése",
|
||||
"repeater_refreshGuestAccess": "Újraindítás vendégHozzáférés",
|
||||
"repeater_refreshPrivacyMode": "Visszaállítás a magánéletvédő módra",
|
||||
"repeater_refreshAdvertisementSettings": "Újraindítás hirdetés beállítások",
|
||||
"repeater_refreshed": "{label} frissítve",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1378,6 +1468,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digitális bemenet",
|
||||
"telemetry_digitalOutputLabel": "Digitális kimenet",
|
||||
"telemetry_analogInputLabel": "Analóg bemenet",
|
||||
"telemetry_analogOutputLabel": "Analóg kimenet",
|
||||
"telemetry_genericLabel": "Általános érzékelő",
|
||||
"telemetry_luminosityLabel": "Fényerő",
|
||||
"telemetry_presenceLabel": "Jelenlét",
|
||||
"telemetry_humidityLabel": "Páratartalom",
|
||||
"telemetry_accelerometerLabel": "Gyorsulásmérő",
|
||||
"telemetry_pressureLabel": "Nyomás",
|
||||
"telemetry_altitudeLabel": "Magasság",
|
||||
"telemetry_frequencyLabel": "Frekvencia",
|
||||
"telemetry_percentageLabel": "Százalék",
|
||||
"telemetry_concentrationLabel": "Koncentráció",
|
||||
"telemetry_powerLabel": "Teljesítmény",
|
||||
"telemetry_distanceLabel": "Távolság",
|
||||
"telemetry_energyLabel": "Energia",
|
||||
"telemetry_directionLabel": "Irány",
|
||||
"telemetry_timeLabel": "Idő",
|
||||
"telemetry_gyrometerLabel": "Giroszkóp",
|
||||
"telemetry_colourLabel": "Szín",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Kapcsoló",
|
||||
"telemetry_polylineLabel": "Töröttvonal",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Kérések száma",
|
||||
"telemetry_error": "Nem sikerült lekérni az adatokat",
|
||||
"telemetry_noData": "Nincsenek elérhető telemetriadatok.",
|
||||
"telemetry_channelTitle": "{channel} csatorna",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -2049,6 +2176,9 @@
|
||||
"translation_enableSubtitle": "Fordítsa az érkező üzeneteket, és lehetővé tegye a küldés előtti fordítást.",
|
||||
"translation_composerTitle": "Fordítsa el, mielőtt elküldi",
|
||||
"translation_composerSubtitle": "Ellenőrzi a zeneszerző fordítási ikon alapértékét.",
|
||||
"translation_autoIncomingTitle": "Üzenetek automatikus fordítása",
|
||||
"translation_autoIncomingSubtitle": "Automatikusan lefordítja az üzeneteket az értesítésekhez, valamint a csevegésekhez vagy csatornákhoz.",
|
||||
"translation_translateMessage": "Üzenet fordítása",
|
||||
"translation_targetLanguage": "Célnyelv",
|
||||
"translation_useAppLanguage": "Használja az alkalmazás nyelvének beállítását.",
|
||||
"translation_downloadedModelLabel": "Letöltött modell",
|
||||
@@ -2104,5 +2234,255 @@
|
||||
"room_guest": "Szoba szerver információk",
|
||||
"chat_sendMessage": "Üzenet küldése",
|
||||
"repeater_guest": "Adatok a repeaterről",
|
||||
"settings_multiAck": "Többszörös visszaigazolások"
|
||||
"repeater_getCategory": "Szereplő értékek",
|
||||
"repeater_powerMgmt": "Energiahatékonyság, energiafelhasználás optimalizálása",
|
||||
"repeater_sensors": "Érzékelők",
|
||||
"repeater_cliHelpPowerOff": "Át kapcsolja a készüléket. (nincs válasz elvárás)",
|
||||
"repeater_cliHelpClkReboot": "Visszaállítja az órát egy ismert időpontra, majd újraindítja a készüléket.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Küld egy közvetlen szomszédoknak szóló hirdetést, amely közvetlen kapcsolatot igényel.",
|
||||
"repeater_cliHelpStartOta": "Elindítja a vezeték nélküli útvonalon történő firmware frissítést a támogatott kártyákon.",
|
||||
"repeater_cliHelpTime": "Beállítja a eszköz óráját a megadott Unix-időpont (Unix epoch) időpontra. Az óra nem tud visszanyúlni.",
|
||||
"repeater_cliHelpBoard": "Megjeleníti a gyártó nevét/a hardver azonosítóját.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Kérést küld a közeli eszközöknek, hogy azok is megtalálják egymást. (Csak egy repeater eszköz számára)",
|
||||
"repeater_cliHelpPowersaving": "Megmutatja, hogy a takarékos üzemmód engedélyezve van-e vagy nem.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Engedélyezi vagy kikapcsolja a takarékos üzemmódot (ha támogatott).",
|
||||
"repeater_cliHelpErase": "(Csak sorozatban) Formázza a eszköz fájlrendszerét. Eltávolítja az összes beállítást és a kapcsolatokat.",
|
||||
"repeater_cliHelpSetDutyCycle": "Beállítja a maximális engedélyezett átviteli időtartamot százalékban (1-100). Belsőleg módosítja az időtartam-szabályozást.",
|
||||
"repeater_cliHelpSetPrvKey": "(Csak sorozatban) Cseréli a eszköz egyedi kulcsát. Az alkalmazáshoz újraindítás szükséges. Új nyilvános kulcsot generál.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Csak SX126x család) A növelt RX erősítést be- és kikapcsolható, így a nagyobb áramfelvétel esetén is javítható a érzékenység.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Megadja az üvegezésben megjelenő tulajdonos elérhetőségeinek szövegét. Használja a '|' karaktert új sorok elválasztására.",
|
||||
"repeater_cliHelpSetPathHashMode": "Beállítja a hálózati útvonal-hash módot. 0 = régebbi, 1 = szabványos, 2 = szigorú. Hatással van a hálózati útvonalak megadatalására.",
|
||||
"repeater_cliHelpSetLoopDetect": "Beállítja a hibaforrás-keresés érzékenységét: kikapcsolva, minimális, közepes vagy szigorú.",
|
||||
"repeater_cliHelpSetFreq": "(Csak soros mód) Gyorsan beállítja a frekvenciát. A rendszer újraindítás szükséges. A teljes rádióparaméterek beállításához a \"rádió beállítás\" funkciót javaslom.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Csak ESPNow híd esetén) Beállítja a híd által használt WiFi-csatornát (1-14).",
|
||||
"repeater_cliHelpGetName": "Megjeleníti a konfigurált csomópont nevét.",
|
||||
"repeater_cliHelpGetRole": "Megmutatja a firmware funkcióját (repeater, szobai szerver stb.).",
|
||||
"repeater_cliHelpGetPublicKey": "Megjeleníti a eszköz nyilvános kulcsát.",
|
||||
"repeater_cliHelpGetPrvKey": "(Csak soros mód) Megjeleníti a eszköz privát kulcsát. Kezelje titkos információként.",
|
||||
"repeater_cliHelpGetRepeat": "Megmutatja, hogy a csomagok továbbításának (repeater funkció) engedélyezve van-e vagy nem.",
|
||||
"repeater_cliHelpGetTx": "Megmutatja a jelenlegi TX (átvitel) teljesítményt dBm-ben.",
|
||||
"repeater_cliHelpGetFreq": "Megjeleníti a konfigurált rádiófrekvenciát MHz-ben.",
|
||||
"repeater_cliHelpGetRadio": "Megjeleníti az összes rádióparamétert: frekvencia, sávszélesség, széttétező tényező, kódolási ráta.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Csak SX126x családra) Megjeleníti az RX erősítés állapotát.",
|
||||
"repeater_cliHelpGetAf": "Megmutatja az aktuális időadó tényezőt.",
|
||||
"repeater_cliHelpGetDutyCycle": "Megmutatja az aktuális engedélyezett működési ciklust százalékban.",
|
||||
"repeater_cliHelpGetIntThresh": "Megmutatja a csatornák közötti interferencia szintjét dB-ben.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Megmutatja az AGC (automatikus gain-kontroll) visszaállítási időt másodpercekben.",
|
||||
"repeater_cliHelpGetMultiAcks": "Megmutatja, hogy a kettős visszaigazolás (double-ACK) mód engedélyezve van-e (1), vagy kikapcsolva (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Megmutatja, hogy a vendég csak olvasási jogosítást engedélyez-e.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Megmutatja a helyi hirdetés időtartamát percenként.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Megmutatja az aktuális időzítést, amikor megjelenik a vízparti reklám, órákonként.",
|
||||
"repeater_cliHelpGetGuestPassword": "Megjeleníti a konfigurált vendégjelszót.",
|
||||
"repeater_cliHelpGetLat": "Megjeleníti a beállított szélességet.",
|
||||
"repeater_cliHelpGetLon": "Megjeleníti a beállított hosszúságot.",
|
||||
"repeater_cliHelpGetRxDelay": "Megmutatja az alapértéket a késéshez.",
|
||||
"repeater_cliHelpGetTxDelay": "Megmutatja a vízszint-érzékelő jelátviteli késésének tényezőjét.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Megmutatja a közvetlen módban használt késés tényezőt.",
|
||||
"repeater_cliHelpGetFloodMax": "Megmutatja a maximális vízszint-emelkedés mértékét.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Megjeleníti az tulajdonos elérhetőségének szövegét.",
|
||||
"repeater_cliHelpGetPathHashMode": "Megjeleníti a hash-alapú mód (0/1/2) beállításokat.",
|
||||
"repeater_cliHelpGetLoopDetect": "Mutatja a cikkszám-azonosító érzékenységet.",
|
||||
"repeater_cliHelpGetAcl": "(Csak sorozat) A repeateren található hozzáférési szabályok listája.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Megmutatja, hogy a híd engedélyezve van-e.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Megmutatja a hídon bekövetkező késést másodpercben.",
|
||||
"repeater_cliHelpGetBridgeSource": "Megmutatja, hogy a híd RX vagy TX csomagokat fogad-e.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Csak RS232 híd) Megjeleníti a híd sebességét.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Csak ESPNow híd) Megjeleníti a híd által használt WiFi csatornát.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Csak ESPNow híd esetén) Megjeleníti a híd által megosztott titkos kulcsot.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Csak NRF52 esetén) Megjeleníti a bootloader verzióját.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "A bemeneti feszültség-átalakító (akkumulátor-feszültség-szabályozó) működését mutatja.",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Megállapítja, hogy a felügyelet rendelkezik-e energiahatékonysági támogatással.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Megmutatja az aktuális energiaforrást: külső vagy akkumulátor.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Megjeleníti az utolsó újraindítás és leállítás okait.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Megjeleníti a rendszerindításkor mért akkumulátor feszültséget millivoltban (mV).",
|
||||
"repeater_cliHelpSensorGet": "Beolvas egy felhasználó által definiált szenzor beállítást kulcs segítségével.",
|
||||
"repeater_cliHelpSensorSet": "Egyedi szenzorbeállítások létrehozása.",
|
||||
"repeater_cliHelpSensorList": "Összesíti az összes egyedi szenzor beállításot, oldalanként, opcionális kezdő index alapján.",
|
||||
"repeater_cliHelpRegionDefault": "Megmutatja a jelenlegi alapértelmezett régió határait.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Beállítja az alapértelmezett régió hatókörét. Használja a \"<null>\" értéket a törléshez.",
|
||||
"repeater_cliHelpRegionListAllowed": "Felhasználható területek, ahol árvíz esetén forgalmat engedélyeznek.",
|
||||
"repeater_cliHelpRegionListDenied": "Felhasznál, amelyek elutasítják a árvíz okozta forgalmat.",
|
||||
"repeater_cliHelpStatsPackets": "(Csak sorozat) A csomagok szintjén történő statisztikát mutat.",
|
||||
"repeater_cliHelpStatsRadio": "(Csak sorozat) Mutat rádióstatisztikákat.",
|
||||
"repeater_cliHelpStatsCore": "(Csak soros mód) A főfirmware-adatokat mutatja.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Többszörös visszaigazolások",
|
||||
"map_sharedAt": "Megosztva",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Kiválasztott akadály",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "A blokkolt területet megjelölve, hogy a térképen kiemeljük.",
|
||||
"losBlockedSpotsTitle": "Foglalhatatlan területek",
|
||||
"losSelectedObstructionDetails": "Elakadt a {obstruction} miatt, {heightUnit} magasságban, {distanceFromA} méterrel A-tól és {distanceFromB} méterrel B-től ({distanceUnit}).",
|
||||
"chat_markAsUnread": "Merekje olvashatóként",
|
||||
"chat_newMessages": "Új üzenetek",
|
||||
"settings_companionDebugLog": "Párhuzamos hibakeresési napló",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB parancsok, válaszok és alapvető adatok",
|
||||
"repeater_chanUtil": "Csatorna-használat",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_delivered": "Szállítva",
|
||||
"common_undo": "Még egyszer",
|
||||
"messageStatus_sent": "Elküldve",
|
||||
"messageStatus_pending": "Elküldés",
|
||||
"messageStatus_failed": "Nem sikerült elküldeni",
|
||||
"messageStatus_repeated": "Ismételtem",
|
||||
"contacts_moreOptions": "További lehetőségek",
|
||||
"contacts_searchOpen": "Keresssz kapcsolatokat",
|
||||
"contacts_searchClose": "Teljesítse a keresést",
|
||||
"routing_title": "Útvonal meghatározás",
|
||||
"routing_modeAuto": "Autó",
|
||||
"routing_modeFlood": "Áradás",
|
||||
"routing_modeManual": "Használati útmutató",
|
||||
"routing_modeAutoHint": "Automatikusan kiválasztja a legismertebb útvonalat, és ha egyik sem ismert, akkor \"vízzel\" tölti ki.",
|
||||
"routing_modeFloodHint": "Átvisszaadások minden erősítőn keresztül. A legmegbízhatóbb megoldás, de több időt igényel.",
|
||||
"routing_modeManualHint": "Mindig pontosan az útvonalat követi, amelyet megad.",
|
||||
"routing_currentRoute": "Jelenlegi útvonal",
|
||||
"routing_directNoHops": "Közvetlen – nincs átjáró állomás",
|
||||
"routing_noPathYet": "Még nincs útvonal. A következő üzenet a keresésig vár.",
|
||||
"routing_floodBroadcast": "Azonnali továbbítás minden erősítőn keresztül.",
|
||||
"routing_editPath": "Útvonal szerkesztése",
|
||||
"routing_forgetPath": "Felejtsd el a útvonalat",
|
||||
"routing_knownPaths": "Jellegzetes útvonalak",
|
||||
"routing_knownPathsHint": "Készíts egy útvonalat, hogy átválhass rá.",
|
||||
"routing_inUse": "Használatban",
|
||||
"routing_qualityStrong": "Erős első lépés",
|
||||
"routing_qualityGood": "Jó első lépés",
|
||||
"routing_qualityFair": "Jó első lépés",
|
||||
"routing_qualityWorked": "Előállított",
|
||||
"routing_qualityFlood": "Információt hallottam a katasztrófa miatt.",
|
||||
"routing_qualityUntested": "Vizsgálatnak nem подвержен",
|
||||
"routing_neverWorked": "sosem megerősítve",
|
||||
"routing_floodDelivery": "Vízparti szállítás",
|
||||
"pathEditor_title": "Út megépítése",
|
||||
"pathEditor_hopCounter": "{count} db 64-ből",
|
||||
"pathEditor_noHops": "Még nem adtam hozzá a bazsalikomot. A lent található gombokat használhatod, hogy sorrendben adjd hozzá, vagy mentheted anélkül, hogy bazsalikomot adnál hozzá, hogy közvetlenül elküldd.",
|
||||
"pathEditor_addHops": "Adja hozzá a bazsaidat a megfelelő sorrendben.",
|
||||
"pathEditor_searchRepeaters": "Ismétlő eszközök keresése",
|
||||
"pathEditor_advancedHex": "Haladó szint: alapvető hex-út",
|
||||
"pathEditor_hexLabel": "Hex előtagok",
|
||||
"pathEditor_hexHelper": "Két hatjegyű szám minden lépésen, amelyek egymástól elválasztják a kommák.",
|
||||
"pathEditor_invalidTokens": "Érvénytelen: {tokens}",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_tooManyHops": "A maximális szám 64.",
|
||||
"pathEditor_usePath": "Használja ezt az útvonalat.",
|
||||
"pathEditor_removeHop": "Távolítsa el a bazsalikomot",
|
||||
"pathEditor_unknownHop": "Tudatlan erősítő",
|
||||
"map_zoomIn": "Nagyítva",
|
||||
"map_zoomOut": "Kicsökkentett nézet",
|
||||
"map_centerMap": "Központi tér térkép",
|
||||
"chrome_bluetoothRequiresChromium": "A Web Bluetooth-hoz egy Chromium-alapú böngésző szükséges.",
|
||||
"channels_communityShortId": "Az azonosító: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS-en megerősítve",
|
||||
"pathTrace_legendInferred": "Feltehető helyzet"
|
||||
}
|
||||
|
||||
+407
-27
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Elimina",
|
||||
"common_enable": "Abilita",
|
||||
"common_disable": "Disattivare",
|
||||
"common_autoRefresh": "Aggiornamento automatico",
|
||||
"common_interval": "Intervallo",
|
||||
"common_reboot": "Riavvia",
|
||||
"common_loading": "Caricamento...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Modalità privacy abilitata",
|
||||
"settings_privacyModeDisabled": "Modalità privacy disabilitata",
|
||||
"settings_actions": "Azioni",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Invia Annuncio",
|
||||
"settings_sendAdvertisementSubtitle": "Presenza trasmessa ora",
|
||||
"settings_advertisementSent": "Annuncio inviato",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Log di Debug dell'App",
|
||||
"settings_appDebugLogSubtitle": "Messaggi di debug dell'applicazione",
|
||||
"settings_about": "Informazioni",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open versione {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Scuro",
|
||||
"appSettings_language": "Lingua",
|
||||
"appSettings_languageSystem": "Predefinito di sistema",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageEn": "Inglese",
|
||||
"appSettings_languageFr": "Francese",
|
||||
"appSettings_languageEs": "Spagnolo",
|
||||
"appSettings_languageDe": "Tedesco",
|
||||
"appSettings_languagePl": "Polacco",
|
||||
"appSettings_languageSl": "Sloveno",
|
||||
"appSettings_languagePt": "Portoghese",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageZh": "Cinese",
|
||||
"appSettings_languageSv": "Svedese",
|
||||
"appSettings_languageNl": "Olandese",
|
||||
"appSettings_languageSk": "Sloveno",
|
||||
"appSettings_languageBg": "Bulgaro",
|
||||
"appSettings_notifications": "Notifiche",
|
||||
"appSettings_enableNotifications": "Abilita Notifiche",
|
||||
"appSettings_enableNotificationsSubtitle": "Ricevi notifiche per messaggi e annunci",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Canale hashtag",
|
||||
"channels_public": "Pubblico",
|
||||
"channels_private": "Privato",
|
||||
"channels_publicChannel": "Canale pubblico",
|
||||
"channels_privateChannel": "Canale privato",
|
||||
"channels_editChannel": "Modifica canale",
|
||||
"channels_muteChannel": "Silenzia canale",
|
||||
"channels_unmuteChannel": "Attiva notifiche canale",
|
||||
@@ -367,7 +368,7 @@
|
||||
"channels_channelName": "Nome canale",
|
||||
"channels_usePublicChannel": "Utilizza il canale pubblico",
|
||||
"channels_standardPublicPsk": "PSK pubblico standard",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (esadecimale)",
|
||||
"channels_generateRandomPsk": "Genera una chiave di permutazione casuale",
|
||||
"channels_enterChannelName": "Inserisci un nome per il canale",
|
||||
"channels_pskMustBe32Hex": "PSK deve essere composto da 32 caratteri esadecimali.",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Compressione SMAZ",
|
||||
"channels_cyr2latCompression": "Compressione Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Sostituisce alcuni caratteri cirillici con caratteri latini durante l'invio.",
|
||||
"channels_cyr2latSettingsHeading": "Impostazioni Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Elenco delle sostituzioni",
|
||||
"channels_cyr2latSettingsDscr": "Modifica la configurazione JSON delle sostituzioni dei caratteri",
|
||||
"channels_cyr2latSettingsDialogHint": "Mappa JSON delle sostituzioni",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "JSON non corretto: {error}",
|
||||
"settings_cyr2latProfileAdd": "Aggiungi profilo Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Nome profilo",
|
||||
"settings_cyr2latProfileNameEmpty": "Il nome del profilo non può essere vuoto",
|
||||
"settings_cyr2latProfileAdded": "Profilo aggiunto con successo",
|
||||
"settings_cyr2latProfileUpdated": "Profilo aggiornato con successo",
|
||||
"settings_cyr2latProfileEdit": "Modifica profilo Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Elimina profilo Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Profilo eliminato con successo",
|
||||
"settings_cyr2latProfileDeleteDscr": "Sei sicuro di voler eliminare il profilo \"{name}\"?",
|
||||
"channels_channelUpdated": "Canale \"{name}\" aggiornato",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Canale pubblico aggiunto",
|
||||
"channels_sortBy": "Ordina per",
|
||||
"channels_sortManual": "Manuale",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "D-Z",
|
||||
"channels_sortLatestMessages": "Ultimi messaggi",
|
||||
"channels_sortUnread": "Non letto",
|
||||
"chat_noMessages": "Nessun messaggio ancora",
|
||||
@@ -456,7 +473,7 @@
|
||||
"chat_sendGif": "Invia GIF",
|
||||
"chat_reply": "Rispondi",
|
||||
"chat_addReaction": "Aggiungi Reazione",
|
||||
"chat_me": "Me",
|
||||
"chat_me": "Io",
|
||||
"emojiCategorySmileys": "Emoji",
|
||||
"emojiCategoryGestures": "Gesti",
|
||||
"emojiCategoryHearts": "Cuori",
|
||||
@@ -504,7 +521,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_timestamp": "- Timestamp: {timestamp}",
|
||||
"debugFrame_timestamp": "- Marca temporale: {timestamp}",
|
||||
"@debugFrame_timestamp": {
|
||||
"placeholders": {
|
||||
"timestamp": {
|
||||
@@ -881,7 +898,7 @@
|
||||
"repeater_managementTools": "Strumenti di Gestione",
|
||||
"repeater_status": "Stato",
|
||||
"repeater_statusSubtitle": "Visualizza lo stato, le statistiche e i vicini del ripetitore",
|
||||
"repeater_telemetry": "Telemetry",
|
||||
"repeater_telemetry": "Telemetria",
|
||||
"repeater_telemetrySubtitle": "Visualizza i dati di telemetria dei sensori e le statistiche di sistema",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cliSubtitle": "Invia comandi al ripetitore",
|
||||
@@ -996,7 +1013,7 @@
|
||||
"repeater_txPower": "TX Potenza",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Larghezza di banda",
|
||||
"repeater_spreadingFactor": "Spreading Factor",
|
||||
"repeater_spreadingFactor": "Fattore di propagazione",
|
||||
"repeater_codingRate": "Tasso di Codifica",
|
||||
"repeater_locationSettings": "Impostazioni Luogo",
|
||||
"repeater_latitude": "Latitudine",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Conferma",
|
||||
"repeater_settingsSaved": "Impostazioni salvate con successo",
|
||||
"repeater_rxGain": "Aumento del guadagno RX",
|
||||
"repeater_rxGainHelper": "Maggiore sensibilità, maggiore assorbimento di corrente (solo per SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Rafforza l'effetto di RX",
|
||||
"repeater_multiAcks": "ACK multipli",
|
||||
"repeater_multiAcksSubtitle": "Riconoscere i messaggi attraverso percorsi multipli per una migliore consegna.",
|
||||
"repeater_refreshMultiAcks": "Riaffermare più ACK",
|
||||
"repeater_networkHealth": "Salute della rete",
|
||||
"repeater_loopDetect": "Rilevamento di cicli",
|
||||
"repeater_loopDetectHelper": "Crea pacchetti di dati che simulano loop di routing.",
|
||||
"repeater_loopDetectOff": "Offerte",
|
||||
"repeater_loopDetectMinimal": "Essenziale",
|
||||
"repeater_loopDetectModerate": "Moderato",
|
||||
"repeater_loopDetectStrict": "Rigido",
|
||||
"repeater_dutyCycle": "Ciclo di lavoro",
|
||||
"repeater_dutyCycleHelper": "Percentuale massima di utilizzo dello spazio pubblicitario",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informazioni sull'operatore",
|
||||
"repeater_ownerInfoHelper": "Metadati pubblici per questo ripetitore",
|
||||
"repeater_refreshOwnerInfo": "Aggiorna le informazioni sull'operatore",
|
||||
"repeater_floodMax": "Massimo numero di salti in caso di inondazione",
|
||||
"repeater_floodMaxHelper": "Numero massimo di pacchetti che un flusso può attraversare (0-64)",
|
||||
"repeater_advancedSettings": "Avanzato",
|
||||
"repeater_advancedSettingsSubtitle": "Manopole di regolazione per operatori esperti",
|
||||
"repeater_pathHashMode": "Modalità di hashing del percorso",
|
||||
"repeater_pathHashModeHelper": "Byte utilizzati per codificare l'ID di questo ripetitore nei tag per il rilevamento del percorso/loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Le versioni 1.13 e precedenti utilizzano percorsi multi-byte: è necessario attivare la rete prima di utilizzare questa funzionalità (a partire dalla versione 1.14).",
|
||||
"repeater_txDelay": "Ritardo a Flood, TX",
|
||||
"repeater_txDelayHelper": "Riassegnare lo spazio tra i pacchetti per gestire il traffico intenso, come un moltiplicatore del tempo di trasmissione (da 0 a 2, valore predefinito 0,5). Un valore più alto significa meno collisioni, ma una trasmissione più lenta.",
|
||||
"repeater_directTxDelay": "Ritardo diretto TX",
|
||||
"repeater_directTxDelayHelper": "Riassegnare lo spazio per il traffico diretto (non di massa), come un moltiplicatore del tempo di trasmissione del pacchetto (da 0 a 2, valore predefinito 0,3).",
|
||||
"repeater_intThresh": "Soglia di interferenza",
|
||||
"repeater_intThreshHelper": "Il limite è stato impostato per la calibrazione del livello di rumore del ricevitore, in modo che esso rifiuti i segnali di interferenza superiori a questo livello. 0 disabilita – aumentalo solo se si verificano errori nel ricevitore in una banda di frequenza rumorosa.",
|
||||
"repeater_agcResetInterval": "Intervallo di ripristino di AGC",
|
||||
"repeater_agcResetIntervalHelper": "Con quale frequenza è necessario resettare il controllo automatico del guadagno per ripristinare il funzionamento dopo un'interruzione. Impostare su secondi, ridotti a multipli di 4. Disattivare la reimpostazione periodica.",
|
||||
"repeater_actionsTitle": "Azioni",
|
||||
"repeater_sendAdvert": "Inviare annuncio relativo alle inondazioni",
|
||||
"repeater_sendAdvertSubtitle": "Trasmettere un annuncio pubblicitario relativo alle inondazioni attraverso la rete.",
|
||||
"repeater_sendAdvertZeroHop": "Inviare un annuncio senza intermediari",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Trasmettere un annuncio a un solo hop (senza ripetitori)",
|
||||
"repeater_clockSync": "Sincronizza l'orologio ora",
|
||||
"repeater_clockSyncSubtitle": "Imposta l'ora del tuo telefono sul ripetitore.",
|
||||
"repeater_actionSucceeded": "{action} ha avuto successo",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Impostazioni salvate — riavviare il ripetitore per applicare le modifiche",
|
||||
"repeater_settingsPartialFailure": "Alcune impostazioni non sono state salvate: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Errore durante il salvataggio delle impostazioni: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Aggiorna Impostazioni Base",
|
||||
"repeater_refreshRadioSettings": "Aggiorna le Impostazioni Radio",
|
||||
"repeater_refreshTxPower": "Aggiorna TX potenza",
|
||||
"repeater_refreshLocationSettings": "Aggiorna le Impostazioni della Posizione",
|
||||
"repeater_refreshPacketForwarding": "Aggiorna il inoltro pacchetti",
|
||||
"repeater_refreshGuestAccess": "Aggiorna Accesso Ospite",
|
||||
"repeater_refreshPrivacyMode": "Aggiorna Modalità Privacy",
|
||||
"repeater_refreshAdvertisementSettings": "Aggiorna le Impostazioni dell'Annuncio",
|
||||
"repeater_refreshed": "{label} aggiornato",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Ingresso digitale",
|
||||
"telemetry_digitalOutputLabel": "Uscita digitale",
|
||||
"telemetry_analogInputLabel": "Ingresso analogico",
|
||||
"telemetry_analogOutputLabel": "Uscita analogica",
|
||||
"telemetry_genericLabel": "Sensore generico",
|
||||
"telemetry_luminosityLabel": "Luminosità",
|
||||
"telemetry_presenceLabel": "Presenza",
|
||||
"telemetry_humidityLabel": "Umidità",
|
||||
"telemetry_accelerometerLabel": "Accelerometro",
|
||||
"telemetry_pressureLabel": "Pressione",
|
||||
"telemetry_altitudeLabel": "Altitudine",
|
||||
"telemetry_frequencyLabel": "Frequenza",
|
||||
"telemetry_percentageLabel": "Percentuale",
|
||||
"telemetry_concentrationLabel": "Concentrazione",
|
||||
"telemetry_powerLabel": "Potenza",
|
||||
"telemetry_distanceLabel": "Distanza",
|
||||
"telemetry_energyLabel": "Energia",
|
||||
"telemetry_directionLabel": "Direzione",
|
||||
"telemetry_timeLabel": "Ora",
|
||||
"telemetry_gyrometerLabel": "Giroscopio",
|
||||
"telemetry_colourLabel": "Colore",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Interruttore",
|
||||
"telemetry_polylineLabel": "Polilinea",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Numero di richieste",
|
||||
"telemetry_error": "Impossibile recuperare i dati",
|
||||
"telemetry_noData": "Nessun dato di telemetria disponibile.",
|
||||
"telemetry_channelTitle": "Canale {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Ordina per",
|
||||
"listFilter_latestMessages": "Ultimi messaggi",
|
||||
"listFilter_heardRecently": "Sentito di recente",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "D-Z",
|
||||
"listFilter_filters": "Filtri",
|
||||
"listFilter_all": "Tutti",
|
||||
"listFilter_users": "Utenti",
|
||||
@@ -1459,7 +1586,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_ok": "OK",
|
||||
"common_ok": "Va bene",
|
||||
"community_title": "Comunità",
|
||||
"community_create": "Crea Comunità",
|
||||
"community_createDesc": "Crea una nuova comunità e condividila tramite codice QR.",
|
||||
@@ -1934,6 +2061,7 @@
|
||||
"appSettings_maxMessageRetriesSubtitle": "Numero di tentativi di riprova prima di considerare un messaggio come fallito.",
|
||||
"path_routeWeight": "{weight}/{max}",
|
||||
"settings_telemetryModeUpdated": "Modalità telemetria aggiornata",
|
||||
"settings_multiAck": "ACK multipli",
|
||||
"map_showOverlaps": "Sovrapposizioni della chiave ripetitore",
|
||||
"map_runTraceWithReturnPath": "Tornare indietro sullo stesso percorso",
|
||||
"@radioStats_noiseFloor": {
|
||||
@@ -2011,6 +2139,9 @@
|
||||
"translation_enableTitle": "Abilitare la traduzione",
|
||||
"translation_title": "Traduzione",
|
||||
"translation_composerSubtitle": "Controlla lo stato predefinito dell'icona di traduzione del compositore.",
|
||||
"translation_autoIncomingTitle": "Traduci automaticamente i messaggi",
|
||||
"translation_autoIncomingSubtitle": "Traduce automaticamente i messaggi per le notifiche e per le chat o i canali.",
|
||||
"translation_translateMessage": "Traduci messaggio",
|
||||
"translation_targetLanguage": "Lingua di destinazione",
|
||||
"translation_useAppLanguage": "Utilizza la lingua dell'app",
|
||||
"translation_downloadedModelLabel": "Modello scaricato",
|
||||
@@ -2066,5 +2197,254 @@
|
||||
"repeater_guestTools": "Strumenti per gli ospiti",
|
||||
"chat_sendMessage": "Invia messaggio",
|
||||
"room_guest": "Informazioni sul server",
|
||||
"settings_multiAck": "ACK multipli"
|
||||
"repeater_getCategory": "Ottenere valori",
|
||||
"repeater_powerMgmt": "Gestione dell'energia",
|
||||
"repeater_sensors": "Sensori",
|
||||
"repeater_cliHelpPowerOff": "Disattiva il dispositivo. (non ci si aspetta alcuna risposta)",
|
||||
"repeater_cliHelpClkReboot": "Riporta l'orologio a un'epoca nota e riavvia il dispositivo.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Invia un annuncio che raggiunge solo i vicini immediati (senza passaggi intermedi).",
|
||||
"repeater_cliHelpStartOta": "Avvia un aggiornamento del firmware tramite la trasmissione radio su schede supportate.",
|
||||
"repeater_cliHelpTime": "Imposta l'orario del dispositivo sui secondi dell'epoca Unix specificati. L'orario non può andare indietro.",
|
||||
"repeater_cliHelpBoard": "Indica il produttore della scheda e l'identificatore hardware.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Invia una richiesta di scoperta di nodi ai vicini. (Solo per ripetitori)",
|
||||
"repeater_cliHelpPowersaving": "Indica se la modalità di risparmio energetico è attiva o disattivata.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Abilita o disabilita la modalità di risparmio energetico (se supportata).",
|
||||
"repeater_cliHelpErase": "(Solo per sistemi di serializzazione) Formatta il file system del dispositivo. Elimina tutte le impostazioni e i contatti.",
|
||||
"repeater_cliHelpSetDutyCycle": "Imposta il ciclo di trasmissione massimo consentito in percentuale (da 1 a 100). Regola internamente il fattore di tempo di trasmissione.",
|
||||
"repeater_cliHelpSetPrvKey": "(Solo per serie) Sostituisce la chiave privata di identificazione del dispositivo. È necessario riavviare il dispositivo per applicare la modifica. Genera una nuova chiave pubblica.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Solo per SX126x) Permette di attivare un guadagno RX potenziato per una maggiore sensibilità a correnti più elevate.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Definisce la stringa contenente le informazioni di contatto del proprietario, presente negli annunci. Utilizzare '|' per i newline.",
|
||||
"repeater_cliHelpSetPathHashMode": "Imposta la modalità di hashing del percorso. 0 = modalità legacy, 1 = modalità standard, 2 = modalità rigorosa. Influisce su come vengono abbinati i percorsi di routing.",
|
||||
"repeater_cliHelpSetLoopDetect": "Imposta il livello di sensibilità per il rilevamento dei loop di routing: disattivato, minimo, moderato o rigoroso.",
|
||||
"repeater_cliHelpSetFreq": "(Solo per la funzione di regolazione della frequenza) Imposta rapidamente la frequenza desiderata. È necessario riavviare il dispositivo. Si consiglia di utilizzare la funzione \"imposta radio\" per impostare tutti i parametri radio.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Solo per il bridge ESPNow) Imposta il canale Wi-Fi (da 1 a 14) utilizzato dal bridge.",
|
||||
"repeater_cliHelpGetName": "Mostra il nome del nodo configurato.",
|
||||
"repeater_cliHelpGetRole": "Indica il ruolo del firmware (ripetitore, server per stanza, ecc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Mostra la chiave pubblica del dispositivo.",
|
||||
"repeater_cliHelpGetPrvKey": "(Solo per serie) Visualizza la chiave privata del dispositivo. Trattala come una informazione riservata.",
|
||||
"repeater_cliHelpGetRepeat": "Indica se la funzione di inoltro dei pacchetti (funzione di ripetitore) è attiva o disattivata.",
|
||||
"repeater_cliHelpGetTx": "Mostra la potenza attuale in dBm.",
|
||||
"repeater_cliHelpGetFreq": "Mostra la frequenza radio configurata in MHz.",
|
||||
"repeater_cliHelpGetRadio": "Visualizza tutti i parametri radio: frequenza, larghezza di banda, fattore di spreading, tasso di codifica.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Solo per i moduli SX126x) Mostra lo stato del guadagno potenziato del RX.",
|
||||
"repeater_cliHelpGetAf": "Mostra il fattore di trasmissione attuale.",
|
||||
"repeater_cliHelpGetDutyCycle": "Mostra il ciclo di lavoro attuale consentito in percentuale.",
|
||||
"repeater_cliHelpGetIntThresh": "Mostra il limite di interferenza del canale in dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Indica l'intervallo di reset dell'AGC in secondi.",
|
||||
"repeater_cliHelpGetMultiAcks": "Indica se la modalità \"ACK doppio\" è attiva (1) o disattivata (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Indica se è consentito l'accesso in sola lettura per gli ospiti.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Indica l'intervallo pubblicitario locale in minuti.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Indica l'intervallo pubblicitario per la trasmissione del servizio di allerta alluvioni, espresso in ore.",
|
||||
"repeater_cliHelpGetGuestPassword": "Visualizza la password del guest configurata.",
|
||||
"repeater_cliHelpGetLat": "Mostra la latitudine configurata.",
|
||||
"repeater_cliHelpGetLon": "Mostra la longitudine impostata.",
|
||||
"repeater_cliHelpGetRxDelay": "Mostra il valore base di rxdelay.",
|
||||
"repeater_cliHelpGetTxDelay": "Mostra il fattore di ritardo in modalità di allarme.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Mostra il fattore di ritardo in modalità diretta.",
|
||||
"repeater_cliHelpGetFloodMax": "Mostra il numero massimo di salti dovuto all'inondazione.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Visualizza la stringa contenente le informazioni di contatto del proprietario.",
|
||||
"repeater_cliHelpGetPathHashMode": "Mostra la modalità \"hash del percorso\" (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Indica la sensibilità alla rilevazione di loop.",
|
||||
"repeater_cliHelpGetAcl": "(Solo per serie) Elenca le voci di controllo degli accessi su un ripetitore.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Indica se il ponte è attivo.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Mostra il ritardo del ponte in millisecondi.",
|
||||
"repeater_cliHelpGetBridgeSource": "Indica se il bridge sta inviando pacchetti RX o TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Solo per l'adattatore RS232) Visualizza la velocità di trasmissione del bridge.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Solo per il bridge ESPNow) Visualizza il canale WiFi del bridge.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Solo per il bridge ESPNow) Visualizza la chiave segreta condivisa.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Solo per NRF52) Visualizza la versione del bootloader.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Mostra il moltiplicatore ADC (adattamento della tensione della batteria).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Indica se il sistema dispone di funzionalità di gestione dell'energia.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Indica la fonte di alimentazione attuale: esterna o batteria.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Mostra le ragioni più recenti per il ripristino e lo spegnimento.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Mostra la tensione della batteria al momento dell'accensione, misurata in millivolt (mV).",
|
||||
"repeater_cliHelpSensorGet": "Legge un valore di configurazione personalizzato per un sensore tramite un tasto.",
|
||||
"repeater_cliHelpSensorSet": "Definisce una configurazione personalizzata per un sensore.",
|
||||
"repeater_cliHelpSensorList": "Elenca tutte le impostazioni personalizzate dei sensori, organizzate in pagine a partire da un indice di inizio opzionale.",
|
||||
"repeater_cliHelpRegionDefault": "Mostra l'ambito predefinito corrente.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Definisce l'ambito regionale predefinito. Utilizzare \"<null>\" per cancellare.",
|
||||
"repeater_cliHelpRegionListAllowed": "Elenca le regioni che consentono il transito di veicoli in caso di allagamenti.",
|
||||
"repeater_cliHelpRegionListDenied": "Elenca le regioni che vietano il transito in caso di alluvioni.",
|
||||
"repeater_cliHelpStatsPackets": "(Solo per la visualizzazione dei dati seriali) Mostra statistiche a livello di pacchetto.",
|
||||
"repeater_cliHelpStatsRadio": "(Solo per serie TV) Visualizza statistiche relative alla trasmissione radiofonica.",
|
||||
"repeater_cliHelpStatsCore": "(Solo per serie) Visualizza le statistiche del firmware di base.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Condiviso",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Ostacolo selezionato",
|
||||
"losBlockedSpotsHint": "Tocca un punto bloccato sulla mappa per evidenziarlo.",
|
||||
"losBlockedSpotsTitle": "Posti occupati",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"settings_companionDebugLogSubtitle": "Comandi, risposte e dati grezzi per protocolli BLE/TCP/USB",
|
||||
"settings_companionDebugLog": "Registro di debug per il supporto",
|
||||
"chat_newMessages": "Nuovi messaggi",
|
||||
"chat_markAsUnread": "Segna come non letto",
|
||||
"repeater_chanUtil": "Utilizzo del canale",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_undo": "Annulla",
|
||||
"messageStatus_delivered": "Consegnato",
|
||||
"messageStatus_sent": "Invia",
|
||||
"messageStatus_pending": "Invio",
|
||||
"messageStatus_failed": "Impossibile inviare",
|
||||
"messageStatus_repeated": "Sentito ripetutamente",
|
||||
"contacts_moreOptions": "Ulteriori opzioni",
|
||||
"contacts_searchOpen": "Cerca contatti",
|
||||
"contacts_searchClose": "Ricerca avanzata",
|
||||
"routing_title": "Instradamento",
|
||||
"routing_modeAuto": "Auto",
|
||||
"routing_modeFlood": "Inondazione",
|
||||
"routing_modeManual": "Manuale",
|
||||
"routing_modeAutoHint": "Seleziona automaticamente il percorso più noto, e in caso di assenza di informazioni, utilizza un percorso casuale.",
|
||||
"routing_modeFloodHint": "Trasmissioni tramite ogni ripetitore. Il metodo più affidabile, ma richiede più tempo di trasmissione.",
|
||||
"routing_modeManualHint": "Invia sempre esattamente il percorso che hai definito.",
|
||||
"routing_currentRoute": "Percorso attuale",
|
||||
"routing_directNoHops": "Diretto — senza passaggi tramite ripetitori",
|
||||
"routing_noPathYet": "Al momento non è stata individuata alcuna via. Il messaggio viene inviato ripetutamente finché non viene trovata una rotta.",
|
||||
"routing_floodBroadcast": "Trasmissione attraverso ogni ripetitore",
|
||||
"routing_editPath": "Percorso di modifica",
|
||||
"routing_forgetPath": "Dimentica il percorso",
|
||||
"routing_knownPaths": "Percorsi noti",
|
||||
"routing_knownPathsHint": "Seleziona un percorso per accedere a questa opzione.",
|
||||
"routing_inUse": "In uso",
|
||||
"routing_qualityStrong": "Primo salto molto deciso",
|
||||
"routing_qualityGood": "Primo tentativo di successo",
|
||||
"routing_qualityFair": "Primo salto di qualità",
|
||||
"routing_qualityWorked": "È stato consegnato",
|
||||
"routing_qualityFlood": "Ho sentito tramite un messaggio urgente",
|
||||
"routing_qualityUntested": "Non testato",
|
||||
"routing_neverWorked": "mai confermato",
|
||||
"routing_floodDelivery": "Consegna in caso di alluvione",
|
||||
"pathEditor_title": "Creare percorso",
|
||||
"pathEditor_hopCounter": "{count} tra 64 varietà di luppolo",
|
||||
"pathEditor_noHops": "Al momento non ci sono ingredienti aggiuntivi. Per aggiungerli nell'ordine desiderato, cliccate sui ripetitori sottostanti. In alternativa, potete salvare la ricetta senza ingredienti aggiuntivi per inviarla direttamente.",
|
||||
"pathEditor_addHops": "Aggiungere i luppoli nell'ordine desiderato.",
|
||||
"pathEditor_searchRepeaters": "Ricerca ripetitori",
|
||||
"pathEditor_advancedHex": "Avanzato: percorso esadecimale grezzo",
|
||||
"pathEditor_hexLabel": "Prefissi esadecimali",
|
||||
"pathEditor_hexHelper": "Due caratteri esadecimali per ogni salto, separati da virgole.",
|
||||
"pathEditor_invalidTokens": "Non valido: {tokens}",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"pathEditor_tooManyHops": "Massimo 64 orari",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_usePath": "Utilizza questo percorso",
|
||||
"pathEditor_removeHop": "Rimuovere il luppolo",
|
||||
"pathEditor_unknownHop": "Ripetitore sconosciuto",
|
||||
"map_zoomIn": "Ingrandisci",
|
||||
"map_zoomOut": "Riduci la visualizzazione",
|
||||
"map_centerMap": "Mappa del centro",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth richiede un browser basato su Chromium.",
|
||||
"pathTrace_legendGpsConfirmed": "Il GPS conferma",
|
||||
"pathTrace_legendInferred": "Posizione dedotta"
|
||||
}
|
||||
|
||||
+443
-63
@@ -27,6 +27,8 @@
|
||||
"common_remove": "削除",
|
||||
"common_enable": "有効化する",
|
||||
"common_disable": "無効化する",
|
||||
"common_autoRefresh": "自動更新",
|
||||
"common_interval": "間隔",
|
||||
"common_reboot": "再起動",
|
||||
"common_loading": "読み込み中...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -49,7 +51,7 @@
|
||||
"scanner_title": "MeshCore オープン",
|
||||
"connectionChoiceUsbLabel": "USB",
|
||||
"connectionChoiceBluetoothLabel": "ブルートゥース",
|
||||
"connectionChoiceTcpLabel": "TCP",
|
||||
"connectionChoiceTcpLabel": "TCP (Transmission Control Protocol)",
|
||||
"tcpScreenTitle": "TCP を使用して接続",
|
||||
"tcpHostLabel": "IPアドレス",
|
||||
"tcpHostHint": "192.168.40.10",
|
||||
@@ -167,6 +169,8 @@
|
||||
"settings_privacyModeEnabled": "プライバシーモードが有効になっています",
|
||||
"settings_privacyModeDisabled": "プライバシーモードは無効化されています",
|
||||
"settings_actions": "行動",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "広告を送信する",
|
||||
"settings_sendAdvertisementSubtitle": "現在、放送での活動",
|
||||
"settings_advertisementSent": "広告が送信されました",
|
||||
@@ -212,7 +216,7 @@
|
||||
"settings_txPower": "TX 信号電力 (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerInvalid": "無効な送信電力 (0-22 dBm)",
|
||||
"settings_clientRepeat": "オフグリッド(電力網から孤立した状態)の繰り返し",
|
||||
"settings_clientRepeat": "オフグリッドリピータ",
|
||||
"settings_clientRepeatSubtitle": "このデバイスが、他のデバイスに対してメッシュパケットを繰り返し送信できるようにする。",
|
||||
"settings_clientRepeatFreqWarning": "オフグリッドでの再送には、433MHz、869MHz、または918MHzの周波数が必要です。",
|
||||
"settings_error": "エラー:{message}",
|
||||
@@ -266,7 +270,7 @@
|
||||
"appSettings_pathsWillBeCleared": "5回失敗した後、経路が再開されます。",
|
||||
"appSettings_pathsWillNotBeCleared": "パスは自動で削除されません。",
|
||||
"appSettings_autoRouteRotation": "自動ルートの切り替え",
|
||||
"appSettings_autoRouteRotationSubtitle": "最適なルートと、洪水モードを切り替える",
|
||||
"appSettings_autoRouteRotationSubtitle": "最適なルートと、フラッドモードを切り替える",
|
||||
"appSettings_autoRouteRotationEnabled": "自動ルートの切り替え機能が有効になっています",
|
||||
"appSettings_autoRouteRotationDisabled": "自動ルートの変更機能が無効になっています。",
|
||||
"appSettings_maxRouteWeight": "最大ルート重量",
|
||||
@@ -306,7 +310,7 @@
|
||||
"appSettings_batteryLipo": "LiPo (3.0-4.2V)",
|
||||
"appSettings_mapDisplay": "地図の表示",
|
||||
"appSettings_showRepeaters": "繰り返し再生機能",
|
||||
"appSettings_showRepeatersSubtitle": "地図上にリピーターノードを表示する",
|
||||
"appSettings_showRepeatersSubtitle": "地図上にリピータノードを表示する",
|
||||
"appSettings_showChatNodes": "チャットノードの表示",
|
||||
"appSettings_showChatNodesSubtitle": "地図上にチャットノードを表示する",
|
||||
"appSettings_showOtherNodes": "他のノードを表示する",
|
||||
@@ -420,7 +424,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"contacts_manageRepeater": "リピーターの管理",
|
||||
"contacts_manageRepeater": "リピータの管理",
|
||||
"contacts_manageRoom": "ルームサーバーの管理",
|
||||
"contacts_roomLogin": "ルームサーバーへのログイン",
|
||||
"contacts_openChat": "自由な会話",
|
||||
@@ -489,11 +493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "ハッシュタグチャンネル",
|
||||
"channels_public": "一般の人々",
|
||||
"channels_private": "個人の",
|
||||
"channels_publicChannel": "一般チャンネル",
|
||||
"channels_privateChannel": "プライベートチャンネル",
|
||||
"channels_editChannel": "チャンネルを編集する",
|
||||
"channels_muteChannel": "ミュート機能",
|
||||
"channels_unmuteChannel": "ミュートを解除する",
|
||||
@@ -548,6 +549,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ 圧縮",
|
||||
"channels_cyr2latCompression": "Cyr2Lat 圧縮",
|
||||
"channels_cyr2latCompressionDscr": "送信時に一部のキリル文字をラテン文字に置き換えます。",
|
||||
"channels_cyr2latSettingsHeading": "cyr2latの設定",
|
||||
"channels_cyr2latSettingsSubheading": "置換リスト",
|
||||
"channels_cyr2latSettingsDscr": "文字置換のJSON設定を編集する",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON置換マップ",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "不正なJSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Cyr2Latプロファイルの追加",
|
||||
"settings_cyr2latProfileName": "プロファイル名",
|
||||
"settings_cyr2latProfileNameEmpty": "プロファイル名は空にできません",
|
||||
"settings_cyr2latProfileAdded": "プロファイルが正常に追加されました",
|
||||
"settings_cyr2latProfileUpdated": "プロファイルの更新に成功しました",
|
||||
"settings_cyr2latProfileEdit": "Cyr2Latプロファイルを編集",
|
||||
"settings_cyr2latProfileDelete": "Cyr2Latプロファイルを削除",
|
||||
"settings_cyr2latProfileDeleted": "プロファイルの削除に成功しました",
|
||||
"settings_cyr2latProfileDeleteDscr": "プロファイル \"{name}\" を削除してもよろしいですか?",
|
||||
"channels_channelUpdated": "チャンネル「{name}」が更新されました",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -718,7 +735,7 @@
|
||||
"chat_ShowAllPaths": "すべての経路を表示",
|
||||
"chat_routingMode": "ルーティングモード",
|
||||
"chat_autoUseSavedPath": "自動 (保存されたパスを使用)",
|
||||
"chat_forceFloodMode": "強制的に洪水モードを起動",
|
||||
"chat_forceFloodMode": "強制的にフラッドモードを起動",
|
||||
"chat_recentAckPaths": "最近使用したACKパス(タップして使用):",
|
||||
"chat_pathHistoryFull": "パスの履歴は完全です。エントリを削除して、新しいものを追加できます。",
|
||||
"chat_hopSingular": "ジャンプ",
|
||||
@@ -741,7 +758,7 @@
|
||||
"chat_clearPathSubtitle": "次回送信時に、以前の情報を再取得する",
|
||||
"chat_pathCleared": "経路が確保されました。次のメッセージでルートを再確認します。",
|
||||
"chat_floodModeSubtitle": "アプリのバーにあるルーティング切り替え機能を使用する",
|
||||
"chat_floodModeEnabled": "洪水モードが有効になっています。アプリのメニューバーにあるルートアイコンを使用して、モードを切り替えることができます。",
|
||||
"chat_floodModeEnabled": "フラッドモードが有効になっています。アプリのメニューバーにあるルートアイコンを使用して、モードを切り替えることができます。",
|
||||
"chat_fullPath": "フルパス",
|
||||
"chat_pathDetailsNotAvailable": "経路の詳細については、まだ情報がありません。「リフレッシュ」ボタンを押して、再度お試しください。",
|
||||
"chat_pathSetHops": "Path set: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
|
||||
@@ -762,7 +779,7 @@
|
||||
"chat_path": "道",
|
||||
"chat_publicKey": "公開鍵",
|
||||
"chat_compressOutgoingMessages": "送信されるメッセージを圧縮する",
|
||||
"chat_floodForced": "洪水(強制的な)",
|
||||
"chat_floodForced": "フラッド(強制的な)",
|
||||
"chat_directForced": "直接的な(強制的な)",
|
||||
"chat_hopsForced": "{count} 本のホップ(強制的に採取)",
|
||||
"@chat_hopsForced": {
|
||||
@@ -772,7 +789,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat_floodAuto": "洪水 (自動)",
|
||||
"chat_floodAuto": "フラッド (自動)",
|
||||
"chat_direct": "直接",
|
||||
"chat_poiShared": "共有されたPOI",
|
||||
"chat_unread": "未読: {count}",
|
||||
@@ -817,7 +834,7 @@
|
||||
}
|
||||
},
|
||||
"map_chat": "チャット",
|
||||
"map_repeater": "繰り返し送信装置",
|
||||
"map_repeater": "リピータ",
|
||||
"map_room": "部屋",
|
||||
"map_sensor": "センサー",
|
||||
"map_pinDm": "ピン(DM)",
|
||||
@@ -849,7 +866,7 @@
|
||||
"map_filterNodes": "フィルタノード",
|
||||
"map_nodeTypes": "ノードの種類",
|
||||
"map_chatNodes": "チャットノード",
|
||||
"map_repeaters": "繰り返し送信装置",
|
||||
"map_repeaters": "リピータ",
|
||||
"map_otherNodes": "その他のノード",
|
||||
"map_keyPrefix": "主要なプレフィックス",
|
||||
"map_filterByKeyPrefix": "主要なプレフィックスでフィルタリングする",
|
||||
@@ -862,7 +879,7 @@
|
||||
"map_lastSeenTime": "最後に確認された時間",
|
||||
"map_sharedPin": "共有パスワード",
|
||||
"map_joinRoom": "部屋に参加する",
|
||||
"map_manageRepeater": "リピーターの管理",
|
||||
"map_manageRepeater": "リピータの管理",
|
||||
"map_tapToAdd": "ノードをクリックして、パスに追加します。",
|
||||
"map_runTrace": "パスの追跡を実行",
|
||||
"map_removeLast": "最後のものを削除",
|
||||
@@ -995,12 +1012,12 @@
|
||||
"login_enterPassword": "パスワードを入力してください",
|
||||
"login_savePassword": "パスワードを保存する",
|
||||
"login_savePasswordSubtitle": "パスワードは、このデバイスに安全に保存されます。",
|
||||
"login_repeaterDescription": "設定やステータスにアクセスするために、リピーターのパスワードを入力してください。",
|
||||
"login_repeaterDescription": "設定やステータスにアクセスするために、リピータのパスワードを入力してください。",
|
||||
"login_roomDescription": "設定やステータスへのアクセスには、部屋のパスワードを入力してください。",
|
||||
"login_routing": "経路設定",
|
||||
"login_routingMode": "ルーティングモード",
|
||||
"login_autoUseSavedPath": "自動 (保存されたパスを使用)",
|
||||
"login_forceFloodMode": "強制的に洪水モードを起動",
|
||||
"login_forceFloodMode": "強制的にフラッドモードを起動",
|
||||
"login_managePaths": "パスの管理",
|
||||
"login_login": "ログイン",
|
||||
"login_attempt": "試行回数:{current}/{max}",
|
||||
@@ -1049,7 +1066,7 @@
|
||||
"path_helperMaxHops": "最大64個のホップ。各プレフィックスは2つの16進数文字(1バイト)で構成されています。",
|
||||
"path_selectFromContacts": "または、連絡先リストから選択してください:",
|
||||
"path_noRepeatersFound": "繰り返し機能やルームサーバーは見つかりませんでした。",
|
||||
"path_customPathsRequire": "カスタムパスには、メッセージを中継できる中間地点が必要です。",
|
||||
"path_customPathsRequire": "カスタムパスには、メッセージを中継できるリピータが必要です。",
|
||||
"path_invalidHexPrefixes": "無効な16進数プレフィックス: {prefixes}",
|
||||
"@path_invalidHexPrefixes": {
|
||||
"placeholders": {
|
||||
@@ -1060,23 +1077,23 @@
|
||||
},
|
||||
"path_tooLong": "経路が長すぎる。最大64回のジャンプのみ許可。",
|
||||
"path_setPath": "パスを設定",
|
||||
"repeater_management": "リピーター管理",
|
||||
"repeater_management": "リピータ管理",
|
||||
"room_management": "ルームサーバーの管理",
|
||||
"repeater_managementTools": "管理ツール",
|
||||
"repeater_status": "ステータス",
|
||||
"repeater_statusSubtitle": "リピーターの状態、統計情報、および隣接するネットワークの情報を表示する",
|
||||
"repeater_statusSubtitle": "リピータの状態、統計情報、および隣接するネットワークの情報を表示する",
|
||||
"repeater_telemetry": "テレメトリー",
|
||||
"repeater_telemetrySubtitle": "センサーおよびシステムの状態に関するテレメトリの表示",
|
||||
"repeater_cli": "CLI(コマンドラインインターフェース)",
|
||||
"repeater_cliSubtitle": "リピーターへのコマンドを送信する",
|
||||
"repeater_cliSubtitle": "リピータへのコマンドを送信する",
|
||||
"repeater_neighbors": "近隣住民",
|
||||
"repeater_neighborsSubtitle": "ゼロホップの隣接ノードを表示する。",
|
||||
"repeater_settings": "設定",
|
||||
"repeater_settingsSubtitle": "リピーターのパラメータを設定する",
|
||||
"repeater_settingsSubtitle": "リピータのパラメータを設定する",
|
||||
"repeater_statusTitle": "再送ステータス",
|
||||
"repeater_routingMode": "ルーティングモード",
|
||||
"repeater_autoUseSavedPath": "自動 (保存されたパスを使用)",
|
||||
"repeater_forceFloodMode": "強制的に洪水モードを起動",
|
||||
"repeater_forceFloodMode": "強制的にフラッドモードを起動",
|
||||
"repeater_pathManagement": "経路管理",
|
||||
"repeater_refresh": "リフレッシュ",
|
||||
"repeater_statusRequestTimeout": "ステータス情報の取得に失敗しました。",
|
||||
@@ -1121,7 +1138,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_packetTxTotal": "合計: {total}, 洪水: {flood}, 直接: {direct}",
|
||||
"repeater_packetTxTotal": "合計: {total}, フラッド: {flood}, 直接: {direct}",
|
||||
"@repeater_packetTxTotal": {
|
||||
"placeholders": {
|
||||
"total": {
|
||||
@@ -1135,7 +1152,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_packetRxTotal": "合計: {total}, 洪水: {flood}, 直接: {direct}",
|
||||
"repeater_packetRxTotal": "合計: {total}, フラッド: {flood}, 直接: {direct}",
|
||||
"@repeater_packetRxTotal": {
|
||||
"placeholders": {
|
||||
"total": {
|
||||
@@ -1168,10 +1185,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsTitle": "リピーター設定",
|
||||
"repeater_settingsTitle": "リピータ設定",
|
||||
"repeater_basicSettings": "基本設定",
|
||||
"repeater_repeaterName": "送信装置名",
|
||||
"repeater_repeaterNameHelper": "このリピーターの名前",
|
||||
"repeater_repeaterName": "リピータ名",
|
||||
"repeater_repeaterNameHelper": "このリピータの名前",
|
||||
"repeater_adminPassword": "管理者パスワード",
|
||||
"repeater_adminPasswordHelper": "完全アクセス権のパスワード",
|
||||
"repeater_guestPassword": "ゲスト用のパスワード",
|
||||
@@ -1191,7 +1208,7 @@
|
||||
"repeater_longitudeHelper": "度分表記(例:-122.4194)",
|
||||
"repeater_features": "特徴",
|
||||
"repeater_packetForwarding": "パケット転送",
|
||||
"repeater_packetForwardingSubtitle": "リピーターがパケットを転送できるように設定する",
|
||||
"repeater_packetForwardingSubtitle": "リピータがパケットを転送できるように設定する",
|
||||
"repeater_guestAccess": "ゲストへのアクセス",
|
||||
"repeater_guestAccessSubtitle": "ゲストへの読み取り専用アクセスを許可する",
|
||||
"repeater_privacyMode": "プライバシーモード",
|
||||
@@ -1206,7 +1223,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_floodAdvertInterval": "洪水に関する広告の表示間隔",
|
||||
"repeater_floodAdvertInterval": "フラッドに関する広告の表示間隔",
|
||||
"repeater_floodAdvertIntervalHours": "{hours} 時間",
|
||||
"@repeater_floodAdvertIntervalHours": {
|
||||
"placeholders": {
|
||||
@@ -1217,15 +1234,15 @@
|
||||
},
|
||||
"repeater_encryptedAdvertInterval": "暗号化された広告表示間",
|
||||
"repeater_dangerZone": "危険区域",
|
||||
"repeater_rebootRepeater": "リピーターを再起動する",
|
||||
"repeater_rebootRepeaterSubtitle": "リピーターデバイスを再起動する",
|
||||
"repeater_rebootRepeaterConfirm": "本当にこのリピーターを再起動したいですか?",
|
||||
"repeater_rebootRepeater": "リピータを再起動する",
|
||||
"repeater_rebootRepeaterSubtitle": "リピータデバイスを再起動する",
|
||||
"repeater_rebootRepeaterConfirm": "本当にこのリピータを再起動したいですか?",
|
||||
"repeater_regenerateIdentityKey": "IDキーの再生成",
|
||||
"repeater_regenerateIdentityKeySubtitle": "新しい公開鍵/秘密鍵のペアを生成する",
|
||||
"repeater_regenerateIdentityKeyConfirm": "これにより、リピーターには新しい識別情報が割り当てられます。続行しますか?",
|
||||
"repeater_regenerateIdentityKeyConfirm": "これにより、リピータには新しい識別情報が割り当てられます。続行しますか?",
|
||||
"repeater_eraseFileSystem": "ファイルシステムを削除する",
|
||||
"repeater_eraseFileSystemSubtitle": "リピーターファイルシステムをフォーマットする",
|
||||
"repeater_eraseFileSystemConfirm": "警告:この操作により、リピーター内のすべてのデータが消去されます。この操作は元に戻すことができません!",
|
||||
"repeater_eraseFileSystemSubtitle": "リピータファイルシステムをフォーマットする",
|
||||
"repeater_eraseFileSystemConfirm": "警告:この操作により、リピータ内のすべてのデータが消去されます。この操作は元に戻すことができません!",
|
||||
"repeater_eraseSerialOnly": "Erase機能は、シリアルコンソール経由でのみ利用可能です。",
|
||||
"repeater_commandSent": "送信されたコマンド: {command}",
|
||||
"@repeater_commandSent": {
|
||||
@@ -1245,6 +1262,81 @@
|
||||
},
|
||||
"repeater_confirm": "確認",
|
||||
"repeater_settingsSaved": "設定が正常に保存されました",
|
||||
"repeater_rxGain": "RX ゲインの向上",
|
||||
"repeater_rxGainHelper": "より高い感度、より大きな電流(SX1262/SX1268のみ)",
|
||||
"repeater_refreshRxGain": "強化されたRX効果を再確認",
|
||||
"repeater_multiAcks": "複数のACK(応答)",
|
||||
"repeater_multiAcksSubtitle": "複数の経路でメッセージを送信することで、より確実な配信を実現する。",
|
||||
"repeater_refreshMultiAcks": "複数のACKをリフレッシュする",
|
||||
"repeater_networkHealth": "ネットワークの状態",
|
||||
"repeater_loopDetect": "ループ検出",
|
||||
"repeater_loopDetectHelper": "ルーティングループを検知する",
|
||||
"repeater_loopDetectOff": "オフ",
|
||||
"repeater_loopDetectMinimal": "最小限の",
|
||||
"repeater_loopDetectModerate": "適度な",
|
||||
"repeater_loopDetectStrict": "厳格な",
|
||||
"repeater_dutyCycle": "動作サイクル",
|
||||
"repeater_dutyCycleHelper": "最大の使用時間割合",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "事業者の情報",
|
||||
"repeater_ownerInfoHelper": "このリピータに関する公開メタデータ",
|
||||
"repeater_refreshOwnerInfo": "オペレーター情報の更新",
|
||||
"repeater_floodMax": "最大ホップ数",
|
||||
"repeater_floodMaxHelper": "フラッドパケットが移動できる最大ホップ数 (0-64)",
|
||||
"repeater_advancedSettings": "高度な",
|
||||
"repeater_advancedSettingsSubtitle": "経験豊富なオペレーター向けの調整ノブ",
|
||||
"repeater_pathHashMode": "パスハッシュモード",
|
||||
"repeater_pathHashModeHelper": "このリピータのIDをフローパス/ループ検出タグにエンコードするために使用されるバイト数。 0=1バイト (256個のID、最大64ホップ)、1=2バイト (65,000個のID、最大32ホップ)、2=3バイト (160万個のID、最大21ホップ)。 v1.13およびそれ以前のファームウェアでは、マルチバイトパスがサポートされていません。 v1.14以降のバージョンでは、一度ネットワークが起動されると、パスが一度だけ検出されます。",
|
||||
"repeater_txDelay": "フロイド・TXでの遅延",
|
||||
"repeater_txDelayHelper": "フラッド時の交通量に対応するための再送信間隔を、パケットの通信時間を掛けた値(0~2、デフォルト0.5)で設定します。値を大きくすると衝突が減りますが、通信速度が遅くなります。",
|
||||
"repeater_directTxDelay": "直接的なTX遅延",
|
||||
"repeater_directTxDelayHelper": "直接(フラッドではない)トラフィックに対する再送信間隔を、パケットの空中時間(0~2、デフォルト0.3)の倍数として設定する。",
|
||||
"repeater_intThresh": "干渉閾値",
|
||||
"repeater_intThreshHelper": "ラジオのノイズレベルを基準とする閾値を設定し、このレベルを超えるノイズを抑制します。 0 を設定すると、ノイズの多い帯域で RX エラーが発生した場合のみ、この値を上げることができます。",
|
||||
"repeater_agcResetInterval": "AGCのリセット間隔",
|
||||
"repeater_agcResetIntervalHelper": "ラジオの自動ゲイン制御をリセットする頻度について:ゲインが固定状態になった場合に、回復するために、何度リセットするかを設定します。4の倍数でリセットする場合、0を設定すると、定期的なリセットは停止します。",
|
||||
"repeater_actionsTitle": "行動",
|
||||
"repeater_sendAdvert": "フラッドに関する広告を送信",
|
||||
"repeater_sendAdvertSubtitle": "ネットワークを通じて、フラッドに関する広告を放送する",
|
||||
"repeater_sendAdvertZeroHop": "ゼロホップ形式の広告を送信する",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "ワンホップでの広告放送(リピータなし)",
|
||||
"repeater_clockSync": "現在、時刻を同期する",
|
||||
"repeater_clockSyncSubtitle": "スマートフォンの時刻をルーターに設定する",
|
||||
"repeater_actionSucceeded": "{action} が成功しました",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} の実行に失敗しました: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "設定を保存しました — リピータを再起動して適用してください",
|
||||
"repeater_settingsPartialFailure": "設定の一部でエラーが発生しました:{failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "設定の保存に失敗しました:{error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1256,11 +1348,9 @@
|
||||
"repeater_refreshBasicSettings": "基本設定をリセットする",
|
||||
"repeater_refreshRadioSettings": "ラジオ設定をリセットする",
|
||||
"repeater_refreshTxPower": "TX の電力レベルをリセットする",
|
||||
"repeater_refreshLocationSettings": "場所設定をリセットする",
|
||||
"repeater_refreshPacketForwarding": "パケット転送の刷新",
|
||||
"repeater_refreshGuestAccess": "ゲストへのアクセスをリフレッシュする",
|
||||
"repeater_refreshPrivacyMode": "プライバシーモードをリセットする",
|
||||
"repeater_refreshAdvertisementSettings": "広告設定のリセット",
|
||||
"repeater_refreshed": "{label} が更新されました",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1277,7 +1367,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_cliTitle": "リピーターのコマンドラインインターフェース",
|
||||
"repeater_cliTitle": "リピータのコマンドラインインターフェース",
|
||||
"repeater_debugNextCommand": "次のコマンドのデバッグ",
|
||||
"repeater_commandHelp": "コマンドヘルプ",
|
||||
"repeater_clearHistory": "明確な歴史",
|
||||
@@ -1311,14 +1401,14 @@
|
||||
"repeater_cliHelpClearStats": "さまざまな統計カウンターをゼロにリセットする。",
|
||||
"repeater_cliHelpSetAf": "空き時間係数を設定します。",
|
||||
"repeater_cliHelpSetTx": "LoRaの送信電力をdBmで設定します。(設定変更後、再起動が必要です)",
|
||||
"repeater_cliHelpSetRepeat": "このノードに対するリピーターの役割を有効化または無効化します。",
|
||||
"repeater_cliHelpSetRepeat": "このノードに対するリピータの役割を有効化または無効化します。",
|
||||
"repeater_cliHelpSetAllowReadOnly": "(ルームサーバー設定)「オン」に設定した場合、空白のパスワードでのログインは可能ですが、ルームへの投稿はできません。(閲覧のみ)",
|
||||
"repeater_cliHelpSetFloodMax": "インバウンドフラッパケットの最大ホップ数を設定します(最大値を超えた場合、パケットは転送されません)。",
|
||||
"repeater_cliHelpSetFloodMax": "インバウンドフラッドパケットの最大ホップ数を設定します(最大値を超えた場合、パケットは転送されません)。",
|
||||
"repeater_cliHelpSetIntThresh": "干渉閾値を設定します(dB単位)。デフォルト値は14です。0に設定すると、チャンネル間の干渉を検出する機能を無効にします。",
|
||||
"repeater_cliHelpSetAgcResetInterval": "オートゲインコントローラーのリセット間隔を設定します。 0 に設定すると無効化されます。",
|
||||
"repeater_cliHelpSetMultiAcks": "「ダブルACK」機能の有効化または無効化を可能にします。",
|
||||
"repeater_cliHelpSetAdvertInterval": "ローカル(ホップなし)の広告パケットを送信する間隔を分単位で設定します。 0 に設定すると、機能を無効にします。",
|
||||
"repeater_cliHelpSetFloodAdvertInterval": "洪水広告の送信間隔を時間単位で設定します。0に設定すると、送信を停止します。",
|
||||
"repeater_cliHelpSetFloodAdvertInterval": "フラッド広告の送信間隔を時間単位で設定します。0に設定すると、送信を停止します。",
|
||||
"repeater_cliHelpSetGuestPassword": "ゲストのパスワードを設定/更新します。(繰り返し利用の場合、ゲストのログインは「統計情報を取得」のリクエストを送信できます)",
|
||||
"repeater_cliHelpSetName": "広告の名前を設定します。",
|
||||
"repeater_cliHelpSetLat": "広告表示の地図の緯度を設定します。(度分秒表記)",
|
||||
@@ -1339,14 +1429,14 @@
|
||||
"repeater_cliHelpLogStart": "パケットのログ記録を開始し、ファイルシステムに保存する。",
|
||||
"repeater_cliHelpLogStop": "ファイルシステムへのパケットログの記録を停止する。",
|
||||
"repeater_cliHelpLogErase": "ファイルシステムからパケットログを削除する。",
|
||||
"repeater_cliHelpNeighbors": "ゼロホップ広告を通じて受信した他のリピーターノードの一覧を表示します。各行は、IDプレフィックス(16進数)、タイムスタンプ、SNR(シグナル強度)の情報を4つ含みます。",
|
||||
"repeater_cliHelpNeighbors": "ゼロホップ広告を通じて受信した他のリピータノードの一覧を表示します。各行は、IDプレフィックス(16進数)、タイムスタンプ、SNR(シグナル強度)の情報を4つ含みます。",
|
||||
"repeater_cliHelpNeighborRemove": "隣接リストから、最初に一致するエントリ(pubkeyプレフィックス(16進数)で特定)を削除します。",
|
||||
"repeater_cliHelpRegion": "(特定のシリーズのみ)定義されたすべての地域と、現在の洪水許可状況を一覧表示します。",
|
||||
"repeater_cliHelpRegion": "(特定のシリーズのみ)定義されたすべての地域と、現在のフラッド許可状況を一覧表示します。",
|
||||
"repeater_cliHelpRegionLoad": "注:これは特殊な複数コマンドの呼び出しです。その後の各コマンドは、地域名であり(スペースを使用して親階層を示し、少なくとも1つのスペースが必要です)、空行/コマンドで終了します。",
|
||||
"repeater_cliHelpRegionGet": "指定された名前のプレフィックスを持つ地域を検索します(または、グローバルな範囲の場合は「*」)。結果として、「region-name (parent-name) 'F'」と返答します。",
|
||||
"repeater_cliHelpRegionPut": "指定された名前で、領域の定義を追加または更新します。",
|
||||
"repeater_cliHelpRegionRemove": "指定された名前を持つ領域の定義を削除します。(正確に一致している必要があり、子領域は存在してはなりません)",
|
||||
"repeater_cliHelpRegionAllowf": "指定された領域に対して、「洪水」アクセス許可を設定します。 (グローバル/従来のスコープには「*」を使用)",
|
||||
"repeater_cliHelpRegionAllowf": "指定された領域に対して、「フラッド」アクセス許可を設定します。 (グローバル/従来のスコープには「*」を使用)",
|
||||
"repeater_cliHelpRegionDenyf": "指定された領域における「FLOOD」権限を削除します。(注:現時点では、グローバル/従来の範囲での使用は推奨されません!)",
|
||||
"repeater_cliHelpRegionHome": "現在の「ホーム」地域に返信します。(まだ適用されていない、将来利用を予定)",
|
||||
"repeater_cliHelpRegionHomeSet": "「ホーム」地域を設定します。",
|
||||
@@ -1363,7 +1453,7 @@
|
||||
"repeater_settingsCategory": "設定",
|
||||
"repeater_bridge": "橋",
|
||||
"repeater_logging": "ログ記録",
|
||||
"repeater_neighborsRepeaterOnly": "近隣住民(リピーターのみ)",
|
||||
"repeater_neighborsRepeaterOnly": "近隣住民(リピータのみ)",
|
||||
"repeater_regionManagementRepeaterOnly": "地域管理(ブロードキャスト用のみ)",
|
||||
"repeater_regionNote": "地域レベルでの管理のため、地域定義と権限の管理を行うための機能が導入されました。",
|
||||
"repeater_gpsManagement": "GPS管理",
|
||||
@@ -1378,6 +1468,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "デジタル入力",
|
||||
"telemetry_digitalOutputLabel": "デジタル出力",
|
||||
"telemetry_analogInputLabel": "アナログ入力",
|
||||
"telemetry_analogOutputLabel": "アナログ出力",
|
||||
"telemetry_genericLabel": "汎用センサー",
|
||||
"telemetry_luminosityLabel": "照度",
|
||||
"telemetry_presenceLabel": "在室",
|
||||
"telemetry_humidityLabel": "湿度",
|
||||
"telemetry_accelerometerLabel": "加速度計",
|
||||
"telemetry_pressureLabel": "気圧",
|
||||
"telemetry_altitudeLabel": "高度",
|
||||
"telemetry_frequencyLabel": "周波数",
|
||||
"telemetry_percentageLabel": "パーセント",
|
||||
"telemetry_concentrationLabel": "濃度",
|
||||
"telemetry_powerLabel": "電力",
|
||||
"telemetry_distanceLabel": "距離",
|
||||
"telemetry_energyLabel": "エネルギー",
|
||||
"telemetry_directionLabel": "方向",
|
||||
"telemetry_timeLabel": "時刻",
|
||||
"telemetry_gyrometerLabel": "ジャイロメーター",
|
||||
"telemetry_colourLabel": "色",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "スイッチ",
|
||||
"telemetry_polylineLabel": "ポリライン",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "リクエスト数",
|
||||
"telemetry_error": "データを取得できません",
|
||||
"telemetry_noData": "テレメトリデータは利用できません。",
|
||||
"telemetry_channelTitle": "チャンネル {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1440,7 +1567,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"neighbors_repeatersNeighbors": "繰り返し送信する、近隣",
|
||||
"neighbors_repeatersNeighbors": "近隣のリピータ",
|
||||
"neighbors_noData": "近隣のデータは利用できません。",
|
||||
"neighbors_unknownContact": "不明な {pubkey}",
|
||||
"@neighbors_unknownContact": {
|
||||
@@ -1461,12 +1588,12 @@
|
||||
"channelPath_title": "パケットパス",
|
||||
"channelPath_viewMap": "地図を表示する",
|
||||
"channelPath_otherObservedPaths": "観察されたその他の経路",
|
||||
"channelPath_repeaterHops": "ホップの繰り返し",
|
||||
"channelPath_repeaterHops": "リピータホップ",
|
||||
"channelPath_noHopDetails": "このパッケージに関する詳細な情報は提供されていません。",
|
||||
"channelPath_messageDetails": "メッセージの詳細",
|
||||
"channelPath_senderLabel": "送信者",
|
||||
"channelPath_timeLabel": "時間",
|
||||
"channelPath_repeatsLabel": "繰り返し",
|
||||
"channelPath_repeatsLabel": "リピータ",
|
||||
"channelPath_pathLabel": "{index} 番目の経路",
|
||||
"channelPath_observedLabel": "観察",
|
||||
"channelPath_observedPathTitle": "観察された経路 {index} • {hops}",
|
||||
@@ -1504,7 +1631,7 @@
|
||||
}
|
||||
},
|
||||
"channelPath_unknownPath": "不明",
|
||||
"channelPath_floodPath": "洪水",
|
||||
"channelPath_floodPath": "フラッド",
|
||||
"channelPath_directPath": "直接",
|
||||
"channelPath_observedZeroOf": "{total}個のホップ",
|
||||
"@channelPath_observedZeroOf": {
|
||||
@@ -1526,7 +1653,7 @@
|
||||
}
|
||||
},
|
||||
"channelPath_mapTitle": "経路図",
|
||||
"channelPath_noRepeaterLocations": "この経路には、中継装置の設置場所がありません。",
|
||||
"channelPath_noRepeaterLocations": "この経路にリピータの位置情報はありません。",
|
||||
"channelPath_primaryPath": "{index}番目の経路(主要経路)",
|
||||
"@channelPath_primaryPath": {
|
||||
"placeholders": {
|
||||
@@ -1704,7 +1831,7 @@
|
||||
"listFilter_addToFavorites": "お気に入りに追加",
|
||||
"listFilter_removeFromFavorites": "お気に入りから削除",
|
||||
"listFilter_users": "利用者",
|
||||
"listFilter_repeaters": "繰り返し送信装置",
|
||||
"listFilter_repeaters": "リピータ",
|
||||
"listFilter_roomServers": "ルーム用サーバー",
|
||||
"listFilter_unreadOnly": "未読のみ",
|
||||
"listFilter_newGroup": "新しいグループ",
|
||||
@@ -1849,8 +1976,8 @@
|
||||
},
|
||||
"contacts_pathTrace": "経路追跡",
|
||||
"contacts_ping": "パング",
|
||||
"contacts_repeaterPathTrace": "リピーターまでの経路を追跡する",
|
||||
"contacts_repeaterPing": "PING 繰り返し",
|
||||
"contacts_repeaterPathTrace": "リピータまでの経路を追跡する",
|
||||
"contacts_repeaterPing": "リピータにPING",
|
||||
"contacts_roomPathTrace": "部屋のサーバーへの経路を追跡する",
|
||||
"contacts_roomPing": "ピンルーム用サーバー",
|
||||
"contacts_chatTraceRoute": "経路の追跡ルート",
|
||||
@@ -1867,7 +1994,7 @@
|
||||
"contacts_contactImported": "連絡先が登録されました。",
|
||||
"contacts_contactImportFailed": "連絡先のインポートに失敗しました。",
|
||||
"contacts_zeroHopAdvert": "ゼロホップ広告",
|
||||
"contacts_floodAdvert": "洪水に関する広告",
|
||||
"contacts_floodAdvert": "フラッドに関する広告",
|
||||
"contacts_copyAdvertToClipboard": "広告をクリップボードにコピー",
|
||||
"contacts_addContactFromClipboard": "クリップボードから連絡先を追加する",
|
||||
"contacts_ShareContact": "連絡先をクリップボードにコピー",
|
||||
@@ -1910,7 +2037,7 @@
|
||||
}
|
||||
},
|
||||
"notification_receivedNewMessage": "新しいメッセージを受信",
|
||||
"settings_gpxExportRepeaters": "GPX へのエクスポート用リピーター/ルームサーバー",
|
||||
"settings_gpxExportRepeaters": "GPX へのエクスポート用リピータ/ルームサーバー",
|
||||
"settings_gpxExportRepeatersSubtitle": "GPXファイルに場所情報を付加した、レピーター/ルームサーバーのエクスポート",
|
||||
"settings_gpxExportContacts": "GPX 形式へのエクスポート",
|
||||
"settings_gpxExportContactsSubtitle": "GPXファイルに位置情報を保存して、他の人と共有する。",
|
||||
@@ -1920,20 +2047,20 @@
|
||||
"settings_gpxExportNoContacts": "エクスポートする連絡先は存在しません。",
|
||||
"settings_gpxExportNotAvailable": "このデバイス/OSではサポートされていません",
|
||||
"settings_gpxExportError": "エクスポート時にエラーが発生しました。",
|
||||
"settings_gpxExportRepeatersRoom": "中継装置およびルームサーバーの設置場所",
|
||||
"settings_gpxExportRepeatersRoom": "リピータ/ルームサーバーの位置情報",
|
||||
"settings_gpxExportChat": "関連施設",
|
||||
"settings_gpxExportAllContacts": "すべての連絡先場所",
|
||||
"settings_gpxExportShareText": "meshcore-openからエクスポートされた地図データ",
|
||||
"settings_gpxExportShareSubject": "meshcore-open GPX形式の地図データのエクスポート",
|
||||
"snrIndicator_nearByRepeaters": "近くの電波中継局",
|
||||
"snrIndicator_nearByRepeaters": "近くのリピータ",
|
||||
"snrIndicator_lastSeen": "最後に確認された場所",
|
||||
"contactsSettings_title": "連絡先設定",
|
||||
"contactsSettings_autoAddTitle": "自動検出",
|
||||
"contactsSettings_otherTitle": "その他の連絡に関する設定",
|
||||
"contactsSettings_autoAddUsersTitle": "自動でユーザーを追加する",
|
||||
"contactsSettings_autoAddUsersSubtitle": "利用者が自動的に発見したユーザーを追加できるようにする。",
|
||||
"contactsSettings_autoAddRepeatersTitle": "自動で繰り返し設定",
|
||||
"contactsSettings_autoAddRepeatersSubtitle": "発見した中継局を、自動的に追加できるようにする。",
|
||||
"contactsSettings_autoAddRepeatersTitle": "リピータを自動追加",
|
||||
"contactsSettings_autoAddRepeatersSubtitle": "発見したリピータを、自動的に追加できるようにする。",
|
||||
"contactsSettings_autoAddRoomServersTitle": "自動でルームサーバーを追加",
|
||||
"contactsSettings_autoAddRoomServersSubtitle": "利用者が、発見した部屋のサーバーを自動的に追加できるようにする。",
|
||||
"contactsSettings_autoAddSensorsTitle": "自動でセンサーを追加",
|
||||
@@ -2035,7 +2162,7 @@
|
||||
"contact_teleLocSubtitle": "位置情報共有を許可する",
|
||||
"contact_teleEnv": "テレメトリ環境",
|
||||
"contact_teleEnvSubtitle": "環境センサーのデータを共有することを許可する",
|
||||
"map_showOverlaps": "リピーターキーの重複",
|
||||
"map_showOverlaps": "リピータキーの重複",
|
||||
"map_runTraceWithReturnPath": "元の経路に戻る。",
|
||||
"@translation_downloadFailed": {
|
||||
"placeholders": {
|
||||
@@ -2049,6 +2176,9 @@
|
||||
"translation_composerTitle": "送信する前に翻訳する",
|
||||
"translation_enableTitle": "翻訳機能を有効にする",
|
||||
"translation_composerSubtitle": "作曲家翻訳アイコンのデフォルト状態を制御する。",
|
||||
"translation_autoIncomingTitle": "メッセージを自動翻訳",
|
||||
"translation_autoIncomingSubtitle": "通知やチャット、チャンネルのメッセージを自動的に翻訳します。",
|
||||
"translation_translateMessage": "メッセージを翻訳",
|
||||
"translation_targetLanguage": "翻訳対象言語",
|
||||
"translation_useAppLanguage": "アプリの言語設定",
|
||||
"translation_downloadedModelLabel": "ダウンロードしたモデル",
|
||||
@@ -2102,7 +2232,257 @@
|
||||
"repeater_clockSyncAfterLoginSubtitle": "ログインが成功した場合、自動的に「時刻同期」を送信する。",
|
||||
"room_guest": "ルームサーバーに関する情報",
|
||||
"chat_sendMessage": "メッセージを送信する",
|
||||
"repeater_guest": "繰り返し送信に関する情報",
|
||||
"repeater_guest": "リピータに関する情報",
|
||||
"repeater_guestTools": "ゲスト向けツール",
|
||||
"settings_multiAck": "複数のACK(応答)"
|
||||
"repeater_getCategory": "価値を取得する",
|
||||
"repeater_powerMgmt": "電力管理",
|
||||
"repeater_sensors": "センサー",
|
||||
"repeater_cliHelpPowerOff": "デバイスをシャットダウンします。(応答は期待されていません)",
|
||||
"repeater_cliHelpClkReboot": "時計を既知の基準時点にリセットし、デバイスを再起動します。",
|
||||
"repeater_cliHelpAdvertZeroHop": "近隣のデバイスのみに、ゼロホップの広告を送信します。",
|
||||
"repeater_cliHelpStartOta": "サポートされているボードに対して、無線でファームウェアのアップデートを開始します。",
|
||||
"repeater_cliHelpTime": "デバイスのクロックを、指定されたUnixエポックの秒数に設定します。クロックは逆方向に進むことはできません。",
|
||||
"repeater_cliHelpBoard": "製造元の名前/ハードウェア識別子を表示します。",
|
||||
"repeater_cliHelpDiscoverNeighbors": "近隣のノードに対して、ノードの探索リクエストを送信します。(リピータ機能のみ)",
|
||||
"repeater_cliHelpPowersaving": "省電力モードがオンになっているかどうかを表示します。",
|
||||
"repeater_cliHelpPowersavingOnOff": "省電力モード(対応している場合)を有効または無効にします。",
|
||||
"repeater_cliHelpErase": "(シリアルモードのみ)デバイスのファイルシステムをフォーマットします。すべての設定と連絡先を消去します。",
|
||||
"repeater_cliHelpSetDutyCycle": "送信可能な最大デューティサイクルをパーセントで設定します(1〜100)。内部で、空き時間の要素を調整します。",
|
||||
"repeater_cliHelpSetPrvKey": "(シリアル番号のみ)デバイスのプライベートキーを置き換えます。適用には再起動が必要です。新しいパブリックキーを生成します。",
|
||||
"repeater_cliHelpSetRadioRxGain": "(SX126xのみ)高電流での使用時に、感度を向上させるために、増幅されたRXのゲインを切り替えることができます。",
|
||||
"repeater_cliHelpSetOwnerInfo": "広告に記載されている所有者連絡先情報を設定します。改行には'|'を使用してください。",
|
||||
"repeater_cliHelpSetPathHashMode": "パスハッシュモードを設定します。 0 = 従来のモード、1 = 標準モード、2 = 厳格モード。ルーティングパスのマッチング方法に影響します。",
|
||||
"repeater_cliHelpSetLoopDetect": "ルーティングループ検出の感度を設定します:オフ、最小、中程度、または厳格。",
|
||||
"repeater_cliHelpSetFreq": "(シリアル設定のみ)特定の周波数のみを素早く設定できます。再起動が必要です。「ラジオ設定」を使用すると、ラジオのすべてのパラメータを設定できます。",
|
||||
"repeater_cliHelpSetBridgeChannel": "(ESPNowブリッジのみ)ブリッジで使用するWi-Fiチャンネル(1~14)を設定します。",
|
||||
"repeater_cliHelpGetName": "設定されたノードの名前を表示します。",
|
||||
"repeater_cliHelpGetRole": "ファームウェアの役割(リピータ、ルームサーバーなど)を表示します。",
|
||||
"repeater_cliHelpGetPublicKey": "デバイスの公開鍵を表示します。",
|
||||
"repeater_cliHelpGetPrvKey": "(シリアル番号のみ)デバイスのプライベートキーを表示します。機密情報として扱ってください。",
|
||||
"repeater_cliHelpGetRepeat": "パケット転送(リピータ機能)が有効になっているかどうかを表示します。",
|
||||
"repeater_cliHelpGetTx": "現在のTX(送信)電力のdBm値を表示します。",
|
||||
"repeater_cliHelpGetFreq": "設定された無線周波数をMHzで表示します。",
|
||||
"repeater_cliHelpGetRadio": "以下のすべての無線パラメータを表示: 周波数、帯域幅、スプレッドファクター、符号化レート。",
|
||||
"repeater_cliHelpGetRadioRxGain": "(SX126xのみ) RX の増幅ゲインの状態を表示します。",
|
||||
"repeater_cliHelpGetAf": "現在の空き時間係数を表示します。",
|
||||
"repeater_cliHelpGetDutyCycle": "現在の許可されたデューティサイクルをパーセントで表示します。",
|
||||
"repeater_cliHelpGetIntThresh": "チャンネル干渉の閾値をdBで表示します。",
|
||||
"repeater_cliHelpGetAgcResetInterval": "AGCのリセット間隔を秒単位で表示します。",
|
||||
"repeater_cliHelpGetMultiAcks": "ダブルACKモードが有効 (1) か無効 (0) かを示す。",
|
||||
"repeater_cliHelpGetAllowReadOnly": "ゲストによる読み取り専用アクセスが許可されているかどうかを示す。",
|
||||
"repeater_cliHelpGetAdvertInterval": "ローカル広告の時間を分単位で表示します。",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "フラッドに関する広告の放送時間を時間単位で表示します。",
|
||||
"repeater_cliHelpGetGuestPassword": "設定されたゲストパスワードを表示します。",
|
||||
"repeater_cliHelpGetLat": "設定された緯度を表示します。",
|
||||
"repeater_cliHelpGetLon": "設定された経度を表示します。",
|
||||
"repeater_cliHelpGetRxDelay": "rxdelay の基本値を表示します。",
|
||||
"repeater_cliHelpGetTxDelay": "フラッドモードにおける送信遅延の要因を示します。",
|
||||
"repeater_cliHelpGetDirectTxDelay": "ダイレクトモードの遅延要素を示します。",
|
||||
"repeater_cliHelpGetFloodMax": "フラッドパケットの最大ホップ数を表示します。",
|
||||
"repeater_cliHelpGetOwnerInfo": "所有者の連絡先情報を表示します。",
|
||||
"repeater_cliHelpGetPathHashMode": "パスハッシュモード(0/1/2)を表示します。",
|
||||
"repeater_cliHelpGetLoopDetect": "ループ検出の感度を示す。",
|
||||
"repeater_cliHelpGetAcl": "(シリアルのみ)リピータ上のアクセス制御設定を一覧表示します。",
|
||||
"repeater_cliHelpGetBridgeEnabled": "橋が有効になっているかどうかを表示します。",
|
||||
"repeater_cliHelpGetBridgeDelay": "橋の遅延時間をミリ秒(ms)で表示します。",
|
||||
"repeater_cliHelpGetBridgeSource": "RX または TX パケットを橋渡ししているかどうかを示す。",
|
||||
"repeater_cliHelpGetBridgeBaud": "(RS232 橋渡し機能のみ)橋渡しのボーレートを表示します。",
|
||||
"repeater_cliHelpGetBridgeChannel": "(ESPNowブリッジのみ)ブリッジで使用しているWi-Fiチャンネルを表示します。",
|
||||
"repeater_cliHelpGetBridgeSecret": "(ESPNowブリッジのみ)ブリッジで共有されている秘密鍵を表示します。",
|
||||
"repeater_cliHelpGetBootloaderVer": "(NRF52のみ)ブートローダーのバージョンを表示します。",
|
||||
"repeater_cliHelpGetAdcMultiplier": "ADC(アナログ-デジタル変換)のマルチプライヤー(バッテリー電圧のスケーリング)を表示します。",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "取締役会が電力管理機能をサポートしているかどうかを報告します。",
|
||||
"repeater_cliHelpGetPwrMgtSource": "現在の電源(外部電源またはバッテリー)を表示します。",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "最新のリセットおよびシャットダウンの理由を表示します。",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "起動時のバッテリー電圧をmVで表示します。",
|
||||
"repeater_cliHelpSensorGet": "キーを使用して、カスタムセンサーの設定を読み取る。",
|
||||
"repeater_cliHelpSensorSet": "カスタムセンサーの設定を作成する。",
|
||||
"repeater_cliHelpSensorList": "カスタムセンサーの設定をすべてリスト表示し、オプションで指定できる開始インデックスからページ分割して表示します。",
|
||||
"repeater_cliHelpRegionDefault": "現在のデフォルトの地域範囲を表示します。",
|
||||
"repeater_cliHelpRegionDefaultSet": "デフォルトの地域範囲を設定します。「<null>」を使用すると、設定をリセットできます。",
|
||||
"repeater_cliHelpRegionListAllowed": "フラッド時の通行が許可されている地域の一覧",
|
||||
"repeater_cliHelpRegionListDenied": "フラッドによる交通を遮断している地域の一覧",
|
||||
"repeater_cliHelpStatsPackets": "(シリアルのみ)パケットレベルの統計情報を表示します。",
|
||||
"repeater_cliHelpStatsRadio": "(シリーズのみ)ラジオの統計情報を表示します。",
|
||||
"repeater_cliHelpStatsCore": "(シリアルのみ)主要なファームウェアの統計情報を表示します。",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "複数のACK(応答)",
|
||||
"map_sharedAt": "共有済み",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "地図上で、特定された場所を強調するために、該当する場所をタップしてください。",
|
||||
"losSelectedObstructionTitle": "選択された障害",
|
||||
"losBlockedSpotsTitle": "利用できない場所",
|
||||
"losSelectedObstructionDetails": "{obstruction} によって {heightUnit} の高さで、A地点から {distanceFromA}、B地点から {distanceFromB} ({distanceUnit}) の距離で塞がれています。",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 関連のコマンド、応答、および生のデータ",
|
||||
"settings_companionDebugLog": "同伴デバッグログ",
|
||||
"chat_newMessages": "新しいメッセージ",
|
||||
"chat_markAsUnread": "未読としてマークする",
|
||||
"repeater_chanUtil": "チャンネルの利用状況",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_delivered": "配達",
|
||||
"common_undo": "元に戻す",
|
||||
"messageStatus_pending": "送信",
|
||||
"messageStatus_sent": "送信",
|
||||
"messageStatus_failed": "送信できませんでした",
|
||||
"contacts_moreOptions": "さらに多くの選択肢",
|
||||
"messageStatus_repeated": "何度も聞いた",
|
||||
"contacts_searchOpen": "連絡先を検索する",
|
||||
"contacts_searchClose": "検索を終了",
|
||||
"routing_modeFlood": "洪水",
|
||||
"routing_title": "経路設定",
|
||||
"routing_modeAuto": "自動車",
|
||||
"routing_modeManual": "マニュアル",
|
||||
"routing_modeAutoHint": "最も一般的な経路を自動的に選択し、経路が不明な場合は、水没状態にします。",
|
||||
"routing_modeFloodHint": "すべてのリピーターを通じて放送。最も信頼性が高いですが、より多くの時間を使用します。",
|
||||
"routing_modeManualHint": "常に、あなたが設定した正確な経路を辿って移動します。",
|
||||
"routing_currentRoute": "現在までのルート",
|
||||
"routing_directNoHops": "直接接続—中継装置を経由しない",
|
||||
"routing_noPathYet": "まだ経路は確立されていません。「次のメッセージを送信し、経路が特定されるまで待ちます」。",
|
||||
"routing_floodBroadcast": "すべてのリピーターを通じて放送",
|
||||
"routing_editPath": "パスの編集",
|
||||
"routing_forgetPath": "道にこだわらない",
|
||||
"routing_knownPaths": "既知の経路",
|
||||
"routing_knownPathsHint": "そのアプリケーションに切り替えるためのショートカットを作成します。",
|
||||
"routing_inUse": "使用中",
|
||||
"routing_qualityStrong": "最初の段階で大きな成果を上げる",
|
||||
"routing_qualityGood": "最初の成功",
|
||||
"routing_qualityFair": "最初の試みは成功を収めた",
|
||||
"routing_qualityWorked": "完了しました",
|
||||
"routing_qualityFlood": "氾濫によって伝聞",
|
||||
"routing_qualityUntested": "未検証",
|
||||
"routing_lastWorked": "{when}に勤務",
|
||||
"routing_neverWorked": "確認されていない",
|
||||
"routing_floodDelivery": "洪水による配送",
|
||||
"pathEditor_title": "経路の作成",
|
||||
"pathEditor_hopCounter": "64個のホップのうち、{count}個",
|
||||
"pathEditor_noHops": "まだホップは追加されていません。ホップを順番に追加するには、以下の「タップ」ボタンをクリックしてください。または、ホップを一切追加せずに直接送信するには、「保存」ボタンをクリックしてください。",
|
||||
"pathEditor_addHops": "ホップを、指定された順番に加える",
|
||||
"pathEditor_searchRepeaters": "繰り返し検索",
|
||||
"pathEditor_advancedHex": "高度なレベル:生のヘックスパス",
|
||||
"pathEditor_hexLabel": "ヘックスプレフィックス",
|
||||
"pathEditor_hexHelper": "各ホップごとに2つのハッシュ文字を、カンマで区切って記述",
|
||||
"pathEditor_invalidTokens": "無効: {tokens}",
|
||||
"pathEditor_tooManyHops": "最大64段階",
|
||||
"pathEditor_usePath": "この経路を使用してください",
|
||||
"pathEditor_removeHop": "ホップを取り除く",
|
||||
"pathEditor_unknownHop": "不明な増幅器",
|
||||
"map_zoomIn": "ズームイン",
|
||||
"map_zoomOut": "ズームアウト",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_centerMap": "中心地図",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth は、Chromium ブラウザが必要です。",
|
||||
"channels_communityShortId": "ID: {id}…",
|
||||
"pathTrace_legendGpsConfirmed": "GPSによる確認",
|
||||
"pathTrace_legendInferred": "推測される位置"
|
||||
}
|
||||
|
||||
+386
-6
@@ -27,6 +27,8 @@
|
||||
"common_remove": "제거",
|
||||
"common_enable": "활성화",
|
||||
"common_disable": "비활성화",
|
||||
"common_autoRefresh": "자동 새로고침",
|
||||
"common_interval": "간격",
|
||||
"common_reboot": "재부팅",
|
||||
"common_loading": "로딩 중...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -167,6 +169,8 @@
|
||||
"settings_privacyModeEnabled": "개인 정보 보호 모드 활성화",
|
||||
"settings_privacyModeDisabled": "개인 정보 보호 모드 비활성화",
|
||||
"settings_actions": "행동",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "광고 전송",
|
||||
"settings_sendAdvertisementSubtitle": "방송 활동",
|
||||
"settings_advertisementSent": "광고 전송",
|
||||
@@ -489,11 +493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "해시태그 채널",
|
||||
"channels_public": "대중의",
|
||||
"channels_private": "사립",
|
||||
"channels_publicChannel": "공개 채널",
|
||||
"channels_privateChannel": "개인 채널",
|
||||
"channels_editChannel": "채널 편집",
|
||||
"channels_muteChannel": "음소거 채널",
|
||||
"channels_unmuteChannel": "채널 음소거 해제",
|
||||
@@ -548,6 +549,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ 압축",
|
||||
"channels_cyr2latCompression": "Cyr2Lat 압축",
|
||||
"channels_cyr2latCompressionDscr": "보낼 때 일부 키릴 문자를 라틴 문자로 바꿉니다.",
|
||||
"channels_cyr2latSettingsHeading": "Cyr2Lat 설정",
|
||||
"channels_cyr2latSettingsSubheading": "변환 목록",
|
||||
"channels_cyr2latSettingsDscr": "문자 변환 JSON 구성 편집",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON 변환 맵",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "잘못된 JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Cyr2Lat 프로필 추가",
|
||||
"settings_cyr2latProfileName": "프로필 이름",
|
||||
"settings_cyr2latProfileNameEmpty": "프로필 이름은 비워둘 수 없습니다",
|
||||
"settings_cyr2latProfileAdded": "프로필이 성공적으로 추가되었습니다",
|
||||
"settings_cyr2latProfileUpdated": "프로필이 성공적으로 업데이트되었습니다",
|
||||
"settings_cyr2latProfileEdit": "Cyr2Lat 프로필 편집",
|
||||
"settings_cyr2latProfileDelete": "Cyr2Lat 프로필 삭제",
|
||||
"settings_cyr2latProfileDeleted": "프로필이 성공적으로 삭제되었습니다",
|
||||
"settings_cyr2latProfileDeleteDscr": "\"{name}\" 프로필을 삭제하시겠습니까?",
|
||||
"channels_channelUpdated": "채널 \"{name}\"이 업데이트되었습니다.",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -1245,6 +1262,81 @@
|
||||
},
|
||||
"repeater_confirm": "확인",
|
||||
"repeater_settingsSaved": "설정이 성공적으로 저장되었습니다.",
|
||||
"repeater_rxGain": "향상된 RX 성능",
|
||||
"repeater_rxGainHelper": "더 높은 감도, 더 많은 전류 소모 (SX1262/SX1268에만 해당)",
|
||||
"repeater_refreshRxGain": "RX 성능 향상 효과 재확인",
|
||||
"repeater_multiAcks": "다중 ACK",
|
||||
"repeater_multiAcksSubtitle": "다양한 경로를 통해 메시지를 확인하여 전달 효율성을 높입니다.",
|
||||
"repeater_refreshMultiAcks": "다중 ACK 재확인",
|
||||
"repeater_networkHealth": "네트워크 상태",
|
||||
"repeater_loopDetect": "루프 감지",
|
||||
"repeater_loopDetectHelper": "라우팅 루프처럼 보이는 과도한 데이터 패킷을 전송",
|
||||
"repeater_loopDetectOff": "거기",
|
||||
"repeater_loopDetectMinimal": "최소",
|
||||
"repeater_loopDetectModerate": "적당한",
|
||||
"repeater_loopDetectStrict": "엄격한",
|
||||
"repeater_dutyCycle": "작동 주기",
|
||||
"repeater_dutyCycleHelper": "허용되는 최대 방송 시간 비율",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "운영자 정보",
|
||||
"repeater_ownerInfoHelper": "이 리피터에 대한 공개 메타데이터",
|
||||
"repeater_refreshOwnerInfo": "운영자 정보 업데이트",
|
||||
"repeater_floodMax": "최대 홉 수",
|
||||
"repeater_floodMaxHelper": "최대 패킷이 이동할 수 있는 홉 수 (0-64)",
|
||||
"repeater_advancedSettings": "고급",
|
||||
"repeater_advancedSettingsSubtitle": "숙련된 운영자를 위한 조절 노브",
|
||||
"repeater_pathHashMode": "패스 해시 모드",
|
||||
"repeater_pathHashModeHelper": "이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수: 0=1 바이트 (256개의 ID, 최대 64개의 홉), 1=2 바이트 (65,000개의 ID, 최대 32개의 홉), 2=3 바이트 (16백만 개의 ID, 최대 21개의 홉). v1.13 및 이전 버전의 펌웨어는 다중 바이트 경로를 지원하지 않으며, 네트워크가 v1.14 이상으로 업그레이드되면 한 번만 감지합니다.",
|
||||
"repeater_txDelay": "플러드 TX 지연",
|
||||
"repeater_txDelayHelper": "홍수 시 교통량에 맞춰 재전송 간격을 설정합니다. 이는 패킷의 전송 시간을 곱한 값 (0-2, 기본값 0.5)으로 설정합니다. 값이 클수록 충돌이 줄어들지만 전송 속도가 느려집니다.",
|
||||
"repeater_directTxDelay": "직접적인 TX 지연",
|
||||
"repeater_directTxDelayHelper": "직접 (대량 전송이 아닌) 트래픽에 대한 재전송 간격을, 패킷의 전송 시간을 곱하여 설정 (0-2, 기본값 0.3).",
|
||||
"repeater_intThresh": "간섭 허용치",
|
||||
"repeater_intThreshHelper": "신호의 잡음 수준을 기준으로 작동하며, 이 수준 이상의 간섭은 차단합니다. 0은 비활성화 상태를 의미하며, 잡음이 심한 대역에서 RX 오류가 발생할 경우에만 활성화해야 합니다.",
|
||||
"repeater_agcResetInterval": "AGC 재설정 간격",
|
||||
"repeater_agcResetIntervalHelper": "자동 게인 제어를 재설정하여 신호가 불안정해졌을 때 원래 상태로 복구하는 빈도를 설정하는 방법은 다음과 같습니다. 4의 배수 단위로 설정하면 주기적인 재설정이 수행됩니다. 0을 설정하면 주기적인 재설정이 수행되지 않습니다.",
|
||||
"repeater_actionsTitle": "행동",
|
||||
"repeater_sendAdvert": "홍수 관련 광고 전송",
|
||||
"repeater_sendAdvertSubtitle": "네트워크를 통해 홍수 광고를 방송",
|
||||
"repeater_sendAdvertZeroHop": "제로 홉 광고 전송",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "단일 중계 (중계 없이) 광고를 송출",
|
||||
"repeater_clockSync": "현재 시계 동기화",
|
||||
"repeater_clockSyncSubtitle": "스마트폰의 시간을 리피터로 설정",
|
||||
"repeater_actionSucceeded": "{action}이 성공적으로 완료되었습니다.",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} 실패: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "설정이 저장되었습니다. 다시 시작하여 설정을 적용하세요.",
|
||||
"repeater_settingsPartialFailure": "다음 설정에 실패했습니다: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "설정 저장 오류: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1256,11 +1348,9 @@
|
||||
"repeater_refreshBasicSettings": "기본 설정 초기화",
|
||||
"repeater_refreshRadioSettings": "라디오 설정 초기화",
|
||||
"repeater_refreshTxPower": "TX 전원 재설정",
|
||||
"repeater_refreshLocationSettings": "위치 설정 초기화",
|
||||
"repeater_refreshPacketForwarding": "패킷 전송 재시작",
|
||||
"repeater_refreshGuestAccess": "게스트 접근 권한 갱신",
|
||||
"repeater_refreshPrivacyMode": "개인 정보 보호 모드 재설정",
|
||||
"repeater_refreshAdvertisementSettings": "광고 설정 재설정",
|
||||
"repeater_refreshed": "{label}가 갱신됨",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1378,6 +1468,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "디지털 입력",
|
||||
"telemetry_digitalOutputLabel": "디지털 출력",
|
||||
"telemetry_analogInputLabel": "아날로그 입력",
|
||||
"telemetry_analogOutputLabel": "아날로그 출력",
|
||||
"telemetry_genericLabel": "일반 센서",
|
||||
"telemetry_luminosityLabel": "조도",
|
||||
"telemetry_presenceLabel": "존재 감지",
|
||||
"telemetry_humidityLabel": "습도",
|
||||
"telemetry_accelerometerLabel": "가속도계",
|
||||
"telemetry_pressureLabel": "압력",
|
||||
"telemetry_altitudeLabel": "고도",
|
||||
"telemetry_frequencyLabel": "주파수",
|
||||
"telemetry_percentageLabel": "백분율",
|
||||
"telemetry_concentrationLabel": "농도",
|
||||
"telemetry_powerLabel": "전력",
|
||||
"telemetry_distanceLabel": "거리",
|
||||
"telemetry_energyLabel": "에너지",
|
||||
"telemetry_directionLabel": "방향",
|
||||
"telemetry_timeLabel": "시간",
|
||||
"telemetry_gyrometerLabel": "자이로미터",
|
||||
"telemetry_colourLabel": "색상",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "스위치",
|
||||
"telemetry_polylineLabel": "폴리라인",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "요청 수",
|
||||
"telemetry_error": "데이터를 가져올 수 없습니다",
|
||||
"telemetry_noData": "텔레메트리 데이터는 제공되지 않습니다.",
|
||||
"telemetry_channelTitle": "채널 {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -2049,6 +2176,9 @@
|
||||
"translation_enableTitle": "번역 기능 활성화",
|
||||
"translation_composerTitle": "보내기 전에 번역",
|
||||
"translation_composerSubtitle": "컴포저 번역 아이콘의 기본 상태를 제어합니다.",
|
||||
"translation_autoIncomingTitle": "메시지 자동 번역",
|
||||
"translation_autoIncomingSubtitle": "알림과 채팅 또는 채널의 메시지를 자동으로 번역합니다.",
|
||||
"translation_translateMessage": "메시지 번역",
|
||||
"translation_targetLanguage": "목표 언어",
|
||||
"translation_useAppLanguage": "앱 언어 사용",
|
||||
"translation_downloadedModelLabel": "다운로드한 모델",
|
||||
@@ -2104,5 +2234,255 @@
|
||||
"chat_sendMessage": "메시지를 보내기",
|
||||
"repeater_guest": "반복 장비 정보",
|
||||
"room_guest": "서버 정보",
|
||||
"settings_multiAck": "다중 ACK"
|
||||
"repeater_getCategory": "가치 얻기",
|
||||
"repeater_powerMgmt": "전력 관리",
|
||||
"repeater_sensors": "센서",
|
||||
"repeater_cliHelpPowerOff": "장치를 끄는 기능 (응답이 없을 것으로 예상)",
|
||||
"repeater_cliHelpClkReboot": "시계를 알려진 시점으로 재설정하고 장치를 재부팅합니다.",
|
||||
"repeater_cliHelpAdvertZeroHop": "직접적인 연결 없이 이웃에게만 광고를 전송합니다.",
|
||||
"repeater_cliHelpStartOta": "지원되는 보드에서 무선으로 펌웨어 업데이트를 시작합니다.",
|
||||
"repeater_cliHelpTime": "장치를 주어진 유닉스 에포크 초부터 시간으로 설정합니다. 시간은 이전으로 이동할 수 없습니다.",
|
||||
"repeater_cliHelpBoard": "제조사/하드웨어 식별 정보를 표시합니다.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "인접한 노드에 대한 탐색 요청을 보냅니다. (리피터만 해당)",
|
||||
"repeater_cliHelpPowersaving": "절전 모드가 켜져 있는지 확인하는 표시",
|
||||
"repeater_cliHelpPowersavingOnOff": "절전 모드를 활성화하거나 비활성화할 수 있습니다 (지원되는 경우).",
|
||||
"repeater_cliHelpErase": "(단일 사용) 장치 파일 시스템을 포맷합니다. 모든 설정 및 연락처를 삭제합니다.",
|
||||
"repeater_cliHelpSetDutyCycle": "최대 허용 전송 주기(백분율)를 설정합니다(1~100%). 내부적으로 통신 시간을 조정합니다.",
|
||||
"repeater_cliHelpSetPrvKey": "(시리얼 키만 해당) 장치 식별용 개인 키를 대체합니다. 적용하려면 재부팅이 필요합니다. 새로운 공개 키를 생성합니다.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(SX126x 전용) 더 높은 전류를 사용할 때 더 나은 감도를 위해 증폭된 RX 감쇠 기능을 전환합니다.",
|
||||
"repeater_cliHelpSetOwnerInfo": "광고에 포함된 소유자 연락처 정보를 지정합니다. 줄 바꿈을 위해 '|' 문자를 사용합니다.",
|
||||
"repeater_cliHelpSetPathHashMode": "경로 해시 모드를 설정합니다. 0 = 고전 방식, 1 = 표준 방식, 2 = 엄격한 방식. 경로 매칭 방식에 영향을 미칩니다.",
|
||||
"repeater_cliHelpSetLoopDetect": "라우팅 루프 감지 감도 설정: 끄기, 최소, 중간, 또는 엄격",
|
||||
"repeater_cliHelpSetFreq": "(단일 기능) 특정 주파수만 빠르게 설정합니다. 재부팅이 필요합니다. 전체 라디오 파라미터 설정에는 \"라디오 설정\" 기능을 사용하는 것이 좋습니다.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(ESPNow 브리지만 해당) 브리지에서 사용되는 WiFi 채널(1~14)을 설정합니다.",
|
||||
"repeater_cliHelpGetName": "구성된 노드의 이름을 표시합니다.",
|
||||
"repeater_cliHelpGetRole": "펌웨어 역할(리피터, 룸 서버 등)을 보여줍니다.",
|
||||
"repeater_cliHelpGetPublicKey": "장치의 공개 키를 표시합니다.",
|
||||
"repeater_cliHelpGetPrvKey": "(전용) 장치의 개인 키를 표시합니다. 비밀 정보로 취급합니다.",
|
||||
"repeater_cliHelpGetRepeat": "패킷 전달(리피터 기능)이 활성화되어 있는지 여부를 표시합니다.",
|
||||
"repeater_cliHelpGetTx": "현재 TX 전력(dBm)을 표시합니다.",
|
||||
"repeater_cliHelpGetFreq": "구성된 무선 주파수를 MHz 단위로 표시합니다.",
|
||||
"repeater_cliHelpGetRadio": "전체 무선 파라미터 표시: 주파수, 대역폭, 스프레딩 계수, 인코딩 속도",
|
||||
"repeater_cliHelpGetRadioRxGain": "(SX126x 전용) RX의 증폭 이득 상태를 표시합니다.",
|
||||
"repeater_cliHelpGetAf": "현재 공기 시간 요소를 보여줍니다.",
|
||||
"repeater_cliHelpGetDutyCycle": "현재 허용되는 작업 주기를 백분율로 표시합니다.",
|
||||
"repeater_cliHelpGetIntThresh": "채널 간섭 임계값을 dB 단위로 표시합니다.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "AGC 재설정 간격을 초 단위로 표시합니다.",
|
||||
"repeater_cliHelpGetMultiAcks": "더블 ACK 모드가 활성화되어 있는지 (1) 또는 비활성화되어 있는지 (0)를 표시합니다.",
|
||||
"repeater_cliHelpGetAllowReadOnly": "게스트의 읽기 전용 액세스가 허용되는지 여부를 표시합니다.",
|
||||
"repeater_cliHelpGetAdvertInterval": "지역 광고 시간 간격을 분 단위로 표시합니다.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "홍수 광고 시간 간격을 시간 단위로 표시합니다.",
|
||||
"repeater_cliHelpGetGuestPassword": "구성된 게스트 비밀번호를 표시합니다.",
|
||||
"repeater_cliHelpGetLat": "설정된 위도를 보여줍니다.",
|
||||
"repeater_cliHelpGetLon": "설정된 경도를 보여줍니다.",
|
||||
"repeater_cliHelpGetRxDelay": "Rxdelay 기본 값을 표시합니다.",
|
||||
"repeater_cliHelpGetTxDelay": "홍수 모드에서의 전송 지연 계수를 보여줍니다.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "직렬 모드에서의 딜레이 계수를 보여줍니다.",
|
||||
"repeater_cliHelpGetFloodMax": "최대 홍수 발생 횟수를 보여줍니다.",
|
||||
"repeater_cliHelpGetOwnerInfo": "소유주 연락처 정보를 표시합니다.",
|
||||
"repeater_cliHelpGetPathHashMode": "경로 해시 모드 (0/1/2)를 표시합니다.",
|
||||
"repeater_cliHelpGetLoopDetect": "루프 탐지 감도를 보여줍니다.",
|
||||
"repeater_cliHelpGetAcl": "(단순히 목록만 표시) 리피터에 설정된 접근 제어 항목 목록을 보여줍니다.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "다리 기능이 활성화되어 있는지 여부를 표시합니다.",
|
||||
"repeater_cliHelpGetBridgeDelay": "다리 통과 시간(밀리초)을 표시합니다.",
|
||||
"repeater_cliHelpGetBridgeSource": "브리지 로그가 RX 또는 TX 패킷을 기록하는지 여부를 보여줍니다.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(RS232 브리지 기능만) 브리지의 보드 속도를 표시합니다.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(ESPNow 브리지만 해당) 브리지의 Wi-Fi 채널을 표시합니다.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(ESPNow 브리지만 해당) 브리지에서 공유된 비밀을 표시합니다.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(NRF52만 해당) 부팅 로더 버전을 표시합니다.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "배터리 전압을 스케일링하는 ADC 멀티플라이어를 보여줍니다.",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "이 보드가 전력 관리 기능을 지원하는지 여부를 나타냅니다.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "현재 전원 공급 장치 (외부 전원 또는 배터리)를 표시합니다.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "가장 최근 재설정 및 종료 이유를 보여줍니다.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "부팅 시 배터리 전압을 mV 단위로 표시합니다.",
|
||||
"repeater_cliHelpSensorGet": "키를 사용하여 사용자 정의 센서 설정을 읽습니다.",
|
||||
"repeater_cliHelpSensorSet": "사용자 정의 센서 설정을 작성합니다.",
|
||||
"repeater_cliHelpSensorList": "사용자 정의 센서 설정 목록을, 선택적으로 지정된 시작 인덱스부터 페이지 나누어 표시합니다.",
|
||||
"repeater_cliHelpRegionDefault": "현재 기본 지역 범위를 보여줍니다.",
|
||||
"repeater_cliHelpRegionDefaultSet": "기본 지역 범위를 설정합니다. \"<null>\"을 사용하여 초기화합니다.",
|
||||
"repeater_cliHelpRegionListAllowed": "홍수 피해 차량 통행이 가능한 지역 목록",
|
||||
"repeater_cliHelpRegionListDenied": "홍수 발생 시 통행 금지 지역 목록",
|
||||
"repeater_cliHelpStatsPackets": "(전송 속도만 표시) 패킷 수준의 통계 정보를 보여줍니다.",
|
||||
"repeater_cliHelpStatsRadio": "(특정 시리즈만 해당) 라디오 통계 정보를 표시합니다.",
|
||||
"repeater_cliHelpStatsCore": "(시리얼 번호만 표시) 핵심 펌웨어 통계 정보를 보여줍니다.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "다중 ACK",
|
||||
"map_sharedAt": "공유됨",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "지도에서 특정 위치를 강조하려면 해당 위치를 클릭하세요.",
|
||||
"losBlockedSpotsTitle": "차단된 공간",
|
||||
"losSelectedObstructionTitle": "선택된 장애물",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"settings_companionDebugLog": "동반 디버깅 로그",
|
||||
"chat_newMessages": "새로운 메시지",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 명령어, 응답 및 원시 데이터",
|
||||
"chat_markAsUnread": "미리 읽지 않음으로 표시",
|
||||
"repeater_chanUtil": "채널 활용도",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_pending": "발송",
|
||||
"messageStatus_sent": "발송",
|
||||
"messageStatus_delivered": "배송 완료",
|
||||
"common_undo": "취소",
|
||||
"messageStatus_failed": "발송 실패",
|
||||
"messageStatus_repeated": "반복적으로 들었습니다",
|
||||
"contacts_searchOpen": "연락처 검색",
|
||||
"contacts_moreOptions": "더 많은 옵션",
|
||||
"contacts_searchClose": "검색 닫기",
|
||||
"routing_title": "라우팅",
|
||||
"routing_modeAuto": "자동",
|
||||
"routing_modeFlood": "홍수",
|
||||
"routing_modeManual": "사용 설명서",
|
||||
"routing_modeAutoHint": "가장 잘 알려진 경로를 자동으로 선택하고, 경로가 없을 경우에는 무작위로 경로를 선택합니다.",
|
||||
"routing_modeFloodHint": "모든 증폭기를 통해 방송됩니다. 가장 안정적이지만, 더 많은 송출 시간을 사용합니다.",
|
||||
"routing_modeManualHint": "항상 설정하신 정확한 경로를 따라 이동합니다.",
|
||||
"routing_currentRoute": "현재 경로",
|
||||
"routing_directNoHops": "직접 연결 – 중계 장치 사용 없이",
|
||||
"routing_noPathYet": "아직 경로가 없습니다. 다음 메시지가 도착할 때까지 계속 탐색합니다.",
|
||||
"routing_floodBroadcast": "모든 증폭기를 통해 방송",
|
||||
"routing_editPath": "경로 편집",
|
||||
"routing_forgetPath": "길을 잊어라",
|
||||
"routing_knownPaths": "알려진 경로",
|
||||
"routing_knownPathsHint": "해당 항목으로 전환하기 위한 경로를 선택합니다.",
|
||||
"routing_inUse": "사용 중",
|
||||
"routing_qualityStrong": "강력한 첫 번째 단계",
|
||||
"routing_qualityGood": "좋은 첫 시작",
|
||||
"routing_qualityFair": "처음 시도",
|
||||
"routing_qualityWorked": "완료됨",
|
||||
"routing_qualityFlood": "홍수 피해 상황을 통해 들었습니다.",
|
||||
"routing_qualityUntested": "검증되지 않음",
|
||||
"routing_lastWorked": "{when}에 일했습니다",
|
||||
"routing_neverWorked": "확인되지 않음",
|
||||
"routing_floodDelivery": "홍수 피해 지역 배송",
|
||||
"pathEditor_title": "경로 만들기",
|
||||
"pathEditor_hopCounter": "64개의 홉 중 {count}",
|
||||
"pathEditor_noHops": "현재 홉은 추가되지 않았습니다. 아래의 탭을 사용하여 순서대로 추가하거나, 홉 없이 바로 전송하려면 \"홉 없음\"으로 저장하십시오.",
|
||||
"pathEditor_addHops": "홉을 순서대로 첨가해주세요.",
|
||||
"pathEditor_searchRepeaters": "반복 검색",
|
||||
"pathEditor_advancedHex": "고급: 원시 헥스 경로",
|
||||
"pathEditor_hexLabel": "헥스 접두사",
|
||||
"pathEditor_hexHelper": "각 홉마다 2개의 6자리 숫자, 쉼표로 구분",
|
||||
"pathEditor_invalidTokens": "유효하지 않음: {tokens}",
|
||||
"pathEditor_tooManyHops": "최대 64개의 홉",
|
||||
"pathEditor_usePath": "이 경로를 사용하세요",
|
||||
"pathEditor_removeHop": "홉 제거",
|
||||
"pathEditor_unknownHop": "알 수 없는 중계기",
|
||||
"map_zoomIn": "줌 인",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "줌 아웃",
|
||||
"map_centerMap": "중심 지도",
|
||||
"chrome_bluetoothRequiresChromium": "웹 블루투스는 크롬 브라우저가 필요합니다.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS 확인 완료",
|
||||
"pathTrace_legendInferred": "추론된 위치"
|
||||
}
|
||||
|
||||
+1790
-243
File diff suppressed because it is too large
Load Diff
+1100
-177
File diff suppressed because it is too large
Load Diff
+1121
-188
File diff suppressed because it is too large
Load Diff
+1069
-151
File diff suppressed because it is too large
Load Diff
+1104
-178
File diff suppressed because it is too large
Load Diff
+1106
-178
File diff suppressed because it is too large
Load Diff
+1080
-156
File diff suppressed because it is too large
Load Diff
+1103
-174
File diff suppressed because it is too large
Load Diff
+1071
-196
File diff suppressed because it is too large
Load Diff
+1019
-146
File diff suppressed because it is too large
Load Diff
+1121
-198
File diff suppressed because it is too large
Load Diff
+1113
-183
File diff suppressed because it is too large
Load Diff
+1104
-178
File diff suppressed because it is too large
Load Diff
+1085
-157
File diff suppressed because it is too large
Load Diff
+1112
-184
File diff suppressed because it is too large
Load Diff
+1098
-175
File diff suppressed because it is too large
Load Diff
+1096
-177
File diff suppressed because it is too large
Load Diff
+1267
-344
File diff suppressed because it is too large
Load Diff
+1000
-133
File diff suppressed because it is too large
Load Diff
+431
-51
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Verwijderen",
|
||||
"common_enable": "Activeren",
|
||||
"common_disable": "Uitschakelen",
|
||||
"common_autoRefresh": "Automatisch vernieuwen",
|
||||
"common_interval": "Tijdsinterval",
|
||||
"common_reboot": "Herstarten",
|
||||
"common_loading": "Laden...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -76,7 +78,7 @@
|
||||
}
|
||||
},
|
||||
"scanner_stop": "Stoppen",
|
||||
"scanner_scan": "Scan",
|
||||
"scanner_scan": "Scannen",
|
||||
"device_quickSwitch": "Snelle overschakeling",
|
||||
"device_meshcore": "MeshCore",
|
||||
"settings_title": "Instellingen",
|
||||
@@ -98,12 +100,14 @@
|
||||
"settings_locationInvalid": "Ongeldige breedtegraad of lengtegraad.",
|
||||
"settings_latitude": "Breedtegraad",
|
||||
"settings_longitude": "Lengtegraad",
|
||||
"settings_privacyMode": "Privacy Mode",
|
||||
"settings_privacyMode": "Privacy-modus",
|
||||
"settings_privacyModeSubtitle": "Naam/locatie verbergen in advertenties",
|
||||
"settings_privacyModeToggle": "Schakel privacy modus in om je naam en locatie in advertenties te verbergen.",
|
||||
"settings_privacyModeEnabled": "Privacy modus is ingeschakeld",
|
||||
"settings_privacyModeDisabled": "Privacy modus is uitgeschakeld",
|
||||
"settings_actions": "Acties",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Verzend Advertentie",
|
||||
"settings_sendAdvertisementSubtitle": "Nu aanwezigheid uitzenden",
|
||||
"settings_advertisementSent": "Advertentie verzonden",
|
||||
@@ -115,13 +119,13 @@
|
||||
"settings_rebootDevice": "Apparaat opnieuw opstarten",
|
||||
"settings_rebootDeviceSubtitle": "Herstart het MeshCore-apparaat",
|
||||
"settings_rebootDeviceConfirm": "Ben je er zeker van dat je het apparaat opnieuw wilt opstarten? Je wordt losgekoppeld.",
|
||||
"settings_debug": "Debug",
|
||||
"settings_debug": "Foutopsporing",
|
||||
"settings_bleDebugLog": "BLE Debug Log",
|
||||
"settings_bleDebugLogSubtitle": "BLE commando's, antwoorden en ruwe data",
|
||||
"settings_appDebugLog": "App Debug Log",
|
||||
"settings_appDebugLog": "Debuglog van de app",
|
||||
"settings_appDebugLogSubtitle": "Toepassingsdebugberichten",
|
||||
"settings_about": "Over",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open versie {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -138,7 +142,7 @@
|
||||
"settings_infoPublicKey": "Openbare Sleutel",
|
||||
"settings_infoContactsCount": "Aantal Contacten",
|
||||
"settings_infoChannelCount": "Aantal Kanalen",
|
||||
"settings_presets": "Presets",
|
||||
"settings_presets": "Voorgeprogrammeerde instellingen",
|
||||
"settings_frequency": "Frequentie (MHz)",
|
||||
"settings_frequencyHelper": "300,0 - 2500,0",
|
||||
"settings_frequencyInvalid": "Ongeldige frequentie (300-2500 MHz)",
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Donker",
|
||||
"appSettings_language": "Taal",
|
||||
"appSettings_languageSystem": "Standaardinstelling",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageEn": "Engels",
|
||||
"appSettings_languageFr": "Frans",
|
||||
"appSettings_languageEs": "Spaans",
|
||||
"appSettings_languageDe": "Duits",
|
||||
"appSettings_languagePl": "Pools",
|
||||
"appSettings_languageSl": "Sloveens",
|
||||
"appSettings_languagePt": "Portugees",
|
||||
"appSettings_languageIt": "Italiaans",
|
||||
"appSettings_languageZh": "Chinees",
|
||||
"appSettings_languageSv": "Zweeds",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageSk": "Sloveens",
|
||||
"appSettings_languageBg": "Bulgaars",
|
||||
"appSettings_notifications": "Notificaties",
|
||||
"appSettings_enableNotifications": "Notificaties inschakelen",
|
||||
"appSettings_enableNotificationsSubtitle": "Ontvang meldingen voor berichten en advertenties",
|
||||
@@ -249,7 +253,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_debugCard": "Debug",
|
||||
"appSettings_debugCard": "Foutopsporing",
|
||||
"appSettings_appDebugLogging": "App Debuggen Loggen",
|
||||
"appSettings_appDebugLoggingSubtitle": "Log app debugberichten voor probleemoplossing",
|
||||
"appSettings_appDebugLoggingEnabled": "App debug logging is ingeschakeld",
|
||||
@@ -271,7 +275,7 @@
|
||||
},
|
||||
"contacts_manageRepeater": "Beheer Repeater",
|
||||
"contacts_roomLogin": "Ruimte Inloggen",
|
||||
"contacts_openChat": "Open Chat",
|
||||
"contacts_openChat": "Open gesprek",
|
||||
"contacts_editGroup": "Groep bewerken",
|
||||
"contacts_deleteGroup": "Groep verwijderen",
|
||||
"contacts_deleteGroupConfirm": "Verwijder {groupName}?",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtag kanaal",
|
||||
"channels_public": "Openbaar",
|
||||
"channels_private": "Privé",
|
||||
"channels_publicChannel": "Open kanaal",
|
||||
"channels_privateChannel": "Private kanaal",
|
||||
"channels_editChannel": "Kanaal bewerken",
|
||||
"channels_muteChannel": "Kanaal dempen",
|
||||
"channels_unmuteChannel": "Kanaal dempen opheffen",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ compressie",
|
||||
"channels_cyr2latCompression": "Cyr2Lat compressie",
|
||||
"channels_cyr2latCompressionDscr": "Vervangt sommige Cyrillische tekens door Latijnse tekens bij het verzenden.",
|
||||
"channels_cyr2latSettingsHeading": "Instellingen Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Lijst met vervangingen",
|
||||
"channels_cyr2latSettingsDscr": "Bewerk de JSON-configuratie voor tekenvervanging",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-vervangingskaart",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Onjuiste JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Cyr2Lat-profiel toevoegen",
|
||||
"settings_cyr2latProfileName": "Profielnaam",
|
||||
"settings_cyr2latProfileNameEmpty": "Profielnaam mag niet leeg zijn",
|
||||
"settings_cyr2latProfileAdded": "Profiel succesvol toegevoegd",
|
||||
"settings_cyr2latProfileUpdated": "Profiel succesvol bijgewerkt",
|
||||
"settings_cyr2latProfileEdit": "Cyr2Lat-profiel bewerken",
|
||||
"settings_cyr2latProfileDelete": "Cyr2Lat-profiel verwijderen",
|
||||
"settings_cyr2latProfileDeleted": "Profiel succesvol verwijderd",
|
||||
"settings_cyr2latProfileDeleteDscr": "Weet u zeker dat u het profiel \"{name}\" wilt verwijderen?",
|
||||
"channels_channelUpdated": "Kanaal \"{name}\" is bijgewerkt",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Open kanaal toegevoegd",
|
||||
"channels_sortBy": "Sorteren door",
|
||||
"channels_sortManual": "Handmatig",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "Alfabetisch",
|
||||
"channels_sortLatestMessages": "Recent berichten",
|
||||
"channels_sortUnread": "Ongelezen",
|
||||
"chat_noMessages": "Nog geen berichten.",
|
||||
@@ -468,7 +485,7 @@
|
||||
"gifPicker_failedLoad": "GIF's konden niet worden geladen",
|
||||
"gifPicker_failedSearch": "Zoeken mislukt",
|
||||
"gifPicker_noInternet": "Geen internetverbinding",
|
||||
"debugLog_appTitle": "App Debug Log",
|
||||
"debugLog_appTitle": "Debuglog van de app",
|
||||
"debugLog_bleTitle": "BLE Debug Log",
|
||||
"debugLog_copyLog": "Kopieer log",
|
||||
"debugLog_clearLog": "Log wissen",
|
||||
@@ -477,7 +494,7 @@
|
||||
"debugLog_noEntries": "Nog geen debug logs beschikbaar.",
|
||||
"debugLog_enableInSettings": "Schakel app debug logging in de instellingen",
|
||||
"debugLog_frames": "Ramen",
|
||||
"debugLog_rawLogRx": "Raw Log-RX",
|
||||
"debugLog_rawLogRx": "Niet-verwerkt Log-RX",
|
||||
"debugLog_noBleActivity": "Geen BLE-activiteit nog.",
|
||||
"debugFrame_length": "Frame Lengte: {count} bytes",
|
||||
"@debugFrame_length": {
|
||||
@@ -541,7 +558,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_hexDump": "Hex Dump:",
|
||||
"debugFrame_hexDump": "Hex-dump:",
|
||||
"chat_pathManagement": "Beheer van Paden",
|
||||
"chat_routingMode": "Routeerwijze",
|
||||
"chat_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)",
|
||||
@@ -599,7 +616,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat_floodAuto": "Flood (auto)",
|
||||
"chat_floodAuto": "Overstroming (van een auto)",
|
||||
"chat_direct": "Direct",
|
||||
"chat_poiShared": "Gedeelde POI",
|
||||
"chat_unread": "Nieuw: {count}",
|
||||
@@ -622,10 +639,10 @@
|
||||
}
|
||||
},
|
||||
"chat_invalidLink": "Ongeldig linkformaat",
|
||||
"map_title": "Node Map",
|
||||
"map_title": "Kaart van de knopen",
|
||||
"map_noNodesWithLocation": "Geen nodes met locatiegegevens",
|
||||
"map_nodesNeedGps": "Nodes moeten hun GPS-coördinaten delen\nom op de kaart te verschijnen",
|
||||
"map_nodesCount": "Nodes: {count}",
|
||||
"map_nodesCount": "Knooppunten: {count}",
|
||||
"@map_nodesCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -642,7 +659,7 @@
|
||||
}
|
||||
},
|
||||
"map_chat": "Chat",
|
||||
"map_repeater": "Repeater",
|
||||
"map_repeater": "Herhaald",
|
||||
"map_room": "Ruimte",
|
||||
"map_sensor": "Sensor",
|
||||
"map_pinDm": "Verzenden als bericht (DM)",
|
||||
@@ -655,7 +672,7 @@
|
||||
"map_flags": "Vlaggen",
|
||||
"map_shareMarkerHere": "Deel marker hier",
|
||||
"map_pinLabel": "Label vastzetten",
|
||||
"map_label": "Label",
|
||||
"map_label": "Etiket",
|
||||
"map_pointOfInterest": "Interessepunt",
|
||||
"map_sendToContact": "Verzenden naar contact",
|
||||
"map_sendToChannel": "Verzenden naar kanaal",
|
||||
@@ -670,10 +687,10 @@
|
||||
}
|
||||
},
|
||||
"map_connectToShareMarkers": "Verbind met een apparaat om markers te delen",
|
||||
"map_filterNodes": "Filter Nodes",
|
||||
"map_filterNodes": "Filternodes",
|
||||
"map_nodeTypes": "Nodetypes",
|
||||
"map_chatNodes": "Chatnodes",
|
||||
"map_repeaters": "Repeaters",
|
||||
"map_repeaters": "Herhaalders",
|
||||
"map_otherNodes": "Andere Nodes",
|
||||
"map_keyPrefix": "Prefix sleutel",
|
||||
"map_filterByKeyPrefix": "Filteren op sleutelvoorgemeld",
|
||||
@@ -696,7 +713,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mapCache_downloadAction": "Download",
|
||||
"mapCache_downloadAction": "Downloaden",
|
||||
"mapCache_cachedTiles": "Opgeslagen {count} tegels",
|
||||
"@mapCache_cachedTiles": {
|
||||
"placeholders": {
|
||||
@@ -814,7 +831,7 @@
|
||||
"login_savePasswordSubtitle": "Het wachtwoord wordt veilig op dit apparaat opgeslagen.",
|
||||
"login_repeaterDescription": "Voer het wachtwoord van de repeater in om instellingen en status te openen.",
|
||||
"login_roomDescription": "Voer het wachtwoord van de kamer in om toegang te krijgen tot instellingen en status.",
|
||||
"login_routing": "Routing",
|
||||
"login_routing": "Routeplanning",
|
||||
"login_routingMode": "Routeerwijze",
|
||||
"login_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)",
|
||||
"login_forceFloodMode": "Dwing Floodmodus Af",
|
||||
@@ -881,7 +898,7 @@
|
||||
"repeater_managementTools": "Beheerfuncties",
|
||||
"repeater_status": "Status",
|
||||
"repeater_statusSubtitle": "Status, statistieken en buren bekijken",
|
||||
"repeater_telemetry": "Telemetry",
|
||||
"repeater_telemetry": "Telemetrie",
|
||||
"repeater_telemetrySubtitle": "Bekijk telemetrie van sensoren en systeemgegevens",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cliSubtitle": "Verzend commando's naar de repeater",
|
||||
@@ -963,7 +980,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_duplicatesFloodDirect": "Flood: {flood}, Direct: {direct}",
|
||||
"repeater_duplicatesFloodDirect": "Overstroming: {flood}, Direct: {direct}",
|
||||
"@repeater_duplicatesFloodDirect": {
|
||||
"placeholders": {
|
||||
"flood": {
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Bevestigen",
|
||||
"repeater_settingsSaved": "Instellingen succesvol opgeslagen",
|
||||
"repeater_rxGain": "Verhoogde RX-uitgang",
|
||||
"repeater_rxGainHelper": "Hogere gevoeligheid, grotere stroomverbruik (alleen voor SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Versterk de reeds bestaande RX-verbetering.",
|
||||
"repeater_multiAcks": "Meerdere bevestigingen",
|
||||
"repeater_multiAcksSubtitle": "Bevestig berichten via verschillende routes voor een betere levering.",
|
||||
"repeater_refreshMultiAcks": "Herhaal meerdere bevestigingen",
|
||||
"repeater_networkHealth": "Netwerkgezondheid",
|
||||
"repeater_loopDetect": "Detectie van beweging",
|
||||
"repeater_loopDetectHelper": "Verzend pakketten die eruitzien als routing-lusjes",
|
||||
"repeater_loopDetectOff": "Af",
|
||||
"repeater_loopDetectMinimal": "Minimaal",
|
||||
"repeater_loopDetectModerate": "Matig",
|
||||
"repeater_loopDetectStrict": "Strikte",
|
||||
"repeater_dutyCycle": "Werkcyclus",
|
||||
"repeater_dutyCycleHelper": "Maximale percentage van de beschikbare uitzendtijd",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informatie over de operator",
|
||||
"repeater_ownerInfoHelper": "Openbare metadata voor deze repeater",
|
||||
"repeater_refreshOwnerInfo": "Herstel informatie over de operator",
|
||||
"repeater_floodMax": "Maximale hoeveelheid hop",
|
||||
"repeater_floodMaxHelper": "Maximale hoeveelheid hop die een pakket kan bevatten (0-64)",
|
||||
"repeater_advancedSettings": "Geavanceerd",
|
||||
"repeater_advancedSettingsSubtitle": "Regelhendels voor ervaren gebruikers",
|
||||
"repeater_pathHashMode": "Hash-modus voor paden",
|
||||
"repeater_pathHashModeHelper": "Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID's, tot 64 hops), 1=2 bytes (65.000 ID's, tot 32 hops), 2=3 bytes (16 miljoen ID's, tot 21 hops). Versies 1.13 en ouder gebruiken multi-byte paden – alleen na het activeren van het netwerk.",
|
||||
"repeater_txDelay": "Vertraging bij Flood TX",
|
||||
"repeater_txDelayHelper": "Herzendinterval voor verkeer tijdens overstromingen, als een veelvoud van de tijd die het pakket nodig heeft (0-2, standaard 0.5). Een hoger getal betekent minder botsingen, maar ook een langere leveringstijd.",
|
||||
"repeater_directTxDelay": "Directe vertraging",
|
||||
"repeater_directTxDelayHelper": "De overzending van tijdslots voor directe (niet-massaal) verkeer, als een vermenigvuldigingsfactor van de tijd die een pakket nodig heeft (0-2, standaard 0,3).",
|
||||
"repeater_intThresh": "Grenswaarde voor interferentie",
|
||||
"repeater_intThreshHelper": "De drempelwaarde is ingesteld zodat de radio storingen boven deze waarde kan detecteren en blokkeren. 0 staat voor \"uitgezet\" – alleen verhoog deze waarde als u fouten in een storingrijke band ziet.",
|
||||
"repeater_agcResetInterval": "Interval voor het opnieuw instellen van AGC",
|
||||
"repeater_agcResetIntervalHelper": "Hoe vaak moet u de automatische gainregeling van de radio opnieuw instellen om terug te keren van een situatie waarin de gain vastzit? Elke seconde, of elke 4e seconde. Het uitschakelen van de periodieke reset (0) zorgt ervoor dat de gain niet automatisch wordt aangepast.",
|
||||
"repeater_actionsTitle": "Acties",
|
||||
"repeater_sendAdvert": "Verzend advertentie over overstromingen",
|
||||
"repeater_sendAdvertSubtitle": "Zend een advertentie over overstromingen uit via het netwerk.",
|
||||
"repeater_sendAdvertZeroHop": "Verzend een advertentie zonder tussenliggende stap",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Zend een advertentie met één enkele verbinding (zonder tussenliggende zenders).",
|
||||
"repeater_clockSync": "Synchroniseer klok nu",
|
||||
"repeater_clockSyncSubtitle": "Stel de tijd van je telefoon in op de repeater.",
|
||||
"repeater_actionSucceeded": "{action} is gelukt",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Instellingen opgeslagen – start de zender opnieuw om de wijzigingen toe te passen.",
|
||||
"repeater_settingsPartialFailure": "Sommige instellingen zijn niet correct uitgevoerd: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Fout bij het opslaan van de instellingen: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Basisinstellingen vernieuwen",
|
||||
"repeater_refreshRadioSettings": "Radiozender Instellingen Verversen",
|
||||
"repeater_refreshTxPower": "Nieuw laden TX-vermogen",
|
||||
"repeater_refreshLocationSettings": "Instellingen Locatie Vernieuwen",
|
||||
"repeater_refreshPacketForwarding": "Vernieuwen Pakket Doorversturing",
|
||||
"repeater_refreshGuestAccess": "Toegang Gast Vernieuwen",
|
||||
"repeater_refreshPrivacyMode": "Privacymode vernieuwen",
|
||||
"repeater_refreshAdvertisementSettings": "Instellingen Advertentie Bijwerken",
|
||||
"repeater_refreshed": "{label} is vernieuwd",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1091,7 +1181,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_cliTitle": "Repeater CLI",
|
||||
"repeater_cliTitle": "CLI-interface voor de repeater",
|
||||
"repeater_debugNextCommand": "Debug Volgende Commando",
|
||||
"repeater_commandHelp": "Help",
|
||||
"repeater_clearHistory": "Geschiedenis Verwijderen",
|
||||
@@ -1176,7 +1266,7 @@
|
||||
"repeater_general": "Algemeen",
|
||||
"repeater_settingsCategory": "Instellingen",
|
||||
"repeater_bridge": "Bruggen",
|
||||
"repeater_logging": "Logging",
|
||||
"repeater_logging": "Loggen",
|
||||
"repeater_neighborsRepeaterOnly": "Buren (Alleen repeaters)",
|
||||
"repeater_regionManagementRepeaterOnly": "Regiobeheer (Alleen Repeater)",
|
||||
"repeater_regionNote": "Regio-commando's zijn geïntroduceerd om regio-definities en permissies te beheren.",
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digitale ingang",
|
||||
"telemetry_digitalOutputLabel": "Digitale uitgang",
|
||||
"telemetry_analogInputLabel": "Analoge ingang",
|
||||
"telemetry_analogOutputLabel": "Analoge uitgang",
|
||||
"telemetry_genericLabel": "Algemene sensor",
|
||||
"telemetry_luminosityLabel": "Lichtsterkte",
|
||||
"telemetry_presenceLabel": "Aanwezigheid",
|
||||
"telemetry_humidityLabel": "Luchtvochtigheid",
|
||||
"telemetry_accelerometerLabel": "Versnellingsmeter",
|
||||
"telemetry_pressureLabel": "Druk",
|
||||
"telemetry_altitudeLabel": "Hoogte",
|
||||
"telemetry_frequencyLabel": "Frequentie",
|
||||
"telemetry_percentageLabel": "Percentage",
|
||||
"telemetry_concentrationLabel": "Concentratie",
|
||||
"telemetry_powerLabel": "Vermogen",
|
||||
"telemetry_distanceLabel": "Afstand",
|
||||
"telemetry_energyLabel": "Energie",
|
||||
"telemetry_directionLabel": "Richting",
|
||||
"telemetry_timeLabel": "Tijd",
|
||||
"telemetry_gyrometerLabel": "Gyrometer",
|
||||
"telemetry_colourLabel": "Kleur",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Schakelaar",
|
||||
"telemetry_polylineLabel": "Polylijn",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Aantal aanvragen",
|
||||
"telemetry_error": "Kan gegevens niet ophalen",
|
||||
"telemetry_noData": "Geen telemetriedata beschikbaar.",
|
||||
"telemetry_channelTitle": "Kanaal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1247,12 +1374,12 @@
|
||||
"channelPath_title": "Pakketpad",
|
||||
"channelPath_viewMap": "Kaart bekijken",
|
||||
"channelPath_otherObservedPaths": "Overige Waargenomen Paden",
|
||||
"channelPath_repeaterHops": "Repeater Hops",
|
||||
"channelPath_repeaterHops": "Herhaalde sprongen",
|
||||
"channelPath_noHopDetails": "De details van de pakket zijn niet verstrekt.",
|
||||
"channelPath_messageDetails": "Details Bericht",
|
||||
"channelPath_senderLabel": "Afzender",
|
||||
"channelPath_timeLabel": "Tijd",
|
||||
"channelPath_repeatsLabel": "Repeats",
|
||||
"channelPath_repeatsLabel": "Herhaalt",
|
||||
"channelPath_pathLabel": "Pad {index}",
|
||||
"channelPath_observedLabel": "Waargenomen",
|
||||
"channelPath_observedPathTitle": "Waargenomen pad {index} • {hops}",
|
||||
@@ -1290,7 +1417,7 @@
|
||||
}
|
||||
},
|
||||
"channelPath_unknownPath": "Onbekend",
|
||||
"channelPath_floodPath": "Flood",
|
||||
"channelPath_floodPath": "Overstroming",
|
||||
"channelPath_directPath": "Direct",
|
||||
"channelPath_observedZeroOf": "0 van {total} sprongen",
|
||||
"@channelPath_observedZeroOf": {
|
||||
@@ -1347,11 +1474,11 @@
|
||||
"listFilter_sortBy": "Sorteren door",
|
||||
"listFilter_latestMessages": "Recente berichten",
|
||||
"listFilter_heardRecently": "Recent gezien",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "Alfabetisch",
|
||||
"listFilter_filters": "Filters",
|
||||
"listFilter_all": "Alles",
|
||||
"listFilter_users": "Gebruikers",
|
||||
"listFilter_repeaters": "Repeaters",
|
||||
"listFilter_repeaters": "Herhalers",
|
||||
"listFilter_roomServers": "Roomservers",
|
||||
"listFilter_unreadOnly": "Alleen ongelezen",
|
||||
"listFilter_newGroup": "Nieuwe groep",
|
||||
@@ -1460,7 +1587,7 @@
|
||||
}
|
||||
},
|
||||
"community_title": "Gemeenschap",
|
||||
"common_ok": "OK",
|
||||
"common_ok": "Prima",
|
||||
"community_createDesc": "Maak een nieuwe community en deel deze via QR-code.",
|
||||
"community_create": "Maak Gemeenschap",
|
||||
"community_join": "Sluit aan",
|
||||
@@ -1554,11 +1681,11 @@
|
||||
"contacts_pathTrace": "Pad Traceren",
|
||||
"contacts_ping": "Pingen",
|
||||
"contacts_repeaterPathTrace": "Pad traceren naar repeater",
|
||||
"contacts_repeaterPing": "Ping repeater",
|
||||
"contacts_repeaterPing": "Ping-repeater",
|
||||
"contacts_roomPathTrace": "Padtrace naar room server",
|
||||
"contacts_roomPing": "Ping kamer server",
|
||||
"contacts_chatTraceRoute": "Route traceren",
|
||||
"contacts_pathTraceTo": "Trace route to {name}",
|
||||
"contacts_pathTraceTo": "Volg de route naar {name}",
|
||||
"appSettings_languageUk": "Oekraïens",
|
||||
"contacts_invalidAdvertFormat": "Ongeldige contactgegevens",
|
||||
"contacts_contactImportFailed": "Contact kon niet geïmporteerd worden.",
|
||||
@@ -1934,6 +2061,7 @@
|
||||
"appSettings_maxMessageRetriesSubtitle": "Aantal pogingen om een bericht opnieuw te versturen voordat het als mislukt wordt gemarkeerd",
|
||||
"path_routeWeight": "{weight}/{max}",
|
||||
"settings_telemetryModeUpdated": "Telemetrie-modus bijgewerkt",
|
||||
"settings_multiAck": "Meerdere bevestigingen",
|
||||
"map_showOverlaps": "Herhalingssleutel overlapt",
|
||||
"map_runTraceWithReturnPath": "Terugkeren op hetzelfde pad.",
|
||||
"@radioStats_noiseFloor": {
|
||||
@@ -2012,6 +2140,9 @@
|
||||
"translation_composerTitle": "Vertaal voor verzending",
|
||||
"translation_composerSubtitle": "Stelt de standaardstatus van het pictogram voor de vertaling van de componist in.",
|
||||
"translation_useAppLanguage": "Gebruik de taal van de app",
|
||||
"translation_autoIncomingTitle": "Berichten automatisch vertalen",
|
||||
"translation_autoIncomingSubtitle": "Vertaalt berichten automatisch voor meldingen en voor chats of kanalen.",
|
||||
"translation_translateMessage": "Bericht vertalen",
|
||||
"translation_targetLanguage": "Doeltaal",
|
||||
"translation_downloadedModelLabel": "Gedownloade model",
|
||||
"translation_presetModelLabel": "Voorgeprogrammeerd Hugging Face-model",
|
||||
@@ -2066,5 +2197,254 @@
|
||||
"room_guest": "Informatie over de server",
|
||||
"chat_sendMessage": "Verzend bericht",
|
||||
"repeater_guest": "Informatie over herhalingsapparatuur",
|
||||
"settings_multiAck": "Meerdere bevestigingen"
|
||||
"repeater_getCategory": "Waarden verkrijgen",
|
||||
"repeater_powerMgmt": "Energiebeheer",
|
||||
"repeater_sensors": "Sensoren",
|
||||
"repeater_cliHelpPowerOff": "Zorgt ervoor dat het apparaat wordt uitgeschakeld. (geen reactie verwacht)",
|
||||
"repeater_cliHelpClkReboot": "Stelt de klok terug naar een bekende tijd en start het apparaat opnieuw op.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Verstuurt een advertentie die alleen naar directe buren wordt gericht (geen tussenliggende stops).",
|
||||
"repeater_cliHelpStartOta": "Start een firmware-update via de lucht op ondersteunde boards.",
|
||||
"repeater_cliHelpTime": "Stelt de klok van het apparaat in op de gegeven Unix-tijd (aantal seconden vanaf de Unix-epoch). De klok kan niet teruggedraaid worden.",
|
||||
"repeater_cliHelpBoard": "Geeft de fabrikant van het bord en/of de hardware-identificatie weer.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Stuurt een verzoek om buren in de buurt te ontdekken. (Alleen van toepassing op een repeater)",
|
||||
"repeater_cliHelpPowersaving": "Geeft aan of de energiebesparingsmodus is ingeschakeld of uitgeschakeld.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Activeert of deactiveert de energiebesparingsmodus (indien ondersteund).",
|
||||
"repeater_cliHelpErase": "(Alleen voor seriële verbindingen) Formateert het bestandssysteem van het apparaat. Verwijdert alle instellingen en contacten.",
|
||||
"repeater_cliHelpSetDutyCycle": "Stelt het maximale toegestane transmissiepercentage in (in procenten, 1-100). Past intern de tijdsschaal aan.",
|
||||
"repeater_cliHelpSetPrvKey": "(Alleen voor seriële toepassingen) Vervangt de private sleutel van het apparaat. Een herstart is vereist om deze wijziging toe te passen. Genereert een nieuwe publieke sleutel.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Alleen voor SX126x-chips) Schakelt de versterkte RX-gain in om de gevoeligheid te verbeteren bij een hoger stroomverbruik.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Definieert de string met contactgegevens van de eigenaar, die in de advertenties wordt opgenomen. Gebruik '|' voor nieuwe regels.",
|
||||
"repeater_cliHelpSetPathHashMode": "Stelt de modus voor het berekenen van de hash van de route in. 0 = voorheen, 1 = standaard, 2 = strikt. Beïnvloedt hoe de routes worden gematched.",
|
||||
"repeater_cliHelpSetLoopDetect": "Stelt de gevoeligheid voor het detecteren van een lus in de routing in: uit, minimaal, matig of strikt.",
|
||||
"repeater_cliHelpSetFreq": "(Alleen voor seriële communicatie) Stelt snel alleen de frequentie in. Herstart is vereist. Het is aan te raden om \"radio instellingen\" te gebruiken voor alle radioparameters.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Alleen voor ESPNow-brug) Stelt het WiFi-kanaal (1-14) in dat door de brug wordt gebruikt.",
|
||||
"repeater_cliHelpGetName": "Toont de naam van de geconfigureerde knoop.",
|
||||
"repeater_cliHelpGetRole": "Geeft de rol van de firmware aan (herhaald, server voor een kamer, enz.).",
|
||||
"repeater_cliHelpGetPublicKey": "Toont het openbare sleutel van het apparaat.",
|
||||
"repeater_cliHelpGetPrvKey": "(Alleen voor seriële communicatie) Toont de private sleutel van het apparaat. Behandel dit als een geheim.",
|
||||
"repeater_cliHelpGetRepeat": "Geeft aan of het doorsturen van pakketten (als repeater) is ingeschakeld of uitgeschakeld.",
|
||||
"repeater_cliHelpGetTx": "Toont de huidige zendvermogen in dBm.",
|
||||
"repeater_cliHelpGetFreq": "Toont de geconfigureerde frequentie in MHz.",
|
||||
"repeater_cliHelpGetRadio": "Geeft alle radioparameters weer: frequentie, bandbreedte, spreidfactor, codegraad.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Alleen voor SX126x-chips) Toont de status van de versterking van de RX-ontvangst.",
|
||||
"repeater_cliHelpGetAf": "Geeft de huidige tijdsfactor weer.",
|
||||
"repeater_cliHelpGetDutyCycle": "Toont de huidige toegestane duty cycle als een percentage.",
|
||||
"repeater_cliHelpGetIntThresh": "Toont het drempelwaarde voor signaalinterferentie in dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Geeft het interval in seconden aan voor het resetten van de AGC (Automatic Gain Control).",
|
||||
"repeater_cliHelpGetMultiAcks": "Geeft aan of de modus \"dubbele bevestiging\" is ingeschakeld (1) of uitgeschakeld (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Geeft aan of er toegang is voor gastgebruikers zonder rechten.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Geeft de duur van de lokale reclame in minuten aan.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Geeft de duur van de reclame-interval in uren aan.",
|
||||
"repeater_cliHelpGetGuestPassword": "Toont het ingestelde gastwachtwoord.",
|
||||
"repeater_cliHelpGetLat": "Toont de ingestelde breedtegraad.",
|
||||
"repeater_cliHelpGetLon": "Toont de ingestelde lengtegraad.",
|
||||
"repeater_cliHelpGetRxDelay": "Toont de basiswaarde van de rx-vertraging.",
|
||||
"repeater_cliHelpGetTxDelay": "Geeft de factor weer die de vertraging in de flood-modus bepaalt.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Geeft de factor voor de vertraging in de directe modus weer.",
|
||||
"repeater_cliHelpGetFloodMax": "Toont het maximale aantal keer dat een overstroming heeft plaatsgevonden.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Toont de string met contactgegevens van de eigenaar.",
|
||||
"repeater_cliHelpGetPathHashMode": "Toont de modus voor het berekenen van de hash (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Geeft de gevoeligheid voor het detecteren van lusvorming weer.",
|
||||
"repeater_cliHelpGetAcl": "(Alleen voor seriële communicatie) Geeft de toegangscontroles weer op een repeater.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Geeft aan of de brug is ingeschakeld.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Geeft de vertraging van de brug in milliseconden weer.",
|
||||
"repeater_cliHelpGetBridgeSource": "Geeft aan of de brug RX- of TX-pakketten verwerkt.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Alleen RS232-brug) Toont de baud-snelheid van de brug.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Alleen voor ESPNow-brug) Toont het WiFi-kanaal van de brug.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Alleen voor ESPNow-brug) Toont het gedeelde geheime sleutel.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Alleen voor NRF52) Toont de versie van de bootloader.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Toont de ADC-vermenigvuldiging (schalen van de batterijspanning).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Geeft aan of het bestuur ondersteuning heeft voor het beheer van energieverbruik.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Geeft de huidige stroombron aan: extern of batterij.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Geeft de meest recente redenen voor het opnieuw opstarten en afsluiten weer.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Geeft de batterijspanning in mV weer, direct na het opstarten.",
|
||||
"repeater_cliHelpSensorGet": "Leest een aangepaste sensorgegevens op basis van een sleutel.",
|
||||
"repeater_cliHelpSensorSet": "Maakt een aangepaste instelling voor een sensor.",
|
||||
"repeater_cliHelpSensorList": "Toont alle aangepaste instellingen voor sensoren, gegroepeerd op basis van een optionele startindex.",
|
||||
"repeater_cliHelpRegionDefault": "Toont het huidige standaard regio-bereik.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Stelt de standaard regio-omvang in. Gebruik \"<null>\" om deze te resetten.",
|
||||
"repeater_cliHelpRegionListAllowed": "Lijst van gebieden waar doorstromen tijdens overstromingen is toegestaan.",
|
||||
"repeater_cliHelpRegionListDenied": "Geeft een lijst van regio's die het verkeer tijdens overstromingen verbieden.",
|
||||
"repeater_cliHelpStatsPackets": "(Alleen voor seriële verbindingen) Toont statistieken op pakketniveau.",
|
||||
"repeater_cliHelpStatsRadio": "(Alleen voor serienummers) Toont radio-statistieken.",
|
||||
"repeater_cliHelpStatsCore": "(Alleen voor seriële communicatie) Toont de belangrijkste firmware-statistieken.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Gedeeld",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Geselecteerde obstakel",
|
||||
"losBlockedSpotsHint": "Tik op een geblokkeerd gebied om het op de kaart te markeren.",
|
||||
"losBlockedSpotsTitle": "Geplande plaatsen",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"settings_companionDebugLog": "Debuglog voor aanvullende informatie",
|
||||
"chat_newMessages": "Nieuwe berichten",
|
||||
"chat_markAsUnread": "Markeer als ongelezen",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB commando's, antwoorden en ruwe data",
|
||||
"repeater_chanUtil": "Gebruik van het kanaal",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "Verzonden",
|
||||
"common_undo": "Achterhalen/Annuleren",
|
||||
"messageStatus_delivered": "Leverd",
|
||||
"messageStatus_pending": "Verzenden",
|
||||
"messageStatus_failed": "Niet verzonden",
|
||||
"messageStatus_repeated": "Hearsay, herhaald",
|
||||
"contacts_moreOptions": "Meer opties",
|
||||
"contacts_searchOpen": "Zoek contactpersonen",
|
||||
"contacts_searchClose": "Zoeken",
|
||||
"routing_title": "Routeplanning",
|
||||
"routing_modeAuto": "Auto",
|
||||
"routing_modeFlood": "Overstroming",
|
||||
"routing_modeManual": "Handleiding",
|
||||
"routing_modeAutoHint": "Selecteert automatisch het bekendste pad, en gebruikt een flood-algoritme als er geen bekend pad is.",
|
||||
"routing_modeFloodHint": "Uitzendingen via elke zender. De meest betrouwbare methode, maar vereist meer uitzendtijd.",
|
||||
"routing_modeManualHint": "Stuurt altijd de exacte route die u heeft aangegeven.",
|
||||
"routing_currentRoute": "Huidige route",
|
||||
"routing_directNoHops": "Direct – zonder tussenliggende schakels",
|
||||
"routing_noPathYet": "Er is nog geen route gevonden. De berichten blijven binnenkomen totdat een route is ontdekt.",
|
||||
"routing_floodBroadcast": "Uitgestoten via elke zender.",
|
||||
"routing_editPath": "Pad bewerken",
|
||||
"routing_forgetPath": "Vergeet het pad",
|
||||
"routing_knownPaths": "Bekende routes",
|
||||
"routing_knownPathsHint": "Maak een route om er naartoe te gaan.",
|
||||
"routing_inUse": "In gebruik",
|
||||
"routing_qualityStrong": "Sterke eerste sprong",
|
||||
"routing_qualityGood": "Een goede eerste stap",
|
||||
"routing_qualityFair": "Een goede eerste hop",
|
||||
"routing_qualityWorked": "Is geleverd",
|
||||
"routing_qualityFlood": "Hears via een overstroming",
|
||||
"routing_qualityUntested": "Niet getest",
|
||||
"routing_neverWorked": "nooit bevestigd",
|
||||
"routing_deliveryCounts": "{successes} zijn behaald, {failures} zijn mislukt",
|
||||
"routing_floodDelivery": "Levering bij overstroming",
|
||||
"pathEditor_title": "Pad creëren",
|
||||
"pathEditor_hopCounter": "{count} van 64 hopgranen",
|
||||
"pathEditor_noHops": "Er zijn nog geen hop toegevoegd. Klik op de onderstaande knoppen om ze in de juiste volgorde toe te voegen, of sla de bestelling op zonder hop om deze direct te versturen.",
|
||||
"pathEditor_addHops": "Voeg hop toe in de juiste volgorde.",
|
||||
"pathEditor_searchRepeaters": "Zoek naar herhaaldelijke zenders",
|
||||
"pathEditor_advancedHex": "Geavanceerd: ruwe hex-pad",
|
||||
"pathEditor_hexLabel": "Hex-voorkanten",
|
||||
"pathEditor_hexHelper": "Twee hex-tekens per stap, gescheiden door komma's",
|
||||
"pathEditor_invalidTokens": "Ongeldig: {tokens}",
|
||||
"pathEditor_tooManyHops": "Maximaal 64 hopken",
|
||||
"pathEditor_usePath": "Gebruik deze route.",
|
||||
"pathEditor_removeHop": "Verwijder de hop",
|
||||
"pathEditor_unknownHop": "Onbekend type zender",
|
||||
"map_zoomIn": "Inzoomen",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"map_zoomOut": "Inzoomen",
|
||||
"map_centerMap": "Centraal overzicht",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth vereist een Chromium-browser.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS-locatie bevestigd",
|
||||
"pathTrace_legendInferred": "Afgeleide positie"
|
||||
}
|
||||
|
||||
+413
-33
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Usuń",
|
||||
"common_enable": "Włącz",
|
||||
"common_disable": "Wyłącz",
|
||||
"common_autoRefresh": "Automatyczne odświeżanie",
|
||||
"common_interval": "Interwał",
|
||||
"common_reboot": "Uruchom ponownie",
|
||||
"common_loading": "Ładowanie...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – wersja open source",
|
||||
"scanner_scanning": "Skanowanie urządzeń...",
|
||||
"scanner_connecting": "Łączenie...",
|
||||
"scanner_disconnecting": "Odłączanie...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Tryb prywatności włączony",
|
||||
"settings_privacyModeDisabled": "Tryb prywatności wyłączony",
|
||||
"settings_actions": "Działania",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Wyślij rozgłoszenie",
|
||||
"settings_sendAdvertisementSubtitle": "Nadaj obecność teraz",
|
||||
"settings_advertisementSent": "Rozgłoszenie wysłane",
|
||||
@@ -115,13 +119,13 @@
|
||||
"settings_rebootDevice": "Zrestartuj Urządzenie",
|
||||
"settings_rebootDeviceSubtitle": "Zrestartuj urządzenie MeshCore",
|
||||
"settings_rebootDeviceConfirm": "Czy na pewno chcesz zrestartować urządzenie? Będziesz odłączony.",
|
||||
"settings_debug": "Debug",
|
||||
"settings_debug": "Naprawianie błędów",
|
||||
"settings_bleDebugLog": "Dziennik debugowania BLE",
|
||||
"settings_bleDebugLogSubtitle": "Polecenia BLE, odpowiedzi i surowe dane",
|
||||
"settings_appDebugLog": "Dziennik debugowania aplikacji",
|
||||
"settings_appDebugLogSubtitle": "Komunikaty debugowania aplikacji",
|
||||
"settings_about": "O aplikacji",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open w wersji {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -133,7 +137,7 @@
|
||||
"settings_aboutDescription": "Otwartoźródłowy klient Flutter dla urządzeń MeshCore LoRa do sieci mesh.",
|
||||
"settings_infoName": "Nazwa",
|
||||
"settings_infoId": "ID",
|
||||
"settings_infoStatus": "Status",
|
||||
"settings_infoStatus": "Stan",
|
||||
"settings_infoBattery": "Bateria",
|
||||
"settings_infoPublicKey": "Klucz Publiczny",
|
||||
"settings_infoContactsCount": "Liczba kontaktów",
|
||||
@@ -146,7 +150,7 @@
|
||||
"settings_spreadingFactor": "Współczynnik rozpraszania",
|
||||
"settings_codingRate": "Współczynnik kodowania",
|
||||
"settings_txPower": "Moc TX (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerHelper": "0 – 22",
|
||||
"settings_txPowerInvalid": "Nieprawidłowa moc TX (0-22 dBm)",
|
||||
"settings_error": "Błąd: {message}",
|
||||
"@settings_error": {
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Ciemny",
|
||||
"appSettings_language": "Język",
|
||||
"appSettings_languageSystem": "Domyślny systemowy",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languageEn": "Angielski",
|
||||
"appSettings_languageFr": "Francuski",
|
||||
"appSettings_languageEs": "Hiszpański",
|
||||
"appSettings_languageDe": "Niemiecki",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageSl": "Słoweński",
|
||||
"appSettings_languagePt": "Portugalski",
|
||||
"appSettings_languageIt": "Włoski",
|
||||
"appSettings_languageZh": "Chiński",
|
||||
"appSettings_languageSv": "Szwedzki",
|
||||
"appSettings_languageNl": "Niderlandzki",
|
||||
"appSettings_languageSk": "Słoweniština",
|
||||
"appSettings_languageBg": "Българский",
|
||||
"appSettings_notifications": "Powiadomienia",
|
||||
"appSettings_enableNotifications": "Włącz Powiadomienia",
|
||||
"appSettings_enableNotificationsSubtitle": "Otrzymuj powiadomienia o wiadomościach i rozgłoszeniach.",
|
||||
@@ -249,7 +253,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_debugCard": "Debug",
|
||||
"appSettings_debugCard": "Naprawianie błędów",
|
||||
"appSettings_appDebugLogging": "Logowanie Debugowania Aplikacji",
|
||||
"appSettings_appDebugLoggingSubtitle": "Rejestruj komunikaty debugowania aplikacji w celu diagnozowania problemów.",
|
||||
"appSettings_appDebugLoggingEnabled": "Logowanie debugowania aplikacji włączone",
|
||||
@@ -347,11 +351,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Kanał hashtagów",
|
||||
"channels_public": "Publiczny",
|
||||
"channels_private": "Prywatny",
|
||||
"channels_publicChannel": "Kanał publiczny",
|
||||
"channels_privateChannel": "Prywatny kanał",
|
||||
"channels_editChannel": "Edytuj kanał",
|
||||
"channels_muteChannel": "Wycisz kanał",
|
||||
"channels_unmuteChannel": "Wyłącz wyciszenie kanału",
|
||||
@@ -377,7 +378,7 @@
|
||||
"channels_channelName": "Nazwa kanału",
|
||||
"channels_usePublicChannel": "Użyj kanału publicznego",
|
||||
"channels_standardPublicPsk": "Standardowy publiczny PSK",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (heksadecymalne)",
|
||||
"channels_generateRandomPsk": "Wygeneruj losowy klucz PSK",
|
||||
"channels_enterChannelName": "Proszę podać nazwę kanału.",
|
||||
"channels_pskMustBe32Hex": "PSK musi składać się z 32 znaków szesnastkowych.",
|
||||
@@ -398,6 +399,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Kompresja SMAZ",
|
||||
"channels_cyr2latCompression": "Kompresja Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Zastępuje niektóre znaki cyrylicy alfabetem łacińskim podczas wysyłania.",
|
||||
"channels_cyr2latSettingsHeading": "Ustawienia Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Lista zamian",
|
||||
"channels_cyr2latSettingsDscr": "Edytuj konfigurację JSON zamiany znaków",
|
||||
"channels_cyr2latSettingsDialogHint": "Mapa zamian JSON",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Nieprawidłowy JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Dodaj profil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Nazwa profilu",
|
||||
"settings_cyr2latProfileNameEmpty": "Nazwa profilu nie może być pusta",
|
||||
"settings_cyr2latProfileAdded": "Profil dodano pomyślnie",
|
||||
"settings_cyr2latProfileUpdated": "Profil został pomyślnie zaktualizowany",
|
||||
"settings_cyr2latProfileEdit": "Edytuj profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Usuń profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Profil został pomyślnie usunięty",
|
||||
"settings_cyr2latProfileDeleteDscr": "Czy na pewno chcesz usunąć profil \"{name}\"?",
|
||||
"channels_channelUpdated": "Kanał \"{name}\" został zaktualizowany",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -409,7 +426,7 @@
|
||||
"channels_publicChannelAdded": "Kanał publiczny dodany",
|
||||
"channels_sortBy": "Sortuj po",
|
||||
"channels_sortManual": "Ręczna",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "Od A do Z",
|
||||
"channels_sortLatestMessages": "Najnowsze wiadomości",
|
||||
"channels_sortUnread": "Nieprzeczytane",
|
||||
"chat_noMessages": "Brak jeszcze wiadomości",
|
||||
@@ -541,7 +558,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Interfejs wiersza poleceń",
|
||||
"debugFrame_textTypePlain": "Zwykły",
|
||||
"debugFrame_text": "- Tekst: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -889,11 +906,11 @@
|
||||
"path_setPath": "Ustaw Ścieżkę",
|
||||
"repeater_management": "Zarządzanie przekaźnikami",
|
||||
"repeater_managementTools": "Narzędzia Zarządzania",
|
||||
"repeater_status": "Status",
|
||||
"repeater_status": "Stan",
|
||||
"repeater_statusSubtitle": "Wyświetl status przekaźnika, statystyki i sąsiadów.",
|
||||
"repeater_telemetry": "Telemetria",
|
||||
"repeater_telemetrySubtitle": "Wyświetl dane telemetryczne z czujników i statystyki systemu",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Interfejs wiersza poleceń",
|
||||
"repeater_cliSubtitle": "Wyślij polecenia do przekaźnika",
|
||||
"repeater_settings": "Ustawienia",
|
||||
"repeater_settingsSubtitle": "Skonfiguruj parametry przekaźnika",
|
||||
@@ -1002,7 +1019,7 @@
|
||||
"repeater_guestPasswordHelper": "Hasło tylko do odczytu",
|
||||
"repeater_radioSettings": "Ustawienia radia",
|
||||
"repeater_frequencyMhz": "Częstotliwość (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300–2500 MHz",
|
||||
"repeater_txPower": "Moc TX",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Przepustowość",
|
||||
@@ -1069,6 +1086,81 @@
|
||||
},
|
||||
"repeater_confirm": "Potwierdź",
|
||||
"repeater_settingsSaved": "Ustawienia zostały pomyślnie zapisane.",
|
||||
"repeater_rxGain": "Zwiększony zysk RX",
|
||||
"repeater_rxGainHelper": "Większa czułość, większe pobieranie prądu (dotyczy tylko SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Zaktualizuj zwiększone zyski RX",
|
||||
"repeater_multiAcks": "Wielokrotne potwierdzenia odbioru",
|
||||
"repeater_multiAcksSubtitle": "Potwierdź odbiór wiadomości za pomocą różnych ścieżek, aby zapewnić lepszą dostawę.",
|
||||
"repeater_refreshMultiAcks": "Odświeżanie wielokrotnych potwierdzeń",
|
||||
"repeater_networkHealth": "Stan sieci",
|
||||
"repeater_loopDetect": "Wykrywanie pętli",
|
||||
"repeater_loopDetectHelper": "Wysyłaj pakiety, które wyglądają jak pętle routingu.",
|
||||
"repeater_loopDetectOff": "Z domu",
|
||||
"repeater_loopDetectMinimal": "Minimalny",
|
||||
"repeater_loopDetectModerate": "Umiarkowany",
|
||||
"repeater_loopDetectStrict": "Surowe",
|
||||
"repeater_dutyCycle": "Cykl pracy",
|
||||
"repeater_dutyCycleHelper": "Maksymalny procent czasu, który stacja może wykorzystać.",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informacje o operatorze",
|
||||
"repeater_ownerInfoHelper": "Publiczne metadane dla tego urządzenia powielającego",
|
||||
"repeater_refreshOwnerInfo": "Aktualizacja danych dotyczących operatora",
|
||||
"repeater_floodMax": "Maksymalna liczba skoków podczas powodzi",
|
||||
"repeater_floodMaxHelper": "Maksymalna liczba pakietów, które mogą przemieszczać się w jednym strumieniu (0-64)",
|
||||
"repeater_advancedSettings": "Zaawansowany",
|
||||
"repeater_advancedSettingsSubtitle": "Regulowane pokrętła dla doświadczonych operatorów",
|
||||
"repeater_pathHashMode": "Tryb haszujący ścieżkę",
|
||||
"repeater_pathHashModeHelper": "Bity wykorzystywane do kodowania identyfikatora tego urządzenia w tagach ścieżek/detekcji pętli. 0=1 bity (256 identyfikatorów, do 64 skoków), 1=2 bity (65 000 identyfikatorów, do 32 skoków), 2=3 bity (1 600 000 identyfikatorów, do 21 skoków). Wersje 1.13 i wcześniejsze nie obsługują ścieżek wielobitowych – wykrywają tylko jedną, gdy sieć jest w wersji 1.14 lub nowszej.",
|
||||
"repeater_txDelay": "Opóźnienie w Flood, TX",
|
||||
"repeater_txDelayHelper": "Ustawienie odstępu dla ruchu związanego z powodzią, jako mnożnik czasu przesyłania pakietu (0-2, domyślnie 0,5). Wyższe wartości oznaczają mniejszą liczbę kolizji, ale wolniejszą prędkość przesyłania.",
|
||||
"repeater_directTxDelay": "Bezpośrednie opóźnienie sygnału TX",
|
||||
"repeater_directTxDelayHelper": "Ustawienie odstępu dla ruchu bezpośredniego (bez rozgłaszania), jako mnożnika czasu przesyłania pakietu (0-2, domyślnie 0,3).",
|
||||
"repeater_intThresh": "Próg zakłóceń",
|
||||
"repeater_intThreshHelper": "Próg został ustawiony na poziom szumów w radiu, dzięki czemu odrzuca sygnały zakłócające powyżej tego poziomu. 0 oznacza wyłączenie – ustaw tylko wtedy, gdy występują błędy odbierania w szumie.",
|
||||
"repeater_agcResetInterval": "Interwał resetowania AGC",
|
||||
"repeater_agcResetIntervalHelper": "Jak często należy resetować automatyczną regulację głośności radia, aby odzyskać z sytuacji, w której głośność jest ustawiona na stałe. Ustawienie \"0\" dezaktywuje okresowe resetowanie.",
|
||||
"repeater_actionsTitle": "Działania",
|
||||
"repeater_sendAdvert": "Wysłać reklamę dotyczącą powodzi",
|
||||
"repeater_sendAdvertSubtitle": "Wyemituj reklamę dotyczącą powodzi w sieci.",
|
||||
"repeater_sendAdvertZeroHop": "Wysłać reklamę bez pośrednictwa",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Napisz reklamę, która będzie transmitowana bezpośrednio (bez powtarzania).",
|
||||
"repeater_clockSync": "Synchronizuj zegar",
|
||||
"repeater_clockSyncSubtitle": "Przekaż czas z telefonu do urządzenia powielającego",
|
||||
"repeater_actionSucceeded": "{action} zakończyło się pomyślnie",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Ustawienia zapisane – uruchom ponownie repeater, aby zastosować zmiany.",
|
||||
"repeater_settingsPartialFailure": "Niektóre ustawienia nie zostały zaimplementowane: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Błąd zapisu ustawień: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1080,11 +1172,9 @@
|
||||
"repeater_refreshBasicSettings": "Odśwież Podstawowe Ustawienia",
|
||||
"repeater_refreshRadioSettings": "Odśwież ustawienia radia",
|
||||
"repeater_refreshTxPower": "Odśwież moc TX",
|
||||
"repeater_refreshLocationSettings": "Odśwież Ustawienia Lokalizacji",
|
||||
"repeater_refreshPacketForwarding": "Odśwież trasowanie pakietów",
|
||||
"repeater_refreshGuestAccess": "Odśwież dostęp gościa",
|
||||
"repeater_refreshPrivacyMode": "Odśwież Tryb Prywatności",
|
||||
"repeater_refreshAdvertisementSettings": "Odśwież ustawienia rozgłoszeń",
|
||||
"repeater_refreshed": "{label} odświeżone",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1202,6 +1292,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Wejście cyfrowe",
|
||||
"telemetry_digitalOutputLabel": "Wyjście cyfrowe",
|
||||
"telemetry_analogInputLabel": "Wejście analogowe",
|
||||
"telemetry_analogOutputLabel": "Wyjście analogowe",
|
||||
"telemetry_genericLabel": "Czujnik ogólny",
|
||||
"telemetry_luminosityLabel": "Jasność",
|
||||
"telemetry_presenceLabel": "Obecność",
|
||||
"telemetry_humidityLabel": "Wilgotność",
|
||||
"telemetry_accelerometerLabel": "Akcelerometr",
|
||||
"telemetry_pressureLabel": "Ciśnienie",
|
||||
"telemetry_altitudeLabel": "Wysokość",
|
||||
"telemetry_frequencyLabel": "Częstotliwość",
|
||||
"telemetry_percentageLabel": "Procent",
|
||||
"telemetry_concentrationLabel": "Stężenie",
|
||||
"telemetry_powerLabel": "Moc",
|
||||
"telemetry_distanceLabel": "Odległość",
|
||||
"telemetry_energyLabel": "Energia",
|
||||
"telemetry_directionLabel": "Kierunek",
|
||||
"telemetry_timeLabel": "Czas",
|
||||
"telemetry_gyrometerLabel": "Żyrometr",
|
||||
"telemetry_colourLabel": "Kolor",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Przełącznik",
|
||||
"telemetry_polylineLabel": "Polilinia",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Liczba żądań",
|
||||
"telemetry_error": "Nie udało się pobrać danych",
|
||||
"telemetry_noData": "Brak dostępnych danych telemetrycznych.",
|
||||
"telemetry_channelTitle": "Kanał {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1216,7 +1343,7 @@
|
||||
"telemetry_mcuTemperatureLabel": "Temperatura MCU",
|
||||
"telemetry_temperatureLabel": "Temperatura",
|
||||
"telemetry_currentLabel": "Prąd",
|
||||
"telemetry_batteryValue": "{percent}% / {volts}V",
|
||||
"telemetry_batteryValue": "{percent}% / {volts} W",
|
||||
"@telemetry_batteryValue": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
@@ -1357,7 +1484,7 @@
|
||||
"listFilter_sortBy": "Sortuj po",
|
||||
"listFilter_latestMessages": "Najnowsze wiadomości",
|
||||
"listFilter_heardRecently": "Słyszano niedawno",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "Od A do Z",
|
||||
"listFilter_filters": "Filtry",
|
||||
"listFilter_all": "Wszystko",
|
||||
"listFilter_users": "Użytkownicy",
|
||||
@@ -1472,7 +1599,7 @@
|
||||
"community_createDesc": "Utwórz nową społeczność i udostępnij za pomocą kodu QR.",
|
||||
"community_title": "Społeczność",
|
||||
"community_create": "Utwórz Społeczność",
|
||||
"common_ok": "OK",
|
||||
"common_ok": "Dobrze",
|
||||
"community_join": "Dołącz",
|
||||
"community_joinTitle": "Dołącz do społeczności",
|
||||
"community_joinConfirmation": "Czy chcesz dołączyć do społeczności \"{name}\"?",
|
||||
@@ -2049,6 +2176,9 @@
|
||||
"translation_enableTitle": "Włącz tłumaczenie",
|
||||
"translation_enableSubtitle": "Tłumaczenie otrzymywanych wiadomości oraz umożliwienie tłumaczenia przed wysłaniem.",
|
||||
"translation_composerSubtitle": "Kontroluje domyślny stan ikony tłumaczenia w edytorze.",
|
||||
"translation_autoIncomingTitle": "Automatycznie tłumacz wiadomości",
|
||||
"translation_autoIncomingSubtitle": "Automatycznie tłumaczy wiadomości do powiadomień oraz do czatów lub kanałów.",
|
||||
"translation_translateMessage": "Przetłumacz wiadomość",
|
||||
"translation_targetLanguage": "Język docelowy",
|
||||
"translation_useAppLanguage": "Użyj języka aplikacji",
|
||||
"translation_downloadedModelLabel": "Pobudowany model",
|
||||
@@ -2104,5 +2234,255 @@
|
||||
"repeater_guestTools": "Narzędzia dla gości",
|
||||
"repeater_guest": "Informacje dotyczące urządzenia powtarzającego",
|
||||
"room_guest": "Informacje o serwerze",
|
||||
"settings_multiAck": "Wielokrotne potwierdzenia odbioru"
|
||||
"repeater_getCategory": "Uzyskaj wartości",
|
||||
"repeater_powerMgmt": "Zarządzanie energią",
|
||||
"repeater_sensors": "Czujniki",
|
||||
"repeater_cliHelpPowerOff": "Wyłącza urządzenie. (oczekiwanie na brak reakcji)",
|
||||
"repeater_cliHelpClkReboot": "Przywraca zegar do znanego punktu odniesienia i resetuje urządzenie.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Wysyła reklamę, która dociera bezpośrednio do sąsiadów (bez pośrednictwa).",
|
||||
"repeater_cliHelpStartOta": "Rozpoczyna aktualizację oprogramowania przez sieć (bezpośrednio z urządzenia).",
|
||||
"repeater_cliHelpTime": "Ustawia zegar urządzenia na określone sekundy od epoki Unix. Zegar nie może się cofać.",
|
||||
"repeater_cliHelpBoard": "Wyświetla informacje o producencie płyty głównej / identyfikator sprzętu.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Wysyła żądanie wykrywania sąsiednich węzłów. (Działa tylko w urządzeniu powielającym sygnał)",
|
||||
"repeater_cliHelpPowersaving": "Pokazuje, czy tryb oszczędzania energii jest włączony, czy wyłączony.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Umożliwia lub wyłącza tryb oszczędzania energii (jeśli jest obsługiwany).",
|
||||
"repeater_cliHelpErase": "(Dla urządzeń) Formatuje system plików urządzenia. Usuwa wszystkie ustawienia i kontakty.",
|
||||
"repeater_cliHelpSetDutyCycle": "Ustawia maksymalny dopuszczalny cykl przesyłania w procentach (1-100). Automatycznie dostosowuje współczynnik czasu przesyłania.",
|
||||
"repeater_cliHelpSetPrvKey": "(Dla urządzeń) Zastępuje klucz prywatny identyfikujący urządzenie. Wymagana jest ponowna uruchomienie urządzenia, aby zastosować zmianę. Generuje nowy klucz publiczny.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(tylko SX126x) Włącza wzmocniony sygnał RX, co poprawia czułość przy wyższym poborze prądu.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Określa ciąg znaków zawierający dane kontaktowe właściciela, który znajduje się w ogłoszeniach. Użyj '|' jako separatora wierszy.",
|
||||
"repeater_cliHelpSetPathHashMode": "Ustawia tryb haszowania ścieżki. 0 = stary, 1 = standardowy, 2 = restrykcyjny. Wpływa na sposób dopasowywania ścieżek routingu.",
|
||||
"repeater_cliHelpSetLoopDetect": "Ustawia czułość detekcji pętli routingu: wyłączona, minimalna, umiarkowana lub rygorystyczna.",
|
||||
"repeater_cliHelpSetFreq": "(Dla urządzeń szeregowych) Szybko ustawia tylko częstotliwość. Wymagana ponowna uruchomienie. Zaleca się użycie opcji \"ustawienie radia\" w celu ustawienia wszystkich parametrów radia.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Tylko most ESPNow) Ustawia kanał WiFi (od 1 do 14), który jest wykorzystywany przez most.",
|
||||
"repeater_cliHelpGetName": "Wyświetla nazwę skonfigurowanego węzła.",
|
||||
"repeater_cliHelpGetRole": "Pokazuje rolę oprogramowania (np. repeater, serwer dla pokoju).",
|
||||
"repeater_cliHelpGetPublicKey": "Wyświetla publiczny klucz urządzenia.",
|
||||
"repeater_cliHelpGetPrvKey": "(Tylko dla serialu) Wyświetla prywatny klucz urządzenia. Traktuj go jako poufny.",
|
||||
"repeater_cliHelpGetRepeat": "Pokazuje, czy funkcja przekierowywania pakietów (funkcja repeatera) jest włączona lub wyłączona.",
|
||||
"repeater_cliHelpGetTx": "Pokazuje aktualną moc transmisji w dBm.",
|
||||
"repeater_cliHelpGetFreq": "Pokazuje skonfigurowaną częstotliwość radiową w MHz.",
|
||||
"repeater_cliHelpGetRadio": "Wyświetla pełne parametry radia: częstotliwość, szerokość pasma, współczynnik modulacji, stopień kodowania.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(tylko SX126x) Wyświetla stan wzmocnienia sygnału RX.",
|
||||
"repeater_cliHelpGetAf": "Pokazuje aktualny współczynnik czasu emisji.",
|
||||
"repeater_cliHelpGetDutyCycle": "Pokazuje aktualny dopuszczalny cykl pracy w procentach.",
|
||||
"repeater_cliHelpGetIntThresh": "Pokazuje próg zakłóceń kanału w dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Pokazuje interwał resetowania AGC w sekundach.",
|
||||
"repeater_cliHelpGetMultiAcks": "Pokazuje, czy tryb podwójnego potwierdzania jest włączony (1) czy wyłączony (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Pokazuje, czy dostęp dla gości jest ograniczony do odczytu tylko.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Pokazuje czas trwania lokalnej reklamy w minutach.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Pokazuje interwał reklamowy dotyczący powodzi w godzinach.",
|
||||
"repeater_cliHelpGetGuestPassword": "Wyświetla ustawione hasło dla gościa.",
|
||||
"repeater_cliHelpGetLat": "Pokazuje ustawioną szerokość geograficzną.",
|
||||
"repeater_cliHelpGetLon": "Pokazuje ustawioną długość geograficzną.",
|
||||
"repeater_cliHelpGetRxDelay": "Pokazuje bazową wartość opóźnienia RX.",
|
||||
"repeater_cliHelpGetTxDelay": "Pokazuje współczynnik opóźnienia transmisji w trybie zalewowym.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Pokazuje współczynnik opóźnienia w trybie bezpośrednim.",
|
||||
"repeater_cliHelpGetFloodMax": "Pokazuje maksymalną liczbę skoków spowodowanych powodzią.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Wyświetla ciąg znaków zawierający dane kontaktowe właściciela.",
|
||||
"repeater_cliHelpGetPathHashMode": "Pokazuje tryb haszujący ścieżkę (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Pokazuje czułość detekcji pętli.",
|
||||
"repeater_cliHelpGetAcl": "(Tylko dla seriali) Wyświetla wpisy kontroli dostępu w repeaterze.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Pokazuje, czy most jest włączony.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Pokazuje opóźnienie mostu w milisekundach.",
|
||||
"repeater_cliHelpGetBridgeSource": "Pokazuje, czy most odbiera pakiety RX lub TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Tylko interfejs RS232) Wyświetla prędkość transmisji na interfejsie RS232.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Tylko moduł ESPNow) Wyświetla kanał WiFi modułu.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Tylko most ESPNow) Wyświetla sekret udostępniony przez most.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(tylko dla NRF52) Wyświetla wersję bootloadera.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Pokazuje wzmacniacz ADC (skalowanie napięcia baterii).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Informuje, czy rada nadzorcza posiada wsparcie w zakresie zarządzania energią.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Pokazuje aktualne źródło zasilania: zewnętrzne lub bateryjne.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Pokazuje najnowsze przyczyny resetowania i wyłączania.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Pokazuje napięcie baterii podczas uruchamiania systemu w milivoltach (mV).",
|
||||
"repeater_cliHelpSensorGet": "Odczytuje ustawienie czujnika zdefiniowane za pomocą klawisza.",
|
||||
"repeater_cliHelpSensorSet": "Tworzy niestandardowe ustawienia dla czujnika.",
|
||||
"repeater_cliHelpSensorList": "Wyświetla wszystkie ustawienia dla niestandardowych czujników, podzielone na strony, z opcjonalnym indeksem początkowym.",
|
||||
"repeater_cliHelpRegionDefault": "Pokazuje aktualny domyślny zakres regionu.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Ustawia domyślny zakres regionu. Użyj wartości \"<null>\", aby go zresetować.",
|
||||
"repeater_cliHelpRegionListAllowed": "Wymienia regiony, w których dopuszczony jest ruch związany z powodzami.",
|
||||
"repeater_cliHelpRegionListDenied": "Wymienia regiony, w których ruch związany z powodziami jest ograniczony.",
|
||||
"repeater_cliHelpStatsPackets": "(Tylko dla serialu) Prezentuje statystyki na poziomie pakietów.",
|
||||
"repeater_cliHelpStatsRadio": "(Tylko serial) Prezentuje statystyki dotyczące nadawania radiowego.",
|
||||
"repeater_cliHelpStatsCore": "(Tylko wersja serialowa) Wyświetla podstawowe statystyki o oprogramowaniu.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Wielokrotne potwierdzenia odbioru",
|
||||
"map_sharedAt": "Udostępnione",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Wybór przeszkody",
|
||||
"losBlockedSpotsTitle": "Zablokowane miejsca",
|
||||
"losBlockedSpotsHint": "Kliknij zablokowane miejsce, aby je zaznaczyć na mapie.",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"chat_newMessages": "Nowe wiadomości",
|
||||
"settings_companionDebugLogSubtitle": "Polecenia, odpowiedzi i surowe dane związane z protokołami BLE/TCP/USB",
|
||||
"chat_markAsUnread": "Oznacz jako nieprzeczytane",
|
||||
"settings_companionDebugLog": "Log debugowania (dla pomocy w rozwiązywaniu problemów)",
|
||||
"repeater_chanUtil": "Wykorzystanie kanału",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "Wysłane",
|
||||
"messageStatus_delivered": "Dostarczone",
|
||||
"messageStatus_pending": "Wysyłanie",
|
||||
"common_undo": "Wycofaj",
|
||||
"messageStatus_failed": "Nie udało się wysłać",
|
||||
"messageStatus_repeated": "Usłyszałem to wielokrotnie",
|
||||
"contacts_moreOptions": "Więcej opcji",
|
||||
"contacts_searchOpen": "Wyszukaj kontakty",
|
||||
"contacts_searchClose": "Zaawansowane wyszukiwanie",
|
||||
"routing_title": "Planowanie tras",
|
||||
"routing_modeAuto": "Samochód",
|
||||
"routing_modeFlood": "Powódź",
|
||||
"routing_modeManual": "Instrukcja obsługi",
|
||||
"routing_modeAutoHint": "Automatycznie wybiera najpopularniejszą ścieżkę, a w przypadku braku znanej, przechodzi do trybu \"przepływu\".",
|
||||
"routing_modeFloodHint": "Transmisje za pośrednictwem każdego repeatera. Najbardziej niezawodna metoda, ale zużywa więcej czasu transmisji.",
|
||||
"routing_modeManualHint": "Zawsze prowadzi dokładnie po trasie, którą określiłeś.",
|
||||
"routing_currentRoute": "Obecna trasa",
|
||||
"routing_directNoHops": "Bezpośrednio – bez pośrednictwa repeaterów",
|
||||
"routing_noPathYet": "Na razie nie ma żadnej ścieżki. Komunikacja trwa do momentu, gdy zostanie odkryta trasa.",
|
||||
"routing_floodBroadcast": "Transmisja za pośrednictwem każdego urządzenia powielającego",
|
||||
"routing_editPath": "Edytuj ścieżkę",
|
||||
"routing_forgetPath": "Zapomnij o ścieżce",
|
||||
"routing_knownPaths": "Znane trasy",
|
||||
"routing_knownPathsHint": "Wybierz ścieżkę, aby przełączyć się na nią.",
|
||||
"routing_inUse": "W użyciu",
|
||||
"routing_qualityStrong": "Silny pierwszy skok",
|
||||
"routing_qualityGood": "Świetny początek",
|
||||
"routing_qualityFair": "Świetny pierwszy krzak",
|
||||
"routing_qualityWorked": "Zostało dostarczone",
|
||||
"routing_qualityFlood": "Usłyszano dzięki doniesieniom",
|
||||
"routing_qualityUntested": "Nieużywany",
|
||||
"routing_lastWorked": "pracował {when}",
|
||||
"routing_neverWorked": "nigdy nie zostało potwierdzone",
|
||||
"routing_floodDelivery": "Dostawa w przypadku powodzi",
|
||||
"pathEditor_title": "Stworzenie ścieżki",
|
||||
"pathEditor_hopCounter": "{count} z 64 rodzajów chmielu",
|
||||
"pathEditor_noHops": "Na razie nie dodano żadnych chmielu. Aby dodać je w odpowiedniej kolejności, kliknij w odpowiednie przyciski poniżej, lub zapisz przepis bez chmielu, aby wysłać go bezpośrednio.",
|
||||
"pathEditor_addHops": "Dodawaj chmiel zgodnie z kolejnością.",
|
||||
"pathEditor_searchRepeaters": "Funkcje powtarzania",
|
||||
"pathEditor_advancedHex": "Zaawansowane: ścieżka w formacie szesnastkowym",
|
||||
"pathEditor_hexLabel": "Prefiksy heksadecymalne",
|
||||
"pathEditor_hexHelper": "Dwa znaki szesnastkowe na każdym kroku, oddzielone przecinkami",
|
||||
"pathEditor_invalidTokens": "Nieprawidłowe: {tokens}",
|
||||
"pathEditor_tooManyHops": "Maksymalnie 64 hopów",
|
||||
"pathEditor_usePath": "Użyj tej ścieżki.",
|
||||
"pathEditor_removeHop": "Usuń dziką psiankę",
|
||||
"pathEditor_unknownHop": "Nieznany repeater",
|
||||
"map_zoomIn": "Przybliż",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Przybliż z powrotem",
|
||||
"map_centerMap": "Mapa centrum",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth wymaga przeglądarki Chromium.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS potwierdzone",
|
||||
"pathTrace_legendInferred": "Wywnioskowana pozycja"
|
||||
}
|
||||
|
||||
+410
-30
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Remover",
|
||||
"common_enable": "Ativar",
|
||||
"common_disable": "Desativar",
|
||||
"common_autoRefresh": "Atualização automática",
|
||||
"common_interval": "Intervalo",
|
||||
"common_reboot": "Reiniciar",
|
||||
"common_loading": "Carregando...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore: Versão aberta",
|
||||
"scanner_scanning": "Procurando por dispositivos...",
|
||||
"scanner_connecting": "Conectando...",
|
||||
"scanner_disconnecting": "Desconectando...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Modo de privacidade ativado",
|
||||
"settings_privacyModeDisabled": "Modo de privacidade desativado",
|
||||
"settings_actions": "Ações",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Enviar Publicidade",
|
||||
"settings_sendAdvertisementSubtitle": "Presença de transmissão agora",
|
||||
"settings_advertisementSent": "Anúncio enviado",
|
||||
@@ -133,12 +137,12 @@
|
||||
"settings_aboutDescription": "Um cliente Flutter de código aberto para dispositivos de rede mesh LoRa Core da MeshCore.",
|
||||
"settings_infoName": "Nome",
|
||||
"settings_infoId": "ID",
|
||||
"settings_infoStatus": "Status",
|
||||
"settings_infoStatus": "Estado",
|
||||
"settings_infoBattery": "Bateria",
|
||||
"settings_infoPublicKey": "Chave Pública",
|
||||
"settings_infoContactsCount": "Número de Contatos",
|
||||
"settings_infoChannelCount": "Número do Canal",
|
||||
"settings_presets": "Presets",
|
||||
"settings_presets": "Configurações pré-definidas",
|
||||
"settings_frequency": "Frequência (MHz)",
|
||||
"settings_frequencyHelper": "300,0 - 2500,0",
|
||||
"settings_frequencyInvalid": "Frequência inválida (300-2500 MHz)",
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Escuro",
|
||||
"appSettings_language": "Idioma",
|
||||
"appSettings_languageSystem": "Padrão do sistema",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languageEn": "Inglês",
|
||||
"appSettings_languageFr": "Francês",
|
||||
"appSettings_languageEs": "Espanhol",
|
||||
"appSettings_languageDe": "Alemão",
|
||||
"appSettings_languagePl": "Polonês",
|
||||
"appSettings_languageSl": "Esloveno",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageZh": "Chinês",
|
||||
"appSettings_languageSv": "Sueco",
|
||||
"appSettings_languageNl": "Holandês",
|
||||
"appSettings_languageSk": "Esloveno",
|
||||
"appSettings_languageBg": "Búlgaro",
|
||||
"appSettings_notifications": "Notificações",
|
||||
"appSettings_enableNotifications": "Ativar Notificações",
|
||||
"appSettings_enableNotificationsSubtitle": "Receber notificações para mensagens e anúncios",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Canal com hashtag",
|
||||
"channels_public": "Público",
|
||||
"channels_private": "Privado",
|
||||
"channels_publicChannel": "Canal público",
|
||||
"channels_privateChannel": "Canal privado",
|
||||
"channels_editChannel": "Editar canal",
|
||||
"channels_muteChannel": "Silenciar canal",
|
||||
"channels_unmuteChannel": "Ativar canal",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Compressão SMAZ",
|
||||
"channels_cyr2latCompression": "Compressão Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Substitui alguns caracteres cirílicos por caracteres latinos ao enviar.",
|
||||
"channels_cyr2latSettingsHeading": "Configuração do Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Lista de substituições",
|
||||
"channels_cyr2latSettingsDscr": "Editar a configuração JSON de substituição de caracteres",
|
||||
"channels_cyr2latSettingsDialogHint": "Mapa de substituições JSON",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "JSON incorreto: {error}",
|
||||
"settings_cyr2latProfileAdd": "Adicionar perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Nome do perfil",
|
||||
"settings_cyr2latProfileNameEmpty": "O nome do perfil não pode estar vazio",
|
||||
"settings_cyr2latProfileAdded": "Perfil adicionado com sucesso",
|
||||
"settings_cyr2latProfileUpdated": "Perfil atualizado com sucesso",
|
||||
"settings_cyr2latProfileEdit": "Editar perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Eliminar perfil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Perfil eliminado com sucesso",
|
||||
"settings_cyr2latProfileDeleteDscr": "Tem a certeza de que deseja eliminar o perfil \"{name}\"?",
|
||||
"channels_channelUpdated": "Canal \"{name}\" atualizado",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Canal público adicionado",
|
||||
"channels_sortBy": "Ordenar por",
|
||||
"channels_sortManual": "Manual",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "De A a Z",
|
||||
"channels_sortLatestMessages": "Últimas mensagens",
|
||||
"channels_sortUnread": "Não lido",
|
||||
"chat_noMessages": "Ainda não existem mensagens.",
|
||||
@@ -504,7 +521,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_timestamp": "- Timestamp: {timestamp}",
|
||||
"debugFrame_timestamp": "- Carimbo: {timestamp}",
|
||||
"@debugFrame_timestamp": {
|
||||
"placeholders": {
|
||||
"timestamp": {
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Interface de Linha de Comando",
|
||||
"debugFrame_textTypePlain": "Simples",
|
||||
"debugFrame_text": "- Texto: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "O histórico está cheio. Remova entradas para adicionar novas.",
|
||||
"chat_hopSingular": "pule",
|
||||
"chat_hopPlural": "salta",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{salto} other{saltos}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -819,7 +836,7 @@
|
||||
"login_autoUseSavedPath": "Auto (usar caminho salvo)",
|
||||
"login_forceFloodMode": "Modo de Inundação Forçado",
|
||||
"login_managePaths": "Gerenciar Caminhos",
|
||||
"login_login": "Login",
|
||||
"login_login": "Entrar",
|
||||
"login_attempt": "Tentar {current}/{max}",
|
||||
"@login_attempt": {
|
||||
"placeholders": {
|
||||
@@ -879,11 +896,11 @@
|
||||
"path_setPath": "Definir Caminho",
|
||||
"repeater_management": "Gerenciamento de Repetidor",
|
||||
"repeater_managementTools": "Ferramentas de Gerenciamento",
|
||||
"repeater_status": "Status",
|
||||
"repeater_status": "Estado",
|
||||
"repeater_statusSubtitle": "Visualizar status do repetidor, estatísticas e vizinhos.",
|
||||
"repeater_telemetry": "Telemetria",
|
||||
"repeater_telemetrySubtitle": "Visualizar telemetria de sensores e estatísticas do sistema",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Interface de Linha de Comando",
|
||||
"repeater_cliSubtitle": "Enviar comandos ao repetidor",
|
||||
"repeater_settings": "Configurações",
|
||||
"repeater_settingsSubtitle": "Configurar parâmetros do repetidor",
|
||||
@@ -993,7 +1010,7 @@
|
||||
"repeater_radioSettings": "Configurações de Rádio",
|
||||
"repeater_frequencyMhz": "Frequência (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_txPower": "TX Power",
|
||||
"repeater_txPower": "Energia da TX",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Largura de banda",
|
||||
"repeater_spreadingFactor": "Fator de Dispersão",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Confirmar",
|
||||
"repeater_settingsSaved": "Configurações salvas com sucesso",
|
||||
"repeater_rxGain": "Aumento do ganho do RX",
|
||||
"repeater_rxGainHelper": "Maior sensibilidade, maior consumo de corrente (apenas para SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Reforçar o ganho do RX",
|
||||
"repeater_multiAcks": "Múltiplas respostas de confirmação",
|
||||
"repeater_multiAcksSubtitle": "Reconheça mensagens através de múltiplos caminhos para uma melhor entrega.",
|
||||
"repeater_refreshMultiAcks": "Reiniciar múltiplas confirmações",
|
||||
"repeater_networkHealth": "Saúde da rede",
|
||||
"repeater_loopDetect": "Detecção de loops",
|
||||
"repeater_loopDetectHelper": "Envie pacotes que pareçam ser loops de roteamento.",
|
||||
"repeater_loopDetectOff": "Desligado",
|
||||
"repeater_loopDetectMinimal": "Mínimo",
|
||||
"repeater_loopDetectModerate": "Moderado",
|
||||
"repeater_loopDetectStrict": "Rígido",
|
||||
"repeater_dutyCycle": "Ciclo de operação",
|
||||
"repeater_dutyCycleHelper": "Porcentagem máxima de tempo de transmissão",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informações sobre o operador",
|
||||
"repeater_ownerInfoHelper": "Metadados públicos para este repetidor",
|
||||
"repeater_refreshOwnerInfo": "Atualizar informações do operador",
|
||||
"repeater_floodMax": "Número máximo de saltos em caso de inundação",
|
||||
"repeater_floodMaxHelper": "Número máximo de saltos que um pacote de inundação pode percorrer (0-64)",
|
||||
"repeater_advancedSettings": "Avançado",
|
||||
"repeater_advancedSettingsSubtitle": "Controles de ajuste para operadores experientes",
|
||||
"repeater_pathHashMode": "Modo de hash de caminho",
|
||||
"repeater_pathHashModeHelper": "Bytes utilizados para codificar o ID deste repetidor nas tags de caminho/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). As versões 1.13 e anteriores do firmware não suportam caminhos multi-byte — apenas funcionam uma vez após a ativação da rede (a partir da versão 1.14+).",
|
||||
"repeater_txDelay": "Atraso na entrega em Flood, TX",
|
||||
"repeater_txDelayHelper": "Ajuste de espaçamento para tráfego de inundações, como um multiplicador do tempo de transmissão (0-2, padrão 0,5). Quanto maior, menos colisões, mas uma entrega mais lenta.",
|
||||
"repeater_directTxDelay": "Atraso direto no sinal TX",
|
||||
"repeater_directTxDelayHelper": "Intervalo de retransmissão para tráfego direto (não em enxame), como um multiplicador do tempo de transmissão do pacote (0-2, padrão 0,3).",
|
||||
"repeater_intThresh": "Limite de interferência",
|
||||
"repeater_intThreshHelper": "O limite é definido para o nível de ruído do rádio, de modo que ele rejeite interferências acima desse nível. 0 desativa – aumente apenas se você observar erros de RX em uma faixa de frequência com ruído.",
|
||||
"repeater_agcResetInterval": "Intervalo de reinicialização do AGC",
|
||||
"repeater_agcResetIntervalHelper": "Com que frequência redefinir o controle automático de ganho do rádio para recuperar de um estado em que o ganho está travado. Segundos, reduzidos a um múltiplo de 4. 0 desativa as redefinições periódicas.",
|
||||
"repeater_actionsTitle": "Ações",
|
||||
"repeater_sendAdvert": "Envie anúncio sobre inundações",
|
||||
"repeater_sendAdvertSubtitle": "Transmita um anúncio sobre inundações pela rede.",
|
||||
"repeater_sendAdvertZeroHop": "Enviar anúncio sem intermediários",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Transmita um anúncio de um único salto (sem repetição).",
|
||||
"repeater_clockSync": "Sincronize o relógio agora",
|
||||
"repeater_clockSyncSubtitle": "Envie a hora do seu telefone para o repetidor.",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Configurações salvas — reinicie o repetidor para aplicar as alterações.",
|
||||
"repeater_settingsPartialFailure": "Algumas configurações falharam: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Erro ao salvar as configurações: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Atualizar Configurações Básicas",
|
||||
"repeater_refreshRadioSettings": "Atualizar Configurações de Rádio",
|
||||
"repeater_refreshTxPower": "Atualizar TX de energia",
|
||||
"repeater_refreshLocationSettings": "Atualizar Configurações de Localização",
|
||||
"repeater_refreshPacketForwarding": "Atualizar Roteamento de Pacotes",
|
||||
"repeater_refreshGuestAccess": "Atualizar Acesso de Convidados",
|
||||
"repeater_refreshPrivacyMode": "Atualizar Modo Privacidade",
|
||||
"repeater_refreshAdvertisementSettings": "Atualizar Configurações do Anúncio",
|
||||
"repeater_refreshed": "{label} atualizado",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Entrada digital",
|
||||
"telemetry_digitalOutputLabel": "Saída digital",
|
||||
"telemetry_analogInputLabel": "Entrada analógica",
|
||||
"telemetry_analogOutputLabel": "Saída analógica",
|
||||
"telemetry_genericLabel": "Sensor genérico",
|
||||
"telemetry_luminosityLabel": "Luminosidade",
|
||||
"telemetry_presenceLabel": "Presença",
|
||||
"telemetry_humidityLabel": "Humidade",
|
||||
"telemetry_accelerometerLabel": "Acelerómetro",
|
||||
"telemetry_pressureLabel": "Pressão",
|
||||
"telemetry_altitudeLabel": "Altitude",
|
||||
"telemetry_frequencyLabel": "Frequência",
|
||||
"telemetry_percentageLabel": "Percentagem",
|
||||
"telemetry_concentrationLabel": "Concentração",
|
||||
"telemetry_powerLabel": "Potência",
|
||||
"telemetry_distanceLabel": "Distância",
|
||||
"telemetry_energyLabel": "Energia",
|
||||
"telemetry_directionLabel": "Direção",
|
||||
"telemetry_timeLabel": "Hora",
|
||||
"telemetry_gyrometerLabel": "Girómetro",
|
||||
"telemetry_colourLabel": "Cor",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Interruptor",
|
||||
"telemetry_polylineLabel": "Polilinha",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Número de solicitações",
|
||||
"telemetry_error": "Não foi possível obter os dados",
|
||||
"telemetry_noData": "Não estão disponíveis dados de telemetria.",
|
||||
"telemetry_channelTitle": "Canal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Ordenar por",
|
||||
"listFilter_latestMessages": "Últimas mensagens",
|
||||
"listFilter_heardRecently": "Ouvido recentemente",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "De A a Z",
|
||||
"listFilter_filters": "Filtros",
|
||||
"listFilter_all": "Tudo",
|
||||
"listFilter_users": "Usuários",
|
||||
@@ -1461,7 +1588,7 @@
|
||||
},
|
||||
"community_title": "Comunidade",
|
||||
"community_createDesc": "Crie uma nova comunidade e compartilhe via código QR.",
|
||||
"common_ok": "OK",
|
||||
"common_ok": "Tudo bem",
|
||||
"community_create": "Criar Comunidade",
|
||||
"community_join": "Junte-se",
|
||||
"community_joinTitle": "Junte-se à Comunidade",
|
||||
@@ -2012,6 +2139,9 @@
|
||||
"translation_enableTitle": "Ativar a tradução",
|
||||
"translation_title": "Tradução",
|
||||
"translation_composerSubtitle": "Controla o estado padrão do ícone de tradução do compositor.",
|
||||
"translation_autoIncomingTitle": "Traduzir mensagens automaticamente",
|
||||
"translation_autoIncomingSubtitle": "Traduz automaticamente mensagens para notificações e para chats ou canais.",
|
||||
"translation_translateMessage": "Traduzir mensagem",
|
||||
"translation_targetLanguage": "Língua-alvo",
|
||||
"translation_useAppLanguage": "Utilize o idioma da aplicação",
|
||||
"translation_downloadedModelLabel": "Modelo baixado",
|
||||
@@ -2066,5 +2196,255 @@
|
||||
"room_guest": "Informações do Servidor",
|
||||
"chat_sendMessage": "Enviar mensagem",
|
||||
"repeater_guest": "Informações sobre repetidores",
|
||||
"repeater_guestTools": "Ferramentas para hóspedes"
|
||||
"repeater_guestTools": "Ferramentas para hóspedes",
|
||||
"repeater_getCategory": "Obter valores",
|
||||
"repeater_powerMgmt": "Gerenciamento de energia",
|
||||
"repeater_sensors": "Sensores",
|
||||
"repeater_cliHelpPowerOff": "Desliga o dispositivo. (não se espera resposta)",
|
||||
"repeater_cliHelpClkReboot": "Redefine o relógio para uma data conhecida e reinicia o dispositivo.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Envia um anúncio sem \"salto\" (apenas para vizinhos próximos).",
|
||||
"repeater_cliHelpStartOta": "Inicia uma atualização de firmware via rádio em placas compatíveis.",
|
||||
"repeater_cliHelpTime": "Define o relógio do dispositivo para os segundos da época Unix especificados. O relógio não pode retroceder.",
|
||||
"repeater_cliHelpBoard": "Indica o fabricante da placa / identificador de hardware.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Envia uma solicitação de descoberta de nós para os vizinhos próximos. (Apenas para repetidores)",
|
||||
"repeater_cliHelpPowersaving": "Indica se o modo de economia de energia está ativado ou desativado.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Habilita ou desabilita o modo de economia de energia (quando disponível).",
|
||||
"repeater_cliHelpErase": "(Apenas para dispositivos) Formata o sistema de arquivos do dispositivo. Apaga todas as configurações e contatos.",
|
||||
"repeater_cliHelpSetDutyCycle": "Define o ciclo de transmissão máximo permitido como uma porcentagem (1-100). Ajusta internamente o fator de tempo de transmissão.",
|
||||
"repeater_cliHelpSetPrvKey": "(Apenas para uso em série) Substitui a chave privada de identificação do dispositivo. É necessário reiniciar o dispositivo para aplicar a alteração. Gera uma nova chave pública.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Apenas para SX126x) Alterna o ganho amplificado do receptor (RX) para melhorar a sensibilidade em condições de corrente mais elevada.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Define a string com as informações de contato do proprietário, que será incluída nos anúncios. Utilize '|' para indicar novas linhas.",
|
||||
"repeater_cliHelpSetPathHashMode": "Define o modo de hash de caminho. 0 = modo legado, 1 = modo padrão, 2 = modo rigoroso. Afeta a forma como os caminhos de roteamento são correspondidos.",
|
||||
"repeater_cliHelpSetLoopDetect": "Define o nível de sensibilidade para a detecção de loops de roteamento: desligado, mínimo, moderado ou estrito.",
|
||||
"repeater_cliHelpSetFreq": "(Apenas para rádio) Define rapidamente a frequência. É necessário reiniciar o dispositivo. Recomenda-se usar a opção \"configurar rádio\" para definir todos os parâmetros do rádio.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Apenas para a ponte ESPNow) Define o canal Wi-Fi (1-14) utilizado pela ponte.",
|
||||
"repeater_cliHelpGetName": "Mostra o nome do nó configurado.",
|
||||
"repeater_cliHelpGetRole": "Mostra o papel do firmware (Repetidor, Servidor de Sala, etc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Exibe a chave pública do dispositivo.",
|
||||
"repeater_cliHelpGetPrvKey": "(Apenas para uso em série) Exibe a chave privada do dispositivo. Trate-a como uma informação confidencial.",
|
||||
"repeater_cliHelpGetRepeat": "Indica se a função de encaminhamento de pacotes (função de repetidor) está ativada ou desativada.",
|
||||
"repeater_cliHelpGetTx": "Mostra a potência atual em dBm.",
|
||||
"repeater_cliHelpGetFreq": "Mostra a frequência de rádio configurada em MHz.",
|
||||
"repeater_cliHelpGetRadio": "Exibe todos os parâmetros de rádio: frequência, largura de banda, fator de espalhamento, taxa de codificação.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Apenas para SX126x) Mostra o estado do ganho amplificado do RX.",
|
||||
"repeater_cliHelpGetAf": "Mostra o fator de tempo de transmissão atual.",
|
||||
"repeater_cliHelpGetDutyCycle": "Mostra o ciclo de trabalho atual permitido em porcentagem.",
|
||||
"repeater_cliHelpGetIntThresh": "Mostra o limite de interferência do canal em dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Mostra o intervalo de reinicialização do AGC em segundos.",
|
||||
"repeater_cliHelpGetMultiAcks": "Indica se o modo de confirmação dupla está ativado (1) ou desativado (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Indica se o acesso somente de leitura para os convidados está habilitado.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Indica o intervalo de publicidade local em minutos.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Mostra o intervalo de tempo da publicidade relacionada às inundações, em horas.",
|
||||
"repeater_cliHelpGetGuestPassword": "Mostra a senha de convidado configurada.",
|
||||
"repeater_cliHelpGetLat": "Mostra a latitude configurada.",
|
||||
"repeater_cliHelpGetLon": "Mostra a longitude configurada.",
|
||||
"repeater_cliHelpGetRxDelay": "Mostra o valor base do atraso de resposta.",
|
||||
"repeater_cliHelpGetTxDelay": "Mostra o fator de atraso em modo de inundação.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Mostra o fator de atraso direto.",
|
||||
"repeater_cliHelpGetFloodMax": "Mostra o número máximo de saltos devido às inundações.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Exibe a string de informações de contato do proprietário.",
|
||||
"repeater_cliHelpGetPathHashMode": "Mostra o modo de hash de caminho (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Demonstra a sensibilidade na detecção de loops.",
|
||||
"repeater_cliHelpGetAcl": "(Apenas para séries) Lista as entradas de controle de acesso em um repetidor.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Indica se a ponte está habilitada.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Mostra o atraso da ponte em milissegundos.",
|
||||
"repeater_cliHelpGetBridgeSource": "Indica se a ponte está enviando ou recebendo pacotes RX ou TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Apenas para ponte RS232) Exibe a taxa de baud da ponte.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Apenas para a ponte ESPNow) Exibe o canal WiFi da ponte.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Apenas para a ponte ESPNow) Exibe o segredo compartilhado pela ponte.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Apenas para NRF52) Exibe a versão do bootloader.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Mostra o multiplicador do ADC (escalonamento da tensão da bateria).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Indica se o sistema possui suporte para gerenciamento de energia.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Indica a fonte de energia atual: externa ou bateria.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Mostra as razões mais recentes para a reinicialização e desligamento.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Mostra a tensão da bateria no momento da inicialização, em milivolts (mV).",
|
||||
"repeater_cliHelpSensorGet": "Lê uma configuração de sensor personalizada através de uma chave.",
|
||||
"repeater_cliHelpSensorSet": "Cria uma configuração personalizada para um sensor.",
|
||||
"repeater_cliHelpSensorList": "Lista todas as configurações de sensores personalizadas, organizadas em páginas a partir de um índice de início opcional.",
|
||||
"repeater_cliHelpRegionDefault": "Mostra o escopo de região padrão atual.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Define o escopo regional padrão. Use \"<null>\" para limpar.",
|
||||
"repeater_cliHelpRegionListAllowed": "Lista as regiões que permitem o tráfego em áreas de risco de inundações.",
|
||||
"repeater_cliHelpRegionListDenied": "Lista as regiões que restringem o tráfego em áreas de risco de inundações.",
|
||||
"repeater_cliHelpStatsPackets": "(Apenas para séries) Apresenta estatísticas em nível de pacotes.",
|
||||
"repeater_cliHelpStatsRadio": "(Apenas para transmissões em série) Exibe estatísticas de rádio.",
|
||||
"repeater_cliHelpStatsCore": "(Apenas para dispositivos em série) Exibe estatísticas básicas do firmware.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Compartilhado",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Locais ocupados",
|
||||
"losBlockedSpotsHint": "Toque em um ponto bloqueado para destacá-lo no mapa.",
|
||||
"losSelectedObstructionTitle": "Obstrução selecionada",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"settings_companionDebugLog": "Registro de depuração auxiliar",
|
||||
"settings_companionDebugLogSubtitle": "Comandos, respostas e dados brutos para protocolos BLE/TCP/USB",
|
||||
"chat_markAsUnread": "Marcar como não lido",
|
||||
"chat_newMessages": "Novas mensagens",
|
||||
"repeater_chanUtil": "Utilização do canal",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_undo": "Desfazer",
|
||||
"messageStatus_sent": "Enviado",
|
||||
"messageStatus_pending": "Enviar",
|
||||
"messageStatus_delivered": "Entregue",
|
||||
"messageStatus_failed": "Falhou ao enviar",
|
||||
"messageStatus_repeated": "Ouvi repetidamente",
|
||||
"contacts_moreOptions": "Mais opções",
|
||||
"contacts_searchOpen": "Pesquisar contatos",
|
||||
"contacts_searchClose": "Pesquisa avançada",
|
||||
"routing_title": "Rotas",
|
||||
"routing_modeAuto": "Carro",
|
||||
"routing_modeFlood": "Inundação",
|
||||
"routing_modeManual": "Manual",
|
||||
"routing_modeAutoHint": "Seleciona automaticamente o caminho mais conhecido, e, se nenhum caminho conhecido for encontrado, utiliza a estratégia de \"inundação\".",
|
||||
"routing_modeFloodHint": "Transmissão através de todos os repetidores. É a opção mais confiável, mas utiliza mais tempo de transmissão.",
|
||||
"routing_modeManualHint": "Sempre segue exatamente o caminho que você define.",
|
||||
"routing_currentRoute": "Rota atual",
|
||||
"routing_directNoHops": "Direto – sem saltos de repetidor",
|
||||
"routing_noPathYet": "Ainda não há um caminho definido. A mensagem continua a ser enviada até que uma rota seja encontrada.",
|
||||
"routing_floodBroadcast": "Transmissão através de todos os repetidores",
|
||||
"routing_editPath": "Editar caminho",
|
||||
"routing_forgetPath": "Esqueça o caminho",
|
||||
"routing_knownPaths": "Rotas conhecidas",
|
||||
"routing_knownPathsHint": "Toque em um caminho para alternar para ele.",
|
||||
"routing_inUse": "Em uso",
|
||||
"routing_qualityStrong": "Primeiro salto notável",
|
||||
"routing_qualityGood": "Primeiro salto bem-sucedido",
|
||||
"routing_qualityFair": "Primeira etapa bem-sucedida",
|
||||
"routing_qualityWorked": "Foi entregue",
|
||||
"routing_qualityFlood": "Informação obtida através de relatos generalizados.",
|
||||
"routing_qualityUntested": "Não testado",
|
||||
"routing_neverWorked": "nunca confirmado",
|
||||
"routing_floodDelivery": "Entrega em áreas afetadas por inundações",
|
||||
"pathEditor_title": "Criar Caminho",
|
||||
"pathEditor_hopCounter": "{count} de 64 gramas de lúpulo",
|
||||
"pathEditor_noHops": "Ainda não há lúpulos adicionados. Clique nos repetidores abaixo para adicioná-los na ordem desejada, ou salve sem adicionar lúpulos para enviar diretamente.",
|
||||
"pathEditor_addHops": "Adicione os lúpulos na seguinte ordem.",
|
||||
"pathEditor_searchRepeaters": "Encontrar repetidores",
|
||||
"pathEditor_advancedHex": "Avançado: caminho hexadecimal bruto",
|
||||
"pathEditor_hexLabel": "Prefixos hexadecimais",
|
||||
"pathEditor_hexHelper": "Dois caracteres hexadecimais por salto, separados por vírgulas.",
|
||||
"pathEditor_invalidTokens": "Inválido: {tokens}",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"pathEditor_tooManyHops": "Máximo de 64 saltos",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_usePath": "Utilize este caminho.",
|
||||
"pathEditor_removeHop": "Remova o lúpulo",
|
||||
"pathEditor_unknownHop": "Repetidor desconhecido",
|
||||
"map_zoomIn": "Ampliar",
|
||||
"map_zoomOut": "Ampliar",
|
||||
"map_centerMap": "Mapa do centro",
|
||||
"chrome_bluetoothRequiresChromium": "O Web Bluetooth requer um navegador Chromium.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS confirmado",
|
||||
"pathTrace_legendInferred": "Posição inferida"
|
||||
}
|
||||
|
||||
+447
-4
@@ -39,6 +39,8 @@
|
||||
"common_notAvailable": "—",
|
||||
"common_voltageValue": "{volts} В",
|
||||
"common_percentValue": "{percent}%",
|
||||
"common_autoRefresh": "Автообновление",
|
||||
"common_interval": "Интервал",
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_scanning": "Поиск устройств...",
|
||||
"scanner_connecting": "Подключение...",
|
||||
@@ -81,6 +83,8 @@
|
||||
"settings_privacyModeEnabled": "Режим конфиденциальности включен",
|
||||
"settings_privacyModeDisabled": "Режим конфиденциальности выключен",
|
||||
"settings_actions": "Действия",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Отправить анонсирование",
|
||||
"settings_sendAdvertisementSubtitle": "Отправить анонсирование о присутствии сейчас",
|
||||
"settings_advertisementSent": "Анонсирование отправлено",
|
||||
@@ -229,11 +233,8 @@
|
||||
"channels_searchChannels": "Поиск каналов...",
|
||||
"channels_noChannelsFound": "Каналы не найдены",
|
||||
"channels_channelIndex": "Канал {index}",
|
||||
"channels_hashtagChannel": "Хэштег-канал",
|
||||
"channels_public": "Публичный",
|
||||
"channels_private": "Приватный",
|
||||
"channels_publicChannel": "Публичный канал",
|
||||
"channels_privateChannel": "Приватный канал",
|
||||
"channels_editChannel": "Изменить канал",
|
||||
"channels_muteChannel": "Отключить уведомления канала",
|
||||
"channels_unmuteChannel": "Включить уведомления канала",
|
||||
@@ -252,6 +253,22 @@
|
||||
"channels_channelAdded": "Канал \"{name}\" добавлен",
|
||||
"channels_editChannelTitle": "Изменить канал {index}",
|
||||
"channels_smazCompression": "Сжатие SMAZ",
|
||||
"channels_cyr2latCompression": "Сжатие Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Заменяет некоторые кириллические символы на латиницу при отправке.",
|
||||
"channels_cyr2latSettingsHeading": "Настройка Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Список замен",
|
||||
"channels_cyr2latSettingsDscr": "Редактировать JSON-конфигурацию замены символов",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-карта замен",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Некорректный JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Добавить профиль Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Название профиля",
|
||||
"settings_cyr2latProfileNameEmpty": "Название профиля не может быть пустым",
|
||||
"settings_cyr2latProfileAdded": "Профиль добавлен",
|
||||
"settings_cyr2latProfileUpdated": "Профиль успешно обновлен",
|
||||
"settings_cyr2latProfileEdit": "Редактировать профиль Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Удалить профиль Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Профиль успешно удален",
|
||||
"settings_cyr2latProfileDeleteDscr": "Вы действительно хотите удалить профиль \"{name}\"?",
|
||||
"channels_channelUpdated": "Канал \"{name}\" обновлён",
|
||||
"channels_publicChannelAdded": "Публичный канал добавлен",
|
||||
"channels_sortBy": "Сортировка",
|
||||
@@ -358,6 +375,8 @@
|
||||
"chat_direct": "Прямой",
|
||||
"chat_poiShared": "Точка интереса отправлена",
|
||||
"chat_unread": "Непрочитанных: {count}",
|
||||
"chat_markAsUnread": "Пометить как непрочитанные",
|
||||
"chat_newMessages": "Новые сообщения",
|
||||
"map_title": "Карта нод",
|
||||
"map_noNodesWithLocation": "Нет нод с данными о местоположении",
|
||||
"map_nodesNeedGps": "Ноды должны передавать свои GPS-координаты, чтобы отображаться на карте",
|
||||
@@ -669,6 +688,43 @@
|
||||
"telemetry_voltageValue": "{volts}В",
|
||||
"telemetry_currentValue": "{amps}А",
|
||||
"telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F",
|
||||
"telemetry_digitalInputLabel": "Цифровой вход",
|
||||
"telemetry_digitalOutputLabel": "Цифровой выход",
|
||||
"telemetry_analogInputLabel": "Аналоговый вход",
|
||||
"telemetry_analogOutputLabel": "Аналоговый выход",
|
||||
"telemetry_genericLabel": "Общий датчик",
|
||||
"telemetry_luminosityLabel": "Освещённость",
|
||||
"telemetry_presenceLabel": "Присутствие",
|
||||
"telemetry_humidityLabel": "Влажность",
|
||||
"telemetry_accelerometerLabel": "Акселерометр",
|
||||
"telemetry_pressureLabel": "Давление",
|
||||
"telemetry_altitudeLabel": "Высота",
|
||||
"telemetry_frequencyLabel": "Частота",
|
||||
"telemetry_percentageLabel": "Процент",
|
||||
"telemetry_concentrationLabel": "Концентрация",
|
||||
"telemetry_powerLabel": "Мощность",
|
||||
"telemetry_distanceLabel": "Расстояние",
|
||||
"telemetry_energyLabel": "Энергия",
|
||||
"telemetry_directionLabel": "Направление",
|
||||
"telemetry_timeLabel": "Время",
|
||||
"telemetry_gyrometerLabel": "Гирометр",
|
||||
"telemetry_colourLabel": "Цвет",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Переключатель",
|
||||
"telemetry_polylineLabel": "Полилиния",
|
||||
"telemetry_altitudeValue": "{meters} м",
|
||||
"telemetry_frequencyValue": "{hertz} Гц",
|
||||
"telemetry_pressureValue": "{hpa} гПа",
|
||||
"telemetry_luminosityValue": "{lux} лк",
|
||||
"telemetry_powerValue": "{watts} Вт",
|
||||
"telemetry_distanceValue": "{meters} м",
|
||||
"telemetry_energyValue": "{kilowattHours} кВт⋅ч",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Количество запросов",
|
||||
"telemetry_error": "Не удалось получить данные",
|
||||
"neighbors_receivedData": "Полученные данные о соседях",
|
||||
"neighbors_requestTimedOut": "Время ожидания данных о соседях истекло.",
|
||||
"neighbors_errorLoading": "Ошибка загрузки соседей: {error}",
|
||||
@@ -1251,6 +1307,9 @@
|
||||
"translation_title": "Перевод",
|
||||
"translation_enableTitle": "Включить перевод",
|
||||
"translation_composerSubtitle": "Управляет исходным состоянием значка перевода, предоставляемого редактором.",
|
||||
"translation_autoIncomingTitle": "Автоматически переводить сообщения",
|
||||
"translation_autoIncomingSubtitle": "Автоматически переводит сообщения для уведомлений, а также для чатов и каналов.",
|
||||
"translation_translateMessage": "Перевести сообщение",
|
||||
"translation_targetLanguage": "Целевой язык",
|
||||
"translation_useAppLanguage": "Используйте язык приложения",
|
||||
"translation_downloadedModelLabel": "Загруженная модель",
|
||||
@@ -1306,5 +1365,389 @@
|
||||
"repeater_guest": "Информация о ретрансляторе",
|
||||
"room_guest": "Информация о сервере",
|
||||
"repeater_guestTools": "Инструменты для гостей",
|
||||
"settings_multiAck": "Несколько подтверждений"
|
||||
"common_done": "Готово",
|
||||
"background_serviceTitle": "MeshCore работает",
|
||||
"background_serviceText": "Поддерживает BLE-соединение",
|
||||
"appSettings_translationModelDeleted": "Удалено {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Не удалось удалить: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Не удалось обновить канал: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Тип",
|
||||
"map_path": "Путь",
|
||||
"map_location": "Местоположение",
|
||||
"map_estLocation": "Прибл. местоположение",
|
||||
"map_publicKey": "Публичный ключ",
|
||||
"map_publicKeyPrefixHint": "напр. ab12",
|
||||
"contact_typeChat": "Чат",
|
||||
"contact_typeRepeater": "Ретранслятор",
|
||||
"contact_typeRoom": "Комната",
|
||||
"contact_typeSensor": "Датчик",
|
||||
"contact_typeUnknown": "Неизвестно",
|
||||
"channels_via": "через {path}",
|
||||
"chat_score": "Оценка",
|
||||
"settings_multiAck": "Несколько подтверждений",
|
||||
"map_sharedAt": "Поделено",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "Щелкните по заблокированной области, чтобы выделить ее на карте.",
|
||||
"losBlockedSpotsTitle": "Зарезервированные места",
|
||||
"losSelectedObstructionTitle": "Выбранный объект, препятствующий движению",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"repeater_rxGain": "Увеличенная эффективность RX",
|
||||
"repeater_rxGainHelper": "Более высокая чувствительность, больший ток потребления (только для SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Обновите усиление RX",
|
||||
"repeater_multiAcks": "Несколько подтверждений",
|
||||
"repeater_multiAcksSubtitle": "Обеспечьте доставку сообщений по нескольким каналам для повышения эффективности.",
|
||||
"repeater_refreshMultiAcks": "Обновление нескольких подтверждений",
|
||||
"repeater_networkHealth": "Состояние сети",
|
||||
"repeater_loopDetect": "Обнаружение циклов",
|
||||
"repeater_loopDetectHelper": "Создайте пакеты данных, которые выглядят как циклы маршрутизации.",
|
||||
"repeater_loopDetectOff": "Отключено",
|
||||
"repeater_loopDetectMinimal": "Минимальный",
|
||||
"repeater_loopDetectModerate": "Умеренный",
|
||||
"repeater_loopDetectStrict": "Строгий",
|
||||
"repeater_dutyCycle": "Цикл работы",
|
||||
"repeater_dutyCycleHelper": "Максимальный процент времени, выделенного на трансляцию.",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Информация о операторе",
|
||||
"repeater_ownerInfoHelper": "Общая метаинформация для этого ретранслятора",
|
||||
"repeater_refreshOwnerInfo": "Обновить информацию о операторе",
|
||||
"repeater_floodMax": "Максимальное количество прыжков при наводнении",
|
||||
"repeater_floodMaxHelper": "Максимальное количество пакетов, которые могут быть отправлены в одном потоке (0-64)",
|
||||
"repeater_advancedSettings": "Продвинутый",
|
||||
"repeater_advancedSettingsSubtitle": "Регуляторы для опытных операторов",
|
||||
"repeater_pathHashMode": "Режим хеширования пути",
|
||||
"repeater_pathHashModeHelper": "Байты, используемые для кодирования идентификатора этого ретранслятора в тегах для обнаружения потоков/циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (1 600 000 идентификаторов, до 21 перехода). Версии прошивки v1.13 и более ранние версии не поддерживают многобайтовые пути — они поднимаются только после того, как ваша сеть будет обновлена до версии v1.14 и выше.",
|
||||
"repeater_txDelay": "Задержка в работе системы Flood TX",
|
||||
"repeater_txDelayHelper": "Передача с увеличенным интервалом для трафика во время наводнения, в качестве коэффициента, умножающего время передачи пакета (от 0 до 2, по умолчанию 0,5). Более высокое значение означает меньшее количество столкновений, но более медленную передачу.",
|
||||
"repeater_directTxDelay": "Прямая задержка сигнала TX",
|
||||
"repeater_directTxDelayHelper": "Передача промежуточных данных для прямого (немассового) трафика, в качестве коэффициента, равного времени передачи пакета (от 0 до 2, по умолчанию 0,3).",
|
||||
"repeater_intThresh": "Пороговое значение помех",
|
||||
"repeater_intThreshHelper": "Порог устанавливается для калибровки уровня шума радио, чтобы оно отсеивало помехи, превышающие этот уровень. Значение \"0\" означает отключение – используйте только в случае, если вы наблюдаете ошибки при приеме сигнала в шумном диапазоне.",
|
||||
"repeater_agcResetInterval": "Интервал сброса AGC",
|
||||
"repeater_agcResetIntervalHelper": "Как часто следует сбрасывать автоматическую регулировку усиления радио, чтобы вернуться к нормальному состоянию после заклинивания? Интервал сброса составляет несколько секунд, кратный 4. Отключение периодического сброса осуществляется с помощью параметра 0.",
|
||||
"repeater_actionsTitle": "Действия",
|
||||
"repeater_sendAdvert": "Отправить объявление о наводнении",
|
||||
"repeater_sendAdvertSubtitle": "Разместите рекламу о наводнении в эфире по всей сети.",
|
||||
"repeater_sendAdvertZeroHop": "Опубликуйте рекламу, не требующую промежуточного распространения.",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Разместите рекламу, распространяемую одним способом (без использования ретрансляторов).",
|
||||
"repeater_clockSync": "Синхронизировать время сейчас",
|
||||
"repeater_clockSyncSubtitle": "Установите время на вашем телефоне, чтобы оно совпадало со временем ретранслятора.",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Настройки сохранены — перезагрузите ретранслятор, чтобы применить их.",
|
||||
"repeater_settingsPartialFailure": "Некоторые настройки не удалось применить: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@settings_multiAck": {
|
||||
"placeholders": {
|
||||
"value": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@common_percentValue": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@telemetry_temperatureValue": {
|
||||
"placeholders": {
|
||||
"celsius": {
|
||||
"type": "String"
|
||||
},
|
||||
"fahrenheit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channelPath_timeWithDate": {
|
||||
"placeholders": {
|
||||
"day": {
|
||||
"type": "int"
|
||||
},
|
||||
"month": {
|
||||
"type": "int"
|
||||
},
|
||||
"time": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channelPath_timeOnly": {
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channelPath_selectedPathLabel": {
|
||||
"placeholders": {
|
||||
"label": {
|
||||
"type": "String"
|
||||
},
|
||||
"prefixes": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_getCategory": "Получить значения",
|
||||
"repeater_powerMgmt": "Управление энергопотреблением",
|
||||
"repeater_sensors": "Датчики",
|
||||
"repeater_cliHelpPowerOff": "Отключает устройство. (ожидается отсутствие ответа).",
|
||||
"repeater_cliHelpClkReboot": "Сбрасывает часы до известной эпохи и перезапускает устройство.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Отправляет рекламу, распространяемую только среди ближайших соседей (без промежуточных узлов).",
|
||||
"repeater_cliHelpStartOta": "Запускает обновление прошивки по воздуху на поддерживаемых устройствах.",
|
||||
"repeater_cliHelpTime": "Устанавливает время устройства в соответствии с заданными секундами от начала эпохи Unix. Время не может сброситься назад.",
|
||||
"repeater_cliHelpBoard": "Отображает информацию о производителе платы / идентификатор аппаратного обеспечения.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Отправляет запрос на обнаружение соседних узлов. (Только для ретранслятора)",
|
||||
"repeater_cliHelpPowersavingOnOff": "Включает или выключает режим экономии энергии (если он поддерживается).",
|
||||
"repeater_cliHelpPowersaving": "Показывает, включен ли режим экономии энергии.",
|
||||
"repeater_cliHelpErase": "(Только для серийного использования) Форматирует файловую систему устройства. Удаляет все настройки и контакты.",
|
||||
"repeater_cliHelpSetDutyCycle": "Устанавливает максимальный допустимый цикл передачи данных в процентах (от 1 до 100). Внутренне корректирует коэффициент времени передачи.",
|
||||
"repeater_cliHelpSetPrvKey": "(Только для серийного использования) Заменяет приватный ключ, идентифицирующий устройство. Требуется перезагрузка для применения. Генерирует новый публичный ключ.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Только для SX126x) Переключает усиление RX для повышения чувствительности при больших токах потребления.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Указывает строку с контактной информацией владельца, которая должна быть включена в объявления. Используйте '|' для переносов строк.",
|
||||
"repeater_cliHelpSetPathHashMode": "Устанавливает режим хеширования пути. 0 = устаревший, 1 = стандартный, 2 = строгий. Влияет на то, как определяются маршруты.",
|
||||
"repeater_cliHelpSetLoopDetect": "Устанавливает чувствительность обнаружения циклов маршрутизации: \"выключено\", \"минимальная\", \"умеренная\" или \"строгая\".",
|
||||
"repeater_cliHelpSetFreq": "(Только для настройки) Быстро устанавливает только частоту. Требуется перезагрузка. Рекомендуется использовать функцию \"настройка радио\" для полного набора параметров.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Только для моста ESPNow) Устанавливает канал Wi-Fi (от 1 до 14), используемый мостом.",
|
||||
"repeater_cliHelpGetName": "Отображает имя настроенного узла.",
|
||||
"repeater_cliHelpGetRole": "Отображает роль прошивки (ретранслятор, сервер для комнаты и т.д.).",
|
||||
"repeater_cliHelpGetPublicKey": "Отображает открытый ключ устройства.",
|
||||
"repeater_cliHelpGetPrvKey": "(Только для серийного использования) Отображает приватный ключ устройства. Рассматривайте его как секретную информацию.",
|
||||
"repeater_cliHelpGetRepeat": "Отображает, включена ли функция перенаправления пакетов (функция ретранслятора) или нет.",
|
||||
"repeater_cliHelpGetTx": "Отображает текущую мощность передатчика в дБм.",
|
||||
"repeater_cliHelpGetFreq": "Отображает настроенную частоту радиосигнала в мегагерцах.",
|
||||
"repeater_cliHelpGetRadio": "Отображает все параметры радиосигнала: частоту, полосу пропускания, коэффициент модуляции, скорость кодирования.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Только для SX126x) Отображает состояние усиления сигнала на входе RX.",
|
||||
"repeater_cliHelpGetAf": "Отображает текущий коэффициент времени эфира.",
|
||||
"repeater_cliHelpGetDutyCycle": "Отображает текущий допустимый цикл работы в процентах.",
|
||||
"repeater_cliHelpGetIntThresh": "Отображает порог помех в децибелах.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Отображает интервал сброса автоматической регулировки усиления в секундах.",
|
||||
"repeater_cliHelpGetMultiAcks": "Показывает, включен ли режим двойной подтверждения (1) или выключен (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Отображает, разрешен ли доступ для чтения только для гостей.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Отображает продолжительность рекламного блока в минутах.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Отображает интервал времени показа рекламного ролика в часах.",
|
||||
"repeater_cliHelpGetGuestPassword": "Отображает установленный пароль для гостя.",
|
||||
"repeater_cliHelpGetLat": "Отображает заданную широту.",
|
||||
"repeater_cliHelpGetLon": "Отображает заданную долготу.",
|
||||
"repeater_cliHelpGetRxDelay": "Отображает базовое значение задержки.",
|
||||
"repeater_cliHelpGetTxDelay": "Отображает коэффициент задержки при работе в режиме затопления.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Отображает коэффициент задержки в режиме прямого подключения.",
|
||||
"repeater_cliHelpGetFloodMax": "Отображает максимальное количество переходов при затоплении.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Отображает строку с контактной информацией владельца.",
|
||||
"repeater_cliHelpGetPathHashMode": "Отображает режим работы с хэшем пути (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Отображает чувствительность к обнаружению циклов.",
|
||||
"repeater_cliHelpGetAcl": "(Только для серий) Перечисляет записи управления доступом на ретрансляторе.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Показывает, включена ли функция моста.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Отображает задержку в миллисекундах.",
|
||||
"repeater_cliHelpGetBridgeSource": "Отображает, какие пакеты RX или TX передаются через мост.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Только для интерфейса RS232) Отображает скорость передачи данных на интерфейсе RS232.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Только для моста ESPNow) Отображает канал WiFi, используемый мостом.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Только для моста ESPNow) Отображает общий секрет, используемый мостом.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Только для NRF52) Отображает версию загрузчика.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Отображает коэффициент умножения аналого-цифрового преобразователя (масштабирование напряжения от батареи).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Сообщает, есть ли у совета поддержки функций управления питанием.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Отображает текущий источник питания: внешний или аккумулятор.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Отображает последние причины сброса и выключения.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Отображает напряжение батареи при запуске системы в милливольтах (мВ).",
|
||||
"repeater_cliHelpSensorGet": "Считывает пользовательское значение для датчика по указанному ключу.",
|
||||
"repeater_cliHelpSensorSet": "Создает пользовательские настройки для датчика.",
|
||||
"repeater_cliHelpSensorList": "Перечисляет все пользовательские настройки датчиков, разбитые на страницы с возможностью указания начального индекса.",
|
||||
"repeater_cliHelpRegionDefault": "Отображает текущий область действия по умолчанию.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Устанавливает значение региона по умолчанию. Используйте \"<null>\", чтобы сбросить значение.",
|
||||
"repeater_cliHelpRegionListAllowed": "Перечисляет регионы, где разрешено движение транспорта во время наводнений.",
|
||||
"repeater_cliHelpRegionListDenied": "Перечисляет регионы, где запрещено движение транспорта во время наводнений.",
|
||||
"repeater_cliHelpStatsPackets": "(Только для серийной версии) Отображает статистику на уровне пакетов.",
|
||||
"repeater_cliHelpStatsRadio": "(Только для серий) Отображает статистику радио.",
|
||||
"repeater_cliHelpStatsCore": "(Только для серийного оборудования) Отображает основные статистические данные прошивки.",
|
||||
"settings_companionDebugLogSubtitle": "Команды, ответы и необработанные данные, используемые для протоколов BLE, TCP и USB.",
|
||||
"repeater_chanUtil": "Использование канала",
|
||||
"settings_companionDebugLog": "Журнал отладки (для сопутствующего приложения)",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_pending": "Отправка",
|
||||
"common_undo": "Отменить",
|
||||
"messageStatus_delivered": "Доставлено",
|
||||
"messageStatus_sent": "Отправлено",
|
||||
"messageStatus_failed": "Не удалось отправить",
|
||||
"messageStatus_repeated": "Услышал несколько раз",
|
||||
"contacts_moreOptions": "Больше вариантов",
|
||||
"contacts_searchOpen": "Найти контакты",
|
||||
"contacts_searchClose": "Закрыть поиск",
|
||||
"routing_title": "Маршрутизация",
|
||||
"routing_modeAuto": "Авто",
|
||||
"routing_modeFlood": "Наводнение",
|
||||
"routing_modeManual": "Инструкция",
|
||||
"routing_modeAutoHint": "Автоматически выбирает наиболее известный путь, и если такой путь неизвестен, использует алгоритм поиска пути.",
|
||||
"routing_modeFloodHint": "Передача сигнала через все ретрансляторы. Самый надежный способ, но требует больше времени на передачу.",
|
||||
"routing_modeManualHint": "Всегда следует точно по указанному вами маршруту.",
|
||||
"routing_currentRoute": "Текущий маршрут",
|
||||
"routing_directNoHops": "Прямое соединение – без использования ретрансляторов",
|
||||
"routing_noPathYet": "Пока нет пути. Следующее сообщение будет отправлено до тех пор, пока не будет обнаружен маршрут.",
|
||||
"routing_floodBroadcast": "Транслируется через все ретрансляторы",
|
||||
"routing_editPath": "Изменить путь",
|
||||
"routing_forgetPath": "Забудьте о маршруте",
|
||||
"routing_knownPaths": "Известные маршруты",
|
||||
"routing_knownPathsHint": "Создайте маршрут для переключения на этот пункт.",
|
||||
"routing_inUse": "В эксплуатации",
|
||||
"routing_qualityStrong": "Сильный первый скачок",
|
||||
"routing_qualityGood": "Хорошее начало",
|
||||
"routing_qualityFair": "Первый хороший урожай",
|
||||
"routing_qualityWorked": "Осуществлено",
|
||||
"routing_qualityFlood": "Узнал из новостей, распространяющихся в интернете.",
|
||||
"routing_qualityUntested": "Непроверенный",
|
||||
"routing_neverWorked": "никогда не было подтверждено",
|
||||
"routing_floodDelivery": "Доставка при затоплении",
|
||||
"pathEditor_title": "Создать маршрут",
|
||||
"pathEditor_hopCounter": "{count} из 64 хмеля",
|
||||
"pathEditor_noHops": "На данный момент хмель еще не добавлен. Чтобы добавить его, нажмите на соответствующие кнопки ниже в нужном порядке, или сохраните рецепт без хмеля, чтобы отправить его напрямую.",
|
||||
"pathEditor_addHops": "Добавляйте хмель в соответствии с указанным порядком.",
|
||||
"pathEditor_searchRepeaters": "Поиск повторителей",
|
||||
"pathEditor_advancedHex": "Продвинутый уровень: прямой путь в шестнадцатеричном формате",
|
||||
"pathEditor_hexLabel": "Префиксы шестнадцатеричной системы",
|
||||
"pathEditor_hexHelper": "Два шестнадцатеричных символа на каждом шаге, разделенные запятыми.",
|
||||
"pathEditor_invalidTokens": "Неверно: {tokens}",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_tooManyHops": "Максимальное количество ингредиентов – 64",
|
||||
"pathEditor_usePath": "Используйте этот путь",
|
||||
"pathEditor_removeHop": "Удалить хмель",
|
||||
"pathEditor_unknownHop": "Неизвестный ретранслятор",
|
||||
"map_zoomIn": "Увеличить масштаб",
|
||||
"map_zoomOut": "Увеличить масштаб",
|
||||
"map_centerMap": "Карта центра",
|
||||
"chrome_bluetoothRequiresChromium": "Для работы Web Bluetooth требуется браузер на основе Chromium.",
|
||||
"channels_communityShortId": "Идентификатор: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS подтверждено",
|
||||
"pathTrace_legendInferred": "Выведенная позиция"
|
||||
}
|
||||
|
||||
+416
-36
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Odstrániť",
|
||||
"common_enable": "Povolit",
|
||||
"common_disable": "Zakázať",
|
||||
"common_autoRefresh": "Automatické obnovenie",
|
||||
"common_interval": "Časový interval",
|
||||
"common_reboot": "Restartovať",
|
||||
"common_loading": "Načítavanie...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – Verzia pre verejnosť",
|
||||
"scanner_scanning": "Skrívania zariadení...",
|
||||
"scanner_connecting": "Pripojujem sa...",
|
||||
"scanner_disconnecting": "Odpojuje sa...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Ochranný režim je povolený.",
|
||||
"settings_privacyModeDisabled": "Ochranný režim je vypnutý",
|
||||
"settings_actions": "Možné akcie",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Odoslať reklamu",
|
||||
"settings_sendAdvertisementSubtitle": "Momentálne priezornejšie.",
|
||||
"settings_advertisementSent": "Reklama odeslaná",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Záznam ladenia aplikácie",
|
||||
"settings_appDebugLogSubtitle": "Správy z ladenia aplikácie",
|
||||
"settings_about": "O nás",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore, verzia {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -132,8 +136,8 @@
|
||||
"settings_aboutLegalese": "MeshCore Open Source Projekt 2024",
|
||||
"settings_aboutDescription": "Otvorený zdrojový Flutter klient pre MeshCore LoRa sieťové zariadenia.",
|
||||
"settings_infoName": "Meno",
|
||||
"settings_infoId": "ID",
|
||||
"settings_infoStatus": "Status",
|
||||
"settings_infoId": "Identifikátor",
|
||||
"settings_infoStatus": "Stav",
|
||||
"settings_infoBattery": "Batéria",
|
||||
"settings_infoPublicKey": "Verejný kľúč",
|
||||
"settings_infoContactsCount": "Počet kontaktov",
|
||||
@@ -146,7 +150,7 @@
|
||||
"settings_spreadingFactor": "Rozptýľovací faktor",
|
||||
"settings_codingRate": "Cenový kurz pre programovanie",
|
||||
"settings_txPower": "TX Výkon (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerHelper": "0 – 22",
|
||||
"settings_txPowerInvalid": "Neplatná hodnota výkonu TX (0-22 dBm)",
|
||||
"settings_error": "Chyba: {message}",
|
||||
"@settings_error": {
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Tmavé",
|
||||
"appSettings_language": "Jazyk",
|
||||
"appSettings_languageSystem": "Predvolený systém",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageEn": "Anglicky",
|
||||
"appSettings_languageFr": "Francúzština",
|
||||
"appSettings_languageEs": "Španielsky",
|
||||
"appSettings_languageDe": "Nemecky",
|
||||
"appSettings_languagePl": "Poľský",
|
||||
"appSettings_languageSl": "Slovenčina",
|
||||
"appSettings_languagePt": "Portugalčina",
|
||||
"appSettings_languageIt": "Taliančina",
|
||||
"appSettings_languageZh": "Čínština",
|
||||
"appSettings_languageSv": "Švédska",
|
||||
"appSettings_languageNl": "Niderlandsky",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageBg": "Българština",
|
||||
"appSettings_notifications": "Upozornenia",
|
||||
"appSettings_enableNotifications": "Povolte Notifikácie",
|
||||
"appSettings_enableNotificationsSubtitle": "Zísť o upozornenia na správy a inzeráty",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Kanál s hashtagom",
|
||||
"channels_public": "Veľké verejné",
|
||||
"channels_private": "Osobné",
|
||||
"channels_publicChannel": "Veľké verejne kanály",
|
||||
"channels_privateChannel": "Osobné kanál",
|
||||
"channels_editChannel": "Upraviť kanál",
|
||||
"channels_muteChannel": "Stlmiť kanál",
|
||||
"channels_unmuteChannel": "Zrušiť stlmenie kanála",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Odstránenie kompresie SMAZ",
|
||||
"channels_cyr2latCompression": "Odstránenie kompresie Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Pri odosielaní nahradí niektoré znaky cyriliky latinskými znakmi.",
|
||||
"channels_cyr2latSettingsHeading": "Nastavenia Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Zoznam nahradení",
|
||||
"channels_cyr2latSettingsDscr": "Upravte konfiguráciu JSON pre nahradenie znakov",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON mapa nahradení",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Nesprávny JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Pridať profil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Názov profilu",
|
||||
"settings_cyr2latProfileNameEmpty": "Názov profilu nesmie byť prázdny",
|
||||
"settings_cyr2latProfileAdded": "Profil bol úspešne pridaný",
|
||||
"settings_cyr2latProfileUpdated": "Profil bol úspešne aktualizovaný",
|
||||
"settings_cyr2latProfileEdit": "Upraviť profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Odstrániť profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Profil bol úspešne odstránený",
|
||||
"settings_cyr2latProfileDeleteDscr": "Naozaj chcete odstrániť profil \"{name}\"?",
|
||||
"channels_channelUpdated": "Kanál \"{name}\" bol aktualizovaný",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "Veľký kanál pridaný",
|
||||
"channels_sortBy": "Triediť podľa",
|
||||
"channels_sortManual": "Ručne",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "Od A po Z",
|
||||
"channels_sortLatestMessages": "Posledné správy",
|
||||
"channels_sortUnread": "Nezriadené",
|
||||
"chat_noMessages": "Zatiaľ žiadne správy.",
|
||||
@@ -477,7 +494,7 @@
|
||||
"debugLog_noEntries": "Zatiaľ neboli zaznamenané žiadne debug logy.",
|
||||
"debugLog_enableInSettings": "Povolte ladicové logy v nastaveniach",
|
||||
"debugLog_frames": "Rámce",
|
||||
"debugLog_rawLogRx": "Raw Log-RX",
|
||||
"debugLog_rawLogRx": "Čistý log – RX",
|
||||
"debugLog_noBleActivity": "Zatiaľ žiadna aktivita BLE.",
|
||||
"debugFrame_length": "Dĺžka rámca: {count} bajtov",
|
||||
"@debugFrame_length": {
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "CLI (Command Line Interface)",
|
||||
"debugFrame_textTypePlain": "Jednoduché",
|
||||
"debugFrame_text": "- Text: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -541,7 +558,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_hexDump": "Hex Dump:",
|
||||
"debugFrame_hexDump": "Hexová analýza:",
|
||||
"chat_pathManagement": "Správa ciest",
|
||||
"chat_routingMode": "Režim trasy",
|
||||
"chat_autoUseSavedPath": "Použiť uloženú cestu",
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "História ciest je plná. Odstráňte záznamy, aby ste mohli pridať nové.",
|
||||
"chat_hopSingular": "Skok",
|
||||
"chat_hopPlural": "Skákať",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{skok} other{skoky}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -879,11 +896,11 @@
|
||||
"path_setPath": "Nastaviť cestu",
|
||||
"repeater_management": "Správa opakérov",
|
||||
"repeater_managementTools": "Nástroje na správu",
|
||||
"repeater_status": "Status",
|
||||
"repeater_status": "Stav",
|
||||
"repeater_statusSubtitle": "Zobraziť stav, štatistiky a susedov repeatera",
|
||||
"repeater_telemetry": "Telemetria",
|
||||
"repeater_telemetrySubtitle": "Zobraziť telemetriu senzorov a systémových štatistík",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "CLI (Command Line Interface)",
|
||||
"repeater_cliSubtitle": "Pošlite príkazy opakovaču",
|
||||
"repeater_settings": "Nastavenia",
|
||||
"repeater_settingsSubtitle": "Konfigurujte parametre opakovača",
|
||||
@@ -992,7 +1009,7 @@
|
||||
"repeater_guestPasswordHelper": "Prístupový heslo iba na čítanie",
|
||||
"repeater_radioSettings": "Nastavenia rádia",
|
||||
"repeater_frequencyMhz": "Frekvencia (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300–2500 MHz",
|
||||
"repeater_txPower": "TX Power",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Šírka pásma",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Potvrdiť",
|
||||
"repeater_settingsSaved": "Nastavenia boli uložené úspešne.",
|
||||
"repeater_rxGain": "Zvýšený zisk RX",
|
||||
"repeater_rxGainHelper": "Vyššia citlivosť, vyšší príkon (platí len pre modely SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Obnovte zvýšený zisk z RX",
|
||||
"repeater_multiAcks": "Víťazné potvrdenia (víťazné ACK)",
|
||||
"repeater_multiAcksSubtitle": "Potvrďte správy prostredníctvom viacerých trás pre lepšiu doručenie.",
|
||||
"repeater_refreshMultiAcks": "Opätovne potvrďte viacero ACK signálov",
|
||||
"repeater_networkHealth": "Zdravie siete",
|
||||
"repeater_loopDetect": "Detekcia slučiek",
|
||||
"repeater_loopDetectHelper": "Vytvorte balíčky, ktoré vizuálne pripomínajú slučky v síti.",
|
||||
"repeater_loopDetectOff": "Vypnuté",
|
||||
"repeater_loopDetectMinimal": "Minimálny",
|
||||
"repeater_loopDetectModerate": "Stredný, mierny",
|
||||
"repeater_loopDetectStrict": "Prísne",
|
||||
"repeater_dutyCycle": "Cyklus činnosti",
|
||||
"repeater_dutyCycleHelper": "Maximálna percentáľ dostupného času vysielania",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informácie o poskytovateľovi",
|
||||
"repeater_ownerInfoHelper": "Veľké dátové informácie pre tento vysielací zdroj",
|
||||
"repeater_refreshOwnerInfo": "Zísť informácie o operátore",
|
||||
"repeater_floodMax": "Maximálny počet skokov pri povodni",
|
||||
"repeater_floodMaxHelper": "Maximálny počet paketov, ktoré môžu preletieť cez jeden hop (0-64)",
|
||||
"repeater_advancedSettings": "Pokročilé",
|
||||
"repeater_advancedSettingsSubtitle": "Ovládacie knopy pre skúsených operátorov",
|
||||
"repeater_pathHashMode": "Režim hashovania cesty",
|
||||
"repeater_pathHashModeHelper": "Byty použité na zakódovanie ID tohto opakovača v tagoch pre trasu/detekciu slučky. 0 = 1 bytu (256 ID, až 64 skokov), 1 = 2 byty (65 000 ID, až 32 skokov), 2 = 3 byty (16 miliónov ID, až 21 skokov). Verzie 1.13 a staršie nepodporujú viacbytové trasy – fungujú len, keď je sieť aktivovaná.",
|
||||
"repeater_txDelay": "Zpoždanie v Flood, TX",
|
||||
"repeater_txDelayHelper": "Nastavenie pre opakované vysielanie pre dopravu počas povodní, ako násobok času, ktorý paket využije (0-2, výchoce hodnota 0,5). Vyššia hodnota znamená menej kolízii, ale pomalšie doručovanie.",
|
||||
"repeater_directTxDelay": "Priame oneskorenie TX",
|
||||
"repeater_directTxDelayHelper": "Nastavenie pre retransmisiu pre priame (nie pre plnú sieť), ako násobok času prenosu paketov (0-2, výchoce 0,3).",
|
||||
"repeater_intThresh": "Hranica, pri ktorej dochádza k rušeniu",
|
||||
"repeater_intThreshHelper": "Hranica je nastavená tak, aby odfiltrovala šum nad touto úrovňou. Hodnota 0 znamená, že sa nebude nič odfiltrovať – nastavte ju len v prípade, že zaznamenáte chyby pri prijímaní signálu v šumnej frekvencii.",
|
||||
"repeater_agcResetInterval": "Interval reštartu AGC",
|
||||
"repeater_agcResetIntervalHelper": "Ako často by ste mali reštartovať automatické ovládanie zosilnenia, aby ste sa vrátili do normálneho stavu, ak je zosilnenie zablokované? Nastavenie „4.0“ vypne pravidelné reštarty.",
|
||||
"repeater_actionsTitle": "Opatrenia",
|
||||
"repeater_sendAdvert": "Odoslať inzerát o povodňovej situácii",
|
||||
"repeater_sendAdvertSubtitle": "Zverejnite reklamu na povodňu prostredníctvom siete.",
|
||||
"repeater_sendAdvertZeroHop": "Odoslať reklamu bez prenosu",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Zverejnite reklamnú správu, ktorá sa prenáša len raz (bez prenosov).",
|
||||
"repeater_clockSync": "Synchronizujte hodiny teraz",
|
||||
"repeater_clockSyncSubtitle": "Nastavte čas na vašom telefóne, aby odpovedal na volania z vysielacieho zariadenia.",
|
||||
"repeater_actionSucceeded": "{action} succeeded",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} failed: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Nastavenia uložené – reštartujte vysielací prístroj, aby sa nastavenia aplikovali.",
|
||||
"repeater_settingsPartialFailure": "Niektoré nastavenia neúspešné: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Chyba pri ukladaní nastavení: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Obnoviť základné nastavenia",
|
||||
"repeater_refreshRadioSettings": "Obnoviť Nastavenia Rádií",
|
||||
"repeater_refreshTxPower": "Obnoviť TX napájanie",
|
||||
"repeater_refreshLocationSettings": "Obnoviť Nastavenia Miesta",
|
||||
"repeater_refreshPacketForwarding": "Obnoviť smerovanie paketov",
|
||||
"repeater_refreshGuestAccess": "Obnoviť prístup hosťa",
|
||||
"repeater_refreshPrivacyMode": "Obnoviť Ochranný režim",
|
||||
"repeater_refreshAdvertisementSettings": "Obnoviť nastavenia reklamy",
|
||||
"repeater_refreshed": "{label} sa znova načítalo",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digitálny vstup",
|
||||
"telemetry_digitalOutputLabel": "Digitálny výstup",
|
||||
"telemetry_analogInputLabel": "Analógový vstup",
|
||||
"telemetry_analogOutputLabel": "Analógový výstup",
|
||||
"telemetry_genericLabel": "Všeobecný senzor",
|
||||
"telemetry_luminosityLabel": "Osvetlenie",
|
||||
"telemetry_presenceLabel": "Prítomnosť",
|
||||
"telemetry_humidityLabel": "Vlhkosť",
|
||||
"telemetry_accelerometerLabel": "Akcelerometer",
|
||||
"telemetry_pressureLabel": "Tlak",
|
||||
"telemetry_altitudeLabel": "Nadmorská výška",
|
||||
"telemetry_frequencyLabel": "Frekvencia",
|
||||
"telemetry_percentageLabel": "Percento",
|
||||
"telemetry_concentrationLabel": "Koncentrácia",
|
||||
"telemetry_powerLabel": "Výkon",
|
||||
"telemetry_distanceLabel": "Vzdialenosť",
|
||||
"telemetry_energyLabel": "Energia",
|
||||
"telemetry_directionLabel": "Smer",
|
||||
"telemetry_timeLabel": "Čas",
|
||||
"telemetry_gyrometerLabel": "Gyrometer",
|
||||
"telemetry_colourLabel": "Farba",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Prepínač",
|
||||
"telemetry_polylineLabel": "Lomená čiara",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Počet požiadaviek",
|
||||
"telemetry_error": "Nepodarilo sa získať údaje",
|
||||
"telemetry_noData": "Nejsú dostupné žiadne údaje z telemetrie.",
|
||||
"telemetry_channelTitle": "Kanál {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Triediť podľa",
|
||||
"listFilter_latestMessages": "Posledné správy",
|
||||
"listFilter_heardRecently": "Nedávno počuli.",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "Od A po Z",
|
||||
"listFilter_filters": "Filtre",
|
||||
"listFilter_all": "Všetko",
|
||||
"listFilter_users": "Používatelia",
|
||||
@@ -1619,8 +1746,8 @@
|
||||
"appSettings_unitsTitle": "Jednotky",
|
||||
"appSettings_unitsMetric": "Metrické (m / km)",
|
||||
"appSettings_unitsImperial": "Imperiálne (ft / mi)",
|
||||
"map_lineOfSight": "Line of Sight",
|
||||
"map_losScreenTitle": "Line of Sight",
|
||||
"map_lineOfSight": "Úroveň výhľadu",
|
||||
"map_losScreenTitle": "Úroveň výhľadu",
|
||||
"losSelectStartEnd": "Vyberte počiatočný a koncový uzol pre LOS.",
|
||||
"losRunFailed": "Kontrola priamej viditeľnosti zlyhala: {error}",
|
||||
"@losRunFailed": {
|
||||
@@ -1879,8 +2006,8 @@
|
||||
"tcpHostLabel": "IP adresa",
|
||||
"tcpScreenTitle": "Spojte sa pomocou protokolu TCP",
|
||||
"connectionChoiceTcpLabel": "TCP",
|
||||
"tcpPortLabel": "Port",
|
||||
"tcpPortHint": "5000",
|
||||
"tcpPortLabel": "Prístav",
|
||||
"tcpPortHint": "5 000",
|
||||
"tcpStatus_notConnected": "Zadajte cieľovú adresu a pripojte sa.",
|
||||
"tcpStatus_connectingTo": "Pripojenie k {endpoint}...",
|
||||
"tcpErrorHostRequired": "Je potrebné zadať IP adresu.",
|
||||
@@ -2012,6 +2139,9 @@
|
||||
"translation_composerTitle": "Preložte pred odeslaním",
|
||||
"translation_title": "Preklad",
|
||||
"translation_composerSubtitle": "Riadi výchoce stav ikony pre preklad, ktorú používa program.",
|
||||
"translation_autoIncomingTitle": "Automaticky prekladať správy",
|
||||
"translation_autoIncomingSubtitle": "Automaticky prekladá správy pre upozornenia aj pre čet alebo kanál.",
|
||||
"translation_translateMessage": "Preložiť správu",
|
||||
"translation_targetLanguage": "Cieľový jazyk",
|
||||
"translation_useAppLanguage": "Použite jazyk aplikácie",
|
||||
"translation_downloadedModelLabel": "Stiahnutý model",
|
||||
@@ -2066,5 +2196,255 @@
|
||||
"chat_sendMessage": "Odoslať správu",
|
||||
"repeater_guest": "Informácie o opakovači",
|
||||
"room_guest": "Informácie o serveri",
|
||||
"repeater_guestTools": "Nástroje pre hostí"
|
||||
"repeater_guestTools": "Nástroje pre hostí",
|
||||
"repeater_getCategory": "Zísť hodnoty",
|
||||
"repeater_powerMgmt": "Správa energie",
|
||||
"repeater_sensors": "Senzory",
|
||||
"repeater_cliHelpPowerOff": "Vypína zariadenie. (neočakáva sa žiadna odpoveď)",
|
||||
"repeater_cliHelpClkReboot": "Resetuje hodiny na známu epochu a reštartuje zariadenie.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Rozosiela reklamu, ktorá sa prenáša len medzi susednými zariadeniami (bez prenosu cez iné siete).",
|
||||
"repeater_cliHelpStartOta": "Spustí aktualizáciu firmvéru prostredníctvom diaľkového prenosu na podporovaných doskách.",
|
||||
"repeater_cliHelpTime": "Nastavuje časovník zariadenia na zadané sekundy od Unix epochy. Časovník sa nedá otáčať dozadu.",
|
||||
"repeater_cliHelpBoard": "Zobrazuje informácie o výrobcom dosky / identifikátor hardvéru.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Odosiela požiadavku na nájdenie susedných uzlov. (Len pre opakovače)",
|
||||
"repeater_cliHelpPowersaving": "Ukazuje, či je režim úspory energie zapnutý alebo vypnutý.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Umožňuje alebo vypína režim úspory energie (ak je podporovaný).",
|
||||
"repeater_cliHelpErase": "(Používa sa len pre sériové zariadenia) Formátuje systém súborov zariadenia. Vymaže všetky nastavenia a kontakty.",
|
||||
"repeater_cliHelpSetDutyCycle": "Nastavuje maximálnu povolenú frekvenciu prenosu ako percento (1-100). Internálne upravuje faktor času prenosu.",
|
||||
"repeater_cliHelpSetPrvKey": "(Používa sa len v sériovej verzii) Nahradí privátny kľúč, ktorý identifikuje zariadenie. Po aplikácii je potrebné zariadenie reštartovať. Generuje nový verejný kľúč.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(iba pre SX126x) Zapína zvýšený zisk prijímania pre zlepšenie citlivosti pri vyššom príkonu.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Definuje reťazec s informáciami o kontaktnom osobě, ktorý je zahrnutý v reklamách. Používajte '|' pre nové riadky.",
|
||||
"repeater_cliHelpSetPathHashMode": "Nastavuje režim hashovania cesty. 0 = starý režim, 1 = štandardný režim, 2 = striktný režim. Ovplyvňuje, ako sa prekladajú trasy.",
|
||||
"repeater_cliHelpSetLoopDetect": "Nastavuje citlivosť detekcie slučky routovania: vypnutá, minimálna, stredná alebo prísna.",
|
||||
"repeater_cliHelpSetFreq": "(Používa sa len v sériovej verzii) Rýchlo nastavuje len frekvenciu. Je potrebné reštartovať. Pre úplné nastavenie rádia preferujte funkciu \"nastavenie rádia\".",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Používa sa len pre ESPNow most) Nastavuje WiFi kanál (1-14), ktorý používa most.",
|
||||
"repeater_cliHelpGetName": "Zobrazuje zadané meno uzla.",
|
||||
"repeater_cliHelpGetRole": "Ukazuje funkciu firmvéru (opakovač, server pre miestnosť atď.).",
|
||||
"repeater_cliHelpGetPublicKey": "Zobrazuje verejný kľúč zariadenia.",
|
||||
"repeater_cliHelpGetPrvKey": "(Používa sa len v sériových aplikáciách) Zobrazuje súkromný kľúč zariadenia. Zotriďte ho ako tajný údaj.",
|
||||
"repeater_cliHelpGetRepeat": "Ukazuje, či je funkcia preposielania paketov (funkcia opakéra) zapnutá alebo vypnutá.",
|
||||
"repeater_cliHelpGetTx": "Zobrazuje aktuálnu výkonovú hodnotu TX v dBm.",
|
||||
"repeater_cliHelpGetFreq": "Zobrazuje nakonfigurovanú frekvenciu v MHz.",
|
||||
"repeater_cliHelpGetRadio": "Zobrazuje všetky parametre rádiového signálu: frekvencia, šírka pásma, faktor rozširovania, rýchlosť kódovania.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(iba pre SX126x) Zobrazuje stav zosilnenia prijímača RX.",
|
||||
"repeater_cliHelpGetAf": "Zobrazuje aktuálny koeficient času vysielania.",
|
||||
"repeater_cliHelpGetDutyCycle": "Zobrazuje aktuálnu povolenú frekvenciu ako percentáž.",
|
||||
"repeater_cliHelpGetIntThresh": "Zobrazuje hranicu pre prechodové signály v dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Zobrazuje interval reštartovania AGC v sekundách.",
|
||||
"repeater_cliHelpGetMultiAcks": "Ukazuje, či je režim dvojité potvrdenie zapnutý (1) alebo vypnutý (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Ukazuje, či je povolená len čítacia funkcia pre hostí.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Zobrazuje čas trvania miestnej reklamnej pauzy v minútach.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Zobrazuje časový interval reklamy počas záplavy v hodinách.",
|
||||
"repeater_cliHelpGetGuestPassword": "Zobrazuje nastavené heslo pre hosta.",
|
||||
"repeater_cliHelpGetLat": "Zobrazuje nastavenú šírku.",
|
||||
"repeater_cliHelpGetLon": "Zobrazuje nastavenú dĺžku.",
|
||||
"repeater_cliHelpGetRxDelay": "Zobrazuje základnú hodnotu rxdelay.",
|
||||
"repeater_cliHelpGetTxDelay": "Ukazuje faktor zpoždenia pre režim povodňovej komunikácie.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Zobrazuje faktor zloženia pri priamej modulácii.",
|
||||
"repeater_cliHelpGetFloodMax": "Zobrazuje maximálny počet opakovaní povodňového stavu.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Zobrazuje reťazec s kontaktnými údajmi vlastníka.",
|
||||
"repeater_cliHelpGetPathHashMode": "Zobrazuje režim hashovania cesty (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Ukazuje citlivosť na detekciu slučiek.",
|
||||
"repeater_cliHelpGetAcl": "(Používa sa len v sériovej konfigurácii) Zobrazuje prístupové pravidlá na opakovači.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Ukazuje, či je most povolený.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Zobrazuje čas strávený prechodom mosta v milisekundách.",
|
||||
"repeater_cliHelpGetBridgeSource": "Ukazuje, či most prijíma alebo vysiela RX alebo TX balíky.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(iba pre rozhranie RS232) Zobrazuje rýchlosť prenosu dát na rozhraní RS232.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Používa sa len pre ESPNow) Zobrazuje WiFi kanál mosta.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Používa sa len pre ESPNow most) Zobrazuje spoločný tajný kľúč mosta.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(iba pre NRF52) Zobrazuje verziu bootloaderu.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Zobrazuje násobič ADC (škálovanie napätia batérie).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Označuje, či riadiace orgány majú podporu pre správu energie.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Ukazuje aktuálny zdroj napájania: externý alebo batéria.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Zobrazuje najaktuálnejšie dôvody pre reštart a vypnutie.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Zobrazuje napätie batérie pri spustení systému v milivoltov (mV).",
|
||||
"repeater_cliHelpSensorGet": "Číta hodnotu nastavenia pre špecifický senzor pomocou klávesového vstupu.",
|
||||
"repeater_cliHelpSensorSet": "Vytvára vlastné nastavenie pre senzor.",
|
||||
"repeater_cliHelpSensorList": "Zobrazuje všetky nastavenia pre špecifické senzory, zoradené podľa voliteľného indexu začiatku.",
|
||||
"repeater_cliHelpRegionDefault": "Zobrazuje aktuálnu rozsiahku, ktorá je nastavená ako výchozí.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Nastavuje výchoce rozsiahku regiónu. Použite \"<null>\", aby ju vymazal.",
|
||||
"repeater_cliHelpRegionListAllowed": "Zoznam oblastí, ktoré umožňujú premávku počas povodní.",
|
||||
"repeater_cliHelpRegionListDenied": "Zoznam oblastí, ktoré zakazujú premávku v dôsledku povodní.",
|
||||
"repeater_cliHelpStatsPackets": "(Len pre sériové záznamy) Zobrazuje štatistiky na úrovni paketov.",
|
||||
"repeater_cliHelpStatsRadio": "(Len pre sériu) Zobrazuje údaje o rádiových staniciach.",
|
||||
"repeater_cliHelpStatsCore": "(Len pre sériové modely) Zobrazuje základné štatistiky firmvéru.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Zdieľané",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Zablokované miesta",
|
||||
"losBlockedSpotsHint": "Kliknite na zablokované miesto, aby ste ho zvýraznili na mape.",
|
||||
"losSelectedObstructionTitle": "Vybraná prekážka",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"chat_markAsUnread": "Označenie ako neprečítané",
|
||||
"settings_companionDebugLogSubtitle": "Príkazy, odpovede a surové dáta pre protokoly BLE/TCP/USB",
|
||||
"settings_companionDebugLog": "Logovanie pre ladenie (sprievodný log)",
|
||||
"chat_newMessages": "Nové správy",
|
||||
"repeater_chanUtil": "Využitie kanálu",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "Odoslané",
|
||||
"messageStatus_delivered": "Doručené",
|
||||
"messageStatus_pending": "Odoslanie",
|
||||
"common_undo": "Zrušiť",
|
||||
"messageStatus_failed": "Neúspešné odeslanie",
|
||||
"messageStatus_repeated": "Slyšal som to opakovane",
|
||||
"contacts_moreOptions": "Ďalšie možnosti",
|
||||
"contacts_searchOpen": "Vyhľadajte kontakty",
|
||||
"contacts_searchClose": "Zavrieť vyhľadávanie",
|
||||
"routing_title": "Navigácia",
|
||||
"routing_modeAuto": "Auto",
|
||||
"routing_modeFlood": "Povodňová vlna",
|
||||
"routing_modeManual": "Ručná príručka",
|
||||
"routing_modeAutoHint": "Automaticky vyberá najznámejší trasa, a ak žiadna nie je známa, použije náhodnú trasu.",
|
||||
"routing_modeFloodHint": "Prenos prostredníctvom všetkých opakovačov. Najspoľahlivejší spôsob, ale vyžaduje viac času vysielania.",
|
||||
"routing_modeManualHint": "Vždy dodáva presne podľa zadaného trasy.",
|
||||
"routing_currentRoute": "Aktuálna trasa",
|
||||
"routing_directNoHops": "Priamo – bez prechodných trás",
|
||||
"routing_noPathYet": "Zatiaľ neexistuje žiadna cesta. Nasledujúce správy budú pokračovať, kým sa nenájde trasa.",
|
||||
"routing_floodBroadcast": "Prenos prostredníctvom každého opakovača",
|
||||
"routing_editPath": "Upraviť trasu",
|
||||
"routing_forgetPath": "Zabudnite na trasu",
|
||||
"routing_knownPaths": "Známe cesty",
|
||||
"routing_knownPathsHint": "Kliknite na cestu, aby ste sa k nej presunuli.",
|
||||
"routing_inUse": "V prevádzke",
|
||||
"routing_qualityStrong": "Silný prvý krok",
|
||||
"routing_qualityGood": "Úspešný prvý krok",
|
||||
"routing_qualityFair": "Prvá, spravodlivá fáza",
|
||||
"routing_qualityWorked": "Dosiahnutý úspech",
|
||||
"routing_qualityFlood": "Zistil som to z informácií, ktoré som získal v dôsledku povodňovej situácie.",
|
||||
"routing_qualityUntested": "Neotestované",
|
||||
"routing_neverWorked": "nikedy nebolo potvrdené",
|
||||
"routing_floodDelivery": "Doručenie v prípade povodní",
|
||||
"pathEditor_title": "Vytvorenie cesty",
|
||||
"pathEditor_hopCounter": "{count} z 64 chmelových zŕš",
|
||||
"pathEditor_noHops": "Zatiaľ žiadne chmel. Kliknite na opakované, aby ste ich pridali postupne, alebo uložte bez chmelu, aby ste ho mohli poslať priamo.",
|
||||
"pathEditor_addHops": "Pridávajte chmel podľa zadaného poriadku.",
|
||||
"pathEditor_searchRepeaters": "Hľadať opakované",
|
||||
"pathEditor_advancedHex": "Pokročilé: pôvodná hexová cesta",
|
||||
"pathEditor_hexLabel": "Prefiksy pre hexadecimálne čísla",
|
||||
"pathEditor_hexHelper": "Dve hexové čísla na každý krok, oddelené čiarkami",
|
||||
"routing_lastWorked": "worked {when}",
|
||||
"pathEditor_invalidTokens": "Neplatné: {tokens}",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_tooManyHops": "Maximálne 64 krokov",
|
||||
"pathEditor_usePath": "Použite túto cestu",
|
||||
"pathEditor_removeHop": "Odstráňte chmel",
|
||||
"pathEditor_unknownHop": "Neznáme zariadenie na opakované vysielanie",
|
||||
"map_zoomIn": "Zväčšiť",
|
||||
"map_zoomOut": "Zmenť zamer zblízka",
|
||||
"map_centerMap": "Mapa centra",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth vyžaduje prehliadač Chromium.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS potvrdilo",
|
||||
"pathTrace_legendInferred": "Odvodená poloha"
|
||||
}
|
||||
|
||||
+410
-30
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Izbrisati",
|
||||
"common_enable": "Omogoči",
|
||||
"common_disable": "Izklopiti",
|
||||
"common_autoRefresh": "Samodejno osveževanje",
|
||||
"common_interval": "Časovni interval",
|
||||
"common_reboot": "Ponoviti",
|
||||
"common_loading": "Naložanje...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -44,7 +46,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_percentValue": "{percent}%",
|
||||
"common_percentValue": "{percent} %",
|
||||
"@common_percentValue": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – Odprto",
|
||||
"scanner_scanning": "Skeniram za naprave...",
|
||||
"scanner_connecting": "Povezujem se...",
|
||||
"scanner_disconnecting": "Odklapljam se...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Privatni način je omogočen.",
|
||||
"settings_privacyModeDisabled": "Privatni način je onemogočen.",
|
||||
"settings_actions": "Akcije",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Pošlji Oglas",
|
||||
"settings_sendAdvertisementSubtitle": "Trenutna prisotnost v oddajah",
|
||||
"settings_advertisementSent": "Oglas poslan",
|
||||
@@ -115,13 +119,13 @@
|
||||
"settings_rebootDevice": "Ponovni zagon naprave",
|
||||
"settings_rebootDeviceSubtitle": "Ponovno zaženi MeshCore napravo",
|
||||
"settings_rebootDeviceConfirm": "Ste prepričani, da želite ponovno zagnati napravo? Povezava bo prekinjena.",
|
||||
"settings_debug": "Debug",
|
||||
"settings_debug": "Odpravljanje napak",
|
||||
"settings_bleDebugLog": "BLE debug log (razhroščevanje)",
|
||||
"settings_bleDebugLogSubtitle": "BLE ukazi, odgovori in surovi podatki",
|
||||
"settings_appDebugLog": "Logi aplikacije",
|
||||
"settings_appDebugLogSubtitle": "Debug sporočila aplikacije",
|
||||
"settings_about": "Oglejte si",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore, različ {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -133,7 +137,7 @@
|
||||
"settings_aboutDescription": "Odprtokodni Flutter klient za naprave za LoRa omrežje MeshCore.",
|
||||
"settings_infoName": "Ime",
|
||||
"settings_infoId": "ID",
|
||||
"settings_infoStatus": "Status",
|
||||
"settings_infoStatus": "Stanje",
|
||||
"settings_infoBattery": "Baterija",
|
||||
"settings_infoPublicKey": "Javni ključ",
|
||||
"settings_infoContactsCount": "Število stikov",
|
||||
@@ -146,7 +150,7 @@
|
||||
"settings_spreadingFactor": "Razširitveni faktor",
|
||||
"settings_codingRate": "Programska hitrost",
|
||||
"settings_txPower": "TX Moč (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerHelper": "0 – 22",
|
||||
"settings_txPowerInvalid": "Neveljavna TX moč (0-22 dBm)",
|
||||
"settings_error": "Napaka: {message}",
|
||||
"@settings_error": {
|
||||
@@ -164,18 +168,18 @@
|
||||
"appSettings_themeDark": "Temno",
|
||||
"appSettings_language": "Jezik",
|
||||
"appSettings_languageSystem": "Sistemska privzeta vrednost",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageEn": "Angleščina",
|
||||
"appSettings_languageFr": "Francija",
|
||||
"appSettings_languageEs": "Španščina",
|
||||
"appSettings_languageDe": "Nemščina",
|
||||
"appSettings_languagePl": "Poljski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languagePt": "Portugalski",
|
||||
"appSettings_languageIt": "Italijanščina",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageSv": "Švedska",
|
||||
"appSettings_languageNl": "Nizozemsko",
|
||||
"appSettings_languageSk": "Slovenščina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_notifications": "Obvestila",
|
||||
"appSettings_enableNotifications": "Omogoči obvestila",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtag kanal",
|
||||
"channels_public": "Javni",
|
||||
"channels_private": "Zasebni",
|
||||
"channels_publicChannel": "Javni kanal",
|
||||
"channels_privateChannel": "Zasebni kanal",
|
||||
"channels_editChannel": "Uredi kanal",
|
||||
"channels_muteChannel": "Utišaj kanal",
|
||||
"channels_unmuteChannel": "Vklopi obvestila kanala",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "Kompresija SMAZ",
|
||||
"channels_cyr2latCompression": "Kompresija Cyr2Lat",
|
||||
"channels_cyr2latCompressionDscr": "Pri pošiljanju nekatere cirilice nadomesti z latiničnimi.",
|
||||
"channels_cyr2latSettingsHeading": "Nastavitve Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Seznam zamenjav",
|
||||
"channels_cyr2latSettingsDscr": "Uredi JSON-konfiguracijo zamenjav znakov",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-tabela zamenjav",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Nepravilen JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Dodaj profil Cyr2Lat",
|
||||
"settings_cyr2latProfileName": "Ime profila",
|
||||
"settings_cyr2latProfileNameEmpty": "Ime profila ne sme biti prazno",
|
||||
"settings_cyr2latProfileAdded": "Profil je bil uspešno dodan",
|
||||
"settings_cyr2latProfileUpdated": "Profil je bil uspešno posodobljen",
|
||||
"settings_cyr2latProfileEdit": "Uredi profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDelete": "Izbriši profil Cyr2Lat",
|
||||
"settings_cyr2latProfileDeleted": "Profil je bil uspešno izbrisan",
|
||||
"settings_cyr2latProfileDeleteDscr": "Ali res želite izbrisati profil \"{name}\"?",
|
||||
"channels_channelUpdated": "Kanal {name} je bil posodobljen",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -399,7 +416,7 @@
|
||||
"channels_publicChannelAdded": "javna skupnost dodana",
|
||||
"channels_sortBy": "Sortiraj po",
|
||||
"channels_sortManual": "Ročno",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "A do Z",
|
||||
"channels_sortLatestMessages": "Najnovejše sporočilo",
|
||||
"channels_sortUnread": "Nerešeno",
|
||||
"chat_noMessages": "Še ni sporočil.",
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "CLI (Command Line Interface)",
|
||||
"debugFrame_textTypePlain": "Preprosto",
|
||||
"debugFrame_text": "- Tekst: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -541,7 +558,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_hexDump": "Hex Dump:",
|
||||
"debugFrame_hexDump": "Izpis heksadecimalnih vrednosti:",
|
||||
"chat_pathManagement": "Upravljanje poti",
|
||||
"chat_routingMode": "Navodilo za usmerjevalni način",
|
||||
"chat_autoUseSavedPath": "Avto (uporabi shranjeno pot)",
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.",
|
||||
"chat_hopSingular": "skok",
|
||||
"chat_hopPlural": "skokov",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{skok} other{skoki}}",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -879,11 +896,11 @@
|
||||
"path_setPath": "Nastavi Pot",
|
||||
"repeater_management": "Upravljanje ponovitve",
|
||||
"repeater_managementTools": "Upravne orodje",
|
||||
"repeater_status": "Status",
|
||||
"repeater_status": "Stanje",
|
||||
"repeater_statusSubtitle": "Pogledati stanje, statistike in sosede repeatera",
|
||||
"repeater_telemetry": "Telemetrija",
|
||||
"repeater_telemetrySubtitle": "Pogledate telemetrijo senzorjev in sistemske statistike",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "CLI (Command Line Interface)",
|
||||
"repeater_cliSubtitle": "Pošlji ukazne povelje na ponovitveno enoto.",
|
||||
"repeater_settings": "Nastavitve",
|
||||
"repeater_settingsSubtitle": "Konfigurirajte parametre ponovitelja",
|
||||
@@ -992,7 +1009,7 @@
|
||||
"repeater_guestPasswordHelper": "Odpovedni dostopni geslo",
|
||||
"repeater_radioSettings": "Nastavitve Radija",
|
||||
"repeater_frequencyMhz": "Frekvenca (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300–2500 MHz",
|
||||
"repeater_txPower": "TX Moč",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Pasovna širina",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Potrdit",
|
||||
"repeater_settingsSaved": "Nastavitve so shranjene uspešno.",
|
||||
"repeater_rxGain": "Povečana dobitka RX",
|
||||
"repeater_rxGainHelper": "Veća občutljivost, večji porabljeni tok (velja samo za SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Povečana dobitka RX, posodobit",
|
||||
"repeater_multiAcks": "Več potrdil",
|
||||
"repeater_multiAcksSubtitle": "Potrdite sporočila po več poti za boljši dostop",
|
||||
"repeater_refreshMultiAcks": "Ponovite več potrdil",
|
||||
"repeater_networkHealth": "Zdravilo omrežja",
|
||||
"repeater_loopDetect": "Detekcija ciklov",
|
||||
"repeater_loopDetectHelper": "Izpišite pakete, ki izgledajo kot pete v omrežju.",
|
||||
"repeater_loopDetectOff": "Izklopljeno",
|
||||
"repeater_loopDetectMinimal": "Minimalen",
|
||||
"repeater_loopDetectModerate": "Umiren",
|
||||
"repeater_loopDetectStrict": "Strogi",
|
||||
"repeater_dutyCycle": "Ciklus delovanja",
|
||||
"repeater_dutyCycleHelper": "Najvišji odstotek časa, ki ga lahko posreduje.",
|
||||
"repeater_dutyCyclePercent": "{percent} %",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Informacije o operaterju",
|
||||
"repeater_ownerInfoHelper": "javni podatki o tej napravi",
|
||||
"repeater_refreshOwnerInfo": "Prejmi informacije o operaterju",
|
||||
"repeater_floodMax": "Največji možni odmerek",
|
||||
"repeater_floodMaxHelper": "Največje število paketov, ki lahko potujejo v enem plovilnem paketu (0-64)",
|
||||
"repeater_advancedSettings": "Napredno",
|
||||
"repeater_advancedSettingsSubtitle": "Gumbi za nastavljanje za izkušene uporabnike",
|
||||
"repeater_pathHashMode": "Način ustvarjanja hash-a poti",
|
||||
"repeater_pathHashModeHelper": "Biti, ki so bila uporabljena za kodiranje ID-ja tega releja v oznakah za zaznavanje pot/kroga, imajo naslednje velikosti: 0=1 bit (256 ID-jev, do 64 skokov), 1=2 biti (65.000 ID-jev, do 32 skokov), 2=3 biti (16 milijonov ID-jev, do 21 skokov). V različicah 1.13 in starejših se ustvarjajo večbitne poti – vendar se to zgodi šele, ko je omrežje vklopljeno v različicah 1.14 in kasnejših.",
|
||||
"repeater_txDelay": "Zatemnitevanje zaradi poplav v Texasu",
|
||||
"repeater_txDelayHelper": "Uporaba intervalov za ponovno pošiljanje v primeru prometa zaradi poplav, kot pomnožnik časovne trajanje paketa (0-2, privzeto 0,5). Veje vrednost = manjše kolizije, vendar počasnejše dostavo.",
|
||||
"repeater_directTxDelay": "Neposredni časovno odlašanje",
|
||||
"repeater_directTxDelayHelper": "Razdalja za ponovno pošiljanje za neposredno (neobvezen) promet, kot pomnožnik časovne trajanja paketa (0-2, privzeto 0,3).",
|
||||
"repeater_intThresh": "Meja, pri kateri nastane motnja",
|
||||
"repeater_intThreshHelper": "Tretja stopnja se uporablja za kalibracijo šumnega nivoja radija, kar omogoča, da se izklaplja pri šumu, ki presega to raven. 0 izklopi – uporabite le, če zaznate napake v šumnem pasu.",
|
||||
"repeater_agcResetInterval": "Interval ponovne kalibracije AGC",
|
||||
"repeater_agcResetIntervalHelper": "Kako pogosto je treba ponovno nastaviti samodejno regulacijo občutljivosti, da se vrnete v normalno stanje? Interval je nastavljen na nekaj sekund, natančno na 4. 0 izklopi periodično ponovno nastavljanje.",
|
||||
"repeater_actionsTitle": "Dejanja",
|
||||
"repeater_sendAdvert": "Pošlji oglas o poplavah",
|
||||
"repeater_sendAdvertSubtitle": "Razpustite oglas o poplavah preko omrežja.",
|
||||
"repeater_sendAdvertZeroHop": "Pošlji oglas, ki ne potrebuje posrednika.",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Premejte oglas, ki uporablja eno povezavo (brez posrednikov).",
|
||||
"repeater_clockSync": "Sinerizirajte uro zdaj",
|
||||
"repeater_clockSyncSubtitle": "Nastavite čas na telefonu, da se sinhronizira s repeatrom.",
|
||||
"repeater_actionSucceeded": "{action} je uspel",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} ni bilo uspešno: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Nastavitve shranjene – ponovni zagon repetitorja za uporabo",
|
||||
"repeater_settingsPartialFailure": "Nekatna nastavitva niso uspešna: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Napaka pri shranjevanju nastavitev: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Ponovno nastavi osnovne nastavitve",
|
||||
"repeater_refreshRadioSettings": "Ponovno Nastavitve Radija",
|
||||
"repeater_refreshTxPower": "Ponovno nastavi TX moč",
|
||||
"repeater_refreshLocationSettings": "Ponovno Nastavi Nastavitve Lokacije",
|
||||
"repeater_refreshPacketForwarding": "Ponovno nastavitve usmerjevanja paketa",
|
||||
"repeater_refreshGuestAccess": "Ponovno nastavitve dostopa gostov",
|
||||
"repeater_refreshPrivacyMode": "Ponovno aktiviraj način zasebnosti",
|
||||
"repeater_refreshAdvertisementSettings": "Ponovno nastavi Oglede Oglasi",
|
||||
"repeater_refreshed": "{label} je bil/a posodobljen/a",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digitalni vhod",
|
||||
"telemetry_digitalOutputLabel": "Digitalni izhod",
|
||||
"telemetry_analogInputLabel": "Analogni vhod",
|
||||
"telemetry_analogOutputLabel": "Analogni izhod",
|
||||
"telemetry_genericLabel": "Splošni senzor",
|
||||
"telemetry_luminosityLabel": "Osvetljenost",
|
||||
"telemetry_presenceLabel": "Prisotnost",
|
||||
"telemetry_humidityLabel": "Vlažnost",
|
||||
"telemetry_accelerometerLabel": "Merilnik pospeška",
|
||||
"telemetry_pressureLabel": "Tlak",
|
||||
"telemetry_altitudeLabel": "Nadmorska višina",
|
||||
"telemetry_frequencyLabel": "Frekvenca",
|
||||
"telemetry_percentageLabel": "Odstotek",
|
||||
"telemetry_concentrationLabel": "Koncentracija",
|
||||
"telemetry_powerLabel": "Moč",
|
||||
"telemetry_distanceLabel": "Razdalja",
|
||||
"telemetry_energyLabel": "Energija",
|
||||
"telemetry_directionLabel": "Smer",
|
||||
"telemetry_timeLabel": "Čas",
|
||||
"telemetry_gyrometerLabel": "Žiroskop",
|
||||
"telemetry_colourLabel": "Barva",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Stikalo",
|
||||
"telemetry_polylineLabel": "Polilinija",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Število zahtev",
|
||||
"telemetry_error": "Podatkov ni bilo mogoče pridobiti",
|
||||
"telemetry_noData": "Niso na voljo podatki o telemetriji.",
|
||||
"telemetry_channelTitle": "Kanal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1347,7 +1474,7 @@
|
||||
"listFilter_sortBy": "Sortiraj po",
|
||||
"listFilter_latestMessages": "Najnovejše sporočilo",
|
||||
"listFilter_heardRecently": "Nedavno slišan",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "A do Z",
|
||||
"listFilter_filters": "Filtri",
|
||||
"listFilter_all": "Vse",
|
||||
"listFilter_users": "Uporabniki",
|
||||
@@ -2011,6 +2138,9 @@
|
||||
"translation_enableSubtitle": "Prevedite vstopne sporočila in omogočite predhodno prevajanje.",
|
||||
"translation_enableTitle": "Omogočite prevod",
|
||||
"translation_composerSubtitle": "Ureja privzeto stanje ikone za prevod, ki jo uporablja avtor.",
|
||||
"translation_autoIncomingTitle": "Samodejno prevajaj sporočila",
|
||||
"translation_autoIncomingSubtitle": "Samodejno prevaja sporočila za obvestila ter za klepete ali kanale.",
|
||||
"translation_translateMessage": "Prevedi sporočilo",
|
||||
"translation_targetLanguage": "Ciljna jezika",
|
||||
"translation_useAppLanguage": "Uporabite jezik aplikacije",
|
||||
"translation_downloadedModelLabel": "Naložen model",
|
||||
@@ -2066,5 +2196,255 @@
|
||||
"chat_sendMessage": "Pošlji sporočilo",
|
||||
"room_guest": "Informacije o strežniku",
|
||||
"repeater_guestTools": "Naložila za goste",
|
||||
"settings_multiAck": "Več potrdil"
|
||||
"repeater_getCategory": "Dobite vrednosti",
|
||||
"repeater_powerMgmt": "Upravljanje z energijo",
|
||||
"repeater_sensors": "Senzori",
|
||||
"repeater_cliHelpPowerOff": "Izklopi naprave. (ne pričakujemo odziva)",
|
||||
"repeater_cliHelpClkReboot": "Ponovno nastavi uro na znano točko in ponovno vklopi naprave.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Pošlje oglas, ki doseže samo neposredne sosede (brez posredovanja).",
|
||||
"repeater_cliHelpStartOta": "Začne nadstrekovno ažuriranje programne opreme na podprtih ploščah.",
|
||||
"repeater_cliHelpTime": "Nastavi časovni ukaz naprave na podano število sekund od Unixovega začetka. Časovni ukaz ne more iti nazaj.",
|
||||
"repeater_cliHelpBoard": "Prikaže proizvajalca plošče / identifikator strojne opreme.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Pošlje zahtevo za odkrivanje sosednjih naprav. (Samo za repeatere)",
|
||||
"repeater_cliHelpPowersaving": "Prikaže, ali je vklopljen način varčevanja z energijo.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Omogoča ali onemogoča način varčevanja z energijo (če je podprt).",
|
||||
"repeater_cliHelpErase": "(Samo za serijske naprave) Formira datotapno sistemsko okolje. Izbriše vse nastavitve in kontakte.",
|
||||
"repeater_cliHelpSetDutyCycle": "Določi maksimalni dovoljeni čas, ki ga naprave lahko posredujejo, v odstotkih (1-100). Samodejno prilagodi faktor, ki odvisen je od časa, ki ga naprave lahko posredujejo.",
|
||||
"repeater_cliHelpSetPrvKey": "(Samo za serijske naprave) Nadomesti zasebni ključ za identifikacijo naprave. Za uporabo je potrebna ponovna aktivacija. Ustvari nov javni ključ.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Samo za SX126x) Vklopi povečano občutljivost RX za izboljšano delovanje pri večjih navorih.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Določi niz z informacijami o kontaktni osebi, ki je v oglasih. Za uporabo novih vrstic uporabite '|'.",
|
||||
"repeater_cliHelpSetPathHashMode": "Nastavlja način \"hash poti\". 0 = za stare sisteme, 1 = za standard, 2 = za stroge. Vpliva na to, kako so poti uskladene.",
|
||||
"repeater_cliHelpSetLoopDetect": "Nastavlja občutljivost detekcije ponavljajočih se povezav: izklopljeno, minimalno, umeren, ali strogo.",
|
||||
"repeater_cliHelpSetFreq": "(Samo za serijske naprave) Hitro nastavi samo frekvenco. Potrebna je ponovna aktivacija. Za popolno nastavitev radio parametrov je priporočljivo uporabiti možnost \"nastavitev radia\".",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Samo za most ESPNow) Nastavlja kanal WiFi-ja (1-14), ki ga uporablja most.",
|
||||
"repeater_cliHelpGetName": "Prikaže ime konfigurirane notranje.",
|
||||
"repeater_cliHelpGetRole": "Prikaže vlogo programskega oprema (repeater, strežnik za sobo itd.).",
|
||||
"repeater_cliHelpGetPublicKey": "Prikazuje javni ključ naprave.",
|
||||
"repeater_cliHelpGetPrvKey": "(Samo za serijske naprave) Prikazuje zasebni ključ naprave. Sprejemajte ga kot skrivno informacijo.",
|
||||
"repeater_cliHelpGetRepeat": "Pokaže, ali je omogočeno posredovanje paketov (delovanje kot repetitor).",
|
||||
"repeater_cliHelpGetTx": "Prikazuje trenutno moč TX v dBm.",
|
||||
"repeater_cliHelpGetFreq": "Prikaže nastavljeno frekvenco v MHz.",
|
||||
"repeater_cliHelpGetRadio": "Prikaže vse parametre radija: frekvenco, širino pasu, faktor razširjanja, raven kodiranja.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Samo za SX126x) Prikazuje stanje povečanega dobiča na RX.",
|
||||
"repeater_cliHelpGetAf": "Prikazuje trenutni faktor, ki določa časovno obdobje.",
|
||||
"repeater_cliHelpGetDutyCycle": "Prikazuje trenutno dovoljeno stopnjo delovanja kot odstotek.",
|
||||
"repeater_cliHelpGetIntThresh": "Prikazuje prag medsebojnega vpliva kanala v dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Prikazuje interval ponovne kalibracije AGC v sekundah.",
|
||||
"repeater_cliHelpGetMultiAcks": "Pokaže, ali je vklopljen način dvojnega potrdila (1) ali je izklopljen (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Pokaže, ali je omogočen le brani dostop za goste.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Prikazuje časovno obdobje lokalne reklame v minutah.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Prikaže časovno obdobje, ko se prikazuje oglas o poplavah, v urah.",
|
||||
"repeater_cliHelpGetGuestPassword": "Prikaže nastavljeno geslo za gostitelja.",
|
||||
"repeater_cliHelpGetLat": "Prikaže določeno zemljepisno širino.",
|
||||
"repeater_cliHelpGetLon": "Prikaže določeno merilo dolžine.",
|
||||
"repeater_cliHelpGetRxDelay": "Prikazuje osnovno vrednost RX odlašanja.",
|
||||
"repeater_cliHelpGetTxDelay": "Prikazuje faktor zamude v načinu delovanja pri plavlju.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Prikazuje faktor odlašanja signala v režimu neposredne komunikacije.",
|
||||
"repeater_cliHelpGetFloodMax": "Prikazuje največjo število, kolikokrat lahko voda doseže najvišjo višino.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Prikazuje niz z informacijami o lastniku.",
|
||||
"repeater_cliHelpGetPathHashMode": "Prikaže način delovanja z hashjem poti (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Prikazuje občutljivost na zaznavanje ciklov.",
|
||||
"repeater_cliHelpGetAcl": "(Samo za serije) Navaja vnos za nadzor dostopa na ponovljalniku.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Pokaže, ali je most omogočen.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Prikazuje zamik mosta v milisekundah.",
|
||||
"repeater_cliHelpGetBridgeSource": "Pokaže, ali most prenaša pakete RX ali TX.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Samo za most RS232) Prikazuje hitrost prenosa podatkov na mostu.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Samo za most ESPNow) Prikazuje kanal WiFi mosta.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Samo za most ESPNow) Prikazuje tajno, ki jo deli most.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Samo za NRF52) Prikazuje različico programskega orodja.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Prikazuje pomnoževalnik ADC (skaliranje napetosti baterije).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Navaja, ali ima uprava področje za upravljanje z energijo.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Prikaže trenutni vir napajanja: zunanji ali baterija.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Prikazuje najnovejšo razlog za ponovno nastavitve in izklop.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Prikazuje napetost baterije v mV ob zagonu.",
|
||||
"repeater_cliHelpSensorGet": "Prebere določeno vrednost senzorja preko tipke.",
|
||||
"repeater_cliHelpSensorSet": "Ustvari prilagojeno nastavitev za senzor.",
|
||||
"repeater_cliHelpSensorList": "Navaja vse nastavitve za uporabniške senzorje, razvrščene po želeni začetni indeksu.",
|
||||
"repeater_cliHelpRegionDefault": "Prikaže trenutno privzeto območje.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Določi privzeto območje. Za izbris uporabite \"<null>\".",
|
||||
"repeater_cliHelpRegionListAllowed": "Navaja regije, ki dovoljujejo promet v času poplav.",
|
||||
"repeater_cliHelpRegionListDenied": "Navaja regije, ki preprečujejo promet zaradi poplav.",
|
||||
"repeater_cliHelpStatsPackets": "(Samo za serijske povezave) Prikazuje statistiko na nivoju paketov.",
|
||||
"repeater_cliHelpStatsRadio": "(Samo za serije) Prikazuje statistične podatke o radiju.",
|
||||
"repeater_cliHelpStatsCore": "(Samo za serijske naprave) Prikazuje osnovne statistične podatke.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"settings_multiAck": "Več potrdil",
|
||||
"map_sharedAt": "Deljeno",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "Dotaknite blokirano točko, da jo označite na zemljeplati.",
|
||||
"losSelectedObstructionTitle": "Izbrano ovire",
|
||||
"losBlockedSpotsTitle": "Zasedena parkirišča",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"settings_companionDebugLog": "Log zapis za odpravljanje napak",
|
||||
"chat_markAsUnread": "Označiti kot neneobdelano",
|
||||
"chat_newMessages": "Nove novice",
|
||||
"settings_companionDebugLogSubtitle": "Navodila, odgovori in surova podatka za BLE/TCP/USB.",
|
||||
"repeater_chanUtil": "Uporaba kanala",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common_undo": "Preobrn",
|
||||
"messageStatus_delivered": "Dostavljeno",
|
||||
"messageStatus_sent": "Pošljeno",
|
||||
"messageStatus_pending": "Pošiljanje",
|
||||
"messageStatus_failed": "Uspešno ni bilo mogo, da se sporočilo pošlje",
|
||||
"messageStatus_repeated": "Slišal sem večkrat",
|
||||
"contacts_moreOptions": "Več možnosti",
|
||||
"contacts_searchOpen": "Iskanje kontaktov",
|
||||
"contacts_searchClose": "Izklopi iskanje",
|
||||
"routing_title": "Navigacija",
|
||||
"routing_modeAuto": "Avto",
|
||||
"routing_modeFlood": "Poplavo",
|
||||
"routing_modeManual": "Navodilo",
|
||||
"routing_modeAutoHint": "Samodejno izbere najbolj poznano pot, in sicer, ko ni na voljo nobena.",
|
||||
"routing_modeFloodHint": "Prenosi preko vseh repetitorjev. Najzanesljivejši način, vendar zahteva več časa.",
|
||||
"routing_modeManualHint": "Vedno sledi natančni poti, ki jo ste določili.",
|
||||
"routing_currentRoute": "Trenutna pot",
|
||||
"routing_directNoHops": "Neposredno – brez prehodov",
|
||||
"routing_noPathYet": "Žep trenutno ni mogoče najti. Naslednje sporočilo bo posredovano, dokler ne bo ugotovljeno, kje je pot.",
|
||||
"routing_floodBroadcast": "Prenos preko vseh repetitiv",
|
||||
"routing_editPath": "Uredi pot",
|
||||
"routing_forgetPath": "Pozabi na pot",
|
||||
"routing_knownPaths": "Poznati poti",
|
||||
"routing_knownPathsHint": "Kliknite na pot, da jo izberete.",
|
||||
"routing_inUse": "V uporabi",
|
||||
"routing_qualityStrong": "Močan prvi korak",
|
||||
"routing_qualityGood": "Prva uspešna faza",
|
||||
"routing_qualityFair": "Prva, uspešna faza",
|
||||
"routing_qualityWorked": "Izpolnil",
|
||||
"routing_qualityFlood": "Slišano preko poplave",
|
||||
"routing_qualityUntested": "Ne preizkušen",
|
||||
"routing_lastWorked": "delal/a {when}",
|
||||
"routing_neverWorked": "nikoli ni bilo potrjeno",
|
||||
"routing_floodDelivery": "Dostava zaradi poplave",
|
||||
"pathEditor_title": "Izgradnja poti",
|
||||
"pathEditor_hopCounter": "{count} od 64 različnih sort hropa",
|
||||
"pathEditor_noHops": "Še niso dodani hmelji. Za dodajanje hmelja v vrstnem redu kliknite na povezavo spodaj, ali pa shranite brez dodanega hmelja, da ga lahko posredujete neposredno.",
|
||||
"pathEditor_addHops": "Dodajte suho travo v skladu s postopkom.",
|
||||
"pathEditor_searchRepeaters": "Iskanje ponovitev",
|
||||
"pathEditor_advancedHex": "Napredno: surovi šestnajstni pot",
|
||||
"pathEditor_hexLabel": "Predfiks za heksadecimalno šifro",
|
||||
"pathEditor_hexHelper": "Dva šestbitna znaka na vsak skok, ločena z vejico",
|
||||
"pathEditor_invalidTokens": "Neveljaven: {tokens}",
|
||||
"pathEditor_tooManyHops": "Največ 64 hopov",
|
||||
"pathEditor_usePath": "Uporabite to poto",
|
||||
"pathEditor_removeHop": "Odstranite hmelj",
|
||||
"pathEditor_unknownHop": "Neznani ponovitelj",
|
||||
"map_zoomIn": "Povečaj",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Povečajte pogled",
|
||||
"map_centerMap": "Krajšarska karta",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth zahteva brskalnik Chromium.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS potrdilo",
|
||||
"pathTrace_legendInferred": "Izpeljana lokacija"
|
||||
}
|
||||
|
||||
+413
-33
@@ -33,6 +33,8 @@
|
||||
"common_remove": "Ta bort",
|
||||
"common_enable": "Aktivera",
|
||||
"common_disable": "Inaktivera",
|
||||
"common_autoRefresh": "Automatisk uppdatering",
|
||||
"common_interval": "Intervall",
|
||||
"common_reboot": "Start om",
|
||||
"common_loading": "Laddar...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -52,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner_title": "MeshCore Open",
|
||||
"scanner_title": "MeshCore – Öppen version",
|
||||
"scanner_scanning": "Söker efter enheter...",
|
||||
"scanner_connecting": "Anslutning...",
|
||||
"scanner_disconnecting": "Anslutning bryts...",
|
||||
@@ -104,6 +106,8 @@
|
||||
"settings_privacyModeEnabled": "Privatläget är aktiverat",
|
||||
"settings_privacyModeDisabled": "Privatläge är avstängt",
|
||||
"settings_actions": "Åtgärder",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "Skicka Annons",
|
||||
"settings_sendAdvertisementSubtitle": "Sändning finns nu",
|
||||
"settings_advertisementSent": "Annons skickad",
|
||||
@@ -121,7 +125,7 @@
|
||||
"settings_appDebugLog": "Appfelsökning",
|
||||
"settings_appDebugLogSubtitle": "Applikations felsökningsmeddelanden",
|
||||
"settings_about": "Om",
|
||||
"settings_aboutVersion": "MeshCore Open v{version}",
|
||||
"settings_aboutVersion": "MeshCore Open version {version}",
|
||||
"@settings_aboutVersion": {
|
||||
"placeholders": {
|
||||
"version": {
|
||||
@@ -146,7 +150,7 @@
|
||||
"settings_spreadingFactor": "Spreadingfaktor",
|
||||
"settings_codingRate": "Kodningsgrad",
|
||||
"settings_txPower": "TX-effekt (dBm)",
|
||||
"settings_txPowerHelper": "0 - 22",
|
||||
"settings_txPowerHelper": "0 – 22",
|
||||
"settings_txPowerInvalid": "Ogiltig TX-effekt (0-22 dBm)",
|
||||
"settings_error": "Fel: {message}",
|
||||
"@settings_error": {
|
||||
@@ -164,19 +168,19 @@
|
||||
"appSettings_themeDark": "Mörk",
|
||||
"appSettings_language": "Språk",
|
||||
"appSettings_languageSystem": "Systemstandard",
|
||||
"appSettings_languageEn": "English",
|
||||
"appSettings_languageFr": "Français",
|
||||
"appSettings_languageEs": "Español",
|
||||
"appSettings_languageDe": "Deutsch",
|
||||
"appSettings_languagePl": "Polski",
|
||||
"appSettings_languageSl": "Slovenščina",
|
||||
"appSettings_languagePt": "Português",
|
||||
"appSettings_languageIt": "Italiano",
|
||||
"appSettings_languageZh": "中文",
|
||||
"appSettings_languageEn": "Engelska",
|
||||
"appSettings_languageFr": "Franska",
|
||||
"appSettings_languageEs": "Spanska",
|
||||
"appSettings_languageDe": "Tyskt",
|
||||
"appSettings_languagePl": "Polsk",
|
||||
"appSettings_languageSl": "Sloveniska",
|
||||
"appSettings_languagePt": "Portugisiska",
|
||||
"appSettings_languageIt": "Italienska",
|
||||
"appSettings_languageZh": "Kinesiska",
|
||||
"appSettings_languageSv": "Svenska",
|
||||
"appSettings_languageNl": "Nederlands",
|
||||
"appSettings_languageSk": "Slovenčina",
|
||||
"appSettings_languageBg": "Български",
|
||||
"appSettings_languageNl": "Nederländska",
|
||||
"appSettings_languageSk": "Sloveniska",
|
||||
"appSettings_languageBg": "Bulgariska",
|
||||
"appSettings_notifications": "Meddelanden",
|
||||
"appSettings_enableNotifications": "Aktivera Notifikationer",
|
||||
"appSettings_enableNotificationsSubtitle": "Ta emot notiser för meddelanden och reklam",
|
||||
@@ -209,9 +213,9 @@
|
||||
}
|
||||
},
|
||||
"appSettings_batteryChemistryConnectFirst": "Anslut till en enhet för att välja",
|
||||
"appSettings_batteryNmc": "18650 NMC (3.0-4.2V)",
|
||||
"appSettings_batteryNmc": "18650 NMC (3,0-4,2V)",
|
||||
"appSettings_batteryLifepo4": "LiFePO4 (2,6–3,65V)",
|
||||
"appSettings_batteryLipo": "LiPo (3.0-4.2V)",
|
||||
"appSettings_batteryLipo": "LiPo (3,0-4,2V)",
|
||||
"appSettings_mapDisplay": "Kartvisning",
|
||||
"appSettings_showRepeaters": "Visa återuppslag",
|
||||
"appSettings_showRepeatersSubtitle": "Visa återspelsnoder på kartan",
|
||||
@@ -337,11 +341,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "Hashtagkanal",
|
||||
"channels_public": "Offentligt",
|
||||
"channels_private": "Privat",
|
||||
"channels_publicChannel": "Allmänt kanal",
|
||||
"channels_privateChannel": "Privat kanal",
|
||||
"channels_editChannel": "Redigera kanal",
|
||||
"channels_muteChannel": "Tysta kanal",
|
||||
"channels_unmuteChannel": "Slå på ljud för kanal",
|
||||
@@ -367,7 +368,7 @@
|
||||
"channels_channelName": "Kanalnamn",
|
||||
"channels_usePublicChannel": "Använd Publikkanal",
|
||||
"channels_standardPublicPsk": "Standard allmän PSK",
|
||||
"channels_pskHex": "PSK (Hex)",
|
||||
"channels_pskHex": "PSK (heks)",
|
||||
"channels_generateRandomPsk": "Generera slumpmässig PSK",
|
||||
"channels_enterChannelName": "Ange en kanalnamn",
|
||||
"channels_pskMustBe32Hex": "PSK måste vara 32 hexadecimala tecken",
|
||||
@@ -388,6 +389,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ-komprimering",
|
||||
"channels_cyr2latCompression": "Cyr2Lat-komprimering",
|
||||
"channels_cyr2latCompressionDscr": "Ersätter vissa kyrilliska tecken med latinska tecken när du skickar.",
|
||||
"channels_cyr2latSettingsHeading": "Inställningar för Cyr2Lat",
|
||||
"channels_cyr2latSettingsSubheading": "Ersättningslista",
|
||||
"channels_cyr2latSettingsDscr": "Redigera JSON-konfigurationen för teckenersättning",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON-ersättningskarta",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "Felaktig JSON: {error}",
|
||||
"settings_cyr2latProfileAdd": "Lägg till Cyr2Lat-profil",
|
||||
"settings_cyr2latProfileName": "Profilnamn",
|
||||
"settings_cyr2latProfileNameEmpty": "Profilnamnet får inte vara tomt",
|
||||
"settings_cyr2latProfileAdded": "Profilen har lagts till",
|
||||
"settings_cyr2latProfileUpdated": "Profilen har uppdaterats",
|
||||
"settings_cyr2latProfileEdit": "Redigera Cyr2Lat-profil",
|
||||
"settings_cyr2latProfileDelete": "Ta bort Cyr2Lat-profil",
|
||||
"settings_cyr2latProfileDeleted": "Profilen har tagits bort",
|
||||
"settings_cyr2latProfileDeleteDscr": "Är du säker på att du vill ta bort profilen \"{name}\"?",
|
||||
"channels_channelUpdated": "Kanalen \"{name}\" har uppdaterats",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -531,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugFrame_textTypeCli": "CLI",
|
||||
"debugFrame_textTypeCli": "Kommandorad",
|
||||
"debugFrame_textTypePlain": "Enkel",
|
||||
"debugFrame_text": "- Text: \"{text}\"",
|
||||
"@debugFrame_text": {
|
||||
@@ -550,7 +567,7 @@
|
||||
"chat_pathHistoryFull": "Historisk sökväg är full. Ta bort poster för att lägga till nya.",
|
||||
"chat_hopSingular": "hoppa",
|
||||
"chat_hopPlural": "hoppar",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
|
||||
"chat_hopsCount": "{count} {count, plural, =1{hopp} other{hopp} }",
|
||||
"@chat_hopsCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
@@ -881,9 +898,9 @@
|
||||
"repeater_managementTools": "Administrationsverktyg",
|
||||
"repeater_status": "Status",
|
||||
"repeater_statusSubtitle": "Visa återspolningsstatus, statistik och grannar",
|
||||
"repeater_telemetry": "Telemetry",
|
||||
"repeater_telemetry": "Telemetri",
|
||||
"repeater_telemetrySubtitle": "Visa telemetri för sensorer och systemstatistik",
|
||||
"repeater_cli": "CLI",
|
||||
"repeater_cli": "Kommandoradgränssnitt",
|
||||
"repeater_cliSubtitle": "Skicka kommandon till repetitorn",
|
||||
"repeater_settings": "Inställningar",
|
||||
"repeater_settingsSubtitle": "Konfigurera återspolarparametrar",
|
||||
@@ -992,7 +1009,7 @@
|
||||
"repeater_guestPasswordHelper": "Läs-skyddspassord",
|
||||
"repeater_radioSettings": "Radioinställningar",
|
||||
"repeater_frequencyMhz": "Frekvens (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300–2500 MHz",
|
||||
"repeater_txPower": "TX Effekt",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "Bandbredd",
|
||||
@@ -1059,6 +1076,81 @@
|
||||
},
|
||||
"repeater_confirm": "Bekräfta",
|
||||
"repeater_settingsSaved": "Inställningarna sparades framgångsrikt.",
|
||||
"repeater_rxGain": "Ökad RX-vinst",
|
||||
"repeater_rxGainHelper": "Ökad känslighet, högre strömförbrukning (endast för SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "Återställ förbättrad RX-signalstyrka",
|
||||
"repeater_multiAcks": "Flera bekräftelser",
|
||||
"repeater_multiAcksSubtitle": "Bekräfta meddelanden via flera olika kanaler för bättre leverans.",
|
||||
"repeater_refreshMultiAcks": "Återställ flera ACK-meddelanden",
|
||||
"repeater_networkHealth": "Nätverkets hälsa",
|
||||
"repeater_loopDetect": "Identifiering av loopar",
|
||||
"repeater_loopDetectHelper": "Skapa \"flödespaket\" som ser ut som att de bildar en loop (en återkommande krets).",
|
||||
"repeater_loopDetectOff": "Av",
|
||||
"repeater_loopDetectMinimal": "Minimal",
|
||||
"repeater_loopDetectModerate": "Måttlig",
|
||||
"repeater_loopDetectStrict": "Strikt",
|
||||
"repeater_dutyCycle": "Arbetscykel",
|
||||
"repeater_dutyCycleHelper": "Maximal procentandel av sändningstid",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "Information om operatören",
|
||||
"repeater_ownerInfoHelper": "Offentliga metadata för denna sändare",
|
||||
"repeater_refreshOwnerInfo": "Uppdatera information om personal",
|
||||
"repeater_floodMax": "Maximala mängden humle",
|
||||
"repeater_floodMaxHelper": "Maximalt antal hopp en paket kan färdas (0-64)",
|
||||
"repeater_advancedSettings": "Avancerad",
|
||||
"repeater_advancedSettingsSubtitle": "Ställjusteringsknappar för erfarna användare",
|
||||
"repeater_pathHashMode": "Hash-läge för sökväg",
|
||||
"repeater_pathHashModeHelper": "Byte används för att koda denna repeaters ID i taggar för att upptäcka loopar/flödesvägar. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Versioner 1.13 och äldre har stöd för multi-byte-vägar – endast en gång när nätverket är aktiverat (från och med version 1.14).",
|
||||
"repeater_txDelay": "Försening i Flood TX",
|
||||
"repeater_txDelayHelper": "Återöverföringsintervall för trafik under perioder med hög belastning, som en multiplikator av paketets överföringstid (0-2, standard 0,5). Högre värde = färre kollisioner, men långsammare leverans.",
|
||||
"repeater_directTxDelay": "Direkt TX-fördröjning",
|
||||
"repeater_directTxDelayHelper": "Återöverföringsintervall för direkt (icke-översvämmande) trafik, som en multiplikator av paketets överföringstid (0-2, standard 0,3).",
|
||||
"repeater_intThresh": "Tröskelvärde för störning",
|
||||
"repeater_intThreshHelper": "Tröskelvärdet har ställts in så att den filtrerar bort störningar som överstiger detta värde. 0 stänger av – aktivera endast om du ser RX-fel i ett störningsfyllt frekvensområde.",
|
||||
"repeater_agcResetInterval": "Återställningsintervall för AGC",
|
||||
"repeater_agcResetIntervalHelper": "Hur ofta ska man återställa radioens automatiska förstärkning för att återhämta sig från ett tillstånd där förstärkningen är fast? Sekunder, inställda till en multipel av 4. 0 stänger av periodiska återställningar.",
|
||||
"repeater_actionsTitle": "Åtgärder",
|
||||
"repeater_sendAdvert": "Skicka annons om översvämning",
|
||||
"repeater_sendAdvertSubtitle": "Sänd en reklamfilm om översvämningar via nätverket.",
|
||||
"repeater_sendAdvertZeroHop": "Skicka en annons som inte kräver någon mellanstopp",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "Sänd en reklamkampanj med en enda sändare (utan mellanliggande sändare).",
|
||||
"repeater_clockSync": "Synkronisera klockan nu",
|
||||
"repeater_clockSyncSubtitle": "Ställ din telefons tid till repeatern.",
|
||||
"repeater_actionSucceeded": "{action} lyckades",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} misslyckades: {error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "Inställningar sparade – starta om repetern för att tillämpa dem",
|
||||
"repeater_settingsPartialFailure": "Vissa inställningar misslyckades: {failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "Fel vid sparande av inställningar: {error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1070,11 +1162,9 @@
|
||||
"repeater_refreshBasicSettings": "Återställ Grundläggande Inställningar",
|
||||
"repeater_refreshRadioSettings": "Återställ Radiosinställningar",
|
||||
"repeater_refreshTxPower": "Återställ TX-effekt",
|
||||
"repeater_refreshLocationSettings": "Uppdatera Lokationsinställningar",
|
||||
"repeater_refreshPacketForwarding": "Återställ Paketväxling",
|
||||
"repeater_refreshGuestAccess": "Återställ Gäståtkomst",
|
||||
"repeater_refreshPrivacyMode": "Återställ Sekretessläge",
|
||||
"repeater_refreshAdvertisementSettings": "Återställ Annonsinställningar",
|
||||
"repeater_refreshed": "{label} har uppdaterats",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1192,6 +1282,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "Digital ingång",
|
||||
"telemetry_digitalOutputLabel": "Digital utgång",
|
||||
"telemetry_analogInputLabel": "Analog ingång",
|
||||
"telemetry_analogOutputLabel": "Analog utgång",
|
||||
"telemetry_genericLabel": "Allmän sensor",
|
||||
"telemetry_luminosityLabel": "Ljusstyrka",
|
||||
"telemetry_presenceLabel": "Närvaro",
|
||||
"telemetry_humidityLabel": "Luftfuktighet",
|
||||
"telemetry_accelerometerLabel": "Accelerometer",
|
||||
"telemetry_pressureLabel": "Tryck",
|
||||
"telemetry_altitudeLabel": "Höjd",
|
||||
"telemetry_frequencyLabel": "Frekvens",
|
||||
"telemetry_percentageLabel": "Procent",
|
||||
"telemetry_concentrationLabel": "Koncentration",
|
||||
"telemetry_powerLabel": "Effekt",
|
||||
"telemetry_distanceLabel": "Avstånd",
|
||||
"telemetry_energyLabel": "Energi",
|
||||
"telemetry_directionLabel": "Riktning",
|
||||
"telemetry_timeLabel": "Tid",
|
||||
"telemetry_gyrometerLabel": "Gyrometer",
|
||||
"telemetry_colourLabel": "Färg",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "Brytare",
|
||||
"telemetry_polylineLabel": "Polylinje",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "Antal förfrågningar",
|
||||
"telemetry_error": "Det gick inte att hämta data",
|
||||
"telemetry_noData": "Inga telemetridata tillgängliga.",
|
||||
"telemetry_channelTitle": "Kanal {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1477,7 +1604,7 @@
|
||||
"community_qrTitle": "Dela Gemenskap",
|
||||
"community_qrInstructions": "Skanna denna QR-kod för att gå med i \"{name}\"",
|
||||
"community_hashtagPrivacyHint": "Community-hashtagkanaler kan endast nås av medlemmar i communityn",
|
||||
"community_hashtagChannel": "Community Hashtag",
|
||||
"community_hashtagChannel": "Hashtag för gemenskapen",
|
||||
"community_invalidQrCode": "Ogiltig community QR-kod",
|
||||
"community_alreadyMember": "Är redan medlem",
|
||||
"community_alreadyMemberMessage": "Du är redan medlem av \"{name}\".",
|
||||
@@ -1504,7 +1631,7 @@
|
||||
"community_regularHashtagDesc": "Offentlig hashtag (alla kan gå med)",
|
||||
"community_communityHashtagDesc": "Endast för medlemmar",
|
||||
"community_forCommunity": "För {name}",
|
||||
"community_communityHashtag": "Community Hashtag",
|
||||
"community_communityHashtag": "Gemenskaps-hashtag",
|
||||
"@community_regenerateSecretConfirm": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
@@ -1551,7 +1678,7 @@
|
||||
"pathTrace_failed": "Sökvägsföljning misslyckades.",
|
||||
"pathTrace_notAvailable": "Path trace ej tillgänglig.",
|
||||
"pathTrace_refreshTooltip": "Uppdatera Path Trace",
|
||||
"contacts_pathTrace": "Path Trace",
|
||||
"contacts_pathTrace": "Spårning",
|
||||
"contacts_ping": "Ping",
|
||||
"contacts_repeaterPathTrace": "Vägspårning till repeater",
|
||||
"contacts_repeaterPing": "Ping-repeater",
|
||||
@@ -1879,7 +2006,7 @@
|
||||
"tcpHostLabel": "IP-adress",
|
||||
"tcpScreenTitle": "Anslut via TCP",
|
||||
"connectionChoiceTcpLabel": "TCP",
|
||||
"tcpPortLabel": "Port",
|
||||
"tcpPortLabel": "Hamn",
|
||||
"tcpPortHint": "5000",
|
||||
"tcpStatus_notConnected": "Ange slutpunkt och anslut",
|
||||
"tcpStatus_connectingTo": "Anslutning till {endpoint}...",
|
||||
@@ -1934,6 +2061,7 @@
|
||||
"appSettings_maxMessageRetriesSubtitle": "Antal försök att skicka om ett meddelande innan det markeras som misslyckat.",
|
||||
"path_routeWeight": "{weight}/{max}",
|
||||
"settings_telemetryModeUpdated": "Telemetri-läge uppdaterat",
|
||||
"settings_multiAck": "Flera bekräftelser",
|
||||
"map_showOverlaps": "Repeater-nyckelöverlappningar",
|
||||
"map_runTraceWithReturnPath": "Gå tillbaka på samma väg",
|
||||
"@radioStats_noiseFloor": {
|
||||
@@ -2011,6 +2139,9 @@
|
||||
"translation_title": "Översättning",
|
||||
"translation_composerTitle": "Översätt innan du skickar",
|
||||
"translation_composerSubtitle": "Styr standardtillståndet för kompositorns översättningsikon.",
|
||||
"translation_autoIncomingTitle": "Översätt meddelanden automatiskt",
|
||||
"translation_autoIncomingSubtitle": "Översätter meddelanden automatiskt för aviseringar och för chattar eller kanaler.",
|
||||
"translation_translateMessage": "Översätt meddelande",
|
||||
"translation_targetLanguage": "Målmedvetet språk",
|
||||
"translation_useAppLanguage": "Använd appens språk",
|
||||
"translation_downloadedModelLabel": "Nedladdad modell",
|
||||
@@ -2066,5 +2197,254 @@
|
||||
"chat_sendMessage": "Skicka meddelande",
|
||||
"repeater_guestTools": "Gästverktyg",
|
||||
"room_guest": "Information om servern",
|
||||
"settings_multiAck": "Flera bekräftelser"
|
||||
"repeater_getCategory": "Hämta värden",
|
||||
"repeater_powerMgmt": "Effektstyrning",
|
||||
"repeater_sensors": "Sensorer",
|
||||
"repeater_cliHelpPowerOff": "Stänger av enheten. (ingen respons förväntas)",
|
||||
"repeater_cliHelpClkReboot": "Återställer klockan till en känd tidpunkt och startar om enheten.",
|
||||
"repeater_cliHelpAdvertZeroHop": "Skickar en annons som når endast direkt grannar (endast närmaste grannar).",
|
||||
"repeater_cliHelpStartOta": "Startar en firmware-uppdatering via luft, på kompatibla enheter.",
|
||||
"repeater_cliHelpTime": "Ställer enheten till den angivna Unix-epokens tid. Klockan kan inte gå bakåt.",
|
||||
"repeater_cliHelpBoard": "Visar tillverkaren av moderkortet / hårdvaru-identifieraren.",
|
||||
"repeater_cliHelpDiscoverNeighbors": "Skickar en förfrågan om att upptäcka närliggande noder. (Endast för repetrar)",
|
||||
"repeater_cliHelpPowersaving": "Visar om energisparläget är aktiverat eller avstängt.",
|
||||
"repeater_cliHelpPowersavingOnOff": "Aktiverar eller inaktiverar energisparläget (om det stöds).",
|
||||
"repeater_cliHelpErase": "(Endast för seriell kommunikation) Formaterar enhetens filsystem. Raderar alla inställningar och kontakter.",
|
||||
"repeater_cliHelpSetDutyCycle": "Anger den maximala tillåtna överföringsfrekvensen som en procent (1-100). Justerar automatiskt tidsfaktorn.",
|
||||
"repeater_cliHelpSetPrvKey": "(Endast för seriell användning) Ersätter enhetsens privata nyckel. Återstart krävs för att tillämpa. Genererar en ny publik nyckel.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(Endast SX126x) Aktiverar förstärkt mottagargain för förbättrad känslighet vid högre strömförbrukning.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Anger kontaktinformationen som ska inkluderas i annonserna. Använd '|' för att separera olika fält.",
|
||||
"repeater_cliHelpSetPathHashMode": "Definierar läget för hash-baserad ruttning. 0 = äldre läge, 1 = standard, 2 = strikt. Påverkar hur ruttvägar matchas.",
|
||||
"repeater_cliHelpSetLoopDetect": "Ställer in känsligheten för att detektera loopar i routningen: av, minimal, måttlig eller strikt.",
|
||||
"repeater_cliHelpSetFreq": "(Endast för seriell kommunikation) Ställer snabbt bara frekvensen. Kräver omstart. Föredrar \"ställ radio\" för att få full kontroll över radioinställningarna.",
|
||||
"repeater_cliHelpSetBridgeChannel": "(Endast ESPNow-brygga) Anger WiFi-kanalen (1-14) som används av bryggan.",
|
||||
"repeater_cliHelpGetName": "Visar det konfigurerade nodnamnet.",
|
||||
"repeater_cliHelpGetRole": "Visar firmware-funktionen (Repeater, Room Server, etc.).",
|
||||
"repeater_cliHelpGetPublicKey": "Visar enhetens publika nyckel.",
|
||||
"repeater_cliHelpGetPrvKey": "(Endast för seriell användning) Visar enheters privata nyckel. Behandla detta som en hemlighet.",
|
||||
"repeater_cliHelpGetRepeat": "Visar om funktionen för att vidarebefordra paket (som en repeater) är aktiverad eller inaktiverad.",
|
||||
"repeater_cliHelpGetTx": "Visar aktuell TX-effekt i dBm.",
|
||||
"repeater_cliHelpGetFreq": "Visar den konfigurerade radiovågen i MHz.",
|
||||
"repeater_cliHelpGetRadio": "Visar alla radioparametrar: frekvens, bandbredd, spridningsfaktor, kodningshastighet.",
|
||||
"repeater_cliHelpGetRadioRxGain": "(Endast för SX126x) Visar RX:s förstärkningstillstånd.",
|
||||
"repeater_cliHelpGetAf": "Visar aktuell tidssats.",
|
||||
"repeater_cliHelpGetDutyCycle": "Visar den aktuella tillåtna arbetscykeln i procent.",
|
||||
"repeater_cliHelpGetIntThresh": "Visar gränsen för kanalinterferens i dB.",
|
||||
"repeater_cliHelpGetAgcResetInterval": "Visar återställningsintervallet för AGC i sekunder.",
|
||||
"repeater_cliHelpGetMultiAcks": "Visar om dubbelbekräftelseläget är aktiverat (1) eller avstängt (0).",
|
||||
"repeater_cliHelpGetAllowReadOnly": "Visar om gäst har tillåtelse att endast läsa.",
|
||||
"repeater_cliHelpGetAdvertInterval": "Visar den lokala reklampausens längd i minuter.",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "Visar tidsintervallet för reklamsegmentet under översvämningen, i timmar.",
|
||||
"repeater_cliHelpGetGuestPassword": "Visar det angivna gästlösen.",
|
||||
"repeater_cliHelpGetLat": "Visar den angivna latituden.",
|
||||
"repeater_cliHelpGetLon": "Visar den angivna longituden.",
|
||||
"repeater_cliHelpGetRxDelay": "Visar grundvärdet för rxdelay.",
|
||||
"repeater_cliHelpGetTxDelay": "Visar faktor för fördröjning i flödesläge.",
|
||||
"repeater_cliHelpGetDirectTxDelay": "Visar faktorn för fördröjning i direktläge.",
|
||||
"repeater_cliHelpGetFloodMax": "Visar det maximala antalet gånger en översvämning har inträffat.",
|
||||
"repeater_cliHelpGetOwnerInfo": "Visar strängen med kontaktinformation för ägaren.",
|
||||
"repeater_cliHelpGetPathHashMode": "Visar hash-läge (0/1/2).",
|
||||
"repeater_cliHelpGetLoopDetect": "Visar känsligheten för att detektera loopar.",
|
||||
"repeater_cliHelpGetAcl": "(Endast för serier) Visar åtkomstkontrollinställningarna för en repeater.",
|
||||
"repeater_cliHelpGetBridgeEnabled": "Visar om bron är aktiverad.",
|
||||
"repeater_cliHelpGetBridgeDelay": "Visar fördröjningen i bron i millisekunder.",
|
||||
"repeater_cliHelpGetBridgeSource": "Visar om bron skickar RX- eller TX-paket.",
|
||||
"repeater_cliHelpGetBridgeBaud": "(Enbart RS232-brygga) Visar bryggans baud-hastighet.",
|
||||
"repeater_cliHelpGetBridgeChannel": "(Endast ESPNow-brygga) Visar WiFi-kanal för bryggan.",
|
||||
"repeater_cliHelpGetBridgeSecret": "(Endast ESPNow-brygga) Visar bryggans delade hemlighet.",
|
||||
"repeater_cliHelpGetBootloaderVer": "(Endast för NRF52) Visar versionen av bootloadern.",
|
||||
"repeater_cliHelpGetAdcMultiplier": "Visar ADC-multiplikatorn (skalning av batterispänning).",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "Anger om styrelsen har stöd för energihantering.",
|
||||
"repeater_cliHelpGetPwrMgtSource": "Visar aktuell strömkälla: extern eller batteri.",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "Visar de senaste orsakerna till återställning och avstängning.",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "Visar batterispänningen vid start i millivolt (mV).",
|
||||
"repeater_cliHelpSensorGet": "Läser en anpassad sensorinställning via tangentbordet.",
|
||||
"repeater_cliHelpSensorSet": "Skapar en anpassad inställning för en sensor.",
|
||||
"repeater_cliHelpSensorList": "Visar alla anpassade sensorinställningar, sorterade från ett valfritt startindex.",
|
||||
"repeater_cliHelpRegionDefault": "Visar det aktuella standardområde.",
|
||||
"repeater_cliHelpRegionDefaultSet": "Definierar standardområde. Använd \"<null>\" för att återställa till standard.",
|
||||
"repeater_cliHelpRegionListAllowed": "Lista områden där det är tillåtet med trafik under översvämningsförhållanden.",
|
||||
"repeater_cliHelpRegionListDenied": "Listar områden där trafik på grund av översvämningar är förbjuden.",
|
||||
"repeater_cliHelpStatsPackets": "(Endast för seriell kommunikation) Visar statistik på paketnivå.",
|
||||
"repeater_cliHelpStatsRadio": "(Enbart för serier) Visar radiostatistik.",
|
||||
"repeater_cliHelpStatsCore": "(Enbart för seriell kommunikation) Visar grundläggande firmware-statistik.",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "Delad",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsTitle": "Reserverade platser",
|
||||
"losSelectedObstructionTitle": "Vald hinder",
|
||||
"losBlockedSpotsHint": "Klicka på en markerad plats för att framhäva den på kartan.",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"chat_markAsUnread": "Markera som oläst",
|
||||
"settings_companionDebugLog": "Följande felsökningslogg",
|
||||
"chat_newMessages": "Nya meddelanden",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-kommandon, svar och rådata",
|
||||
"repeater_chanUtil": "Användning av kanal",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "Sen",
|
||||
"messageStatus_delivered": "Levererad",
|
||||
"common_undo": "Ångra",
|
||||
"messageStatus_pending": "Skicka",
|
||||
"messageStatus_failed": "Misslyckades med att skicka",
|
||||
"messageStatus_repeated": "Hördes upprepade gånger",
|
||||
"contacts_moreOptions": "Fler alternativ",
|
||||
"contacts_searchOpen": "Sök efter kontakter",
|
||||
"contacts_searchClose": "Avancerad sökning",
|
||||
"routing_title": "Ruttplanering",
|
||||
"routing_modeAuto": "Bil",
|
||||
"routing_modeFlood": "Översvämning",
|
||||
"routing_modeManual": "Instruktioner",
|
||||
"routing_modeAutoHint": "Väljer automatiskt den bästa kända vägen, och använder en \"flooding\"-strategi om ingen väg är känd.",
|
||||
"routing_modeFloodHint": "Sändningar via alla repetrar. Det mest pålitliga alternativet, men kräver mer sändtid.",
|
||||
"routing_modeManualHint": "Skickar alltid den exakta väg du har angivit.",
|
||||
"routing_currentRoute": "Nuvarande rutt",
|
||||
"routing_directNoHops": "Direkt – utan mellanliggande routrar",
|
||||
"routing_noPathYet": "Ingen väg hittad ännu. Nästa meddelande skickas tills en rutt har upptäckts.",
|
||||
"routing_floodBroadcast": "Sändas via alla repetrar",
|
||||
"routing_editPath": "Redigera sökväg",
|
||||
"routing_forgetPath": "Glöm vägen",
|
||||
"routing_knownPaths": "Kända vägar",
|
||||
"routing_knownPathsHint": "Välj en väg för att byta till den.",
|
||||
"routing_inUse": "I användning",
|
||||
"routing_qualityStrong": "En stark start",
|
||||
"routing_qualityGood": "Bra första steg",
|
||||
"routing_qualityFair": "Bra första hopp",
|
||||
"routing_qualityWorked": "Har levererat",
|
||||
"routing_qualityFlood": "Fått information via nyhetsflöde",
|
||||
"routing_qualityUntested": "Ej testat",
|
||||
"routing_lastWorked": "arbetade {when}",
|
||||
"routing_neverWorked": "aldrig bekräftat",
|
||||
"routing_floodDelivery": "Leverans vid översvämningsområde",
|
||||
"pathEditor_title": "Skapa väg",
|
||||
"pathEditor_hopCounter": "{count} av 64 humlor",
|
||||
"pathEditor_noHops": "Inga humle än. Använd knapparna nedan för att lägga till dem i rätt ordning, eller spara utan humle för att skicka direkt.",
|
||||
"pathEditor_addHops": "Tillsätt humlen i rätt ordning.",
|
||||
"pathEditor_searchRepeaters": "Sök efter återupptagna samtal",
|
||||
"pathEditor_advancedHex": "Avancerat: rå hex-sökväg",
|
||||
"pathEditor_hexLabel": "Hex-prefikser",
|
||||
"pathEditor_hexHelper": "Två hex-tecken per steg, separerade med kommatecken.",
|
||||
"pathEditor_invalidTokens": "Ogiltigt: {tokens}",
|
||||
"pathEditor_tooManyHops": "Maximalt 64 humlörter",
|
||||
"pathEditor_usePath": "Använd denna väg",
|
||||
"pathEditor_removeHop": "Ta bort humlen",
|
||||
"pathEditor_unknownHop": "Okänd förstärkare",
|
||||
"map_zoomIn": "Zooma in",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"map_zoomOut": "Zooma ut",
|
||||
"map_centerMap": "Kartöversikt",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth kräver en Chromium-baserad webbläsare.",
|
||||
"channels_communityShortId": "ID: {id}...",
|
||||
"pathTrace_legendGpsConfirmed": "GPS-verifierat",
|
||||
"pathTrace_legendInferred": "Antagen position"
|
||||
}
|
||||
|
||||
+559
-199
File diff suppressed because it is too large
Load Diff
+392
-12
@@ -34,6 +34,8 @@
|
||||
"common_remove": "移除",
|
||||
"common_enable": "启用",
|
||||
"common_disable": "禁用",
|
||||
"common_autoRefresh": "自动刷新",
|
||||
"common_interval": "间隔",
|
||||
"common_reboot": "重启",
|
||||
"common_loading": "正在加载...",
|
||||
"common_notAvailable": "—",
|
||||
@@ -79,7 +81,7 @@
|
||||
"scanner_stop": "停止",
|
||||
"scanner_scan": "扫描",
|
||||
"device_quickSwitch": "快速切换",
|
||||
"device_meshcore": "MeshCore",
|
||||
"device_meshcore": "网格核心",
|
||||
"settings_title": "设置",
|
||||
"settings_deviceInfo": "设备信息",
|
||||
"settings_appSettings": "应用设置",
|
||||
@@ -109,6 +111,8 @@
|
||||
"settings_privacyModeEnabled": "隐私模式已启用",
|
||||
"settings_privacyModeDisabled": "隐私模式已关闭",
|
||||
"settings_actions": "操作",
|
||||
"settings_deleteAllPaths": "Delete All Paths",
|
||||
"settings_deleteAllPathsSubtitle": "Clear all path data from contacts.",
|
||||
"settings_sendAdvertisement": "发送广播",
|
||||
"settings_sendAdvertisementSubtitle": "立即发送广播",
|
||||
"settings_advertisementSent": "已发送广播",
|
||||
@@ -352,11 +356,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_hashtagChannel": "标签频道",
|
||||
"channels_public": "公共",
|
||||
"channels_private": "私有",
|
||||
"channels_publicChannel": "公共频道",
|
||||
"channels_privateChannel": "私有频道",
|
||||
"channels_editChannel": "编辑频道",
|
||||
"channels_muteChannel": "静音频道",
|
||||
"channels_unmuteChannel": "取消静音频道",
|
||||
@@ -403,6 +404,22 @@
|
||||
}
|
||||
},
|
||||
"channels_smazCompression": "SMAZ 压缩",
|
||||
"channels_cyr2latCompression": "Cyr2Lat 压缩",
|
||||
"channels_cyr2latCompressionDscr": "发送时将一些西里尔字符替换为拉丁字符。",
|
||||
"channels_cyr2latSettingsHeading": "Cyr2Lat 設定",
|
||||
"channels_cyr2latSettingsSubheading": "替換清單",
|
||||
"channels_cyr2latSettingsDscr": "編輯 JSON 字元替換設定檔",
|
||||
"channels_cyr2latSettingsDialogHint": "JSON 替換映射表",
|
||||
"channels_cyr2latSettingsDialogWrongJSON": "JSON 格式錯誤:{error}",
|
||||
"settings_cyr2latProfileAdd": "新增 Cyr2Lat 設定檔",
|
||||
"settings_cyr2latProfileName": "設定檔名稱",
|
||||
"settings_cyr2latProfileNameEmpty": "設定檔名稱不能為空",
|
||||
"settings_cyr2latProfileAdded": "設定檔已成功新增",
|
||||
"settings_cyr2latProfileUpdated": "設定檔已成功更新",
|
||||
"settings_cyr2latProfileEdit": "編輯 Cyr2Lat 設定檔",
|
||||
"settings_cyr2latProfileDelete": "刪除 Cyr2Lat 設定檔",
|
||||
"settings_cyr2latProfileDeleted": "設定檔已成功刪除",
|
||||
"settings_cyr2latProfileDeleteDscr": "您確定要刪除設定檔 \"{name}\" 嗎?",
|
||||
"channels_channelUpdated": "频道 \"{name}\" 已更新",
|
||||
"@channels_channelUpdated": {
|
||||
"placeholders": {
|
||||
@@ -414,7 +431,7 @@
|
||||
"channels_publicChannelAdded": "已添加公共频道",
|
||||
"channels_sortBy": "排序方式",
|
||||
"channels_sortManual": "手动",
|
||||
"channels_sortAZ": "A-Z",
|
||||
"channels_sortAZ": "A到Z",
|
||||
"channels_sortLatestMessages": "最新消息",
|
||||
"channels_sortUnread": "未读",
|
||||
"channels_createPrivateChannel": "创建私有频道",
|
||||
@@ -1022,7 +1039,7 @@
|
||||
"repeater_guestPasswordHelper": "只读访问密码",
|
||||
"repeater_radioSettings": "无线电设置",
|
||||
"repeater_frequencyMhz": "频率 (MHz)",
|
||||
"repeater_frequencyHelper": "300-2500 MHz",
|
||||
"repeater_frequencyHelper": "300-2500 兆赫",
|
||||
"repeater_txPower": "TX 功率",
|
||||
"repeater_txPowerHelper": "1-30 dBm",
|
||||
"repeater_bandwidth": "带宽",
|
||||
@@ -1089,6 +1106,81 @@
|
||||
},
|
||||
"repeater_confirm": "确认",
|
||||
"repeater_settingsSaved": "设置保存成功",
|
||||
"repeater_rxGain": "增强的 RX 增益",
|
||||
"repeater_rxGainHelper": "更高的灵敏度,更大的电流消耗(仅适用于 SX1262/SX1268)",
|
||||
"repeater_refreshRxGain": "重新启动增强型 RX 功能",
|
||||
"repeater_multiAcks": "多重确认",
|
||||
"repeater_multiAcksSubtitle": "通过多个路径确认消息,以提高传递效率。",
|
||||
"repeater_refreshMultiAcks": "刷新多个确认",
|
||||
"repeater_networkHealth": "网络健康",
|
||||
"repeater_loopDetect": "循环检测",
|
||||
"repeater_loopDetectHelper": "创建看起来像路由环的“洪水包”",
|
||||
"repeater_loopDetectOff": "离开",
|
||||
"repeater_loopDetectMinimal": "最少",
|
||||
"repeater_loopDetectModerate": "适度的",
|
||||
"repeater_loopDetectStrict": "严格",
|
||||
"repeater_dutyCycle": "工作周期",
|
||||
"repeater_dutyCycleHelper": "最大可使用的空闲时间百分比",
|
||||
"repeater_dutyCyclePercent": "{percent}%",
|
||||
"@repeater_dutyCyclePercent": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_ownerInfo": "运营商信息",
|
||||
"repeater_ownerInfoHelper": "此复播器的公共元数据",
|
||||
"repeater_refreshOwnerInfo": "刷新操作员信息",
|
||||
"repeater_floodMax": "最大跳跃次数",
|
||||
"repeater_floodMaxHelper": "一个洪水包中,最大可以传输的跳数 (0-64)",
|
||||
"repeater_advancedSettings": "高级",
|
||||
"repeater_advancedSettingsSubtitle": "高级操作员使用的调节旋钮",
|
||||
"repeater_pathHashMode": "路径哈希模式",
|
||||
"repeater_pathHashModeHelper": "用于编码此复用器的 ID 的字节数,在“洪流路径/环检测”标签中使用。 0=1 字节(256 个 ID,最多 64 个跳跃),1=2 字节(65K 个 ID,最多 32 个跳跃),2=3 字节(16M 个 ID,最多 21 个跳跃)。 v1.13 及更早版本的固件会使用多字节路径——只有在您的网络升级到 v1.14 或更高版本后才会生效。",
|
||||
"repeater_txDelay": "洪水(德克萨斯州)延误",
|
||||
"repeater_txDelayHelper": "对于洪水流量,重新传输间隔应设置为包的传输时间(0-2,默认值为0.5)的倍数。 较高的值意味着更少的冲突,但传输速度会变慢。",
|
||||
"repeater_directTxDelay": "直接的 TX 延迟",
|
||||
"repeater_directTxDelayHelper": "对于直接(非广播)流量,重新传输间隔应设置为包的传输时间(0-2,默认值为0.3)的倍数。",
|
||||
"repeater_intThresh": "干扰阈值",
|
||||
"repeater_intThreshHelper": "将阈值传递给射频信号的噪声水平校准,使其能够拒绝高于该水平的干扰。 0 表示禁用——只有在您在嘈杂频段中看到 RX 错误时才启用。",
|
||||
"repeater_agcResetInterval": "AGC 恢复间隔",
|
||||
"repeater_agcResetIntervalHelper": "为了从失控的增益状态中恢复,应该多久重置收音机的自动增益控制?设置为“秒”,每次重置间隔为4秒。将此选项设置为“0”将禁用周期性重置。",
|
||||
"repeater_actionsTitle": "行动",
|
||||
"repeater_sendAdvert": "发布防洪广告",
|
||||
"repeater_sendAdvertSubtitle": "通过网络播放防洪广告",
|
||||
"repeater_sendAdvertZeroHop": "发送零跳广告",
|
||||
"repeater_sendAdvertZeroHopSubtitle": "进行单跳广告广播(不使用中继)",
|
||||
"repeater_clockSync": "现在同步时钟",
|
||||
"repeater_clockSyncSubtitle": "将手机的时间设置为与中继器同步",
|
||||
"repeater_actionSucceeded": "{action} 成功",
|
||||
"@repeater_actionSucceeded": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_actionFailed": "{action} 失败:{error}",
|
||||
"@repeater_actionFailed": {
|
||||
"placeholders": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_settingsSavedRebootNeeded": "设置已保存 — 重启发射器以应用",
|
||||
"repeater_settingsPartialFailure": "部分设置失败:{failures}",
|
||||
"@repeater_settingsPartialFailure": {
|
||||
"placeholders": {
|
||||
"failures": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repeater_errorSavingSettings": "保存设置时出错:{error}",
|
||||
"@repeater_errorSavingSettings": {
|
||||
"placeholders": {
|
||||
@@ -1100,11 +1192,9 @@
|
||||
"repeater_refreshBasicSettings": "刷新基本设置",
|
||||
"repeater_refreshRadioSettings": "刷新无线电设置",
|
||||
"repeater_refreshTxPower": "刷新 TX 功率",
|
||||
"repeater_refreshLocationSettings": "刷新位置设置",
|
||||
"repeater_refreshPacketForwarding": "刷新包转发",
|
||||
"repeater_refreshGuestAccess": "刷新访客权限",
|
||||
"repeater_refreshPrivacyMode": "刷新隐私模式",
|
||||
"repeater_refreshAdvertisementSettings": "刷新广播设置",
|
||||
"repeater_refreshed": "{label} 已刷新",
|
||||
"@repeater_refreshed": {
|
||||
"placeholders": {
|
||||
@@ -1222,6 +1312,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_digitalInputLabel": "数字输入",
|
||||
"telemetry_digitalOutputLabel": "数字输出",
|
||||
"telemetry_analogInputLabel": "模拟输入",
|
||||
"telemetry_analogOutputLabel": "模拟输出",
|
||||
"telemetry_genericLabel": "通用传感器",
|
||||
"telemetry_luminosityLabel": "照度",
|
||||
"telemetry_presenceLabel": "存在检测",
|
||||
"telemetry_humidityLabel": "湿度",
|
||||
"telemetry_accelerometerLabel": "加速度计",
|
||||
"telemetry_pressureLabel": "气压",
|
||||
"telemetry_altitudeLabel": "高度",
|
||||
"telemetry_frequencyLabel": "频率",
|
||||
"telemetry_percentageLabel": "百分比",
|
||||
"telemetry_concentrationLabel": "浓度",
|
||||
"telemetry_powerLabel": "功率",
|
||||
"telemetry_distanceLabel": "距离",
|
||||
"telemetry_energyLabel": "能量",
|
||||
"telemetry_directionLabel": "方向",
|
||||
"telemetry_timeLabel": "时间",
|
||||
"telemetry_gyrometerLabel": "陀螺仪",
|
||||
"telemetry_colourLabel": "颜色",
|
||||
"telemetry_gpsLabel": "GPS",
|
||||
"telemetry_switchLabel": "开关",
|
||||
"telemetry_polylineLabel": "折线",
|
||||
"telemetry_altitudeValue": "{meters} m",
|
||||
"telemetry_frequencyValue": "{hertz} Hz",
|
||||
"telemetry_pressureValue": "{hpa} hPa",
|
||||
"telemetry_luminosityValue": "{lux} lx",
|
||||
"telemetry_powerValue": "{watts} W",
|
||||
"telemetry_distanceValue": "{meters} m",
|
||||
"telemetry_energyValue": "{kilowattHours} kWh",
|
||||
"telemetry_directionValue": "{degrees}°",
|
||||
"telemetry_concentrationValue": "{ppm} ppm",
|
||||
"telemetry_percentageValue": "{percent}%",
|
||||
"telemetry_analogValue": "{value}",
|
||||
"telemetry_autoFetchQuantity": "请求次数",
|
||||
"telemetry_error": "无法获取数据",
|
||||
"telemetry_noData": "暂无遥测数据",
|
||||
"telemetry_channelTitle": "频道 {channel}",
|
||||
"@telemetry_channelTitle": {
|
||||
@@ -1247,7 +1374,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_voltageValue": "{volts}V",
|
||||
"telemetry_voltageValue": "{volts}伏",
|
||||
"@telemetry_voltageValue": {
|
||||
"placeholders": {
|
||||
"volts": {
|
||||
@@ -1541,7 +1668,7 @@
|
||||
"listFilter_sortBy": "排序方式",
|
||||
"listFilter_latestMessages": "最新消息",
|
||||
"listFilter_heardRecently": "最近听到",
|
||||
"listFilter_az": "A-Z",
|
||||
"listFilter_az": "A到Z",
|
||||
"listFilter_filters": "筛选",
|
||||
"listFilter_all": "全部",
|
||||
"listFilter_users": "用户",
|
||||
@@ -1554,7 +1681,7 @@
|
||||
"pathTrace_notAvailable": "无法获取路径信息。",
|
||||
"pathTrace_refreshTooltip": "刷新路径追踪",
|
||||
"contacts_pathTrace": "路径追踪",
|
||||
"contacts_ping": "Ping",
|
||||
"contacts_ping": "乒",
|
||||
"contacts_repeaterPathTrace": "Trace 转发节点",
|
||||
"contacts_repeaterPing": "Ping 转发节点",
|
||||
"contacts_roomPathTrace": "Trace 房间服务器",
|
||||
@@ -2017,6 +2144,9 @@
|
||||
"translation_composerTitle": "在发送之前进行翻译",
|
||||
"translation_enableTitle": "启用翻译功能",
|
||||
"translation_composerSubtitle": "控制作曲家翻译图标的默认状态。",
|
||||
"translation_autoIncomingTitle": "自动翻译消息",
|
||||
"translation_autoIncomingSubtitle": "自动为通知以及聊天或频道翻译消息。",
|
||||
"translation_translateMessage": "翻译消息",
|
||||
"translation_targetLanguage": "目标语言",
|
||||
"translation_useAppLanguage": "使用应用程序语言",
|
||||
"translation_downloadedModelLabel": "下载的模型",
|
||||
@@ -2071,5 +2201,255 @@
|
||||
"repeater_guestTools": "访客工具",
|
||||
"repeater_guest": "重复器信息",
|
||||
"chat_sendMessage": "发送消息",
|
||||
"room_guest": "服务器信息"
|
||||
"room_guest": "服务器信息",
|
||||
"repeater_getCategory": "获取值",
|
||||
"repeater_powerMgmt": "电源管理",
|
||||
"repeater_sensors": "传感器",
|
||||
"repeater_cliHelpPowerOff": "关闭设备。(不应有任何响应)",
|
||||
"repeater_cliHelpClkReboot": "将时钟重置为已知的时间点,并重启设备。",
|
||||
"repeater_cliHelpAdvertZeroHop": "发送无中继广告(仅限于邻居)。",
|
||||
"repeater_cliHelpStartOta": "在支持的板上启动通过空中进行固件更新。",
|
||||
"repeater_cliHelpTime": "将设备时钟设置为给定的 Unix 纪元秒。时钟不能倒退。",
|
||||
"repeater_cliHelpBoard": "显示制造商/硬件标识。",
|
||||
"repeater_cliHelpDiscoverNeighbors": "向附近的邻居发送节点发现请求。(仅限中继器)",
|
||||
"repeater_cliHelpPowersaving": "显示节能模式是否已开启或已关闭。",
|
||||
"repeater_cliHelpPowersavingOnOff": "启用或禁用节能模式(如果支持)。",
|
||||
"repeater_cliHelpErase": "(仅适用于序列模式)格式化设备的文件系统。清除所有设置和联系人。",
|
||||
"repeater_cliHelpSetDutyCycle": "设定允许的最大传输时段百分比(1-100)。内部调整空闲时间因子。",
|
||||
"repeater_cliHelpSetPrvKey": "(仅适用于序列号)替换设备身份私钥。需要重启才能应用。生成一个新的公钥。",
|
||||
"repeater_cliHelpSetRadioRxGain": "(仅适用于 SX126x 芯片) 启用增强型 RX 增益,以在较高电流下提高灵敏度。",
|
||||
"repeater_cliHelpSetOwnerInfo": "设置广告中包含的联系人信息字符串。使用 '|' 作为换行符。",
|
||||
"repeater_cliHelpSetPathHashMode": "设置路径哈希模式。 0 = 传统模式,1 = 标准模式,2 = 严格模式。 影响路由路径的匹配方式。",
|
||||
"repeater_cliHelpSetLoopDetect": "设置路由环检测的灵敏度:关闭、低、中、或高。",
|
||||
"repeater_cliHelpSetFreq": "(仅限串行模式)快速设置频率。需要重启。 建议使用“设置收音机参数”功能,以便设置完整的收音机参数。",
|
||||
"repeater_cliHelpSetBridgeChannel": "(仅适用于 ESPNow 桥)设置桥使用的 WiFi 频道(1-14)。",
|
||||
"repeater_cliHelpGetName": "显示配置的节点名称。",
|
||||
"repeater_cliHelpGetRole": "显示固件的功能(如:中继器、房间服务器等)。",
|
||||
"repeater_cliHelpGetPublicKey": "显示设备的公钥。",
|
||||
"repeater_cliHelpGetPrvKey": "(仅适用于序列号)显示设备的私钥。请将其视为机密信息。",
|
||||
"repeater_cliHelpGetRepeat": "显示数据包转发(作为中继器)是否已启用或已禁用。",
|
||||
"repeater_cliHelpGetTx": "显示当前的发射功率(以dBm为单位)。",
|
||||
"repeater_cliHelpGetFreq": "显示配置的射频频率(以兆赫兹为单位)。",
|
||||
"repeater_cliHelpGetRadio": "显示完整的无线电参数:频率、带宽、扩频因子、编码速率。",
|
||||
"repeater_cliHelpGetRadioRxGain": "(仅适用于 SX126x 模块)显示 RX 放大器的状态。",
|
||||
"repeater_cliHelpGetAf": "显示当前的空闲时间系数。",
|
||||
"repeater_cliHelpGetDutyCycle": "显示当前允许的占空比(以百分比表示)。",
|
||||
"repeater_cliHelpGetIntThresh": "显示信道干扰阈值(以dB为单位)。",
|
||||
"repeater_cliHelpGetAgcResetInterval": "显示 AGC 重置的间隔时间(以秒为单位)。",
|
||||
"repeater_cliHelpGetMultiAcks": "显示双重确认模式是否已启用(1)或已禁用(0)。",
|
||||
"repeater_cliHelpGetAllowReadOnly": "显示是否允许访客仅限查看权限。",
|
||||
"repeater_cliHelpGetAdvertInterval": "显示本地广告的时间间隔,单位为分钟。",
|
||||
"repeater_cliHelpGetFloodAdvertInterval": "显示洪水广告的播放时间间隔,以小时为单位。",
|
||||
"repeater_cliHelpGetGuestPassword": "显示已配置的访客密码。",
|
||||
"repeater_cliHelpGetLat": "显示已配置的纬度。",
|
||||
"repeater_cliHelpGetLon": "显示已配置的经度。",
|
||||
"repeater_cliHelpGetRxDelay": "显示 rxdelay 的基本值。",
|
||||
"repeater_cliHelpGetTxDelay": "显示洪水模式下的传输延迟系数。",
|
||||
"repeater_cliHelpGetDirectTxDelay": "显示直接模式下的时延系数。",
|
||||
"repeater_cliHelpGetFloodMax": "显示最大洪水传播次数。",
|
||||
"repeater_cliHelpGetOwnerInfo": "显示所有者的联系信息。",
|
||||
"repeater_cliHelpGetPathHashMode": "显示哈希模式(0/1/2)。",
|
||||
"repeater_cliHelpGetLoopDetect": "显示循环检测的灵敏度。",
|
||||
"repeater_cliHelpGetAcl": "(仅适用于序列号)列出复用器上的访问控制条目。",
|
||||
"repeater_cliHelpGetBridgeEnabled": "显示桥是否已启用。",
|
||||
"repeater_cliHelpGetBridgeDelay": "显示桥梁延迟的时间,单位为毫秒。",
|
||||
"repeater_cliHelpGetBridgeSource": "显示桥接设备是否接收或发送 RX 或 TX 类型的数据包。",
|
||||
"repeater_cliHelpGetBridgeBaud": "(仅限 RS232 桥)显示桥的波特率。",
|
||||
"repeater_cliHelpGetBridgeChannel": "(仅适用于 ESPNow 桥)显示桥的 WiFi 通道。",
|
||||
"repeater_cliHelpGetBridgeSecret": "(仅适用于 ESPNow 桥)显示桥的共享密钥。",
|
||||
"repeater_cliHelpGetBootloaderVer": "(仅适用于NRF52)显示引导程序版本。",
|
||||
"repeater_cliHelpGetAdcMultiplier": "显示 ADC 乘数(电池电压缩放)。",
|
||||
"repeater_cliHelpGetPwrMgtSupport": "报告董事会是否支持电源管理功能。",
|
||||
"repeater_cliHelpGetPwrMgtSource": "显示当前的电源:外部电源或电池。",
|
||||
"repeater_cliHelpGetPwrMgtBootReason": "显示最近的重置和关闭原因。",
|
||||
"repeater_cliHelpGetPwrMgtBootMv": "显示启动时的电池电压,单位为毫伏 (mV)。",
|
||||
"repeater_cliHelpSensorGet": "通过按键读取自定义传感器设置。",
|
||||
"repeater_cliHelpSensorSet": "编写自定义传感器设置。",
|
||||
"repeater_cliHelpSensorList": "列出所有自定义传感器设置,并按可选的起始索引进行分页显示。",
|
||||
"repeater_cliHelpRegionDefault": "显示当前默认的区域范围。",
|
||||
"repeater_cliHelpRegionDefaultSet": "设置默认的区域范围。使用 \"<null>\" 可以清除。",
|
||||
"repeater_cliHelpRegionListAllowed": "列出允许洪水交通的区域。",
|
||||
"repeater_cliHelpRegionListDenied": "列出禁止洪水交通的区域。",
|
||||
"repeater_cliHelpStatsPackets": "(仅显示序列信息)显示数据包级别的统计信息。",
|
||||
"repeater_cliHelpStatsRadio": "(仅显示序列信息)显示收音机相关统计数据。",
|
||||
"repeater_cliHelpStatsCore": "(仅显示序列号)显示核心固件统计信息。",
|
||||
"common_done": "Done",
|
||||
"background_serviceTitle": "MeshCore running",
|
||||
"background_serviceText": "Keeping BLE connected",
|
||||
"appSettings_translationModelDeleted": "Deleted {name}",
|
||||
"@appSettings_translationModelDeleted": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appSettings_translationModelDeleteFailed": "Failed to delete: {error}",
|
||||
"@appSettings_translationModelDeleteFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels_channelUpdateFailed": "Failed to update channel: {error}",
|
||||
"@channels_channelUpdateFailed": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_type": "Type",
|
||||
"map_path": "Path",
|
||||
"map_location": "Location",
|
||||
"map_estLocation": "Est. Location",
|
||||
"map_publicKey": "Public Key",
|
||||
"map_publicKeyPrefixHint": "e.g. ab12",
|
||||
"contact_typeChat": "Chat",
|
||||
"contact_typeRepeater": "Repeater",
|
||||
"contact_typeRoom": "Room",
|
||||
"contact_typeSensor": "Sensor",
|
||||
"contact_typeUnknown": "Unknown",
|
||||
"channels_via": "via {path}",
|
||||
"chat_score": "Score",
|
||||
"map_sharedAt": "已分享",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "被占用区域",
|
||||
"losBlockedSpotsHint": "点击地图上的某个被遮盖的区域,以突出显示该区域。",
|
||||
"losSelectedObstructionTitle": "选择性阻碍",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"chat_markAsUnread": "标记为未读",
|
||||
"settings_companionDebugLog": "调试日志",
|
||||
"chat_newMessages": "新的消息",
|
||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 协议、响应和原始数据",
|
||||
"repeater_chanUtil": "频道利用率",
|
||||
"@routing_lastWorked": {
|
||||
"placeholders": {
|
||||
"when": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@routing_deliveryCounts": {
|
||||
"placeholders": {
|
||||
"successes": {
|
||||
"type": "int"
|
||||
},
|
||||
"failures": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_hopCounter": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pathEditor_invalidTokens": {
|
||||
"placeholders": {
|
||||
"tokens": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@channels_communityShortId": {
|
||||
"placeholders": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageStatus_sent": "发送",
|
||||
"common_undo": "撤销",
|
||||
"messageStatus_delivered": "已送达",
|
||||
"messageStatus_pending": "发送",
|
||||
"messageStatus_failed": "发送失败",
|
||||
"messageStatus_repeated": "多次听到",
|
||||
"contacts_moreOptions": "更多选择",
|
||||
"contacts_searchOpen": "搜索联系人",
|
||||
"contacts_searchClose": "高级搜索",
|
||||
"routing_title": "路由",
|
||||
"routing_modeAuto": "汽车",
|
||||
"routing_modeFlood": "洪水",
|
||||
"routing_modeManual": "手册",
|
||||
"routing_modeAutoHint": "自动选择已知最佳路径,当没有已知路径时,则进行“洪水”搜索。",
|
||||
"routing_modeFloodHint": "通过所有中继站进行广播。 这种方式最可靠,但占用更多的时间。",
|
||||
"routing_modeManualHint": "总是按照您设置的路径进行导航。",
|
||||
"routing_currentRoute": "当前路线",
|
||||
"routing_directNoHops": "直接连接— 无中继跳",
|
||||
"routing_noPathYet": "目前还没有找到路径。直到找到路径,才会收到后续消息。",
|
||||
"routing_floodBroadcast": "通过所有中继器进行广播",
|
||||
"routing_editPath": "编辑路径",
|
||||
"routing_forgetPath": "忘记原路",
|
||||
"routing_knownPaths": "已知的路径",
|
||||
"routing_knownPathsHint": "点击该路径以切换到它。",
|
||||
"routing_inUse": "使用中",
|
||||
"routing_qualityStrong": "强劲的初始阶段",
|
||||
"routing_qualityGood": "不错的开端",
|
||||
"routing_qualityFair": "第一次尝试,结果良好",
|
||||
"routing_qualityWorked": "已完成",
|
||||
"routing_qualityFlood": "通过新闻报道",
|
||||
"routing_qualityUntested": "未经测试",
|
||||
"routing_lastWorked": "工作于 {when}",
|
||||
"routing_neverWorked": "从未得到证实",
|
||||
"routing_floodDelivery": "洪水配送",
|
||||
"pathEditor_title": "构建路径",
|
||||
"pathEditor_noHops": "目前还没有添加任何啤酒花。点击下面的“添加”按钮,按顺序添加,或者直接保存,不添加任何啤酒花。",
|
||||
"pathEditor_addHops": "按照顺序添加啤酒花",
|
||||
"pathEditor_searchRepeaters": "重复搜索",
|
||||
"pathEditor_advancedHex": "高级:原始十六进制路径",
|
||||
"pathEditor_hexLabel": "十六进制前缀",
|
||||
"pathEditor_hexHelper": "每次跳跃,使用两个十六进制字符,用逗号分隔。",
|
||||
"pathEditor_invalidTokens": "无效:{tokens}",
|
||||
"pathEditor_tooManyHops": "最多 64 个跳跃",
|
||||
"pathEditor_usePath": "请使用此路径",
|
||||
"pathEditor_removeHop": "去除啤酒花",
|
||||
"routing_deliveryCounts": "{successes} delivered, {failures} failed",
|
||||
"pathEditor_hopCounter": "{count} of 64 hops",
|
||||
"pathEditor_unknownHop": "未知的重复器",
|
||||
"map_zoomIn": "放大",
|
||||
"map_zoomOut": "放大",
|
||||
"map_centerMap": "中心地图",
|
||||
"chrome_bluetoothRequiresChromium": "Web Bluetooth 需要 Chromium 浏览器",
|
||||
"channels_communityShortId": "ID:{id}...",
|
||||
"pathTrace_legendGpsConfirmed": "通过GPS确认",
|
||||
"pathTrace_legendInferred": "推测的位置"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../models/contact.dart';
|
||||
import 'app_localizations.dart';
|
||||
|
||||
/// UI-level localization helpers for [Contact].
|
||||
///
|
||||
/// Kept out of the model layer so `Contact` does not depend on
|
||||
/// `AppLocalizations`. Use these from widgets/screens; for logs and
|
||||
/// non-UI export use `Contact.typeLabelRaw`.
|
||||
extension ContactLocalization on Contact {
|
||||
String typeLabel(AppLocalizations l10n) {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return l10n.contact_typeChat;
|
||||
case advTypeRepeater:
|
||||
return l10n.contact_typeRepeater;
|
||||
case advTypeRoom:
|
||||
return l10n.contact_typeRoom;
|
||||
case advTypeSensor:
|
||||
return l10n.contact_typeSensor;
|
||||
default:
|
||||
return l10n.contact_typeUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
String pathLabel(AppLocalizations l10n) {
|
||||
if (pathOverride != null) {
|
||||
if (pathOverride! < 0) return l10n.chat_floodForced;
|
||||
if (pathOverride == 0) return l10n.chat_directForced;
|
||||
return l10n.chat_hopsForced(pathOverride!);
|
||||
}
|
||||
if (pathLength < 0) return l10n.channelPath_floodPath;
|
||||
if (pathLength == 0) return l10n.chat_direct;
|
||||
return l10n.chat_hopsCount(pathLength);
|
||||
}
|
||||
}
|
||||
+38
-18
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -23,11 +24,21 @@ import 'services/translation_service.dart';
|
||||
import 'services/ui_view_state_service.dart';
|
||||
import 'services/timeout_prediction_service.dart';
|
||||
import 'storage/prefs_manager.dart';
|
||||
import 'theme/mesh_theme.dart';
|
||||
import 'utils/app_logger.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// On desktop, debugPrint is not suppressed in release builds and every
|
||||
// call is a synchronous stdout write. The connector logs heavily on hot
|
||||
// paths (frame handling, queue/channel sync), which shows up as syscall
|
||||
// overhead on low-end Linux machines (issue #202). The in-app debug log
|
||||
// screens are unaffected — they store entries themselves.
|
||||
if (kReleaseMode) {
|
||||
debugPrint = (String? message, {int? wrapWidth}) {};
|
||||
}
|
||||
|
||||
// Initialize SharedPreferences cache
|
||||
await PrefsManager.initialize();
|
||||
|
||||
@@ -59,6 +70,9 @@ void main() async {
|
||||
final notificationService = NotificationService();
|
||||
await notificationService.initialize();
|
||||
await backgroundService.initialize();
|
||||
backgroundService.setLanguageOverrideProvider(
|
||||
() => appSettingsService.settings.languageOverride,
|
||||
);
|
||||
_registerThirdPartyLicenses();
|
||||
|
||||
await chatTextScaleService.initialize();
|
||||
@@ -187,23 +201,8 @@ class MeshCoreApp extends StatelessWidget {
|
||||
locale: _localeFromSetting(
|
||||
settingsService.settings.languageOverride,
|
||||
),
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
|
||||
useMaterial3: true,
|
||||
snackBarTheme: const SnackBarThemeData(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
useMaterial3: true,
|
||||
snackBarTheme: const SnackBarThemeData(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
),
|
||||
theme: MeshTheme.light(),
|
||||
darkTheme: MeshTheme.dark(),
|
||||
themeMode: _themeModeFromSetting(
|
||||
settingsService.settings.themeMode,
|
||||
),
|
||||
@@ -211,7 +210,10 @@ class MeshCoreApp extends StatelessWidget {
|
||||
// Update notification service with resolved locale
|
||||
final locale = Localizations.localeOf(context);
|
||||
NotificationService().setLocale(locale);
|
||||
return child ?? const SizedBox.shrink();
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: _systemUiOverlayStyle(context),
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
home: (PlatformInfo.isWeb && !PlatformInfo.isChrome)
|
||||
? const ChromeRequiredScreen()
|
||||
@@ -233,6 +235,24 @@ class MeshCoreApp extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
SystemUiOverlayStyle _systemUiOverlayStyle(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
final isDark = theme.brightness == Brightness.dark;
|
||||
final iconBrightness = isDark ? Brightness.light : Brightness.dark;
|
||||
|
||||
// Keep Android system bars aligned with the resolved Flutter theme.
|
||||
return SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: iconBrightness,
|
||||
statusBarBrightness: isDark ? Brightness.dark : Brightness.light,
|
||||
systemNavigationBarColor: colorScheme.surface,
|
||||
systemNavigationBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarDividerColor: colorScheme.surface,
|
||||
systemNavigationBarContrastEnforced: false,
|
||||
);
|
||||
}
|
||||
|
||||
Locale? _localeFromSetting(String? languageCode) {
|
||||
if (languageCode == null) return null;
|
||||
return Locale(languageCode);
|
||||
|
||||
@@ -13,6 +13,67 @@ extension UnitSystemValue on UnitSystem {
|
||||
}
|
||||
}
|
||||
|
||||
const Map<String, String> defaultCyr2LatCharMap = {
|
||||
'А': 'A',
|
||||
'В': 'B',
|
||||
'Е': 'E',
|
||||
'Ё': 'E',
|
||||
'З': '3',
|
||||
'К': 'K',
|
||||
'М': 'M',
|
||||
'Н': 'H',
|
||||
'О': 'O',
|
||||
'Р': 'P',
|
||||
'С': 'C',
|
||||
'Т': 'T',
|
||||
'Х': 'X',
|
||||
'Ь': 'b',
|
||||
'а': 'a',
|
||||
'е': 'e',
|
||||
'ё': 'e',
|
||||
'о': 'o',
|
||||
'р': 'p',
|
||||
'с': 'c',
|
||||
'у': 'y',
|
||||
'х': 'x',
|
||||
};
|
||||
|
||||
class Cyr2LatProfile {
|
||||
final String id;
|
||||
final String name;
|
||||
final Map<String, String> charMap;
|
||||
|
||||
Cyr2LatProfile({required this.id, required this.name, required this.charMap});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'id': id, 'name': name, 'char_map': charMap};
|
||||
}
|
||||
|
||||
factory Cyr2LatProfile.fromJson(Map<String, dynamic> json) {
|
||||
return Cyr2LatProfile(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
charMap:
|
||||
(json['char_map'] as Map?)?.map(
|
||||
(key, value) => MapEntry(key.toString(), value.toString()),
|
||||
) ??
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
Cyr2LatProfile copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
Map<String, String>? charMap,
|
||||
}) {
|
||||
return Cyr2LatProfile(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
charMap: charMap ?? this.charMap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppSettings {
|
||||
static const Object _unset = Object();
|
||||
|
||||
@@ -52,11 +113,22 @@ class AppSettings {
|
||||
final int tcpServerPort;
|
||||
final bool jumpToOldestUnread;
|
||||
final bool translationEnabled;
|
||||
final bool autoTranslateIncomingMessages;
|
||||
final String? translationTargetLanguageCode;
|
||||
final bool composerTranslationEnabled;
|
||||
final String? translationModelSourceUrl;
|
||||
final String? translationSelectedModelId;
|
||||
final List<TranslationModelRecord> translationDownloadedModels;
|
||||
final List<Cyr2LatProfile> cyr2latProfiles;
|
||||
final String selectedCyr2latProfileId;
|
||||
|
||||
Map<String, String> get cyr2latCharMap {
|
||||
final profile = cyr2latProfiles.firstWhere(
|
||||
(p) => p.id == selectedCyr2latProfileId,
|
||||
orElse: () => cyr2latProfiles.first,
|
||||
);
|
||||
return profile.charMap;
|
||||
}
|
||||
|
||||
AppSettings({
|
||||
this.clearPathOnMaxRetry = false,
|
||||
@@ -69,7 +141,7 @@ class AppSettings {
|
||||
this.mapKeyPrefix = '',
|
||||
this.mapShowMarkers = true,
|
||||
this.mapShowGuessedLocations = true,
|
||||
this.enableMessageTracing = false,
|
||||
this.enableMessageTracing = true,
|
||||
this.mapCacheBounds,
|
||||
this.mapCacheMinZoom = 10,
|
||||
this.mapCacheMaxZoom = 15,
|
||||
@@ -77,7 +149,7 @@ class AppSettings {
|
||||
this.notifyOnNewMessage = true,
|
||||
this.notifyOnNewChannelMessage = true,
|
||||
this.notifyOnNewAdvert = true,
|
||||
this.autoRouteRotationEnabled = false,
|
||||
this.autoRouteRotationEnabled = true,
|
||||
this.maxRouteWeight = 5.0,
|
||||
this.initialRouteWeight = 3.0,
|
||||
this.routeWeightSuccessIncrement = 0.5,
|
||||
@@ -95,15 +167,28 @@ class AppSettings {
|
||||
this.tcpServerPort = 0,
|
||||
this.jumpToOldestUnread = false,
|
||||
this.translationEnabled = false,
|
||||
this.autoTranslateIncomingMessages = true,
|
||||
this.translationTargetLanguageCode,
|
||||
this.composerTranslationEnabled = false,
|
||||
this.translationModelSourceUrl,
|
||||
this.translationSelectedModelId,
|
||||
List<TranslationModelRecord>? translationDownloadedModels,
|
||||
List<Cyr2LatProfile>? cyr2latProfiles,
|
||||
String? selectedCyr2latProfileId,
|
||||
}) : batteryChemistryByDeviceId = batteryChemistryByDeviceId ?? {},
|
||||
batteryChemistryByRepeaterId = batteryChemistryByRepeaterId ?? {},
|
||||
mutedChannels = mutedChannels ?? {},
|
||||
translationDownloadedModels = translationDownloadedModels ?? const [];
|
||||
translationDownloadedModels = translationDownloadedModels ?? const [],
|
||||
cyr2latProfiles =
|
||||
cyr2latProfiles ??
|
||||
[
|
||||
Cyr2LatProfile(
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
charMap: defaultCyr2LatCharMap,
|
||||
),
|
||||
],
|
||||
selectedCyr2latProfileId = selectedCyr2latProfileId ?? 'default';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
@@ -143,6 +228,7 @@ class AppSettings {
|
||||
'tcp_server_port': tcpServerPort,
|
||||
'jump_to_oldest_unread': jumpToOldestUnread,
|
||||
'translation_enabled': translationEnabled,
|
||||
'auto_translate_incoming_messages': autoTranslateIncomingMessages,
|
||||
'translation_target_language_code': translationTargetLanguageCode,
|
||||
'composer_translation_enabled': composerTranslationEnabled,
|
||||
'translation_model_source_url': translationModelSourceUrl,
|
||||
@@ -150,6 +236,10 @@ class AppSettings {
|
||||
'translation_downloaded_models': translationDownloadedModels
|
||||
.map((model) => model.toJson())
|
||||
.toList(),
|
||||
'cyr2lat_profiles': cyr2latProfiles
|
||||
.map((profile) => profile.toJson())
|
||||
.toList(),
|
||||
'selected_cyr2lat_profile_id': selectedCyr2latProfileId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,7 +264,7 @@ class AppSettings {
|
||||
mapShowMarkers: json['map_show_markers'] as bool? ?? true,
|
||||
mapShowGuessedLocations:
|
||||
json['map_show_guessed_locations'] as bool? ?? true,
|
||||
enableMessageTracing: json['enable_message_tracing'] as bool? ?? false,
|
||||
enableMessageTracing: json['enable_message_tracing'] as bool? ?? true,
|
||||
mapCacheBounds: (json['map_cache_bounds'] as Map?)?.map(
|
||||
(key, value) => MapEntry(key.toString(), (value as num).toDouble()),
|
||||
),
|
||||
@@ -186,7 +276,7 @@ class AppSettings {
|
||||
json['notify_on_new_channel_message'] as bool? ?? true,
|
||||
notifyOnNewAdvert: json['notify_on_new_advert'] as bool? ?? true,
|
||||
autoRouteRotationEnabled:
|
||||
json['auto_route_rotation_enabled'] as bool? ?? false,
|
||||
json['auto_route_rotation_enabled'] as bool? ?? true,
|
||||
maxRouteWeight: (json['max_route_weight'] as num?)?.toDouble() ?? 5.0,
|
||||
initialRouteWeight:
|
||||
(json['initial_route_weight'] as num?)?.toDouble() ?? 3.0,
|
||||
@@ -220,6 +310,8 @@ class AppSettings {
|
||||
tcpServerPort: json['tcp_server_port'] as int? ?? 0,
|
||||
jumpToOldestUnread: json['jump_to_oldest_unread'] as bool? ?? false,
|
||||
translationEnabled: json['translation_enabled'] as bool? ?? false,
|
||||
autoTranslateIncomingMessages:
|
||||
json['auto_translate_incoming_messages'] as bool? ?? true,
|
||||
translationTargetLanguageCode:
|
||||
json['translation_target_language_code'] as String?,
|
||||
composerTranslationEnabled:
|
||||
@@ -237,6 +329,38 @@ class AppSettings {
|
||||
)
|
||||
.toList() ??
|
||||
const [],
|
||||
cyr2latProfiles:
|
||||
(json['cyr2lat_profiles'] as List<dynamic>?)
|
||||
?.map(
|
||||
(entry) => Cyr2LatProfile.fromJson(
|
||||
Map<String, dynamic>.from(entry as Map),
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
// Backward compatibility: if old cyr2lat_char_map exists, create a profile from it
|
||||
(json['cyr2lat_char_map'] != null
|
||||
? [
|
||||
Cyr2LatProfile(
|
||||
id: 'migrated',
|
||||
name: 'Migrated Profile',
|
||||
charMap:
|
||||
(json['cyr2lat_char_map'] as Map?)?.map(
|
||||
(key, value) =>
|
||||
MapEntry(key.toString(), value.toString()),
|
||||
) ??
|
||||
defaultCyr2LatCharMap,
|
||||
),
|
||||
]
|
||||
: [
|
||||
Cyr2LatProfile(
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
charMap: defaultCyr2LatCharMap,
|
||||
),
|
||||
]),
|
||||
selectedCyr2latProfileId:
|
||||
json['selected_cyr2lat_profile_id'] as String? ??
|
||||
(json['cyr2lat_char_map'] != null ? 'migrated' : 'default'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -277,11 +401,14 @@ class AppSettings {
|
||||
int? tcpServerPort,
|
||||
bool? jumpToOldestUnread,
|
||||
bool? translationEnabled,
|
||||
bool? autoTranslateIncomingMessages,
|
||||
Object? translationTargetLanguageCode = _unset,
|
||||
bool? composerTranslationEnabled,
|
||||
Object? translationModelSourceUrl = _unset,
|
||||
Object? translationSelectedModelId = _unset,
|
||||
List<TranslationModelRecord>? translationDownloadedModels,
|
||||
List<Cyr2LatProfile>? cyr2latProfiles,
|
||||
String? selectedCyr2latProfileId,
|
||||
}) {
|
||||
return AppSettings(
|
||||
clearPathOnMaxRetry: clearPathOnMaxRetry ?? this.clearPathOnMaxRetry,
|
||||
@@ -332,6 +459,8 @@ class AppSettings {
|
||||
tcpServerPort: tcpServerPort ?? this.tcpServerPort,
|
||||
jumpToOldestUnread: jumpToOldestUnread ?? this.jumpToOldestUnread,
|
||||
translationEnabled: translationEnabled ?? this.translationEnabled,
|
||||
autoTranslateIncomingMessages:
|
||||
autoTranslateIncomingMessages ?? this.autoTranslateIncomingMessages,
|
||||
translationTargetLanguageCode: translationTargetLanguageCode == _unset
|
||||
? this.translationTargetLanguageCode
|
||||
: translationTargetLanguageCode as String?,
|
||||
@@ -345,6 +474,9 @@ class AppSettings {
|
||||
: translationSelectedModelId as String?,
|
||||
translationDownloadedModels:
|
||||
translationDownloadedModels ?? this.translationDownloadedModels,
|
||||
cyr2latProfiles: cyr2latProfiles ?? this.cyr2latProfiles,
|
||||
selectedCyr2latProfileId:
|
||||
selectedCyr2latProfileId ?? this.selectedCyr2latProfileId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import 'dart:typed_data';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import 'community.dart';
|
||||
|
||||
enum ChannelType { public, private, hashtag, communityPublic, communityHashtag }
|
||||
|
||||
class Channel {
|
||||
final int index;
|
||||
@@ -111,5 +114,36 @@ class Channel {
|
||||
return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
||||
}
|
||||
|
||||
static bool isCommunityChannel(ChannelType channelType) {
|
||||
switch (channelType) {
|
||||
case ChannelType.communityPublic:
|
||||
case ChannelType.communityHashtag:
|
||||
return true;
|
||||
case ChannelType.public:
|
||||
case ChannelType.private:
|
||||
case ChannelType.hashtag:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static ChannelType getChannelType(
|
||||
Channel channel,
|
||||
CommunityPskIndex communityIndex,
|
||||
) {
|
||||
Community? community = communityIndex.getCommunityForChannel(channel);
|
||||
if (community != null) {
|
||||
if (Community.isCommunityPublicChannel(channel, community)) {
|
||||
return ChannelType.communityPublic;
|
||||
}
|
||||
return ChannelType.communityHashtag;
|
||||
}
|
||||
if (channel.isPublicChannel) {
|
||||
return ChannelType.public;
|
||||
} else if (channel.name.startsWith('#')) {
|
||||
return ChannelType.hashtag;
|
||||
}
|
||||
return ChannelType.private;
|
||||
}
|
||||
|
||||
static const String publicChannelPsk = '8b3387e9c5cdea6ac9e5edbaa115cd72';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import 'channel.dart';
|
||||
|
||||
/// Represents a community with a shared secret for deriving channel PSKs.
|
||||
///
|
||||
/// A Community is a namespace with a shared secret K (32 random bytes),
|
||||
@@ -162,6 +164,12 @@ class Community {
|
||||
return hashtag.replaceFirst(RegExp(r'^#'), '').toLowerCase().trim();
|
||||
}
|
||||
|
||||
/// Returns true if this is the community's public channel
|
||||
static bool isCommunityPublicChannel(Channel channel, Community community) {
|
||||
final publicPsk = community.deriveCommunityPublicPsk();
|
||||
return channel.pskHex == Channel.formatPskHex(publicPsk);
|
||||
}
|
||||
|
||||
/// Add a hashtag channel to this community's list
|
||||
Community addHashtagChannel(String hashtag) {
|
||||
final normalized = _normalizeCommunityHashtag(hashtag);
|
||||
@@ -237,3 +245,28 @@ class Community {
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
|
||||
class CommunityPskIndex {
|
||||
// Cache of PSK hex -> Community for quick lookup
|
||||
final Map<String, Community> _pskToCommunity = {};
|
||||
|
||||
void initialize(List<Community> communities) {
|
||||
_pskToCommunity.clear();
|
||||
for (final community in communities) {
|
||||
// Map the community public channel PSK
|
||||
final publicPsk = community.deriveCommunityPublicPsk();
|
||||
_pskToCommunity[Channel.formatPskHex(publicPsk)] = community;
|
||||
|
||||
// Map all known hashtag channel PSKs
|
||||
for (final hashtag in community.hashtagChannels) {
|
||||
final hashtagPsk = community.deriveCommunityHashtagPsk(hashtag);
|
||||
_pskToCommunity[Channel.formatPskHex(hashtagPsk)] = community;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the community this channel belongs to, or null if not a community channel
|
||||
Community? getCommunityForChannel(Channel channel) {
|
||||
return _pskToCommunity[channel.pskHex];
|
||||
}
|
||||
}
|
||||
|
||||
+32
-15
@@ -17,6 +17,7 @@ class Contact {
|
||||
final double? longitude;
|
||||
final DateTime lastSeen;
|
||||
final DateTime lastMessageAt;
|
||||
final DateTime? lastModified;
|
||||
final bool isActive;
|
||||
final bool wasPulled;
|
||||
final Uint8List? rawPacket;
|
||||
@@ -33,6 +34,7 @@ class Contact {
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
required this.lastSeen,
|
||||
this.lastModified,
|
||||
DateTime? lastMessageAt,
|
||||
this.isActive = true,
|
||||
this.wasPulled = false,
|
||||
@@ -41,7 +43,10 @@ class Contact {
|
||||
|
||||
String get publicKeyHex => pubKeyToHex(publicKey);
|
||||
|
||||
String get typeLabel {
|
||||
/// Non-localized type label, intended for logs and non-UI exports
|
||||
/// (e.g. GPX). For UI use the `typeLabel(l10n)` extension in
|
||||
/// `lib/l10n/contact_localization.dart`.
|
||||
String get typeLabelRaw {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return 'Chat';
|
||||
@@ -56,17 +61,6 @@ class Contact {
|
||||
}
|
||||
}
|
||||
|
||||
String get pathLabel {
|
||||
if (pathOverride != null) {
|
||||
if (pathOverride! < 0) return 'Flood (forced)';
|
||||
if (pathOverride == 0) return 'Direct (forced)';
|
||||
return '$pathOverride hops (forced)';
|
||||
}
|
||||
if (pathLength < 0) return 'Flood';
|
||||
if (pathLength == 0) return 'Direct';
|
||||
return '$pathLength hops';
|
||||
}
|
||||
|
||||
bool get hasLocation {
|
||||
const double epsilon = 1e-6;
|
||||
final lat = latitude ?? 0.0;
|
||||
@@ -94,6 +88,7 @@ class Contact {
|
||||
double? longitude,
|
||||
DateTime? lastSeen,
|
||||
DateTime? lastMessageAt,
|
||||
DateTime? lastModified,
|
||||
bool? isActive,
|
||||
Uint8List? rawPacket,
|
||||
}) {
|
||||
@@ -114,6 +109,7 @@ class Contact {
|
||||
longitude: longitude ?? this.longitude,
|
||||
lastSeen: lastSeen ?? this.lastSeen,
|
||||
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
|
||||
lastModified: lastModified ?? this.lastModified,
|
||||
isActive: isActive ?? this.isActive,
|
||||
rawPacket: rawPacket ?? this.rawPacket,
|
||||
);
|
||||
@@ -182,16 +178,34 @@ class Contact {
|
||||
return null;
|
||||
}
|
||||
|
||||
final lastMod = reader.readUInt32LE();
|
||||
// mandatory last_advert_timestamp
|
||||
final lastAdvertTimestamp = reader.readUInt32LE();
|
||||
|
||||
double? lat, lon;
|
||||
if (reader.remaining >= 8) {
|
||||
DateTime? lastModified;
|
||||
if (reader.remaining >= 12) {
|
||||
final latRaw = reader.readInt32LE();
|
||||
final lonRaw = reader.readInt32LE();
|
||||
final lastModRaw = reader.readUInt32LE();
|
||||
// TODO: should this be &&?
|
||||
if (latRaw != 0 || lonRaw != 0) {
|
||||
lat = latRaw / 1e6;
|
||||
lon = lonRaw / 1e6;
|
||||
}
|
||||
if (lastModRaw != 0) {
|
||||
lastModified = DateTime.fromMillisecondsSinceEpoch(lastModRaw * 1000);
|
||||
}
|
||||
} else if (reader.remaining >= 8) {
|
||||
// Old layout: gps without lastmod
|
||||
final latRaw = reader.readInt32LE();
|
||||
final lonRaw = reader.readInt32LE();
|
||||
if (latRaw != 0 || lonRaw != 0) {
|
||||
lat = latRaw / 1e6;
|
||||
lon = lonRaw / 1e6;
|
||||
}
|
||||
appLogger.info(
|
||||
'Contact ${pubKeyToHex(pubKey).substring(0, 8)} has gps but no lastmod (legacy firmware layout)',
|
||||
);
|
||||
}
|
||||
|
||||
return Contact(
|
||||
@@ -203,7 +217,10 @@ class Contact {
|
||||
path: pathBytes,
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
lastSeen: DateTime.fromMillisecondsSinceEpoch(lastMod * 1000),
|
||||
lastSeen: DateTime.fromMillisecondsSinceEpoch(
|
||||
lastAdvertTimestamp * 1000,
|
||||
),
|
||||
lastModified: lastModified,
|
||||
isActive: true,
|
||||
rawPacket: null,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import 'path_history.dart';
|
||||
|
||||
/// One observed route rendered on the path map — the live traced path
|
||||
/// (primary) or an alternate from the contact's path history — resolved to
|
||||
/// map coordinates with per-hop confidence flags.
|
||||
class DisplayPath {
|
||||
final String id;
|
||||
final String label;
|
||||
final Color color;
|
||||
final bool isPrimary;
|
||||
|
||||
/// Outbound hop bytes, including hops that could not be placed on the map.
|
||||
final List<int> hopBytes;
|
||||
|
||||
/// Resolved map points: self, each locatable hop, then the target when its
|
||||
/// position is known. Hops with no position are skipped here but still
|
||||
/// counted in [unresolvedHops].
|
||||
final List<LatLng> points;
|
||||
|
||||
/// Display name for each entry of [points].
|
||||
final List<String> pointLabels;
|
||||
|
||||
/// Whether each entry of [points] is a GPS-grade position (vs inferred).
|
||||
final List<bool> pointConfirmed;
|
||||
|
||||
/// Per segment (length points-1): true when either endpoint is inferred or
|
||||
/// unlocatable hops were skipped in between — rendered dashed.
|
||||
final List<bool> segmentEstimated;
|
||||
|
||||
/// Per segment: the transmission ordinal of the segment's destination,
|
||||
/// used to highlight the matching hop-list row during animation.
|
||||
final List<int> rowForSegment;
|
||||
|
||||
/// Total transmissions on the full route (including unlocatable hops).
|
||||
final int totalTransmissions;
|
||||
|
||||
/// True when the route ends with a chat-target endpoint row.
|
||||
final bool hasTargetEndpoint;
|
||||
|
||||
final int gpsConfirmedHops;
|
||||
final int unresolvedHops;
|
||||
final double distanceMeters;
|
||||
|
||||
/// History metadata; null for the live traced (primary) path.
|
||||
final PathRecord? record;
|
||||
|
||||
const DisplayPath({
|
||||
required this.id,
|
||||
required this.label,
|
||||
required this.color,
|
||||
required this.isPrimary,
|
||||
required this.hopBytes,
|
||||
required this.points,
|
||||
required this.pointLabels,
|
||||
required this.pointConfirmed,
|
||||
required this.segmentEstimated,
|
||||
required this.rowForSegment,
|
||||
required this.totalTransmissions,
|
||||
required this.hasTargetEndpoint,
|
||||
required this.gpsConfirmedHops,
|
||||
required this.unresolvedHops,
|
||||
required this.distanceMeters,
|
||||
this.record,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
/// Timeline state for the packet-flow animation on the path map.
|
||||
///
|
||||
/// The packet travels each segment over [segmentMs] (scaled by [speed]),
|
||||
/// then dwells at the reached hop for [dwellMs] so the hop visibly lights up.
|
||||
/// Overlay layers listen to this controller directly; [activeSegment] only
|
||||
/// fires when the segment index changes so list highlights rebuild cheaply.
|
||||
class PathPlaybackController extends ChangeNotifier {
|
||||
static const double segmentMs = 1100;
|
||||
static const double dwellMs = 380;
|
||||
static const List<double> speedSteps = [0.5, 1.0, 2.0];
|
||||
|
||||
late final Ticker _ticker;
|
||||
List<LatLng> _points = const [];
|
||||
double _timelineMs = 0;
|
||||
Duration _lastTick = Duration.zero;
|
||||
bool _playing = false;
|
||||
bool _started = false;
|
||||
double _speed = 1.0;
|
||||
|
||||
/// Segment currently being traveled (clamped to the last segment), or -1
|
||||
/// while the animation has not been started — listeners use this for
|
||||
/// hop-list highlighting without rebuilding every tick.
|
||||
final ValueNotifier<int> activeSegment = ValueNotifier(-1);
|
||||
|
||||
PathPlaybackController(TickerProvider vsync) {
|
||||
_ticker = vsync.createTicker(_onTick);
|
||||
}
|
||||
|
||||
List<LatLng> get points => _points;
|
||||
bool get hasPath => _points.length >= 2;
|
||||
int get segmentCount => hasPath ? _points.length - 1 : 0;
|
||||
bool get playing => _playing;
|
||||
double get speed => _speed;
|
||||
|
||||
/// True once the user has started or stepped the animation; the packet
|
||||
/// overlay renders only in this state.
|
||||
bool get started => _started;
|
||||
|
||||
double get _slotMs => segmentMs + dwellMs;
|
||||
double get _totalMs => segmentCount * _slotMs;
|
||||
bool get isComplete => hasPath && _timelineMs >= _totalMs;
|
||||
|
||||
int get currentSegment {
|
||||
if (!hasPath) return 0;
|
||||
return (_timelineMs / _slotMs).floor().clamp(0, segmentCount - 1);
|
||||
}
|
||||
|
||||
/// Travel progress through [currentSegment]; 1.0 while dwelling at its end.
|
||||
double get segmentProgress {
|
||||
if (!hasPath) return 0;
|
||||
final within = _timelineMs - currentSegment * _slotMs;
|
||||
return (within / segmentMs).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// Dwell progress (0..1) at the reached hop, or null while traveling.
|
||||
double? get dwellProgress {
|
||||
if (!hasPath || isComplete) return null;
|
||||
final within = _timelineMs - currentSegment * _slotMs;
|
||||
if (within < segmentMs) return null;
|
||||
return ((within - segmentMs) / dwellMs).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// Index of the point the packet has most recently reached.
|
||||
int get reachedPointIndex {
|
||||
if (!hasPath) return 0;
|
||||
if (isComplete) return _points.length - 1;
|
||||
return segmentProgress >= 1.0 ? currentSegment + 1 : currentSegment;
|
||||
}
|
||||
|
||||
LatLng get position {
|
||||
if (!hasPath) return const LatLng(0, 0);
|
||||
final seg = currentSegment;
|
||||
final a = _points[seg];
|
||||
final b = _points[seg + 1];
|
||||
final t = segmentProgress;
|
||||
return LatLng(
|
||||
a.latitude + (b.latitude - a.latitude) * t,
|
||||
a.longitude + (b.longitude - a.longitude) * t,
|
||||
);
|
||||
}
|
||||
|
||||
/// Replaces the path and resets the animation to the start.
|
||||
void setPath(List<LatLng> points) {
|
||||
_ticker.stop();
|
||||
_points = List.unmodifiable(points);
|
||||
_timelineMs = 0;
|
||||
_playing = false;
|
||||
_started = false;
|
||||
activeSegment.value = -1;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void play() {
|
||||
if (!hasPath) return;
|
||||
if (isComplete) _timelineMs = 0;
|
||||
_started = true;
|
||||
_playing = true;
|
||||
activeSegment.value = currentSegment;
|
||||
if (!_ticker.isActive) {
|
||||
_lastTick = Duration.zero;
|
||||
_ticker.start();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void pause() {
|
||||
_ticker.stop();
|
||||
_playing = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void togglePlay() => _playing ? pause() : play();
|
||||
|
||||
void replay() {
|
||||
if (!hasPath) return;
|
||||
_timelineMs = 0;
|
||||
activeSegment.value = 0;
|
||||
play();
|
||||
}
|
||||
|
||||
/// Stops playback and hides the packet overlay.
|
||||
void stop() {
|
||||
_ticker.stop();
|
||||
_playing = false;
|
||||
_started = false;
|
||||
_timelineMs = 0;
|
||||
activeSegment.value = -1;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void stepForward() => _jumpToPoint(reachedPointIndex + 1);
|
||||
|
||||
void stepBack() => _jumpToPoint(reachedPointIndex - 1);
|
||||
|
||||
void cycleSpeed() {
|
||||
final index = speedSteps.indexOf(_speed);
|
||||
_speed = speedSteps[(index + 1) % speedSteps.length];
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void _jumpToPoint(int index) {
|
||||
if (!hasPath) return;
|
||||
_ticker.stop();
|
||||
_playing = false;
|
||||
_started = true;
|
||||
final clamped = index.clamp(0, _points.length - 1);
|
||||
// Land at the start of the dwell window so the hop pulse plays.
|
||||
_timelineMs = clamped == 0 ? 0 : (clamped - 1) * _slotMs + segmentMs;
|
||||
activeSegment.value = currentSegment;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void _onTick(Duration elapsed) {
|
||||
final dtMs = (elapsed - _lastTick).inMicroseconds / 1000.0;
|
||||
_lastTick = elapsed;
|
||||
_timelineMs = (_timelineMs + dtMs * _speed).clamp(0.0, _totalMs);
|
||||
if (_timelineMs >= _totalMs) {
|
||||
_ticker.stop();
|
||||
_playing = false;
|
||||
}
|
||||
if (activeSegment.value != currentSegment) {
|
||||
activeSegment.value = currentSegment;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ticker.dispose();
|
||||
activeSegment.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -181,6 +181,276 @@ class RadioSettings {
|
||||
txPowerDbm: 14,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Artyom (VVO)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 864.281,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Biysk (BSK)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 869.000,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Chelyabinsk (CEK)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Cherepovets (CEE)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.570,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Irkutsk (IKT)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Ivanovo (IWA)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Izhevsk (IJK)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.732,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Kaluga (KLF)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Kazan (KZN)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Khabarovsk (KHV)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 864.281,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Kirov (KVX)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Lipetsk (LPK)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.950,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf9,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Moscow (MOW)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Nizhny Novgorod (GOJ)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Novosibirsk (OVB)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 869.000,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf9,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Rostov-on-Don (ROV)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf9,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Ryazan (RZN)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.880,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf9,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Samara (KUF)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 864.281,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Saratov (GSV)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 864.281,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia St. Petersburg (LED)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.856,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Tambov (TBW)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.950,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf10,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Tula (TYA)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Tver (KLD)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 869.169,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Ufa (UFA)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.732,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Volgograd (VOG)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 869.525,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Voronezh (VOZ)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 868.731,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf8,
|
||||
codingRate: LoRaCodingRate.cr4_6,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Russia Yekaterinburg (SVX)',
|
||||
RadioSettings(
|
||||
frequencyMHz: 869.046,
|
||||
bandwidth: LoRaBandwidth.bw62_5,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf7,
|
||||
codingRate: LoRaCodingRate.cr4_7,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Switzerland',
|
||||
RadioSettings(
|
||||
@@ -228,7 +498,7 @@ class RadioSettings {
|
||||
frequencyMHz: 433.0,
|
||||
bandwidth: LoRaBandwidth.bw250,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf11,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
@@ -238,7 +508,7 @@ class RadioSettings {
|
||||
frequencyMHz: 869.0,
|
||||
bandwidth: LoRaBandwidth.bw250,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf11,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 14,
|
||||
),
|
||||
),
|
||||
@@ -248,7 +518,7 @@ class RadioSettings {
|
||||
frequencyMHz: 918.0,
|
||||
bandwidth: LoRaBandwidth.bw250,
|
||||
spreadingFactor: LoRaSpreadingFactor.sf11,
|
||||
codingRate: LoRaCodingRate.cr4_5,
|
||||
codingRate: LoRaCodingRate.cr4_8,
|
||||
txPowerDbm: 20,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import '../l10n/l10n.dart';
|
||||
import '../services/app_debug_log_service.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/adaptive_app_bar_title.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
@@ -58,25 +59,57 @@ class AppDebugLogScreen extends StatelessWidget {
|
||||
child: hasEntries
|
||||
? ListView.separated(
|
||||
itemCount: entries.length,
|
||||
separatorBuilder: (_, _) => const Divider(height: 1),
|
||||
separatorBuilder: (_, _) =>
|
||||
const Divider(height: 1, color: MeshPalette.line),
|
||||
itemBuilder: (context, index) {
|
||||
final entry = entries[index];
|
||||
return ListTile(
|
||||
dense: true,
|
||||
leading: _buildLevelIcon(entry.level),
|
||||
title: Text(
|
||||
'[${entry.tag}] ${entry.message}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'monospace',
|
||||
),
|
||||
return Container(
|
||||
color: MeshPalette.bg,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
subtitle: Text(
|
||||
entry.formattedTime,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildLevelIcon(context, entry.level),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '[${entry.tag}] ',
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: _levelColor(entry.level),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: entry.message,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: MeshPalette.ink2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
entry.formattedTime,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 9.5,
|
||||
color: MeshPalette.ink4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -85,25 +118,25 @@ class AppDebugLogScreen extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
const Icon(
|
||||
Icons.bug_report_outlined,
|
||||
size: 64,
|
||||
color: Colors.grey[400],
|
||||
color: MeshPalette.ink3,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
context.l10n.debugLog_noEntries,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey[600],
|
||||
color: MeshPalette.ink3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
context.l10n.debugLog_enableInSettings,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
color: MeshPalette.ink3,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -115,18 +148,37 @@ class AppDebugLogScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLevelIcon(AppDebugLogLevel level) {
|
||||
Color _levelColor(AppDebugLogLevel level) {
|
||||
switch (level) {
|
||||
case AppDebugLogLevel.info:
|
||||
return const Icon(Icons.info_outline, size: 18, color: Colors.blue);
|
||||
return MeshPalette.blue;
|
||||
case AppDebugLogLevel.warning:
|
||||
return MeshPalette.warn;
|
||||
case AppDebugLogLevel.error:
|
||||
return MeshPalette.alert;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildLevelIcon(BuildContext context, AppDebugLogLevel level) {
|
||||
switch (level) {
|
||||
case AppDebugLogLevel.info:
|
||||
return const Icon(
|
||||
Icons.info_outline,
|
||||
size: 18,
|
||||
color: MeshPalette.blue,
|
||||
);
|
||||
case AppDebugLogLevel.warning:
|
||||
return const Icon(
|
||||
Icons.warning_amber_outlined,
|
||||
size: 18,
|
||||
color: Colors.orange,
|
||||
color: MeshPalette.warn,
|
||||
);
|
||||
case AppDebugLogLevel.error:
|
||||
return const Icon(Icons.error_outline, size: 18, color: Colors.red);
|
||||
return const Icon(
|
||||
Icons.error_outline,
|
||||
size: 18,
|
||||
color: MeshPalette.alert,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1623
-907
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../services/ble_debug_log_service.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/adaptive_app_bar_title.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
@@ -32,6 +33,7 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: AdaptiveAppBarTitle(context.l10n.debugLog_bleTitle),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: context.l10n.debugLog_copyLog,
|
||||
@@ -101,23 +103,14 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
|
||||
itemCount: showingFrames
|
||||
? entries.length
|
||||
: rawEntries.length,
|
||||
separatorBuilder: (_, _) => const Divider(height: 1),
|
||||
separatorBuilder: (_, _) =>
|
||||
const Divider(height: 1, color: MeshPalette.line),
|
||||
itemBuilder: (context, index) {
|
||||
if (showingFrames) {
|
||||
final entry = entries[index];
|
||||
final time =
|
||||
'${entry.timestamp.hour.toString().padLeft(2, '0')}:${entry.timestamp.minute.toString().padLeft(2, '0')}:${entry.timestamp.second.toString().padLeft(2, '0')}';
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Text(entry.description),
|
||||
subtitle: Text('${entry.hexPreview}\n$time'),
|
||||
isThreeLine: true,
|
||||
leading: Icon(
|
||||
entry.outgoing
|
||||
? Icons.upload
|
||||
: Icons.download,
|
||||
size: 18,
|
||||
),
|
||||
return GestureDetector(
|
||||
onLongPress: () async {
|
||||
await Clipboard.setData(
|
||||
ClipboardData(
|
||||
@@ -131,6 +124,60 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
color: MeshPalette.bg,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
entry.outgoing
|
||||
? Icons.upload
|
||||
: Icons.download,
|
||||
size: 18,
|
||||
color: entry.outgoing
|
||||
? MeshPalette.blue
|
||||
: MeshPalette.signal,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
entry.description,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: MeshPalette.ink,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
entry.hexPreview,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 10,
|
||||
color: MeshPalette.ink3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
time,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 9.5,
|
||||
color: MeshPalette.ink4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,18 +185,65 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
|
||||
final info = _decodeRawPacket(entry.payload);
|
||||
final time =
|
||||
'${entry.timestamp.hour.toString().padLeft(2, '0')}:${entry.timestamp.minute.toString().padLeft(2, '0')}:${entry.timestamp.second.toString().padLeft(2, '0')}';
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Text(info.title),
|
||||
subtitle: Text('${info.summary}\n$time'),
|
||||
isThreeLine: true,
|
||||
leading: const Icon(Icons.download, size: 18),
|
||||
return GestureDetector(
|
||||
onTap: () => _showRawDialog(context, info),
|
||||
child: Container(
|
||||
color: MeshPalette.bg,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.download,
|
||||
size: 18,
|
||||
color: MeshPalette.signal,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
info.title,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: MeshPalette.ink,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
info.summary,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 10,
|
||||
color: MeshPalette.ink3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
time,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 9.5,
|
||||
color: MeshPalette.ink4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Center(
|
||||
child: Text(context.l10n.debugLog_noBleActivity),
|
||||
child: Text(
|
||||
context.l10n.debugLog_noBleActivity,
|
||||
style: const TextStyle(color: MeshPalette.ink3),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+678
-479
File diff suppressed because it is too large
Load Diff
+710
-1077
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
|
||||
class ChromeRequiredScreen extends StatelessWidget {
|
||||
const ChromeRequiredScreen({super.key});
|
||||
@@ -7,81 +9,95 @@ class ChromeRequiredScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
final theme = Theme.of(context);
|
||||
final isDark = theme.brightness == Brightness.dark;
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: isDark
|
||||
? [const Color(0xFF1A1A1A), const Color(0xFF0D0D0D)]
|
||||
: [const Color(0xFFF5F7FA), const Color(0xFFE4E7EB)],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.orange.withValues(alpha: 0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.browser_not_supported_rounded,
|
||||
size: 80,
|
||||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
l10n.scanner_chromeRequired,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isDark ? Colors.white : Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.scanner_chromeRequiredMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color: isDark ? Colors.white70 : Colors.black54,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
// We can't really "fix" it for them other than telling them to use Chrome
|
||||
// but we can provide a nice visual.
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(color: Colors.blue.withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.info_outline, size: 20, color: Colors.blue),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
"Web Bluetooth requires a Chromium browser",
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
body: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Icon in tinted circle
|
||||
Container(
|
||||
width: 88,
|
||||
height: 88,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: scheme.tertiary.withValues(alpha: 0.10),
|
||||
border: Border.all(
|
||||
color: scheme.tertiary.withValues(alpha: 0.25),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Icon(
|
||||
Icons.browser_not_supported_rounded,
|
||||
size: 42,
|
||||
color: scheme.tertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 28),
|
||||
|
||||
// Title
|
||||
Text(
|
||||
l10n.scanner_chromeRequired,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: scheme.onSurface,
|
||||
letterSpacing: -0.3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Body text
|
||||
Text(
|
||||
l10n.scanner_chromeRequiredMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: scheme.onSurfaceVariant,
|
||||
height: 1.55,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Info chip
|
||||
MeshCard(
|
||||
margin: EdgeInsets.zero,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
color: scheme.secondaryContainer.withValues(alpha: 0.35),
|
||||
borderColor: scheme.outline.withValues(alpha: 0.3),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 18,
|
||||
color: scheme.secondary,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Text(
|
||||
l10n.chrome_bluetoothRequiresChromium,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 12,
|
||||
color: scheme.onSecondaryContainer,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../connector/meshcore_connector.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../models/community.dart';
|
||||
import '../storage/community_store.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/adaptive_app_bar_title.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../widgets/qr_scanner_widget.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
/// Screen for scanning community QR codes to join communities.
|
||||
///
|
||||
@@ -35,16 +39,87 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
|
||||
centerTitle: true,
|
||||
),
|
||||
body: _isProcessing
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
? Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: const Center(child: CircularProgressIndicator()),
|
||||
)
|
||||
: QrScannerWidget(
|
||||
onScanned: (data) => _handleScannedData(context, data),
|
||||
validator: Community.isValidQrData,
|
||||
onValidationFailed: (_) => _showInvalidQrError(context),
|
||||
instructions: context.l10n.community_scanInstructions,
|
||||
overlay: _buildThemedOverlay(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildThemedOverlay(BuildContext context) {
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// Dark semi-transparent background with cutout
|
||||
ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withValues(alpha: 0.5),
|
||||
BlendMode.srcOut,
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.black,
|
||||
backgroundBlendMode: BlendMode.dstOut,
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Container(
|
||||
height: 250,
|
||||
width: 250,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Corner brackets on top
|
||||
const ScannerCornerOverlay(
|
||||
scanWindowSize: 250,
|
||||
borderColor: MeshPalette.blue,
|
||||
borderWidth: 2,
|
||||
cornerLength: 24,
|
||||
),
|
||||
// Instructions pill below the scan window
|
||||
Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 250 + 24),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 10,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.72),
|
||||
borderRadius: BorderRadius.circular(MeshRadii.pill),
|
||||
),
|
||||
child: Text(
|
||||
context.l10n.community_scanInstructions,
|
||||
style: const TextStyle(color: MeshPalette.ink2, fontSize: 13),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleScannedData(BuildContext context, String data) async {
|
||||
if (_isProcessing) return;
|
||||
|
||||
@@ -80,7 +155,7 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.community_invalidQrCode),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: MeshPalette.alert,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -96,29 +171,74 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.community_invalidQrCode),
|
||||
backgroundColor: Colors.orange,
|
||||
backgroundColor: MeshPalette.warn,
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
}
|
||||
|
||||
void _showAlreadyMemberDialog(BuildContext context, Community community) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
title: Text(context.l10n.community_alreadyMember),
|
||||
content: Text(
|
||||
context.l10n.community_alreadyMemberMessage(community.name),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(dialogContext);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(context.l10n.common_ok),
|
||||
),
|
||||
],
|
||||
),
|
||||
showMeshSheet(
|
||||
context,
|
||||
builder: (sheetContext) {
|
||||
final sheetScheme = Theme.of(sheetContext).colorScheme;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
BottomSheetHeader(title: context.l10n.community_alreadyMember),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 0, 20, 4),
|
||||
child: Text(
|
||||
context.l10n.community_alreadyMemberMessage(community.name),
|
||||
style: TextStyle(color: sheetScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
MeshCard(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.groups,
|
||||
color: MeshPalette.magenta,
|
||||
size: 32,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
community.name,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'ID: ${community.shortCommunityId}...',
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: sheetScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
||||
child: FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(sheetContext);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(context.l10n.common_ok),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,77 +247,111 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
|
||||
Community community,
|
||||
) async {
|
||||
bool addPublicChannel = true;
|
||||
final completer = Completer<bool>();
|
||||
|
||||
final result = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (dialogContext) => StatefulBuilder(
|
||||
builder: (dialogContext, setDialogState) => AlertDialog(
|
||||
title: Text(context.l10n.community_joinTitle),
|
||||
content: Column(
|
||||
await showMeshSheet<void>(
|
||||
context,
|
||||
builder: (sheetContext) => StatefulBuilder(
|
||||
builder: (sheetContext, setSheetState) {
|
||||
final joinScheme = Theme.of(sheetContext).colorScheme;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(context.l10n.community_joinConfirmation(community.name)),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.groups,
|
||||
color: Theme.of(dialogContext).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
community.name,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
'ID: ${community.shortCommunityId}...',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
BottomSheetHeader(title: context.l10n.community_joinTitle),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 0, 20, 4),
|
||||
child: Text(
|
||||
context.l10n.community_joinConfirmation(community.name),
|
||||
style: TextStyle(color: joinScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
MeshCard(
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarCircle(
|
||||
name: community.name,
|
||||
icon: Icons.groups,
|
||||
color: MeshPalette.magenta,
|
||||
size: 44,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
community.name,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'ID: ${community.shortCommunityId}...',
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11.5,
|
||||
color: joinScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 8),
|
||||
CheckboxListTile(
|
||||
value: addPublicChannel,
|
||||
onChanged: (value) {
|
||||
setDialogState(() {
|
||||
setSheetState(() {
|
||||
addPublicChannel = value ?? true;
|
||||
});
|
||||
},
|
||||
title: Text(context.l10n.community_addPublicChannel),
|
||||
subtitle: Text(context.l10n.community_addPublicChannelHint),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
completer.complete(false);
|
||||
Navigator.pop(sheetContext);
|
||||
},
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () {
|
||||
completer.complete(true);
|
||||
Navigator.pop(sheetContext);
|
||||
},
|
||||
child: Text(context.l10n.community_join),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(dialogContext, false),
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(dialogContext, true),
|
||||
child: Text(context.l10n.community_join),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (result == true && context.mounted) {
|
||||
// If sheet was dismissed without a button press, treat as cancel
|
||||
if (!completer.isCompleted) {
|
||||
completer.complete(false);
|
||||
}
|
||||
|
||||
final result = await completer.future;
|
||||
|
||||
if (result && context.mounted) {
|
||||
await _joinCommunity(context, community, addPublicChannel);
|
||||
} else if (context.mounted) {
|
||||
// User cancelled - go back
|
||||
@@ -231,7 +385,7 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.community_joined(community.name)),
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: MeshPalette.signal,
|
||||
);
|
||||
|
||||
// Return to previous screen
|
||||
|
||||
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:meshcore_open/connector/meshcore_connector.dart';
|
||||
import 'package:meshcore_open/models/companion_radio_stats.dart';
|
||||
import 'package:meshcore_open/l10n/l10n.dart';
|
||||
import 'package:meshcore_open/theme/mesh_theme.dart';
|
||||
import 'package:meshcore_open/widgets/mesh_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class CompanionRadioStatsScreen extends StatefulWidget {
|
||||
@@ -49,6 +51,25 @@ class _CompanionRadioStatsScreenState extends State<CompanionRadioStatsScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget _tile(String text, IconData icon, Color color) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 16, color: color),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: MeshTheme.mono(fontSize: 13, color: scheme.onSurface),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
@@ -85,44 +106,105 @@ class _CompanionRadioStatsScreenState extends State<CompanionRadioStatsScreen> {
|
||||
valueListenable: connector.radioStatsNotifier,
|
||||
builder: (context, stats, _) {
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
children: [
|
||||
if (stats != null) ...[
|
||||
Text(
|
||||
l10n.radioStats_noiseFloor(stats.noiseFloorDbm),
|
||||
style: tt.titleMedium,
|
||||
const SectionHeader(
|
||||
'Signal',
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(l10n.radioStats_lastRssi(stats.lastRssiDbm)),
|
||||
Text(
|
||||
l10n.radioStats_lastSnr(
|
||||
stats.lastSnrDb.toStringAsFixed(1),
|
||||
MeshCard(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 4,
|
||||
),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_tile(
|
||||
l10n.radioStats_noiseFloor(stats.noiseFloorDbm),
|
||||
Icons.noise_aware,
|
||||
scheme.onSurfaceVariant,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_tile(
|
||||
l10n.radioStats_lastRssi(stats.lastRssiDbm),
|
||||
Icons.wifi_tethering,
|
||||
scheme.onSurfaceVariant,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_tile(
|
||||
l10n.radioStats_lastSnr(
|
||||
stats.lastSnrDb.toStringAsFixed(1),
|
||||
),
|
||||
Icons.signal_cellular_alt,
|
||||
MeshTheme.snrColor(stats.lastSnrDb, blocked: false),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(l10n.radioStats_txAir(stats.txAirSecs)),
|
||||
Text(l10n.radioStats_rxAir(stats.rxAirSecs)),
|
||||
const SizedBox(height: 16),
|
||||
] else
|
||||
Text(l10n.radioStats_waiting),
|
||||
const SizedBox(height: 16),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: CustomPaint(
|
||||
painter: _NoiseChartPainter(
|
||||
samples: List<double>.from(_noiseHistory),
|
||||
colorScheme: scheme,
|
||||
textTheme: tt,
|
||||
const SectionHeader(
|
||||
'Airtime',
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
),
|
||||
MeshCard(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 4,
|
||||
),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_tile(
|
||||
l10n.radioStats_txAir(stats.txAirSecs),
|
||||
Icons.upload,
|
||||
MeshPalette.blue,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_tile(
|
||||
l10n.radioStats_rxAir(stats.rxAirSecs),
|
||||
Icons.download,
|
||||
MeshPalette.blue,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
const SizedBox(height: 80),
|
||||
Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Center(
|
||||
child: Text(
|
||||
l10n.radioStats_waiting,
|
||||
style: TextStyle(color: scheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
],
|
||||
SectionHeader(
|
||||
l10n.radioStats_chartCaption,
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
child: CustomPaint(
|
||||
painter: _NoiseChartPainter(
|
||||
samples: List<double>.from(_noiseHistory),
|
||||
colorScheme: scheme,
|
||||
textTheme: tt,
|
||||
),
|
||||
child: const SizedBox.expand(),
|
||||
),
|
||||
child: const SizedBox.expand(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
l10n.radioStats_chartCaption,
|
||||
style: tt.bodySmall?.copyWith(
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -210,10 +292,10 @@ class _NoiseChartPainter extends CustomPainter {
|
||||
}
|
||||
final span = maxV - minV;
|
||||
|
||||
for (var i = 0; i <= 2; i++) {
|
||||
final v = maxV - span * i / 2;
|
||||
for (var i = 0; i <= 4; i++) {
|
||||
final v = maxV - span * i / 4;
|
||||
final tp = _yAxisLabel(v);
|
||||
final y = chart.top + (chart.height * i / 2) - tp.height / 2;
|
||||
final y = chart.top + (chart.height * i / 4) - tp.height / 2;
|
||||
tp.paint(canvas, Offset(4, y));
|
||||
}
|
||||
|
||||
|
||||
+462
-254
File diff suppressed because it is too large
Load Diff
+210
-128
@@ -7,11 +7,14 @@ import 'package:provider/provider.dart';
|
||||
import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../l10n/contact_localization.dart';
|
||||
import '../models/contact.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../utils/contact_search.dart';
|
||||
import '../utils/platform_info.dart';
|
||||
import '../widgets/app_bar.dart';
|
||||
import '../widgets/list_filter_widget.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
enum DiscoverySortOption { lastSeen, name, type }
|
||||
@@ -46,6 +49,34 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
: contact.lastSeen;
|
||||
}
|
||||
|
||||
/// Node-type avatar color per design language.
|
||||
Color _avatarColor(int type) {
|
||||
switch (type) {
|
||||
case advTypeRepeater:
|
||||
return MeshPalette.warn;
|
||||
case advTypeRoom:
|
||||
return MeshPalette.magenta;
|
||||
case advTypeSensor:
|
||||
return const Color(0xFF4ACCC4); // teal
|
||||
default:
|
||||
return MeshPalette.blue;
|
||||
}
|
||||
}
|
||||
|
||||
/// Node-type avatar icon; null = show initials for chat nodes.
|
||||
IconData? _avatarIcon(int type) {
|
||||
switch (type) {
|
||||
case advTypeRepeater:
|
||||
return Icons.cell_tower;
|
||||
case advTypeRoom:
|
||||
return Icons.meeting_room;
|
||||
case advTypeSensor:
|
||||
return Icons.sensors;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
@@ -71,7 +102,10 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.delete, color: Colors.red),
|
||||
Icon(
|
||||
Icons.delete,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(context.l10n.discoveredContacts_deleteContactAll),
|
||||
],
|
||||
@@ -89,103 +123,185 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
children: [
|
||||
_buildFilters(filteredAndSorted, connector),
|
||||
Expanded(
|
||||
child: discoveredContacts.isEmpty
|
||||
? Center(child: Text(l10n.contacts_noContacts))
|
||||
: filteredAndSorted.isEmpty
|
||||
? Center(child: Text(l10n.discoveredContacts_noMatching))
|
||||
: ListView.builder(
|
||||
itemCount: filteredAndSorted.length,
|
||||
itemBuilder: (context, index) {
|
||||
final contact = filteredAndSorted[index];
|
||||
final tile = ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: _getTypeColor(contact.type),
|
||||
child: Icon(
|
||||
_getTypeIcon(contact.type),
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
child: discoveredContacts.isEmpty
|
||||
? Center(
|
||||
key: const ValueKey('empty_all'),
|
||||
child: Text(l10n.contacts_noContacts),
|
||||
)
|
||||
: filteredAndSorted.isEmpty
|
||||
? Center(
|
||||
key: const ValueKey('empty_filtered'),
|
||||
child: Text(l10n.discoveredContacts_noMatching),
|
||||
)
|
||||
: ListView.builder(
|
||||
key: const ValueKey('list'),
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
itemCount: filteredAndSorted.length,
|
||||
itemBuilder: (context, index) {
|
||||
final contact = filteredAndSorted[index];
|
||||
final tile = _buildDiscoveryTile(
|
||||
context,
|
||||
contact,
|
||||
connector,
|
||||
index,
|
||||
);
|
||||
if (PlatformInfo.isDesktop) {
|
||||
return GestureDetector(
|
||||
onSecondaryTapUp: (_) =>
|
||||
_showContactContextMenu(contact, connector),
|
||||
child: tile,
|
||||
);
|
||||
}
|
||||
return tile;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDiscoveryTile(
|
||||
BuildContext context,
|
||||
Contact contact,
|
||||
MeshCoreConnector connector,
|
||||
int index,
|
||||
) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final isChat = contact.type == advTypeChat;
|
||||
|
||||
return ListEntrance(
|
||||
index: index,
|
||||
child: MeshCard(
|
||||
onTap: () async {
|
||||
try {
|
||||
final imported = await connector.importDiscoveredContact(contact);
|
||||
if (!context.mounted) return;
|
||||
if (!imported) {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.contacts_contactImportFailed),
|
||||
);
|
||||
return;
|
||||
}
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.discoveredContacts_contactAdded),
|
||||
action: SnackBarAction(
|
||||
label: context.l10n.common_undo,
|
||||
onPressed: () => connector.removeContact(contact),
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
if (!context.mounted) return;
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.contacts_contactImportFailed),
|
||||
);
|
||||
}
|
||||
},
|
||||
onLongPress: () => _showContactContextMenu(contact, connector),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarCircle(
|
||||
name: contact.name,
|
||||
size: 42,
|
||||
color: isChat ? null : _avatarColor(contact.type),
|
||||
icon: _avatarIcon(contact.type),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Name + type chip
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
contact.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
StatusChip(
|
||||
label: contact.typeLabel(context.l10n).toUpperCase(),
|
||||
color: _avatarColor(contact.type),
|
||||
icon: _avatarIcon(contact.type),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
// Short pub key
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
contact.shortPubKeyHex,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
// Clamp text scaling in trailing section to prevent overflow while
|
||||
// maintaining accessibility. Primary content (title/subtitle) scales normally.
|
||||
trailing: MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(
|
||||
MediaQuery.textScalerOf(
|
||||
context,
|
||||
).scale(1.0).clamp(1.0, 1.3),
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
_formatLastSeen(
|
||||
context,
|
||||
_resolveLastSeen(contact),
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (contact.hasLocation)
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
size: 14,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
if (contact.rawPacket != null)
|
||||
const SizedBox(width: 2),
|
||||
if (contact.rawPacket != null)
|
||||
Icon(
|
||||
Icons.cell_tower,
|
||||
size: 14,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
connector.importDiscoveredContact(contact);
|
||||
},
|
||||
onLongPress: () =>
|
||||
_showContactContextMenu(contact, connector),
|
||||
);
|
||||
if (PlatformInfo.isDesktop) {
|
||||
return GestureDetector(
|
||||
onSecondaryTapUp: (_) =>
|
||||
_showContactContextMenu(contact, connector),
|
||||
child: tile,
|
||||
);
|
||||
}
|
||||
return tile;
|
||||
},
|
||||
),
|
||||
if (contact.hasLocation) ...[
|
||||
const SizedBox(width: 6),
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
size: 13,
|
||||
color: scheme.onSurfaceVariant.withValues(
|
||||
alpha: 0.55,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (contact.rawPacket != null) ...[
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
Icons.cell_tower,
|
||||
size: 13,
|
||||
color: scheme.onSurfaceVariant.withValues(
|
||||
alpha: 0.55,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
// Last seen time
|
||||
MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(
|
||||
MediaQuery.textScalerOf(context).scale(1.0).clamp(1.0, 1.3),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
_formatLastSeen(context, _resolveLastSeen(contact)),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.right,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -194,19 +310,17 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
Contact contact,
|
||||
MeshCoreConnector connector,
|
||||
) async {
|
||||
final action = await showModalBottomSheet<String>(
|
||||
context: context,
|
||||
showDragHandle: true,
|
||||
final action = await showMeshSheet<String>(
|
||||
context,
|
||||
builder: (sheetContext) {
|
||||
final l10n = context.l10n;
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.add_reaction_sharp),
|
||||
title: Text(l10n.discoveredContacts_addContact),
|
||||
onTap: () => Navigator.of(sheetContext).pop('import_contact'),
|
||||
BottomSheetHeader(
|
||||
title: contact.name,
|
||||
subtitle: contact.typeLabel(l10n),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.copy),
|
||||
@@ -218,6 +332,7 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
title: Text(l10n.discoveredContacts_deleteContact),
|
||||
onTap: () => Navigator.of(sheetContext).pop('delete_contact'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -227,9 +342,6 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
if (!mounted || action == null) return;
|
||||
|
||||
switch (action) {
|
||||
case 'import_contact':
|
||||
connector.importDiscoveredContact(contact);
|
||||
break;
|
||||
case 'copy_contact':
|
||||
if (contact.rawPacket == null) return;
|
||||
final hexString = pubKeyToHex(contact.rawPacket!);
|
||||
@@ -429,36 +541,6 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
IconData _getTypeIcon(int type) {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return Icons.chat;
|
||||
case advTypeRepeater:
|
||||
return Icons.cell_tower;
|
||||
case advTypeRoom:
|
||||
return Icons.group;
|
||||
case advTypeSensor:
|
||||
return Icons.sensors;
|
||||
default:
|
||||
return Icons.device_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getTypeColor(int type) {
|
||||
switch (type) {
|
||||
case advTypeChat:
|
||||
return Colors.blue;
|
||||
case advTypeRepeater:
|
||||
return Colors.orange;
|
||||
case advTypeRoom:
|
||||
return Colors.purple;
|
||||
case advTypeSensor:
|
||||
return Colors.green;
|
||||
default:
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
String _formatLastSeen(BuildContext context, DateTime lastSeen) {
|
||||
final now = DateTime.now();
|
||||
final diff = now.difference(lastSeen);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+223
-109
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
@@ -9,6 +10,9 @@ import '../services/app_settings_service.dart';
|
||||
import '../services/map_tile_cache_service.dart';
|
||||
import '../widgets/adaptive_app_bar_title.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../widgets/themed_map_tile_layer.dart';
|
||||
|
||||
class MapCacheScreen extends StatefulWidget {
|
||||
const MapCacheScreen({super.key});
|
||||
@@ -18,6 +22,9 @@ class MapCacheScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
static const double _mapMinZoom = 2.0;
|
||||
static const double _mapMaxZoom = 18.0;
|
||||
|
||||
final MapController _mapController = MapController();
|
||||
|
||||
LatLngBounds? _selectedBounds;
|
||||
@@ -43,6 +50,68 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool _isDesktopPlatform(TargetPlatform platform) {
|
||||
return platform == TargetPlatform.linux ||
|
||||
platform == TargetPlatform.windows ||
|
||||
platform == TargetPlatform.macOS;
|
||||
}
|
||||
|
||||
void _zoomMapBy(double delta) {
|
||||
final camera = _mapController.camera;
|
||||
final nextZoom = (camera.zoom + delta)
|
||||
.clamp(_mapMinZoom, _mapMaxZoom)
|
||||
.toDouble();
|
||||
_mapController.move(camera.center, nextZoom);
|
||||
}
|
||||
|
||||
void _resetMapView() {
|
||||
final bounds = _selectedBounds;
|
||||
if (bounds != null) {
|
||||
_mapController.fitCamera(
|
||||
CameraFit.bounds(bounds: bounds, padding: const EdgeInsets.all(48)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
_mapController.move(const LatLng(0, 0), 2.0);
|
||||
}
|
||||
|
||||
Widget _buildDesktopMapControls() {
|
||||
return Positioned(
|
||||
top: 12,
|
||||
left: 12,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: MeshPalette.bg1.withValues(alpha: 0.90),
|
||||
borderRadius: BorderRadius.circular(MeshRadii.md),
|
||||
border: Border.all(color: MeshPalette.line2),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(MeshRadii.md),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
tooltip: context.l10n.map_zoomIn,
|
||||
onPressed: () => _zoomMapBy(1),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.remove),
|
||||
tooltip: context.l10n.map_zoomOut,
|
||||
onPressed: () => _zoomMapBy(-1),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.my_location),
|
||||
tooltip: context.l10n.map_centerMap,
|
||||
onPressed: _resetMapView,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _loadSettings() {
|
||||
final settings = context.read<AppSettingsService>().settings;
|
||||
final bounds = MapTileCacheService.boundsFromJson(settings.mapCacheBounds);
|
||||
@@ -222,6 +291,8 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
final tileCache = context.read<MapTileCacheService>();
|
||||
final selectedBounds = _selectedBounds;
|
||||
final l10n = context.l10n;
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final isDesktop = _isDesktopPlatform(defaultTargetPlatform);
|
||||
final progressValue = _estimatedTiles == 0
|
||||
? 0.0
|
||||
: (_completedTiles / _estimatedTiles).clamp(0.0, 1.0).toDouble();
|
||||
@@ -238,20 +309,27 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
children: [
|
||||
FlutterMap(
|
||||
mapController: _mapController,
|
||||
options: const MapOptions(
|
||||
initialCenter: LatLng(0, 0),
|
||||
options: MapOptions(
|
||||
initialCenter: const LatLng(0, 0),
|
||||
initialZoom: 2.0,
|
||||
minZoom: 2.0,
|
||||
maxZoom: 18.0,
|
||||
minZoom: _mapMinZoom,
|
||||
maxZoom: _mapMaxZoom,
|
||||
interactionOptions: InteractionOptions(
|
||||
flags: ~InteractiveFlag.rotate,
|
||||
scrollWheelVelocity: isDesktop ? 0.012 : 0.005,
|
||||
cursorKeyboardRotationOptions:
|
||||
CursorKeyboardRotationOptions.disabled(),
|
||||
keyboardOptions: isDesktop
|
||||
? const KeyboardOptions(
|
||||
enableArrowKeysPanning: true,
|
||||
enableWASDPanning: true,
|
||||
enableRFZooming: true,
|
||||
)
|
||||
: const KeyboardOptions.disabled(),
|
||||
),
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: kMapTileUrlTemplate,
|
||||
tileProvider: tileCache.tileProvider,
|
||||
userAgentPackageName:
|
||||
MapTileCacheService.userAgentPackageName,
|
||||
maxZoom: 19,
|
||||
),
|
||||
ThemedMapTileLayer(tileCache: tileCache),
|
||||
if (selectedBounds != null)
|
||||
PolygonLayer(
|
||||
polygons: [
|
||||
@@ -265,17 +343,29 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop) _buildDesktopMapControls(),
|
||||
Positioned(
|
||||
top: 12,
|
||||
right: 12,
|
||||
child: Card(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: MeshPalette.bg1.withValues(alpha: 0.93),
|
||||
borderRadius: BorderRadius.circular(MeshRadii.md),
|
||||
border: Border.all(color: MeshPalette.line2),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
selectedBounds == null
|
||||
? l10n.mapCache_noAreaSelected
|
||||
: _formatBounds(selectedBounds, l10n),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
color: MeshPalette.ink2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -285,109 +375,133 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
|
||||
),
|
||||
SafeArea(
|
||||
top: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
l10n.mapCache_cacheArea,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: scheme.surfaceContainerLow,
|
||||
border: Border(top: BorderSide(color: scheme.outlineVariant)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SectionHeader(
|
||||
l10n.mapCache_cacheArea,
|
||||
padding: const EdgeInsets.fromLTRB(0, 12, 0, 8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.crop_free),
|
||||
label: Text(l10n.mapCache_useCurrentView),
|
||||
onPressed: _isDownloading ? null : _setBoundsFromView,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.crop_free),
|
||||
label: Text(l10n.mapCache_useCurrentView),
|
||||
onPressed: _isDownloading
|
||||
? null
|
||||
: _setBoundsFromView,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
TextButton(
|
||||
onPressed: _isDownloading || selectedBounds == null
|
||||
? null
|
||||
: _clearBounds,
|
||||
child: Text(l10n.common_clear),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.mapCache_zoomRange,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
RangeSlider(
|
||||
values: RangeValues(
|
||||
_minZoom.toDouble(),
|
||||
_maxZoom.toDouble(),
|
||||
),
|
||||
min: 3,
|
||||
max: 18,
|
||||
divisions: 15,
|
||||
labels: RangeLabels('$_minZoom', '$_maxZoom'),
|
||||
onChanged: _isDownloading
|
||||
? null
|
||||
: (values) {
|
||||
setState(() {
|
||||
_minZoom = values.start.round();
|
||||
_maxZoom = values.end.round();
|
||||
});
|
||||
},
|
||||
onChangeEnd: _isDownloading
|
||||
? null
|
||||
: (_) {
|
||||
_saveZoomRange();
|
||||
},
|
||||
),
|
||||
Text(l10n.mapCache_estimatedTiles(_estimatedTiles)),
|
||||
if (_isDownloading) ...[
|
||||
const SizedBox(height: 8),
|
||||
LinearProgressIndicator(value: progressValue),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.mapCache_downloadedTiles(
|
||||
_completedTiles,
|
||||
_estimatedTiles,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.download),
|
||||
label: Text(l10n.mapCache_downloadTilesButton),
|
||||
const SizedBox(width: 12),
|
||||
TextButton(
|
||||
onPressed: _isDownloading || selectedBounds == null
|
||||
? null
|
||||
: _startDownload,
|
||||
: _clearBounds,
|
||||
child: Text(l10n.common_clear),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SectionHeader(
|
||||
l10n.mapCache_zoomRange,
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 0, 0),
|
||||
),
|
||||
RangeSlider(
|
||||
values: RangeValues(
|
||||
_minZoom.toDouble(),
|
||||
_maxZoom.toDouble(),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
OutlinedButton(
|
||||
onPressed: _isDownloading ? null : _clearCache,
|
||||
child: Text(l10n.mapCache_clearCacheButton),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_failedTiles > 0 && !_isDownloading)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
l10n.mapCache_failedDownloads(_failedTiles),
|
||||
style: TextStyle(color: Colors.orange[700]),
|
||||
min: 3,
|
||||
max: 18,
|
||||
divisions: 15,
|
||||
labels: RangeLabels('$_minZoom', '$_maxZoom'),
|
||||
onChanged: _isDownloading
|
||||
? null
|
||||
: (values) {
|
||||
setState(() {
|
||||
_minZoom = values.start.round();
|
||||
_maxZoom = values.end.round();
|
||||
});
|
||||
},
|
||||
onChangeEnd: _isDownloading
|
||||
? null
|
||||
: (_) {
|
||||
_saveZoomRange();
|
||||
},
|
||||
),
|
||||
Text(
|
||||
l10n.mapCache_estimatedTiles(_estimatedTiles),
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 12,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_isDownloading) ...[
|
||||
const SizedBox(height: 8),
|
||||
LinearProgressIndicator(
|
||||
value: progressValue,
|
||||
color: MeshPalette.blue,
|
||||
backgroundColor: scheme.surfaceContainerHighest,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.mapCache_downloadedTiles(
|
||||
_completedTiles,
|
||||
_estimatedTiles,
|
||||
),
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 12,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.download),
|
||||
label: Text(l10n.mapCache_downloadTilesButton),
|
||||
onPressed: _isDownloading || selectedBounds == null
|
||||
? null
|
||||
: _startDownload,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: MeshPalette.alert,
|
||||
side: const BorderSide(
|
||||
color: MeshPalette.alertLine,
|
||||
),
|
||||
),
|
||||
onPressed: _isDownloading ? null : _clearCache,
|
||||
child: Text(l10n.mapCache_clearCacheButton),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_failedTiles > 0 && !_isDownloading)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
l10n.mapCache_failedDownloads(_failedTiles),
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 12,
|
||||
color: MeshPalette.alert,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
+2396
-761
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,10 @@ import '../models/path_selection.dart';
|
||||
import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../services/repeater_command_service.dart';
|
||||
import '../widgets/path_management_dialog.dart';
|
||||
import '../widgets/snr_indicator.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/empty_state.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../widgets/routing_sheet.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
class NeighborsScreen extends StatefulWidget {
|
||||
@@ -167,7 +169,7 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.neighbors_receivedData),
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: Theme.of(context).colorScheme.tertiary,
|
||||
);
|
||||
_statusTimeout?.cancel();
|
||||
if (!mounted) return;
|
||||
@@ -227,7 +229,7 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.neighbors_requestTimedOut),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
);
|
||||
_recordStatusResult(false);
|
||||
});
|
||||
@@ -241,7 +243,7 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.neighbors_errorLoading(e.toString())),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -279,7 +281,9 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
children: [
|
||||
Text(
|
||||
l10n.neighbors_repeatersNeighbors,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
repeater.name,
|
||||
@@ -287,75 +291,18 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
centerTitle: false,
|
||||
actions: [
|
||||
PopupMenuButton<String>(
|
||||
IconButton(
|
||||
icon: Icon(isFloodMode ? Icons.waves : Icons.route),
|
||||
tooltip: l10n.repeater_routingMode,
|
||||
onSelected: (mode) async {
|
||||
if (mode == 'flood') {
|
||||
await connector.setPathOverride(repeater, pathLen: -1);
|
||||
} else {
|
||||
await connector.setPathOverride(repeater, pathLen: null);
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
value: 'auto',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.auto_mode,
|
||||
size: 20,
|
||||
color: !isFloodMode
|
||||
? Theme.of(context).primaryColor
|
||||
: null,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_autoUseSavedPath,
|
||||
style: TextStyle(
|
||||
fontWeight: !isFloodMode
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'flood',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.waves,
|
||||
size: 20,
|
||||
color: isFloodMode
|
||||
? Theme.of(context).primaryColor
|
||||
: null,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_forceFloodMode,
|
||||
style: TextStyle(
|
||||
fontWeight: isFloodMode
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.timeline),
|
||||
tooltip: l10n.repeater_pathManagement,
|
||||
onPressed: () =>
|
||||
PathManagementDialog.show(context, contact: repeater),
|
||||
ContactRoutingSheet.show(context, contact: repeater),
|
||||
),
|
||||
IconButton(
|
||||
icon: _isLoading
|
||||
@@ -375,23 +322,16 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _loadNeighbors,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 24),
|
||||
children: [
|
||||
if (!_isLoaded &&
|
||||
!_hasData &&
|
||||
(_parsedNeighbors == null || _parsedNeighbors!.isEmpty))
|
||||
Center(
|
||||
child: Text(
|
||||
l10n.neighbors_noData,
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
||||
),
|
||||
),
|
||||
EmptyState(icon: Icons.wifi_find, title: l10n.neighbors_noData),
|
||||
if (_isLoaded ||
|
||||
_hasData &&
|
||||
!(_parsedNeighbors == null || _parsedNeighbors!.isEmpty))
|
||||
_buildNeighborsInfoCard(
|
||||
"${l10n.repeater_neighbors} - $_neighborCount",
|
||||
),
|
||||
_buildNeighborsList(connector),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -399,81 +339,97 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNeighborsInfoCard(String title) {
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
Widget _buildNeighborsList(MeshCoreConnector connector) {
|
||||
final l10n = context.l10n;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SectionHeader(
|
||||
'${l10n.repeater_neighbors} — $_neighborCount',
|
||||
padding: const EdgeInsets.fromLTRB(4, 8, 4, 10),
|
||||
),
|
||||
for (var i = 0; i < _parsedNeighbors!.length; i++)
|
||||
ListEntrance(
|
||||
index: i,
|
||||
child: _buildNeighborRow(_parsedNeighbors![i], connector.currentSf),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNeighborRow(Map<String, dynamic> data, int? spreadingFactor) {
|
||||
final l10n = context.l10n;
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final Contact? contact = data['contact'] as Contact?;
|
||||
final double snr = data['snr'] as double;
|
||||
final int lastHeardSeconds = data['lastHeard'] as int;
|
||||
|
||||
final name = contact != null
|
||||
? contact.name
|
||||
: l10n.neighbors_unknownContact(
|
||||
'<${pubKeyToHex(data['publicKey'] as Uint8List)}>',
|
||||
);
|
||||
|
||||
final snrColor = MeshTheme.snrColor(snr, blocked: false);
|
||||
final heardLabel = l10n.neighbors_heardAgo(
|
||||
fmtDuration(lastHeardSeconds + 0.0),
|
||||
);
|
||||
|
||||
return MeshCard(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarCircle(
|
||||
name: name,
|
||||
size: 40,
|
||||
color: contact != null ? MeshPalette.warn : scheme.onSurfaceVariant,
|
||||
icon: contact != null ? Icons.cell_tower : Icons.device_unknown,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
heardLabel,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
for (final entry in _parsedNeighbors!.asMap().entries)
|
||||
_buildInfoRow(
|
||||
entry.value['contact'] != null
|
||||
? entry.value['contact'].name
|
||||
: context.l10n.neighbors_unknownContact(
|
||||
"<${pubKeyToHex(entry.value['publicKey'])}>",
|
||||
),
|
||||
context.l10n.neighbors_heardAgo(
|
||||
fmtDuration(entry.value['lastHeard'] + 0.0),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SignalBars(snr: snr, height: 16),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${snr.toStringAsFixed(1)} dB',
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: snrColor,
|
||||
),
|
||||
entry.value['snr'],
|
||||
connector.currentSf!,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(
|
||||
String label,
|
||||
String value,
|
||||
double snr,
|
||||
int spreadingFactor,
|
||||
) {
|
||||
final snrUi = snrUiFromSNR(snr, spreadingFactor);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 3),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
label,
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text(value),
|
||||
trailing: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(snrUi.icon, color: snrUi.color, size: 18.0),
|
||||
Text(
|
||||
snrUi.text,
|
||||
style: TextStyle(fontSize: 10, color: snrUi.color),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
+1030
-206
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:meshcore_open/connector/meshcore_protocol.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../models/contact.dart';
|
||||
import '../l10n/contact_localization.dart';
|
||||
import '../services/app_settings_service.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import 'repeater_status_screen.dart';
|
||||
import 'repeater_cli_screen.dart';
|
||||
import 'repeater_settings_screen.dart';
|
||||
@@ -25,175 +29,157 @@ class RepeaterHubScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final settingsService = context.watch<AppSettingsService>();
|
||||
final chemistry = settingsService.batteryChemistryForRepeater(
|
||||
repeater.publicKeyHex,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isAdmin)
|
||||
Text(
|
||||
repeater.type == advTypeRepeater
|
||||
? l10n.repeater_management
|
||||
: l10n.room_management,
|
||||
),
|
||||
if (!isAdmin)
|
||||
Text(
|
||||
repeater.type == advTypeRepeater
|
||||
? l10n.repeater_guest
|
||||
: l10n.room_guest,
|
||||
),
|
||||
Text(
|
||||
repeater.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
repeater.type == advTypeRepeater
|
||||
? (isAdmin ? l10n.repeater_management : l10n.repeater_guest)
|
||||
: (isAdmin ? l10n.room_management : l10n.room_guest),
|
||||
),
|
||||
centerTitle: false,
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
children: [
|
||||
// Repeater info card
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
// ── Identity card ─────────────────────────────────────────────
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 20, 16, 4),
|
||||
child: MeshCard(
|
||||
margin: EdgeInsets.zero,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.orange,
|
||||
child: const Icon(
|
||||
Icons.cell_tower,
|
||||
size: 40,
|
||||
color: Colors.white,
|
||||
),
|
||||
AvatarCircle(
|
||||
name: repeater.name,
|
||||
size: 52,
|
||||
color: MeshPalette.warn,
|
||||
icon: Icons.cell_tower,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
repeater.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
repeater.shortPubKeyHex,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
repeater.pathLabel,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
),
|
||||
if (repeater.hasLocation) ...[
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
size: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${repeater.latitude?.toStringAsFixed(4)}, ${repeater.longitude?.toStringAsFixed(4)}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
repeater.name,
|
||||
style: Theme.of(context).textTheme.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.w700),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
repeater.shortPubKeyHex,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
repeater.pathLabel(l10n),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(color: scheme.onSurfaceVariant),
|
||||
),
|
||||
if (repeater.hasLocation) ...[
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
size: 12,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${repeater.latitude?.toStringAsFixed(4)}, '
|
||||
'${repeater.longitude?.toStringAsFixed(4)}',
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 10,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
StatusChip(
|
||||
label: isAdmin ? 'ADMIN' : 'GUEST',
|
||||
color: isAdmin
|
||||
? MeshPalette.blue
|
||||
: scheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
if (isAdmin)
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.battery_full),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l10n.appSettings_batteryChemistry,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: chemistry,
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
isDense: true,
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
settingsService.setBatteryChemistryForRepeater(
|
||||
repeater.publicKeyHex,
|
||||
value,
|
||||
);
|
||||
},
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 'nmc',
|
||||
child: Text(l10n.appSettings_batteryNmc),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'lifepo4',
|
||||
child: Text(l10n.appSettings_batteryLifepo4),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'lipo',
|
||||
child: Text(l10n.appSettings_batteryLipo),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
// ── Battery chemistry (admin only) ─────────────────────────────
|
||||
if (isAdmin) ...[
|
||||
SectionHeader(l10n.appSettings_batteryChemistry),
|
||||
MeshCard(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
padding: const EdgeInsets.fromLTRB(14, 10, 14, 14),
|
||||
child: DropdownButtonFormField<String>(
|
||||
initialValue: chemistry,
|
||||
isExpanded: true,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.battery_full, size: 18),
|
||||
labelText: l10n.appSettings_batteryChemistry,
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
settingsService.setBatteryChemistryForRepeater(
|
||||
repeater.publicKeyHex,
|
||||
value,
|
||||
);
|
||||
},
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 'nmc',
|
||||
child: Text(l10n.appSettings_batteryNmc),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'lifepo4',
|
||||
child: Text(l10n.appSettings_batteryLifepo4),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'lipo',
|
||||
child: Text(l10n.appSettings_batteryLipo),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
],
|
||||
|
||||
// ── Tools ──────────────────────────────────────────────────────
|
||||
SectionHeader(
|
||||
isAdmin
|
||||
? l10n.repeater_managementTools
|
||||
: l10n.repeater_guestTools,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Status button
|
||||
_buildManagementCard(
|
||||
context,
|
||||
|
||||
_HubActionTile(
|
||||
index: 0,
|
||||
icon: Icons.analytics,
|
||||
title: l10n.repeater_status,
|
||||
subtitle: l10n.repeater_statusSubtitle,
|
||||
color: Colors.blue,
|
||||
accentColor: MeshPalette.blue,
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -205,15 +191,15 @@ class RepeaterHubScreen extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Telemetry button
|
||||
_buildManagementCard(
|
||||
context,
|
||||
|
||||
_HubActionTile(
|
||||
index: 1,
|
||||
icon: Icons.bar_chart_sharp,
|
||||
title: l10n.repeater_telemetry,
|
||||
subtitle: l10n.repeater_telemetrySubtitle,
|
||||
color: Colors.teal,
|
||||
accentColor: MeshPalette.magenta,
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -222,16 +208,34 @@ class RepeaterHubScreen extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isAdmin) const SizedBox(height: 12),
|
||||
// CLI button
|
||||
if (isAdmin)
|
||||
_buildManagementCard(
|
||||
context,
|
||||
|
||||
_HubActionTile(
|
||||
index: 2,
|
||||
icon: Icons.group,
|
||||
title: l10n.repeater_neighbors,
|
||||
subtitle: l10n.repeater_neighborsSubtitle,
|
||||
accentColor: MeshPalette.signal,
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
NeighborsScreen(repeater: repeater, password: password),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
if (isAdmin) ...[
|
||||
_HubActionTile(
|
||||
index: 3,
|
||||
icon: Icons.terminal,
|
||||
title: l10n.repeater_cli,
|
||||
subtitle: l10n.repeater_cliSubtitle,
|
||||
color: Colors.green,
|
||||
accentColor: MeshPalette.warn,
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -243,34 +247,14 @@ class RepeaterHubScreen extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Neighbors button
|
||||
_buildManagementCard(
|
||||
context,
|
||||
icon: Icons.group,
|
||||
title: l10n.repeater_neighbors,
|
||||
subtitle: l10n.repeater_neighborsSubtitle,
|
||||
color: Colors.orange,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
NeighborsScreen(repeater: repeater, password: password),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isAdmin) const SizedBox(height: 12),
|
||||
// Settings button
|
||||
if (isAdmin)
|
||||
_buildManagementCard(
|
||||
context,
|
||||
_HubActionTile(
|
||||
index: 4,
|
||||
icon: Icons.settings,
|
||||
title: l10n.repeater_settings,
|
||||
subtitle: l10n.repeater_settingsSubtitle,
|
||||
color: Colors.deepOrange,
|
||||
accentColor: MeshPalette.alert,
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -282,60 +266,76 @@ class RepeaterHubScreen extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildManagementCard(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required Color color,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
child: InkWell(
|
||||
class _HubActionTile extends StatelessWidget {
|
||||
final int index;
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final Color accentColor;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _HubActionTile({
|
||||
required this.index,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.accentColor,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return ListEntrance(
|
||||
index: index,
|
||||
child: MeshCard(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(icon, color: color, size: 32),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: accentColor.withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(MeshRadii.md),
|
||||
border: Border.all(color: accentColor.withValues(alpha: 0.3)),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(icon, size: 22, color: accentColor),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 15,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
fontSize: 12.5,
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Icon(Icons.chevron_right, color: Colors.grey[400]),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(Icons.chevron_right, color: scheme.onSurfaceVariant, size: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../models/contact.dart';
|
||||
@@ -10,8 +11,10 @@ import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../services/app_settings_service.dart';
|
||||
import '../services/repeater_command_service.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../utils/battery_utils.dart';
|
||||
import '../widgets/path_management_dialog.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../widgets/routing_sheet.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
class RepeaterStatusScreen extends StatefulWidget {
|
||||
@@ -38,7 +41,6 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
StreamSubscription<Uint8List>? _frameSubscription;
|
||||
RepeaterCommandService? _commandService;
|
||||
Timer? _statusTimeout;
|
||||
DateTime? _statusRequestedAt;
|
||||
int? _batteryMv;
|
||||
int? _uptimeSecs;
|
||||
int? _queueLen;
|
||||
@@ -56,6 +58,7 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
int? _directRx;
|
||||
int? _dupFlood;
|
||||
int? _dupDirect;
|
||||
double? _chanUtil;
|
||||
PathSelection? _pendingStatusSelection;
|
||||
|
||||
@override
|
||||
@@ -64,7 +67,9 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
_commandService = RepeaterCommandService(connector);
|
||||
_setupMessageListener();
|
||||
_loadStatus();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) _loadStatus();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -77,12 +82,8 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
|
||||
void _setupMessageListener() {
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
|
||||
// Listen for incoming text messages from the repeater
|
||||
_frameSubscription = connector.receivedFrames.listen((frame) {
|
||||
if (frame.isEmpty) return;
|
||||
|
||||
// Check if it's a text message response
|
||||
if (frame[0] == pushCodeStatusResponse) {
|
||||
_handleStatusResponse(frame);
|
||||
} else if (frame[0] == respCodeContactMsgRecv ||
|
||||
@@ -114,11 +115,7 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
final parsed = parseContactMessageText(frame);
|
||||
if (parsed == null) return;
|
||||
if (!_matchesRepeaterPrefix(parsed.senderPrefix)) return;
|
||||
|
||||
// Notify command service of response (for retry handling)
|
||||
_commandService?.handleResponse(widget.repeater, parsed.text);
|
||||
|
||||
// Parse status responses
|
||||
_parseStatusResponse(parsed.text);
|
||||
_recordStatusResult(true);
|
||||
}
|
||||
@@ -127,7 +124,6 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
if (frame.length < 8) return;
|
||||
final prefix = frame.sublist(2, 8);
|
||||
if (!_matchesRepeaterPrefix(prefix)) return;
|
||||
|
||||
if (frame.length < _statusResponseBytes) return;
|
||||
|
||||
final data = ByteData.sublistView(
|
||||
@@ -192,6 +188,7 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
_lastSnr = lastSnrRaw / 4.0;
|
||||
_dupDirect = directDups;
|
||||
_dupFlood = floodDups;
|
||||
_chanUtil = ((txAirSecs + rxAirSecs) / uptimeSecs) * 100;
|
||||
});
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
connector.updateRepeaterBatterySnapshot(
|
||||
@@ -249,14 +246,9 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
_dupFlood = _asInt(data['dup_flood']);
|
||||
_dupDirect = _asInt(data['dup_direct']);
|
||||
}
|
||||
} catch (_) {
|
||||
// Ignore parse failures for non-JSON responses.
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
} catch (_) {}
|
||||
}
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _loadStatus() async {
|
||||
@@ -264,7 +256,6 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_statusRequestedAt = DateTime.now();
|
||||
_pendingStatusSelection = null;
|
||||
_batteryMv = null;
|
||||
_uptimeSecs = null;
|
||||
@@ -283,6 +274,7 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
_directRx = null;
|
||||
_dupFlood = null;
|
||||
_dupDirect = null;
|
||||
_chanUtil = null;
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -297,9 +289,7 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
var messageBytes = frame.length >= _statusResponseBytes
|
||||
? frame.length
|
||||
: _statusResponseBytes;
|
||||
if (messageBytes < maxFrameSize) {
|
||||
messageBytes = maxFrameSize;
|
||||
}
|
||||
if (messageBytes < maxFrameSize) messageBytes = maxFrameSize;
|
||||
final timeoutMs = connector.calculateTimeout(
|
||||
pathLength: pathLengthValue,
|
||||
messageBytes: messageBytes,
|
||||
@@ -307,26 +297,21 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
_statusTimeout?.cancel();
|
||||
_statusTimeout = Timer(Duration(milliseconds: timeoutMs), () {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
setState(() => _isLoading = false);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.repeater_statusRequestTimeout),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
);
|
||||
_recordStatusResult(false);
|
||||
});
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
setState(() => _isLoading = false);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.repeater_errorLoadingStatus(e.toString())),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
);
|
||||
}
|
||||
_recordStatusResult(false);
|
||||
@@ -342,267 +327,6 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
_pendingStatusSelection = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
final connector = context.watch<MeshCoreConnector>();
|
||||
final repeater = _resolveRepeater(connector);
|
||||
final isFloodMode = repeater.pathOverride == -1;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(l10n.repeater_statusTitle),
|
||||
Text(
|
||||
repeater.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
centerTitle: false,
|
||||
actions: [
|
||||
PopupMenuButton<String>(
|
||||
icon: Icon(isFloodMode ? Icons.waves : Icons.route),
|
||||
tooltip: l10n.repeater_routingMode,
|
||||
onSelected: (mode) async {
|
||||
if (mode == 'flood') {
|
||||
await connector.setPathOverride(repeater, pathLen: -1);
|
||||
} else {
|
||||
await connector.setPathOverride(repeater, pathLen: null);
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
value: 'auto',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.auto_mode,
|
||||
size: 20,
|
||||
color: !isFloodMode
|
||||
? Theme.of(context).primaryColor
|
||||
: null,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_autoUseSavedPath,
|
||||
style: TextStyle(
|
||||
fontWeight: !isFloodMode
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'flood',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.waves,
|
||||
size: 20,
|
||||
color: isFloodMode
|
||||
? Theme.of(context).primaryColor
|
||||
: null,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_forceFloodMode,
|
||||
style: TextStyle(
|
||||
fontWeight: isFloodMode
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.timeline),
|
||||
tooltip: l10n.repeater_pathManagement,
|
||||
onPressed: () =>
|
||||
PathManagementDialog.show(context, contact: repeater),
|
||||
),
|
||||
IconButton(
|
||||
icon: _isLoading
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.refresh),
|
||||
onPressed: _isLoading ? null : _loadStatus,
|
||||
tooltip: l10n.repeater_refresh,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _loadStatus,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
_buildSystemInfoCard(),
|
||||
const SizedBox(height: 16),
|
||||
_buildRadioStatsCard(),
|
||||
const SizedBox(height: 16),
|
||||
_buildPacketStatsCard(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSystemInfoCard() {
|
||||
final l10n = context.l10n;
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_systemInformation,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
_buildInfoRow(l10n.repeater_battery, _batteryText()),
|
||||
_buildInfoRow(l10n.repeater_clockAtLogin, _clockText()),
|
||||
_buildInfoRow(l10n.repeater_uptime, _formatDuration(_uptimeSecs)),
|
||||
_buildInfoRow(l10n.repeater_queueLength, _formatValue(_queueLen)),
|
||||
_buildInfoRow(l10n.repeater_debugFlags, _formatValue(_debugFlags)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioStatsCard() {
|
||||
final l10n = context.l10n;
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.radio,
|
||||
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_radioStatistics,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
_buildInfoRow(
|
||||
l10n.repeater_lastRssi,
|
||||
_formatValue(_lastRssi, suffix: ' dB'),
|
||||
),
|
||||
_buildInfoRow(l10n.repeater_lastSnr, _formatSnr(_lastSnr)),
|
||||
_buildInfoRow(
|
||||
l10n.repeater_noiseFloor,
|
||||
_formatValue(_noiseFloor, suffix: ' dB'),
|
||||
),
|
||||
_buildInfoRow(l10n.repeater_txAirtime, _formatDuration(_txAirSecs)),
|
||||
_buildInfoRow(l10n.repeater_rxAirtime, _formatDuration(_rxAirSecs)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPacketStatsCard() {
|
||||
final l10n = context.l10n;
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.analytics,
|
||||
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.repeater_packetStatistics,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
_buildInfoRow(l10n.repeater_sent, _packetTxText()),
|
||||
_buildInfoRow(l10n.repeater_received, _packetRxText()),
|
||||
_buildInfoRow(l10n.repeater_duplicates, _duplicateText()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 130,
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
int? _asInt(dynamic value) {
|
||||
if (value == null) return null;
|
||||
if (value is int) return value;
|
||||
@@ -639,11 +363,13 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
}
|
||||
|
||||
String _clockText() {
|
||||
if (_statusRequestedAt == null) return '—';
|
||||
final dt = _statusRequestedAt!;
|
||||
final date = '${dt.day}/${dt.month}/${dt.year}';
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
final dt = connector.repeaterClockAtLogin(widget.repeater.publicKey);
|
||||
if (dt == null) return '—';
|
||||
final local = dt.toLocal();
|
||||
final date = '${local.day}/${local.month}/${local.year}';
|
||||
final time =
|
||||
'${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
|
||||
'${local.hour.toString().padLeft(2, '0')}:${local.minute.toString().padLeft(2, '0')}';
|
||||
return '$date $time';
|
||||
}
|
||||
|
||||
@@ -673,6 +399,11 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
return l10n.repeater_packetRxTotal(_packetsRecv!, flood, direct);
|
||||
}
|
||||
|
||||
String _chanUtilText() {
|
||||
if (_chanUtil == null) return '—';
|
||||
return _formatPercent(_chanUtil);
|
||||
}
|
||||
|
||||
String _duplicateText() {
|
||||
final l10n = context.l10n;
|
||||
if (_dupFlood != null || _dupDirect != null) {
|
||||
@@ -693,8 +424,230 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
|
||||
return suffix == null ? value.toString() : '$value$suffix';
|
||||
}
|
||||
|
||||
String _formatPercent(double? p) {
|
||||
if (p == null) return '—';
|
||||
return '${p.toStringAsFixed(2)}%';
|
||||
}
|
||||
|
||||
String _formatSnr(double? snr) {
|
||||
if (snr == null) return '—';
|
||||
return snr.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
final connector = context.watch<MeshCoreConnector>();
|
||||
final repeater = _resolveRepeater(connector);
|
||||
final isFloodMode = repeater.pathOverride == -1;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(l10n.repeater_statusTitle),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(isFloodMode ? Icons.waves : Icons.route),
|
||||
tooltip: l10n.repeater_routingMode,
|
||||
onPressed: () =>
|
||||
ContactRoutingSheet.show(context, contact: repeater),
|
||||
),
|
||||
IconButton(
|
||||
icon: _isLoading
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.refresh),
|
||||
onPressed: _isLoading ? null : _loadStatus,
|
||||
tooltip: l10n.repeater_refresh,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _loadStatus,
|
||||
child: _isLoading && _batteryMv == null
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _buildBody(l10n, repeater.name),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(dynamic l10n, String name) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return ListView(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
children: [
|
||||
// ── System ─────────────────────────────────────────────────────────
|
||||
SectionHeader(l10n.repeater_systemInformation),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildStatGrid([
|
||||
_StatItem(
|
||||
icon: Icons.battery_std,
|
||||
label: l10n.repeater_battery,
|
||||
value: _batteryText(),
|
||||
color: _batteryColor(),
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.timer_outlined,
|
||||
label: l10n.repeater_uptime,
|
||||
value: _formatDuration(_uptimeSecs),
|
||||
color: MeshPalette.blue,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.schedule,
|
||||
label: l10n.repeater_clockAtLogin,
|
||||
value: _clockText(),
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.inbox,
|
||||
label: l10n.repeater_queueLength,
|
||||
value: _formatValue(_queueLen),
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.bug_report_outlined,
|
||||
label: l10n.repeater_debugFlags,
|
||||
value: _formatValue(_debugFlags),
|
||||
color: _debugFlags != null && _debugFlags! > 0
|
||||
? MeshPalette.warn
|
||||
: scheme.onSurfaceVariant,
|
||||
),
|
||||
]),
|
||||
),
|
||||
|
||||
// ── Radio ──────────────────────────────────────────────────────────
|
||||
SectionHeader(l10n.repeater_radioStatistics),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildStatGrid([
|
||||
_StatItem(
|
||||
icon: Icons.signal_cellular_alt,
|
||||
label: l10n.repeater_lastRssi,
|
||||
value: _formatValue(_lastRssi, suffix: ' dB'),
|
||||
color: MeshPalette.blue,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.waves,
|
||||
label: l10n.repeater_lastSnr,
|
||||
value: _formatSnr(_lastSnr),
|
||||
color: MeshTheme.snrColor(_lastSnr, blocked: false),
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.noise_control_off,
|
||||
label: l10n.repeater_noiseFloor,
|
||||
value: _formatValue(_noiseFloor, suffix: ' dB'),
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.upload,
|
||||
label: l10n.repeater_txAirtime,
|
||||
value: _formatDuration(_txAirSecs),
|
||||
color: MeshPalette.warn,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.download,
|
||||
label: l10n.repeater_rxAirtime,
|
||||
value: _formatDuration(_rxAirSecs),
|
||||
color: MeshPalette.signal,
|
||||
),
|
||||
]),
|
||||
),
|
||||
|
||||
// ── Packets ────────────────────────────────────────────────────────
|
||||
SectionHeader(l10n.repeater_packetStatistics),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildStatGrid([
|
||||
_StatItem(
|
||||
icon: Icons.send,
|
||||
label: l10n.repeater_sent,
|
||||
value: _packetTxText(),
|
||||
color: MeshPalette.blue,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.call_received,
|
||||
label: l10n.repeater_received,
|
||||
value: _packetRxText(),
|
||||
color: MeshPalette.signal,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.content_copy,
|
||||
label: l10n.repeater_duplicates,
|
||||
value: _duplicateText(),
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
_StatItem(
|
||||
icon: Icons.percent,
|
||||
label: l10n.repeater_chanUtil,
|
||||
value: _chanUtilText(),
|
||||
color: _chanUtil != null && _chanUtil! > 80
|
||||
? MeshPalette.alert
|
||||
: _chanUtil != null && _chanUtil! > 50
|
||||
? MeshPalette.warn
|
||||
: MeshPalette.signal,
|
||||
),
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Color _batteryColor() {
|
||||
final connector = context.watch<MeshCoreConnector>();
|
||||
final batteryMv =
|
||||
connector.getRepeaterBatteryMillivolts(widget.repeater.publicKeyHex) ??
|
||||
_batteryMv;
|
||||
if (batteryMv == null)
|
||||
return Theme.of(context).colorScheme.onSurfaceVariant;
|
||||
final percent = estimateBatteryPercentFromMillivolts(
|
||||
batteryMv,
|
||||
_batteryChemistry(),
|
||||
);
|
||||
if (percent < 20) return MeshPalette.alert;
|
||||
if (percent < 40) return MeshPalette.warn;
|
||||
return MeshPalette.signal;
|
||||
}
|
||||
|
||||
Widget _buildStatGrid(List<_StatItem> items) {
|
||||
return GridView.count(
|
||||
crossAxisCount: 2,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
childAspectRatio: 2.2,
|
||||
children: items
|
||||
.map(
|
||||
(item) => StatTile(
|
||||
icon: item.icon,
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
color: item.color,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StatItem {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final String value;
|
||||
final Color color;
|
||||
|
||||
const _StatItem({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.color,
|
||||
});
|
||||
}
|
||||
|
||||
+221
-156
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../utils/platform_info.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -7,11 +8,14 @@ import 'package:provider/provider.dart';
|
||||
import '../connector/meshcore_connector.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../services/linux_ble_error_classifier.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../widgets/adaptive_app_bar_title.dart';
|
||||
import '../widgets/device_tile.dart';
|
||||
import '../widgets/empty_state.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
import 'contacts_screen.dart';
|
||||
import 'channels_screen.dart';
|
||||
import 'tcp_screen.dart';
|
||||
import 'usb_screen.dart';
|
||||
|
||||
@@ -25,6 +29,7 @@ class ScannerScreen extends StatefulWidget {
|
||||
|
||||
class _ScannerScreenState extends State<ScannerScreen> {
|
||||
bool _changedNavigation = false;
|
||||
String? _connectingDeviceId;
|
||||
late final MeshCoreConnector _connector;
|
||||
late final VoidCallback _connectionListener;
|
||||
BluetoothAdapterState _bluetoothState = BluetoothAdapterState.unknown;
|
||||
@@ -46,7 +51,7 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
_changedNavigation = true;
|
||||
if (mounted) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => const ContactsScreen()),
|
||||
MaterialPageRoute(builder: (context) => const ChannelsScreen()),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -101,6 +106,32 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
title: AdaptiveAppBarTitle(context.l10n.scanner_title),
|
||||
centerTitle: true,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
if (PlatformInfo.supportsUsbSerial)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.usb),
|
||||
tooltip: context.l10n.connectionChoiceUsbLabel,
|
||||
onPressed: () {
|
||||
appLogger.info(
|
||||
'USB selected, opening UsbScreen',
|
||||
tag: 'ScannerScreen',
|
||||
);
|
||||
Navigator.of(
|
||||
context,
|
||||
).push(MaterialPageRoute(builder: (_) => const UsbScreen()));
|
||||
},
|
||||
),
|
||||
if (!PlatformInfo.isWeb)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.lan),
|
||||
tooltip: context.l10n.connectionChoiceTcpLabel,
|
||||
onPressed: () {
|
||||
Navigator.of(
|
||||
context,
|
||||
).push(MaterialPageRoute(builder: (_) => const TcpScreen()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
@@ -108,12 +139,21 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
builder: (context, connector, child) {
|
||||
return Column(
|
||||
children: [
|
||||
// Bluetooth off warning
|
||||
if (_bluetoothState == BluetoothAdapterState.off)
|
||||
_bluetoothOffWarning(context),
|
||||
// Bluetooth off warning — slides in/out with AnimatedSize
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeInOut,
|
||||
child: _bluetoothState == BluetoothAdapterState.off
|
||||
? _BluetoothOffBanner(
|
||||
onEnable: PlatformInfo.isAndroid
|
||||
? () => FlutterBluePlus.turnOn()
|
||||
: null,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
|
||||
// Status bar
|
||||
_buildStatusBar(context, connector),
|
||||
// Connection status header
|
||||
_ConnectionStatusHeader(connector: connector),
|
||||
|
||||
// Device list
|
||||
Expanded(child: _buildDeviceList(context, connector)),
|
||||
@@ -122,84 +162,43 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Consumer<MeshCoreConnector>(
|
||||
floatingActionButton: Consumer<MeshCoreConnector>(
|
||||
builder: (context, connector, child) {
|
||||
final isScanning =
|
||||
connector.state == MeshCoreConnectionState.scanning;
|
||||
final isBluetoothOff = _bluetoothState == BluetoothAdapterState.off;
|
||||
final usbSupported = PlatformInfo.supportsUsbSerial;
|
||||
final tcpSupported = !PlatformInfo.isWeb;
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
minimum: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (usbSupported)
|
||||
FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
appLogger.info(
|
||||
'USB selected, opening UsbScreen',
|
||||
tag: 'ScannerScreen',
|
||||
);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => const UsbScreen()),
|
||||
);
|
||||
},
|
||||
heroTag: 'scanner_usb_action',
|
||||
icon: const Icon(Icons.usb),
|
||||
label: Text(context.l10n.connectionChoiceUsbLabel),
|
||||
return FloatingActionButton.extended(
|
||||
heroTag: 'scanner_ble_action',
|
||||
onPressed: isBluetoothOff
|
||||
? null
|
||||
: () {
|
||||
HapticFeedback.lightImpact();
|
||||
_toggleScan(connector);
|
||||
},
|
||||
icon: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
transitionBuilder: (child, anim) =>
|
||||
ScaleTransition(scale: anim, child: child),
|
||||
child: isScanning
|
||||
? SizedBox(
|
||||
key: const ValueKey('scanning'),
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
)
|
||||
: const Icon(
|
||||
Icons.bluetooth_searching,
|
||||
key: ValueKey('idle'),
|
||||
),
|
||||
if (usbSupported) const SizedBox(width: 12),
|
||||
if (tcpSupported)
|
||||
FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => const TcpScreen()),
|
||||
);
|
||||
},
|
||||
heroTag: 'scanner_tcp_action',
|
||||
icon: const Icon(Icons.lan),
|
||||
label: Text(context.l10n.connectionChoiceTcpLabel),
|
||||
),
|
||||
if (tcpSupported) const SizedBox(width: 12),
|
||||
FloatingActionButton.extended(
|
||||
heroTag: 'scanner_ble_action',
|
||||
onPressed: isBluetoothOff
|
||||
? null
|
||||
: () {
|
||||
if (isScanning) {
|
||||
connector.stopScan();
|
||||
} else {
|
||||
unawaited(
|
||||
connector.startScan().catchError((e) {
|
||||
appLogger.warn(
|
||||
'startScan error: $e',
|
||||
tag: 'ScannerScreen',
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: isScanning
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.bluetooth_searching),
|
||||
label: Text(
|
||||
isScanning
|
||||
? context.l10n.scanner_stop
|
||||
: context.l10n.scanner_scan,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
label: Text(
|
||||
isScanning
|
||||
? context.l10n.scanner_stop
|
||||
: context.l10n.scanner_scan,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -207,79 +206,70 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusBar(BuildContext context, MeshCoreConnector connector) {
|
||||
String statusText;
|
||||
Color statusColor;
|
||||
|
||||
final l10n = context.l10n;
|
||||
switch (connector.state) {
|
||||
case MeshCoreConnectionState.scanning:
|
||||
statusText = l10n.scanner_scanning;
|
||||
statusColor = Colors.blue;
|
||||
break;
|
||||
case MeshCoreConnectionState.connecting:
|
||||
statusText = l10n.scanner_connecting;
|
||||
statusColor = Colors.orange;
|
||||
break;
|
||||
case MeshCoreConnectionState.connected:
|
||||
statusText = l10n.scanner_connectedTo(connector.deviceDisplayName);
|
||||
statusColor = Colors.green;
|
||||
break;
|
||||
case MeshCoreConnectionState.disconnecting:
|
||||
statusText = l10n.scanner_disconnecting;
|
||||
statusColor = Colors.orange;
|
||||
break;
|
||||
case MeshCoreConnectionState.disconnected:
|
||||
statusText = l10n.scanner_notConnected;
|
||||
statusColor = Colors.grey;
|
||||
break;
|
||||
void _toggleScan(MeshCoreConnector connector) {
|
||||
if (PlatformInfo.isWeb) {
|
||||
// flutter_blue_plus has no web backend, so a BLE scan silently no-ops in
|
||||
// the browser. Tell the user instead of leaving them staring at a button.
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.scanner_bluetoothWebUnsupported),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (connector.state == MeshCoreConnectionState.scanning) {
|
||||
connector.stopScan();
|
||||
} else {
|
||||
unawaited(
|
||||
connector.startScan().catchError((e) {
|
||||
appLogger.warn('startScan error: $e', tag: 'ScannerScreen');
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
color: statusColor.withValues(alpha: 0.1),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.circle, size: 12, color: statusColor),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
statusText,
|
||||
style: TextStyle(color: statusColor, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeviceList(BuildContext context, MeshCoreConnector connector) {
|
||||
if (connector.scanResults.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.bluetooth, size: 64, color: Colors.grey[400]),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
connector.state == MeshCoreConnectionState.scanning
|
||||
? context.l10n.scanner_searchingDevices
|
||||
: context.l10n.scanner_tapToScan,
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey[600]),
|
||||
),
|
||||
],
|
||||
),
|
||||
final isBluetoothOff = _bluetoothState == BluetoothAdapterState.off;
|
||||
final isScanning = connector.state == MeshCoreConnectionState.scanning;
|
||||
return EmptyState(
|
||||
icon: isBluetoothOff ? Icons.bluetooth_disabled : Icons.bluetooth,
|
||||
title: isBluetoothOff
|
||||
? context.l10n.scanner_bluetoothOff
|
||||
: isScanning
|
||||
? context.l10n.scanner_searchingDevices
|
||||
: context.l10n.scanner_tapToScan,
|
||||
subtitle: isBluetoothOff
|
||||
? context.l10n.scanner_bluetoothOffMessage
|
||||
: null,
|
||||
action: (isBluetoothOff || isScanning)
|
||||
? null
|
||||
: FilledButton.icon(
|
||||
onPressed: () {
|
||||
HapticFeedback.lightImpact();
|
||||
_toggleScan(connector);
|
||||
},
|
||||
icon: const Icon(Icons.bluetooth_searching),
|
||||
label: Text(context.l10n.scanner_scan),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(8),
|
||||
final isConnecting = connector.state == MeshCoreConnectionState.connecting;
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 0, 96),
|
||||
itemCount: connector.scanResults.length,
|
||||
separatorBuilder: (context, index) => const Divider(),
|
||||
itemBuilder: (context, index) {
|
||||
final result = connector.scanResults[index];
|
||||
return DeviceTile(
|
||||
scanResult: result,
|
||||
onTap: () => _connectToDevice(context, connector, result),
|
||||
final deviceId = result.device.remoteId.toString();
|
||||
return ListEntrance(
|
||||
index: index,
|
||||
child: DeviceTile(
|
||||
scanResult: result,
|
||||
isConnecting: isConnecting && _connectingDeviceId == deviceId,
|
||||
onTap: isConnecting
|
||||
? null
|
||||
: () => _connectToDevice(context, connector, result),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -293,6 +283,9 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
final name = result.device.platformName.isNotEmpty
|
||||
? result.device.platformName
|
||||
: result.advertisementData.advName;
|
||||
setState(() {
|
||||
_connectingDeviceId = result.device.remoteId.toString();
|
||||
});
|
||||
try {
|
||||
await connector.connect(
|
||||
result.device,
|
||||
@@ -321,9 +314,15 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.scanner_connectionFailed(e.toString())),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_connectingDeviceId = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,47 +411,113 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||
);
|
||||
return pin;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _bluetoothOffWarning(BuildContext context) {
|
||||
final errorColor = Theme.of(context).colorScheme.error;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||
color: errorColor.withValues(alpha: 0.15),
|
||||
// ── Private sub-widgets ────────────────────────────────────────────────────
|
||||
|
||||
/// Bluetooth-off warning banner — styled as an alert MeshCard.
|
||||
class _BluetoothOffBanner extends StatelessWidget {
|
||||
final VoidCallback? onEnable;
|
||||
|
||||
const _BluetoothOffBanner({this.onEnable});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return MeshCard(
|
||||
color: scheme.error.withValues(alpha: 0.08),
|
||||
borderColor: scheme.error.withValues(alpha: 0.35),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.bluetooth_disabled, size: 24, color: errorColor),
|
||||
const SizedBox(width: 12),
|
||||
Icon(Icons.bluetooth_disabled, size: 20, color: scheme.error),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.scanner_bluetoothOff,
|
||||
style: TextStyle(
|
||||
color: errorColor,
|
||||
color: scheme.error,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
fontSize: 13.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
context.l10n.scanner_bluetoothOffMessage,
|
||||
style: TextStyle(
|
||||
color: errorColor.withValues(alpha: 0.85),
|
||||
color: scheme.error.withValues(alpha: 0.8),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (PlatformInfo.isAndroid)
|
||||
if (onEnable != null) ...[
|
||||
const SizedBox(width: 8),
|
||||
TextButton(
|
||||
onPressed: () => FlutterBluePlus.turnOn(),
|
||||
onPressed: onEnable,
|
||||
child: Text(context.l10n.scanner_enableBluetooth),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Connection status header with AnimatedSwitcher between states.
|
||||
class _ConnectionStatusHeader extends StatelessWidget {
|
||||
final MeshCoreConnector connector;
|
||||
|
||||
const _ConnectionStatusHeader({required this.connector});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
|
||||
final (String label, Color color, bool pulse) = switch (connector.state) {
|
||||
MeshCoreConnectionState.scanning => (
|
||||
l10n.scanner_scanning,
|
||||
MeshPalette.blue,
|
||||
true,
|
||||
),
|
||||
MeshCoreConnectionState.connecting => (
|
||||
l10n.scanner_connecting,
|
||||
MeshPalette.warn,
|
||||
true,
|
||||
),
|
||||
MeshCoreConnectionState.connected => (
|
||||
l10n.scanner_connectedTo(connector.deviceDisplayName),
|
||||
MeshPalette.signal,
|
||||
false,
|
||||
),
|
||||
MeshCoreConnectionState.disconnecting => (
|
||||
l10n.scanner_disconnecting,
|
||||
MeshPalette.warn,
|
||||
true,
|
||||
),
|
||||
MeshCoreConnectionState.disconnected => (
|
||||
l10n.scanner_notConnected,
|
||||
scheme.onSurfaceVariant,
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Align(
|
||||
key: ValueKey(connector.state),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: StatusChip(label: label, color: color, pulse: pulse),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+636
-417
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user